]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.10pre4 2.3.10pre4
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:26:02 +0000 (15:26 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:26:02 +0000 (15:26 -0500)
261 files changed:
CREDITS
Documentation/Configure.help
Documentation/cpqarray.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/networking/arcnet-hardware.txt
Documentation/networking/arcnet.txt
Documentation/networking/olympic.txt [new file with mode: 0644]
Documentation/sound/Introduction
Documentation/sound/OPL3-SA2
Documentation/sysctl/README
Documentation/sysctl/fs.txt
Documentation/sysctl/kernel.txt
Documentation/sysctl/sunrpc.txt
Documentation/sysctl/vm.txt
Documentation/video4linux/API.html
Documentation/video4linux/README.buz [new file with mode: 0644]
Documentation/video4linux/bttv/PROBLEMS
Documentation/video4linux/bttv/README.RADIO
Documentation/video4linux/bttv/THANKS
arch/alpha/kernel/signal.c
arch/arm/kernel/process.c
arch/arm/kernel/time.c
arch/arm/nwfpe/fpmodule.c
arch/i386/boot/setup.S
arch/i386/defconfig
arch/i386/kernel/process.c
arch/i386/kernel/setup.c
arch/i386/math-emu/fpu_emu.h
arch/mips/boot/elf2ecoff.c
arch/mips/config.in
arch/mips/defconfig
arch/mips/kernel/ptrace.c
arch/mips/kernel/r4k_misc.S
arch/mips/kernel/setup.c
arch/mips/mm/fault.c
arch/ppc/amiga/amiints.c
arch/ppc/amiga/config.c
arch/ppc/kernel/irq.c
arch/ppc/kernel/pci.c
arch/ppc/kernel/ppc-stub.c
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/setup.c
arch/sparc/ap1000/aplib.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/process.c
arch/sparc/kernel/ptrace.c
arch/sparc/kernel/sparc-stub.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/mm/fault.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc64/kernel/psycho.c
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/sys_sunos32.c
arch/sparc64/solaris/socksys.c
drivers/acorn/char/keyb_arc.c
drivers/ap1000/bif.c
drivers/block/Config.in
drivers/block/Makefile
drivers/block/cpqarray.c [new file with mode: 0644]
drivers/block/cpqarray.h [new file with mode: 0644]
drivers/block/genhd.c
drivers/block/hpt34x.c
drivers/block/ida_cmd.h [new file with mode: 0644]
drivers/block/ida_ioctl.h [new file with mode: 0644]
drivers/block/ide-disk.c
drivers/block/ide-pci.c
drivers/block/ide-probe.c
drivers/block/ide.c
drivers/block/ll_rw_blk.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/smart1,2.h [new file with mode: 0644]
drivers/char/Config.in
drivers/char/Makefile
drivers/char/adbmouse.c
drivers/char/amigamouse.c
drivers/char/bttv.c
drivers/char/bttv.h
drivers/char/buz.c [new file with mode: 0644]
drivers/char/buz.h [new file with mode: 0644]
drivers/char/bw-qcam.c
drivers/char/c-qcam.c
drivers/char/chipsets.h [new file with mode: 0644]
drivers/char/dz.c
drivers/char/hfmodem/main.c
drivers/char/i2c.c
drivers/char/lp_intern.c
drivers/char/n_hdlc.c
drivers/char/pc_keyb.c
drivers/char/ppdev.c [new file with mode: 0644]
drivers/char/ppdev.h [new file with mode: 0644]
drivers/char/radio-aimslab.c
drivers/char/radio-aztech.c
drivers/char/radio-cadet.c
drivers/char/radio-gemtek.c
drivers/char/radio-miropcm20.c
drivers/char/radio-rtrack2.c
drivers/char/radio-sf16fmi.c
drivers/char/radio-terratec.c [new file with mode: 0644]
drivers/char/radio-zoltrix.c
drivers/char/rocket.c
drivers/char/saa7111.c [new file with mode: 0644]
drivers/char/saa7185.c [new file with mode: 0644]
drivers/char/tpqic02.c
drivers/char/videodev.c
drivers/char/zr36057.h [new file with mode: 0644]
drivers/char/zr36060.h [new file with mode: 0644]
drivers/fc4/socal.c
drivers/i2o/README
drivers/i2o/README.lan
drivers/i2o/i2o_block.c
drivers/i2o/i2o_config.c
drivers/i2o/i2o_core.c
drivers/i2o/i2o_lan.c
drivers/i2o/i2o_lan.h
drivers/i2o/i2o_pci.c
drivers/i2o/i2o_proc.c
drivers/i2o/i2o_proc.h
drivers/i2o/i2o_scsi.c
drivers/isdn/avmb1/capidrv.c
drivers/isdn/isdn_bsdcomp.c
drivers/net/arlan-proc.c [new file with mode: 0644]
drivers/net/arlan.c [new file with mode: 0644]
drivers/net/arlan.h [new file with mode: 0644]
drivers/net/eepro100.c
drivers/net/eql.c
drivers/net/eth16i.c
drivers/net/ewrk3.c
drivers/net/hamradio/hdlcdrv.c
drivers/net/hamradio/soundmodem/sm.h
drivers/net/hostess_sv11.c
drivers/net/ibmtr.c
drivers/net/irda/smc-ircc.c
drivers/net/irda/toshoboe.c
drivers/net/irda/uircc.c
drivers/net/ne2k-pci.c
drivers/net/olympic.c [new file with mode: 0644]
drivers/net/olympic.h [new file with mode: 0644]
drivers/net/ppp.c
drivers/net/rtl8139.c
drivers/net/sealevel.c [new file with mode: 0644]
drivers/net/seeq8005.c
drivers/net/slhc.c
drivers/net/sunbmac.c
drivers/net/sunlance.c
drivers/net/tulip.c
drivers/net/via-rhine.c
drivers/net/z85230.c
drivers/net/zlib.c
drivers/pci/pci.c
drivers/sbus/char/bpp.c
drivers/sbus/sbus.c
drivers/scsi/53c7xx.c
drivers/scsi/NCR53C9x.c
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx/aic7xxx.reg
drivers/scsi/aic7xxx_reg.h
drivers/scsi/atp870u.c
drivers/scsi/constants.c
drivers/scsi/i60uscsi.c
drivers/scsi/ini9100u.c
drivers/scsi/inia100.c
drivers/scsi/megaraid.c
drivers/scsi/mvme16x.c
drivers/scsi/pas16.c
drivers/scsi/qlogicfc.c
drivers/scsi/qlogicfc.h
drivers/scsi/qlogicisp.c
drivers/scsi/scsi_debug.c
drivers/scsi/sym53c416.c
drivers/sgi/char/usema.c
drivers/sound/cmpci.c
drivers/sound/dev_table.h
drivers/sound/es1370.c
drivers/sound/es1371.c
drivers/sound/lowlevel/awe_compat-fbsd.h
drivers/sound/maui.c
drivers/sound/msnd_pinnacle.c
drivers/sound/opl3sa2.c
drivers/sound/sb_ess.c
drivers/sound/sb_mixer.c
drivers/sound/sb_mixer.h
drivers/sound/sgalaxy.c
drivers/sound/sonicvibes.c
drivers/sound/sound_calls.h
drivers/sound/sound_syms.c
drivers/sound/trix.c
drivers/sound/wavfront.c
drivers/sound/wf_midi.c
drivers/usb/uhci.c
fs/binfmt_elf.c
fs/coda/inode.c
fs/exec.c
fs/inode.c
fs/ioctl.c
fs/locks.c
fs/minix/file.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfsd/nfsctl.c
fs/nfsd/vfs.c
fs/open.c
fs/proc/link.c
fs/qnx4/dir.c
fs/qnx4/symlinks.c
fs/sysv/file.c
fs/ufs/balloc.c
fs/umsdos/file.c
include/asm-i386/bugs.h
include/asm-i386/setup.h [new file with mode: 0644]
include/asm-mips/processor.h
include/asm-mips/ptrace.h
include/asm-sparc/audioio.h
include/asm-sparc64/audioio.h
include/linux/blk.h
include/linux/fs.h
include/linux/i2c.h
include/linux/i2o.h
include/linux/ide.h
include/linux/major.h
include/linux/mm.h
include/linux/proc_fs.h
include/linux/soundcard.h
include/linux/video_decoder.h [new file with mode: 0644]
include/linux/video_encoder.h [new file with mode: 0644]
include/linux/videodev.h
include/net/irda/irmod.h
init/main.c
kernel/fork.c
kernel/ksyms.c
kernel/ptrace.c
kernel/signal.c
kernel/sysctl.c
lib/string.c
mm/memory.c
mm/mmap.c
net/appletalk/ddp.c
net/ax25/af_ax25.c
net/bridge/br.c
net/decnet/dn_fib.c
net/ipv4/icmp.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/ip6_fw.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipx/af_ipx.c
net/irda/compressors/irda_deflate.c
net/irda/irmod.c
net/netrom/af_netrom.c
net/netsyms.c
net/rose/af_rose.c
net/unix/af_unix.c
net/x25/af_x25.c
net/x25/x25_dev.c
scripts/ver_linux

diff --git a/CREDITS b/CREDITS
index 5fff6760b10b992b512a147d5542cb4b7a62b187..04a8c9d310894f338f1df1d52491258ed7b534f0 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -880,13 +880,11 @@ S: Mergenthalerallee 45-47
 S: 65760 Eschborn
 S: Germany
 
-N: Kenji Tsutomu Hollis
-E: khollis@bitgate.com
-W: http://www.nurk.org/
+N: Kenji Hollis
+E: kenji@bitgate.com
+W: http://www.bitgate.com/
 D: Berkshire PC Watchdog Driver
-S: Post Office Box 15
-S: Grants Pass, Oregon 97526
-S: USA
+D: Small/Industrial Driver Project
 
 N: Nick Holloway
 E: Nick.Holloway@alfie.demon.co.uk
@@ -1672,6 +1670,15 @@ S: 4390 Albany Drive #41A
 S: San Jose, California 95129
 S: USA
 
+N: Augusto Cesar Radtke
+E: bishop@sekure.org
+W: http://bishop.sekure.org
+D: {copy,get,put}_user calls updates
+D: Miscellaneous hacks
+S: R. Otto Marquardt, 226 - Garcia
+S: 89020-350 Blumenau - Santa Catarina
+S: Brazil
+
 N: Eric S. Raymond
 E: esr@thyrsus.com
 W: http://www.tuxedo.org/~esr/
index ace1522fec35e61ef5dd0eb2f5a5d09c6cc5dc09..8bf3057423ef786723d6d0deed00bbaa6d1542c8 100644 (file)
@@ -1674,6 +1674,45 @@ SGI Visual Workstation framebuffer support
 CONFIG_FB_SGIVW
   SGI Visual Workstation support for framebuffer graphics.
 
+I2O support
+CONFIG_I2O
+  The Intelligent Input/Output (I2O) architecture allows
+  hardware drivers to be split into two parts: an operating system
+  specific module called the OSM and an hardware specific module
+  called the HDM. The OSM can talk to a whole range of HDM's, and
+  ideally the HDM's are not OS dependent. This allows for the same
+  driver to be used under different operating systems if the relevant
+  OSM is in place. If you say Y here, you will get a choice of OSM's
+  with the following questions.
+
+  This support is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
+
+  If unsure, say N.
+
+I2O PCI support
+CONFIG_I2O_PCI
+  Build in support for PCI bus I2O interface adapters. Currently this
+  is the only variety supported.
+
+I2O Block OSM
+CONFIG_I2O_BLOCK
+  Include support for the I2O Block OSM. The Block OSM presents disk and
+  other structured block devices to the operating system.
+
+I2O LAN OSM
+CONFIG_I2O_LAN
+  Include support for the LAN OSM. You will also need to include support
+  for token ring or fddi if you wish to use token ring or FDDI I2O cards
+  with this driver.
+
+I2O SCSI OSM
+CONFIG_I2O_SCSI
+  Allow direct scsi access to scsi devices on a SCSI or FibreChannel I2O 
+  controller. You can use both the SCSI and Block OSM together if you wish.
+
 System V IPC
 CONFIG_SYSVIPC
   Inter Process Communication is a suite of library functions and
@@ -2040,6 +2079,11 @@ CONFIG_FB_VESA
   You will get a boot time penguin logo at no additional cost. Please
   read Documentation/fb/vesafb.txt. If unsure, say Y.
 
+VGA 16-color graphics console
+CONFIG_FB_VGA16
+  This is the frame buffer device driver for VGA 16 color graphic
+  cards. Say Y if you have such a card.
+
 Backward compatibility mode for Xpmac
 CONFIG_FB_COMPAT_XPMAC
   If you use the Xpmac X server (common with mklinux), you'll need to
@@ -2328,7 +2372,7 @@ CONFIG_PARPORT_1284
   want to use a device that uses enhanced parallel port transfer modes
   such as EPP and ECP, say Y here to enable advanced IEEE 1284
   transfer modes. Also say Y if you want device ID information to
-  appear in /proc/parport/*/autoprobe*. It is safe to say N.
+  appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
 
 Enable loadable module support
 CONFIG_MODULES
@@ -5231,6 +5275,17 @@ CONFIG_WAVELAN
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+Aironet Arlan 655 & IC2200 DS support
+CONFIG_ARLAN
+  Aironet makes Arlan. www.aironet.com. Uses www.Telxon.com chip, which is
+  used on several similar cards. Driver is tested on 655 and IC2200 series. 
+  Look for http://www.ylenurme.ee/~elmer/655/ for latest information. 
+  Driver is build as two modules, arlan and arlan-proc. The later is /proc
+  interface and not needed most of time.
+  On some computers the card ends up in non-valid state after some time.
+  Use a ping-reset script to clear it.
+   
+
 LAPB over Ethernet driver
 CONFIG_LAPBETHER
   This is a driver for a pseudo device (typically called /dev/lapb0)
@@ -5357,6 +5412,15 @@ CONFIG_ETHERTAP
   module, say M here and read Documentation/modules.txt. If you don't
   know what to use this for, you don't need it.
 
+Sealevel Systems 4021 support
+CONFIG_SEALEVEL_4021
+  This is a driver for the Sealevel Systems ACB 56 serial I/O adapter.
+  
+  This driver can only be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to do that, say M here. The module will be called
+  sealevel.o.
+
 Frame Relay (DLCI) support
 CONFIG_DLCI
   This is support for the frame relay protocol; frame relay is a fast
@@ -5763,6 +5827,40 @@ CONFIG_WANPIPE_PPP
   you say N, the PPP support will not be included in the driver (saves
   about 16 KB of kernel memory).
 
+Cyclom 2X(tm) multiprotocol cards
+CONFIG_CYCLADES_SYNC
+  Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and
+  http://www.cyclades.com.br; to browse the WWW, you need to have
+  access to a machine on the Internet that has a program like lynx or
+  netscape) is an intelligent multiprotocol WAN adapter with data
+  transfer rates up to 512 Kbps). These cards support the X.25 and SNA
+  related protocols. If you have one or more of these cards, say Y to
+  this option. The next questions will ask you about the protocols you
+  want the driver to support (for now only X.25 is supported).
+
+  While no documentation is available at this time please grab the
+  wanconfig tarball in http://www.conectiva.com.br/~acme/cycsyn-devel
+  (with minor changes to make it compile with the current wanrouter
+  include files; efforts are being made to use the original package
+  available at ftp://ftp.sangoma.com).
+
+  Feel free to contact me or the cycsyn-devel mailing list at
+  acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for
+  aditional details, I hope to have documentation available as soon
+  as possible.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cyclomx.o. For general information about
+  modules read Documentation/modules.txt.
+
+Cyclom 2X X.25 support
+CONFIG_CYCLOMX_X25
+  Say Y to this option if you are planning to connect a Cyclom 2X card
+  to an X.25 network. 
+  If you say N, the X.25 support will not be included in the driver
+  (saves about 11 KB of kernel memory).
+
 Ethernet (10 or 100Mbit)
 CONFIG_NET_ETHERNET
   Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
@@ -5976,7 +6074,7 @@ CONFIG_YELLOWFIN
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called yellowfin.o.
 
-Alteon AceNIC / 3Com 3C985 Gigabit Ethernet support.
+Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
   Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit
   Ethernet adapter. The driver allows for using the Jumbo Frame
@@ -6734,6 +6832,25 @@ CONFIG_IBMTR
   The module will be called ibmtr.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+IBM Olympic chipset PCI adapter support
+CONFIG_IBMOL
+  This is support for all non-Lanstreamer IBM PCI Token Ring Cards. 
+  Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II
+  Wake On Lan, and PCI 100/16/4 adapters.
+
+  If you have such an adapter, say Y and read the Token-Ring mini-HOWTO,
+  available via FTP (user:anonymous) from
+  ftp://metalab.unc/edu/pub/Linux/docs/HOWTO.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will will be called olympic.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+  Also read the linux/Documentation/networking/olympic.txt or check the 
+  Linux Token Ring Project site for the latest information at
+  http://www.linuxtr.net
+
 SysKonnect adapter support
 CONFIG_SKTR
   This is support for all SysKonnect Token Ring cards, specifically
@@ -8387,6 +8504,16 @@ CONFIG_CYCLADES
 
   If you haven't heard about it, it's safe to say N.
 
+Cyclades-Z interrupt mode operation (EXPERIMENTAL)
+CONFIG_CYZ_INTR
+  The Cyclades-Z family of multiport cards allows 2 (two) driver
+  op modes: polling and interrupt. In polling mode, the driver will
+  check the status of the Cyclades-Z ports every certain amount of
+  time (which is called polling cycle and is configurable). In
+  interrupt mode, it will use an interrupt line (IRQ) in order to check
+  the status of the Cyclades-Z ports. The default op mode is polling.
+  If unsure, say N.
+
 Stallion multiport serial support 
 CONFIG_STALDRV
   Stallion cards give you many serial ports. You would need something
@@ -9476,7 +9603,7 @@ CONFIG_SOUND
   after the PnP configuration is finished. To do this, say M here and
   read Documentation/modules.txt as well as
   Documentation/sound/README.modules; the module will be called
-  sound.o.
+  soundcore.o.
 
   I'm told that even without a sound card, you can make your computer
   say more than an occasional beep, by programming the PC speaker.
@@ -11022,6 +11149,11 @@ CONFIG_RADIO_RTRACK2
   Choose Y here if you have this FM radio card, and then fill in the 
   port address below.
 
+  If you have GemTeks combined (PnP) sound- and radio card you must use
+  this driver as a module and setup the card with isapnptools. You must
+  also pass the module a suitable io parameter, 0x248 has been reported
+  to be used by these cards.
+
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on 
   this API and pointers to "v4l" programs may be found on the WWW at
@@ -11198,6 +11330,40 @@ CONFIG_RADIO_GEMTEK_PORT
   Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
   0x34c, if you haven't changed the jumper setting on the card.
 
+PlanB Video-In for PowerMacs
+CONFIG_VIDEO_PLANB
+  PlanB is the V4L driver for the PowerMac 7x00/8x00 series video
+  input hardware. If you want to experiment with this, say Y.
+  Otherwise, or if you don't understand a word, say N.
+  See http://www.cpu.lu/~mlan/planb.html for more info.
+
+  Saying M will compile this driver as a module (planb.o).
+
+TerraTec ActiveRadio
+CONFIG_RADIO_TERRATEC
+  Choose Y here if you have this FM radio card, and then fill in the
+  port address below. (TODO)
+
+  Note: This driver is in its early stages. Right now volume and frequency
+  control and muting works at least for me, but unfortunately i have not
+  found anybody who wants to use this card with linux. So if it is this
+  what YOU are trying to do right now, PLEASE DROP ME A NOTE!!
+  Rolf Offermanns (rolf@offermanns.de)
+  
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video for Linux API. Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
+  you need to have access to a machine on the Internet that has a
+  program like lynx or netscape.
+
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-terratec.o.
+  
+
 BT848 Video For Linux
 CONFIG_VIDEO_BT848
   Support for BT848 based frame grabber/overlay boards. This includes
@@ -11244,6 +11410,14 @@ CONFIG_VIDEO_PMS
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+Compaq SMART2 support
+CONFIG_BLK_CPQ_DA
+   This is the driver for Compaq Smart Array controllers.  
+   Everyone using these boards should say Y here.  
+   See "linux/Documentation/cpqarray.txt" for the current list of 
+   boards supported by this driver, and for further information 
+   on the use of this driver. 
 #
 # ARM options
 #
@@ -11542,6 +11716,21 @@ CONFIG_IRTTY_SIR
 
   If unsure, say Y.
 
+IrPORT IrDA Device Driver
+CONFIG_IRPORT_SIR
+  Say Y here if you want to build support for the IrPORT IrDA device
+  driver. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt. IrPORT can be used instead of
+  IrTTY and sometimes this can be better. One example is if your
+  IrDA port does not have echo-canceling, which will work OK with
+  IrPORT since this driver is working in half-duplex mode only. You
+  don't need to use irattach with IrPORT, but you just insert it 
+  the same way as FIR drivers (insmod irport io=0x3e8 irq=11).
+  Notice that IrPORT is a SIR device driver which means that speed
+  is limited to 115200 bps.
+
+  If unsure, say Y.
+
 Winbond W83977AF IrDA Device Driver
 CONFIG_WINBOND_FIR
   Say Y here if you want to build IrDA support for the Winbond
@@ -11565,6 +11754,13 @@ CONFIG_SHARP_FIR
   read Documentation/modules.txt. This chipset is used by the Toshiba
   Tecra laptops.
 
+Toshiba Type-O IR Port Device Driver
+CONFIG_TOSHIBA_FIR
+  Say Y here if you want to build support for the Toshiba Type-O IR
+  chipset. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt. This chipset is used by the Toshiba
+  Libretto 100CT, and many more laptops.
+
 ESI JetEye PC Dongle
 CONFIG_ESI_DONGLE
   Say Y here if you want to build support for the Extended Systems
@@ -11602,6 +11798,15 @@ CONFIG_GIRBIL_DONGLE
   by IrTTY. To activate support for Greenwich dongles you will have to
   insert "irattach -d girbil" in the /etc/irda/drivers script.
 
+Parallax Litelink dongle
+CONFIG_LITELINK_DONGLE
+  Say Y here if you want to build support for the Parallax Litelink
+  dongle. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The Parallax dongle attaches to the
+  normal 9-pin serial port connector, and can currently only be used
+  by IrTTY. To activate support for Parallax dongles you will have to
+  insert "irattach -d litelink" in the /etc/irda/drivers script.
+
 VME (Motorola and BVM) support
 CONFIG_VME
   Say Y here if you want to build a kernel for a 680x0 based VME
@@ -11738,6 +11943,16 @@ CONFIG_USB_ACM
   This driver allows for devices which support the Abstract Control Model,
   including many USB-based modems, ISDN adapters, and network adapters.
 
+Support for user-space parallel port device drivers
+CONFIG_PPDEV
+  Saying Y to this adds support for /dev/parport device nodes.
+  NB. You have to make them before you can use them:
+    mknod /dev/parport00 c 99 0
+    mknod /dev/parport01 c 99 1
+    mknod /dev/parport10 c 99 16
+    mknod /dev/parport11 c 99 17
+    etc..
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, 
diff --git a/Documentation/cpqarray.txt b/Documentation/cpqarray.txt
new file mode 100644 (file)
index 0000000..45a5321
--- /dev/null
@@ -0,0 +1,107 @@
+This driver is for Compaq's SMART2 Intellegent Disk Array Controllers.
+
+WARNING:
+--------
+
+This driver comes with NO WARRANTY.  It is not officially supported by
+Compaq.  Do not call technical support.  Use at your own risk.
+
+Supported Cards:
+----------------
+
+This driver is known to work with the following cards:
+
+       * SMART (EISA)
+       * SMART-2/E (EISA)
+       * SMART-2/P
+       * SMART-2DH
+       * SMART-2SL
+       * SMART-221
+       * SMART-3100ES
+       * SMART-3200
+       * Integrated Smart Array Controller
+       * SA 4200
+       * SA 4250ES
+
+It should also work with some really old Disk array adapters, but I am
+unable to test against these cards:
+
+       * IDA
+       * IDA-2
+       * IAES
+
+Installing:
+-----------
+
+You need to build a new kernel to use this device, even if you want to
+use a loadable module.  
+
+Apply the patch to a 2.2.x kernel:
+
+# cd linux
+# patch -p1 <smart2.patch
+
+Then build a new kernel and turn on Compaq SMART2 Disk Array support.
+Create device nodes for the diskarray device:
+
+# mkdev.ida [ctlrs]
+
+Where ctlrs is the number of controllers you have (defaults to 1 if not
+specified).
+
+EISA Controllers:
+-----------------
+
+If you want to use an EISA controller you'll have to supply some
+insmod/lilo paramaters.  If the driver is compiled into the kernel, must
+give it the controller's IO port address at boot time (it is no longer
+necessary to specifiy the IRQ).  For example, if you had two SMART-2/E
+controllers, in EISA slots 1 and 2 you'd give it a boot argument like
+this:
+
+       smart2=0x1000,0x2000
+
+If you were loading the driver as a module, you'd give load it like this:
+
+       insmod cpqarray.o eisa=0x1000,0x2000
+
+You can use EISA and PCI adapters at the same time.
+
+Booting:
+--------
+
+You'll need to use a modified lilo if you want to boot from a disk array.
+Its simply a version of lilo with some code added to tell it how to
+understand Compaq diskarray devices.
+
+Device Naming:
+--------------
+
+You need some entries in /dev for the ida device.  The mkdev.ida script
+can make device nodes for you automatically.  Currently the device setup
+is as follows:
+
+Major numbers:
+       72      ida0
+       73      ida1
+       74      ida2
+       etc...
+
+Minor numbers:
+        b7 b6 b5 b4 b3 b2 b1 b0
+        |----+----| |----+----|
+             |           |
+             |           +-------- Partition ID (0=wholedev, 1-15 partition)
+             |
+             +-------------------- Logical Volume number
+
+The suggested device naming scheme is:
+/dev/ida/c0d0          Controller 0, disk 0, whole device
+/dev/ida/c0d0p1                Controller 0, disk 0, partition 1
+/dev/ida/c0d0p2                Controller 0, disk 0, partition 2
+/dev/ida/c0d0p3                Controller 0, disk 0, partition 3
+
+/dev/ida/c1d1          Controller 1, disk 1, whole device
+/dev/ida/c1d1p1                Controller 1, disk 1, partition 1
+/dev/ida/c1d1p2                Controller 1, disk 1, partition 2
+/dev/ida/c1d1p3                Controller 1, disk 1, partition 3
index 9c293fbc9f45138f01274e97aa8c45f5dec8e72b..e1392c277afc0da5fe84f0e1d518553cc8914d73 100644 (file)
@@ -37,7 +37,7 @@ restrictions referred to are that the relevant option is valid if:
     SOUND      Appropriate sound system support is enabled.
     VGA        The VGA console has been enabled.
     VT         Virtual terminal support is enabled.
-    XT         IBM PC/XT support is enabled.
+    XT         IBM PC/XT MFM hard disk support is enabled.
 
 In addition, the following text indicates that the option:
 
index 0c1dbcea9b8ff2bd801d711d2443b239779a6667..638bb8abfff4c98a4d0c8756b4a8040ec6d1916b 100644 (file)
@@ -20,14 +20,14 @@ INTRODUCTION TO ARCNET
 ARCnet is a network type which works in a way similar to popular Ethernet
 networks but which is also different in some very important ways.
 
-First of all, you can get ARCnet cards in at least two speeds: 2.5Mbps
-(slower than Ethernet) and 100Mbps (faster than normal Ethernet).  In fact,
+First of all, you can get ARCnet cards in at least two speeds: 2.5 Mbps
+(slower than Ethernet) and 100 Mbps (faster than normal Ethernet).  In fact,
 there are others as well, but these are less common.  The different hardware
 types, as far as I'm aware, are not compatible and so you cannot wire a
-100Mbps card to a 2.5Mbps card, and so on.  From what I hear, my driver does
-work with 100Mbps cards, but I haven't been able to verify this myself,
-since I only have the 2.5Mbps variety.  It is probably not going to saturate
-your 100Mbps card.  Stop complaining :)
+100 Mbps card to a 2.5 Mbps card, and so on.  From what I hear, my driver does
+work with 100 Mbps cards, but I haven't been able to verify this myself,
+since I only have the 2.5 Mbps variety.  It is probably not going to saturate
+your 100 Mbps card.  Stop complaining. :)
 
 You also cannot connect an ARCnet card to any kind of Ethernet card and
 expect it to work.  
@@ -52,17 +52,17 @@ a pass around the "ring" within a maximum length of time.  This makes it
 useful for realtime networks.
 
 In addition, all known ARCnet cards have an (almost) identical programming
-interface.  This means that with one "arcnet" driver you can support any
-card; whereas, with Ethernet, each manufacturer uses what is sometimes a
+interface.  This means that with one ARCnet driver you can support any
+card, whereas with Ethernet each manufacturer uses what is sometimes a
 completely different programming interface, leading to a lot of different,
 sometimes very similar, Ethernet drivers.  Of course, always using the same
 programming interface also means that when high-performance hardware
-facilities like PCI busmastering DMA appear, it's hard to take advantage of
+facilities like PCI bus mastering DMA appear, it's hard to take advantage of
 them.  Let's not go into that.
 
 One thing that makes ARCnet cards difficult to program for, however, is the
 limit on their packet sizes; standard ARCnet can only send packets that are
-up to 508 bytes in length.  This is smaller than the internet "bare minimum"
+up to 508 bytes in length.  This is smaller than the Internet "bare minimum"
 of 576 bytes, let alone the Ethernet MTU of 1500.  To compensate, an extra
 level of encapsulation is defined by RFC1201, which I call "packet
 splitting," that allows "virtual packets" to grow as large as 64K each,
@@ -1005,9 +1005,9 @@ LCS-8830(-T) (8 and 16-bit cards)
     only (the JP0 jumper is hardwired), and BNC only.
        
 This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC,
-nowhere else, not even on the few xeroxed sheets from the manual).
+nowhere else, not even on the few Xeroxed sheets from the manual).
 
-SMC Arcnet Board Type LCS-8830-T
+SMC ARCnet Board Type LCS-8830-T
 
    ------------------------------------
   |                                    |
@@ -1070,7 +1070,7 @@ Switches        Base
 
 DIP Switches 1-5 of SW2 encode the RAM and ROM Address Range:
 
-Switches        Ram           Rom
+Switches        RAM           ROM
 12345           Address Range  Address Range
 00000          C:0000-C:07ff   C:2000-C:3fff
 10000          C:0800-C:0fff
@@ -1170,11 +1170,11 @@ Carl de Billy <CARL@carainfo.com> explains J3 and J4:
 DIP Switches:
 
        The DIP switches accessible on the accessible end of the card while
-        it is installed, is used to set the arcnet address.  There are 8
+        it is installed, is used to set the ARCnet address.  There are 8
         switches.  Use an address from 1 to 254.
 
        Switch No.
-       12345678        Arcnet address
+       12345678        ARCnet address
        -----------------------------------------
        00000000        FF      (Don't use this!)
        00000001        FE
@@ -1222,7 +1222,7 @@ DIP Switches:
         from the upper memory regions, and then attempting to load ARCETHER
         using these addresses.
 
-       I recommend using an arcnet memory address of 0xD000, and putting
+       I recommend using an ARCnet memory address of 0xD000, and putting
         the EMS page frame at 0xC000 while using QEMM stealth mode.  That
         way, you get contiguous high memory from 0xD100 almost all the way
         the end of the megabyte.
@@ -1687,7 +1687,7 @@ parameters. These two jumpers are normally left open.
                 |____________________________________________| |__|
 
 
-UM9065L : Arcnet Controller
+UM9065L : ARCnet Controller
 
 SW 1    : Shared Memory Address and I/O Base
 
@@ -1800,7 +1800,7 @@ SW2 1-8     Node ID Select (ID0-ID7)
 J1-J5       IRQ Select
 J6-J21      Unknown (Probably extra timeouts & ROM enable ...)
 LED1        Activity LED 
-BNC         Coax connector (STAR arcnet)
+BNC         Coax connector (STAR ARCnet)
 RAM         2k of SRAM
 ROM         Boot ROM socket
 UFS         Unidentified Flying Sockets
@@ -1905,7 +1905,7 @@ LAN-ARC-8, an 8-bit card
 ------------------------
   - from Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>
 
-This is another SMC 90C65 based arcnet card. I couldn't identify the
+This is another SMC 90C65-based ARCnet card. I couldn't identify the
 manufacturer, but it might be DataPoint, because the card has the
 original arcNet logo in its upper right corner.
 
@@ -1942,9 +1942,9 @@ SW1 1-5:    Base Memory Address Select
 SW2 1-8:    Node ID Select
 SW3 1-5:    IRQ Select   
     6-7:    Extra Timeout
-    8  :    Rom Enable   
+    8  :    ROM Enable   
 BNC         Coax connector
-XTAL        20MHz Crystal
+XTAL        20 MHz Crystal
 
 
 Setting the Node ID
@@ -2081,11 +2081,11 @@ SW1 1-5     Base Memory Address Select
     6-8     Base I/O Address Select
 SW2 1-8     Node ID Select (ID0-ID7)
 J1          IRQ Select
-J2          Rom Enable
+J2          ROM Enable
 J3          Extra Timeout
 LED1        Activity LED 
-BNC         Coax connector (BUS arcnet)
-RJ          Twisted Pair Connector (daisychain)
+BNC         Coax connector (BUS ARCnet)
+RJ          Twisted Pair Connector (daisy chain)
 
 
 Setting the Node ID
@@ -2419,7 +2419,7 @@ using information from the Original
 
 Legend:
 
-COM90C65:       Arcnet Probe
+COM90C65:       ARCnet Probe
 S1  1-8:    Node ID Select
 S2  1-3:    I/O Base Address Select
     4-6:    Memory Base Address Select
@@ -2791,7 +2791,7 @@ SW1 1-5:    Base Memory Address Select
 SW2 1-8:    Node ID Select (ID0-ID7)
 SW3 1-5:    IRQ Select   
     6-7:    Extra Timeout
-    8  :    Rom Enable   
+    8  :    ROM Enable   
 JP1         Led connector
 BNC         Coax connector
 
@@ -3089,7 +3089,7 @@ Tiara LanCard of Tiara Computer Systems.
 0 = Jumper Installed
 1 = Open
 
-Top Jumper line Bit 7 = Rom Enable 654=Memory location 321=I/O
+Top Jumper line Bit 7 = ROM Enable 654=Memory location 321=I/O
 
 Settings for Memory Location (Top Jumper Line)
 456     Address selected
index 3bb2f6d961937207b206554590316b416d1949ee..2cdb6db629145c966a13a410c6acd04266579e05 100644 (file)
@@ -1,4 +1,3 @@
-
 ----------------------------------------------------------------------------
 NOTE:  See also arcnet-hardware.txt in this directory for jumper-setting
 and cabling information if you're like many of us and didn't happen to get a
@@ -92,10 +91,10 @@ ARCnet:
        http://www.perftech.com/ or ftp to ftp.perftech.com.
        
 Novell makes a networking stack for DOS which includes ARCnet drivers.  Try
-ftp'ing to ftp.novell.com.
+FTPing to ftp.novell.com.
 
 You can get the Crynwr packet driver collection (including arcether.com, the
-one you'll want to use with arcnet cards) from
+one you'll want to use with ARCnet cards) from
 oak.oakland.edu:/simtel/msdos/pktdrvr. It won't work perfectly on a 386+
 without patches, though, and also doesn't like several cards.  Fixed
 versions are available on my WWW page, or via e-mail if you don't have WWW
@@ -183,7 +182,7 @@ Loadable Module Support
 -----------------------
 
 Configure and rebuild Linux.  When asked, answer 'm' to "Generic ARCnet 
-support" and to support for your ARcnet chipset if you want to use the
+support" and to support for your ARCnet chipset if you want to use the
 loadable module. You can also say 'y' to "Generic ARCnet support" and 'm' 
 to the chipset support if you wish.
 
@@ -269,7 +268,7 @@ Windows:  See DOS :)  Trumpet Winsock works fine with either the Novell or
        Arcether client, assuming you remember to load winpkt of course.
 
 LAN Manager and Windows for Workgroups: These programs use protocols that
-        are incompatible with the internet standard.  They try to pretend
+        are incompatible with the Internet standard.  They try to pretend
         the cards are Ethernet, and confuse everyone else on the network. 
         
         However, v2.00 and higher of the Linux ARCnet driver supports this
@@ -288,7 +287,7 @@ Windows 95: Tools are included with Win95 that let you use either the LANMAN
        you're completely insane, and/or you need to build some kind of
        hybrid network that uses both encapsulation types.
 
-OS2: I've been told it works under Warp Connect with an ARCnet driver from
+OS/2: I've been told it works under Warp Connect with an ARCnet driver from
        SMC.  You need to use the 'arc0e' interface for this.  If you get
        the SMC driver to work with the TCP/IP stuff included in the
        "normal" Warp Bonus Pack, let me know.
@@ -309,7 +308,7 @@ Using Multiprotocol ARCnet
 The ARCnet driver v2.10 ALPHA supports three protocols, each on its own
 "virtual network device":
 
-       arc0  - RFC1201 protocol, the official internet standard which just
+       arc0  - RFC1201 protocol, the official Internet standard which just
                happens to be 100% compatible with Novell's TRXNET driver. 
                Version 1.00 of the ARCnet driver supported _only_ this
                protocol.  arc0 is the fastest of the three protocols (for
@@ -331,13 +330,13 @@ The ARCnet driver v2.10 ALPHA supports three protocols, each on its own
                reasons yet to be determined.  (Probably it's the smaller
                MTU that does it.)
                
-       arc0s - The "[s]imple" RFC1051 protocol is the "previous" internet
+       arc0s - The "[s]imple" RFC1051 protocol is the "previous" Internet
                standard that is completely incompatible with the new
                standard.  Some software today, however, continues to
                support the old standard (and only the old standard)
                including NetBSD and AmiTCP.  RFC1051 also does not support
                RFC1201's packet splitting, and the MTU of 507 is still
-               smaller than the internet "requirement," so it's quite
+               smaller than the Internet "requirement," so it's quite
                possible that you may run into problems.  It's also slower
                than RFC1201 by about 25%, for the same reason as arc0e.
                
@@ -388,16 +387,16 @@ can set up your network then:
    Linux but runs the free Microsoft LANMAN Client instead.
 
    Worse, one of the Linux computers (freedom) also has a modem and acts as
-   a router to my internet provider.  The other Linux box (insight) also has
+   a router to my Internet provider.  The other Linux box (insight) also has
    its own IP address and needs to use freedom as its default gateway.  The
-   XT (patience), however, does not have its own internet IP address and so
+   XT (patience), however, does not have its own Internet IP address and so
    I assigned it one on a "private subnet" (as defined by RFC1597).
 
    To start with, take a simple network with just insight and freedom. 
    Insight needs to:
        - talk to freedom via RFC1201 (arc0) protocol, because I like it
          more and it's faster.
-       - use freedom as its internet gateway.
+       - use freedom as its Internet gateway.
        
    That's pretty easy to do.  Set up insight like this:
        ifconfig arc0 insight
@@ -417,20 +416,20 @@ can set up your network then:
        /* and default gateway is configured by pppd */
        
    Great, now insight talks to freedom directly on arc0, and sends packets
-   to the internet through freedom.  If you didn't know how to do the above,
+   to the Internet through freedom.  If you didn't know how to do the above,
    you should probably stop reading this section now because it only gets
    worse.
 
    Now, how do I add patience into the network?  It will be using LANMAN
    Client, which means I need the arc0e device.  It needs to be able to talk
    to both insight and freedom, and also use freedom as a gateway to the
-   internet.  (Recall that patience has a "private IP address" which won't
-   work on the internet; that's okay, I configured Linux IP masquerading on
+   Internet.  (Recall that patience has a "private IP address" which won't
+   work on the Internet; that's okay, I configured Linux IP masquerading on
    freedom for this subnet).
    
    So patience (necessarily; I don't have another IP number from my
    provider) has an IP address on a different subnet than freedom and
-   insight, but needs to use freedom as an internet gateway.  Worse, most
+   insight, but needs to use freedom as an Internet gateway.  Worse, most
    DOS networking programs, including LANMAN, have braindead networking
    schemes that rely completely on the netmask and a 'default gateway' to
    determine how to route packets.  This means that to get to freedom or
@@ -449,7 +448,7 @@ can set up your network then:
    
    This way, freedom will send all packets for patience through arc0e,
    giving its IP address as gatekeeper (on the private subnet).  When it
-   talks to insight or the internet, it will use its "freedom" internet IP
+   talks to insight or the Internet, it will use its "freedom" Internet IP
    address.
    
    You will notice that we haven't configured the arc0e device on insight. 
@@ -473,7 +472,7 @@ can set up your network then:
    
                                                     
           [RFC1201 NETWORK]                   [ETHER-ENCAP NETWORK]
-      (registered internet subnet)           (RFC1597 private subnet)
+      (registered Internet subnet)           (RFC1597 private subnet)
   
                              (IP Masquerade)
           /---------------\         *            /---------------\
@@ -523,7 +522,7 @@ found unless you turn on the D_INIT_REASONS debugging flag.
 Once the driver is running, you can run the arcdump shell script (available
 from me or in the full ARCnet package, if you have it) as root to list the
 contents of the arcnet buffers at any time.  To make any sense at all out of
-this, you should grab the pertinent RFC's. (some are listed near the top of
+this, you should grab the pertinent RFCs. (some are listed near the top of
 arcnet.c).  arcdump assumes your card is at 0xD0000.  If it isn't, edit the
 script.
 
diff --git a/Documentation/networking/olympic.txt b/Documentation/networking/olympic.txt
new file mode 100644 (file)
index 0000000..04198ae
--- /dev/null
@@ -0,0 +1,75 @@
+
+IBM PCI Pit/Pit-Phy/Olympic CHIPSET BASED TOKEN RING CARDS README
+
+Release 0.2.0 - Release    
+       June 8th 1999 Peter De Schrijver & Mike Phillips
+
+
+Thanks:
+Erik De Cock, Adrian Bridgett and Frank Fiene for their 
+patience and testing.  
+Paul Norton without whose tr.c code we would have had
+a lot more work to do.
+Options:
+
+The driver accepts three options: ringspeed, pkt_buf_sz, and  
+message_level.
+
+These options can be specified differently for each card found. 
+
+ringspeed:  Has one of three settings 0 (default), 4 or 16.  0 will 
+make the card autosense the ringspeed and join at the appropriate speed, 
+this will be the default option for most people.  4 or 16 allow you to 
+explicitly force the card to operate at a certain speed.  The card will fail 
+if you try to insert it at the wrong speed. (Although some hubs will allow 
+this so be *very* careful).  The main purpose for explicitly setting the ring
+speed is for when the card is first on the ring.  In autosense mode, if the card
+cannot detect any active monitors on the ring it will not open, so you must 
+re-init the card at the appropriate speed.  Unfortunately at present the only
+way of doing this is rmmod and insmod which is a bit tough if it is compiled
+in the kernel.
+
+pkt_buf_sz:  This is this initial receive buffer allocation size.  This will
+default to 4096 if no value is entered. You may increase performance of the 
+driver by setting this to a value larger than the network packet size, although
+the driver now re-sizes buffers based on MTU settings as well. 
+
+message_level: Controls level of messages created by the driver. Defaults to 0:
+which only displays start-up and critical messages.  Presently any non-zero 
+value will display all soft messages as well.  NB This does not turn 
+debuging messages on, that must be done by modified the source code.
+
+Multi-card:
+
+The driver will detect multiple cards and will work with shared interrupts,
+each card is assigned the next token ring device, i.e. tr0 , tr1, tr2.  The 
+driver should also happily reside in the system with other drivers.  It has 
+been tested with ibmtr.c running, and I personnally have had one Olicom PCI 
+card and two IBM olympic cards (all on the same interrupt), all running
+together. 
+
+Variable MTU size:
+
+The driver can handle a MTU size upto either 4500 or 18000 depending upon 
+ring speed.  The driver also changes the size of the receive buffers as part
+of the mtu re-sizing, so if you set mtu = 18000, you will need to be able
+to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring 
+position = 296,000 bytes of memory space, plus of course anything 
+necessary for the tx sk_buff's.  Remember this is per card, so if you are
+building routers, gateway's etc, you could start to use a lot of memory
+real fast.
+
+Network Monitor Mode:
+
+By modifying the #define OLYMPIC_NETWORK_MONITOR from 0 to 1 in the 
+source code the driver will implement a quasi network monitoring 
+mode.  All unexpected MAC frames (beaconing etc.) will be received
+by the driver and the source and destination addresses printed. 
+Also an entry will be added in  /proc/net called olympic_tr. This 
+displays low level information about the configuration of the ring and
+the adapter. This feature has been designed for network adiministrators
+to assist in the diagnosis of network / ring problems.
+
+6/8/99 Peter De Schrijver and Mike Phillips
+
index 14fadf3fe24a6a2308ad18c2abf2275641aea284..f33121e0ccbfde10e170d841fa8fb2147eaec265 100644 (file)
@@ -1,6 +1,6 @@
-Soundcore      Notes on Modular Sound Drivers and Soundcore
+Introduction   Notes on Modular Sound Drivers and Soundcore
 Wade Hampton 
-11/20/1998
+6/30/1999
 
 Purpose:  
 ========
@@ -10,13 +10,21 @@ support modules sound.o, soundlow.o and soundcore.o.
 
 Note, some of this probably should be added to the Sound-HOWTO!
 
+
 Copying:
 ========
 none
 
+
 History:
 ========
-0.1.0  11/20/1998  First version
+0.1.0  11/20/1998  First version, draft
+1.0.0  11/1998     Alan Cox changes, incorporation in 2.2.0
+                   as /usr/src/linux/Documentation/sound/Introduction
+1.1.0  6/30/1999   Second version, added notes on making the drivers,
+                   added info on multiple sound cards of similar types,]
+                   added more diagnostics info, added info about esd.
+                   added info on OSS and ALSA.
 
 
 Modular Sound Drivers:
@@ -58,6 +66,53 @@ Warning, the options for different cards sometime use different names
 for the same or a similar feature (dma1= versus dma16=).  As a last 
 resort, inspect the code (search for MODULE_PARM).
 
+Notes:
+
+1.  There is a new OpenSource sound driver called ALSA which is
+    currently under development:  http://www.alsa-project.org/
+    I have not tried it nor am I aware of its status, but it is
+    currently under development.
+
+2.  The commercial OSS driver may be obtained from the site:
+    http://www/opensound.com.  This may be used for cards that
+    are unsupported by the kernel driver, or may be used
+    by other operating systems.  
+
+3.  The enlightenment sound daemon may be used for playing
+    multiple sounds at the same time via a single card, eliminating
+    some of the requirements for multiple sound card systems.  For
+    more information, see:  http://www.tux.org/~ricdude/EsounD.html  
+    The "esd" program may be used with the real-player and mpeg 
+    players like mpg123 and x11amp.
+
+
+Building the Modules:
+=====================
+
+This document does not provide full details on building the 
+kernel, etc.  The notes below apply only to making the kernel
+sound modules.   If this conflicts with the kernel's README,
+the README takes precedence. 
+
+1.  To make the kernel sound modules, cd to your /usr/src/linux
+    directory (typically) and type make config, make menuconfig, 
+    or make xconfig (to start the command line, dialog, or x-based
+    configuration tool).  
+
+2.  Select the Sound option and a dialog will be displayed.  
+
+3.  Select M (module) for "Sound card support".
+
+4.  Select your sound driver(s) as a module.  For ProAudio, Sound
+    Blaster, etc., select M (module) for OSS sound modules.
+    [thanks to marvin stodolsky <stodolsk@erols.com>]A
+
+5.  Make the kernel (e.g., make dep ; make bzImage), and install
+    the kernel.
+
+6.  Make the modules and install them (make modules; make modules_install).
+
+
 
 INSMOD:
 =======
@@ -82,6 +137,9 @@ echo Starting sound blaster....
 /sbin/insmod uart401
 /sbin/insmod sb io=$SB_BASE irq=$SB_IRQ dma=$SB_DMA dma16=$SB_DMA2 mpu_io=$SB_MP
 
+When using sound as a module, I typically put these commands
+in a file such as /root/soundon.sh.
+
 
 MODPROBE:
 =========
@@ -117,8 +175,8 @@ which other modules may be checked by:
        soundcore               1968   8  [sb sound]
 
 
-Removing Sound:
-===============
+Removing Sound: 
+=============== 
 
 Sound may be removed by using /sbin/rmmod in the reverse order
 in which you load the modules.  Note, if a program has a sound device
@@ -134,6 +192,25 @@ in the reverse order in which I loaded the modules):
 /sbin/rmmod soundlow
 /sbin/rmmod soundcore
 
+When using sound as a module, I typically put these commands
+in a script such as /root/soundoff.sh.
+
+
+Removing Sound for use with OSS: 
+================================ 
+
+If you get really stuck or have a card that the kernel modules
+will not support, you can get a commercial sound driver from
+http://www.opensound.com.  Before loading the commercial sound
+driver, you should do the following:
+
+1.  remove sound modules (detailed above)
+2.  remove the sound modules from /etc/conf.modules
+3.  move the sound modules from /lib/modules/<kernel>/misc
+    (for example, I make a /lib/modules/<kernel>/misc/tmp
+    directory and copy the sound module files to that 
+    directory).
+
 
 Multiple Sound Cards:
 =====================
@@ -154,11 +231,30 @@ All you have to do is to load the one you want as /dev/dsp
 first (in my case "sb") and then load the other one
 (in my case "cs4232").
 
+If you have two cards of the same type that are jumpered 
+cards or different PnP revisions, you may load the same 
+module twice.  For example, I have a SoundBlaster vibra 16
+and an older SoundBlaster 16 (jumpers).  To load the module
+twice, you need to do the following:
+
+1.  Copy the sound modules to a new name.  For example
+    sb.o could be copied (or symlinked) to sb1.o for the
+    second SoundBlasster.
+
+2.  Make a second entry in /etc/conf.modules, for example,
+    sound1 or sb1.  This second entry should refer to the
+    new module names for example sb1, and should include
+    the I/O, etc. for the second sound card.
+
+3.  Update your soundon.sh script, etc.
+
 Warning:  I have never been able to get two PnP sound cards of the
 same type to load at the same time.  I have tried this several times
 with the Soundblaster Vibra 16 cards.  OSS has indicated that this
 is a PnP problem....  If anyone has any luck doing this, please 
-send me an E-MAIL.  PCI sound cards should not have this problem.
+send me an E-MAIL.  PCI sound cards should not have this problem.a
+Since this was originally release, I have received a couple of 
+mails from people who have accomplished this!
 
 
 Sound Problems:
@@ -175,6 +271,8 @@ in the Sound-HOWTO).
       write down what addresses, IRQ, and DMA channels
       those were using for the same hardware.  You probably 
       can use these addresses, IRQs, and DMA channels.
+      You should really do this BEFORE attempting to get
+      sound working!
   
   B)  Check (cat) /proc/interrupts, /proc/ioports,
       and /proc/dma.  Are you trying to use an address,
@@ -184,22 +282,44 @@ in the Sound-HOWTO).
       may need a kernel patch to get this device).
   
   D)  Inspect your /var/log/messages file.  Often that will 
-      indicate what IRQ or IO port could not be obtained
+      indicate what IRQ or IO port could not be obtained.
   
   E)  Try another port or IRQ.  Note this may involve 
       using the PnP tools to move the sound card to 
-      another location.
+      another location.  Sometimes this is the only way 
+      and it is more or less trial and error.
 
-2)  If you get motorboating (the same sound or part of a 
+2)  If you get motor-boating (the same sound or part of a 
     sound clip repeated), you probably have either an IRQ
-    or DMA conflict.  Move the card to another address.  This
-    has happened to me when playing long files when I had 
-    an IRQ conflict.
-
-3)  Ask for help on the sound list or send E-MAIL to the
+    or DMA conflict.  Move the card to another IRQ or DMA
+    port.  This has happened to me when playing long files 
+    when I had an IRQ conflict.
+
+3.  If you get dropouts or pauses when playing high sample
+    rate files such as using mpg123 or x11amp/xmms, you may 
+    have too slow of a CPU and may have to use the options to 
+    play the files at 1/2 speed.  For example, you may use
+    the -2 or -4 option on mpg123.  You may also get this
+    when trying to play mpeg files stored on a CD-ROM
+    (my Toshiba T8000 PII/366 sometimes has this problem).
+
+4.  If you get "cannot access device" errors, your /dev/dsp
+    files, etc. may be set to owner root, mode 600.  You 
+    may have to use the command:
+      chmod 666 /dev/dsp /dev/mixer /dev/audio
+
+5.  If you get "device busy" errors, another program has the
+    sound device open.  For example, if using the Enlightenment
+    sound daemon "esd", the "esd" program has the sound device.
+    If using "esd", please RTFM the docs on ESD.  For example,
+    esddsp <program> may be used to play files via a non-esd
+    aware program.
+
+
+6)  Ask for help on the sound list or send E-MAIL to the
     sound driver author/maintainer.
 
-4)  Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB).
+7)  Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB).
 
 
 Configuring Sound:
@@ -210,7 +330,8 @@ There are several ways of configuring your sound:
 1)  Hardcoded in the kernel at compile time (not applicable when
     using sound modules).  This was the OLD way!
 
-2)  On the command line when using insmod.
+2)  On the command line when using insmod or in a bash script
+    using command line calls to load sound.
 
 3)  In /etc/conf.modules when using modprobe.
 
@@ -224,7 +345,6 @@ And I am sure, several other ways.
 Anyone want to write a linuxconf module for configuring sound?
 
 
-
 For More Information (RTFM):
 ============================
 1)  Information on kernel modules:  linux/Documentation/modules.txt
@@ -242,8 +362,12 @@ For More Information (RTFM):
 
 7)  The sndconfig and rhsound documentation from Red Hat.
 
-8)  The Linux-sound mailing list:  sound-list@redhat.com
+8)  The Linux-sound mailing list:  sound-list@redhat.com.
 
+9)  Enlightenment documentation (for info on esd)
+    http://www.tux.org/~ricdude/EsounD.html.
+
+10) ALSA home page:  http://www.alsa-project.org/
 
 
 Contact Information:
@@ -251,3 +375,4 @@ Contact Information:
 Wade Hampton:  (whampton@staffnet.com)
 
 
+
index fb07d6a0ad0d8ff4a384d76e168d2df92fb5b518..a51a4aebbaadb70437bf6544c617afff1c5a4a77 100644 (file)
@@ -46,6 +46,21 @@ possible for most people with PnP BIOS.  If it does not work for you,
 then email me if you are willing to experiment in an effort to make it
 work.
 
+************************************************************************
+* I have now had two such machines, and I have fixed this to work
+* properly when built into the kernel.  The Toshiba Libretto series, or
+* at least models 70CT and 110CT which I have owned, use a Yamaha
+* OPL3-SAx (OPL3-SA3 according to documentation) sound chip, IRQ 5,
+* IO addresses 220/530/388/330/370 and DMA 1,0 (_not_ 0,1).  All these
+* configuration settings can be gathered by booting another OS which
+* recognizes the card already.
+*
+* I have made things 'just work' for the non-modular case on such
+* machines when configured properly.
+*
+* David Luyer <luyer@ucs.uwa.edu.au>
+************************************************************************
+
 If you are using isapnp, follow the directions in its documentation to
 produce a configuration file.  Here is the relevant excerpt I use for
 my SAx card from my isapnp.conf:
index cf062682a1f8ddcf68d410616bfc82fe0d6b89d7..fccc16512846c7be89db599f1788cc07bb51e947 100644 (file)
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/           kernel version 2.2.5
+Documentation for /proc/sys/           kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 'Why', I hear you ask, 'would anyone even _want_ documentation
index b88d5ed5c007de70872b2a950b00d27c1265f3bb..ed53d96c7f5ba1c553be6a838a5f224cacd411d6 100644 (file)
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/fs/*       kernel version 2.2.5
+Documentation for /proc/sys/fs/*       kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
index 8f65d6037064fd2e7064f27b8022b7fdf0324de5..01fbbc9c420c5f9c275b70492fff18d01899b71b 100644 (file)
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/kernel/*   kernel version 2.2.5
+Documentation for /proc/sys/kernel/*   kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
@@ -76,12 +76,21 @@ to decide what to do with it.
 
 domainname & hostname:
 
-These files can be controlled to set the domainname and
-hostname of your box. For the classic darkstar.frop.org
-a simple:
+These files can be used to set the NIS/YP domainname and the
+hostname of your box in exactly the same way as the commands
+domainname and hostname, i.e.:
 # echo "darkstar" > /proc/sys/kernel/hostname
-# echo "frop.org" > /proc/sys/kernel/domainname
-would suffice to set your hostname and domainname.
+# echo "mydomain" > /proc/sys/kernel/domainname
+has the same effect as
+# hostname "darkstar" > /proc/sys/kernel/hostname
+# domainname "mydomain" > /proc/sys/kernel/domainname
+
+Note, however, that the classic darkstar.frop.org has the
+hostname "darkstar" and DNS (Internet Domain Name Server)
+domainname "frop.org", not to be confused with the NIS (Network
+Information Service) or YP (Yellow Pages) domainname. These two
+domain names are in general different. For a detailed discussion
+see the hostname(1) man page.
 
 ==============================================================
 
index 4a52862c5b1af840cf0abbeb511b2b06fd6950b0..ae1ecac6f85aa5cf554a773bd52e088e1dcb64ec 100644 (file)
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/sunrpc/*   kernel version 2.2.5
+Documentation for /proc/sys/sunrpc/*   kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
index 470c001d3389ccca8e2409272afc7ff3b50ddd29..5fe4af170183d3ab21f89e8e5f5bed83dc7f53b6 100644 (file)
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/vm/*       kernel version 2.2.5
+Documentation for /proc/sys/vm/*       kernel version 2.2.10
        (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
index 1af60ed4eb39de60268a2f3e5227869eca3351ce..b4b9d0dcc61ff9e184f8f150f31c00d1dbc78824 100644 (file)
@@ -1,6 +1,9 @@
 <HTML><HEAD>
-<TITLE>Video4Linux Kernel API Reference v0.1:19980516</TITLE>
+<TITLE>Video4Linux Kernel API Reference v0.1:19990430</TITLE>
 </HEAD>
+<! Revision History: >
+<!   4/30/1999 - Fred Gleason (fredg@wava.com)>
+<! Documented extensions for the Radio Data System (RDS) extensions >
 <BODY bgcolor="#ffffff">
 <H3>Devices</H3>
 Video4Linux provides the following sets of device files. These live on the
@@ -117,7 +120,7 @@ fields available to the user.
 </TABLE>
 <P>
 Merely setting the window does not enable capturing. Overlay capturing
-is activatied by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
+is activated by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
 disabled by passing it a value of 0. 
 <P>
 Some capture devices can capture a subfield of the image they actually see.
@@ -150,7 +153,7 @@ the <b>struct video_channel</b> is filled in with information about the
 nature of the channel itself.
 <P>
 The <b>VIDIOCSCHAN</b> ioctl takes an integer argument and switches the
-capture to this input. It is not defined whether paramters such as colour
+capture to this input. It is not defined whether parameters such as colour
 settings or tuning are maintained across a channel switch. The caller should
 maintain settings as desired for each channel. (This is reasonable as 
 different video inputs may have different properties).
@@ -249,6 +252,8 @@ The following flags exist
 <TR><TD><b>VIDEO_TUNER_LOW</b><TD>Frequency is in a lower range</TD>
 <TR><TD><b>VIDEO_TUNER_NORM</b><TD>The norm for this tuner is settable</TD>
 <TR><TD><b>VIDEO_TUNER_STEREO_ON</b><TD>The tuner is seeing stereo audio</TD>
+<TR><TD><b>VIDEO_TUNER_RDS_ON</b><TD>The tuner is seeing a RDS datastream</TD>
+<TR><TD><b>VIDEO_TUNER_MBS_ON</b><TD>The tuner is seeing a MBS datastream</TD>
 </TABLE>
 <P>
 The following modes are defined
@@ -349,6 +354,21 @@ devices if any exist. The video_unit structure has the following fields.
 <TR><TD><b>teletext</b><TD>Teletext device</TD>
 </TABLE>
 <P>
-
+<H3>RDS Datastreams</H3>
+For radio devices that support it, it is possible to receive Radio Data
+System (RDS) data by means of a read() on the device.  The data is packed in
+groups of three, as follows:
+<TABLE>
+<TR><TD>First Octet</TD><TD>Least Siginificant Byte of RDS Block</TD></TR>
+<TR><TD>Second Octet</TD><TD>Most Siginificant Byte of RDS Block
+<TR><TD>Third Octet</TD><TD>Bit 7:</TD><TD>Error bit.  Indicates that
+an uncorrectable error occured during reception of this block.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bit 6:</TD><TD>Corrected bit.  Indicates that  
+an error was corrected for this data block.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bits 5-3:</TD><TD>Reeived Offset.  Indicates the  
+offset received by the sync system.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bits 2-0:</TD><TD>Offset Name.  Indicates the  
+offset applied to this data.</TD></TR>
+</TABLE>
 </BODY>
 </HTML>
diff --git a/Documentation/video4linux/README.buz b/Documentation/video4linux/README.buz
new file mode 100644 (file)
index 0000000..b9eb9cd
--- /dev/null
@@ -0,0 +1,212 @@
+Iomega Buz Driver for Linux
+===========================
+
+by Rainer Johanni <Rainer@Johanni.de>
+
+Compiling and Loading the Driver
+================================
+
+You must run a 2.2.x kernel in order to use this driver.
+
+To compile the driver, just type make.
+
+Besides the files in this directory, the driver needs the
+'videodev' and the 'i2c' module from the Linux kernel.
+In order to get these modules available, enable module support
+for VIDEODEV and BTTV (which implies i2c) in your kernel
+configuration. You find these devices in the menu
+"Character Devices" in your Kernel Configuration.
+
+Before you load the driver you must have a video device
+at major device node 81. If you don't have it yet, do the
+following (as root!):
+
+cd /dev
+mknod video0 c 81 0
+ln -s video0 video
+
+Edit the 'update' script if you want to give the driver
+special options and then type (as root)
+
+./update
+
+to insert all the necessary modules into the kernel.
+
+If you want to make full use of the Video for Linux uncompressed
+grabbing facilities, you must either
+
+- obtain and install the "big_physarea patch" for your kernel and
+  set aside the necessary memory during boot time.
+  There seem to be several versions of this patch against
+  various kernel versions floating around in the net,
+  you may obtain one e.g. from:
+  http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz
+  You also have to compile your driber AFTER installing that patch
+  in order to get it working
+
+  or
+
+- start your kernel with the mem=xxx option, where xxx is your
+  real memory minus the memory needed for the buffers.
+  For doing this add an entry in lilo.conf (if you use lilo):
+    append "mem=xxxM"
+  or add a line in your linux.par file (if you use loadlin):
+    mem=xxxM
+
+The second method is by far easier, however it is dangerous
+if more than one driver at a time has the idea to use the memory
+leftover by setting the mem=xxx parameter below the actual
+memory size.
+
+Read also below how to use this memory!
+
+
+
+Driver Options
+==============
+
+You are able to customize the behavior of the driver by giving
+it some options at start time.
+
+default_input, default_norm
+---------------------------
+
+As soon as the driver is loaded, the Buz samples video signals
+from one of its input ports and displays it on its output.
+The driver uses the Composite Input and the video norm PAL for this.
+If you want to change this default behavior, set default_input=1
+(for S-VHS input) or default_norm=1 for NTSC.
+
+v4l_nbufs, v4l_bufsize
+----------------------
+
+In order to make to make full use of the Video for Linux picture
+grabbing facilities of the driver (which are needed by many
+Video for Linux applications), the driver needs a set of
+physically contiguous buffers for grabbing. These parameters
+determine how many buffers of which size the driver will
+allocate at open (the open will fail if it is unable to do so!).
+
+These values do not affect the MJPEG grabbing facilities of the driver,
+they are needed for uncompressed image grabbing only!!!
+
+v4l_nbufs is the number of buffers to allocate, a value of 2 (the default)
+should be sufficient in allmost all cases. Only special applications
+(streaming captures) will need more buffers and then mostly the
+MJPEG capturing features of the Buz will be more apropriate.
+So leave this parameter at it's default unless you know what you do.
+
+The things for v4l_bufsize are more complicated:
+v4l_bufsize is set by default to 128 [KB] which is the maximum
+amount of physically contiguous memory Linux is able to allocate
+without kernel changes. This is sufficient for grabbing 24 bit color images
+up to sizes of approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072).
+
+In order to be able to capture bigger images you have either to
+- obtain and install the "big_physarea patch" and set aside
+  the necessary memory during boot time or
+- start your kernel with the mem=xxx option, where xxx is your
+  real memory minus the memory needed for the buffers.
+In that case, usefull settings for v4l_bufsize are
+- 1296 [Kb] for grabbing 24 bit images of max size 768*576
+- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!)
+You may reduce these numbers accordingly if you know you are only
+grabbing 720 pixels wide images or NTSC images (max height 480).
+
+In some cases it may happen that Linux isn't even able to obtain
+the default 128 KB buffers. If you don't need uncompressed image
+grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4)
+in order to be able to open the video device.
+
+vidmem
+------
+
+The video mem address of the video card.
+The driver has a little database for some videocards
+to determine it from there. If your video card is not in there
+you have either to give it to the driver as a parameter
+or set in in a VIDIOCSFBUF ioctl
+
+The videocard database is contained in the file "videocards.h"
+Gernot Ziegler wants to keep an actual version of that file.
+If your card is not contained in that file, look at
+http://www.lysator.liu.se/~gz/buz/ for an actual version of
+"videocards.h".
+
+triton, natoma
+--------------
+
+The driver tries to detect if you have a triton or natome chipset
+in order to take special messures for these chipsets.
+If this detection fails but you are sure you have such a chipset,
+set the corresponding variable to 1.
+This is a very special option and may go away in the future.
+
+
+
+Programming interface
+=====================
+
+This driver should be fully compliant to Video for Linux, so all
+tools working with Video for Linux should work with (hopefully)
+no problems.
+
+A description of the Video for Linux programming interace can be found at:
+http://roadrunner.swansea.linux.org.uk/v4lapi.shtml
+
+Besides the Video for Linux interface, the driver has a "proprietary"
+interface for accessing the Buz's MJPEG capture and playback facilities.
+
+The ioctls for that interface are as follows:
+
+BUZIOC_G_PARAMS
+BUZIOC_S_PARAMS
+
+Get and set the parameters of the buz. The user should allways
+do a BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default
+settings, change what he likes and then make a BUZIOC_S_PARAMS call.
+A typical application should at least set the members
+input, norm and decimation of the struct buz_params.
+For a full description of all members see "buz.h"
+
+BUZIOC_REQBUFS
+
+Before being able to capture/playback, the user has to request
+the buffers he is wanting to use. Fill the structure
+buz_requestbuffers with the size (recommended: 256*1024) and
+the number (recommended 32 up to 256). There are no such restrictions
+as for the Video for Linux buffers, you should LEAVE SUFFICIENT
+MEMORY for your system however, else strange things will happen ....
+On return, the buz_requestbuffers structure contains number and
+size of the actually allocated buffers.
+You should use these numbers for doing a mmap of the buffers
+into the user space.
+The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap
+maps the MJPEG buffer instead of the V4L buffers.
+
+BUZIOC_QBUF_CAPT
+BUZIOC_QBUF_PLAY
+
+Queue a buffer for capture or playback. The first call also starts
+streaming capture. When streaming capture is going on, you may
+only queue further buffers or issue syncs until streaming
+capture is switched off again with a argument of -1 to
+a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl.
+
+BUZIOC_SYNC
+
+Issue this ioctl when all buffers are queued. This ioctl will
+block until the first buffer becomes free for saving its
+data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY).
+
+BUZIOC_G_STATUS
+
+Get the status of the input lines (video source connected/norm).
+This ioctl may be subject to change.
+
+
+
+
+
+See the examples directory delivered with this driver
+for actual coding examples!
index 6148f859c7d189bbddcaebebceaf00c1ef3cba82..0371d2e74e75ae39dc5d14792427b0a42d53e74d 100644 (file)
@@ -17,9 +17,9 @@
   If this 64MB area overlaps the IO memory of the Bt848 you also have to
   remap this. E.g.: insmod bttv vidmem=0xfb0 remap=0xfa0
 
-  If the videomemory is found at the right place and there are no address
-  conflicts but still no picture (or the computer even crashes.),
-  try disabling features of your PCI chipset in the BIOS Setup.
+  If the video memory is found at the right place and there are no address
+  conflicts but still no picture (or the computer even crashes),
+  try disabling features of your PCI chipset in the BIOS setup.
 
   Frank Kapahnke <frank@kapahnke.prima.ruhr.de> also reported that problems
   with his S3 868 went away when he upgraded to XFree 3.2.
   
   Disable backing store by starting X with the option "-bs"
 
-- When using 32bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
+- When using 32 bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
   can sometimes lock up if you use more than 1 bt848 card at the same time.
   You will always get pixel errors when e.g. using more than 1 card in full
   screen mode. Maybe we need something faster than the PCI bus ...
 
 
-- Some S3 cards and the Matrox Mystique will produce pixel erros with
-  full resolution in 32bit mode.
+- Some S3 cards and the Matrox Mystique will produce pixel errors with
+  full resolution in 32-bit mode.
 
-- Some video cards have problems with Accelerated X 4.1
\ No newline at end of file
+- Some video cards have problems with Accelerated X 4.1
index 53d04f59b79b78eb153e0dd34faefbca3581ec78..f22f9c0cabff2134e7f6a6b1487d5f8fd74269e9 100644 (file)
@@ -6,7 +6,7 @@ Support is in now:
 
 So you should have TV with (stereo) sound now.  Radio does _not_ work.
 It probably does not work with sat receivers. I can't test this and
-therefore hav'nt added support for it yet. If someone needs this and
+therefore have not added support for it yet. If someone needs this and
 can help testing the sat stuff, drop me a note.
 
   Gerd
index 0da6d9f8e280062bfc349eb2519ea8b9225db204..2085399da7d4c3274b39c133bd253523af370ef1 100644 (file)
@@ -17,7 +17,7 @@ Many thanks to:
   components on their cards. (E.g. how the tuner type is detected)
   Without their card I could not have debugged the NTSC mode.
        
-- Hauppauge for telling how the sound input is selected and what compenents
+- Hauppauge for telling how the sound input is selected and what components
   they do and will use on their radio cards.
   Also many thanks for faxing me the FM1216 data sheet.
 
index a477c2344059270b562f7c4681ee9a4a2e8fab96..832d72ee0de497f87115d430eb6bd68e255bef62 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/signal.h>
 #include <linux/stddef.h>
 
 #include <asm/bitops.h>
index 68bf5aa1f99620c3bbaea14fa8fdcf5d7a32ef93..ff0c548b465f78827cc4106cf22672c808c1d7a4 100644 (file)
@@ -27,9 +27,7 @@
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/config.h>
-#include <linux/unistd.h>
 #include <linux/delay.h>
-#include <linux/smp.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 
index c874a1ba85ba724bd85359d334f1347b2e747fc9..4e49885b866c7ede24b16f20cd4af06c44469236 100644 (file)
@@ -23,8 +23,6 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
index fb05fc6fb3c98a479b78baece29fe34d5af1ed84..e4a6a6911cae5d164d2732f20a5c4afbf0895150 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/sched.h>
 #include <linux/init.h>
 
 #include <asm/system.h>
index a2c8ecb37b93ef4a81421d327a7e8c79c9fd79af..e45fcda2d0b11e3046c07135671cbf709039e9cb 100644 (file)
@@ -753,19 +753,29 @@ bootsect_panic_mess:
 ! This routine checks that the keyboard command queue is empty
 ! (after emptying the output buffers)
 !
-! No timeout is used - if this hangs there is something wrong with
-! the machine, and we probably couldn't proceed anyway.
+! Some machines have delusions that the keyboard buffer is always full
+! with no keyboard attached...
+
 empty_8042:
+       push    ecx
+       mov     ecx,#0xFFFFFF
+
+empty_8042_loop:
+       dec     ecx
+       jz      empty_8042_end_loop
+
        call    delay
        in      al,#0x64        ! 8042 status port
        test    al,#1           ! output buffer?
        jz      no_output
        call    delay
        in      al,#0x60        ! read it
-       jmp     empty_8042
+       jmp     empty_8042_loop
 no_output:
        test    al,#2           ! is input buffer full?
-       jnz     empty_8042      ! yes - loop
+       jnz     empty_8042_loop ! yes - loop
+empty_8042_end_loop:
+        pop     ecx
        ret
 
 !
index 80656a9971982ce8b61bf12cc623af43eb01c026..881cb153ff81c811a0e3ffa622b6d684b3eae732 100644 (file)
@@ -96,6 +96,7 @@ CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_BLK_DEV_HPT34X is not set
 CONFIG_BLK_DEV_PIIX=y
 # CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_CPQ_DA is not set
 
 #
 # Additional Block Devices
index ad522c6c755eb2885cf1e0c8716c4821ce6fcb3c..08dde1ed7c9c4c70ef7c5f02dfc0719041edcdd8 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/config.h>
-#include <linux/unistd.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
index 202de42d756378060315c504d8c898e04dabd8c1..c0721b4825ab9b450ec13cff8094b609b9d0c224 100644 (file)
@@ -11,7 +11,7 @@
  *      Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
  * 
  *  Force Centaur C6 processors to report MTRR capability.
- *      Bart Hartgers <bart@etpmod.phys.tue.nl>, May 199.
+ *      Bart Hartgers <bart@etpmod.phys.tue.nl>, May 1999.
  *
  *  Intel Mobile Pentium II detection fix. Sean Gilley, June 1999.
  */
@@ -690,8 +690,8 @@ static struct cpu_model_info cpu_models[] __initdata = {
            NULL, NULL, NULL, NULL }},
        { X86_VENDOR_INTEL,     6,
          { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
-            NULL, "Pentium II (Deschutes)", "Mobile Pentium II", NULL,
-           NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
+           NULL, "Pentium II (Deschutes)", "Mobile Pentium II", "Pentium III (Katmai)",
+           "Pentium III (Coppermine)", NULL, NULL, NULL, NULL, NULL, NULL }},
        { X86_VENDOR_AMD,       4,
          { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
            "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
@@ -799,16 +799,15 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c))
                        /* Names for the Pentium II Celeron processors 
                            detectable only by also checking the cache size */
                        if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
-                           && (cpu_models[i].x86 == 6)){ 
-                               if(c->x86_model == 6 && c->x86_cache_size == 128) {
+                           && (cpu_models[i].x86 == 6))
+                       {
+                               if(c->x86_model == 5 &&  c->x86_cache_size == 0)
+                                       p = "Celeron (Covington)";                                              
+                               else if(c->x86_model == 6 && c->x86_cache_size == 128)
                                        p = "Celeron (Mendocino)"; 
-                               }
-                               else { 
-                               if (c->x86_model == 5 && c->x86_cache_size == 0) {
-                                       p = "Celeron (Covington)";
-                               }
-                        }
-                    }
+                               else if(c->x86_model == 5 && c->x86_cache_size == 256)
+                                       p = "Celeron (Dixon)";
+                       }
                }
                        
        }
index e5734c82d7f6abfefc9c035fe5cbf555dc9eb462..fe02425ec0b0058d785702dcf03ec93f46fdf362 100644 (file)
@@ -165,8 +165,6 @@ extern u_char const data_sizes_16[32];
 #define signpositive(a) ( (signbyte(a) & 0x80) == 0 )
 #define signnegative(a) (signbyte(a) & 0x80)
 
-#include "fpu_proto.h"
-
 static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
 {
   *(short *)&(y->exp) = *(const short *)&(x->exp); 
index 55f5896c5f9e0fa4ed2934b466585492f0b38d9e..dc8e981e69007046a7634330f7ffbe0218e07260 100644 (file)
@@ -35,7 +35,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <string.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <fcntl.h>
index ec1e8d62436760c17c3ea0188befe583ddb67def..ea48cabb7606c3a2807cb40762cacef53e728022 100644 (file)
@@ -93,7 +93,7 @@ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
 
 if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
-  tristate 'Parallel port support' CONFIG_PARPORT
+source drivers/misc/Config.in
 fi
 endmenu
 
index a476aeb8767f3ecdb9339e74cedbae7c99a40d45..2f3af4f3da03c9934c13bbbec4aec4406ab7edc8 100644 (file)
@@ -62,11 +62,6 @@ CONFIG_KMOD=y
 # CONFIG_I2O_SCSI is not set
 # CONFIG_I2O_PROC is not set
 
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
 #
 # Block devices
 #
index 8b75c936b581feacb6c70d50b0e8bd50209bd0c4..12b01c4e481323d6b34f65408922493944ff5a1b 100644 (file)
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct task_struct * tsk,
-                             struct vm_area_struct * vma, unsigned long addr)
-{
-       pgd_t *pgdir;
-       pmd_t *pgmiddle;
-       pte_t *pgtable;
-       unsigned long page, retval;
-
-repeat:
-       pgdir = pgd_offset(vma->vm_mm, addr);
-       if (pgd_none(*pgdir)) {
-               handle_mm_fault(tsk, vma, addr, 0);
-               goto repeat;
-       }
-       if (pgd_bad(*pgdir)) {
-               printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-               pgd_clear(pgdir);
-               return 0;
-       }
-       pgmiddle = pmd_offset(pgdir, addr);
-       if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk, vma, addr, 0);
-               goto repeat;
-       }
-       if (pmd_bad(*pgmiddle)) {
-               printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-               pmd_clear(pgmiddle);
-               return 0;
-       }
-       pgtable = pte_offset(pgmiddle, addr);
-       if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 0);
-               goto repeat;
-       }
-       page = pte_page(*pgtable);
-       /* This is a hack for non-kernel-mapped video buffers and similar */
-       if (MAP_NR(page) >= MAP_NR(high_memory))
-               return 0;
-       page += addr & ~PAGE_MASK;
-       /* We can't use flush_page_to_ram() since we're running in
-        * another context ...
-        */
-       flush_cache_all();
-       retval = *(unsigned long *) page;
-       flush_cache_all();      /* VCED avoidance  */
-       return retval;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it.  -M.U-
- */
-static void put_long(struct task_struct *tsk,
-                    struct vm_area_struct * vma, unsigned long addr,
-       unsigned long data)
-{
-       pgd_t *pgdir;
-       pmd_t *pgmiddle;
-       pte_t *pgtable;
-       unsigned long page;
-
-repeat:
-       pgdir = pgd_offset(vma->vm_mm, addr);
-       if (!pgd_present(*pgdir)) {
-               handle_mm_fault(tsk, vma, addr, 1);
-               goto repeat;
-       }
-       if (pgd_bad(*pgdir)) {
-               printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-               pgd_clear(pgdir);
-               return;
-       }
-       pgmiddle = pmd_offset(pgdir, addr);
-       if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk, vma, addr, 1);
-               goto repeat;
-       }
-       if (pmd_bad(*pgmiddle)) {
-               printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-               pmd_clear(pgmiddle);
-               return;
-       }
-       pgtable = pte_offset(pgmiddle, addr);
-       if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 1);
-               goto repeat;
-       }
-       page = pte_page(*pgtable);
-       if (!pte_write(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 1);
-               goto repeat;
-       }
-       /* This is a hack for non-kernel-mapped video buffers and similar */
-       if (MAP_NR(page) < MAP_NR(high_memory))
-               flush_cache_all();
-       *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-       if (MAP_NR(page) < MAP_NR(high_memory))
-               flush_cache_all();
-       /*
-        * We're bypassing pagetables, so we have to set the dirty bit
-        * ourselves this should also re-instate whatever read-only mode
-        * there was before
-        */
-       set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-       flush_tlb_page(vma, addr);
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-       unsigned long * result)
-{
-       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-       if (!vma)
-               return -EIO;
-       if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-               unsigned long low,high;
-               struct vm_area_struct * vma_high = vma;
-
-               if (addr + sizeof(long) >= vma->vm_end) {
-                       vma_high = vma->vm_next;
-                       if (!vma_high || vma_high->vm_start != vma->vm_end)
-                               return -EIO;
-               }
-               low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-               high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
-               switch (addr & (sizeof(long)-1)) {
-                       case 1:
-                               low >>= 8;
-                               low |= high << 24;
-                               break;
-                       case 2:
-                               low >>= 16;
-                               low |= high << 16;
-                               break;
-                       case 3:
-                               low >>= 24;
-                               low |= high << 8;
-                               break;
-               }
-               *result = low;
-       } else
-               *result = get_long(tsk, vma, addr);
-       return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-       unsigned long data)
-{
-       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-       if (!vma)
-               return -EIO;
-       if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-               unsigned long low,high;
-               struct vm_area_struct * vma_high = vma;
-
-               if (addr + sizeof(long) >= vma->vm_end) {
-                       vma_high = vma->vm_next;
-                       if (!vma_high || vma_high->vm_start != vma->vm_end)
-                               return -EIO;
-               }
-               low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-               high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
-               switch (addr & (sizeof(long)-1)) {
-                       case 0: /* shouldn't happen, but safety first */
-                               low = data;
-                               break;
-                       case 1:
-                               low &= 0x000000ff;
-                               low |= data << 8;
-                               high &= ~0xff;
-                               high |= data >> 24;
-                               break;
-                       case 2:
-                               low &= 0x0000ffff;
-                               low |= data << 16;
-                               high &= ~0xffff;
-                               high |= data >> 16;
-                               break;
-                       case 3:
-                               low &= 0x00ffffff;
-                               low |= data << 24;
-                               high &= ~0xffffff;
-                               high |= data >> 8;
-                               break;
-               }
-               put_long(tsk, vma, addr & ~(sizeof(long)-1),low);
-               put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
-       } else
-               put_long(tsk, vma, addr, data);
-       return 0;
-}
-
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -322,15 +110,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
        case PTRACE_PEEKTEXT: /* read word at location addr. */ 
        case PTRACE_PEEKDATA: {
                unsigned long tmp;
+               int copied;
 
-               down(&child->mm->mmap_sem);
-               res = read_long(child, addr, &tmp);
-               up(&child->mm->mmap_sem);
-               if (res < 0)
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               res = -EIO;
+               if (copied != sizeof(tmp))
                        goto out;
                res = put_user(tmp,(unsigned long *) data);
+
                goto out;
-               }
+       }
 
        /* Read the word at location addr in the USER area.  */
        case PTRACE_PEEKUSR: {
@@ -394,9 +183,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 
        case PTRACE_POKETEXT: /* write the word at location addr. */
        case PTRACE_POKEDATA:
-               down(&child->mm->mmap_sem);
-               res = write_long(child,addr,data);
-               up(&child->mm->mmap_sem);
+               res = 0;
+               if (access_process_vm(child, addr, &data, sizeof(data), 1)
+                   == sizeof(data))
+                       goto out;
+               res = -EIO;
                goto out;
 
        case PTRACE_POKEUSR: {
index ebdc94dd4b0dc17abbe61cfd0dce08f22c90bd82..0d451c322dc8e59830ef9a297fb71e3e8f505216 100644 (file)
@@ -13,7 +13,6 @@
 #include <asm/offset.h>
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
-#include <asm/current.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsconfig.h>
 #include <asm/mipsregs.h>
index 289e4a649f3d40e7087b56f6f9c39ac0740b02c0..447023634f975b60a2de89b7c987724b6b90bf69 100644 (file)
@@ -30,7 +30,6 @@
 #endif
 #include <linux/ide.h>
 #ifdef CONFIG_RTC
-#include <linux/ioport.h>
 #include <linux/timex.h>
 #endif
 
index fe4a0cf418bb9fdcf3cf1a1a0e5c800625a58027..efc59dee6f2233439295d018745d701163008d4f 100644 (file)
@@ -43,7 +43,7 @@ unsigned long asid_cache;
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
                              unsigned long address)
 {
        struct vm_area_struct * vma;
@@ -59,7 +59,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
                goto no_context;
 #if 0
        printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid,
-              address, writeaccess, regs->cp0_epc);
+              address, write, regs->cp0_epc);
 #endif
        down(&mm->mmap_sem);
        vma = find_vma(mm, address);
@@ -76,14 +76,26 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
  * we can handle it..
  */
 good_area:
-       if (writeaccess) {
+       if (write) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
        } else {
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
-       handle_mm_fault(tsk, vma, address, writeaccess);
+
+       /*
+        * If for any reason at all we couldn't handle the fault,
+        * make sure we exit gracefully rather than endlessly redo
+        * the fault.
+        */
+       {
+               int fault = handle_mm_fault(tsk, vma, address, write);
+               if (fault < 0)
+                       goto out_of_memory;
+               if (!fault)
+                       goto do_sigbus;
+       }
        up(&mm->mmap_sem);
        return;
 
@@ -96,12 +108,12 @@ bad_area:
 
        if (user_mode(regs)) {
                tsk->tss.cp0_badvaddr = address;
-               tsk->tss.error_code = writeaccess;
+               tsk->tss.error_code = write;
 #if 0
                printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n"
                       "%08lx (epc == %08lx, ra == %08lx)\n",
                       tsk->comm,
-                      writeaccess ? "writeaccess to" : "readaccess from",
+                      write ? "write access to" : "read access from",
                       address,
                       (unsigned long) regs->cp0_epc,
                       (unsigned long) regs->regs[31]);
@@ -132,6 +144,31 @@ no_context:
        printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
               "address %08lx, epc == %08lx, ra == %08lx\n",
               address, regs->cp0_epc, regs->regs[31]);
-       die("Oops", regs, writeaccess);
+       die("Oops", regs, write);
        do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+       up(&mm->mmap_sem);
+       printk("VM: killing process %s\n", tsk->comm);
+       if (user_mode(regs))
+               do_exit(SIGKILL);
+       goto no_context;
+
+do_sigbus:
+       up(&mm->mmap_sem);
+
+       /*
+        * Send a sigbus, regardless of whether we were in kernel
+        * or user mode.
+        * XXX Store details about fault for siginfo handling into tss.
+        */
+       force_sig(SIGBUS, tsk);
+
+       /* Kernel mode? Handle exceptions or die */
+       if (!user_mode(regs))
+               goto no_context;
 }
index e8f72f298ce01b3875195ad23377d33e3c299dbe..a221dc59b9ec80cd93fc3578e945bb6b795b2ddc 100644 (file)
@@ -108,7 +108,7 @@ __initfunc(void amiga_init_IRQ(void))
        custom.intreq = 0x7fff;
 
 #ifdef CONFIG_APUS
-       /* Clear any inter-CPU interupt requests. Circumvents bug in
+       /* Clear any inter-CPU interrupt requests. Circumvents bug in
            Blizzard IPL emulation HW (or so it appears). */
        APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
 
index 2335adfb97c8e387a9d396caad0dcebb765f1eac..5a38fa7f032047bc63431126d2125c9edef1bea5 100644 (file)
@@ -30,7 +30,6 @@ void (*kbd_reset_setup) (char *, int) __initdata = 0;
 #include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
-#include <linux/init.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
index 014957be25635effda5e792ff9a655605e79bcea..1d42bf69b2be3ffbc0d80166c98198d8e1fdd165 100644 (file)
@@ -50,7 +50,6 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/gg2.h>
 #include <asm/cache.h>
 #include <asm/prom.h>
index ccef5f36a84532a5b473fe803c00b1cdb0157cdd..985abf6e6295a1358abb7ca8c28aa5408734eda5 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/config.h>
-#include <linux/pci.h>
 #include <linux/openpic.h>
 
 #include <asm/processor.h>
index 462e50691d7f8690fba7b0c35158e2e434aa8ade..d7fef0869b7ae7eb7880f9d1475bf13c990d310a 100644 (file)
 
 #include <asm/system.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/kgdb.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
index 05d46a698b84e0e7729e7b6d878bf48fe96c4d82..c99f6bbd77151a58a955206ace66cdc90221e656 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <linux/ide.h>
 #include <asm/ide.h>
 #include <asm/cache.h>
 #include <asm/dma.h>
index 48c06d6e8255a7cea25ef63436fbc54ba4e722cc..b75b92db4fc6574529bfafa3d52156bf09114286 100644 (file)
@@ -32,7 +32,6 @@
 #endif
 #include <asm/bootx.h>
 #include <asm/machdep.h>
-#include <asm/ide.h>
 
 extern void pmac_init(unsigned long r3,
                       unsigned long r4,
index 2c36a5ae1028de405150f22fd682488fb7ab2f7e..4e476aba36711d7467b173d27420ab8465218577 100644 (file)
@@ -27,7 +27,6 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 
  #include <asm/ap1000/pgtapmmu.h>
index a4ae9497e7049b5525dcb780c424239bc0916f5a..461773e96f753f3a447d1a6f0479cec8309ebd72 100644 (file)
@@ -20,7 +20,6 @@
 #include <asm/ebus.h>
 #include <asm/sbus.h> /* for sanity check... */
 #include <asm/swift.h> /* for cache flushing. */
-
 #include <asm/io.h>
 
 #undef PROM_DEBUG
@@ -39,7 +38,6 @@
 #include <linux/timex.h>
 #include <linux/interrupt.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/oplib.h>
 #include <asm/pcic.h>
index 301747c222513723e2a1c456f1086b464eaa223e..f6a6315a482e2b09c034d590daa1519d22d622c6 100644 (file)
@@ -37,7 +37,6 @@
 #include <asm/delay.h>
 #include <asm/processor.h>
 #include <asm/psr.h>
-#include <asm/system.h>
 #include <asm/elf.h>
 
 extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
index bb80f65ee873d0d590602b25aa4dd03b3571b320..f7b6cdfd0c7cce7a9672a3222a1b55cdb89c648b 100644 (file)
@@ -369,24 +369,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
        case PTRACE_PEEKTEXT: /* read word at location addr. */ 
        case PTRACE_PEEKDATA: {
                unsigned long tmp;
-               int res;
 
-               /* XXX Find out what is really going on. */
-               flush_cache_all();
-
-               /* Non-word alignment _not_ allowed on Sparc. */
-               if(addr & (sizeof(unsigned long) - 1)) {
-                       pt_error_return(regs, EINVAL);
-                       goto out;
-               }
-               down(&child->mm->mmap_sem);
-               res = read_long(child, addr, &tmp);
-               up(&child->mm->mmap_sem);
-               if (res < 0) {
-                       pt_error_return(regs, -res);
-                       goto out;
-               }
-               pt_os_succ_return(regs, tmp, (long *) data);
+               if (access_process_vm(child, addr,
+                                     &tmp, sizeof(tmp), 0) == sizeof(tmp))
+                       pt_os_succ_return(regs, tmp, (long *)data);
+               else
+                       pt_error_return(regs, EIO);
                goto out;
        }
 
@@ -400,22 +388,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
 
        case PTRACE_POKETEXT: /* write the word at location addr. */
        case PTRACE_POKEDATA: {
-               struct vm_area_struct *vma;
-               int res;
-
-               /* Non-word alignment _not_ allowed on Sparc. */
-               if(addr & (sizeof(unsigned long) - 1)) {
-                       pt_error_return(regs, EINVAL);
-                       goto out;
-               }
-               down(&child->mm->mmap_sem);
-               vma = find_extend_vma(child, addr);
-               res = write_long(child, addr, data);
-               up(&child->mm->mmap_sem);
-               if(res < 0)
-                       pt_error_return(regs, -res);
+               if (access_process_vm(child, addr,
+                                     &data, sizeof(data), 1) == sizeof(data))
+                       pt_succ_return(regs, 0);
                else
-                       pt_succ_return(regs, res);
+                       pt_error_return(regs, EIO);
                goto out;
        }
 
index 9426ec0d9f1c4c99fc0d16487e8200d4ad1b924c..a78b16f57d38863d25fe1168a3be195aca121e6c 100644 (file)
 #include <asm/oplib.h>
 #include <asm/head.h>
 #include <asm/traps.h>
-#include <asm/system.h>
 #include <asm/vac-ops.h>
 #include <asm/kgdb.h>
 #include <asm/pgtable.h>
index b043d647d93d1580d8c3c46268789c3c813bed87..99a1f9242cc953b1ec34ba356ce2fccae4110517 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/dma.h>
 #endif
 #include <asm/a.out.h>
-#include <asm/spinlock.h>
 #include <asm/io-unit.h>
 
 struct poll {
index febbd2e745c902a403fd4d0470bc6ba6e3f64b90..9e7bf2a2d1b1bfdcde6370ee10b319bff78535c1 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/signal.h>
 #include <linux/uio.h>
 #include <linux/utsname.h>
-#include <linux/fs.h>
 #include <linux/major.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
index 87f056c2ec0addf1c2b1618dbd00b7d4c66d5d2e..0f1f3d983069959ce1ca0c15eacb12012cbc9ed8 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/mman.h>
 #include <linux/tasks.h>
 #include <linux/kernel.h>
-#include <linux/smp.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
index 5b63aa11ad600c70c79e164547104b63b4db34f6..66d3c535de217200b1ef3094ea38cb0e9fb8cd99 100644 (file)
@@ -2076,6 +2076,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
                        goto done;
                inode = file->f_dentry->d_inode;
                offset = (address & PAGE_MASK) - vma->vm_start;
+               spin_lock(&inode->i_shared_lock);
                vmaring = inode->i_mmap; 
                do {
                        /* Do not mistake ourselves as another mapping. */
@@ -2109,6 +2110,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
                                }
                        }
                } while ((vmaring = vmaring->vm_next_share) != NULL);
+               spin_unlock(&inode->i_shared_lock);
 
                if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) {
                        pgdp = srmmu_pgd_offset(vma->vm_mm, address);
index d6387d473f984b1a683097e1e78ba39cf35a2cc2..c6bf02fc01c81df29e247ce58ba72de0458c77fb 100644 (file)
@@ -2682,8 +2682,10 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
                inode = dentry->d_inode;
        if(inode) {
                unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
-               struct vm_area_struct *vmaring = inode->i_mmap; 
+               struct vm_area_struct *vmaring;
                int alias_found = 0;
+               spin_lock(&inode->i_shared_lock);
+               vmaring = inode->i_mmap; 
                do {
                        unsigned long vaddr = vmaring->vm_start + offset;
                        unsigned long start;
@@ -2712,6 +2714,7 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
                                }
                        }
                } while ((vmaring = vmaring->vm_next_share) != NULL);
+               spin_unlock(&inode->i_shared_lock);
 
                if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
                        pgdp = sun4c_pgd_offset(vma->vm_mm, address);
index 6baf5958b261a1aefb83bcc541982b8bde4991fa..392ddab55d0005bfe7c1d738e9bdbd0b96d814b0 100644 (file)
@@ -68,7 +68,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 
-#include <asm/io.h>
 #include <asm/oplib.h>
 #include <asm/pbm.h>
 #include <asm/apb.h>
index 476d53558cf763507862d980b63709ac243b4bc1..61a6a6bfa32ba7f4a080e41c3fdea80cd8956405 100644 (file)
 
 #define MAGIC_CONSTANT 0x80000000
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static pte_t *ptrace_get_page(struct task_struct * tsk,
-       struct vm_area_struct * vma, unsigned long addr, int write)
-{
-       pgd_t * pgdir;
-       pmd_t * pgmiddle;
-       pte_t * pgtable;
-
-repeat:
-       pgdir = pgd_offset(vma->vm_mm, addr);
-
-       /* Seems non-intuitive but the page copy/clear routines always
-        * check current's value.
-        */
-       current->mm->segments = (void *) (addr & PAGE_SIZE);
-
-       if (pgd_none(*pgdir)) {
-               handle_mm_fault(tsk, vma, addr, write);
-               goto repeat;
-       }
-       if (pgd_bad(*pgdir)) {
-               printk("ptrace: bad page directory %016lx\n", pgd_val(*pgdir));
-               pgd_clear(pgdir);
-               return 0;
-       }
-       pgmiddle = pmd_offset(pgdir, addr);
-       if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk, vma, addr, write);
-               goto repeat;
-       }
-       if (pmd_bad(*pgmiddle)) {
-               printk("ptrace: bad page middle %016lx\n", pmd_val(*pgmiddle));
-               pmd_clear(pgmiddle);
-               return 0;
-       }
-       pgtable = pte_offset(pgmiddle, addr);
-       if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, write);
-               goto repeat;
-       }
-       if (write && !pte_write(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, write);
-               goto repeat;
-       }
-       return pgtable;
-}
-
-/* We must bypass the L1-cache to avoid alias issues.  -DaveM */
-static __inline__ unsigned long read_user_long(unsigned long kvaddr)
-{
-       unsigned long ret;
-
-       __asm__ __volatile__("ldxa [%1] %2, %0"
-                            : "=r" (ret)
-                            : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
-       return ret;
-}
-
-static __inline__ unsigned int read_user_int(unsigned long kvaddr)
-{
-       unsigned int ret;
-
-       __asm__ __volatile__("lduwa [%1] %2, %0"
-                            : "=r" (ret)
-                            : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
-       return ret;
-}
-
-static __inline__ void write_user_long(unsigned long kvaddr, unsigned long val)
-{
-       __asm__ __volatile__("stxa %0, [%1] %2"
-                            : /* no outputs */
-                            : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
-}
-
-static __inline__ void write_user_int(unsigned long kvaddr, unsigned int val)
-{
-       __asm__ __volatile__("stwa %0, [%1] %2"
-                            : /* no outputs */
-                            : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
-}
-
-static inline unsigned long get_long(struct task_struct * tsk,
-       struct vm_area_struct * vma, unsigned long addr)
-{
-       pte_t * pgtable;
-       unsigned long page, retval;
-       
-       if (!(pgtable = ptrace_get_page (tsk, vma, addr, 0))) return 0;
-       page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-       if (MAP_NR(page) >= max_mapnr)
-               return 0;
-       page += addr & ~PAGE_MASK;
-       retval = read_user_long(page);
-       flush_page_to_ram(page);
-       return retval;
-}
-
-static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
-       unsigned long addr, unsigned long data)
-{
-       pte_t *pgtable;
-       unsigned long page;
-
-       if (!(pgtable = ptrace_get_page (tsk, vma, addr, 1))) return;
-       page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-       flush_cache_page(vma, addr);
-       if (MAP_NR(page) < max_mapnr) {
-               unsigned long pgaddr;
-
-               pgaddr = page + (addr & ~PAGE_MASK);
-               write_user_long(pgaddr, data);
-
-               __asm__ __volatile__("
-               membar  #StoreStore
-               flush   %0
-"              : : "r" (pgaddr & ~7) : "memory");
-       }
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
-       set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-       flush_tlb_page(vma, addr);
-}
-
-static inline unsigned int get_int(struct task_struct * tsk,
-       struct vm_area_struct * vma, unsigned long addr)
-{
-       pte_t * pgtable;
-       unsigned long page;
-       unsigned int retval;
-       
-       if (!(pgtable = ptrace_get_page (tsk, vma, addr, 0))) return 0;
-       page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-       if (MAP_NR(page) >= max_mapnr)
-               return 0;
-       page += addr & ~PAGE_MASK;
-       retval = read_user_int(page);
-       flush_page_to_ram(page);
-       return retval;
-}
-
-static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma,
-       unsigned long addr, unsigned int data)
-{
-       pte_t *pgtable;
-       unsigned long page;
-
-       if (!(pgtable = ptrace_get_page (tsk, vma, addr, 1))) return;
-       page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-       flush_cache_page(vma, addr);
-       if (MAP_NR(page) < max_mapnr) {
-               unsigned long pgaddr;
-
-               pgaddr = page + (addr & ~PAGE_MASK);
-               write_user_int(pgaddr, data);
-
-               __asm__ __volatile__("
-               membar  #StoreStore
-               flush   %0
-"              : : "r" (pgaddr & ~7) : "memory");
-       }
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
-       set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-       flush_tlb_page(vma, addr);
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-                    unsigned long * result)
-{
-       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-       if (!vma)
-               return -EIO;
-       *result = get_long(tsk, vma, addr);
-       return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_int() to read a int.
- */
-static int read_int(struct task_struct * tsk, unsigned long addr,
-                    unsigned int * result)
-{
-       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-       if (!vma)
-               return -EIO;
-       *result = get_int(tsk, vma, addr);
-       return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-                     unsigned long data)
-{
-       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-       if (!vma)
-               return -EIO;
-       put_long(tsk, vma, addr, data);
-       return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_int() to write a int.
- */
-static int write_int(struct task_struct * tsk, unsigned long addr,
-                    unsigned int data)
-{
-       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-       if (!vma)
-               return -EIO;
-       put_int(tsk, vma, addr, data);
-       return 0;
-}
-
 /* Returning from ptrace is a bit tricky because the syscall return
  * low level code assumes any value returned which is negative and
  * is a valid errno will mean setting the condition codes to indicate
@@ -310,175 +74,6 @@ pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr)
                pt_succ_return_linux (regs, val, addr);
 }
 
-#if 0
-/* XXX: Implement this some day */
-/* Fuck me gently with a chainsaw... */
-static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
-                                  struct task_struct *tsk, long *addr)
-{
-       struct pt_regs *cregs = tsk->tss.kregs;
-       struct thread_struct *t = &tsk->tss;
-       int v;
-       
-       if(offset >= 1024)
-               offset -= 1024; /* whee... */
-       if(offset & ((sizeof(unsigned int) - 1))) {
-               pt_error_return(regs, EIO);
-               return;
-       }
-       if(offset >= 16 && offset < 784) {
-               offset -= 16; offset >>= 2;
-               if (t->w_saved)
-                       pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
-               return;
-       }
-       if(offset >= 784 && offset < 832) {
-               offset -= 784; offset >>= 2;
-               if (t->w_saved)
-                       pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
-               return;
-       }
-       switch(offset) {
-       case 0:
-               v = t->ksp;
-               break;
-#if 0
-       case 4:
-               v = t->kpc;
-               break;
-#endif
-       case 8:
-               v = t->kpsr;
-               break;
-       case 12:
-               v = t->uwinmask;
-               break;
-       case 832:
-               v = t->w_saved;
-               break;
-       case 896:
-               v = cregs->u_regs[UREG_I0];
-               break;
-       case 900:
-               v = cregs->u_regs[UREG_I1];
-               break;
-       case 904:
-               v = cregs->u_regs[UREG_I2];
-               break;
-       case 908:
-               v = cregs->u_regs[UREG_I3];
-               break;
-       case 912:
-               v = cregs->u_regs[UREG_I4];
-               break;
-       case 916:
-               v = cregs->u_regs[UREG_I5];
-               break;
-       case 920:
-               v = cregs->u_regs[UREG_I6];
-               break;
-       case 924:
-               if(tsk->tss.flags & MAGIC_CONSTANT)
-                       v = cregs->u_regs[UREG_G1];
-               else
-                       v = 0;
-               break;
-       case 940:
-               v = cregs->u_regs[UREG_I0];
-               break;
-       case 944:
-               v = cregs->u_regs[UREG_I1];
-               break;
-
-       case 948:
-               /* Isn't binary compatibility _fun_??? */
-               if(cregs->psr & PSR_C)
-                       v = cregs->u_regs[UREG_I0] << 24;
-               else
-                       v = 0;
-               break;
-
-               /* Rest of them are completely unsupported. */
-       default:
-               printk("%s [%d]: Wants to read user offset %ld\n",
-                      current->comm, current->pid, offset);
-               pt_error_return(regs, EIO);
-               return;
-       }
-       pt_os_succ_return_linux (regs, v, addr);
-       return;
-}
-
-static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
-                                   struct task_struct *tsk)
-{
-       struct pt_regs *cregs = tsk->tss.kregs;
-       struct thread_struct *t = &tsk->tss;
-       unsigned int value = regs->u_regs[UREG_I3];
-
-       if(offset >= 1024)
-               offset -= 1024; /* whee... */
-       if(offset & ((sizeof(unsigned long) - 1)))
-               goto failure;
-       if(offset >= 16 && offset < 784) {
-               offset -= 16; offset >>= 2;
-               if (t->w_saved)
-                       *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
-               goto success;
-       }
-       if(offset >= 784 && offset < 832) {
-               offset -= 784; offset >>= 2;
-               if (t->w_saved)
-                       *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
-               goto success;
-       }
-       switch(offset) {
-       case 896:
-               cregs->u_regs[UREG_I0] = value;
-               break;
-       case 900:
-               cregs->u_regs[UREG_I1] = value;
-               break;
-       case 904:
-               cregs->u_regs[UREG_I2] = value;
-               break;
-       case 908:
-               cregs->u_regs[UREG_I3] = value;
-               break;
-       case 912:
-               cregs->u_regs[UREG_I4] = value;
-               break;
-       case 916:
-               cregs->u_regs[UREG_I5] = value;
-               break;
-       case 920:
-               cregs->u_regs[UREG_I6] = value;
-               break;
-       case 924:
-               cregs->u_regs[UREG_I7] = value;
-               break;
-       case 940:
-               cregs->u_regs[UREG_I0] = value;
-               break;
-       case 944:
-               cregs->u_regs[UREG_I1] = value;
-               break;
-
-               /* Rest of them are completely unsupported or "no-touch". */
-       default:
-               printk("%s [%d]: Wants to write user offset %ld\n",
-                      current->comm, current->pid, offset);
-               goto failure;
-       }
-success:
-       pt_succ_return(regs, 0);
-       return;
-failure:
-       pt_error_return(regs, EIO);
-       return;
-}
-#endif
-
 /* #define ALLOW_INIT_TRACING */
 /* #define DEBUG_PTRACE */
 
@@ -642,76 +237,54 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
        switch(request) {
        case PTRACE_PEEKTEXT: /* read word at location addr. */ 
        case PTRACE_PEEKDATA: {
-               unsigned long tmp;
-               int res;
+               unsigned long tmp64;
+               unsigned int tmp32;
+               int res, copied;
 
-               /* Non-word alignment _not_ allowed on Sparc. */
+               res = -EIO;
                if (current->tss.flags & SPARC_FLAG_32BIT) {
-                       unsigned int x;
-                       if(addr & (sizeof(unsigned int) - 1)) {
-                               pt_error_return(regs, EINVAL);
-                               goto out;
-                       }
-                       down(&child->mm->mmap_sem);
-                       res = read_int(child, addr, &x);
-                       up(&child->mm->mmap_sem);
-                       tmp = x;
+                       copied = access_process_vm(child, addr,
+                                                  &tmp32, sizeof(tmp32), 0);
+                       tmp64 = (unsigned long) tmp32;
+                       if (copied == sizeof(tmp32))
+                               res = 0;
                } else {
-                       if(addr & (sizeof(unsigned long) - 1)) {
-                               pt_error_return(regs, EINVAL);
-                               goto out;
-                       }
-                       down(&child->mm->mmap_sem);
-                       res = read_long(child, addr, &tmp);
-                       up(&child->mm->mmap_sem);
+                       copied = access_process_vm(child, addr,
+                                                  &tmp64, sizeof(tmp64), 0);
+                       if (copied == sizeof(tmp64))
+                               res = 0;
                }
-               if (res < 0) {
+               if (res < 0)
                        pt_error_return(regs, -res);
-                       goto out;
-               }
-               pt_os_succ_return(regs, tmp, (long *) data);
-               goto out;
+               else
+                       pt_os_succ_return(regs, tmp64, (long *) data);
+               goto flush_and_out;
        }
 
-       case PTRACE_PEEKUSR:
-#if 0  
-               read_sunos_user(regs, addr, child, (long *) data);
-#endif
-               goto out;
-
-       case PTRACE_POKEUSR:
-#if 0  
-               write_sunos_user(regs, addr, child);
-#endif         
-               goto out;
-
        case PTRACE_POKETEXT: /* write the word at location addr. */
        case PTRACE_POKEDATA: {
-               int res;
+               unsigned long tmp64;
+               unsigned int tmp32;
+               int copied, res = -EIO;
 
-               /* Non-word alignment _not_ allowed on Sparc. */
                if (current->tss.flags & SPARC_FLAG_32BIT) {
-                       if(addr & (sizeof(unsigned int) - 1)) {
-                               pt_error_return(regs, EINVAL);
-                               goto out;
-                       }
-                       down(&child->mm->mmap_sem);
-                       res = write_int(child, addr, data);
-                       up(&child->mm->mmap_sem);
+                       tmp32 = data;
+                       copied = access_process_vm(child, addr,
+                                                  &tmp32, sizeof(tmp32), 1);
+                       if (copied == sizeof(tmp32))
+                               res = 0;
                } else {
-                       if(addr & (sizeof(unsigned long) - 1)) {
-                               pt_error_return(regs, EINVAL);
-                               goto out;
-                       }
-                       down(&child->mm->mmap_sem);
-                       res = write_long(child, addr, data);
-                       up(&child->mm->mmap_sem);
+                       tmp64 = data;
+                       copied = access_process_vm(child, addr,
+                                                  &tmp64, sizeof(tmp64), 1);
+                       if (copied == sizeof(tmp64))
+                               res = 0;
                }
                if(res < 0)
                        pt_error_return(regs, -res);
                else
                        pt_succ_return(regs, res);
-               goto out;
+               goto flush_and_out;
        }
 
        case PTRACE_GETREGS: {
@@ -926,98 +499,31 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
 
        case PTRACE_READTEXT:
        case PTRACE_READDATA: {
-               unsigned char *dest = (unsigned char *) addr2;
-               unsigned long src = addr;
-               int len = data, curlen;
-               struct vm_area_struct *vma;
-               pte_t *pgtable;
-               unsigned long page;
-
-               while(len) {
-                       down(&child->mm->mmap_sem);
-                       vma = find_extend_vma(child, src);
-                       if (!vma) {
-                               up(&child->mm->mmap_sem);
-                               pt_error_return(regs, EIO);
-                               goto flush_and_out;
-                       }
-                       pgtable = ptrace_get_page (child, vma, src, 0);
-                       up(&child->mm->mmap_sem);
-                       if (src & ~PAGE_MASK) {
-                               curlen = PAGE_SIZE - (src & ~PAGE_MASK);
-                               if (curlen > len) curlen = len;
-                       } else if (len > PAGE_SIZE)
-                               curlen = PAGE_SIZE;
-                       else
-                               curlen = len;
-                       if (pgtable && MAP_NR(page = pte_page(*pgtable)) < max_mapnr) {
-                               if (copy_to_user (dest, ((char *)page) + (src & ~PAGE_MASK), curlen)) {
-                                       flush_page_to_ram(page);
-                                       pt_error_return(regs, EFAULT);
-                                       goto flush_and_out;
-                               }
-                               flush_page_to_ram(page);
-                       } else {
-                               if (clear_user (dest, curlen)) {
-                                       pt_error_return(regs, EFAULT);
-                                       goto flush_and_out;
-                               }
-                       }
-                       src += curlen;
-                       dest += curlen;
-                       len -= curlen;
+               int res = ptrace_readdata(child, addr,
+                                         (void *)addr2, data);
+               if (res == data) {
+                       pt_succ_return(regs, 0);
+                       goto flush_and_out;
                }
-               pt_succ_return(regs, 0);
+               if (res >= 0)
+                       res = -EIO;
+               pt_error_return(regs, -res);
                goto flush_and_out;
        }
 
        case PTRACE_WRITETEXT:
        case PTRACE_WRITEDATA: {
-               unsigned char *src = (unsigned char *) addr2;
-               unsigned long dest = addr;
-               int len = data, curlen;
-               struct vm_area_struct *vma;
-               pte_t *pgtable;
-               unsigned long page;
-
-               while(len) {
-                       down(&child->mm->mmap_sem);
-                       vma = find_extend_vma(child, dest);
-                       if (!vma) {
-                               up(&child->mm->mmap_sem);
-                               pt_error_return(regs, EIO);
-                               goto flush_and_out;
-                       }
-                       pgtable = ptrace_get_page (child, vma, dest, 1);
-                       up(&child->mm->mmap_sem);
-                       if (dest & ~PAGE_MASK) {
-                               curlen = PAGE_SIZE - (dest & ~PAGE_MASK);
-                               if (curlen > len) curlen = len;
-                       } else if (len > PAGE_SIZE)
-                               curlen = PAGE_SIZE;
-                       else
-                               curlen = len;
-                       if (pgtable && MAP_NR(page = pte_page(*pgtable)) < max_mapnr) {
-                               flush_cache_page(vma, dest);
-                               if (copy_from_user (((char *)page) + (dest & ~PAGE_MASK), src, curlen)) {
-                                       flush_page_to_ram(page);
-                                       set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-                                       flush_tlb_page(vma, dest);
-                                       pt_error_return(regs, EFAULT);
-                                       goto flush_and_out;
-                               }
-                               flush_page_to_ram(page);
-                               set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-                               flush_tlb_page(vma, dest);
-                       }
-                       src += curlen;
-                       dest += curlen;
-                       len -= curlen;
+               int res = ptrace_writedata(child, (void *) addr2,
+                                          addr, data);
+               if (res == data) {
+                       pt_succ_return(regs, 0);
+                       goto flush_and_out;
                }
-               pt_succ_return(regs, 0);
+               if (res >= 0)
+                       res = -EIO;
+               pt_error_return(regs, -res);
                goto flush_and_out;
        }
-
        case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
                addr = 1;
 
@@ -1105,6 +611,14 @@ flush_and_out:
                unsigned long va;
                for(va =  0; va < (PAGE_SIZE << 1); va += 32)
                        spitfire_put_dcache_tag(va, 0x0);
+               if (request == PTRACE_PEEKTEXT ||
+                   request == PTRACE_POKETEXT ||
+                   request == PTRACE_READTEXT ||
+                   request == PTRACE_WRITETEXT) {
+                       for(va =  0; va < (PAGE_SIZE << 1); va += 32)
+                               spitfire_put_icache_tag(va, 0x0);
+                       __asm__ __volatile__("flush %g6");
+               }
        }
 out:
        unlock_kernel();
index 9eca01cca175ea83f7523a0c38ea40b6d262adb1..91277fc4a9d61769c18bf8500e9a497b289808b8 100644 (file)
@@ -45,7 +45,6 @@
 #include <asm/ebus.h>
 #endif
 #include <asm/a.out.h>
-#include <asm/svr4.h>
 
 struct poll {
        int fd;
index 8d1c2502570d3bbf0927c4d099f09e008e9047f3..cddc73e6835df22cc1a32878e7b5a09554bd0305 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/utime.h>
 #include <linux/resource.h>
 #include <linux/times.h>
-#include <linux/utime.h>
 #include <linux/utsname.h>
 #include <linux/timex.h>
 #include <linux/smp.h>
 #include <linux/smb_mount.h>
 #include <linux/ncp_fs.h>
 #include <linux/quota.h>
-#include <linux/file.h>
 #include <linux/module.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/cache.h>
 #include <linux/nfsd/xdr.h>
 #include <linux/nfsd/syscall.h>
-#include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/personality.h>
 #include <linux/stat.h>
-#include <linux/timex.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
index f2a2847857ab32605086d2d6763e51c94d79656c..b6b58c30a0e1207e442210bb9a0aa2f540d0160f 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/signal.h>
 #include <linux/uio.h>
 #include <linux/utsname.h>
-#include <linux/fs.h>
 #include <linux/major.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
index dbdbcd1a2364a8ea7e5afa0181efa97c756e7e8e..f6d31920ea8313ec65771113644490699a2b0b56 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/file.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/file.h>
 #include <linux/malloc.h>
 
 #include <asm/uaccess.h>
index 01c496a2be6e27331e78088a7ce8b602ea46089d..0370c9944b3ed5e7ef2ac77798358162d91e06f9 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/kbd_ll.h>
-#include <linux/tty.h>
 #include <linux/kbd_kern.h>
 #include <linux/delay.h>
 
index 2cde93a0676421ce17e0b80302c108ef75c1dd27..08492ca1751f2978593ba59087b348fac3c1eba4 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/io.h>
 
 #include <linux/inet.h>
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
index d0b4a5d07555519e959a6bab94560a085b01c5c3..6fba7d5fc57a8c7ebdf9e00acf3e3707023774d9 100644 (file)
@@ -163,6 +163,7 @@ if [ "$CONFIG_ATARI" = "y" ]; then
     dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI
   fi
 fi
+tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
 
 comment 'Additional Block Devices'
 
index 61909b033ff8665e871331db1d1877291b6c2b6e..bb03a3200240585ad248696e094c0cd64a57b35b 100644 (file)
@@ -274,6 +274,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_BLK_CPQ_DA),y)
+L_OBJS += cpqarray.o
+else
+  ifeq ($(CONFIG_BLK_CPQ_DA),m)
+  M_OBJS += cpqarray.o
+  endif
+endif
+
 ifeq ($(CONFIG_BLK_DEV_MD),y)
 LX_OBJS += md.o
 
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
new file mode 100644 (file)
index 0000000..6dbb751
--- /dev/null
@@ -0,0 +1,1731 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/blkpg.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <linux/hdreg.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+#include <asm/io.h>
+
+
+#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
+
+#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.4)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,4)
+#define MAJOR_NR COMPAQ_SMART2_MAJOR
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+
+#include "cpqarray.h"
+#include "ida_cmd.h"
+#include "smart1,2.h"
+#include "ida_ioctl.h"
+
+#define READ_AHEAD     128
+#define NR_CMDS                128 /* This could probably go as high as ~400 */
+
+#define MAX_CTLR       8
+#define CTLR_SHIFT     8
+
+static int nr_ctlr = 0;
+static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static int eisa[8] = { 0, 0 ,0 ,0, 0, 0 ,0 ,0 };
+
+#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type))
+
+/*  board_id = Subsystem Device ID & Vendor ID
+ *  product = Marketing Name for the board
+ *  access = Address of the struct of function pointers 
+ */
+struct board_type products[] = {
+       { 0x0040110E, "IDA",                    &smart1_access },
+       { 0x0140110E, "IDA-2",                  &smart1_access },
+       { 0x1040110E, "IAES",                   &smart1_access },
+       { 0x2040110E, "SMART",                  &smart1_access },
+       { 0x3040110E, "SMART-2/E",              &smart2e_access },
+       { 0x40300E11, "SMART-2/P",              &smart2_access },
+       { 0x40310E11, "SMART-2SL",              &smart2_access },
+       { 0x40320E11, "Smart Array 3200",       &smart2_access },
+       { 0x40330E11, "Smart Array 3100ES",     &smart2_access },
+       { 0x40340E11, "Smart Array 221",        &smart2_access },
+       { 0x40400E11, "Integrated Array",       &smart4_access },
+       { 0x40500E11, "Smart Array 4200",       &smart4_access },
+       { 0x40510E11, "Smart Array 4250ES",     &smart4_access },
+};
+
+static struct hd_struct * ida;
+static int * ida_sizes;
+static int * ida_blocksizes;
+static int * ida_hardsizes;
+static struct gendisk ida_gendisk[MAX_CTLR];
+
+struct proc_dir_entry *proc_array = NULL;
+
+/* Debug... */
+#define DBG(s) do { s } while(0)
+/* Debug (general info)... */
+#define DBGINFO(s) do { } while(0)
+/* Debug Paranoid... */
+#define DBGP(s)  do { } while(0)
+/* Debug Extra Paranoid... */
+#define DBGPX(s) do { } while(0)
+
+void cpqarray_init(void);
+static int cpqarray_pci_detect(void);
+static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn);
+static ulong remap_pci_mem(ulong base, ulong size);
+static int cpqarray_eisa_detect(void);
+static int pollcomplete(int ctlr);
+static void getgeometry(int ctlr);
+static void start_fwbk(int ctlr);
+
+static cmdlist_t * cmd_alloc(ctlr_info_t *h);
+static void cmd_free(ctlr_info_t *h, cmdlist_t *c);
+
+static int sendcmd(
+       __u8    cmd,
+       int     ctlr,
+       void    *buff,
+       size_t  size,
+       unsigned int blk,
+       unsigned int blkcnt,
+       unsigned int log_unit );
+
+static int ida_open(struct inode *inode, struct file *filep);
+static int ida_release(struct inode *inode, struct file *filep);
+static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
+static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
+
+static void do_ida_request(int i);
+/*
+ * This is a hack.  This driver eats a major number for each controller, and
+ * sets blkdev[xxx].request_fn to each one of these so the real request
+ * function knows what controller its working with.
+ */
+#define DO_IDA_REQUEST(x) { do_ida_request(x); }
+
+static void do_ida_request0(void) DO_IDA_REQUEST(0);
+static void do_ida_request1(void) DO_IDA_REQUEST(1);
+static void do_ida_request2(void) DO_IDA_REQUEST(2);
+static void do_ida_request3(void) DO_IDA_REQUEST(3);
+static void do_ida_request4(void) DO_IDA_REQUEST(4);
+static void do_ida_request5(void) DO_IDA_REQUEST(5);
+static void do_ida_request6(void) DO_IDA_REQUEST(6);
+static void do_ida_request7(void) DO_IDA_REQUEST(7);
+
+static void start_io(ctlr_info_t *h);
+
+static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
+static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);
+static inline void complete_buffers(struct buffer_head *bh, int ok);
+static inline void complete_command(cmdlist_t *cmd, int timeout);
+
+static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void ida_timer(unsigned long tdata);
+static int frevalidate_logvol(kdev_t dev);
+static int revalidate_logvol(kdev_t dev, int maxusage);
+static int revalidate_allvol(kdev_t dev);
+
+static void ida_procinit(int i);
+static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+
+static void ida_geninit(struct gendisk *g)
+{
+       int ctlr = g-ida_gendisk;
+       int i,j;
+       drv_info_t *drv;
+
+       for(i=0; i<NWD; i++) {
+               drv = &hba[ctlr]->drv[i];
+               if (!drv->nr_blks)
+                       continue;
+               ida[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)].nr_sects =
+               ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)] =
+                               drv->nr_blks;
+
+               for(j=0; j<16; j++) {
+                       ida_blocksizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
+                               1024;
+                       ida_hardsizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
+                               drv->blk_size;
+               }
+               ida_gendisk[ctlr].nr_real++;
+       }
+
+}
+
+struct file_operations ida_fops  = {
+       NULL,                        /* lseek - default */
+       block_read,                  /* read - general block-dev read */
+       block_write,                 /* write - general block-dev write */
+       NULL,                        /* readdir - bad */
+       NULL,                        /* select */
+       ida_ioctl,                  /* ioctl */
+       NULL,                        /* mmap */
+       ida_open,                     /* open code */
+       NULL,
+       ida_release,                  /* release */
+       block_fsync,                  /* fsync */
+       NULL,                        /* fasync */
+       NULL,                   /* Disk change */
+       frevalidate_logvol,     /* revalidate */
+};
+
+
+/*
+ * Get us a file in /proc/array that says something about each controller.
+ * Create /proc/array if it doesn't exist yet.
+ */
+static void ida_procinit(int i)
+{
+       struct proc_dir_entry *pd;
+
+       if (proc_array == NULL) {
+               proc_array = create_proc_entry("array", S_IFDIR|S_IRUGO|S_IXUGO,
+                                                               &proc_root);
+               if (!proc_array) return;
+       }
+
+       pd = create_proc_entry(hba[i]->devname, S_IFREG|S_IRUGO, proc_array);
+       if (!pd) return;
+       pd->read_proc = ida_proc_get_info;
+       pd->data = hba[i];
+}
+
+/*
+ * Report information about this controller.
+ */
+static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+       off_t pos = 0;
+       off_t len = 0;
+       int size, i, ctlr;
+       ctlr_info_t *h = (ctlr_info_t*)data;
+       drv_info_t *drv;
+#ifdef CPQ_PROC_PRINT_QUEUES
+       cmdlist_t *c;
+#endif
+
+       ctlr = h->ctlr;
+       size = sprintf(buffer, "%s:  Compaq %s Controller\n"
+               "       Board ID: %08lx\n"
+               "       Firmware Revision: %c%c%c%c\n"
+               "       Controller Sig: %08lx\n"
+               "       Memory Address: %08lx\n"
+               "       I/O Port: %04x\n"
+               "       IRQ: %x\n"
+               "       Logical drives: %d\n"
+               "       Physical drives: %d\n\n"
+               "       Current Q depth: %d\n"
+               "       Max Q depth since init: %d\n\n",
+               h->devname, 
+               h->product_name,
+               (unsigned long)h->board_id,
+               h->firm_rev[0], h->firm_rev[1], h->firm_rev[2], h->firm_rev[3],
+               (unsigned long)h->ctlr_sig, (unsigned long)h->vaddr,
+               (unsigned int) h->ioaddr, (unsigned int)h->intr,
+               h->log_drives, h->phys_drives,
+               h->Qdepth, h->maxQsinceinit);
+
+       pos += size; len += size;
+       
+       size = sprintf(buffer+len, "Logical Drive Info:\n");
+       pos += size; len += size;
+
+       for(i=0; i<h->log_drives; i++) {
+               drv = &h->drv[i];
+               size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
+                               ctlr, i, drv->blk_size, drv->nr_blks);
+               pos += size; len += size;
+       }
+
+#ifdef CPQ_PROC_PRINT_QUEUES
+       size = sprintf(buffer+len, "\nCurrent Queues:\n");
+       pos += size; len += size;
+
+       c = h->reqQ;
+       size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
+       if (c) c=c->next;
+       while(c && c != h->reqQ) {
+               size = sprintf(buffer+len, "->%p", c);
+               pos += size; len += size;
+               c=c->next;
+       }
+
+       c = h->cmpQ;
+       size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
+       if (c) c=c->next;
+       while(c && c != h->cmpQ) {
+               size = sprintf(buffer+len, "->%p", c);
+               pos += size; len += size;
+               c=c->next;
+       }
+
+       size = sprintf(buffer+len, "\n"); pos += size; len += size;
+#endif
+       size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
+                       h->nr_allocs, h->nr_frees);
+       pos += size; len += size;
+
+       *eof = 1;
+       *start = buffer+offset;
+       len -= offset;
+       if (len>length)
+               len = length;
+       return len;
+}
+
+#ifdef MODULE
+
+MODULE_PARM(eisa, "1-8i");
+EXPORT_NO_SYMBOLS;
+
+/* This is a bit of a hack... */
+int init_module(void)
+{
+       int i, j;
+       cpqarray_init();
+       if (nr_ctlr == 0)
+               return -EIO;
+
+       for(i=0; i<nr_ctlr; i++) {
+               ida_geninit(&ida_gendisk[i]); 
+               for(j=0; j<NWD; j++)    
+                       if (ida_sizes[(i<<CTLR_SHIFT) + (j<<NWD_SHIFT)])
+                               resetup_one_dev(&ida_gendisk[i], j);
+       }
+       return 0;
+}
+void cleanup_module(void)
+{
+       int i;
+       struct gendisk *g;
+
+       for(i=0; i<nr_ctlr; i++) {
+               hba[i]->access.set_intr_mask(hba[i], 0);
+               free_irq(hba[i]->intr, hba[i]);
+               iounmap((void*)hba[i]->vaddr);
+               unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+               del_timer(&hba[i]->timer);
+               remove_proc_entry(hba[i]->devname, proc_array);
+               kfree(hba[i]->cmd_pool);
+               kfree(hba[i]->cmd_pool_bits);
+
+               if (gendisk_head == &ida_gendisk[i]) {
+                       gendisk_head = ida_gendisk[i].next;
+               } else {
+                       for(g=gendisk_head; g; g=g->next) {
+                               if (g->next == &ida_gendisk[i]) {
+                                       g->next = ida_gendisk[i].next;
+                                       break;
+                               }
+                       }
+               }
+       }
+       remove_proc_entry("array", &proc_root);
+       kfree(ida);
+       kfree(ida_sizes);
+       kfree(ida_hardsizes);
+       kfree(ida_blocksizes);
+
+
+}
+#endif /* MODULE */
+
+/*
+ *  This is it.  Find all the controllers and register them.  I really hate
+ *  stealing all these major device numbers.
+ */
+void cpqarray_init(void)
+{
+       void (*request_fns[MAX_CTLR])(void) = {
+               do_ida_request0, do_ida_request1,
+               do_ida_request2, do_ida_request3,
+               do_ida_request4, do_ida_request5,
+               do_ida_request6, do_ida_request7,
+       };
+       int i;
+
+       /* detect controllers */
+       cpqarray_pci_detect();
+       cpqarray_eisa_detect();
+       
+       if (nr_ctlr == 0)
+               return;
+
+       printk(DRIVER_NAME "\n");
+       printk("Found %d controller(s)\n", nr_ctlr);
+
+       /* allocate space for disk structs */
+       ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL);
+       
+       if(ida==NULL)
+               goto bail;
+       ida_sizes =      kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+       if(ida_sizes==NULL)
+               goto bail2;
+       ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+       if(ida_blocksizes==NULL)
+               goto bail3;
+       ida_hardsizes =  kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+       if(ida_hardsizes==NULL)
+               goto bail4;
+
+       memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16);
+       memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+       memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+       memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+       memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR);
+
+       /* 
+        * register block devices
+        * Find disks and fill in structs
+        * Get an interrupt, set the Q depth and get into /proc
+        */
+       for(i=0; i< nr_ctlr; i++) {
+               hba[i]->access.set_intr_mask(hba[i], 0);
+               if (request_irq(hba[i]->intr, do_ida_intr,
+                       SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) {
+
+                       printk("Unable to get irq %d for %s\n", 
+                               hba[i]->intr, hba[i]->devname);
+                       continue;
+               }
+               if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
+                       printk("Unable to get major number %d for ida\n",
+                               MAJOR_NR+i);
+                       continue;
+               }
+
+               hba[i]->cmd_pool = (cmdlist_t *)kmalloc(
+                               NR_CMDS * sizeof(cmdlist_t), GFP_KERNEL);
+               hba[i]->cmd_pool_bits = (__u32*)kmalloc(
+                               ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
+               
+               if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
+               {
+                       int j;
+                       if(hba[i]->cmd_pool_bits)
+                               kfree(hba[i]->cmd_pool_bits);
+                       if(hba[i]->cmd_pool)
+                               kfree(hba[i]->cmd_pool);
+                       for(j=0;i<i;j++)
+                       {
+                               free_irq(hba[j]->intr, hba[j]);
+                               unregister_blkdev(MAJOR_NR+j, hba[j]->devname);
+                               kfree(hba[j]->cmd_pool_bits);
+                               kfree(hba[j]->cmd_pool);
+                       }
+                       free_irq(hba[i]->intr, hba[i]);
+                       unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+                       goto bail5;
+               }
+               memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
+               memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
+               printk("Finding drives on %s", hba[i]->devname);
+               getgeometry(i);
+               start_fwbk(i); 
+
+               hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
+
+               ida_procinit(i);
+               ida_gendisk[i].major = MAJOR_NR + i;
+               ida_gendisk[i].major_name = "ida";
+               ida_gendisk[i].minor_shift = NWD_SHIFT;
+               ida_gendisk[i].max_p = 16;
+               ida_gendisk[i].max_nr = 16;
+               ida_gendisk[i].init = ida_geninit;
+               ida_gendisk[i].part = ida + (i*256);
+               ida_gendisk[i].sizes = ida_sizes + (i*256);
+               /* ida_gendisk[i].nr_real is handled by getgeometry */
+       
+               blk_dev[MAJOR_NR+i].request_fn = request_fns[i];
+               blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
+               hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256);
+               read_ahead[MAJOR_NR+i] = READ_AHEAD;
+
+               /* Get on the disk list */
+               ida_gendisk[i].next = gendisk_head;
+               gendisk_head = &ida_gendisk[i];
+
+               init_timer(&hba[i]->timer);
+               hba[i]->timer.expires = jiffies + IDA_TIMER;
+               hba[i]->timer.data = (unsigned long)hba[i];
+               hba[i]->timer.function = ida_timer;
+               add_timer(&hba[i]->timer);
+
+       }
+       /* done ! */
+       return;
+bail5:
+       kfree(ida_hardsizes);
+bail4:
+       kfree(ida_blocksizes);
+bail3:
+       kfree(ida_sizes);
+bail2:
+       kfree(ida);
+bail:
+       printk(KERN_ERR "cpqarray: out of memory.\n");
+}
+
+/*
+ * Find the controller and initialize it
+ *  Cannot use the class code to search, because older array controllers use
+ *    0x018000 and new ones use 0x010400.  So I might as well search for each
+ *    each device IDs, being there are only going to be three of them. 
+ */
+static int cpqarray_pci_detect(void)
+{
+       int index;
+       unchar bus=0, dev_fn=0;
+       
+       /* This seems dumb, surely we could use an array of types to match ?? */
+
+       for(index=0; ; index++) {
+               if (pcibios_find_device(PCI_VENDOR_ID_DEC,
+                        PCI_DEVICE_ID_COMPAQ_42XX, index, &bus, &dev_fn))
+                       break;
+               printk(KERN_DEBUG "42XX Device has been found at %x %x\n",
+                               bus, dev_fn);
+               if (index == 1000000) break;
+               if (nr_ctlr == 8) {
+                       printk("This driver supports a maximum of "
+                               "8 controllers.\n");
+                       break;
+               }
+               
+               hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+               if(hba[nr_ctlr]==NULL)
+               {
+                       printk(KERN_ERR "cpqarray: out of memory.\n");
+                       continue;
+               }
+               memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+               if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
+                       continue;
+               sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+               hba[nr_ctlr]->ctlr = nr_ctlr;
+               nr_ctlr++;
+       }
+
+       for(index=0; ; index++) {
+               unsigned short subvendor=0;
+
+                if (pcibios_find_device(PCI_VENDOR_ID_NCR,
+                         PCI_DEVICE_ID_NCR_53C1510, index, &bus, &dev_fn))
+                        break;
+                printk(KERN_DEBUG "Integrated RAID Chip has been found at %x %x\n",
+                                bus, dev_fn);
+               if(pcibios_read_config_word(bus, dev_fn, 
+                       PCI_SUBSYSTEM_VENDOR_ID, &subvendor))   
+               {
+                       printk(KERN_DEBUG "cpqarray failed to read subvendor\n");
+                       break;
+               }
+               if(subvendor !=  PCI_VENDOR_ID_COMPAQ)
+                       break;
+               printk(KERN_DEBUG "Its a compaq RAID Chip\n");
+                if (index == 1000000) break;
+                if (nr_ctlr == 8) {
+                        printk("This driver supports a maximum of "
+                                "8 controllers.\n");
+                        break;
+                }
+
+                hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+                if(hba[nr_ctlr]==NULL)
+                {
+                       printk(KERN_ERR "cpqarray: out of memory.\n");
+                       continue;
+                }
+                memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+                /* DOESNT THIS LEAK MEMORY ?????? - AC */
+                if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
+                        continue;
+                sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+                hba[nr_ctlr]->ctlr = nr_ctlr;
+                nr_ctlr++;
+        }
+
+       for(index=0; ; index++) {
+               if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
+                       PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn))
+                       break;
+
+               if (index == 1000000) break;
+               if (nr_ctlr == 8) {
+                       printk("This driver supports a maximum of "
+                               "8 controllers.\n");
+                       break;
+               }
+               
+               hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+               if(hba[nr_ctlr]==NULL)
+                {
+                       printk(KERN_ERR "cpqarray: out of memory.\n");
+                       continue;
+                }
+               memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+               if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
+                       continue;
+               sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+               hba[nr_ctlr]->ctlr = nr_ctlr;
+               nr_ctlr++;
+       }
+
+       return nr_ctlr;
+}
+/*
+ * Find the IO address of the controller, its IRQ and so forth.  Fill
+ * in some basic stuff into the ctlr_info_t structure.
+ */
+static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
+{
+       ushort vendor_id, device_id, command;
+       unchar cache_line_size, latency_timer;
+       unchar irq, revision;
+       uint addr[6];
+       __u32 board_id;
+       struct pci_dev *pdev;
+
+       int i;
+
+       pdev = pci_find_slot(bus, device_fn);
+       vendor_id = pdev->vendor;
+       device_id = pdev->device;
+       irq = pdev->irq;
+
+       for(i=0; i<6; i++)
+               addr[i] = pdev->base_address[i];
+
+       (void) pcibios_read_config_word(bus, device_fn,
+                                       PCI_COMMAND,&command);
+       (void) pcibios_read_config_byte(bus, device_fn,
+                                       PCI_CLASS_REVISION,&revision);
+       (void) pcibios_read_config_byte(bus, device_fn,
+                                       PCI_CACHE_LINE_SIZE, &cache_line_size);
+       (void) pcibios_read_config_byte(bus, device_fn,
+                                       PCI_LATENCY_TIMER, &latency_timer);
+
+       (void) pcibios_read_config_dword(bus, device_fn, 0x2c, &board_id);
+
+DBGINFO(
+       printk("vendor_id = %x\n", vendor_id);
+       printk("device_id = %x\n", device_id);
+       printk("command = %x\n", command);
+       for(i=0; i<6; i++)
+               printk("addr[%d] = %x\n", i, addr[i]);
+       printk("revision = %x\n", revision);
+       printk("irq = %x\n", irq);
+       printk("cache_line_size = %x\n", cache_line_size);
+       printk("latency_timer = %x\n", latency_timer);
+       printk("board_id = %x\n", board_id);
+);
+
+       c->intr = irq;
+       c->ioaddr = addr[0] & ~0x1;
+
+       /*
+        * Memory base addr is first addr with the first bit _not_ set
+        */
+       for(i=0; i<6; i++)
+               if (!(addr[i] & 0x1)) {
+                       c->paddr = addr[i];
+                       break;
+               }
+       c->vaddr = remap_pci_mem(c->paddr, 128);
+       c->board_id = board_id;
+
+       for(i=0; i<NR_PRODUCTS; i++) {
+               if (board_id == products[i].board_id) {
+                       c->product_name = products[i].product_name;
+                       c->access = *(products[i].access);
+                       break;
+               }
+       }
+       if (i == NR_PRODUCTS) {
+               printk("Sorry, I don't know how to access the SMART Array"
+                       " controller %08lx\n", (unsigned long)board_id);
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Map (physical) PCI mem into (virtual) kernel space
+ */
+static ulong remap_pci_mem(ulong base, ulong size)
+{
+        ulong page_base        = ((ulong) base) & PAGE_MASK;
+        ulong page_offs        = ((ulong) base) - page_base;
+        ulong page_remapped    = (ulong) ioremap(page_base, page_offs+size);
+
+        return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);
+}
+
+/*
+ * Copy the contents of the ints[] array passed to us by init.
+ */
+void cpqarray_setup(char *str, int *ints)
+{
+       int i;
+       for(i=0; i<ints[0] && i<8; i++)
+               eisa[i] = ints[i+1];
+}
+
+/*
+ * Find an EISA controller's signature.  Set up an hba if we find it.
+ */
+static int cpqarray_eisa_detect(void)
+{
+       int i=0, j;
+       __u32 board_id;
+       int intr;
+
+       while(i<8 && eisa[i]) {
+               if (nr_ctlr == 8) {
+                       printk("This driver supports a maximum of "
+                               "8 controllers.\n");
+                       break;
+               }
+               board_id = inl(eisa[i]+0xC80);
+               for(j=0; j < NR_PRODUCTS; j++)
+                       if (board_id == products[j].board_id) 
+                               break;
+
+               if (j == NR_PRODUCTS) {
+                       printk("Sorry, I don't know how to access the SMART"
+                         " Array controller %08lx\n", (unsigned long)board_id);
+                       continue;
+               }
+               hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+               if(hba[nr_ctlr]==NULL)
+               {
+                       printk(KERN_ERR "cpqarray: out of memory.\n");
+                       continue;
+               }
+               memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+               hba[nr_ctlr]->ioaddr = eisa[i];
+
+               /*
+                * Read the config register to find our interrupt
+                */
+               intr = inb(eisa[i]+0xCC0) >> 4;
+               if (intr & 1) intr = 11;
+               else if (intr & 2) intr = 10;
+               else if (intr & 4) intr = 14;
+               else if (intr & 8) intr = 15;
+               
+               hba[nr_ctlr]->intr = intr;
+               sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+               hba[nr_ctlr]->product_name = products[j].product_name;
+               hba[nr_ctlr]->access = *(products[j].access);
+               hba[nr_ctlr]->ctlr = nr_ctlr;
+               hba[nr_ctlr]->board_id = board_id;
+
+DBGINFO(
+       printk("i = %d, j = %d\n", i, j);
+       printk("irq = %x\n", intr);
+       printk("product name = %s\n", products[j].product_name);
+       printk("board_id = %x\n", board_id);
+);
+
+               nr_ctlr++;
+               i++;
+       }
+
+       return nr_ctlr;
+}
+
+
+/*
+ * Open.  Make sure the device is really there.
+ */
+static int ida_open(struct inode *inode, struct file *filep)
+{
+       int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+       int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+       DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
+       if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
+               return -ENXIO;
+
+       if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) +
+                                               MINOR(inode->i_rdev)] == 0)
+               return -ENXIO;
+
+       /*
+        * Root is allowed to open raw volume zero even if its not configured
+        * so array config can still work.  I don't think I really like this,
+        * but I'm already using way to many device nodes to claim another one
+        * for "raw controller".
+        */
+       if (suser()
+               && ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0 
+               && MINOR(inode->i_rdev) != 0)
+               return -ENXIO;
+
+       hba[ctlr]->drv[dsk].usage_count++;
+       hba[ctlr]->usage_count++;
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+/*
+ * Close.  Sync first.
+ */
+static int ida_release(struct inode *inode, struct file *filep)
+{
+       int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+       int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+       DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
+       fsync_dev(inode->i_rdev);
+
+       hba[ctlr]->drv[dsk].usage_count--;
+       hba[ctlr]->usage_count--;
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+/*
+ * Enqueuing and dequeuing functions for cmdlists.
+ */
+static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c)
+{
+       if (*Qptr == NULL) {
+               *Qptr = c;
+               c->next = c->prev = c;
+       } else {
+               c->prev = (*Qptr)->prev;
+               c->next = (*Qptr);
+               (*Qptr)->prev->next = c;
+               (*Qptr)->prev = c;
+       }
+}
+
+static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
+{
+       if (c && c->next != c) {
+               if (*Qptr == c) *Qptr = c->next;
+               c->prev->next = c->next;
+               c->next->prev = c->prev;
+       } else {
+               *Qptr = NULL;
+       }
+       return c;
+}
+
+/*
+ * Get a request and submit it to the controller.
+ * This routine needs to grab all the requests it possibly can from the
+ * req Q and submit them.  Interrupts are off (and need to be off) when you
+ * are in here (either via the dummy do_ida_request functions or by being
+ * called from the interrupt handler
+ */
+static void do_ida_request(int ctlr)
+{
+       ctlr_info_t *h = hba[ctlr];
+       cmdlist_t *c;
+       int seg, sect;
+       char *lastdataend;
+       struct buffer_head *bh;
+       struct request *creq;
+
+       creq = blk_dev[MAJOR_NR+ctlr].current_request;
+       if (creq == NULL || creq->rq_status == RQ_INACTIVE)
+               goto doreq_done;
+
+       if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ||
+               ctlr > nr_ctlr || h == NULL) {
+               printk("doreq cmd for %d, %x at %p\n",
+                               ctlr, creq->rq_dev, creq);
+               complete_buffers(creq->bh, 0);
+               goto doreq_done;
+       }
+
+       if ((c = cmd_alloc(h)) == NULL)
+               goto doreq_done;
+
+       bh = creq->bh;
+
+       c->ctlr = ctlr;
+       c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
+       c->hdr.size = sizeof(rblk_t) >> 2;
+       c->size += sizeof(rblk_t);
+
+       c->req.hdr.blk = ida[(ctlr<<CTLR_SHIFT) + MINOR(creq->rq_dev)].start_sect + creq->sector;
+       c->bh = bh;
+DBGPX(
+       if (bh == NULL)
+               panic("bh == NULL?");
+       
+       printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);
+);
+       seg = 0; lastdataend = NULL;
+       sect = 0;
+       while(bh) {
+               sect += bh->b_size/512;
+DBGPX(
+               if (bh->b_size % 512) {
+                       printk("Oh damn.  %d+%d, size = %d\n", creq->sector, sect, bh->b_size);
+                       panic("b_size %% 512 != 0");
+               }
+);
+               if (bh->b_data == lastdataend) {
+                       c->req.sg[seg-1].size += bh->b_size;
+                       lastdataend += bh->b_size;
+               } else {
+                       c->req.sg[seg].size = bh->b_size;
+                       c->req.sg[seg].addr = (__u32)virt_to_bus(bh->b_data);
+                       lastdataend = bh->b_data + bh->b_size;
+                       if (++seg == SG_MAX)
+                               break;
+               }
+               bh = bh->b_reqnext;
+       }
+DBGPX( printk("Submitting %d sectors in %d segments\n", sect, seg); );
+       c->req.hdr.sg_cnt = seg;
+       c->req.hdr.blk_cnt = sect;
+
+       creq->sector += sect;
+       creq->nr_sectors -= sect;
+
+       /* Ready the next request:
+        * Fix up creq if we still have more buffers in the buffer chain, or
+        * mark this request as done and ready the next one.
+         */
+       if (creq->nr_sectors) {
+DBGPX(
+               if (bh==NULL) {
+                       printk("sector=%d, nr_sectors=%d, sect=%d, seg=%d\n",
+                               creq->sector, creq->nr_sectors, sect, seg);
+                       panic("mother...");
+               }
+);
+               creq->bh = bh->b_reqnext;
+               bh->b_reqnext = NULL;
+DBGPX(         printk("More to do on same request %p\n", creq); );
+       } else {
+DBGPX(         printk("Done with %p, queueing %p\n", creq, creq->next); );
+               creq->rq_status = RQ_INACTIVE;
+               blk_dev[MAJOR_NR+ctlr].current_request = creq->next;
+               wake_up(&wait_for_request);
+       }
+
+       c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE;
+       c->type = CMD_RWREQ;
+
+       /* Put the request on the tail of the request queue */
+       addQ(&h->reqQ, c);
+       h->Qdepth++;
+       if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth;
+
+doreq_done:
+       start_io(h);
+}
+
+/* 
+ * start_io submits everything on a controller's request queue
+ * and moves it to the completion queue.
+ *
+ * Interrupts had better be off if you're in here
+ */
+static void start_io(ctlr_info_t *h)
+{
+       cmdlist_t *c;
+
+       while((c = h->reqQ) != NULL) {
+               /* Can't do anything if we're busy */
+               if (h->access.fifo_full(h) == 0)
+                       return;
+
+               /* Get the first entry from the request Q */
+               removeQ(&h->reqQ, c);
+               h->Qdepth--;
+       
+               /* Tell the controller to do our bidding */
+               h->access.submit_command(h, c);
+
+               /* Get onto the completion Q */
+               addQ(&h->cmpQ, c);
+       }
+}
+
+static inline void complete_buffers(struct buffer_head *bh, int ok)
+{
+       struct buffer_head *xbh;
+       while(bh) {
+               xbh = bh->b_reqnext;
+               bh->b_reqnext = NULL;
+               
+               bh->b_end_io(bh, ok);
+
+               bh = xbh;
+       }
+}
+/*
+ * Mark all buffers that cmd was responsible for
+ */
+static inline void complete_command(cmdlist_t *cmd, int timeout)
+{
+       char buf[80];
+       int ok=1;
+
+       if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
+          (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
+               sprintf(buf, "Non Fatal error on ida/c%dd%d\n",
+                               cmd->ctlr, cmd->hdr.unit);
+               console_print(buf);
+               hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
+       }
+       if (cmd->req.hdr.rcode & RCODE_FATAL) {
+               sprintf(buf, "Fatal error on ida/c%dd%d\n",
+                               cmd->ctlr, cmd->hdr.unit);
+               console_print(buf);
+               ok = 0;
+       }
+       if (cmd->req.hdr.rcode & RCODE_INVREQ) {
+                               sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
+                               cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,
+                               cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,
+                               cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
+               console_print(buf);
+               ok = 0; 
+       }
+       if (timeout) ok = 0;
+       complete_buffers(cmd->bh, ok);
+}
+
+/*
+ *  The controller will interrupt us upon completion of commands.
+ *  Find the command on the completion queue, remove it, tell the OS and
+ *  try to queue up more IO
+ */
+static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       ctlr_info_t *h = dev_id;
+       cmdlist_t *c;
+       unsigned long istat;
+       unsigned long flags;
+       __u32 a,a1;
+
+
+       istat = h->access.intr_pending(h);
+       /* Is this interrupt for us? */
+       if (istat == 0)
+               return;
+
+       /*
+        * If there are completed commands in the completion queue,
+        * we had better do something about it.
+        */
+       spin_lock_irqsave(&io_request_lock, flags);
+       if (istat & FIFO_NOT_EMPTY) {
+               while((a = h->access.command_completed(h))) {
+                       a1 = a; a &= ~3;
+                       if ((c = h->cmpQ) == NULL) goto bad_completion;
+                       while(c->busaddr != a) {
+                               c = c->next;
+                               if (c == h->cmpQ) break;
+                       }
+                       /*
+                        * If we've found the command, take it off the
+                        * completion Q and free it
+                        */
+                       if (c->busaddr == a) {
+                               removeQ(&h->cmpQ, c);
+                               if (c->type == CMD_RWREQ) {
+                                       complete_command(c, 0);
+                                       cmd_free(h, c);
+                               } else if (c->type == CMD_IOCTL_PEND) {
+                                       c->type = CMD_IOCTL_DONE;
+                               }
+                               continue;
+                       }
+bad_completion:
+                       printk("Completion of %08lx ignored\n", (unsigned long)a1);
+               }
+       }
+
+       /*
+        * See if we can queue up some more IO
+        */
+       do_ida_request(h->ctlr);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/*
+ * This timer was for timing out requests that haven't happened after
+ * IDA_TIMEOUT.  That wasn't such a good idea.  This timer is used to
+ * reset a flags structure so we don't flood the user with
+ * "Non-Fatal error" messages.
+ */
+static void ida_timer(unsigned long tdata)
+{
+       ctlr_info_t *h = (ctlr_info_t*)tdata;
+
+       h->timer.expires = jiffies + IDA_TIMER;
+       add_timer(&h->timer);
+       h->misc_tflags = 0;
+}
+
+/*
+ *  ida_ioctl does some miscellaneous stuff like reporting drive geometry,
+ *  setting readahead and submitting commands from userspace to the controller.
+ */
+static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+       int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+       int error;
+       int diskinfo[4];
+       struct hd_geometry *geo = (struct hd_geometry *)arg;
+       ida_ioctl_t *io = (ida_ioctl_t*)arg;
+       ida_ioctl_t my_io;
+
+       switch(cmd) {
+       case HDIO_GETGEO:
+               if (hba[ctlr]->drv[dsk].cylinders) {
+                       diskinfo[0] = hba[ctlr]->drv[dsk].heads;
+                       diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
+                       diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
+               } else {
+                       diskinfo[0] = 0xff;
+                       diskinfo[1] = 0x3f;
+                       diskinfo[2] = hba[ctlr]->drv[dsk].nr_blks / (0xff*0x3f);
+               }
+               put_user(diskinfo[0], &geo->heads);
+               put_user(diskinfo[1], &geo->sectors);
+               put_user(diskinfo[2], &geo->cylinders);
+               put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].start_sect, &geo->start);
+               return 0;
+       case IDAGETDRVINFO:
+               return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
+       case BLKGETSIZE:
+               if (!arg) return -EINVAL;
+               put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].nr_sects, (long*)arg);
+               return 0;
+       case BLKRRPART:
+               return revalidate_logvol(inode->i_rdev, 1);
+       case IDAPASSTHRU:
+               if (!suser()) return -EPERM;
+               error = copy_from_user(&my_io, io, sizeof(my_io));
+               if (error) return error;
+               error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
+               if (error) return error;
+               error = copy_to_user(io, &my_io, sizeof(my_io));
+               return error;
+       case IDAGETCTLRSIG:
+               if (!arg) return -EINVAL;
+               put_user(hba[ctlr]->ctlr_sig, (int*)arg);
+               return 0;
+       case IDAREVALIDATEVOLS:
+               return revalidate_allvol(inode->i_rdev);
+       case IDADRIVERVERSION:
+               if (!arg) return -EINVAL;
+               put_user(DRIVER_VERSION, (unsigned long*)arg);
+               return 0;
+
+       case BLKFLSBUF:
+       case BLKROSET:
+       case BLKROGET:
+       case BLKRASET:
+       case BLKRAGET:
+       case BLKPG:
+               return blk_ioctl(inode->i_rdev, cmd, arg);
+
+       default:
+               return -EBADRQC;
+       }
+               
+}
+/*
+ * ida_ctlr_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ * however, any elements in the sglist need to be copied to kernel space
+ * or copied back to userspace.
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments.  Doing an IDA_WRITE_MEDIA and
+ * putting a 64M buffer in the sglist is probably a *bad* idea.
+ */
+static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
+{
+       ctlr_info_t *h = hba[ctlr];
+       cmdlist_t *c;
+       void *p = NULL;
+       unsigned long flags;
+       int error;
+
+       if ((c = cmd_alloc(NULL)) == NULL)
+               return -ENOMEM;
+       c->ctlr = ctlr;
+       c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk;
+       c->hdr.size = sizeof(rblk_t) >> 2;
+       c->size += sizeof(rblk_t);
+
+       c->req.hdr.cmd = io->cmd;
+       c->req.hdr.blk = io->blk;
+       c->req.hdr.blk_cnt = io->blk_cnt;
+       c->type = CMD_IOCTL_PEND;
+
+       /* Pre submit processing */
+       switch(io->cmd) {
+       case PASSTHRU_A:
+               p = kmalloc(io->sg[0].size, GFP_KERNEL);
+               if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+               copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
+               c->req.bp = virt_to_bus(&(io->c));
+               c->req.sg[0].size = io->sg[0].size;
+               c->req.sg[0].addr = virt_to_bus(p);
+               c->req.hdr.sg_cnt = 1;
+               break;
+       case IDA_READ:
+               p = kmalloc(io->sg[0].size, GFP_KERNEL);
+               if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+               c->req.sg[0].size = io->sg[0].size;
+               c->req.sg[0].addr = virt_to_bus(p);
+               c->req.hdr.sg_cnt = 1;
+               break;
+       case IDA_WRITE:
+       case IDA_WRITE_MEDIA:
+       case DIAG_PASS_THRU:
+               p = kmalloc(io->sg[0].size, GFP_KERNEL);
+               if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+               copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
+               c->req.sg[0].size = io->sg[0].size;
+               c->req.sg[0].addr = virt_to_bus(p);
+               c->req.hdr.sg_cnt = 1;
+               break;
+       default:
+               c->req.sg[0].size = sizeof(io->c);
+               c->req.sg[0].addr = virt_to_bus(&io->c);
+               c->req.hdr.sg_cnt = 1;
+       }
+
+       /* Put the request on the tail of the request queue */
+       spin_lock_irqsave(&io_request_lock, flags);
+       addQ(&h->reqQ, c);
+       h->Qdepth++;
+       start_io(h);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+
+       /* Wait for completion */
+       while(c->type != CMD_IOCTL_DONE)
+               schedule();
+
+       /* Post submit processing */
+       switch(io->cmd) {
+       case PASSTHRU_A:
+       case IDA_READ:
+       case DIAG_PASS_THRU:
+               copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size);
+               /* fall through and free p */
+       case IDA_WRITE:
+       case IDA_WRITE_MEDIA:
+               kfree(p);
+               break;
+       default:
+               /* Nothing to do */
+       }
+
+       io->rcode = c->req.hdr.rcode;
+       error = 0;
+ioctl_err_exit:
+       cmd_free(NULL, c);
+       return error;
+}
+
+/*
+ * Commands are pre-allocated in a large block.  Here we use a simple bitmap
+ * scheme to suballocte them to the driver.  Operations that are not time
+ * critical (and can wait for kmalloc and possibly sleep) can pass in NULL
+ * as the first argument to get a new command.
+ */
+static cmdlist_t * cmd_alloc(ctlr_info_t *h)
+{
+       cmdlist_t * c;
+       int i;
+
+       if (h == NULL) {
+               c = (cmdlist_t*)kmalloc(sizeof(cmdlist_t), GFP_KERNEL);
+               if(c==NULL)
+                       return NULL;
+       } else {
+               do {
+                       i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+                       if (i == NR_CMDS)
+                               return NULL;
+               } while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);
+               c = h->cmd_pool + i;
+               h->nr_allocs++;
+       }
+
+       memset(c, 0, sizeof(cmdlist_t));
+       c->busaddr = virt_to_bus(c);
+       return c;
+}
+
+static void cmd_free(ctlr_info_t *h, cmdlist_t *c)
+{
+       int i;
+
+       if (h == NULL) {
+               kfree(c);
+       } else {
+               i = c - h->cmd_pool;
+               clear_bit(i%32, h->cmd_pool_bits+(i/32));
+               h->nr_frees++;
+       }
+}
+
+/***********************************************************************
+    name:        sendcmd
+    Send a command to an IDA using the memory mapped FIFO interface
+    and wait for it to complete.  
+    This routine should only be called at init time.
+***********************************************************************/
+static int sendcmd(
+       __u8    cmd,
+       int     ctlr,
+       void    *buff,
+       size_t  size,
+       unsigned int blk,
+       unsigned int blkcnt,
+       unsigned int log_unit )
+{
+       cmdlist_t *c;
+       int complete;
+       unsigned long temp;
+       unsigned long i;
+       ctlr_info_t *info_p = hba[ctlr];
+
+       c = cmd_alloc(info_p);
+       c->ctlr = ctlr;
+       c->hdr.unit = log_unit;
+       c->hdr.prio = 0;
+       c->hdr.size = sizeof(rblk_t) >> 2;
+       c->size += sizeof(rblk_t);
+
+       /* The request information. */
+       c->req.hdr.next = 0;
+       c->req.hdr.rcode = 0;
+       c->req.bp = 0;
+       c->req.hdr.sg_cnt = 1;
+       c->req.hdr.reserved = 0;
+       
+       if (size == 0)
+               c->req.sg[0].size = 512;
+       else
+               c->req.sg[0].size = size;
+
+       c->req.hdr.blk = blk;
+       c->req.hdr.blk_cnt = blkcnt;
+       c->req.hdr.cmd = (unsigned char) cmd;
+       c->req.sg[0].addr = (__u32) virt_to_bus(buff);
+       /*
+        * Disable interrupt
+        */
+       info_p->access.set_intr_mask(info_p, 0);
+       /* Make sure there is room in the command FIFO */
+       /* Actually it should be completely empty at this time. */
+       for (i = 200000; i > 0; i--) {
+               temp = info_p->access.fifo_full(info_p);
+               if (temp != 0) {
+                       break;
+               }
+               udelay(10);
+DBG(
+               printk("ida%d: idaSendPciCmd FIFO full, waiting!\n",
+                      ctlr);
+);
+       } 
+       /*
+        * Send the cmd
+        */
+       info_p->access.submit_command(info_p, c);
+       complete = pollcomplete(ctlr);
+       if (complete != 1) {
+               if (complete != c->busaddr) {
+                       printk(
+                       "ida%d: idaSendPciCmd "
+                     "Invalid command list address returned! (%08lx)\n",
+                               ctlr, (unsigned long)complete);
+                       cmd_free(info_p, c);
+                       return (IO_ERROR);
+               }
+       } else {
+               printk(
+                       "ida%d: idaSendPciCmd Timeout out, "
+                       "No command list address returned!\n",
+                       ctlr);
+               cmd_free(info_p, c);
+               return (IO_ERROR);
+       }
+
+       if (c->req.hdr.rcode & 0x00FE) {
+               if (!(c->req.hdr.rcode & BIG_PROBLEM)) {
+                       printk(
+                       "ida%d: idaSendPciCmd, error: Controller failed "
+                               "at init time "
+                               "cmd: 0x%x, return code = 0x%x\n",
+                               ctlr, c->req.hdr.cmd, c->req.hdr.rcode);
+
+                       cmd_free(info_p, c);
+                       return (IO_ERROR);
+               }
+       }
+       cmd_free(info_p, c);
+       return (IO_OK);
+}
+
+static int frevalidate_logvol(kdev_t dev)
+{
+       return revalidate_logvol(dev, 0);
+}
+
+/*
+ * revalidate_allvol is for online array config utilities.  After a
+ * utility reconfigures the drives in the array, it can use this function
+ * (through an ioctl) to make the driver zap any previous disk structs for
+ * that controller and get new ones.
+ *
+ * Right now I'm using the getgeometry() function to do this, but this
+ * function should probably be finer grained and allow you to revalidate one
+ * particualar logical volume (instead of all of them on a particular
+ * controller).
+ */
+static int revalidate_allvol(kdev_t dev)
+{
+       int ctlr, i;
+       unsigned long flags;
+
+       ctlr = MAJOR(dev) - MAJOR_NR;
+       if (MINOR(dev) != 0)
+               return -ENXIO;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       if (hba[ctlr]->usage_count > 1) {
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               printk("Device busy for volume revalidation (usage=%d)\n",
+                                       hba[ctlr]->usage_count);
+               return -EBUSY;
+       }
+       spin_unlock_irqrestore(&io_request_lock, flags);
+       hba[ctlr]->usage_count++;
+
+       /*
+        * Set the partition and block size structures for all volumes
+        * on this controller to zero.  We will reread all of this data
+        */
+       memset(ida+(ctlr*256),            0, sizeof(struct hd_struct)*NWD*16);
+       memset(ida_sizes+(ctlr*256),      0, sizeof(int)*NWD*16);
+       memset(ida_blocksizes+(ctlr*256), 0, sizeof(int)*NWD*16);
+       memset(ida_hardsizes+(ctlr*256),  0, sizeof(int)*NWD*16);
+       memset(hba[ctlr]->drv,            0, sizeof(drv_info_t)*NWD);
+       ida_gendisk[ctlr].nr_real = 0;
+
+       /*
+        * Tell the array controller not to give us any interupts while
+        * we check the new geometry.  Then turn interrupts back on when
+        * we're done.
+        */
+       hba[ctlr]->access.set_intr_mask(hba[ctlr], 0);
+       getgeometry(ctlr);
+       hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY);
+
+       ida_geninit(&ida_gendisk[ctlr]);
+       for(i=0; i<NWD; i++)
+               if (ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)])
+                       revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
+
+       hba[ctlr]->usage_count--;
+       return 0;
+}
+
+/* Borrowed and adapted from sd.c */
+static int revalidate_logvol(kdev_t dev, int maxusage)
+{
+       int ctlr, target;
+       struct gendisk *gdev;
+       unsigned long flags;
+       int max_p;
+       int start;
+       int i;
+
+       target = DEVICE_NR(dev);
+       ctlr = MAJOR(dev) - MAJOR_NR;
+       gdev = &ida_gendisk[ctlr];
+       
+       spin_lock_irqsave(&io_request_lock, flags);
+       if (hba[ctlr]->drv[target].usage_count > maxusage) {
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               printk("Device busy for revalidation (usage=%d)\n",
+                                       hba[ctlr]->drv[target].usage_count);
+               return -EBUSY;
+       }
+
+       hba[ctlr]->drv[target].usage_count++;
+       spin_unlock_irqrestore(&io_request_lock, flags);
+
+       max_p = gdev->max_p;
+       start = target << gdev->minor_shift;
+
+       for(i=max_p; i>=0; i--) {
+               int minor = start+i;
+               kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
+               struct super_block *sb = get_super(devi);
+               sync_dev(devi);
+               if (sb) invalidate_inodes(sb);
+               invalidate_buffers(devi);
+               gdev->part[minor].start_sect = 0;       
+               gdev->part[minor].nr_sects = 0; 
+
+               /* reset the blocksize so we can read the partition table */
+               blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+       }
+
+       gdev->part[start].nr_sects =  hba[ctlr]->drv[target].nr_blks;
+       resetup_one_dev(gdev, target);
+       hba[ctlr]->drv[target].usage_count--;
+       return 0;
+}
+
+
+/********************************************************************
+    name: pollcomplete
+    Wait polling for a command to complete.
+    The memory mapped FIFO is polled for the completion.
+    Used only at init time, interrupts disabled.
+ ********************************************************************/
+static int pollcomplete(int ctlr)
+{
+       int done;
+       int i;
+
+       /* Wait (up to 2 seconds) for a command to complete */
+
+       for (i = 200000; i > 0; i--) {
+               done = hba[ctlr]->access.command_completed(hba[ctlr]);
+               if (done == 0) {
+                       udelay(10);     /* a short fixed delay */
+               } else
+                       return (done);
+       }
+       /* Invalid address to tell caller we ran out of time */
+       return 1;
+}
+/*****************************************************************
+    start_fwbk
+    Starts controller firmwares background processing. 
+    Currently only the Integrated Raid controller needs this done.
+    If the PCI mem address registers are written to after this, 
+        data corruption may occur
+*****************************************************************/
+static void start_fwbk(int ctlr)
+{
+               id_ctlr_t *id_ctlr_buf; 
+       int ret_code;
+
+       if(     hba[ctlr]->board_id != 0x40400E11)
+       /* Not a Integrated Raid, so there is nothing for us to do */
+               return;
+       printk(KERN_DEBUG "Starting firmware's background processing\n");
+       /* Command does not return anything, but idasend command needs a 
+               buffer */
+       id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+       if(id_ctlr_buf==NULL)
+       {
+               printk(KERN_WARNING "Out of memory. Unable to start background processing.\n");
+               return;
+       }               
+       ret_code = sendcmd(RESUME_BACKGROUND_ACTIVITY, ctlr, 
+               id_ctlr_buf, 0, 0, 0, 0);
+       if(ret_code != IO_OK)
+               printk(KERN_WARNING "Unable to start background processing\n");
+       kfree(id_ctlr_buf);
+}
+/*****************************************************************
+    getgeometry
+    Get ida logical volume geometry from the controller 
+    This is a large bit of code which once existed in two flavors,
+    It is used only at init time.
+*****************************************************************/
+static void getgeometry(int ctlr)
+{                              
+       id_log_drv_t *id_ldrive;
+       id_ctlr_t *id_ctlr_buf;
+       sense_log_drv_stat_t *id_lstatus_buf;
+       config_t *sense_config_buf;
+       unsigned int log_unit, log_index;
+       int ret_code, size;
+       drv_info_t *drv;
+       ctlr_info_t *info_p = hba[ctlr];
+
+       info_p->log_drv_map = 0;        
+       
+       id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
+       if(id_ldrive == NULL)
+               return;
+       id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+       if(id_ctlr_buf == NULL)
+               goto bail2;
+       id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
+       if(id_lstatus_buf == NULL)
+               goto bail3;
+       sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
+       if(sense_config_buf == NULL)
+               goto bail4;
+       memset(id_ldrive, 0, sizeof(id_log_drv_t));
+       memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));
+       memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));
+       memset(sense_config_buf, 0, sizeof(config_t));
+
+       info_p->phys_drives = 0;
+       info_p->log_drv_map = 0;
+       info_p->drv_assign_map = 0;
+       info_p->drv_spare_map = 0;
+       info_p->mp_failed_drv_map = 0;  /* only initialized here */
+       /* Get controllers info for this logical drive */
+       ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0);
+       if (ret_code == IO_ERROR) {
+               /*
+                * If can't get controller info, set the logical drive map to 0,
+                * so the idastubopen will fail on all logical drives
+                * on the controller.
+                */
+               goto geo_ret;   /* release the buf and return */
+       }
+       info_p->log_drives = id_ctlr_buf->nr_drvs;;
+       *(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev);
+       info_p->ctlr_sig = id_ctlr_buf->cfg_sig;
+
+       printk(" (%s)\n", info_p->product_name);
+       /*
+        * Initialize logical drive map to zero
+        */
+       log_index = 0;
+       /*
+        * Get drive geometry for all logical drives
+        */
+       if (id_ctlr_buf->nr_drvs > 16)
+               printk("ida%d:  This driver supports 16 logical drives "
+                       "per controller.\n.  Additional drives will not be "
+                       "detected\n", ctlr);
+
+       for (log_unit = 0;
+            (log_index < id_ctlr_buf->nr_drvs)
+            && (log_unit < NWD);
+            log_unit++) {
+
+               size = sizeof(sense_log_drv_stat_t);
+
+               /*
+                  Send "Identify logical drive status" cmd
+                */
+               ret_code = sendcmd(SENSE_LOG_DRV_STAT,
+                            ctlr, id_lstatus_buf, size, 0, 0, log_unit);
+               if (ret_code == IO_ERROR) {
+                       /*
+                          If can't get logical drive status, set
+                          the logical drive map to 0, so the
+                          idastubopen will fail for all logical drives
+                          on the controller. 
+                        */
+                       info_p->log_drv_map = 0;        
+                       printk(
+                            "ida%d: idaGetGeometry - Controller failed "
+                               "to report status of logical drive %d\n"
+                        "Access to this controller has been disabled\n",
+                               ctlr, log_unit);
+                       goto geo_ret;   /* release the buf and return */
+
+               }
+               /*
+                  Make sure the logical drive is configured
+                */
+               if (id_lstatus_buf->status != LOG_NOT_CONF) {
+                       ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive,
+                              sizeof(id_log_drv_t), 0, 0, log_unit);
+                       /*
+                          If error, the bit for this
+                          logical drive won't be set and
+                          idastubopen will return error. 
+                        */
+                       if (ret_code != IO_ERROR) {
+                               drv = &info_p->drv[log_unit];
+                               drv->blk_size = id_ldrive->blk_size;
+                               drv->nr_blks = id_ldrive->nr_blks;
+                               drv->cylinders = id_ldrive->drv.cyl;
+                               drv->heads = id_ldrive->drv.heads;
+                               drv->sectors = id_ldrive->drv.sect_per_track;
+                               info_p->log_drv_map |=  (1 << log_unit);
+
+       printk("ida/c%dd%d: blksz=%d nr_blks=%d\n",
+               ctlr, log_unit, drv->blk_size, drv->nr_blks);
+                               ret_code = sendcmd(SENSE_CONFIG,
+                                                 ctlr, sense_config_buf,
+                                sizeof(config_t), 0, 0, log_unit);
+                               if (ret_code == IO_ERROR) {
+                                       info_p->log_drv_map = 0;
+                                       goto geo_ret;   /* release the buf and return */
+                               }
+                               info_p->phys_drives =
+                                   sense_config_buf->ctlr_phys_drv;
+                               info_p->drv_assign_map
+                                   |= sense_config_buf->drv_asgn_map;
+                               info_p->drv_assign_map
+                                   |= sense_config_buf->spare_asgn_map;
+                               info_p->drv_spare_map
+                                   |= sense_config_buf->spare_asgn_map;
+                       }       /* end of if no error on id_ldrive */
+                       log_index = log_index + 1;
+               }               /* end of if logical drive configured */
+       }                       /* end of for log_unit */
+geo_ret:
+       kfree(sense_config_buf);
+bail4: 
+       kfree(id_ldrive);
+bail3:
+       kfree(id_lstatus_buf);
+bail2: 
+       kfree(id_ctlr_buf);
+}
diff --git a/drivers/block/cpqarray.h b/drivers/block/cpqarray.h
new file mode 100644 (file)
index 0000000..457d44a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef CPQARRAY_H
+#define CPQARRAY_H
+
+#ifdef __KERNEL__
+#include <linux/blkdev.h>
+#include <linux/locks.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+#include <linux/proc_fs.h>
+#include <linux/md.h>
+#include <linux/timer.h>
+#endif
+
+#include "ida_cmd.h"
+
+#define IO_OK          0
+#define IO_ERROR       1
+#define NWD            16
+#define NWD_SHIFT      4
+
+#define IDA_TIMER      (5*HZ)
+#define IDA_TIMEOUT    (10*HZ)
+
+#define MISC_NONFATAL_WARN     0x01
+
+typedef struct {
+       unsigned blk_size;
+       unsigned nr_blks;
+       unsigned cylinders;
+       unsigned heads;
+       unsigned sectors;
+       int usage_count;
+} drv_info_t;
+
+#ifdef __KERNEL__
+
+struct ctlr_info;
+typedef struct ctlr_info ctlr_info_t;
+
+struct access_method {
+       void (*submit_command)(ctlr_info_t *h, cmdlist_t *c);
+       void (*set_intr_mask)(ctlr_info_t *h, unsigned long val);
+       unsigned long (*fifo_full)(ctlr_info_t *h);
+       unsigned long (*intr_pending)(ctlr_info_t *h);
+       unsigned long (*command_completed)(ctlr_info_t *h);
+};
+
+struct board_type {
+       __u32   board_id;
+       char    *product_name;
+       struct access_method *access;
+};
+
+struct ctlr_info {
+       int     ctlr;
+       char    devname[8];
+       __u32   log_drv_map;
+       __u32   drv_assign_map;
+       __u32   drv_spare_map;
+       __u32   mp_failed_drv_map;
+
+       char    firm_rev[4];
+       int     ctlr_sig;
+
+       int     log_drives;
+       int     phys_drives;
+
+       __u32   board_id;
+       char    *product_name;  
+
+       __u32   vaddr;
+       __u32   paddr;
+       __u32   ioaddr;
+       int     intr;
+       int     usage_count;
+       drv_info_t      drv[NWD];
+       struct proc_dir_entry *proc;
+
+       struct access_method access;
+
+       cmdlist_t *reqQ;
+       cmdlist_t *cmpQ;
+       cmdlist_t *cmd_pool;
+       __u32   *cmd_pool_bits;
+
+       unsigned int Qdepth;
+       unsigned int maxQsinceinit;
+
+       unsigned int nr_requests;
+       unsigned int nr_allocs;
+       unsigned int nr_frees;
+       struct timer_list timer;
+       unsigned int misc_tflags;
+};
+#endif
+
+#endif /* CPQARRAY_H */
index 1eebf20a1284b52a0cb54876bd10af03f5293018..c3ac37354de9008457f4067ee225374bcec4e600 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 
 #include <asm/system.h>
+#include <asm/byteorder.h>
 
 /*
  * Many architectures don't like unaligned accesses, which is
@@ -60,6 +61,7 @@ extern int chr_dev_init(void);
 extern int blk_dev_init(void);
 extern int scsi_dev_init(void);
 extern int net_dev_init(void);
+extern int i2o_init(void);
 
 #ifdef CONFIG_PPC
 extern void note_bootable_part(kdev_t dev, int part);
@@ -112,6 +114,16 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
                        return buf;
                }
        }
+       if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
+               int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
+               int disk = minor >> hd->minor_shift;
+               int part = minor & (( 1 << hd->minor_shift) - 1);
+               if (part == 0)
+                       sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
+               else
+                       sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
+               return buf;
+       }
        if (part)
                sprintf(buf, "%s%c%d", maj, unit, part);
        else
@@ -121,10 +133,13 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
 
 static void add_partition (struct gendisk *hd, int minor, int start, int size)
 {
-       char buf[32];
+       char buf[40];
        hd->part[minor].start_sect = start;
        hd->part[minor].nr_sects   = size;
-       printk(" %s", disk_name(hd, minor, buf));
+       if (hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7)
+               printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+       else
+               printk(" %s", disk_name(hd, minor, buf));
 }
 
 static inline int is_extended_partition(struct partition *p)
@@ -222,7 +237,7 @@ static void extended_partition(struct gendisk *hd, kdev_t dev)
                if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
                        return;
 
-               if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
+               if ((*(__u16 *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
                        goto done;
 
                p = (struct partition *) (0x1BE + bh->b_data);
@@ -676,12 +691,10 @@ static int osf_partition(struct gendisk *hd, unsigned int dev, unsigned long fir
        label = (struct disklabel *) (bh->b_data+64);
        partition = label->d_partitions;
        if (label->d_magic != DISKLABELMAGIC) {
-               printk("magic: %08x\n", label->d_magic);
                brelse(bh);
                return 0;
        }
        if (label->d_magic2 != DISKLABELMAGIC) {
-               printk("magic2: %08x\n", label->d_magic2);
                brelse(bh);
                return 0;
        }
@@ -775,14 +788,11 @@ static int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sec
 #endif /* CONFIG_SUN_PARTITION */
 
 #ifdef CONFIG_SGI_PARTITION
-#include <asm/byteorder.h>
 
 static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
 {
-       int i, csum;
-       unsigned int *ui;
-       unsigned int start, blocks, cs;
-       int magic;
+       int i, csum, magic;
+       unsigned int *ui, start, blocks, cs;
        struct buffer_head *bh;
        struct sgi_disklabel {
                int magic_mushroom;         /* Big fat spliff... */
@@ -851,7 +861,6 @@ static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sec
 #endif
 
 #ifdef CONFIG_AMIGA_PARTITION
-#include <asm/byteorder.h>
 #include <linux/affs_hardblocks.h>
 
 static __inline__ u32
@@ -919,13 +928,14 @@ amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
                                blk = htonl(pb->pb_Next);
                                if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block(
                                    (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
-                                       
+
                                        /* Tell Kernel about it */
 
                                        if (!(nr_sects = (htonl(pb->pb_Environment[10]) + 1 -
                                                          htonl(pb->pb_Environment[9])) *
                                                         htonl(pb->pb_Environment[3]) *
                                                         htonl(pb->pb_Environment[5]))) {
+                                               brelse(bh);
                                                continue;
                                        }
                                        start_sect = htonl(pb->pb_Environment[9]) *
@@ -938,8 +948,9 @@ amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
                                brelse(bh);
                        }
                        printk("\n");
-                       break;
                }
+               else
+                       brelse(bh);
        }
 
 rdb_done:
@@ -1077,7 +1088,7 @@ static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
 #endif /* CONFIG_MAC_PARTITION */
 
 #ifdef CONFIG_ATARI_PARTITION
-#include <asm/atari_rootsec.h>
+#include <linux/atari_rootsec.h>
 
 /* ++guenther: this should be settable by the user ("make config")?.
  */
@@ -1091,16 +1102,27 @@ static int atari_partition (struct gendisk *hd, kdev_t dev,
   struct rootsector *rs;
   struct partition_info *pi;
   ulong extensect;
+  unsigned int psum;
+  int i;
 #ifdef ICD_PARTS
   int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
 #endif
 
   bh = bread (dev, 0, get_ptable_blocksize(dev));
-  if (!bh)
-    {
-      printk (" unable to read block 0\n");
+  if (!bh) {
+      printk (" unable to read block 0 (partition table)\n");
       return -1;
-    }
+  }
+
+  /* Verify this is an Atari rootsector: */
+  psum=0;
+  for (i=0;i<256;i++) {
+    psum+=ntohs(((__u16 *) (bh->b_data))[i]);
+  }
+  if ((psum & 0xFFFF) != 0x1234) {
+    brelse(bh);
+    return 0;
+  }
 
   rs = (struct rootsector *) bh->b_data;
   pi = &rs->part[0];
@@ -1121,7 +1143,7 @@ static int atari_partition (struct gendisk *hd, kdev_t dev,
              part_fmt = 1;
 #endif
              printk(" XGM<");
-             partsect = extensect = pi->st;
+             partsect = extensect = ntohl(pi->st);
              while (1)
                {
                  xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev));
@@ -1142,8 +1164,8 @@ static int atari_partition (struct gendisk *hd, kdev_t dev,
                    break;
                  }
 
-                 add_partition(hd, minor, partsect + xrs->part[0].st,
-                               xrs->part[0].siz);
+                 add_partition(hd, minor, partsect + ntohl(xrs->part[0].st),
+                               ntohl(xrs->part[0].siz));
 
                  if (!(xrs->part[1].flg & 1)) {
                    /* end of linked partition list */
@@ -1156,7 +1178,7 @@ static int atari_partition (struct gendisk *hd, kdev_t dev,
                    break;
                  }
 
-                 partsect = xrs->part[1].st + extensect;
+                 partsect = ntohl(xrs->part[1].st) + extensect;
                  brelse (xbh);
                  minor++;
                  if (minor >= m_lim) {
@@ -1169,7 +1191,7 @@ static int atari_partition (struct gendisk *hd, kdev_t dev,
          else
            {
              /* we don't care about other id's */
-             add_partition (hd, minor, pi->st, pi->siz);
+             add_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz));
            }
        }
     }
@@ -1196,7 +1218,7 @@ static int atari_partition (struct gendisk *hd, kdev_t dev,
              memcmp (pi->id, "RAW", 3) == 0) )
         {
           part_fmt = 2;
-         add_partition (hd, minor, pi->st, pi->siz);
+         add_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz));
         }
       }
       printk(" >");
@@ -1211,14 +1233,62 @@ static int atari_partition (struct gendisk *hd, kdev_t dev,
 }
 #endif /* CONFIG_ATARI_PARTITION */
 
+#ifdef CONFIG_ULTRIX_PARTITION
+
+static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
+{
+       int i, minor = current_minor;
+       struct buffer_head *bh;
+       struct ultrix_disklabel {
+               s32     pt_magic;       /* magic no. indicating part. info exits */
+               s32     pt_valid;       /* set by driver if pt is current */
+               struct  pt_info {
+                       s32             pi_nblocks; /* no. of sectors */
+                       u32             pi_blkoff;  /* block offset for start */
+               } pt_part[8];
+       } *label;
+
+#define PT_MAGIC       0x032957        /* Partition magic number */
+#define PT_VALID       1               /* Indicates if struct is valid */
+
+#define        SBLOCK  ((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \
+                  /get_ptable_blocksize(dev)))
+
+       bh = bread (dev, SBLOCK, get_ptable_blocksize(dev));
+       if (!bh) {
+               printk (" unable to read block 0x%lx\n", SBLOCK);
+               return -1;
+       }
+       
+       label = (struct ultrix_disklabel *)(bh->b_data
+                                            + get_ptable_blocksize(dev)
+                                            - sizeof(struct ultrix_disklabel));
+
+       if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
+               for (i=0; i<8; i++, minor++)
+                       if (label->pt_part[i].pi_nblocks)
+                               add_partition(hd, minor, 
+                                             label->pt_part[i].pi_blkoff,
+                                             label->pt_part[i].pi_nblocks);
+               brelse(bh);
+               printk ("\n");
+               return 1;
+       } else {
+               brelse(bh);
+               return 0;
+       }
+}
+
+#endif /* CONFIG_ULTRIX_PARTITION */
+
 static void check_partition(struct gendisk *hd, kdev_t dev)
 {
        static int first_time = 1;
        unsigned long first_sector;
-       char buf[32];
+       char buf[40];
 
        if (first_time)
-               printk("Partition check:\n");
+               printk(KERN_INFO "Partition check:\n");
        first_time = 0;
        first_sector = hd->part[MINOR(dev)].start_sect;
 
@@ -1231,7 +1301,7 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
                return;
        }
 
-       printk(" %s:", disk_name(hd, MINOR(dev), buf));
+       printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
 #ifdef CONFIG_MSDOS_PARTITION
        if (msdos_partition(hd, dev, first_sector))
                return;
@@ -1259,6 +1329,10 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
 #ifdef CONFIG_SGI_PARTITION
        if(sgi_partition(hd, dev, first_sector))
                return;
+#endif
+#ifdef CONFIG_ULTRIX_PARTITION
+       if(ultrix_partition(hd, dev, first_sector))
+               return;
 #endif
        printk(" unknown partition table\n");
 }
@@ -1309,9 +1383,10 @@ static inline void setup_dev(struct gendisk *dev)
                resetup_one_dev(dev, drive);
 }
 
-__initfunc(void device_setup(void))
+void __init device_setup(void)
 {
        extern void console_map_init(void);
+       extern void cpqarray_init(void);
 #ifdef CONFIG_PARPORT
        extern int parport_init(void) __init;
 #endif
@@ -1325,6 +1400,13 @@ __initfunc(void device_setup(void))
 
 #ifdef CONFIG_PARPORT
        parport_init();
+#endif
+       /*
+        *      I2O must come before block and char as the I2O layer may
+        *      in future claim devices that block/char most not touch.
+        */
+#ifdef CONFIG_I2O
+       i2o_init();
 #endif
        chr_dev_init();
        blk_dev_init();
@@ -1336,6 +1418,9 @@ __initfunc(void device_setup(void))
 #ifdef CONFIG_SCSI
        scsi_dev_init();
 #endif
+#ifdef CONFIG_BLK_CPQ_DA
+       cpqarray_init();
+#endif
 #ifdef CONFIG_INET
        net_dev_init();
 #endif
@@ -1362,7 +1447,7 @@ __initfunc(void device_setup(void))
 int get_partition_list(char * page)
 {
        struct gendisk *p;
-       char buf[32];
+       char buf[40];
        int n, len;
 
        len = sprintf(page, "major minor  #blocks  name\n\n");
index 01494ca1e019ad7869ffdc2a58a2195f9d72a59c..79df61b1fbd2a1fb3835297d912070b4848fee1c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/hpt343.c                Version 0.23    May 12, 1999
+ * linux/drivers/block/hpt34x.c                Version 0.24    July 3, 1999
  *
  * Copyright (C) 1998-99       Andre Hedrick
  *                                     (hedrick@astro.dyer.vanderbilt.edu)
@@ -383,6 +383,7 @@ __initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name))
                        pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
                        printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address);
                }
+               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
        } else {
                pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
        }
diff --git a/drivers/block/ida_cmd.h b/drivers/block/ida_cmd.h
new file mode 100644 (file)
index 0000000..056863b
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef ARRAYCMD_H
+#define ARRAYCMD_H
+
+#include <asm/types.h>
+#if 0
+#include <linux/blkdev.h>
+#endif
+
+/* for the Smart Array 42XX cards */
+#define S42XX_REQUEST_PORT_OFFSET      0x40
+#define S42XX_REPLY_INTR_MASK_OFFSET   0x34
+#define S42XX_REPLY_PORT_OFFSET                0x44
+#define S42XX_INTR_STATUS              0x30
+
+#define S42XX_INTR_OFF         0x08
+#define S42XX_INTR_PENDING     0x08
+
+#define COMMAND_FIFO           0x04
+#define COMMAND_COMPLETE_FIFO  0x08
+#define INTR_MASK              0x0C
+#define INTR_STATUS            0x10
+#define INTR_PENDING           0x14
+
+#define FIFO_NOT_EMPTY         0x01
+#define FIFO_NOT_FULL          0x02
+
+#define BIG_PROBLEM            0x40
+#define LOG_NOT_CONF           2
+
+#pragma pack(1)
+typedef struct {
+       __u32   size;
+       __u32   addr;
+} sg_t;
+
+#define RCODE_NONFATAL 0x02
+#define RCODE_FATAL    0x04
+#define RCODE_INVREQ   0x10
+typedef struct {
+       __u16   next;
+       __u8    cmd;
+       __u8    rcode;
+       __u32   blk;
+       __u16   blk_cnt;
+       __u8    sg_cnt;
+       __u8    reserved;
+} rhdr_t;
+
+#define SG_MAX                 32
+typedef struct {
+       rhdr_t  hdr;
+       sg_t    sg[SG_MAX];
+       __u32   bp;
+} rblk_t;
+
+typedef struct {
+       __u8    unit;
+       __u8    prio;
+       __u16   size;
+} chdr_t;
+
+#define CMD_RWREQ      0x00
+#define CMD_IOCTL_PEND 0x01
+#define CMD_IOCTL_DONE 0x02
+
+typedef struct cmdlist {
+       chdr_t  hdr;
+       rblk_t  req;
+       __u32   size;
+       int     retry_cnt;
+       __u32   busaddr;
+       int     ctlr;
+       struct cmdlist *prev;
+       struct cmdlist *next;
+       struct buffer_head *bh;
+       int type;
+} cmdlist_t;
+       
+#define ID_CTLR                0x11
+typedef struct {
+       __u8    nr_drvs;
+       __u32   cfg_sig;
+       __u8    firm_rev[4];
+       __u8    rom_rev[4];
+       __u8    hw_rev;
+       __u32   bb_rev;
+       __u32   drv_present_map;
+       __u32   ext_drv_map;
+       __u32   board_id;
+       __u8    cfg_error;
+       __u32   non_disk_bits;
+       __u8    bad_ram_addr;
+       __u8    cpu_rev;
+       __u8    pdpi_rev;
+       __u8    epic_rev;
+       __u8    wcxc_rev;
+       __u8    marketing_rev;
+       __u8    ctlr_flags;
+       __u8    host_flags;
+       __u8    expand_dis;
+       __u8    scsi_chips;
+       __u32   max_req_blocks;
+       __u32   ctlr_clock;
+       __u8    drvs_per_bus;
+       __u16   big_drv_present_map[8];
+       __u16   big_ext_drv_map[8];
+       __u16   big_non_disk_map[8];
+       __u16   task_flags;
+       __u8    icl_bus;
+       __u8    red_modes;
+       __u8    cur_red_mode;
+       __u8    red_ctlr_stat;
+       __u8    red_fail_reason;
+       __u8    reserved[403];
+} id_ctlr_t;
+
+typedef struct {
+       __u16   cyl;
+       __u8    heads;
+       __u8    xsig;
+       __u8    psectors;
+       __u16   wpre;
+       __u8    maxecc;
+       __u8    drv_ctrl;
+       __u16   pcyls;
+       __u8    pheads;
+       __u16   landz;
+       __u8    sect_per_track;
+       __u8    cksum;
+} drv_param_t;
+
+#define ID_LOG_DRV     0x10
+typedef struct {
+       __u16   blk_size;
+       __u32   nr_blks;
+       drv_param_t drv;
+       __u8    fault_tol;
+       __u8    reserved;
+       __u8    bios_disable;
+} id_log_drv_t;
+
+#define ID_LOG_DRV_EXT 0x18
+typedef struct {
+       __u32   log_drv_id;
+       __u8    log_drv_label[64];
+       __u8    reserved[418];
+} id_log_drv_ext_t;
+
+#define SENSE_LOG_DRV_STAT     0x12
+typedef struct {
+       __u8    status;
+       __u32   fail_map;
+       __u16   read_err[32];
+       __u16   write_err[32];
+       __u8    drv_err_data[256];
+       __u8    drq_timeout[32];
+       __u32   blks_to_recover;
+       __u8    drv_recovering;
+       __u16   remap_cnt[32];
+       __u32   replace_drv_map;
+       __u32   act_spare_map;
+       __u8    spare_stat;
+       __u8    spare_repl_map[32];
+       __u32   repl_ok_map;
+       __u8    media_exch;
+       __u8    cache_fail;
+       __u8    expn_fail;
+       __u8    unit_flags;
+       __u16   big_fail_map[8];
+       __u16   big_remap_map[8];
+       __u16   big_repl_map[8];
+       __u16   big_act_spare_map[8];
+       __u8    big_spar_repl_map[128];
+       __u16   big_repl_ok_map[8];
+       __u8    big_drv_rebuild;
+       __u8    reserved[36];
+} sense_log_drv_stat_t;
+
+#define START_RECOVER          0x13
+
+#define ID_PHYS_DRV            0x15
+typedef struct {
+       __u8    scsi_bus;
+       __u8    scsi_id;
+       __u16   blk_size;
+       __u32   nr_blks;
+       __u32   rsvd_blks;
+       __u8    drv_model[40];
+       __u8    drv_sn[40];
+       __u8    drv_fw[8];
+       __u8    scsi_iq_bits;
+       __u8    compaq_drv_stmp;
+       __u8    last_fail;
+       __u8    phys_drv_flags;
+       __u8    phys_drv_flags1;
+       __u8    scsi_lun;
+       __u8    phys_drv_flags2;
+       __u8    reserved;
+       __u32   spi_speed_rules;
+       __u8    phys_connector[2];
+       __u8    phys_box_on_bus;
+       __u8    phys_bay_in_box;
+} id_phys_drv_t;
+
+#define BLINK_DRV_LEDS         0x16
+typedef struct {
+       __u32   blink_duration;
+       __u32   reserved;
+       __u8    blink[256];
+       __u8    reserved1[248];
+} blink_drv_leds_t;
+
+#define SENSE_BLINK_LEDS       0x17
+typedef struct {
+       __u32   blink_duration;
+       __u32   btime_elap;
+       __u8    blink[256];
+       __u8    reserved1[248];
+} sense_blink_leds_t;
+
+#define IDA_READ               0x20
+#define IDA_WRITE              0x30
+#define IDA_WRITE_MEDIA                0x31
+#define RESET_TO_DIAG          0x40
+#define DIAG_PASS_THRU         0x41
+
+#define SENSE_CONFIG           0x50
+#define SET_CONFIG             0x51
+typedef struct {
+       __u32   cfg_sig;
+       __u16   compat_port;
+       __u8    data_dist_mode;
+       __u8    surf_an_ctrl;
+       __u16   ctlr_phys_drv;
+       __u16   log_unit_phys_drv;
+       __u16   fault_tol_mode;
+       __u8    phys_drv_param[16];
+       drv_param_t drv;
+       __u32   drv_asgn_map;
+       __u16   dist_factor;
+       __u32   spare_asgn_map;
+       __u8    reserved[6];
+       __u16   os;
+       __u8    ctlr_order;
+       __u8    extra_info;
+       __u32   data_offs;
+       __u8    parity_backedout_write_drvs;
+       __u8    parity_dist_mode;
+       __u8    parity_shift_fact;
+       __u8    bios_disable_flag;
+       __u32   blks_on_vol;
+       __u32   blks_per_drv;
+       __u8    scratch[16];
+       __u16   big_drv_map[8];
+       __u16   big_spare_map[8];
+       __u8    ss_source_vol;
+       __u8    mix_drv_cap_range;
+       struct {
+               __u16   big_drv_map[8];
+               __u32   blks_per_drv;
+               __u16   fault_tol_mode;
+               __u16   dist_factor;
+       } MDC_range[4];
+       __u8    reserved1[248];
+} config_t;
+
+#define BYPASS_VOL_STATE       0x52
+#define SS_CREATE_VOL          0x53
+#define CHANGE_CONFIG          0x54
+#define SENSE_ORIG_CONF                0x55
+#define REORDER_LOG_DRV                0x56
+typedef struct {
+       __u8    old_units[32];
+} reorder_log_drv_t;
+
+#define LABEL_LOG_DRV          0x57
+typedef struct {
+       __u8    log_drv_label[64];
+} label_log_drv_t;
+
+#define SS_TO_VOL              0x58
+       
+#define SET_SURF_DELAY         0x60
+typedef struct {
+       __u16   delay;
+       __u8    reserved[510];
+} surf_delay_t;
+
+#define SET_OVERHEAT_DELAY     0x61
+typedef struct {
+       __u16   delay;
+} overhead_delay_t;
+#define SET_MP_DELAY
+typedef struct {
+       __u16   delay;
+       __u8    reserved[510];
+} mp_delay_t;
+
+#define PASSTHRU_A     0x91
+typedef struct {
+       __u8    target;
+       __u8    bus;
+       __u8    lun;
+       __u32   timeout;
+       __u32   flags;
+       __u8    status;
+       __u8    error;
+       __u8    cdb_len;
+       __u8    sense_error;
+       __u8    sense_key;
+       __u32   sense_info;
+       __u8    sense_code;
+       __u8    sense_qual;
+       __u8    residual;
+       __u8    reserved[4];
+       __u8    cdb[12];        
+} scsi_param_t;
+
+#define RESUME_BACKGROUND_ACTIVITY     0x99
+#pragma pack() 
+
+#endif /* ARRAYCMD_H */
diff --git a/drivers/block/ida_ioctl.h b/drivers/block/ida_ioctl.h
new file mode 100644 (file)
index 0000000..9c159df
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef IDA_IOCTL_H
+#define IDA_IOCTL_H
+
+#include "ida_cmd.h"
+#include "cpqarray.h"
+
+#define IDAGETDRVINFO          0x27272828
+#define IDAPASSTHRU            0x28282929
+#define IDAGETCTLRSIG          0x29293030
+#define IDAREVALIDATEVOLS      0x30303131
+#define IDADRIVERVERSION       0x31313232
+
+/*
+ * Normally, the ioctl determines the logical unit for this command by
+ * the major,minor number of the fd passed to ioctl.  If you need to send
+ * a command to a different/nonexistant unit (such as during config), you
+ * can override the normal behavior by setting the unit valid bit. (Normally,
+ * it should be zero) The controller the command is sent to is still
+ * determined by the major number of the open device.
+ */
+
+#define UNITVALID      0x80
+typedef struct {
+       __u8    cmd;
+       __u8    rcode;
+       __u8    unit;
+       __u32   blk;
+       __u16   blk_cnt;
+
+/* currently, sg_cnt is assumed to be 1: only the 0th element of sg is used */
+       struct {
+               void    *addr;
+               size_t  size;
+       } sg[SG_MAX];
+       int     sg_cnt;
+
+       union ctlr_cmds {
+               drv_info_t              drv;
+               unsigned char           buf[512];
+
+               id_ctlr_t               id_ctlr;
+               drv_param_t             drv_param;
+               id_log_drv_t            id_log_drv;
+               id_log_drv_ext_t        id_log_drv_ext;
+               sense_log_drv_stat_t    sense_log_drv_stat;
+               id_phys_drv_t           id_phys_drv;
+               blink_drv_leds_t        blink_drv_leds;
+               sense_blink_leds_t      sense_blink_leds;
+               config_t                config;
+               reorder_log_drv_t       reorder_log_drv;
+               label_log_drv_t         label_log_drv;
+               surf_delay_t            surf_delay;
+               overhead_delay_t        overhead_delay;
+               mp_delay_t              mp_delay;
+               scsi_param_t            scsi_param;
+       } c;
+} ida_ioctl_t;
+
+#endif /* IDA_IOCTL_H */
index fee5297f1e0caf78632d49215fdeb78b6fca30af..2ea7d5b51d003e2d32773a83d9a769c173917e01 100644 (file)
@@ -776,8 +776,9 @@ static void idedisk_setup (ide_drive_t *drive)
                        drive->bios_cyl, drive->bios_head, drive->bios_sect);
 
        if (drive->using_dma) {
-               if  ((id->field_valid & 4) && (id->word93 & 0x2000) &&
-                    (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
+               if ((id->field_valid & 4) && (id->word93 & 0x2000) &&
+                   (HWIF(drive)->udma_four) &&
+                   (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
                        printk(", UDMA(66)");   /* UDMA BIOS-enabled! */
                } else if ((id->field_valid & 4) &&
                           (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
index df3100d377a5d72b1f30d938cc99f352f767797f..019aec4fb3ca8136fe73b986228805fec637b945 100644 (file)
@@ -242,8 +242,11 @@ __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const
                                        dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
 
                                pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
-                               if (!(pcicmd & PCI_COMMAND_MEMORY))
+                               if (!(pcicmd & PCI_COMMAND_MEMORY)) {
                                        pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+                               } else {
+                                       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+                               }
                        }
                case PCI_DEVICE_ID_PROMISE_20246:
                case PCI_DEVICE_ID_PROMISE_20262:
@@ -483,8 +486,11 @@ check_if_enabled:
                }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-               if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513))
+               if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X))
                        autodma = 0;
+               if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262))
+                       hwif->udma_four = 1;
                if (autodma)
                        hwif->autodma = 1;
                if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
index 3b5d24744ad0b9426c6358d9336340da19aded68..76dc905dd3ce4dcc71b7d8c2c3bb39cddbcd878a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-probe.c    Version 1.04  March 10, 1999
+ *  linux/drivers/block/ide-probe.c    Version 1.05  July 3, 1999
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
  *                      by Andrea Arcangeli
  * Version 1.03                fix for (hwif->chipset == ide_4drives)
  * Version 1.04                fixed buggy treatments of known flash memory cards
- *                     fix for (hwif->chipset == ide_pdc4030)
+ *
+ * Version 1.05                fix for (hwif->chipset == ide_pdc4030)
  *                     added ide6/7
+ *                     allowed for secondary flash card to be detectable
+ *                      with new flag : drive->ata_flash : 1;
  */
 
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
@@ -141,8 +144,10 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
         */
        if (drive_is_flashcard(drive)) {
                ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
-               mate->present = 0;
-               mate->noprobe = 1;
+               if (!mate->ata_flash) {
+                       mate->present = 0;
+                       mate->noprobe = 1;
+               }
        }
        drive->media = ide_disk;
        printk("ATA DISK drive\n");
index 6d324bea84895e4a532fe677ea504378d7aef930..9a09e7ec37bcc975e663461484ffd115d4e0a8bd 100644 (file)
@@ -297,7 +297,8 @@ int drive_is_flashcard (ide_drive_t *drive)
                if (!strncmp(id->model, "KODAK ATA_FLASH", 15)  /* Kodak */
                 || !strncmp(id->model, "Hitachi CV", 10)       /* Hitachi */
                 || !strncmp(id->model, "SunDisk SDCFB", 13)    /* SunDisk */
-                || !strncmp(id->model, "HAGIWARA HPC", 12))    /* Hagiwara */
+                || !strncmp(id->model, "HAGIWARA HPC", 12)     /* Hagiwara */
+                || !strncmp(id->model, "ATA_FLASH", 9))        /* Simple Tech */
                {
                        return 1;       /* yes, it is a flash memory card */
                }
@@ -1353,7 +1354,7 @@ void ide_timer_expiry (unsigned long data)
                        (void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
                        printk("%s: timeout waiting for DMA\n", drive->name);
        /*
-        *  need something here for HX PIIX3 UDMA and HPT343.......AMH
+        *  need something here for HPT34X.......AMH
         *  irq timeout: status=0x58 { DriveReady SeekComplete DataRequest }
         */
                }
@@ -1898,6 +1899,7 @@ void ide_unregister (unsigned int index)
        hwif->irq = old_hwif.irq;
        hwif->major = old_hwif.major;
        hwif->proc = old_hwif.proc;
+       hwif->udma_four = old_hwif.udma_four;
        hwif->chipset = old_hwif.chipset;
        hwif->pci_dev = old_hwif.pci_dev;
        hwif->pci_devid = old_hwif.pci_devid;
@@ -2338,10 +2340,15 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        }
                        if ((((byte *)arg)[0] == WIN_SETFEATURES) &&
                            (((byte *)arg)[1] > 66) &&
-                           (((byte *)arg)[2] == 3) &&
-                           ((drive->id->word93 & 0x2000) == 0)) {
-                               printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
-                               goto abort;
+                           (((byte *)arg)[2] == 3)) {
+                               if (!HWIF(drive)->udma_four) {
+                                       printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name);
+                                       goto abort;
+                               }
+                               if ((drive->id->word93 & 0x2000) == 0) {
+                                       printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
+                                       goto abort;
+                               }
                        }
                        err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
                        if (!err &&
@@ -2602,6 +2609,9 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i
  *
  * "hdx=swapdata"      : when the drive is a disk, byte swap all data
  * "hdx=bswap"         : same as above..........
+ * "hdx=flash"         : allows for more than one ata_flash disk to be
+ *                             registered. In most cases, only one device
+ *                             will be present.
  *
  * "idebus=xx"         : inform IDE driver of VESA/PCI bus speed in MHz,
  *                             where "xx" is between 20 and 66 inclusive,
@@ -2688,7 +2698,7 @@ __initfunc(void ide_setup (char *s))
        if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
                const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
                                "serialize", "autotune", "noautotune",
-                               "slow", "swapdata", "bswap", NULL};
+                               "slow", "swapdata", "bswap", "flash", NULL};
                unit = s[2] - 'a';
                hw   = unit / MAX_DRIVES;
                unit = unit % MAX_DRIVES;
@@ -2729,6 +2739,9 @@ __initfunc(void ide_setup (char *s))
                        case -10:
                                drive->bswap = 1;
                                goto done;
+                       case -11:
+                               drive->ata_flash = 1;
+                               goto done;
                        case 3: /* cyl,head,sect */
                                drive->media    = ide_disk;
                                drive->cyl      = drive->bios_cyl  = vals[0];
index ccf814002a5863be7b867293d451e87b0937d0ec..cdfd315b7172fb180b71f0da4feb4c4a33fdaf74 100644 (file)
@@ -347,6 +347,9 @@ void add_request(struct blk_dev_struct * dev, struct request * req)
 /* for SCSI devices, call request_fn unconditionally */
        if (scsi_blk_major(MAJOR(req->rq_dev)))
                queue_new_request = 1;
+       if (MAJOR(req->rq_dev) >= COMPAQ_SMART2_MAJOR+0 &&
+           MAJOR(req->rq_dev) <= COMPAQ_SMART2_MAJOR+7)
+               queue_new_request = 1;
 out:
        if (queue_new_request)
                (dev->request_fn)();
@@ -506,6 +509,14 @@ void make_request(int major,int rw, struct buffer_head * bh)
             case SCSI_DISK7_MAJOR:
             case SCSI_CDROM_MAJOR:
             case I2O_MAJOR:
+            case COMPAQ_SMART2_MAJOR+0:
+            case COMPAQ_SMART2_MAJOR+1:
+            case COMPAQ_SMART2_MAJOR+2:
+            case COMPAQ_SMART2_MAJOR+3:
+            case COMPAQ_SMART2_MAJOR+4:
+            case COMPAQ_SMART2_MAJOR+5:
+            case COMPAQ_SMART2_MAJOR+6:
+            case COMPAQ_SMART2_MAJOR+7:
 
                do {
                        if (req->sem)
@@ -717,7 +728,7 @@ end_that_request_last( struct request *req )
        wake_up(&wait_for_request);
 }
 
-__initfunc(int blk_dev_init(void))
+int __init blk_dev_init(void)
 {
        struct request * req;
        struct blk_dev_struct *dev;
index 29d78129f32ebb939dd2c193bf64c36dad109d8a..b7987f33d0982ffb8ef3b2ed580758f0ea782ec7 100644 (file)
  * - Should use an own CAP_* category instead of CAP_SYS_ADMIN 
  * - Should use the underlying filesystems/devices read function if possible
  *   to support read ahead (and for write)
- */
+ *
+ * WARNING/FIXME:
+ * - The block number as IV passing to low level transfer functions is broken:
+ *   it passes the underlying device's block number instead of the
+ *   offset. This makes it change for a given block when the file is 
+ *   moved/restored/copied and also doesn't work over NFS. 
+ */ 
 
 #include <linux/module.h>
 
@@ -107,7 +113,7 @@ static int none_status(struct loop_device *lo, struct loop_info *info)
 
 static int xor_status(struct loop_device *lo, struct loop_info *info)
 {
-       if (info->lo_encrypt_key_size < 0)
+       if (info->lo_encrypt_key_size <= 0)
                return -EINVAL;
        return 0;
 }
@@ -369,6 +375,10 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
                   a file structure */
                lo->lo_backing_file = NULL;
        } else if (S_ISREG(inode->i_mode)) {
+               if (!inode->i_op->bmap) { 
+                       printk(KERN_ERR "loop: device has no block access/not implemented\n");
+                       goto out_putf;
+               }
 
                /* Backed by a regular file - we need to hold onto
                   a file structure for this file.  We'll use it to
@@ -505,8 +515,6 @@ static int loop_set_status(struct loop_device *lo, struct loop_info *arg)
        if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
                return -EINVAL;
        type = info.lo_encrypt_type; 
-       if (info.lo_encrypt_key_size == 0 && type == LO_CRYPT_XOR)
-               return -EINVAL;
        if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL)
                return -EINVAL;
        err = loop_release_xfer(lo);
index da74a771b196769d2547d651c59ce9b58469730a..ab18b55b00a09e91c8005766c3ba0259e9d201e4 100644 (file)
@@ -401,7 +401,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
                return 0;
        case NBD_SET_SIZE_BLOCKS:
                nbd_sizes[dev] = arg;
-               nbd_bytesizes[dev] = arg << nbd_blksize_bits[dev];
+               nbd_bytesizes[dev] = ((u64) arg) << nbd_blksize_bits[dev];
                return 0;
        case NBD_DO_IT:
                if (!lo->file)
diff --git a/drivers/block/smart1,2.h b/drivers/block/smart1,2.h
new file mode 100644 (file)
index 0000000..221e4a5
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+
+/*
+ * This file contains the controller communication implementation for
+ * Compaq SMART-1 and SMART-2 controllers.  To the best of my knowledge,
+ * this should support:
+ *
+ *  PCI:
+ *  SMART-2/P, SMART-2DH, SMART-2SL, SMART-221, SMART-3100ES, SMART-3200
+ *  Integerated SMART Array Controller, SMART-4200, SMART-4250ES
+ *
+ *  EISA:
+ *  SMART-2/E, SMART, IAES, IDA-2, IDA
+ */
+
+/*
+ * Memory mapped FIFO interface (SMART 42xx cards)
+ */
+static void smart4_submit_command(ctlr_info_t *h, cmdlist_t *c)
+{
+        writel(c->busaddr, h->vaddr + S42XX_REQUEST_PORT_OFFSET);
+}
+
+/*  
+ *  This card is the oposite of the other cards.  
+ *   0 turns interrupts on... 
+ *   0x08 turns them off... 
+ */
+static void smart4_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+       if (val) 
+       { /* Turn interrupts on */
+               writel(0, h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET);
+       } else /* Turn them off */
+       {
+               writel( S42XX_INTR_OFF, 
+                       h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET);
+       }
+}
+
+/*
+ *  For this card fifo is full if reading this port returns 0! 
+ * 
+ */ 
+static unsigned long smart4_fifo_full(ctlr_info_t *h)
+{
+       
+        return (~readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET));
+}
+
+/* This type of controller returns -1 if the fifo is empty, 
+ *    Not 0 like the others.
+ *    And we need to let it know we read a value out 
+ */ 
+static unsigned long smart4_completed(ctlr_info_t *h)
+{
+       long register_value 
+               = readl(h->vaddr + S42XX_REPLY_PORT_OFFSET);
+
+       /* Fifo is empty */
+       if( register_value == -1)
+               return 0;       
+
+       /* Need to let it know we got the reply */
+       /* We do this by writing a 0 to the port we just read from */
+       writel(0, h->vaddr + S42XX_REPLY_PORT_OFFSET);
+
+       return ((unsigned long) register_value); 
+}
+
+ /*
+ *  This hardware returns interrupt pending at a different place and 
+ *  it does not tell us if the fifo is empty, we will have check  
+ *  that by getting a 0 back from the comamnd_completed call. 
+ */
+static unsigned long smart4_intr_pending(ctlr_info_t *h)
+{
+       unsigned long register_value  = 
+               readl(h->vaddr + S42XX_INTR_STATUS);
+
+       if( register_value &  S42XX_INTR_PENDING) 
+               return  FIFO_NOT_EMPTY; 
+       return 0 ;
+}
+
+static struct access_method smart4_access = {
+       smart4_submit_command,
+       smart4_intr_mask,
+       smart4_fifo_full,
+       smart4_intr_pending,
+       smart4_completed,
+};
+
+/*
+ * Memory mapped FIFO interface (PCI SMART2 and SMART 3xxx cards)
+ */
+static void smart2_submit_command(ctlr_info_t *h, cmdlist_t *c)
+{
+       writel(c->busaddr, h->vaddr + COMMAND_FIFO);
+}
+
+static void smart2_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+       writel(val, h->vaddr + INTR_MASK);
+}
+
+static unsigned long smart2_fifo_full(ctlr_info_t *h)
+{
+       return readl(h->vaddr + COMMAND_FIFO);
+}
+
+static unsigned long smart2_completed(ctlr_info_t *h)
+{
+       return readl(h->vaddr + COMMAND_COMPLETE_FIFO);
+}
+
+static unsigned long smart2_intr_pending(ctlr_info_t *h)
+{
+       return readl(h->vaddr + INTR_PENDING);
+}
+
+static struct access_method smart2_access = {
+       smart2_submit_command,
+       smart2_intr_mask,
+       smart2_fifo_full,
+       smart2_intr_pending,
+       smart2_completed,
+};
+
+/*
+ *  IO access for SMART-2/E cards
+ */
+static void smart2e_submit_command(ctlr_info_t *h, cmdlist_t *c)
+{
+       outl(c->busaddr, h->ioaddr + COMMAND_FIFO);
+}
+
+static void smart2e_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+       outl(val, h->ioaddr + INTR_MASK);
+}
+
+static unsigned long smart2e_fifo_full(ctlr_info_t *h)
+{
+       return inl(h->ioaddr + COMMAND_FIFO);
+}
+
+static unsigned long smart2e_completed(ctlr_info_t *h)
+{
+       return inl(h->ioaddr + COMMAND_COMPLETE_FIFO);
+}
+
+static unsigned long smart2e_intr_pending(ctlr_info_t *h)
+{
+       return inl(h->ioaddr + INTR_PENDING);
+}
+
+static struct access_method smart2e_access = {
+       smart2e_submit_command,
+       smart2e_intr_mask,
+       smart2e_fifo_full,
+       smart2e_intr_pending,
+       smart2e_completed,
+};
+
+/*
+ *  IO access for older SMART-1 type cards
+ */
+#define SMART1_SYSTEM_MASK             0xC8E
+#define SMART1_SYSTEM_DOORBELL         0xC8F
+#define SMART1_LOCAL_MASK              0xC8C
+#define SMART1_LOCAL_DOORBELL          0xC8D
+#define SMART1_INTR_MASK               0xC89
+#define SMART1_LISTADDR                        0xC90
+#define SMART1_LISTLEN                 0xC94
+#define SMART1_TAG                     0xC97
+#define SMART1_COMPLETE_ADDR           0xC98
+#define SMART1_LISTSTATUS              0xC9E
+
+#define CHANNEL_BUSY                   0x01
+#define CHANNEL_CLEAR                  0x02
+
+static void smart1_submit_command(ctlr_info_t *h, cmdlist_t *c)
+{
+       /*
+        * This __u16 is actually a bunch of control flags on SMART
+        * and below.  We want them all to be zero.
+        */
+       c->hdr.size = 0;
+
+       outb(CHANNEL_CLEAR, h->ioaddr + SMART1_SYSTEM_DOORBELL);
+
+       outl(c->busaddr, h->ioaddr + SMART1_LISTADDR);
+       outw(c->size, h->ioaddr + SMART1_LISTLEN);
+
+       outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL);
+}
+
+static void smart1_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+       if (val == 1) {
+               outb(0xFD, h->ioaddr + SMART1_SYSTEM_DOORBELL);
+               outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL);
+               outb(0x01, h->ioaddr + SMART1_INTR_MASK);
+               outb(0x01, h->ioaddr + SMART1_SYSTEM_MASK);
+       } else {
+               outb(0, h->ioaddr + 0xC8E);
+       }
+}
+
+static unsigned long smart1_fifo_full(ctlr_info_t *h)
+{
+       unsigned char chan;
+       chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR;
+       return chan;
+}
+
+static unsigned long smart1_completed(ctlr_info_t *h)
+{
+       unsigned char status;
+       unsigned long cmd;
+
+       if (inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) {
+               outb(CHANNEL_BUSY, h->ioaddr + SMART1_SYSTEM_DOORBELL);
+
+               cmd = inl(h->ioaddr + SMART1_COMPLETE_ADDR);
+               status = inb(h->ioaddr + SMART1_LISTSTATUS);
+
+               outb(CHANNEL_CLEAR, h->ioaddr + SMART1_LOCAL_DOORBELL);
+
+               if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status;
+       } else {
+               cmd = 0;
+       }
+       return cmd;
+}
+
+static unsigned long smart1_intr_pending(ctlr_info_t *h)
+{
+       unsigned char chan;
+       chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY;
+       return chan;
+}
+
+static struct access_method smart1_access = {
+       smart1_submit_command,
+       smart1_intr_mask,
+       smart1_fifo_full,
+       smart1_intr_pending,
+       smart1_completed,
+};
index 8bc1b4feb484069801eccd649aa41f0ac1f5a198..4885f3caf1ab280eddb9695d53566e79c3783c5d 100644 (file)
@@ -54,6 +54,7 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
   if [ "$CONFIG_PRINTER" != "n" ]; then
     bool '  Support for console on line printer' CONFIG_LP_CONSOLE
   fi
+  dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
 
 bool 'Mouse Support (not serial mice)' CONFIG_MOUSE
index 4cc45ecc3f9a54b04bb4622dbd120822aa0224dd..686b7c4fc618f247451f261ab7d4ad2d0e737326 100644 (file)
@@ -468,6 +468,14 @@ ifdef CONFIG_H8
 LX_OBJS += h8.o
 endif
 
+ifeq ($(CONFIG_PPDEV),y)
+L_OBJS += ppdev.o
+else
+  ifeq ($(CONFIG_PPDEV),m)
+  M_OBJS += ppdev.o
+  endif
+endif
+
 ifeq ($(L_I2C),y)
 LX_OBJS += i2c.o
 else
index 77bbbbd69a99ad60f510fe12d2620ee2007e7803..a7ed0881587b0cdaabd387d5abbc0c6343d3d28d 100644 (file)
@@ -38,9 +38,7 @@
 #ifdef __powerpc__
 #include <asm/processor.h>
 #endif
-#ifdef __mc68000__
 #include <asm/setup.h>
-#endif
 
 static struct mouse_status mouse;
 static unsigned char adb_mouse_buttons[16];
@@ -282,7 +280,6 @@ __initfunc(void adb_mouse_setup(char *str, int *ints))
 }
 
 #ifdef MODULE
-#include <asm/setup.h>
 
 int init_module(void)
 {
index e62ea57535a2365554061e6fd5a36f5f4b8b2592..274230c64989454ffac7da46738ebc724f99372b 100644 (file)
@@ -333,7 +333,6 @@ __initfunc(int amiga_mouse_init(void))
 }
 
 #ifdef MODULE
-#include <asm/setup.h>
 
 int init_module(void)
 {
index 614349275febfe7e6f9b7bfba18b1a3c769aff15..c24d96b2718749421195b030d2e3400c1be670ad 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 
 #if LINUX_VERSION_CODE >= 0x020100
 #include <asm/uaccess.h>
@@ -81,8 +80,8 @@ copy_from_user(void *to, const void *from, unsigned long n)
 #include "bttv.h"
 #include "tuner.h"
 
-#define DEBUG(x)               /* Debug driver */      
-#define IDEBUG(x)              /* Debug interrupt handler */
+#define DEBUG(x)               /* Debug driver */      
+#define IDEBUG(x)              /* Debug interrupt handler */
 
 #if LINUX_VERSION_CODE >= 0x020117
 MODULE_PARM(vidmem,"i");
@@ -110,7 +109,7 @@ static int triton1=0;
 #define CARD_DEFAULT 0
 #endif
 
-static unsigned int remap[BTTV_MAX];    /* remap Bt848 */
+static unsigned long remap[BTTV_MAX];    /* remap Bt848 */
 static unsigned int radio[BTTV_MAX];
 static unsigned int card[BTTV_MAX] = { CARD_DEFAULT, CARD_DEFAULT, 
                                        CARD_DEFAULT, CARD_DEFAULT };
@@ -129,51 +128,80 @@ static struct bttv bttvs[BTTV_MAX];
 #define EEPROM_WRITE_DELAY    20000
 #define BURSTOFFSET 76
 
-
-
 /*******************************/
 /* Memory management functions */
 /*******************************/
 
-/* convert virtual user memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+#define MDEBUG(x)      do { } while(0)         /* Debug memory management */
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ *    out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed.  We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
 
-static inline unsigned long uvirt_to_phys(unsigned long adr)
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
 {
-       pgd_t *pgd;
+        unsigned long ret = 0UL;
        pmd_t *pmd;
        pte_t *ptep, pte;
   
-       pgd = pgd_offset(current->mm, adr);
-       if (pgd_none(*pgd))
-               return 0;
-       pmd = pmd_offset(pgd, adr);
-       if (pmd_none(*pmd))
-               return 0;
-       ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
-       pte = *ptep;
-       if(pte_present(pte))
-               return 
-                 virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
-       return 0;
+       if (!pgd_none(*pgd)) {
+                pmd = pmd_offset(pgd, adr);
+                if (!pmd_none(*pmd)) {
+                        ptep = pte_offset(pmd, adr);
+                        pte = *ptep;
+                        if(pte_present(pte))
+                                ret = (pte_page(pte)|(adr&(PAGE_SIZE-1)));
+                }
+        }
+        MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
+       return ret;
 }
 
 static inline unsigned long uvirt_to_bus(unsigned long adr) 
 {
-       return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
-}
+        unsigned long kva, ret;
 
-/* convert virtual kernel memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+        kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
+       ret = virt_to_bus((void *)kva);
+        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
+        return ret;
+}
 
-static inline unsigned long kvirt_to_phys(unsigned long adr) 
+static inline unsigned long kvirt_to_bus(unsigned long adr) 
 {
-       return uvirt_to_phys(VMALLOC_VMADDR(adr));
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+        kva = uvirt_to_kva(pgd_offset_k(va), va);
+       ret = virt_to_bus((void *)kva);
+        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
+        return ret;
 }
 
-static inline unsigned long kvirt_to_bus(unsigned long adr) 
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-       return uvirt_to_bus(VMALLOC_VMADDR(adr));
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+        kva = uvirt_to_kva(pgd_offset_k(va), va);
+       ret = __pa(kva);
+        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+        return ret;
 }
 
 static void * rvmalloc(unsigned long size)
@@ -188,8 +216,8 @@ static void * rvmalloc(unsigned long size)
                adr=(unsigned long) mem;
                while (size > 0) 
                 {
-                       page = kvirt_to_phys(adr);
-                       mem_map_reserve(MAP_NR(phys_to_virt(page)));
+                       page = kvirt_to_pa(adr);
+                       mem_map_reserve(MAP_NR(__va(page)));
                        adr+=PAGE_SIZE;
                        size-=PAGE_SIZE;
                }
@@ -206,8 +234,8 @@ static void rvfree(void * mem, unsigned long size)
                adr=(unsigned long) mem;
                while (size > 0) 
                 {
-                       page = kvirt_to_phys(adr);
-                       mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+                       page = kvirt_to_pa(adr);
+                       mem_map_unreserve(MAP_NR(__va(page)));
                        adr+=PAGE_SIZE;
                        size-=PAGE_SIZE;
                }
@@ -541,13 +569,13 @@ static struct tvcard tvcards[] =
         /* Aimslab VHX */
         { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
         /* Zoltrix TV-Max */
-        { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
+        { 3, 1, 0, 2, 0x00000f, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0x8}},
         /* Pixelview PlayTV (bt878) */
         { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},
         /* "Leadtek WinView 601", */
         { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
         /* AVEC Intercapture */
-        { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
+        { 3, 2, 0, 2, 0, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0}},
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
 
@@ -823,30 +851,30 @@ static void make_vbitab(struct bttv *btv)
        unsigned int *po=(unsigned int *) btv->vbi_odd;
        unsigned int *pe=(unsigned int *) btv->vbi_even;
   
-       DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd));
-       DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even));
-       DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
-       DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
+       DEBUG(printk(KERN_DEBUG "vbiodd: 0x%lx\n",(long)btv->vbi_odd));
+       DEBUG(printk(KERN_DEBUG "vbievn: 0x%lx\n",(long)btv->vbi_even));
+       DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po));
+       DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
         
-       *(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0;
+       *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
        for (i=0; i<16; i++) 
        {
-               *(po++)=VBI_RISC;
-               *(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
+               *(po++)=cpu_to_le32(VBI_RISC);
+               *(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048));
        }
-       *(po++)=BT848_RISC_JUMP;
-       *(po++)=virt_to_bus(btv->risc_jmp+4);
+       *(po++)=cpu_to_le32(BT848_RISC_JUMP);
+       *(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
 
-       *(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0;
+       *(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0;
        for (i=16; i<32; i++) 
        {
-               *(pe++)=VBI_RISC;
-               *(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
+               *(pe++)=cpu_to_le32(VBI_RISC);
+               *(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048));
        }
-       *(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16);
-       *(pe++)=virt_to_bus(btv->risc_jmp+10);
-       DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
-       DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
+       *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16));
+       *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
+       DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po));
+       DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
 }
 
 int fmtbppx2[16] = {
@@ -881,8 +909,8 @@ static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
        unsigned long bpl=1024;         /* bytes per line */
        unsigned long vadr=(unsigned long) vbuf;
 
-       *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
-       *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+       *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
+       *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
   
         /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
            is 2 and without separate VBI grabbing.
@@ -890,17 +918,17 @@ static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
 
        for (line=0; line < 640; line++)
        {
-                *(ro++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL;
-                *(ro++)=kvirt_to_bus(vadr);
-                *(re++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL;
-                *(re++)=kvirt_to_bus(vadr+BTTV_MAX_FBUF/2);
+                *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL);
+                *(ro++)=cpu_to_le32(kvirt_to_bus(vadr));
+                *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL);
+                *(re++)=cpu_to_le32(kvirt_to_bus(vadr+BTTV_MAX_FBUF/2));
                 vadr+=bpl;
        }
        
-       *(ro++)=BT848_RISC_JUMP;
-       *(ro++)=btv->bus_vbi_even;
-       *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
-       *(re++)=btv->bus_vbi_odd;
+       *(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+       *(ro++)=cpu_to_le32(btv->bus_vbi_even);
+       *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
+       *(re++)=cpu_to_le32(btv->bus_vbi_odd);
        
        return 0;
 }
@@ -954,8 +982,8 @@ static int  make_prisctab(struct bttv *btv, unsigned int *ro,
        cradr=cbadr+csize;
        inter = (height>btv->win.cropheight/2) ? 1 : 0;
        
-       *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(ro++)=0;
-       *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(re++)=0;
+       *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0;
+       *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(re++)=0;
   
        for (line=0; line < (height<<(1^inter)); line++)
        {
@@ -991,15 +1019,15 @@ static int  make_prisctab(struct bttv *btv, unsigned int *ro,
                 todo-=bl;
                 if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */
                 
-                *((*rp)++)=rcmd|bl;
-                *((*rp)++)=blcb|(blcr<<16);
-                *((*rp)++)=kvirt_to_bus(vadr);
+                *((*rp)++)=cpu_to_le32(rcmd|bl);
+                *((*rp)++)=cpu_to_le32(blcb|(blcr<<16));
+                *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
                 vadr+=bl;
                 if((rcmd&(15<<28))==BT848_RISC_WRITE123)
                 {
-                       *((*rp)++)=kvirt_to_bus(cbadr);
+                       *((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr));
                        cbadr+=blcb;
-                       *((*rp)++)=kvirt_to_bus(cradr);
+                       *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr));
                        cradr+=blcr;
                 }
                 
@@ -1007,10 +1035,10 @@ static int  make_prisctab(struct bttv *btv, unsigned int *ro,
                }
        }
        
-       *(ro++)=BT848_RISC_JUMP;
-       *(ro++)=btv->bus_vbi_even;
-       *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
-       *(re++)=btv->bus_vbi_odd;
+       *(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+       *(ro++)=cpu_to_le32(btv->bus_vbi_even);
+       *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
+       *(re++)=cpu_to_le32(btv->bus_vbi_odd);
        
        return 0;
 }
@@ -1037,8 +1065,8 @@ static int  make_vrisctab(struct bttv *btv, unsigned int *ro,
        inter = (height>btv->win.cropheight/2) ? 1 : 0;
        bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
        
-       *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
-       *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+       *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
+       *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
   
        for (line=0; line < (height<<(1^inter)); line++)
        {
@@ -1050,35 +1078,35 @@ static int  make_vrisctab(struct bttv *btv, unsigned int *ro,
                bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
                if (bpl<=bl)
                 {
-                       *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|
-                               BT848_RISC_EOL|bpl; 
-                       *((*rp)++)=kvirt_to_bus(vadr);
+                       *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+                                               BT848_RISC_EOL|bpl);
+                       *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
                        vadr+=bpl;
                }
                else
                {
                        todo=bpl;
-                       *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl;
-                       *((*rp)++)=kvirt_to_bus(vadr);
+                       *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl);
+                       *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
                        vadr+=bl;
                        todo-=bl;
                        while (todo>PAGE_SIZE)
                        {
-                               *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE;
-                               *((*rp)++)=kvirt_to_bus(vadr);
+                               *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE);
+                               *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
                                vadr+=PAGE_SIZE;
                                todo-=PAGE_SIZE;
                        }
-                       *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo;
-                       *((*rp)++)=kvirt_to_bus(vadr);
+                       *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo);
+                       *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
                        vadr+=todo;
                }
        }
        
-       *(ro++)=BT848_RISC_JUMP;
-       *(ro++)=btv->bus_vbi_even;
-       *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
-       *(re++)=btv->bus_vbi_odd;
+       *(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+       *(ro++)=cpu_to_le32(btv->bus_vbi_even);
+       *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
+       *(re++)=cpu_to_le32(btv->bus_vbi_odd);
        
        return 0;
 }
@@ -1162,10 +1190,10 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
        adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
        if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
                /* can't clip, don't generate any risc code */
-               *(ro++)=BT848_RISC_JUMP;
-               *(ro++)=btv->bus_vbi_even;
-               *(re++)=BT848_RISC_JUMP;
-               *(re++)=btv->bus_vbi_odd;
+               *(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+               *(ro++)=cpu_to_le32(btv->bus_vbi_even);
+               *(re++)=cpu_to_le32(BT848_RISC_JUMP);
+               *(re++)=cpu_to_le32(btv->bus_vbi_odd);
        }
        if (ncr < 0) {  /* bitmap was pased */
                memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE);
@@ -1187,8 +1215,8 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
        if (btv->win.y<0)
                clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y));
        
-       *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
-       *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+       *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
+       *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
        
        /* translate bitmap to risc code */
         for (line=outofmem=0; line < (height<<inter) && !outofmem; line++)
@@ -1206,10 +1234,10 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
                                flags |= ((!sx) ? BT848_RISC_SOL : 0);
                                flags |= ((sx + dx == width) ? BT848_RISC_EOL : 0);
                                if (!lastbit) {
-                                       *((*rp)++)=BT848_RISC_WRITE|flags|len;
-                                       *((*rp)++)=adr + bpp * sx;
+                                       *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|flags|len);
+                                       *((*rp)++)=cpu_to_le32(adr + bpp * sx);
                                } else
-                                       *((*rp)++)=BT848_RISC_SKIP|flags|len;
+                                       *((*rp)++)=cpu_to_le32(BT848_RISC_SKIP|flags|len);
                                lastbit=cbit;
                                sx += dx;
                                dx = 1;
@@ -1224,10 +1252,10 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
        }
        vfree(clipmap);
        /* outofmem flag relies on the following code to discard extra data */
-       *(ro++)=BT848_RISC_JUMP;
-       *(ro++)=btv->bus_vbi_even;
-       *(re++)=BT848_RISC_JUMP;
-       *(re++)=btv->bus_vbi_odd;
+       *(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+       *(ro++)=cpu_to_le32(btv->bus_vbi_even);
+       *(re++)=cpu_to_le32(BT848_RISC_JUMP);
+       *(re++)=cpu_to_le32(btv->bus_vbi_odd);
 }
 
 /* set geometry for even/odd frames 
@@ -1297,6 +1325,23 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
         set_pll(btv);
 
        btwrite(fmt, BT848_COLOR_FMT);
+#ifdef __sparc__
+        if(fmt == BT848_COLOR_FMT_RGB32 ||
+           fmt == BT848_COLOR_FMT_RGB24) {
+                btwrite((BT848_COLOR_CTL_GAMMA         |
+                         BT848_COLOR_CTL_WSWAP_ODD     |
+                         BT848_COLOR_CTL_WSWAP_EVEN    |
+                         BT848_COLOR_CTL_BSWAP_ODD     |
+                         BT848_COLOR_CTL_BSWAP_EVEN),
+                        BT848_COLOR_CTL);
+        } else if(fmt == BT848_COLOR_FMT_RGB16 ||
+           fmt == BT848_COLOR_FMT_RGB15) {
+                btwrite((BT848_COLOR_CTL_GAMMA         |
+                         BT848_COLOR_CTL_BSWAP_ODD     |
+                         BT848_COLOR_CTL_BSWAP_EVEN),
+                        BT848_COLOR_CTL);
+        }
+#endif
        hactive=width;
 
         vtc=0;
@@ -1474,7 +1519,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
                        btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
                        btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
                }
-               btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
+               btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
         }
        btor(3, BT848_CAP_CTL);
        btor(3, BT848_GPIO_DMA_CTL);
@@ -2268,7 +2313,7 @@ static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long si
        pos=(unsigned long) btv->fbuffer;
        while (size > 0) 
        {
-               page = kvirt_to_phys(pos);
+               page = kvirt_to_pa(pos);
                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
                        return -EAGAIN;
                start+=PAGE_SIZE;
@@ -3110,44 +3155,44 @@ static void bt848_set_risc_jmps(struct bttv *btv)
        int flags=btv->cap;
 
        /* Sync to start of odd field */
-       btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE;
+       btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE);
        btv->risc_jmp[1]=0;
 
        /* Jump to odd vbi sub */
-       btv->risc_jmp[2]=BT848_RISC_JUMP|(0x5<<20);
+       btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0x5<<20));
        if (flags&8)
-               btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd);
+               btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd));
        else
-               btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4);
+               btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
 
         /* Jump to odd sub */
-       btv->risc_jmp[4]=BT848_RISC_JUMP|(0x6<<20);
+       btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0x6<<20));
        if (flags&2)
-               btv->risc_jmp[5]=virt_to_bus(btv->risc_odd);
+               btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd));
        else
-               btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6);
+               btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6));
 
 
        /* Sync to start of even field */
-       btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO;
+       btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO);
        btv->risc_jmp[7]=0;
 
        /* Jump to even vbi sub */
-       btv->risc_jmp[8]=BT848_RISC_JUMP;
+       btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP);
        if (flags&4)
-               btv->risc_jmp[9]=virt_to_bus(btv->vbi_even);
+               btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even));
        else
-               btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10);
+               btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
 
        /* Jump to even sub */
-       btv->risc_jmp[10]=BT848_RISC_JUMP|(8<<20);
+       btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20));
        if (flags&1)
-               btv->risc_jmp[11]=virt_to_bus(btv->risc_even);
+               btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even));
        else
-               btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp+12);
+               btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12));
 
-       btv->risc_jmp[12]=BT848_RISC_JUMP;
-       btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp);
+       btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
+       btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp));
 
        /* enable capturing */
        btaor(flags, ~0x0f, BT848_CAP_CTL);
@@ -3165,7 +3210,7 @@ static int init_bt848(int i)
 
        /* reset the bt848 */
        btwrite(0, BT848_SRESET);
-       DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem));
+       DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem));
 
        /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
        btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */
@@ -3330,8 +3375,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                if (!astat)
                        return;
                btwrite(astat,BT848_INT_STAT);
-               IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat));
-               IDEBUG(printk ("bttv%d:  stat %08x\n", btv->nr, stat));
+               IDEBUG(printk ("bttv%d: astat %08x stat %08x\n", btv->nr, astat, stat));
 
                /* get device status bits */
                dstat=btread(BT848_DSTATUS);
@@ -3387,8 +3431,8 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                                        btv->gro = btv->gro_next;
                                        btv->gre = btv->gre_next;
                                        btv->grf = btv->grf_next;
-                                        btv->risc_jmp[5]=btv->gro;
-                                       btv->risc_jmp[11]=btv->gre;
+                                        btv->risc_jmp[5]=cpu_to_le32(btv->gro);
+                                       btv->risc_jmp[11]=cpu_to_le32(btv->gre);
                                        bt848_set_geo(btv, btv->gwidth,
                                                      btv->gheight,
                                                      btv->gfmt);
@@ -3405,9 +3449,9 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                        }
                        if (stat&(8<<28)) 
                        {
-                               btv->risc_jmp[5]=btv->gro;
-                               btv->risc_jmp[11]=btv->gre;
-                               btv->risc_jmp[12]=BT848_RISC_JUMP;
+                               btv->risc_jmp[5]=cpu_to_le32(btv->gro);
+                               btv->risc_jmp[11]=cpu_to_le32(btv->gre);
+                               btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
                                bt848_set_geo(btv, btv->gwidth, btv->gheight,
                                              btv->gfmt);
                        }
@@ -3502,14 +3546,16 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
 
         if (remap[bttv_num])
         {
+                unsigned int dw = btv->bt848_adr;
+
                 if (remap[bttv_num] < 0x1000)
                         remap[bttv_num]<<=20;
                 remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK;
-                printk(KERN_INFO "bttv%d: remapping to : 0x%08x.\n",
+                printk(KERN_INFO "bttv%d: remapping to : 0x%lx.\n",
                        bttv_num,remap[bttv_num]);
                 remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
                 pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]);
-                pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr);
+                pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dw);
                 btv->dev->base_address[0] = btv->bt848_adr;
         }                                      
         btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
@@ -3518,7 +3564,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
                bttv_num,btv->id, btv->revision);
         printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn);
         printk("irq: %d, ",btv->irq);
-        printk("memory: 0x%08x.\n", btv->bt848_adr);
+        printk("memory: 0x%lx.\n", btv->bt848_adr);
 
         btv->pll.pll_crystal = 0;
         btv->pll.pll_ifreq   = 0;
@@ -3542,7 +3588,11 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
                 }
         }
         
+#ifdef __sparc__
+        btv->bt848_mem=(unsigned char *)btv->bt848_adr;
+#else
         btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+#endif
         
         /* clear interrupt mask */
        btwrite(0, BT848_INT_MASK);
@@ -3817,17 +3867,17 @@ static void release_bttv(void)
                if (btv->risc_even)
                        kfree((void *) btv->risc_even);
 
-               DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%08x.\n", btv->risc_jmp));
+               DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp));
                if (btv->risc_jmp)
                        kfree((void *) btv->risc_jmp);
 
-               DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf));
+               DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%p.\n", btv->vbibuf));
                if (btv->vbibuf)
                        vfree((void *) btv->vbibuf);
 
 
                free_irq(btv->irq,btv);
-               DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));
+               DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem));
                if (btv->bt848_mem)
                        iounmap(btv->bt848_mem);
 
index da4f91c85caa707e0c223c0aae4d1b4841a50559..847336116cb90cdb0e269c490ba5d11c21c24a2d 100644 (file)
@@ -102,9 +102,9 @@ struct bttv
 #else
        struct pci_dev *dev;
 #endif
-       unsigned char irq;          /* IRQ used by Bt848 card */
+       unsigned int irq;           /* IRQ used by Bt848 card */
        unsigned char revision;
-       unsigned int bt848_adr;      /* bus address of IO mem returned by PCI BIOS */
+       unsigned long bt848_adr;    /* bus address of IO mem returned by PCI BIOS */
        unsigned char *bt848_mem;   /* pointer to mapped IO memory */
        unsigned long busriscmem; 
        u32 *riscmem;
@@ -274,7 +274,7 @@ struct bttv
 #define TEA6320_S          0x07  /* switch register */
                                  /* values for those registers: */
 #define TEA6320_S_SA       0x01  /* stereo A input */
-#define TEA6320_S_SB       0x02  /* stereo B */
+#define TEA6320_S_SB       0x07  /* stereo B -- databook wrong? this works */
 #define TEA6320_S_SC       0x04  /* stereo C */
 #define TEA6320_S_GMU      0x80  /* general mute */
 
diff --git a/drivers/char/buz.c b/drivers/char/buz.c
new file mode 100644 (file)
index 0000000..b207e0b
--- /dev/null
@@ -0,0 +1,3479 @@
+#define MAX_KMALLOC_MEM (512*1024)
+/*
+   buz - Iomega Buz driver version 1.0
+
+   Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+
+   based on
+
+   buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   and
+
+   bttv - Bt848 frame grabber driver
+
+   Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+   & Marcus Metzler (mocm@thp.uni-koeln.de)
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <asm/spinlock.h>
+
+#include <linux/videodev.h>
+
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include "buz.h"
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+
+#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ )
+#define GPIO_MASK 0xdf
+
+/*
+ BUZ
+   GPIO0 = 1, take board out of reset
+   GPIO1 = 1, take JPEG codec out of sleep mode
+   GPIO3 = 1, deassert FRAME# to 36060
+   
+
+   GIRQ0 signals a vertical sync of the video signal
+   GIRQ1 signals that ZR36060's DATERR# line is asserted.
+
+   SAA7111A
+
+   In their infinite wisdom, the Iomega engineers decided to
+   use the same input line for composite and S-Video Color,
+   although there are two entries not connected at all!
+   Through this ingenious strike, it is not possible to
+   keep two running video sources connected at the same time
+   to Composite and S-VHS input!
+
+   mode 0 - N/C
+   mode 1 - S-Video Y
+   mode 2 - noise or something I don't know
+   mode 3 - Composite and S-Video C
+   mode 4 - N/C
+   mode 5 - S-Video (gain C independently selectable of gain Y)
+   mode 6 - N/C
+   mode 7 - S-Video (gain C adapted to gain Y)
+ */
+
+#define MAJOR_VERSION 1                /* driver major version */
+#define MINOR_VERSION 0                /* driver minor version */
+
+#define BUZ_NAME      "Iomega BUZ V-1.0"       /* name of the driver */
+
+#define DEBUG(x)               /* Debug driver */
+#define IDEBUG(x)              /* Debug interrupt handler */
+#define IOCTL_DEBUG(x)
+
+
+/* The parameters for this driver */
+
+/*
+   The video mem address of the video card.
+   The driver has a little database for some videocards
+   to determine it from there. If your video card is not in there
+   you have either to give it to the driver as a parameter
+   or set in in a VIDIOCSFBUF ioctl
+ */
+
+static unsigned long vidmem = 0;       /* Video memory base address */
+
+/* Special purposes only: */
+
+static int triton = 0;         /* 0=no, 1=yes */
+static int natoma = 0;         /* 0=no, 1=yes */
+
+/*
+   Number and size of grab buffers for Video 4 Linux
+   The vast majority of applications should not need more than 2,
+   the very popular BTTV driver actually does ONLY have 2.
+   Time sensitive applications might need more, the maximum
+   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
+
+   The size is set so that the maximum possible request
+   can be satisfied. Decrease  it, if bigphys_area alloc'd
+   memory is low. If you don't have the bigphys_area patch,
+   set it to 128 KB. Will you allow only to grab small
+   images with V4L, but that's better than nothing.
+
+   v4l_bufsize has to be given in KB !
+
+ */
+
+static int v4l_nbufs = 2;
+static int v4l_bufsize = 128;  /* Everybody should be able to work with this setting */
+
+/*
+   Default input and video norm at startup of the driver.
+ */
+
+static int default_input = 0;  /* 0=Composite, 1=S-VHS */
+static int default_norm = 0;   /* 0=PAL, 1=NTSC */
+
+MODULE_PARM(vidmem, "i");
+MODULE_PARM(triton, "i");
+MODULE_PARM(natoma, "i");
+MODULE_PARM(v4l_nbufs, "i");
+MODULE_PARM(v4l_bufsize, "i");
+MODULE_PARM(default_input, "i");
+MODULE_PARM(default_norm, "i");
+
+/* Anybody who uses more than four? */
+#define BUZ_MAX 4
+
+static int zoran_num;          /* number of Buzs in use */
+static struct zoran zoran[BUZ_MAX];
+
+/* forward references */
+
+static void v4l_fbuffer_free(struct zoran *zr);
+static void jpg_fbuffer_free(struct zoran *zr);
+static void zoran_feed_stat_com(struct zoran *zr);
+
+
+
+/*
+ *   Allocate the V4L grab buffers
+ *
+ *   These have to be pysically contiguous.
+ *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
+ */
+
+static int v4l_fbuffer_alloc(struct zoran *zr)
+{
+       int i, off;
+       unsigned char *mem;
+
+       for (i = 0; i < v4l_nbufs; i++) {
+               if (zr->v4l_gbuf[i].fbuffer)
+                       printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i);
+
+               if (v4l_bufsize <= MAX_KMALLOC_MEM) {
+                       /* Use kmalloc */
+
+                       mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL);
+                       if (mem == 0) {
+                               printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name);
+                               v4l_fbuffer_free(zr);
+                               return -ENOBUFS;
+                       }
+                       zr->v4l_gbuf[i].fbuffer = mem;
+                       zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem);
+                       zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem);
+                       for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
+                               mem_map_reserve(MAP_NR(mem + off));
+                       DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem)));
+               } else {
+                       return -ENOBUFS;
+               }
+       }
+
+       return 0;
+}
+
+/* free the V4L grab buffers */
+static void v4l_fbuffer_free(struct zoran *zr)
+{
+       int i, off;
+       unsigned char *mem;
+
+       for (i = 0; i < v4l_nbufs; i++) {
+               if (!zr->v4l_gbuf[i].fbuffer)
+                       continue;
+
+               mem = zr->v4l_gbuf[i].fbuffer;
+               for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
+                       mem_map_unreserve(MAP_NR(mem + off));
+               kfree((void *) zr->v4l_gbuf[i].fbuffer);
+               zr->v4l_gbuf[i].fbuffer = NULL;
+       }
+}
+
+/*
+ *   Allocate the MJPEG grab buffers.
+ *
+ *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
+ *   kmalloc is used to request a physically contiguous area,
+ *   else we allocate the memory in framgents with get_free_page.
+ *
+ *   If a Natoma chipset is present and this is a revision 1 zr36057,
+ *   each MJPEG buffer needs to be physically contiguous.
+ *   (RJ: This statement is from Dave Perks' original driver,
+ *   I could never check it because I have a zr36067)
+ *   The driver cares about this because it reduces the buffer
+ *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
+ *
+ *   RJ: The contents grab buffers needs never be accessed in the driver.
+ *       Therefore there is no need to allocate them with vmalloc in order
+ *       to get a contiguous virtual memory space.
+ *       I don't understand why many other drivers first allocate them with
+ *       vmalloc (which uses internally also get_free_page, but delivers you
+ *       virtual addresses) and then again have to make a lot of efforts
+ *       to get the physical address.
+ *
+ */
+
+static int jpg_fbuffer_alloc(struct zoran *zr)
+{
+       int i, j, off, alloc_contig;
+       unsigned long mem;
+
+       /* Decide if we should alloc contiguous or fragmented memory */
+       /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
+
+       alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM);
+
+       for (i = 0; i < zr->jpg_nbufs; i++) {
+               if (zr->jpg_gbuf[i].frag_tab)
+                       printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i);
+
+               /* Allocate fragment table for this buffer */
+
+               mem = get_free_page(GFP_KERNEL);
+               if (mem == 0) {
+                       printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i);
+                       jpg_fbuffer_free(zr);
+                       return -ENOBUFS;
+               }
+               memset((void *) mem, 0, PAGE_SIZE);
+               zr->jpg_gbuf[i].frag_tab = (u32 *) mem;
+               zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem);
+
+               if (alloc_contig) {
+                       mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL);
+                       if (mem == 0) {
+                               jpg_fbuffer_free(zr);
+                               return -ENOBUFS;
+                       }
+                       zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem);
+                       zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1;
+                       for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE)
+                               mem_map_reserve(MAP_NR(mem + off));
+               } else {
+                       /* jpg_bufsize is alreay page aligned */
+                       for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
+                               mem = get_free_page(GFP_KERNEL);
+                               if (mem == 0) {
+                                       jpg_fbuffer_free(zr);
+                                       return -ENOBUFS;
+                               }
+                               zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem);
+                               zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1;
+                               mem_map_reserve(MAP_NR(mem));
+                       }
+
+                       zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1;
+               }
+       }
+
+       DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n",
+                    (zr->jpg_nbufs * zr->jpg_bufsize) >> 10));
+       zr->jpg_buffers_allocated = 1;
+       return 0;
+}
+
+/* free the MJPEG grab buffers */
+static void jpg_fbuffer_free(struct zoran *zr)
+{
+       int i, j, off, alloc_contig;
+       unsigned char *mem;
+
+       /* Decide if we should alloc contiguous or fragmented memory */
+       /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
+
+       alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM);
+
+       for (i = 0; i < zr->jpg_nbufs; i++) {
+               if (!zr->jpg_gbuf[i].frag_tab)
+                       continue;
+
+               if (alloc_contig) {
+                       if (zr->jpg_gbuf[i].frag_tab[0]) {
+                               mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]);
+                               for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE)
+                                       mem_map_unreserve(MAP_NR(mem + off));
+                               kfree((void *) mem);
+                               zr->jpg_gbuf[i].frag_tab[0] = 0;
+                               zr->jpg_gbuf[i].frag_tab[1] = 0;
+                       }
+               } else {
+                       for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
+                               if (!zr->jpg_gbuf[i].frag_tab[2 * j])
+                                       break;
+                               mem_map_unreserve(MAP_NR(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])));
+                               free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]));
+                               zr->jpg_gbuf[i].frag_tab[2 * j] = 0;
+                               zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0;
+                       }
+               }
+
+               free_page((unsigned long) zr->jpg_gbuf[i].frag_tab);
+               zr->jpg_gbuf[i].frag_tab = NULL;
+       }
+       zr->jpg_buffers_allocated = 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+/* I2C functions                                                           */
+
+#define I2C_DELAY   10
+
+
+/* software I2C functions */
+
+static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data)
+{
+       struct zoran *zr = (struct zoran *) bus->data;
+       btwrite((data << 1) | ctrl, ZR36057_I2CBR);
+       btread(ZR36057_I2CBR);
+       udelay(I2C_DELAY);
+}
+
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+       struct zoran *zr = (struct zoran *) bus->data;
+       return (btread(ZR36057_I2CBR) >> 1) & 1;
+}
+
+void attach_inform(struct i2c_bus *bus, int id)
+{
+       DEBUG(struct zoran *zr = (struct zoran *) bus->data);
+       DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id));
+}
+
+void detach_inform(struct i2c_bus *bus, int id)
+{
+       DEBUG(struct zoran *zr = (struct zoran *) bus->data);
+       DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id));
+}
+
+static struct i2c_bus zoran_i2c_bus_template =
+{
+       "zr36057",
+       I2C_BUSID_BT848,
+       NULL,
+
+       SPIN_LOCK_UNLOCKED,
+
+       attach_inform,
+       detach_inform,
+
+       i2c_setlines,
+       i2c_getdataline,
+       NULL,
+       NULL,
+};
+
+
+/* ----------------------------------------------------------------------- */
+
+static void GPIO(struct zoran *zr, unsigned bit, unsigned value)
+{
+       u32 reg;
+       u32 mask;
+
+       mask = 1 << (24 + bit);
+       reg = btread(ZR36057_GPPGCR1) & ~mask;
+       if (value) {
+               reg |= mask;
+       }
+       btwrite(reg, ZR36057_GPPGCR1);
+       /* Stop any PCI posting on the GPIO bus */
+       btread(ZR36057_I2CBR);
+}
+
+
+/*
+ *   Set the registers for the size we have specified. Don't bother
+ *   trying to understand this without the ZR36057 manual in front of
+ *   you [AC].
+ *
+ *   PS: The manual is free for download in .pdf format from
+ *   www.zoran.com - nicely done those folks.
+ */
+
+struct tvnorm {
+       u16 Wt, Wa, Ht, Ha, HStart, VStart;
+};
+
+static struct tvnorm tvnorms[] =
+{
+   /* PAL-BDGHI */
+       {864, 720, 625, 576, 31, 16},
+   /* NTSC */
+       {858, 720, 525, 480, 21, 8},
+};
+#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm))
+
+static int format2bpp(int format)
+{
+       int bpp;
+
+       /* Determine the number of bytes per pixel for the video format requested */
+
+       switch (format) {
+
+       case VIDEO_PALETTE_YUV422:
+               bpp = 2;
+               break;
+
+       case VIDEO_PALETTE_RGB555:
+               bpp = 2;
+               break;
+
+       case VIDEO_PALETTE_RGB565:
+               bpp = 2;
+               break;
+
+       case VIDEO_PALETTE_RGB24:
+               bpp = 3;
+               break;
+
+       case VIDEO_PALETTE_RGB32:
+               bpp = 4;
+               break;
+
+       default:
+               bpp = 0;
+       }
+
+       return bpp;
+}
+
+/*
+ * set geometry
+ */
+static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height,
+                           unsigned int video_format)
+{
+       struct tvnorm *tvn;
+       unsigned HStart, HEnd, VStart, VEnd;
+       unsigned DispMode;
+       unsigned VidWinWid, VidWinHt;
+       unsigned hcrop1, hcrop2, vcrop1, vcrop2;
+       unsigned Wa, We, Ha, He;
+       unsigned X, Y, HorDcm, VerDcm;
+       u32 reg;
+       unsigned mask_line_size;
+
+       if (zr->params.norm < 0 || zr->params.norm > 1) {
+               printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name,  zr->params.norm);
+               return;
+       }
+       if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) {
+               printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height);
+               return;
+       }
+       tvn = &tvnorms[zr->params.norm];
+
+       Wa = tvn->Wa;
+       Ha = tvn->Ha;
+
+       /* if window has more than half of active height,
+          switch on interlacing - we want the full information */
+
+       zr->video_interlace = (video_height > Ha / 2);
+
+/**** zr36057 ****/
+
+       /* horizontal */
+       VidWinWid = video_width;
+       X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
+       We = (VidWinWid * 64) / X;
+       HorDcm = 64 - X;
+       hcrop1 = 2 * ((tvn->Wa - We) / 4);
+       hcrop2 = tvn->Wa - We - hcrop1;
+       HStart = tvn->HStart | 1;
+       HEnd = HStart + tvn->Wa - 1;
+       HStart += hcrop1;
+       HEnd -= hcrop2;
+       reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
+           | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
+       reg |= ZR36057_VFEHCR_HSPol;
+       btwrite(reg, ZR36057_VFEHCR);
+
+       /* Vertical */
+       DispMode = !zr->video_interlace;
+       VidWinHt = DispMode ? video_height : video_height / 2;
+       Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
+       He = (VidWinHt * 64) / Y;
+       VerDcm = 64 - Y;
+       vcrop1 = (tvn->Ha / 2 - He) / 2;
+       vcrop2 = tvn->Ha / 2 - He - vcrop1;
+       VStart = tvn->VStart;
+       VEnd = VStart + tvn->Ha / 2 - 1;
+       VStart += vcrop1;
+       VEnd -= vcrop2;
+       reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
+           | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
+       reg |= ZR36057_VFEVCR_VSPol;
+       btwrite(reg, ZR36057_VFEVCR);
+
+       /* scaler and pixel format */
+       reg = 0                 // ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */
+            | (HorDcm << ZR36057_VFESPFR_HorDcm)
+           | (VerDcm << ZR36057_VFESPFR_VerDcm)
+           | (DispMode << ZR36057_VFESPFR_DispMode)
+           | ZR36057_VFESPFR_LittleEndian;
+       /* RJ: I don't know, why the following has to be the opposite
+          of the corresponding ZR36060 setting, but only this way
+          we get the correct colors when uncompressing to the screen  */
+       reg |= ZR36057_VFESPFR_VCLKPol;
+       /* RJ: Don't know if that is needed for NTSC also */
+       reg |= ZR36057_VFESPFR_TopField;
+       switch (video_format) {
+
+       case VIDEO_PALETTE_YUV422:
+               reg |= ZR36057_VFESPFR_YUV422;
+               break;
+
+       case VIDEO_PALETTE_RGB555:
+               reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;
+               break;
+
+       case VIDEO_PALETTE_RGB565:
+               reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;
+               break;
+
+       case VIDEO_PALETTE_RGB24:
+               reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;
+               break;
+
+       case VIDEO_PALETTE_RGB32:
+               reg |= ZR36057_VFESPFR_RGB888;
+               break;
+
+       default:
+               printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format);
+               return;
+
+       }
+       if (HorDcm >= 48) {
+               reg |= 3 << ZR36057_VFESPFR_HFilter;    /* 5 tap filter */
+       } else if (HorDcm >= 32) {
+               reg |= 2 << ZR36057_VFESPFR_HFilter;    /* 4 tap filter */
+       } else if (HorDcm >= 16) {
+               reg |= 1 << ZR36057_VFESPFR_HFilter;    /* 3 tap filter */
+       }
+       btwrite(reg, ZR36057_VFESPFR);
+
+       /* display configuration */
+
+       reg = (16 << ZR36057_VDCR_MinPix)
+           | (VidWinHt << ZR36057_VDCR_VidWinHt)
+           | (VidWinWid << ZR36057_VDCR_VidWinWid);
+       if (triton)
+               reg &= ~ZR36057_VDCR_Triton;
+       else
+               reg |= ZR36057_VDCR_Triton;
+       btwrite(reg, ZR36057_VDCR);
+
+       /* Write overlay clipping mask data, but don't enable overlay clipping */
+       /* RJ: since this makes only sense on the screen, we use 
+          zr->window.width instead of video_width */
+
+       mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+       reg = virt_to_bus(zr->overlay_mask);
+       btwrite(reg, ZR36057_MMTR);
+       reg = virt_to_bus(zr->overlay_mask + mask_line_size);
+       btwrite(reg, ZR36057_MMBR);
+       reg = mask_line_size - (zr->window.width + 31) / 32;
+       if (DispMode == 0)
+               reg += mask_line_size;
+       reg <<= ZR36057_OCR_MaskStride;
+       btwrite(reg, ZR36057_OCR);
+
+}
+
+/*
+ * Switch overlay on or off
+ */
+
+static void zr36057_overlay(struct zoran *zr, int on)
+{
+       int fmt, bpp;
+       u32 reg;
+
+       if (on) {
+               /* do the necessary settings ... */
+
+               btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);       /* switch it off first */
+
+               switch (zr->buffer.depth) {
+               case 15:
+                       fmt = VIDEO_PALETTE_RGB555;
+                       bpp = 2;
+                       break;
+               case 16:
+                       fmt = VIDEO_PALETTE_RGB565;
+                       bpp = 2;
+                       break;
+               case 24:
+                       fmt = VIDEO_PALETTE_RGB24;
+                       bpp = 3;
+                       break;
+               case 32:
+                       fmt = VIDEO_PALETTE_RGB32;
+                       bpp = 4;
+                       break;
+               default:
+                       fmt = 0;
+                       bpp = 0;
+               }
+
+               zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt);
+
+               /* Start and length of each line MUST be 4-byte aligned.
+                  This should be allready checked before the call to this routine.
+                  All error messages are internal driver checking only! */
+
+               /* video display top and bottom registers */
+
+               reg = (u32) zr->buffer.base
+                   + zr->window.x * bpp
+                   + zr->window.y * zr->buffer.bytesperline;
+               btwrite(reg, ZR36057_VDTR);
+               if (reg & 3)
+                       printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name);
+               if (zr->video_interlace)
+                       reg += zr->buffer.bytesperline;
+               btwrite(reg, ZR36057_VDBR);
+
+               /* video stride, status, and frame grab register */
+
+               reg = zr->buffer.bytesperline - zr->window.width * bpp;
+               if (zr->video_interlace)
+                       reg += zr->buffer.bytesperline;
+               if (reg & 3)
+                       printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name);
+               reg = (reg << ZR36057_VSSFGR_DispStride);
+               reg |= ZR36057_VSSFGR_VidOvf;   /* clear overflow status */
+               btwrite(reg, ZR36057_VSSFGR);
+
+               /* Set overlay clipping */
+
+               if (zr->window.clipcount)
+                       btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
+
+               /* ... and switch it on */
+
+               btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+       } else {
+               /* Switch it off */
+
+               btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+       }
+}
+
+/*
+ * The overlay mask has one bit for each pixel on a scan line,
+ *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
+ */
+static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count)
+{
+       unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+       u32 *mask;
+       int x, y, width, height;
+       unsigned i, j, k;
+       u32 reg;
+
+       /* fill mask with one bits */
+       memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
+       reg = 0;
+
+       for (i = 0; i < count; ++i) {
+               /* pick up local copy of clip */
+               x = vp[i].x;
+               y = vp[i].y;
+               width = vp[i].width;
+               height = vp[i].height;
+
+               /* trim clips that extend beyond the window */
+               if (x < 0) {
+                       width += x;
+                       x = 0;
+               }
+               if (y < 0) {
+                       height += y;
+                       y = 0;
+               }
+               if (x + width > zr->window.width) {
+                       width = zr->window.width - x;
+               }
+               if (y + height > zr->window.height) {
+                       height = zr->window.height - y;
+               }
+               /* ignore degenerate clips */
+               if (height <= 0) {
+                       continue;
+               }
+               if (width <= 0) {
+                       continue;
+               }
+               /* apply clip for each scan line */
+               for (j = 0; j < height; ++j) {
+                       /* reset bit for each pixel */
+                       /* this can be optimized later if need be */
+                       mask = zr->overlay_mask + (y + j) * mask_line_size;
+                       for (k = 0; k < width; ++k) {
+                               mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32);
+                       }
+               }
+       }
+}
+
+/* Enable/Disable uncompressed memory grabbing of the 36057 */
+
+static void zr36057_set_memgrab(struct zoran *zr, int mode)
+{
+       if (mode) {
+               if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab))
+                       printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name);
+
+               /* switch on VSync interrupts */
+
+               btwrite(IRQ_MASK, ZR36057_ISR);         // Clear Interrupts
+
+               btor(ZR36057_ICR_GIRQ0, ZR36057_ICR);
+
+               /* enable SnapShot */
+
+               btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+
+               /* Set zr36057 video front end  and enable video */
+
+#ifdef XAWTV_HACK
+               zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat);
+#else
+               zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat);
+#endif
+
+               zr->v4l_memgrab_active = 1;
+       } else {
+               zr->v4l_memgrab_active = 0;
+
+               /* switch off VSync interrupts */
+
+               btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR);
+
+               /* reenable grabbing to screen if it was running */
+
+               if (zr->v4l_overlay_active) {
+                       zr36057_overlay(zr, 1);
+               } else {
+                       btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+                       btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+               }
+       }
+}
+
+static int wait_grab_pending(struct zoran *zr)
+{
+       unsigned long flags;
+
+       /* wait until all pending grabs are finished */
+
+       if (!zr->v4l_memgrab_active)
+               return 0;
+
+       while (zr->v4l_pend_tail != zr->v4l_pend_head) {
+               interruptible_sleep_on(&zr->v4l_capq);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+       }
+
+       spin_lock_irqsave(&zr->lock, flags);
+       zr36057_set_memgrab(zr, 0);
+       spin_unlock_irqrestore(&zr->lock, flags);
+
+       return 0;
+}
+
+/*
+ *   V4L Buffer grabbing
+ */
+
+static int v4l_grab(struct zoran *zr, struct video_mmap *mp)
+{
+       unsigned long flags;
+       int res, bpp;
+
+       /*
+        * There is a long list of limitations to what is allowed to be grabbed
+        * We don't output error messages her, since some programs (e.g. xawtv)
+        * just try several settings to find out what is valid or not.
+        */
+
+       /* No grabbing outside the buffer range! */
+
+       if (mp->frame >= v4l_nbufs || mp->frame < 0)
+               return -EINVAL;
+
+       /* Check size and format of the grab wanted */
+
+       if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH)
+               return -EINVAL;
+       if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH)
+               return -EINVAL;
+
+       bpp = format2bpp(mp->format);
+       if (bpp == 0)
+               return -EINVAL;
+
+       /* Check against available buffer size */
+
+       if (mp->height * mp->width * bpp > v4l_bufsize)
+               return -EINVAL;
+
+       /* The video front end needs 4-byte alinged line sizes */
+
+       if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3)))
+               return -EINVAL;
+
+       /*
+        * To minimize the time spent in the IRQ routine, we avoid setting up
+        * the video front end there.
+        * If this grab has different parameters from a running streaming capture
+        * we stop the streaming capture and start it over again.
+        */
+
+       if (zr->v4l_memgrab_active &&
+           (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) {
+               res = wait_grab_pending(zr);
+               if (res)
+                       return res;
+       }
+       zr->gwidth = mp->width;
+       zr->gheight = mp->height;
+       zr->gformat = mp->format;
+       zr->gbpl = bpp * zr->gwidth;
+
+
+       spin_lock_irqsave(&zr->lock, flags);
+
+       /* make sure a grab isn't going on currently with this buffer */
+
+       switch (zr->v4l_gbuf[mp->frame].state) {
+
+       default:
+       case BUZ_STATE_PEND:
+               res = -EBUSY;   /* what are you doing? */
+               break;
+
+       case BUZ_STATE_USER:
+       case BUZ_STATE_DONE:
+               /* since there is at least one unused buffer there's room for at least one more pend[] entry */
+               zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame;
+               zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND;
+               res = 0;
+               break;
+
+       }
+
+       /* put the 36057 into frame grabbing mode */
+
+       if (!res && !zr->v4l_memgrab_active)
+               zr36057_set_memgrab(zr, 1);
+
+       spin_unlock_irqrestore(&zr->lock, flags);
+
+       return res;
+}
+
+/*
+ * Sync on a V4L buffer
+ */
+
+static int v4l_sync(struct zoran *zr, int frame)
+{
+       unsigned long flags;
+
+
+       /* check passed-in frame number */
+       if (frame >= v4l_nbufs || frame < 0) {
+               printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame);
+               return -EINVAL;
+       }
+       /* Check if is buffer was queued at all */
+
+       if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) {
+//             printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name);
+               return -EINVAL;
+       }
+       /* wait on this buffer to get ready */
+
+       while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) {
+               interruptible_sleep_on(&zr->v4l_capq);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+       }
+
+       /* buffer should now be in BUZ_STATE_DONE */
+
+       if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE)
+               printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name);
+
+       /* Check if streaming capture has finished */
+
+       spin_lock_irqsave(&zr->lock, flags);
+
+       if (zr->v4l_pend_tail == zr->v4l_pend_head)
+               zr36057_set_memgrab(zr, 0);
+
+       spin_unlock_irqrestore(&zr->lock, flags);
+
+       return 0;
+}
+/*****************************************************************************
+ *                                                                           *
+ *  Set up the Buz-specific MJPEG part                                       *
+ *                                                                           *
+ *****************************************************************************/
+
+/*
+ *     Wait til post office is no longer busy 
+ */
+static int post_office_wait(struct zoran *zr)
+{
+       u32 por;
+       u32 ct=0;
+
+       while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
+               ct++;
+               if(ct>100000)
+               {
+                       printk(KERN_ERR "%s: timeout on post office.\n", zr->name);
+                       return -1;
+               }
+               /* wait for something to happen */
+       }
+       if ((por & ZR36057_POR_POPen) != 0) {
+               printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por);
+               return -1;
+       }
+       if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) {
+               printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por);
+               return -1;
+       }
+       return 0;
+}
+
+static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value)
+{
+       u32 por;
+
+       post_office_wait(zr);
+       por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF);
+       btwrite(por, ZR36057_POR);
+       return post_office_wait(zr);
+}
+
+static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg)
+{
+       u32 por;
+
+       post_office_wait(zr);
+       por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
+       btwrite(por, ZR36057_POR);
+       if (post_office_wait(zr) < 0) {
+               return -1;
+       }
+       return btread(ZR36057_POR) & 0xFF;
+}
+
+static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val)
+{
+       if (post_office_wait(zr)
+           || post_office_write(zr, 0, 1, reg >> 8)
+           || post_office_write(zr, 0, 2, reg)) {
+               return -1;
+       }
+       return post_office_write(zr, 0, 3, val);
+}
+
+static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val)
+{
+       if (zr36060_write_8(zr, reg + 0, val >> 8)) {
+               return -1;
+       }
+       return zr36060_write_8(zr, reg + 1, val >> 0);
+}
+
+static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val)
+{
+       if (zr36060_write_8(zr, reg + 0, val >> 16)) {
+               return -1;
+       }
+       return zr36060_write_16(zr, reg + 1, val >> 0);
+}
+
+static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val)
+{
+       if (zr36060_write_16(zr, reg + 0, val >> 16)) {
+               return -1;
+       }
+       return zr36060_write_16(zr, reg + 2, val >> 0);
+}
+
+static u32 zr36060_read_8(struct zoran *zr, unsigned reg)
+{
+       if (post_office_wait(zr)
+           || post_office_write(zr, 0, 1, reg >> 8)
+           || post_office_write(zr, 0, 2, reg)) {
+               return -1;
+       }
+       return post_office_read(zr, 0, 3) & 0xFF;
+}
+
+static int zr36060_reset(struct zoran *zr)
+{
+       return post_office_write(zr, 3, 0, 0);
+}
+
+static void zr36060_sleep(struct zoran *zr, int sleep)
+{
+       GPIO(zr, 1, !sleep);
+}
+
+
+static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
+{
+       struct tvnorm *tvn;
+       u32 reg;
+       int size;
+
+       reg = (1 << 0)          /* CodeMstr */
+           |(0 << 2)           /* CFIS=0 */
+           |(0 << 6)           /* Endian=0 */
+           |(0 << 7);          /* Code16=0 */
+       zr36060_write_8(zr, 0x002, reg);
+
+       switch (mode) {
+
+       case BUZ_MODE_MOTION_DECOMPRESS:
+       case BUZ_MODE_STILL_DECOMPRESS:
+               reg = 0x00;     /* Codec mode = decompression */
+               break;
+
+       case BUZ_MODE_MOTION_COMPRESS:
+       case BUZ_MODE_STILL_COMPRESS:
+       default:
+               reg = 0xa4;     /* Codec mode = compression with variable scale factor */
+               break;
+
+       }
+       zr36060_write_8(zr, 0x003, reg);
+
+       reg = 0x00;             /* reserved, mbz */
+       zr36060_write_8(zr, 0x004, reg);
+
+       reg = 0xff;             /* 510 bits/block */
+       zr36060_write_8(zr, 0x005, reg);
+
+       /* JPEG markers */
+       reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */
+       if (zr->params.COM_len)
+               reg |= JPEG_MARKER_COM;
+       if (zr->params.APP_len)
+               reg |= JPEG_MARKER_APP;
+       zr36060_write_8(zr, 0x006, reg);
+
+       reg = (0 << 3)          /* DATERR=0 */
+           |(0 << 2)           /* END=0 */
+           |(0 << 1)           /* EOI=0 */
+           |(0 << 0);          /* EOAV=0 */
+       zr36060_write_8(zr, 0x007, reg);
+
+       /* code volume */
+
+       /* Target field size in pixels: */
+       tvn = &tvnorms[zr->params.norm];
+       size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm);
+
+       /* Target compressed field size in bits: */
+       size = size * 16;       /* uncompressed size in bits */
+       size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */
+
+       /* Lower limit (arbitrary, 1 KB) */
+       if (size < 8192)
+               size = 8192;
+
+       /* Upper limit: 7/8 of the code buffers */
+       if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7)
+               size = zr->jpg_bufsize * 7 / zr->params.field_per_buff;
+
+       reg = size;
+       zr36060_write_32(zr, 0x009, reg);
+
+       /* how do we set initial SF as a function of quality parameter? */
+       reg = 0x0100;           /* SF=1.0 */
+       zr36060_write_16(zr, 0x011, reg);
+
+       reg = 0x00ffffff;       /* AF=max */
+       zr36060_write_24(zr, 0x013, reg);
+
+       reg = 0x0000;           /* test */
+       zr36060_write_16(zr, 0x024, reg);
+}
+
+static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode)
+{
+       struct tvnorm *tvn;
+       u32 reg;
+
+       reg = (0 << 7)          /* Video8=0 */
+           |(0 << 6)           /* Range=0 */
+           |(0 << 3)           /* FlDet=0 */
+           |(1 << 2)           /* FlVedge=1 */
+           |(0 << 1)           /* FlExt=0 */
+           |(0 << 0);          /* SyncMstr=0 */
+
+       /* According to ZR36067 documentation, FlDet should correspond
+          to the odd_even flag of the ZR36067 */
+       if (zr->params.odd_even)
+               reg |= (1 << 3);
+
+       if (mode != BUZ_MODE_STILL_DECOMPRESS) {
+               /* limit pixels to range 16..235 as per CCIR-601 */
+               reg |= (1 << 6);        /* Range=1 */
+       }
+       zr36060_write_8(zr, 0x030, reg);
+
+       reg = (0 << 7)          /* VCLKPol=0 */
+           |(0 << 6)           /* PValPol=0 */
+           |(1 << 5)           /* PoePol=1 */
+           |(0 << 4)           /* SImgPol=0 */
+           |(0 << 3)           /* BLPol=0 */
+           |(0 << 2)           /* FlPol=0 */
+           |(0 << 1)           /* HSPol=0, sync on falling edge */
+           |(1 << 0);          /* VSPol=1 */
+       zr36060_write_8(zr, 0x031, reg);
+
+       switch (zr->params.HorDcm) {
+       default:
+       case 1:
+               reg = (0 << 0);
+               break;          /* HScale = 0 */
+
+       case 2:
+               reg = (1 << 0);
+               break;          /* HScale = 1 */
+
+       case 4:
+               reg = (2 << 0);
+               break;          /* HScale = 2 */
+       }
+       if (zr->params.VerDcm == 2)
+               reg |= (1 << 2);
+       zr36060_write_8(zr, 0x032, reg);
+
+       reg = 0x80;             /* BackY */
+       zr36060_write_8(zr, 0x033, reg);
+
+       reg = 0xe0;             /* BackU */
+       zr36060_write_8(zr, 0x034, reg);
+
+       reg = 0xe0;             /* BackV */
+       zr36060_write_8(zr, 0x035, reg);
+
+       /* sync generator */
+
+       tvn = &tvnorms[zr->params.norm];
+
+       reg = tvn->Ht - 1;      /* Vtotal */
+       zr36060_write_16(zr, 0x036, reg);
+
+       reg = tvn->Wt - 1;      /* Htotal */
+       zr36060_write_16(zr, 0x038, reg);
+
+       reg = 6 - 1;            /* VsyncSize */
+       zr36060_write_8(zr, 0x03a, reg);
+
+       reg = 100 - 1;          /* HsyncSize */
+       zr36060_write_8(zr, 0x03b, reg);
+
+       reg = tvn->VStart - 1;  /* BVstart */
+       zr36060_write_8(zr, 0x03c, reg);
+
+       reg += tvn->Ha / 2;     /* BVend */
+       zr36060_write_16(zr, 0x03e, reg);
+
+       reg = tvn->HStart - 1;  /* BHstart */
+       zr36060_write_8(zr, 0x03d, reg);
+
+       reg += tvn->Wa;         /* BHend */
+       zr36060_write_16(zr, 0x040, reg);
+
+       /* active area */
+       reg = zr->params.img_y + tvn->VStart;   /* Vstart */
+       zr36060_write_16(zr, 0x042, reg);
+
+       reg += zr->params.img_height;   /* Vend */
+       zr36060_write_16(zr, 0x044, reg);
+
+       reg = zr->params.img_x + tvn->HStart;   /* Hstart */
+       zr36060_write_16(zr, 0x046, reg);
+
+       reg += zr->params.img_width;    /* Hend */
+       zr36060_write_16(zr, 0x048, reg);
+
+       /* subimage area */
+       reg = zr->params.img_y + tvn->VStart;   /* SVstart */
+       zr36060_write_16(zr, 0x04a, reg);
+
+       reg += zr->params.img_height;   /* SVend */
+       zr36060_write_16(zr, 0x04c, reg);
+
+       reg = zr->params.img_x + tvn->HStart;   /* SHstart */
+       zr36060_write_16(zr, 0x04e, reg);
+
+       reg += zr->params.img_width;    /* SHend */
+       zr36060_write_16(zr, 0x050, reg);
+}
+
+static void zr36060_set_jpg_SOF(struct zoran *zr)
+{
+       u32 reg;
+
+
+       reg = 0xffc0;           /* SOF marker */
+       zr36060_write_16(zr, 0x060, reg);
+
+       reg = 17;               /* SOF length */
+       zr36060_write_16(zr, 0x062, reg);
+
+       reg = 8;                /* precision 8 bits */
+       zr36060_write_8(zr, 0x064, reg);
+
+       reg = zr->params.img_height / zr->params.VerDcm;        /* image height */
+       zr36060_write_16(zr, 0x065, reg);
+
+       reg = zr->params.img_width / zr->params.HorDcm; /* image width */
+       zr36060_write_16(zr, 0x067, reg);
+
+       reg = 3;                /* 3 color components */
+       zr36060_write_8(zr, 0x069, reg);
+
+       reg = 0x002100;         /* Y component */
+       zr36060_write_24(zr, 0x06a, reg);
+
+       reg = 0x011101;         /* U component */
+       zr36060_write_24(zr, 0x06d, reg);
+
+       reg = 0x021101;         /* V component */
+       zr36060_write_24(zr, 0x070, reg);
+}
+
+static void zr36060_set_jpg_SOS(struct zoran *zr)
+{
+       u32 reg;
+
+
+       reg = 0xffda;           /* SOS marker */
+       zr36060_write_16(zr, 0x07a, reg);
+
+       reg = 12;               /* SOS length */
+       zr36060_write_16(zr, 0x07c, reg);
+
+       reg = 3;                /* 3 color components */
+       zr36060_write_8(zr, 0x07e, reg);
+
+       reg = 0x0000;           /* Y component */
+       zr36060_write_16(zr, 0x07f, reg);
+
+       reg = 0x0111;           /* U component */
+       zr36060_write_16(zr, 0x081, reg);
+
+       reg = 0x0211;           /* V component */
+       zr36060_write_16(zr, 0x083, reg);
+
+       reg = 0x003f00;         /* Start, end spectral scans */
+       zr36060_write_24(zr, 0x085, reg);
+}
+
+static void zr36060_set_jpg_DRI(struct zoran *zr)
+{
+       u32 reg;
+
+
+       reg = 0xffdd;           /* DRI marker */
+       zr36060_write_16(zr, 0x0c0, reg);
+
+       reg = 4;                /* DRI length */
+       zr36060_write_16(zr, 0x0c2, reg);
+
+       reg = 8;                /* length in MCUs */
+       zr36060_write_16(zr, 0x0c4, reg);
+}
+
+static void zr36060_set_jpg_DQT(struct zoran *zr)
+{
+       unsigned i;
+       unsigned adr;
+       static const u8 dqt[] =
+       {
+               0xff, 0xdb,     /* DHT marker */
+               0x00, 0x84,     /* DHT length */
+               0x00,           /* table ID 0 */
+               0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+               0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+               0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+               0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+               0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+               0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+               0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+               0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+               0x01,           /* table ID 1 */
+               0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+               0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+               0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
+       };
+
+       /* write fixed quantitization tables */
+       adr = 0x0cc;
+       for (i = 0; i < sizeof(dqt); ++i) {
+               zr36060_write_8(zr, adr++, dqt[i]);
+       }
+}
+
+static void zr36060_set_jpg_DHT(struct zoran *zr)
+{
+       unsigned i;
+       unsigned adr;
+       static const u8 dht[] =
+       {
+               0xff, 0xc4,     /* DHT marker */
+               0x01, 0xa2,     /* DHT length */
+               0x00,           /* table class 0, ID 0 */
+               0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,         /* # codes of length 1..8 */
+               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,         /* # codes of length 8..16 */
+               0x00,           /* values for codes of length 2 */
+               0x01, 0x02, 0x03, 0x04, 0x05,   /* values for codes of length 3 */
+               0x06,           /* values for codes of length 4 */
+               0x07,           /* values for codes of length 5 */
+               0x08,           /* values for codes of length 6 */
+               0x09,           /* values for codes of length 7 */
+               0x0a,           /* values for codes of length 8 */
+               0x0b,           /* values for codes of length 9 */
+               0x01,           /* table class 0, ID 1 */
+               0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,         /* # codes of length 1..8 */
+               0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,         /* # codes of length 9..16 */
+               0x00, 0x01, 0x02,       /* values for codes of length 2 */
+               0x03,           /* values for codes of length 3 */
+               0x04,           /* values for codes of length 4 */
+               0x05,           /* values for codes of length 5 */
+               0x06,           /* values for codes of length 6 */
+               0x07,           /* values for codes of length 7 */
+               0x08,           /* values for codes of length 8 */
+               0x09,           /* values for codes of length 9 */
+               0x0a,           /* values for codes of length 10 */
+               0x0b,           /* values for codes of length 11 */
+               0x10,
+               0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+               0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+               0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+               0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+               0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+               0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+               0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+               0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+               0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+               0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+               0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+               0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+               0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+               0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+               0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+               0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+               0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+               0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+               0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+               0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+               0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
+               0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00,
+               0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,
+               0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+               0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08,
+               0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23,
+               0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a,
+               0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
+               0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35,
+               0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+               0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55,
+               0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84,
+               0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+               0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
+               0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+               0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+               0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+               0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+               0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+               0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5,
+               0xf6, 0xf7, 0xf8, 0xf9, 0xfa
+       };
+
+       /* write fixed Huffman tables */
+       adr = 0x1d4;
+       for (i = 0; i < sizeof(dht); ++i) {
+               zr36060_write_8(zr, adr++, dht[i]);
+       }
+}
+
+static void zr36060_set_jpg_APP(struct zoran *zr)
+{
+       unsigned adr;
+       int len, i;
+       u32 reg;
+
+
+       len = zr->params.APP_len;
+       if (len < 0)
+               len = 0;
+       if (len > 60)
+               len = 60;
+
+       i = zr->params.APPn;
+       if (i < 0)
+               i = 0;
+       if (i > 15)
+               i = 15;
+
+       reg = 0xffe0 + i;       /* APPn marker */
+       zr36060_write_16(zr, 0x380, reg);
+
+       reg = len + 2;          /* APPn len */
+       zr36060_write_16(zr, 0x382, reg);
+
+       /* write APPn data */
+       adr = 0x384;
+       for (i = 0; i < 60; i++) {
+               zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0));
+       }
+}
+
+static void zr36060_set_jpg_COM(struct zoran *zr)
+{
+       unsigned adr;
+       int len, i;
+       u32 reg;
+
+
+       len = zr->params.COM_len;
+       if (len < 0)
+               len = 0;
+       if (len > 60)
+               len = 60;
+
+       reg = 0xfffe;           /* COM marker */
+       zr36060_write_16(zr, 0x3c0, reg);
+
+       reg = len + 2;          /* COM len */
+       zr36060_write_16(zr, 0x3c2, reg);
+
+       /* write COM data */
+       adr = 0x3c4;
+       for (i = 0; i < 60; i++) {
+               zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0));
+       }
+}
+
+static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode)
+{
+       unsigned i;
+       u32 reg;
+
+       zr36060_reset(zr);
+       mdelay(10);
+
+       reg = (0 << 7)          /* Load=0 */
+           |(1 << 0);          /* SynRst=1 */
+       zr36060_write_8(zr, 0x000, reg);
+
+       zr36060_set_jpg(zr, mode);
+       zr36060_set_video(zr, mode);
+       zr36060_set_jpg_SOF(zr);
+       zr36060_set_jpg_SOS(zr);
+       zr36060_set_jpg_DRI(zr);
+       zr36060_set_jpg_DQT(zr);
+       zr36060_set_jpg_DHT(zr);
+       zr36060_set_jpg_APP(zr);
+       zr36060_set_jpg_COM(zr);
+
+       reg = (1 << 7)          /* Load=1 */
+           |(0 << 0);          /* SynRst=0 */
+       zr36060_write_8(zr, 0x000, reg);
+
+       /* wait for codec to unbusy */
+       for (i = 0; i < 1000; ++i) {
+               reg = zr36060_read_8(zr, 0x001);
+               if ((reg & (1 << 7)) == 0) {
+                       DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i));
+                       return;
+               }
+               udelay(1000);
+       }
+       printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg);
+}
+
+static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
+{
+       struct tvnorm *tvn;
+       u32 reg;
+       int i;
+
+       tvn = &tvnorms[zr->params.norm];
+
+       /* assert P_Reset */
+       btwrite(0, ZR36057_JPC);
+
+       /* re-initialize DMA ring stuff */
+       zr->jpg_que_head = 0;
+       zr->jpg_dma_head = 0;
+       zr->jpg_dma_tail = 0;
+       zr->jpg_que_tail = 0;
+       zr->jpg_seq_num = 0;
+       for (i = 0; i < BUZ_NUM_STAT_COM; ++i) {
+               zr->stat_com[i] = 1;    /* mark as unavailable to zr36057 */
+       }
+       for (i = 0; i < zr->jpg_nbufs; i++) {
+               zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */
+       }
+
+       /* MJPEG compression mode */
+       switch (mode) {
+
+       case BUZ_MODE_MOTION_COMPRESS:
+       default:
+               reg = ZR36057_JMC_MJPGCmpMode;
+               break;
+
+       case BUZ_MODE_MOTION_DECOMPRESS:
+               reg = ZR36057_JMC_MJPGExpMode;
+               reg |= ZR36057_JMC_SyncMstr;
+               /* RJ: The following is experimental - improves the output to screen */
+               if (zr->params.VFIFO_FB)
+                       reg |= ZR36057_JMC_VFIFO_FB;
+               break;
+
+       case BUZ_MODE_STILL_COMPRESS:
+               reg = ZR36057_JMC_JPGCmpMode;
+               break;
+
+       case BUZ_MODE_STILL_DECOMPRESS:
+               reg = ZR36057_JMC_JPGExpMode;
+               break;
+
+       }
+       reg |= ZR36057_JMC_JPG;
+       if (zr->params.field_per_buff == 1)
+               reg |= ZR36057_JMC_Fld_per_buff;
+       btwrite(reg, ZR36057_JMC);
+
+       /* vertical */
+       btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
+       reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot);
+       btwrite(reg, ZR36057_VSP);
+       reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY)
+           | (zr->params.img_height << ZR36057_FVAP_PAY);
+       btwrite(reg, ZR36057_FVAP);
+
+       /* horizontal */
+       btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
+       reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot);
+       btwrite(reg, ZR36057_HSP);
+       reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX)
+           | (zr->params.img_width << ZR36057_FHAP_PAX);
+       btwrite(reg, ZR36057_FHAP);
+
+       /* field process parameters */
+       if (zr->params.odd_even)
+               reg = ZR36057_FPP_Odd_Even;
+       else
+               reg = 0;
+       btwrite(reg, ZR36057_FPP);
+
+       /* Set proper VCLK Polarity, else colors will be wrong during playback */
+       btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
+
+       /* code base address and FIFO threshold */
+       reg = virt_to_bus(zr->stat_com);
+       btwrite(reg, ZR36057_JCBA);
+       reg = 0x50;
+       btwrite(reg, ZR36057_JCFT);
+
+       /* JPEG codec guest ID */
+       reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg);
+       btwrite(reg, ZR36057_JCGI);
+
+       /* Code transfer guest ID */
+       reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg);
+       reg |= ZR36057_MCTCR_CFlush;
+       btwrite(reg, ZR36057_MCTCR);
+
+       /* deassert P_Reset */
+       btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
+}
+
+static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode)
+{
+       static int zero = 0;
+       static int one = 1;
+
+       switch (mode) {
+
+       case BUZ_MODE_MOTION_COMPRESS:
+               zr36060_set_cap(zr, mode);
+               zr36057_set_jpg(zr, mode);
+               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one);
+               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero);
+
+               /* deassert P_Reset, assert Code transfer enable */
+               btwrite(IRQ_MASK, ZR36057_ISR);
+               btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+               break;
+
+       case BUZ_MODE_MOTION_DECOMPRESS:
+               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero);
+               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one);
+               zr36060_set_cap(zr, mode);
+               zr36057_set_jpg(zr, mode);
+
+               /* deassert P_Reset, assert Code transfer enable */
+               btwrite(IRQ_MASK, ZR36057_ISR);
+               btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+               break;
+
+       case BUZ_MODE_IDLE:
+       default:
+               /* shut down processing */
+               btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+               btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
+               btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
+               btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
+               btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+               btwrite(0, ZR36057_ISR);
+               zr36060_reset(zr);
+               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one);
+               i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero);
+               break;
+
+       }
+       zr->codec_mode = mode;
+}
+
+/*
+ *   Queue a MJPEG buffer for capture/playback
+ */
+
+static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode)
+{
+       unsigned long flags;
+       int res;
+
+       /* Check if buffers are allocated */
+
+       if (!zr->jpg_buffers_allocated) {
+               printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name);
+               return -ENOMEM;
+       }
+       /* Does the user want to stop streaming? */
+
+       if (frame < 0) {
+               if (zr->codec_mode == mode) {
+                       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+                       return 0;
+               } else {
+                       printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name);
+                       return -EINVAL;
+               }
+       }
+       /* No grabbing outside the buffer range! */
+
+       if (frame >= zr->jpg_nbufs) {
+               printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame);
+               return -EINVAL;
+       }
+       /* what is the codec mode right now? */
+
+       if (zr->codec_mode == BUZ_MODE_IDLE) {
+               /* Ok load up the zr36060 and go */
+               zr36057_enable_jpg(zr, mode);
+       } else if (zr->codec_mode != mode) {
+               /* wrong codec mode active - invalid */
+               printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name);
+               return -EINVAL;
+       }
+       spin_lock_irqsave(&zr->lock, flags);
+
+       /* make sure a grab isn't going on currently with this buffer */
+
+       switch (zr->jpg_gbuf[frame].state) {
+
+       default:
+       case BUZ_STATE_DMA:
+       case BUZ_STATE_PEND:
+       case BUZ_STATE_DONE:
+               res = -EBUSY;   /* what are you doing? */
+               break;
+
+       case BUZ_STATE_USER:
+               /* since there is at least one unused buffer there's room for at least one more pend[] entry */
+               zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame;
+               zr->jpg_gbuf[frame].state = BUZ_STATE_PEND;
+               zoran_feed_stat_com(zr);
+               res = 0;
+               break;
+
+       }
+
+       spin_unlock_irqrestore(&zr->lock, flags);
+
+       /* Start the zr36060 when the first frame is queued  */
+       if (zr->jpg_que_head == 1) {
+               btor(ZR36057_JMC_Go_en, ZR36057_JMC);
+               btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC);
+       }
+       return res;
+}
+
+/*
+ *   Sync on a MJPEG buffer
+ */
+
+static int jpg_sync(struct zoran *zr, struct zoran_sync *bs)
+{
+       unsigned long flags;
+       int frame;
+
+       if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
+           zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
+               return -EINVAL;
+       }
+       while (zr->jpg_que_tail == zr->jpg_dma_tail) {
+               interruptible_sleep_on(&zr->jpg_capq);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+       }
+
+       spin_lock_irqsave(&zr->lock, flags);
+
+       frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
+
+       /* buffer should now be in BUZ_STATE_DONE */
+
+       if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE)
+               printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name);
+
+       *bs = zr->jpg_gbuf[frame].bs;
+       zr->jpg_gbuf[frame].state = BUZ_STATE_USER;
+
+       spin_unlock_irqrestore(&zr->lock, flags);
+
+       return 0;
+}
+
+/* when this is called the spinlock must be held */
+static void zoran_feed_stat_com(struct zoran *zr)
+{
+       /* move frames from pending queue to DMA */
+
+       int frame, i, max_stat_com;
+
+       max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
+
+       while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com
+              && zr->jpg_dma_head != zr->jpg_que_head) {
+
+               frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
+               if (zr->params.TmpDcm == 1) {
+                       /* fill 1 stat_com entry */
+                       i = zr->jpg_dma_head & BUZ_MASK_STAT_COM;
+                       zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
+               } else {
+                       /* fill 2 stat_com entries */
+                       i = (zr->jpg_dma_head & 1) * 2;
+                       zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
+                       zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus;
+               }
+               zr->jpg_gbuf[frame].state = BUZ_STATE_DMA;
+               zr->jpg_dma_head++;
+
+       }
+}
+
+/* when this is called the spinlock must be held */
+static void zoran_reap_stat_com(struct zoran *zr)
+{
+       /* move frames from DMA queue to done queue */
+
+       int i;
+       u32 stat_com;
+       unsigned int seq;
+       unsigned int dif;
+       int frame;
+       struct zoran_gbuffer *gbuf;
+
+       /* In motion decompress we don't have a hardware frame counter,
+          we just count the interrupts here */
+
+       if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
+               zr->jpg_seq_num++;
+
+       while (zr->jpg_dma_tail != zr->jpg_dma_head) {
+               if (zr->params.TmpDcm == 1)
+                       i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM;
+               else
+                       i = (zr->jpg_dma_tail & 1) * 2 + 1;
+
+               stat_com = zr->stat_com[i];
+
+               if ((stat_com & 1) == 0) {
+                       return;
+               }
+               frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+               gbuf = &zr->jpg_gbuf[frame];
+               get_fast_time(&gbuf->bs.timestamp);
+
+               if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+                       gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
+
+                       /* update sequence number with the help of the counter in stat_com */
+
+                       seq = stat_com >> 24;
+                       dif = (seq - zr->jpg_seq_num) & 0xff;
+                       zr->jpg_seq_num += dif;
+               } else {
+                       gbuf->bs.length = 0;
+               }
+               gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
+               gbuf->state = BUZ_STATE_DONE;
+
+               zr->jpg_dma_tail++;
+       }
+}
+
+static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       u32 stat, astat;
+       int count;
+       struct zoran *zr;
+       unsigned long flags;
+
+       zr = (struct zoran *) dev_id;
+       count = 0;
+
+       spin_lock_irqsave(&zr->lock, flags);
+       while (1) {
+               /* get/clear interrupt status bits */
+               stat = btread(ZR36057_ISR);
+               astat = stat & IRQ_MASK;
+               if (!astat) {
+                       break;
+               }
+               btwrite(astat, ZR36057_ISR);
+               IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat));
+
+#if (IRQ_MASK & ZR36057_ISR_GIRQ0)
+               if (astat & ZR36057_ISR_GIRQ0) {
+
+                       /* Interrupts may still happen when zr->v4l_memgrab_active is switched off.
+                          We simply ignore them */
+
+                       if (zr->v4l_memgrab_active) {
+
+/* A lot more checks should be here ... */
+                               if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0)
+                                       printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name);
+
+                               if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
+                                       /* There is a grab on a frame going on, check if it has finished */
+
+                                       if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) {
+                                               /* it is finished, notify the user */
+
+                                               zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE;
+                                               zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+                                               zr->v4l_grab_seq++;
+                                               zr->v4l_pend_tail++;
+                                       }
+                               }
+                               if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
+                                       wake_up_interruptible(&zr->v4l_capq);
+
+                               /* Check if there is another grab queued */
+
+                               if (zr->v4l_grab_frame == NO_GRAB_ACTIVE &&
+                                   zr->v4l_pend_tail != zr->v4l_pend_head) {
+
+                                       int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
+                                       u32 reg;
+
+                                       zr->v4l_grab_frame = frame;
+
+                                       /* Set zr36057 video front end and enable video */
+
+                                       /* Buffer address */
+
+                                       reg = zr->v4l_gbuf[frame].fbuffer_bus;
+                                       btwrite(reg, ZR36057_VDTR);
+                                       if (zr->video_interlace)
+                                               reg += zr->gbpl;
+                                       btwrite(reg, ZR36057_VDBR);
+
+                                       /* video stride, status, and frame grab register */
+
+#ifdef XAWTV_HACK
+                                       reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0;
+#else
+                                       reg = 0;
+#endif
+                                       if (zr->video_interlace)
+                                               reg += zr->gbpl;
+                                       reg = (reg << ZR36057_VSSFGR_DispStride);
+                                       reg |= ZR36057_VSSFGR_VidOvf;
+                                       reg |= ZR36057_VSSFGR_SnapShot;
+                                       reg |= ZR36057_VSSFGR_FrameGrab;
+                                       btwrite(reg, ZR36057_VSSFGR);
+
+                                       btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+                               }
+                       }
+               }
+#endif                         /* (IRQ_MASK & ZR36057_ISR_GIRQ0) */
+
+#if (IRQ_MASK & ZR36057_ISR_GIRQ1)
+               if (astat & ZR36057_ISR_GIRQ1) {
+                       unsigned csr = zr36060_read_8(zr, 0x001);
+                       unsigned isr = zr36060_read_8(zr, 0x008);
+
+                       IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n",
+                                     zr->name, csr, isr));
+
+                       btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR);
+                       zoran_reap_stat_com(zr);
+                       zoran_feed_stat_com(zr);
+               }
+#endif                         /* (IRQ_MASK & ZR36057_ISR_GIRQ1) */
+
+#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
+               if (astat & ZR36057_ISR_CodRepIRQ) {
+                       IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name));
+                       btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
+               }
+#endif                         /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
+
+#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
+               if ((astat & ZR36057_ISR_JPEGRepIRQ) &&
+                   (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+                    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) {
+                       zoran_reap_stat_com(zr);
+                       zoran_feed_stat_com(zr);
+                       wake_up_interruptible(&zr->jpg_capq);
+               }
+#endif                         /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
+
+               count++;
+               if (count > 10) {
+                       printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count);
+                       if (count > 20) {
+                               btwrite(0, ZR36057_ICR);
+                               printk(KERN_ERR  "%s: IRQ lockup, cleared int mask\n", zr->name);
+                               break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&zr->lock, flags);
+}
+
+/* Check a zoran_params struct for correctness, insert default params */
+
+static int zoran_check_params(struct zoran *zr, struct zoran_params *params)
+{
+       int err = 0, err0 = 0;
+
+       /* insert constant params */
+
+       params->major_version = MAJOR_VERSION;
+       params->minor_version = MINOR_VERSION;
+
+       /* Check input and norm */
+
+       if (params->input != 0 && params->input != 1) {
+               err++;
+       }
+       if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) {
+               err++;
+       }
+       /* Check decimation, set default values for decimation = 1, 2, 4 */
+
+       switch (params->decimation) {
+       case 1:
+
+               params->HorDcm = 1;
+               params->VerDcm = 1;
+               params->TmpDcm = 1;
+               params->field_per_buff = 2;
+
+               params->img_x = 0;
+               params->img_y = 0;
+               params->img_width = 720;
+               params->img_height = tvnorms[params->norm].Ha / 2;
+               break;
+
+       case 2:
+
+               params->HorDcm = 2;
+               params->VerDcm = 1;
+               params->TmpDcm = 2;
+               params->field_per_buff = 1;
+
+               params->img_x = 8;
+               params->img_y = 0;
+               params->img_width = 704;
+               params->img_height = tvnorms[params->norm].Ha / 2;
+               break;
+
+       case 4:
+
+               params->HorDcm = 4;
+               params->VerDcm = 2;
+               params->TmpDcm = 2;
+               params->field_per_buff = 1;
+
+               params->img_x = 8;
+               params->img_y = 0;
+               params->img_width = 704;
+               params->img_height = tvnorms[params->norm].Ha / 2;
+               break;
+
+       case 0:
+
+               /* We have to check the data the user has set */
+
+               if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4)
+                       err0++;
+               if (params->VerDcm != 1 && params->VerDcm != 2)
+                       err0++;
+               if (params->TmpDcm != 1 && params->TmpDcm != 2)
+                       err0++;
+               if (params->field_per_buff != 1 && params->field_per_buff != 2)
+                       err0++;
+
+               if (params->img_x < 0)
+                       err0++;
+               if (params->img_y < 0)
+                       err0++;
+               if (params->img_width < 0)
+                       err0++;
+               if (params->img_height < 0)
+                       err0++;
+               if (params->img_x + params->img_width > 720)
+                       err0++;
+               if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2)
+                       err0++;
+               if (params->img_width % (16 * params->HorDcm) != 0)
+                       err0++;
+               if (params->img_height % (8 * params->VerDcm) != 0)
+                       err0++;
+
+               if (err0) {
+                       err++;
+               }
+               break;
+
+       default:
+               err++;
+               break;
+       }
+
+       if (params->quality > 100)
+               params->quality = 100;
+       if (params->quality < 5)
+               params->quality = 5;
+
+       if (params->APPn < 0)
+               params->APPn = 0;
+       if (params->APPn > 15)
+               params->APPn = 15;
+       if (params->APP_len < 0)
+               params->APP_len = 0;
+       if (params->APP_len > 60)
+               params->APP_len = 60;
+       if (params->COM_len < 0)
+               params->COM_len = 0;
+       if (params->COM_len > 60)
+               params->COM_len = 60;
+
+       if (err)
+               return -EINVAL;
+
+       return 0;
+
+}
+static void zoran_open_init_params(struct zoran *zr)
+{
+       int i;
+
+       /* Per default, map the V4L Buffers */
+
+       zr->map_mjpeg_buffers = 0;
+
+       /* User must explicitly set a window */
+
+       zr->window_set = 0;
+
+       zr->window.x = 0;
+       zr->window.y = 0;
+       zr->window.width = 0;
+       zr->window.height = 0;
+       zr->window.chromakey = 0;
+       zr->window.flags = 0;
+       zr->window.clips = NULL;
+       zr->window.clipcount = 0;
+
+       zr->video_interlace = 0;
+
+       zr->v4l_memgrab_active = 0;
+       zr->v4l_overlay_active = 0;
+
+       zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+       zr->v4l_grab_seq = 0;
+
+       zr->gwidth = 0;
+       zr->gheight = 0;
+       zr->gformat = 0;
+       zr->gbpl = 0;
+
+       /* DMA ring stuff for V4L */
+
+       zr->v4l_pend_tail = 0;
+       zr->v4l_pend_head = 0;
+       for (i = 0; i < v4l_nbufs; i++) {
+               zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */
+       }
+
+       /* Set necessary params and call zoran_check_params to set the defaults */
+
+       zr->params.decimation = 1;
+
+       zr->params.quality = 50;        /* default compression factor 8 */
+       zr->params.odd_even = 1;
+
+       zr->params.APPn = 0;
+       zr->params.APP_len = 0; /* No APPn marker */
+       for (i = 0; i < 60; i++)
+               zr->params.APP_data[i] = 0;
+
+       zr->params.COM_len = 0; /* No COM marker */
+       for (i = 0; i < 60; i++)
+               zr->params.COM_data[i] = 0;
+
+       zr->params.VFIFO_FB = 0;
+
+       memset(zr->params.reserved, 0, sizeof(zr->params.reserved));
+
+       zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT;
+
+       i = zoran_check_params(zr, &zr->params);
+       if (i)
+               printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name);
+}
+
+/*
+ *   Open a buz card. Right now the flags stuff is just playing
+ */
+
+static int zoran_open(struct video_device *dev, int flags)
+{
+       struct zoran *zr = (struct zoran *) dev;
+
+       DEBUG(printk(KERN_INFO ": zoran_open\n"));
+
+       switch (flags) {
+
+       case 0:
+               if (zr->user)
+                       return -EBUSY;
+               zr->user++;
+
+               if (v4l_fbuffer_alloc(zr) < 0) {
+                       zr->user--;
+                       return -ENOMEM;
+               }
+               /* default setup */
+
+               zoran_open_init_params(zr);
+
+               zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+
+               btwrite(IRQ_MASK, ZR36057_ISR);         // Clears interrupts
+
+               btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
+
+               break;
+
+       default:
+               return -EBUSY;
+
+       }
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static void zoran_close(struct video_device *dev)
+{
+       struct zoran *zr = (struct zoran *) dev;
+
+       DEBUG(printk(KERN_INFO ": zoran_close\n"));
+       
+       /* disable interrupts */
+       btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+
+       /* wake up sleeping beauties */
+       wake_up_interruptible(&zr->v4l_capq);
+       wake_up_interruptible(&zr->jpg_capq);
+
+       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+       zr36057_set_memgrab(zr, 0);
+       if (zr->v4l_overlay_active)
+               zr36057_overlay(zr, 0);
+
+       zr->user--;
+
+       v4l_fbuffer_free(zr);
+       jpg_fbuffer_free(zr);
+       zr->jpg_nbufs = 0;
+
+       MOD_DEC_USE_COUNT;
+       DEBUG(printk(KERN_INFO ": zoran_close done\n"));
+}
+
+
+static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock)
+{
+       return -EINVAL;
+}
+
+static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock)
+{
+       return -EINVAL;
+}
+
+/*
+ *   ioctl routine
+ */
+
+
+static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+       struct zoran *zr = (struct zoran *) dev;
+
+       switch (cmd) {
+
+       case VIDIOCGCAP:
+               {
+                       struct video_capability b;
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n"));
+                       strncpy(b.name, zr->video_dev.name, sizeof(b.name));
+                       b.type = VID_TYPE_CAPTURE |
+                           VID_TYPE_OVERLAY |
+                           VID_TYPE_CLIPPING |
+                           VID_TYPE_FRAMERAM |
+                           VID_TYPE_SCALES;
+                       /* theoretically we could also flag VID_TYPE_SUBCAPTURE
+                          but this is not even implemented in the BTTV driver */
+
+                       b.channels = 2;         /* composite, svhs */
+                       b.audios = 0;
+                       b.maxwidth = BUZ_MAX_WIDTH;
+                       b.maxheight = BUZ_MAX_HEIGHT;
+                       b.minwidth = BUZ_MIN_WIDTH;
+                       b.minheight = BUZ_MIN_HEIGHT;
+                       if (copy_to_user(arg, &b, sizeof(b))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+       case VIDIOCGCHAN:
+               {
+                       struct video_channel v;
+
+                       if (copy_from_user(&v, arg, sizeof(v))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel));
+                       switch (v.channel) {
+                       case 0:
+                               strcpy(v.name, "Composite");
+                               break;
+                       case 1:
+                               strcpy(v.name, "SVHS");
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       v.tuners = 0;
+                       v.flags = 0;
+                       v.type = VIDEO_TYPE_CAMERA;
+                       v.norm = zr->params.norm;
+                       if (copy_to_user(arg, &v, sizeof(v))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+               /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
+
+                * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
+                *                                 ^^^^^^^
+                * The famos BTTV driver has it implemented with a struct video_channel argument
+                * and we follow it for compatibility reasons
+                *
+                * BTW: this is the only way the user can set the norm!
+                */
+
+       case VIDIOCSCHAN:
+               {
+                       struct video_channel v;
+                       int input;
+                       int on, res;
+
+                       if (copy_from_user(&v, arg, sizeof(v))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm));
+                       switch (v.channel) {
+                       case 0:
+                               input = 3;
+                               break;
+                       case 1:
+                               input = 7;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+
+                       if (v.norm != VIDEO_MODE_PAL
+                           && v.norm != VIDEO_MODE_NTSC) {
+                               return -EINVAL;
+                       }
+                       zr->params.norm = v.norm;
+                       zr->params.input = v.channel;
+
+                       /* We switch overlay off and on since a change in the norm
+                          needs different VFE settings */
+
+                       on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
+                       if (on)
+                               zr36057_overlay(zr, 0);
+
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+
+                       if (on)
+                               zr36057_overlay(zr, 1);
+
+                       /* Make sure the changes come into effect */
+                       res = wait_grab_pending(zr);
+                       if (res)
+                               return res;
+
+                       return 0;
+               }
+
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+                       return -EINVAL;
+
+       case VIDIOCGPICT:
+               {
+                       struct video_picture p = zr->picture;
+
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n"));
+                       p.depth = zr->buffer.depth;
+                       switch (zr->buffer.depth) {
+                       case 15:
+                               p.palette = VIDEO_PALETTE_RGB555;
+                               break;
+
+                       case 16:
+                               p.palette = VIDEO_PALETTE_RGB565;
+                               break;
+
+                       case 24:
+                               p.palette = VIDEO_PALETTE_RGB24;
+                               break;
+
+                       case 32:
+                               p.palette = VIDEO_PALETTE_RGB32;
+                               break;
+                       }
+
+                       if (copy_to_user(arg, &p, sizeof(p))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+       case VIDIOCSPICT:
+               {
+                       struct video_picture p;
+
+                       if (copy_from_user(&p, arg, sizeof(p))) {
+                               return -EFAULT;
+                       }
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n",
+                                          p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette));
+                       /* The depth and palette values have no meaning to us,
+                          should we return  -EINVAL if they don't fit ? */
+                       zr->picture = p;
+                       return 0;
+               }
+
+       case VIDIOCCAPTURE:
+               {
+                       int v, res;
+
+                       if (copy_from_user(&v, arg, sizeof(v))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v));
+                       /* If there is nothing to do, return immediatly */
+
+                       if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active))
+                               return 0;
+
+                       if (v == 0) {
+                               zr->v4l_overlay_active = 0;
+                               if (!zr->v4l_memgrab_active)
+                                       zr36057_overlay(zr, 0);
+                               /* When a grab is running, the video simply won't be switched on any more */
+                       } else {
+                               if (!zr->buffer_set || !zr->window_set) {
+                                       return -EINVAL;
+                               }
+                               zr->v4l_overlay_active = 1;
+                               if (!zr->v4l_memgrab_active)
+                                       zr36057_overlay(zr, 1);
+                               /* When a grab is running, the video will be switched on when grab is finished */
+                       }
+                       /* Make sure the changes come into effect */
+                       res = wait_grab_pending(zr);
+                       if (res)
+                               return res;
+                       return 0;
+               }
+
+       case VIDIOCGWIN:
+               {
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n"));
+                       if (copy_to_user(arg, &zr->window, sizeof(zr->window))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+       case VIDIOCSWIN:
+               {
+                       struct video_clip *vcp;
+                       struct video_window vw;
+                       int on, end, res;
+
+                       if (copy_from_user(&vw, arg, sizeof(vw))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount));
+                       if (!zr->buffer_set) {
+                               return -EINVAL;
+                       }
+                       /*
+                        * The video front end needs 4-byte alinged line sizes, we correct that
+                        * silently here if necessary
+                        */
+
+                       if (zr->buffer.depth == 15 || zr->buffer.depth == 16) {
+                               end = (vw.x + vw.width) & ~1;   /* round down */
+                               vw.x = (vw.x + 1) & ~1;         /* round up */
+                               vw.width = end - vw.x;
+                       }
+                       if (zr->buffer.depth == 24) {
+                               end = (vw.x + vw.width) & ~3;   /* round down */
+                               vw.x = (vw.x + 3) & ~3;         /* round up */
+                               vw.width = end - vw.x;
+                       }
+#if 0
+                       // At least xawtv seems to care about the following - just leave it away
+                       /*
+                        * Also corrected silently (as long as window fits at all):
+                        * video not fitting the screen
+                        */
+#if 0
+                       if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width ||
+                           vw.y + vw.height > zr->buffer.height) {
+                               printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n",
+                                      vw.width, vw.height, vw.x, vw.y);
+                               return -EINVAL;
+                       }
+#else
+                       if (vw.x < 0)
+                               vw.x = 0;
+                       if (vw.y < 0)
+                               vw.y = 0;
+                       if (vw.x + vw.width > zr->buffer.width)
+                               vw.width = zr->buffer.width - vw.x;
+                       if (vw.y + vw.height > zr->buffer.height)
+                               vw.height = zr->buffer.height - vw.y;
+#endif
+#endif
+
+                       /* Check for vaild parameters */
+                       if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT ||
+                           vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) {
+                               return -EINVAL;
+                       }
+#ifdef XAWTV_HACK
+                       if (vw.width > 720)
+                               vw.width = 720;
+#endif
+
+                       zr->window.x = vw.x;
+                       zr->window.y = vw.y;
+                       zr->window.width = vw.width;
+                       zr->window.height = vw.height;
+                       zr->window.chromakey = 0;
+                       zr->window.flags = 0;   // RJ: Is this intended for interlace on/off ?
+
+                       zr->window.clips = NULL;
+                       zr->window.clipcount = vw.clipcount;
+
+                       /*
+                        * If an overlay is running, we have to switch it off
+                        * and switch it on again in order to get the new settings in effect.
+                        *
+                        * We also want to avoid that the overlay mask is written
+                        * when an overlay is running.
+                        */
+
+                       on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
+                       if (on)
+                               zr36057_overlay(zr, 0);
+
+                       /*
+                        *   Write the overlay mask if clips are wanted.
+                        */
+                       if (vw.clipcount) {
+                               vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4));
+                               if (vcp == NULL) {
+                                       return -ENOMEM;
+                               }
+                               if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) {
+                                       vfree(vcp);
+                                       return -EFAULT;
+                               }
+                               write_overlay_mask(zr, vcp, vw.clipcount);
+                               vfree(vcp);
+                       }
+                       if (on)
+                               zr36057_overlay(zr, 1);
+                       zr->window_set = 1;
+
+                       /* Make sure the changes come into effect */
+                       res = wait_grab_pending(zr);
+                       if (res)
+                               return res;
+
+                       return 0;
+               }
+
+       case VIDIOCGFBUF:
+               {
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n"));
+                       if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+       case VIDIOCSFBUF:
+               {
+                       struct video_buffer v;
+
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EPERM;
+
+                       if (copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline));
+                       if (zr->v4l_overlay_active) {
+                               /* Has the user gotten crazy ... ? */
+                               return -EINVAL;
+                       }
+                       if (v.depth != 15
+                           && v.depth != 16
+                           && v.depth != 24
+                           && v.depth != 32) {
+                               return -EINVAL;
+                       }
+                       if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) {
+                               return -EINVAL;
+                       }
+                       if (v.bytesperline & 3) {
+                               return -EINVAL;
+                       }
+                       if (v.base) {
+                               zr->buffer.base = (void *) ((unsigned long) v.base & ~3);
+                       }
+                       zr->buffer.height = v.height;
+                       zr->buffer.width = v.width;
+                       zr->buffer.depth = v.depth;
+                       zr->buffer.bytesperline = v.bytesperline;
+
+                       if (zr->buffer.base)
+                               zr->buffer_set = 1;
+                       zr->window_set = 0;     /* The user should set new window parameters */
+                       return 0;
+               }
+
+               /* RJ: what is VIDIOCKEY intended to do ??? */
+
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               return -EINVAL;
+               
+       case VIDIOCSYNC:
+               {
+                       int v;
+
+                       if (copy_from_user(&v, arg, sizeof(v))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v));
+                       return v4l_sync(zr, v);
+               }
+
+       case VIDIOCMCAPTURE:
+               {
+                       struct video_mmap vm;
+
+                       if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n",
+                              vm.frame, vm.height, vm.width, vm.format));
+                       return v4l_grab(zr, &vm);
+               }
+
+       case VIDIOCGMBUF:
+               {
+                       struct video_mbuf vm;
+                       int i;
+
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n"));
+               
+                       vm.size = v4l_nbufs * v4l_bufsize;
+                       vm.frames = v4l_nbufs;
+                       for (i = 0; i < v4l_nbufs; i++) {
+                               vm.offsets[i] = i * v4l_bufsize;
+                       }
+
+                       /* The next mmap will map the V4L buffers */
+                       zr->map_mjpeg_buffers = 0;
+
+                       if (copy_to_user(arg, &vm, sizeof(vm))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+       case VIDIOCGUNIT:
+               {
+                       struct video_unit vu;
+
+                       IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n"));
+                       vu.video = zr->video_dev.minor;
+                       vu.vbi = VIDEO_NO_UNIT;
+                       vu.radio = VIDEO_NO_UNIT;
+                       vu.audio = VIDEO_NO_UNIT;
+                       vu.teletext = VIDEO_NO_UNIT;
+                       if (copy_to_user(arg, &vu, sizeof(vu)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+               /*
+                * RJ: In principal we could support subcaptures for V4L grabbing.
+                *     Not even the famous BTTV driver has them, however.
+                *     If there should be a strong demand, one could consider
+                *     to implement them.
+                */
+       case VIDIOCGCAPTURE:
+       case VIDIOCSCAPTURE:
+                       return -EINVAL;
+
+       case BUZIOC_G_PARAMS:
+               {
+                       IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n"));
+                       if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) 
+                               return -EFAULT;
+                       return 0;
+               }
+
+       case BUZIOC_S_PARAMS:
+               {
+                       struct zoran_params bp;
+                       int input, on;
+
+                       if (zr->codec_mode != BUZ_MODE_IDLE) {
+                               return -EINVAL;
+                       }
+                       if (copy_from_user(&bp, arg, sizeof(bp))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n"));
+                       
+                       /* Check the params first before overwriting our internal values */
+
+                       if (zoran_check_params(zr, &bp))
+                               return -EINVAL;
+
+                       zr->params = bp;
+
+                       /* Make changes of input and norm go into effect immediatly */
+
+                       /* We switch overlay off and on since a change in the norm
+                          needs different VFE settings */
+
+                       on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
+                       if (on)
+                               zr36057_overlay(zr, 0);
+
+                       input = zr->params.input == 0 ? 3 : 7;
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+
+                       if (on)
+                               zr36057_overlay(zr, 1);
+
+                       if (copy_to_user(arg, &bp, sizeof(bp))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+       case BUZIOC_REQBUFS:
+               {
+                       struct zoran_requestbuffers br;
+
+                       if (zr->jpg_buffers_allocated) {
+                               return -EINVAL;
+                       }
+                       if (copy_from_user(&br, arg, sizeof(br))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n",
+                                          br.count, br.size));
+                       /* Enforce reasonable lower and upper limits */
+                       if (br.count < 4)
+                               br.count = 4;   /* Could be choosen smaller */
+                       if (br.count > BUZ_MAX_FRAME)
+                               br.count = BUZ_MAX_FRAME;
+                       br.size = PAGE_ALIGN(br.size);
+                       if (br.size < 8192)
+                               br.size = 8192;         /* Arbitrary */
+                       /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */
+                       if (br.size > (512 * 1024))
+                               br.size = (512 * 1024);         /* 512 K should be enough */
+                       if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM)
+                               br.size = MAX_KMALLOC_MEM;
+
+                       zr->jpg_nbufs = br.count;
+                       zr->jpg_bufsize = br.size;
+
+                       if (jpg_fbuffer_alloc(zr))
+                               return -ENOMEM;
+
+                       /* The next mmap will map the MJPEG buffers */
+                       zr->map_mjpeg_buffers = 1;
+
+                       if (copy_to_user(arg, &br, sizeof(br))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+       case BUZIOC_QBUF_CAPT:
+               {
+                       int nb;
+
+                       if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb));
+                       return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS);
+               }
+
+       case BUZIOC_QBUF_PLAY:
+               {
+                       int nb;
+
+                       if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb));
+                       return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS);
+               }
+
+       case BUZIOC_SYNC:
+               {
+                       struct zoran_sync bs;
+                       int res;
+
+                       IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n"));
+                       res = jpg_sync(zr, &bs);
+                       if (copy_to_user(arg, &bs, sizeof(bs))) {
+                               return -EFAULT;
+                       }
+                       return res;
+               }
+
+       case BUZIOC_G_STATUS:
+               {
+                       struct zoran_status bs;
+                       int norm, input, status;
+
+                       if (zr->codec_mode != BUZ_MODE_IDLE) {
+                               return -EINVAL;
+                       }
+                       if (copy_from_user(&bs, arg, sizeof(bs))) {
+                               return -EFAULT;
+                       }
+                       IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n"));
+                       switch (bs.input) {
+                       case 0:
+                               input = 3;
+                               break;
+                       case 1:
+                               input = 7;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+
+                       /* Set video norm to VIDEO_MODE_AUTO */
+
+                       norm = VIDEO_MODE_AUTO;
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
+
+                       /* sleep 1 second */
+
+                       schedule_timeout(HZ);
+                       
+                       /* Get status of video decoder */
+
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status);
+                       bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0;
+                       bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
+                       bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0;
+
+                       /* restore previous input and norm */
+                       input = zr->params.input == 0 ? 3 : 7;
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
+                       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+
+                       if (copy_to_user(arg, &bs, sizeof(bs))) {
+                               return -EFAULT;
+                       }
+                       return 0;
+               }
+
+       default:
+                   return -ENOIOCTLCMD;
+
+       }
+       return 0;
+}
+
+
+/*
+ *   This maps the buffers to user space.
+ *
+ *   Depending on the state of zr->map_mjpeg_buffers
+ *   the V4L or the MJPEG buffers are mapped
+ *
+ */
+
+static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+       struct zoran *zr = (struct zoran *) dev;
+       unsigned long start = (unsigned long) adr;
+       unsigned long page, pos, todo, fraglen;
+       int i, j;
+
+       if (zr->map_mjpeg_buffers) {
+               /* Map the MJPEG buffers */
+
+               if (!zr->jpg_buffers_allocated) {
+                       return -ENOMEM;
+               }
+               if (size > zr->jpg_nbufs * zr->jpg_bufsize) {
+                       return -EINVAL;
+               }
+
+               for (i = 0; i < zr->jpg_nbufs; i++) {
+                       for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
+                               fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1;
+                               todo = size;
+                               if (todo > fraglen)
+                                       todo = fraglen;
+                               pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j];
+                               page = virt_to_phys(bus_to_virt(pos));  /* should just be pos on i386 */
+                               if (remap_page_range(start, page, todo, PAGE_SHARED)) {
+                                       printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name);
+                                       return -EAGAIN;
+                               }
+                               size -= todo;
+                               start += todo;
+                               if (size == 0)
+                                       break;
+                               if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1)
+                                       break;  /* was last fragment */
+                       }
+                       if (size == 0)
+                               break;
+               }
+       } else {
+               /* Map the V4L buffers */
+
+               if (size > v4l_nbufs * v4l_bufsize) {
+                       return -EINVAL;
+               }
+
+               for (i = 0; i < v4l_nbufs; i++) {
+                       todo = size;
+                       if (todo > v4l_bufsize)
+                               todo = v4l_bufsize;
+                       page = zr->v4l_gbuf[i].fbuffer_phys;
+                       DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start));
+                       if (remap_page_range(start, page, todo, PAGE_SHARED)) {
+                               printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name);
+                               return -EAGAIN;
+                       }
+                       size -= todo;
+                       start += todo;
+                       if (size == 0)
+                               break;
+               }
+       }
+       return 0;
+}
+
+static int zoran_init_done(struct video_device *dev)
+{
+       return 0;
+}
+
+static struct video_device zoran_template =
+{
+       BUZ_NAME,
+       VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
+       VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
+       VID_HARDWARE_BT848,     /* Not true, but the buz is not yet in the list */
+       zoran_open,
+       zoran_close,
+       zoran_read,
+       zoran_write,
+       NULL,
+       zoran_ioctl,
+       zoran_mmap,
+       zoran_init_done,
+       NULL,
+       0,
+       0
+};
+
+static int zr36057_init(int i)
+{
+       struct zoran *zr = &zoran[i];
+       unsigned long mem;
+       unsigned mem_needed;
+       int j;
+       int rev;
+
+       /* reset zr36057 */
+       btwrite(0, ZR36057_SPGPPCR);
+       mdelay(10);
+
+       /* default setup of all parameters which will persist beetween opens */
+
+       zr->user = 0;
+       
+       init_waitqueue_head(&zr->v4l_capq);
+       init_waitqueue_head(&zr->jpg_capq);
+
+       zr->map_mjpeg_buffers = 0;      /* Map V4L buffers by default */
+
+       zr->jpg_nbufs = 0;
+       zr->jpg_bufsize = 0;
+       zr->jpg_buffers_allocated = 0;
+
+       zr->buffer_set = 0;     /* Flag if frame buffer has been set */
+       zr->buffer.base = (void *) vidmem;
+       zr->buffer.width = 0;
+       zr->buffer.height = 0;
+       zr->buffer.depth = 0;
+       zr->buffer.bytesperline = 0;
+
+       zr->params.norm = default_norm ? 1 : 0; /* Avoid nonsense settings from user */
+       zr->params.input = default_input ? 1 : 0;       /* Avoid nonsense settings from user */
+       zr->video_interlace = 0;
+
+       /* Should the following be reset at every open ? */
+
+       zr->picture.colour = 32768;
+       zr->picture.brightness = 32768;
+       zr->picture.hue = 32768;
+       zr->picture.contrast = 32768;
+       zr->picture.whiteness = 0;
+       zr->picture.depth = 0;
+       zr->picture.palette = 0;
+
+       for (j = 0; j < VIDEO_MAX_FRAME; j++) {
+               zr->v4l_gbuf[i].fbuffer = 0;
+               zr->v4l_gbuf[i].fbuffer_phys = 0;
+               zr->v4l_gbuf[i].fbuffer_bus = 0;
+       }
+
+       zr->stat_com = 0;
+
+       /* default setup (will be repeated at every open) */
+
+       zoran_open_init_params(zr);
+
+       /* allocate memory *before* doing anything to the hardware in case allocation fails */
+
+       /* STAT_COM table and overlay mask */
+
+       mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4;
+       mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL);
+       if (!mem) {
+               return -ENOMEM;
+       }
+       memset((void *) mem, 0, mem_needed);
+
+       zr->stat_com = (u32 *) mem;
+       for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+               zr->stat_com[j] = 1;    /* mark as unavailable to zr36057 */
+       }
+       zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4);
+
+       /* Initialize zr->jpg_gbuf */
+
+       for (j = 0; j < BUZ_MAX_FRAME; j++) {
+               zr->jpg_gbuf[j].frag_tab = 0;
+               zr->jpg_gbuf[j].frag_tab_bus = 0;
+               zr->jpg_gbuf[j].state = BUZ_STATE_USER;
+               zr->jpg_gbuf[j].bs.frame = j;
+       }
+
+       /* take zr36057 out of reset now */
+       btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
+       mdelay(10);
+
+       /* stop all DMA processes */
+       btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+       btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+       /* assert P_Reset */
+       btwrite(0, ZR36057_JPC);
+
+       switch(zr->board)
+       {
+               case BOARD_BUZ:
+       
+                       /* set up GPIO direction */
+                       btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
+
+                       /* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */
+                       btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1);
+                       mdelay(10);
+
+                       /* reset video decoder */
+
+                       GPIO(zr, 0, 0);
+                       mdelay(10);
+                       GPIO(zr, 0, 1);
+                       mdelay(10);
+
+                       /* reset JPEG codec */
+                       zr36060_sleep(zr, 0);
+                       mdelay(10);
+                       zr36060_reset(zr);
+                       mdelay(10);
+                       zr36060_sleep(zr, 1);
+                       mdelay(10);
+       
+                       /* display codec revision */
+                       if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
+                               printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
+                              zr->name, zr36060_read_8(zr, 0x023));
+                       } else {
+                               printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev);
+                               kfree((void *) zr->stat_com);
+                               return -1;
+                       }
+                       break;
+                       
+               case BOARD_LML33:
+//                     btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR);
+//                     udelay(100);
+//                     btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR);
+//                     udelay(1000);
+
+                       /*
+                        *      Set up the GPIO direction
+                        */
+                       btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR);
+                       /* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */
+                       btwrite(0xFF00F888, ZR36057_GPPGCR1);
+                       mdelay(10);
+                       GPIO(zr, 5, 0);         /* Analog video bypass */
+                       udelay(3000);
+                       GPIO(zr, 0, 0);         /* Reset 819 */
+                       udelay(3000);
+                       GPIO(zr, 0, 1);         /* 819 back */
+                       udelay(3000);
+                       /* reset JPEG codec */
+                       zr36060_sleep(zr, 0);
+                       udelay(3000);
+                       zr36060_reset(zr);
+                       udelay(3000);
+                       zr36060_sleep(zr, 1);
+                       udelay(3000);
+
+                       /* display codec revision */
+                       if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
+                               printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
+                              zr->name, zr36060_read_8(zr, 0x023));
+                       } else {
+                               printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev);
+//                             kfree((void *) zr->stat_com);
+//                             return -1;
+                       }
+                       break;
+       }
+       /* i2c */
+       memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus));
+       sprintf(zr->i2c.name, "zoran%u%u", zr->id);
+       zr->i2c.data = zr;
+       if (i2c_register_bus(&zr->i2c) < 0) {
+               kfree((void *) zr->stat_com);
+               return -1;
+       }
+       /*
+        *   Now add the template and register the device unit.
+        */
+       memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template));
+       sprintf(zr->video_dev.name, "zoran%u", zr->id);
+       if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) {
+               i2c_unregister_bus(&zr->i2c);
+               kfree((void *) zr->stat_com);
+               return -1;
+       }
+       /* toggle JPEG codec sleep to sync PLL */
+       zr36060_sleep(zr, 1);
+       mdelay(10);
+       zr36060_sleep(zr, 0);
+       mdelay(10);
+
+       /* Enable bus-mastering */
+       pci_set_master(zr->pci_dev);
+
+       j = zr->params.input == 0 ? 3 : 7;
+       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j);
+       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+       i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+
+       /* set individual interrupt enables (without GIRQ0)
+          but don't global enable until zoran_open() */
+
+       btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR);
+
+       if(request_irq(zr->pci_dev->irq, zoran_irq,
+              SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0)
+       {
+               printk(KERN_ERR "%s: Can't assign irq.\n", zr->name);
+               video_unregister_device(&zr->video_dev);
+               i2c_unregister_bus(&zr->i2c);
+               kfree((void *) zr->stat_com);
+               return -1;
+       }
+       zr->initialized = 1;
+       return 0;
+}
+
+
+
+static void release_zoran(void)
+{
+       u8 command;
+       int i;
+       struct zoran *zr;
+
+       for (i = 0; i < zoran_num; i++) {
+               zr = &zoran[i];
+
+               if (!zr->initialized)
+                       continue;
+
+               /* unregister i2c_bus */
+               i2c_unregister_bus((&zr->i2c));
+
+               /* disable PCI bus-mastering */
+               pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command);
+               command &= ~PCI_COMMAND_MASTER;
+               pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command);
+
+               /* put chip into reset */
+               btwrite(0, ZR36057_SPGPPCR);
+
+               free_irq(zr->pci_dev->irq, zr);
+
+               /* unmap and free memory */
+
+               kfree((void *) zr->stat_com);
+
+               iounmap(zr->zr36057_mem);
+
+               video_unregister_device(&zr->video_dev);
+       }
+}
+
+/*
+ *   Scan for a Buz card (actually for the PCI controller ZR36057),
+ *   request the irq and map the io memory
+ */
+
+static int find_zr36057(void)
+{
+       unsigned char latency;
+       struct zoran *zr;
+       struct pci_dev *dev = NULL;
+
+       zoran_num = 0;
+
+       while (zoran_num < BUZ_MAX
+              && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
+               zr = &zoran[zoran_num];
+               zr->pci_dev = dev;
+               zr->zr36057_mem = NULL;
+               zr->id = zoran_num;
+               sprintf(zr->name, "zoran%u", zr->id);
+
+               spin_lock_init(&zr->lock);
+
+               zr->zr36057_adr = zr->pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+               pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
+               if (zr->revision < 2) {
+                       printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
+                              zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr);
+               } else {
+                       unsigned short ss_vendor_id, ss_id;
+
+                       pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor_id);
+                       pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_ID, &ss_id);
+                       printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
+                              zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr);
+                       printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n",
+                              zr->name, ss_vendor_id, ss_id);
+                       if(ss_vendor_id==0xFF10 && ss_id == 0xDE41)
+                       {
+                               zr->board = BOARD_LML33;
+                               printk(KERN_INFO "%s: LML33 detected.\n", zr->name);
+                       }
+               }
+
+               zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000);
+
+               /* set PCI latency timer */
+               pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency);
+               if (latency != 48) {
+                       printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency);
+                       latency = 48;
+                       pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency);
+               }
+               zoran_num++;
+       }
+       if (zoran_num == 0)
+               printk(KERN_INFO "zoran: no cards found.\n");
+
+       return zoran_num;
+}
+
+#include "chipsets.h"
+
+static void handle_chipset(void)
+{
+       int index;
+       struct pci_dev *dev = NULL;
+
+       for (index = 0; index < sizeof(black) / sizeof(black[0]); index++) {
+               if ((dev = pci_find_device(black[index].vendor, black[index].device, dev)) != NULL) {
+                       printk(KERN_INFO ": Host bridge: %s, ", black[index].name);
+                       switch (black[index].action) {
+
+                       case TRITON:
+                               printk("enabling Triton support.\n");
+                               triton = 1;
+                               break;
+
+                       case NATOMA:
+                               printk("enabling Natoma workaround.\n");
+                               natoma = 1;
+                               break;
+                       }
+               }
+       }
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+int init_zoran_cards(struct video_init *unused)
+#endif
+{
+       int i;
+
+
+       printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n");
+
+       /* Look for Buz cards */
+
+       if (find_zr36057() <= 0) {
+               return -EIO;
+       }
+       printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num);
+
+       if (zoran_num == 0)
+               return -ENXIO;
+
+       
+       /* check the parameters we have been given, adjust if necessary */
+
+       if (v4l_nbufs < 0)
+               v4l_nbufs = 0;
+       if (v4l_nbufs > VIDEO_MAX_FRAME)
+               v4l_nbufs = VIDEO_MAX_FRAME;
+       /* The user specfies the in KB, we want them in byte (and page aligned) */
+       v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
+       if (v4l_bufsize < 32768)
+               v4l_bufsize = 32768;
+       /* 2 MB is arbitrary but sufficient for the maximum possible images */
+       if (v4l_bufsize > 2048 * 1024)
+               v4l_bufsize = 2048 * 1024;
+
+       printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10);
+
+       /* Use parameter for vidmem or try to find a video card */
+
+       if (vidmem) {
+               printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem);
+       }
+
+       /* check if we have a Triton or Natome chipset */
+
+       handle_chipset();
+
+       /* take care of Natoma chipset and a revision 1 zr36057 */
+
+       for (i = 0; i < zoran_num; i++) {
+               if (natoma && zoran[i].revision <= 1) {
+                       zoran[i].need_contiguous = 1;
+                       printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name);
+               } else {
+                       zoran[i].need_contiguous = 0;
+               }
+       }
+
+       /* initialize the Buzs */
+
+       /* We have to know which ones must be released if an error occurs */
+       for (i = 0; i < zoran_num; i++)
+               zoran[i].initialized = 0;
+
+       for (i = 0; i < zoran_num; i++) {
+               if (zr36057_init(i) < 0) {
+                       release_zoran();
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+       release_zoran();
+}
+
+#endif
diff --git a/drivers/char/buz.h b/drivers/char/buz.h
new file mode 100644 (file)
index 0000000..06b794a
--- /dev/null
@@ -0,0 +1,319 @@
+/* 
+   buz - Iomega Buz driver
+
+   Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+
+   based on
+
+   buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   and
+
+   bttv - Bt848 frame grabber driver
+   Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BUZ_H_
+#define _BUZ_H_
+
+/* The Buz only supports a maximum width of 720, but some V4L
+   applications (e.g. xawtv are more happy with 768).
+   If XAWTV_HACK is defined, we try to fake a device with bigger width */
+
+#define XAWTV_HACK
+
+#ifdef XAWTV_HACK
+#define   BUZ_MAX_WIDTH   768  /* never display more than 768 pixels */
+#else
+#define   BUZ_MAX_WIDTH   720  /* never display more than 720 pixels */
+#endif
+#define   BUZ_MAX_HEIGHT  576  /* never display more than 576 rows */
+#define   BUZ_MIN_WIDTH    32  /* never display less than 32 pixels */
+#define   BUZ_MIN_HEIGHT   24  /* never display less than 24 rows */
+
+struct zoran_requestbuffers {
+       unsigned long count;    /* Number of buffers for MJPEG grabbing */
+       unsigned long size;     /* Size PER BUFFER in bytes */
+};
+
+struct zoran_sync {
+       unsigned long frame;    /* number of buffer that has been free'd */
+       unsigned long length;   /* number of code bytes in buffer (capture only) */
+       unsigned long seq;      /* frame sequence number */
+       struct timeval timestamp;       /* timestamp */
+};
+
+struct zoran_status {
+       int input;              /* Input channel, has to be set prior to BUZIOC_G_STATUS */
+       int signal;             /* Returned: 1 if valid video signal detected */
+       int norm;               /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+       int color;              /* Returned: 1 if color signal detected */
+};
+
+struct zoran_params {
+
+       /* The following parameters can only be queried */
+
+       int major_version;      /* Major version number of driver */
+       int minor_version;      /* Minor version number of driver */
+
+       /* Main control parameters */
+
+       int input;              /* Input channel: 0 = Composite, 1 = S-VHS */
+       int norm;               /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+       int decimation;         /* decimation of captured video,
+                                  enlargement of video played back.
+                                  Valid values are 1, 2, 4 or 0.
+                                  0 is a special value where the user
+                                  has full control over video scaling */
+
+       /* The following parameters only have to be set if decimation==0,
+          for other values of decimation they provide the data how the image is captured */
+
+       int HorDcm;             /* Horizontal decimation: 1, 2 or 4 */
+       int VerDcm;             /* Vertical decimation: 1 or 2 */
+       int TmpDcm;             /* Temporal decimation: 1 or 2,
+                                  if TmpDcm==2 in capture every second frame is dropped,
+                                  in playback every frame is played twice */
+       int field_per_buff;     /* Number of fields per buffer: 1 or 2 */
+       int img_x;              /* start of image in x direction */
+       int img_y;              /* start of image in y direction */
+       int img_width;          /* image width BEFORE decimation,
+                                  must be a multiple of HorDcm*16 */
+       int img_height;         /* image height BEFORE decimation,
+                                  must be a multiple of VerDcm*8 */
+
+       /* --- End of parameters for decimation==0 only --- */
+
+       /* JPEG control parameters */
+
+       int quality;            /* Measure for quality of compressed images.
+                                  Scales linearly with the size of the compressed images.
+                                  Must be beetween 0 and 100, 100 is a compression
+                                  ratio of 1:4 */
+
+       int odd_even;           /* Which field should come first ??? */
+
+       int APPn;               /* Number of APP segment to be written, must be 0..15 */
+       int APP_len;            /* Length of data in JPEG APPn segment */
+       char APP_data[60];      /* Data in the JPEG APPn segment. */
+
+       int COM_len;            /* Length of data in JPEG COM segment */
+       char COM_data[60];      /* Data in JPEG COM segment */
+
+       unsigned long jpeg_markers;     /* Which markers should go into the JPEG output.
+                                          Unless you exactly know what you do, leave them untouched.
+                                          Inluding less markers will make the resulting code
+                                          smaller, but there will be fewer aplications
+                                          which can read it.
+                                          The presence of the APP and COM marker is
+                                          influenced by APP0_len and COM_len ONLY! */
+#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */
+#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */
+#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */
+#define JPEG_MARKER_COM (1<<6) /* Comment segment */
+#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */
+
+       int VFIFO_FB;           /* Flag for enabling Video Fifo Feedback.
+                                  If this flag is turned on and JPEG decompressing
+                                  is going to the screen, the decompress process
+                                  is stopped every time the Video Fifo is full.
+                                  This enables a smooth decompress to the screen
+                                  but the video output signal will get scrambled */
+
+       /* Misc */
+
+       char reserved[312];     /* Makes 512 bytes for this structure */
+};
+
+/*
+   Private IOCTL to set up for displaying MJPEG
+ */
+#define BUZIOC_G_PARAMS       _IOR ('v', BASE_VIDIOCPRIVATE+0,  struct zoran_params)
+#define BUZIOC_S_PARAMS       _IOWR('v', BASE_VIDIOCPRIVATE+1,  struct zoran_params)
+#define BUZIOC_REQBUFS        _IOWR('v', BASE_VIDIOCPRIVATE+2,  struct zoran_requestbuffers)
+#define BUZIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOCPRIVATE+3,  int)
+#define BUZIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOCPRIVATE+4,  int)
+#define BUZIOC_SYNC           _IOR ('v', BASE_VIDIOCPRIVATE+5,  struct zoran_sync)
+#define BUZIOC_G_STATUS       _IOWR('v', BASE_VIDIOCPRIVATE+6,  struct zoran_status)
+
+
+#ifdef __KERNEL__
+
+#define BUZ_NUM_STAT_COM    4
+#define BUZ_MASK_STAT_COM   3
+
+#define BUZ_MAX_FRAME     256  /* Must be a power of 2 */
+#define BUZ_MASK_FRAME    255  /* Must be BUZ_MAX_FRAME-1 */
+
+#if VIDEO_MAX_FRAME <= 32
+#define   V4L_MAX_FRAME   32
+#elif VIDEO_MAX_FRAME <= 64
+#define   V4L_MAX_FRAME   64
+#else
+#error   "Too many video frame buffers to handle"
+#endif
+#define   V4L_MASK_FRAME   (V4L_MAX_FRAME - 1)
+
+
+#include "zr36057.h"
+
+enum zoran_codec_mode {
+       BUZ_MODE_IDLE,          /* nothing going on */
+       BUZ_MODE_MOTION_COMPRESS,       /* grabbing frames */
+       BUZ_MODE_MOTION_DECOMPRESS,     /* playing frames */
+       BUZ_MODE_STILL_COMPRESS,        /* still frame conversion */
+       BUZ_MODE_STILL_DECOMPRESS       /* still frame conversion */
+};
+
+enum zoran_buffer_state {
+       BUZ_STATE_USER,         /* buffer is owned by application */
+       BUZ_STATE_PEND,         /* buffer is queued in pend[] ready to feed to I/O */
+       BUZ_STATE_DMA,          /* buffer is queued in dma[] for I/O */
+       BUZ_STATE_DONE          /* buffer is ready to return to application */
+};
+
+struct zoran_gbuffer {
+       u32 *frag_tab;          /* addresses of frag table */
+       u32 frag_tab_bus;       /* same value cached to save time in ISR */
+       enum zoran_buffer_state state;  /* non-zero if corresponding buffer is in use in grab queue */
+       struct zoran_sync bs;   /* DONE: info to return to application */
+};
+
+struct v4l_gbuffer {
+       char *fbuffer;          /* virtual  address of frame buffer */
+       unsigned long fbuffer_phys;     /* physical address of frame buffer */
+       unsigned long fbuffer_bus;      /* bus      address of frame buffer */
+       enum zoran_buffer_state state;  /* state: unused/pending/done */
+};
+
+struct zoran {
+       struct video_device video_dev;
+       struct i2c_bus i2c;
+
+       int initialized;        /* flag if zoran has been correctly initalized */
+       int user;               /* number of current users (0 or 1) */
+
+       unsigned short id;      /* number of this device */
+       char name[32];          /* name of this device */
+       struct pci_dev *pci_dev;        /* PCI device */
+       unsigned char revision;         /* revision of zr36057 */
+       int board;                      /* Board type */
+#define BOARD_BUZ              0
+#define BOARD_LML33            1       
+       unsigned int zr36057_adr;       /* bus address of IO mem returned by PCI BIOS */
+       unsigned char *zr36057_mem;     /* pointer to mapped IO memory */
+
+       int map_mjpeg_buffers;  /* Flag which bufferset will map by next mmap() */
+
+       spinlock_t lock;        /* Spinlock */
+
+       /* Video for Linux parameters */
+
+       struct video_picture picture;   /* Current picture params */
+       struct video_buffer buffer;     /* Current buffer params */
+       struct video_window window;     /* Current window params */
+       int buffer_set, window_set;     /* Flags if the above structures are set */
+       int video_interlace;    /* Image on screen is interlaced */
+
+       u32 *overlay_mask;
+
+       wait_queue_head_t v4l_capq;     /* wait here for grab to finish */
+
+       int v4l_overlay_active; /* Overlay grab is activated */
+       int v4l_memgrab_active; /* Memory grab is activated */
+
+       int v4l_grab_frame;     /* Frame number being currently grabbed */
+#define NO_GRAB_ACTIVE (-1)
+       int v4l_grab_seq;       /* Number of frames grabbed */
+       int gwidth;             /* Width of current memory capture */
+       int gheight;            /* Height of current memory capture */
+       int gformat;            /* Format of ... */
+       int gbpl;               /* byte per line of ... */
+
+       /* V4L grab queue of frames pending */
+
+       unsigned v4l_pend_head;
+       unsigned v4l_pend_tail;
+       int v4l_pend[V4L_MAX_FRAME];
+
+       struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME];   /* V4L   buffers' info */
+
+       /* Buz MJPEG parameters */
+
+       unsigned long jpg_nbufs;        /* Number of buffers */
+       unsigned long jpg_bufsize;      /* Size of mjpeg buffers in bytes */
+       int jpg_buffers_allocated;      /* Flag if buffers are allocated  */
+       int need_contiguous;    /* Flag if contiguous buffers are needed */
+
+       enum zoran_codec_mode codec_mode;               /* status of codec */
+       struct zoran_params params;     /* structure with a lot of things to play with */
+
+       wait_queue_head_t  jpg_capq;    /* wait here for grab to finish */
+
+       /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */
+       /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */
+       /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */
+       unsigned long jpg_que_head;     /* Index where to put next buffer which is queued */
+       unsigned long jpg_dma_head;     /* Index of next buffer which goes into stat_com  */
+       unsigned long jpg_dma_tail;     /* Index of last buffer in stat_com               */
+       unsigned long jpg_que_tail;     /* Index of last buffer in queue                  */
+       unsigned long jpg_seq_num;      /* count of frames since grab/play started */
+
+       /* zr36057's code buffer table */
+       u32 *stat_com;          /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+
+       /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
+       int jpg_pend[BUZ_MAX_FRAME];
+
+       /* array indexed by frame number */
+       struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME];   /* MJPEG buffers' info */
+};
+
+#endif
+
+/*The following should be done in more portable way. It depends on define
+   of _ALPHA_BUZ in the Makefile. */
+
+#ifdef _ALPHA_BUZ
+#define btwrite(dat,adr)    writel((dat),(char *) (zr->zr36057_adr+(adr)))
+#define btread(adr)         readl(zr->zr36057_adr+(adr))
+#else
+#define btwrite(dat,adr)    writel((dat), (char *) (zr->zr36057_mem+(adr)))
+#define btread(adr)         readl(zr->zr36057_mem+(adr))
+#endif
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+#define I2C_TSA5522        0xc2
+#define I2C_TDA9850        0xb6
+#define I2C_HAUPEE         0xa0
+#define I2C_STBEE          0xae
+#define   I2C_SAA7111        0x48
+#define   I2C_SAA7185        0x88
+
+#define TDA9850_CON1       0x04
+#define TDA9850_CON2       0x05
+#define TDA9850_CON3       0x06
+#define TDA9850_CON4       0x07
+#define TDA9850_ALI1       0x08
+#define TDA9850_ALI2       0x09
+#define TDA9850_ALI3       0x0a
+
+#endif
index 87821edf896f87db53c1a6b13fc08f8f994eabe3..29cdac314819f6b52144781ee4dee625f2cae31c 100644 (file)
@@ -159,6 +159,8 @@ static struct qcam_device *qcam_init(struct parport *port)
        struct qcam_device *q;
        
        q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
+       if(q==NULL)
+               return NULL;
 
        q->pport = port;
        q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
@@ -1045,7 +1047,7 @@ void cleanup_module(void)
                close_bwqcam(qcams[i]);
 }
 #else
-__initfunc(int init_bw_qcams(struct video_init *unused))
+int __init init_bw_qcams(struct video_init *unused)
 {
        struct parport *port;
 
index 41586b58f1321e8cb3d42e2d16d5a3cfa98a633c..3c7cc317a0993b0153c6fa03d9044e10bb66da33 100644 (file)
@@ -641,6 +641,8 @@ static struct qcam_device *qcam_init(struct parport *port)
        struct qcam_device *q;
        
        q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
+       if(q==NULL)
+               return NULL;
 
        q->pport = port;
        q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
@@ -765,7 +767,7 @@ void cleanup_module(void)
                close_cqcam(qcams[i]);
 }
 #else
-__initfunc(int init_colour_qcams(struct video_init *unused))
+int __init init_colour_qcams(struct video_init *unused)
 {
        cqcam_init();
        return 0;
diff --git a/drivers/char/chipsets.h b/drivers/char/chipsets.h
new file mode 100644 (file)
index 0000000..80c9525
--- /dev/null
@@ -0,0 +1,41 @@
+static const struct {
+       unsigned short vendor;
+       unsigned short device;
+       enum {
+               TRITON,
+               NATOMA
+       } action;
+       const char *name;
+} black[] = {
+
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, TRITON, "82437"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, TRITON, "82437VX Triton II"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, TRITON, "82439HX Triton II"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, TRITON, "82439TX"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, NATOMA, "82441FX Natoma"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, NATOMA, "440LX - 82443LX PAC Host"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, NATOMA, "440LX - 82443LX PAC AGP"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, NATOMA, "440BX - 82443BX Host"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, NATOMA, "440BX - 82443BX AGP"
+       },
+       {
+               PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, NATOMA, "440BX - 82443BX Host (no AGP)"
+       },
+};
index 3bfb89ff952caaedd73044461a27664f01e82c75..c63403415ebfaa2db58450015220a7ccc7973c8b 100644 (file)
@@ -16,6 +16,8 @@
  *            field from "current" - somewhere between 2.1.121 and 2.1.131
  */
 
+#define DEBUG_DZ 1
+
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
 /* for definition of struct console */
 #ifdef CONFIG_SERIAL_CONSOLE
 #define CONSOLE_LINE (3)
-#include <linux/console.h>
 #endif /* ifdef CONFIG_SERIAL_CONSOLE */
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ)
+#include <linux/console.h>
+#endif /* if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) */
 
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <asm/dec/kn01.h>
 #include <asm/dec/kn02.h>
 
-#define DEBUG_DZ 1
 #ifdef DEBUG_DZ
-#include <linux/tty.h>
-#include <linux/major.h>
 #include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/console.h>
 #include <linux/fs.h>
 #include <asm/bootinfo.h>
 
index 6af834fce503f9dee9a525a2e005df7afa9d260b..3d2980e4f83163dc0ad00cc59f712c3f4331b39f 100644 (file)
@@ -62,7 +62,6 @@
 #if LINUX_VERSION_CODE >= 0x20100
 #include <asm/uaccess.h>
 #else
-#include <asm/segment.h>
 #include <linux/mm.h>
 
 #undef put_user
index c85b95bc3a1adf413792af3ae2df5b2bf7a1c0fa..452583f86441053f65553ffa48fb96c5a40b4123 100644 (file)
@@ -40,6 +40,14 @@ static int bus_count = 0, driver_count = 0;
 extern int i2c_tuner_init(void);
 extern int msp3400c_init(void);
 #endif
+#ifdef CONFIG_VIDEO_BUZ
+extern int saa7111_init(void);
+extern int saa7185_init(void);
+#endif
+#ifdef CONFIG_VIDEO_LML33
+extern int bt819_init(void);
+extern int bt856_init(void);
+#endif
 
 int i2c_init(void)
 {
@@ -50,6 +58,14 @@ int i2c_init(void)
        i2c_tuner_init();
        msp3400c_init();
 #endif 
+#ifdef CONFIG_VIDEO_BUZ
+       saa7111_init();
+       saa7185_init();
+#endif
+#ifdef CONFIG_VIDEO_LML33
+       bt819_init();
+       bt856_init();
+#endif
        return 0;
 }
 
index 45f2a289b45e70aa738dfccb6be38e1fb803ebfc..e4fc30403f0df5e19c279e0aaafd41cc5f1fc499 100644 (file)
@@ -28,7 +28,6 @@
 #endif
 #ifdef CONFIG_ATARI
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
 #endif
index 0dc5a7cca7e41e2a6e736a95e3ffce47749cf607..7251a4e05098bc6349ef45b4300ccfe65097ceb6 100644 (file)
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>       /* to get the struct task_struct */
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
 #include <asm/system.h>
index 2a0a561e795cbacf131eed6e5813d7087fe6dedb..fc570b8861172ca82233a92bff905a381e8eda9b 100644 (file)
@@ -38,7 +38,6 @@
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/irq.h>
 
 /* Some configuration switches are present in the include file... */
 
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
new file mode 100644 (file)
index 0000000..881e521
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * linux/drivers/char/ppdev.c
+ *
+ * This is the code behind /dev/parport* -- it allows a user-space
+ * application to use the parport subsystem.
+ *
+ * Copyright (C) 1998-9 Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * A /dev/parportxy device node represents an arbitrary device ('y')
+ * on port 'x'.  The following operations are possible:
+ *
+ * open                do nothing, set up default IEEE 1284 protocol to be COMPAT
+ * close       release port and unregister device (if necessary)
+ * ioctl
+ *   EXCL      register device exclusively (may fail)
+ *   CLAIM     (register device first time) parport_claim_or_block
+ *   RELEASE   parport_release
+ *   SETMODE   set the IEEE 1284 protocol to use for read/write
+ *   DATADIR   data_forward / data_reverse
+ *   WDATA     write_data
+ *   RDATA     read_data
+ *   WCONTROL  write_control
+ *   RCONTROL  read_control
+ *   FCONTROL  frob_control
+ *   RSTATUS   read_status
+ *   NEGOT     parport_negotiate
+ *   YIELD     parport_yield_blocking
+ * read/write  read or write in current IEEE 1284 protocol
+ * select      wait for interrupt (in readfds)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include "ppdev.h"
+
+#define PP_VERSION "ppdev: user-space parallel port driver"
+#define CHRDEV "ppdev"
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* The device minor encodes the parport number and (arbitrary) 
+ * pardevice number as (port << 4) | dev. */
+#define PP_PORT(minor) ((minor >> 4) & 0xf)
+#define PP_DEV(minor) ((minor) & 0xf)
+
+struct pp_struct {
+       struct pardevice * pdev;
+       wait_queue_head_t irq_wait;
+       int mode;
+       unsigned int flags;
+};
+
+/* pp_struct.flags bitfields */
+#define PP_CLAIMED    (1<<0)
+#define PP_EXCL       (1<<1)
+
+/* Other constants */
+#define PP_INTERRUPT_TIMEOUT (10 * HZ) /* 10s */
+#define PP_BUFFER_SIZE 256
+#define PARDEVICE_MAX 8
+
+static struct pp_struct pp_table[PARPORT_MAX][PARDEVICE_MAX];
+
+static loff_t pp_lseek (struct file * file, long long offset, int origin)
+{
+       return -ESPIPE;
+}
+
+/* This looks a bit like parport_read.  The difference is that we don't
+ * determine the mode to use from the port data, but rather from the
+ * mode the driver told us to use. */
+static ssize_t do_read (struct pp_struct *pp, void *buf, size_t len)
+{
+       size_t (*fn) (struct parport *, void *, size_t, int);
+       struct parport *port = pp->pdev->port;
+
+       switch (pp->mode) {
+       case IEEE1284_MODE_COMPAT:
+               /* This is a write-only mode. */
+               return -EIO;
+
+       case IEEE1284_MODE_NIBBLE:
+               fn = port->ops->nibble_read_data;
+               break;
+
+       case IEEE1284_MODE_BYTE:
+               fn = port->ops->byte_read_data;
+               break;
+
+       case IEEE1284_MODE_EPP:
+               fn = port->ops->epp_read_data;
+               break;
+
+       case IEEE1284_MODE_ECP:
+       case IEEE1284_MODE_ECPRLE:
+               fn = port->ops->ecp_read_data;
+               break;
+
+       case IEEE1284_MODE_ECPSWE:
+               fn = parport_ieee1284_ecp_read_data;
+               break;
+
+       default:
+               printk (KERN_DEBUG "%s: unknown mode 0x%02x\n",
+                       pp->pdev->name, pp->mode);
+               return -EINVAL;
+       }
+
+       return (*fn) (port, buf, len, 0);
+}
+
+/* This looks a bit like parport_write.  The difference is that we don't
+ * determine the mode to use from the port data, but rather from the
+ * mode the driver told us to use. */
+static ssize_t do_write (struct pp_struct *pp, const void *buf, size_t len)
+{
+       size_t (*fn) (struct parport *, const void *, size_t, int);
+       struct parport *port = pp->pdev->port;
+
+       switch (pp->mode) {
+       case IEEE1284_MODE_NIBBLE:
+       case IEEE1284_MODE_BYTE:
+               /* Read-only modes. */
+               return -EIO;
+
+       case IEEE1284_MODE_COMPAT:
+               fn = port->ops->compat_write_data;
+               break;
+
+       case IEEE1284_MODE_EPP:
+               fn = port->ops->epp_write_data;
+               break;
+
+       case IEEE1284_MODE_ECP:
+       case IEEE1284_MODE_ECPRLE:
+               fn = port->ops->ecp_write_data;
+               break;
+
+       case IEEE1284_MODE_ECPSWE:
+               fn = parport_ieee1284_ecp_write_data;
+               break;
+
+       default:
+               printk (KERN_DEBUG "%s: unknown mode 0x%02x\n",
+                       pp->pdev->name, pp->mode);
+               return -EINVAL;
+       }
+
+       return (*fn) (port, buf, len, 0);
+}
+
+static ssize_t pp_read (struct file * file, char * buf, size_t count,
+                       loff_t * ppos)
+{
+       unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+       unsigned int portnum = PP_PORT (minor);
+       unsigned int dev = PP_DEV (minor);
+       char * kbuffer;
+       ssize_t bytes_read = 0;
+       ssize_t got = 0;
+
+       if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+               /* Don't have the port claimed */
+               printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+                       minor);
+               return -EPERM;
+       }
+
+       kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
+       if (!kbuffer)
+               return -ENOMEM;
+
+       while (bytes_read < count) {
+               ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE);
+
+               got = do_read (&pp_table[portnum][dev], kbuffer, need);
+
+               if (got < 0) {
+                       if (!bytes_read)
+                               bytes_read = got;
+
+                       break;
+               }
+
+               if (copy_to_user (kbuffer, buf + bytes_read, got)) {
+                       bytes_read = -EFAULT;
+                       break;
+               }
+
+               bytes_read += got;
+
+               if (signal_pending (current)) {
+                       if (!bytes_read)
+                               bytes_read = -EINTR;
+                       break;
+               }
+
+               if (current->need_resched)
+                       schedule ();
+       }
+
+       kfree (kbuffer);
+       return bytes_read;
+}
+
+static ssize_t pp_write (struct file * file, const char * buf, size_t count,
+                        loff_t * ppos)
+{
+       unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+       unsigned int portnum = PP_PORT (minor);
+       unsigned int dev = PP_DEV (minor);
+       char * kbuffer;
+       ssize_t bytes_written = 0;
+       ssize_t wrote;
+
+       if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+               /* Don't have the port claimed */
+               printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+                       minor);
+               return -EPERM;
+       }
+
+       kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
+       if (!kbuffer)
+               return -ENOMEM;
+
+       while (bytes_written < count) {
+               ssize_t n = min(count - bytes_written, PP_BUFFER_SIZE);
+
+               if (copy_from_user (kbuffer, buf + bytes_written, n)) {
+                       bytes_written = -EFAULT;
+                       break;
+               }
+
+               wrote = do_write (&pp_table[portnum][dev], kbuffer, n);
+
+               if (wrote < 0) {
+                       if (!bytes_written)
+                               bytes_written = wrote;
+                       break;
+               }
+
+               bytes_written += wrote;
+
+               if (signal_pending (current)) {
+                       if (!bytes_written)
+                               bytes_written = -EINTR;
+                       break;
+               }
+
+               if (current->need_resched)
+                       schedule ();
+       }
+
+       kfree (kbuffer);
+       return bytes_written;
+}
+
+static void pp_irq (int irq, void * private, struct pt_regs * unused)
+{
+       struct pp_struct * pp = (struct pp_struct *) private;
+       wake_up_interruptible (&pp->irq_wait);
+}
+
+static int register_device (int minor)
+{
+       unsigned int portnum = PP_PORT (minor);
+       unsigned int dev = PP_DEV (minor);
+       struct parport * port;
+       struct pardevice * pdev = NULL;
+       char *name;
+       int fl;
+
+       name = kmalloc (strlen (CHRDEV) + 3, GFP_KERNEL);
+       if (name == NULL)
+               return -ENOMEM;
+
+       sprintf (name, CHRDEV "%02x", minor);
+       port = parport_enumerate (); /* FIXME: use attach/detach */
+
+       while (port && port->number != portnum)
+               port = port->next;
+
+       if (!port) {
+               printk (KERN_WARNING "%s: no associated port!\n", name);
+               kfree (name);
+               return -ENXIO;
+       }
+
+       fl = (pp_table[portnum][dev].flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+       pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl,
+                                       &pp_table[portnum][dev]);
+
+       if (!pdev) {
+               printk (KERN_WARNING "%s: failed to register device!\n", name);
+               kfree (name);
+               return -ENXIO;
+       }
+
+       pp_table[portnum][dev].pdev = pdev;
+       printk (KERN_DEBUG "%s: registered pardevice\n", name);
+       return 0;
+}
+
+static int pp_ioctl(struct inode *inode, struct file *file,
+                   unsigned int cmd, unsigned long arg)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       unsigned int portnum = PP_PORT (minor);
+       unsigned int dev = PP_DEV (minor);
+       struct parport * port;
+
+       /* First handle the cases that don't take arguments. */
+       if (cmd == PPCLAIM) {
+               if (pp_table[portnum][dev].flags & PP_CLAIMED) {
+                       printk (KERN_DEBUG CHRDEV
+                               "%02x: you've already got it!\n", minor);
+                       return -EINVAL;
+               }
+
+               /* Deferred device registration. */
+               if (!pp_table[portnum][dev].pdev) {
+                       int err = register_device (minor);
+                       if (err)
+                               return err;
+               }
+
+               parport_claim_or_block (pp_table[portnum][dev].pdev);
+               pp_table[portnum][dev].flags |= PP_CLAIMED;
+               return 0;
+       }
+
+       port = pp_table[portnum][dev].pdev->port;
+       if (cmd == PPEXCL) {
+               if (pp_table[portnum][dev].pdev) {
+                       printk (KERN_DEBUG CHRDEV "%02x: too late for PPEXCL; "
+                               "already registered\n", minor);
+                       if (pp_table[portnum][dev].flags & PP_EXCL)
+                               /* But it's not really an error. */
+                               return 0;
+                       /* There's no chance of making the driver happy. */
+                       return -EINVAL;
+               }
+
+               /* Just remember to register the device exclusively
+                * when we finally do the registration. */
+               pp_table[portnum][dev].flags |= PP_EXCL;
+               return 0;
+       }
+
+       /* Everything else requires the port to be claimed, so check
+        * that now. */
+       if ((pp_table[portnum][dev].flags & PP_CLAIMED) == 0) {
+               printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+                       minor);
+               return -EPERM;
+       }
+
+       switch (cmd) {
+               unsigned char reg;
+               unsigned char mask;
+               int mode;
+
+       case PPRSTATUS:
+               reg = parport_read_status (port);
+               return copy_to_user ((unsigned char *) arg, &reg,
+                                    sizeof (reg));
+
+       case PPRDATA:
+               reg = parport_read_data (port);
+               return copy_to_user ((unsigned char *) arg, &reg,
+                                    sizeof (reg));
+
+       case PPRCONTROL:
+               reg = parport_read_control (port);
+               return copy_to_user ((unsigned char *) arg, &reg,
+                                    sizeof (reg));
+
+       case PPYIELD:
+               parport_yield_blocking (pp_table[portnum][dev].pdev);
+               return 0;
+
+       case PPRELEASE:
+               parport_release (pp_table[portnum][dev].pdev);
+               pp_table[portnum][dev].flags &= ~PP_CLAIMED;
+               return 0;
+
+       case PPSETMODE:
+               if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+                       return -EFAULT;
+               /* FIXME: validate mode */
+               pp_table[portnum][dev].mode = mode;
+               return 0;
+
+       case PPWCONTROL:
+               if (copy_from_user (&reg, (unsigned char *) arg, sizeof (reg)))
+                       return -EFAULT;
+               parport_write_control (port, reg);
+               return 0;
+
+       case PPWDATA:
+               if (copy_from_user (&reg, (unsigned char *) arg, sizeof (reg)))
+                       return -EFAULT;
+               parport_write_data (port, reg);
+               return 0;
+
+       case PPFCONTROL:
+               if (copy_from_user (&mask, (unsigned char *) arg,
+                                   sizeof (mask)))
+                       return -EFAULT;
+               if (copy_from_user (&reg, 1 + (unsigned char *) arg,
+                                   sizeof (reg)))
+                       return -EFAULT;
+               parport_frob_control (port, mask, reg);
+               return 0;
+
+       case PPDATADIR:
+               if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+                       return -EFAULT;
+               if (mode)
+                       port->ops->data_reverse (port);
+               else
+                       port->ops->data_forward (port);
+               return 0;
+
+       case PPNEGOT:
+               if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+                       return -EFAULT;
+               /* FIXME: validate mode */
+               return parport_negotiate (port, mode);
+
+       default:
+               printk (KERN_DEBUG CHRDEV "%02x: What? (cmd=0x%x\n", minor,
+                       cmd);
+               return -EINVAL;
+       }
+
+       /* Keep the compiler happy */
+       return 0;
+}
+
+static int pp_open (struct inode * inode, struct file * file)
+{
+       unsigned int minor = MINOR (inode->i_rdev);
+       unsigned int portnum = PP_PORT (minor);
+       unsigned int dev = PP_DEV (minor);
+
+       if (portnum >= PARPORT_MAX)
+               return -ENXIO;
+
+       if (pp_table[portnum][dev].pdev)
+               return -EBUSY;
+
+       pp_table[portnum][dev].mode = IEEE1284_MODE_COMPAT;
+       pp_table[portnum][dev].flags = 0;
+       init_waitqueue_head (&pp_table[portnum][dev].irq_wait);
+
+       /* Defer the actual device registration until the first claim.
+        * That way, we know whether or not the driver wants to have
+        * exclusive access to the port (PPEXCL).
+        */
+       pp_table[portnum][dev].pdev = NULL;
+
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static int pp_release (struct inode * inode, struct file * file)
+{
+       unsigned int minor = MINOR (inode->i_rdev);
+       unsigned int portnum = PP_PORT (minor);
+       unsigned int dev = PP_DEV (minor);
+
+       if (pp_table[portnum][dev].flags & PP_CLAIMED) {
+               parport_release (pp_table[portnum][dev].pdev);
+               printk (KERN_DEBUG CHRDEV "%02x: released pardevice because "
+                       "user-space forgot\n", minor);
+       }
+
+       if (pp_table[portnum][dev].pdev) {
+               kfree (pp_table[portnum][dev].pdev->name);
+               parport_unregister_device (pp_table[portnum][dev].pdev);
+               pp_table[portnum][dev].pdev = NULL;
+               printk (KERN_DEBUG CHRDEV "%02x: unregistered pardevice\n",
+                       minor);
+       }
+
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+#if 0
+static unsigned int pp_poll (struct file * file, poll_table * wait)
+{
+       unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+       poll_wait (file, &pp_table[minor].irq_wait, wait);
+       return 0; /* FIXME! Return value is wrong here */
+}
+#endif
+
+static struct file_operations pp_fops = {
+       pp_lseek,
+       pp_read,
+       pp_write,
+       NULL,   /* pp_readdir */
+       NULL,   /* pp_poll */
+       pp_ioctl,
+       NULL,   /* pp_mmap */
+       pp_open,
+       NULL,   /* pp_flush */
+       pp_release
+};
+
+#ifdef MODULE
+#define pp_init init_module
+#endif
+
+int pp_init (void)
+{
+       if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
+               printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
+                       PP_MAJOR);
+               return -EIO;
+       }
+
+       printk (KERN_INFO PP_VERSION "\n");
+       return 0;
+}
+
+#ifdef MODULE
+void cleanup_module (void)
+{
+       /* Clean up all parport stuff */
+       unregister_chrdev (PP_MAJOR, CHRDEV);
+}
+#endif /* MODULE */
diff --git a/drivers/char/ppdev.h b/drivers/char/ppdev.h
new file mode 100644 (file)
index 0000000..f52d3c7
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * linux/drivers/char/ppdev.h
+ *
+ * User-space parallel port device driver (header file).
+ *
+ * Copyright (C) 1998-9 Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#define PP_MAJOR       99
+
+#define PP_IOCTL       'p'
+
+/* Set mode for read/write (e.g. IEEE1284_MODE_EPP) */
+#define PPSETMODE      _IOW(PP_IOCTL, 0x80, int)
+
+/* Read status */
+#define PPRSTATUS      _IOR(PP_IOCTL, 0x81, unsigned char)
+#define PPWSTATUS      OBSOLETE__IOW(PP_IOCTL, 0x82, unsigned char)
+
+/* Read/write control */
+#define PPRCONTROL     _IOR(PP_IOCTL, 0x83, unsigned char)
+#define PPWCONTROL     _IOW(PP_IOCTL, 0x84, unsigned char)
+
+struct ppdev_frob_struct {
+       unsigned char mask;
+       unsigned char val;
+};
+#define PPFCONTROL      _IOW(PP_IOCTL, 0x8e, struct ppdev_frob_struct)
+
+/* Read/write data */
+#define PPRDATA                _IOR(PP_IOCTL, 0x85, unsigned char)
+#define PPWDATA                _IOW(PP_IOCTL, 0x86, unsigned char)
+
+/* Read/write econtrol (not used) */
+#define PPRECONTROL    OBSOLETE__IOR(PP_IOCTL, 0x87, unsigned char)
+#define PPWECONTROL    OBSOLETE__IOW(PP_IOCTL, 0x88, unsigned char)
+
+/* Read/write FIFO (not used) */
+#define PPRFIFO                OBSOLETE__IOR(PP_IOCTL, 0x89, unsigned char)
+#define PPWFIFO                OBSOLETE__IOW(PP_IOCTL, 0x8a, unsigned char)
+
+/* Claim the port to start using it */
+#define PPCLAIM                _IO(PP_IOCTL, 0x8b)
+
+/* Release the port when you aren't using it */
+#define PPRELEASE      _IO(PP_IOCTL, 0x8c)
+
+/* Yield the port (release it if another driver is waiting,
+ * then reclaim) */
+#define PPYIELD                _IO(PP_IOCTL, 0x8d)
+
+/* Register device exclusively (must be before PPCLAIM). */
+#define PPEXCL         _IO(PP_IOCTL, 0x8f)
+
+/* Data line direction: non-zero for input mode. */
+#define PPDATADIR      _IOW(PP_IOCTL, 0x90, int)
+
+/* Negotiate a particular IEEE 1284 mode. */
+#define PPNEGOT                _IOW(PP_IOCTL, 0x91, int)
index 99c1b92bcaf3975d7d03ee97ccdeef9713c9ada9..fc3101f347307b20ed48ab8b4dfde50ca93db001 100644 (file)
@@ -324,7 +324,7 @@ static struct video_device rtrack_radio=
        NULL
 };
 
-__initfunc(int rtrack_init(struct video_init *v))
+int __init rtrack_init(struct video_init *v)
 {
        if (check_region(io, 2)) 
        {
index e21adc44a1ba0062b384807a908e27e34bc743c0..1c26bba933d186aa10266b963f96ed3f45999a27 100644 (file)
@@ -279,7 +279,7 @@ static struct video_device aztech_radio=
        NULL
 };
 
-__initfunc(int aztech_init(struct video_init *v))
+int __init aztech_init(struct video_init *v)
 {
        if (check_region(io, 2)) 
        {
index cfca71f7f784ec5ca6c9fb3d0b5039bbbb5ddfc6..239a611b227729ea7dab0a03bd880cfb7f332260 100644 (file)
@@ -1,7 +1,7 @@
-/* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card 
+/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card 
  *
  * by Fred Gleason <fredg@wava.com>
- * Version 0.3.2
+ * Version 0.3.3
  *
  * (Loosely) based on code for the Aztech radio card by
  *
@@ -346,17 +346,13 @@ void cadet_handler(unsigned long data)
 static long cadet_read(struct video_device *v,char *buf,unsigned long count,
                       int nonblock)
 {
-        int i=0,c;
+        int i=0;
        unsigned char readbuf[RDS_BUFFER];
 
         if(rdsstat==0) {
                cadet_lock++;
                rdsstat=1;
                outb(0x80,io);        /* Select RDS fifo */
-               c=3*(inb(io)&0x03);
-               for(i=0;i<c;i++) {    /* Flush the fifo */
-                       inb(io+1);
-               }
                cadet_lock--;
                init_timer(&readtimer);
                readtimer.function=cadet_handler;
@@ -546,7 +542,7 @@ static struct video_device cadet_radio=
        NULL
 };
 
-__initfunc(int cadet_init(struct video_init *v))
+int __init cadet_init(struct video_init *v)
 {
 #ifndef MODULE        
         if(cadet_probe()<0) {
index 46d41f423912736aeeaf7837119da3a550db911a..9cee2342e3fd8568474947f8cb971a37b1720651 100644 (file)
@@ -250,7 +250,7 @@ static struct video_device gemtek_radio=
        NULL
 };
 
-__initfunc(int gemtek_init(struct video_init *v))
+int __init gemtek_init(struct video_init *v)
 {
        if (check_region(io, 4)) 
        {
@@ -282,7 +282,7 @@ __initfunc(int gemtek_init(struct video_init *v))
 MODULE_AUTHOR("Jonas Munsin");
 MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
 MODULE_PARM(io, "i");
-MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c)");
+MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (or 0x248 for the combined sound/radiocard))");
 
 EXPORT_NO_SYMBOLS;
 
@@ -290,7 +290,7 @@ int init_module(void)
 {
        if(io==-1)
        {
-               printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c\n");
+               printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (or io=0x248 for the combined sound/radiocard)\n");
                return -EINVAL;
        }
        return gemtek_init(NULL);
index 1f15d389a6e5e717d429346550559c06ac11b100..66314f72faa1e747d990d63bdf017f75ebda6a5d 100644 (file)
@@ -205,7 +205,7 @@ static struct video_device pcm20_radio=
        NULL
 };
 
-__initfunc(int pcm20_init(struct video_init *v))
+int __init pcm20_init(struct video_init *v)
 {
 
        pcm20_radio.priv=&pcm20_unit;
index 793548839803a84a879e7d4667641938c4293038..7370f3a616006e7d4e8b7eb635bd9b63d73cbbc5 100644 (file)
@@ -218,7 +218,7 @@ static struct video_device rtrack2_radio=
        NULL
 };
 
-__initfunc(int rtrack2_init(struct video_init *v))
+int __init rtrack2_init(struct video_init *v)
 {
        if (check_region(io, 4)) 
        {
index 53333f082de8457cfb8464ed86bf1e1d3746ff29..c659cc7ba29ebff8dcb81933758a0eeb3240b541 100644 (file)
@@ -276,7 +276,7 @@ static struct video_device fmi_radio=
        NULL
 };
 
-__initfunc(int fmi_init(struct video_init *v))
+int __init fmi_init(struct video_init *v)
 {
        if (check_region(io, 2)) 
        {
diff --git a/drivers/char/radio-terratec.c b/drivers/char/radio-terratec.c
new file mode 100644 (file)
index 0000000..ae14d11
--- /dev/null
@@ -0,0 +1,353 @@
+/* Terratec ActiveRadio ISA Standalone card driver for Linux radio support
+ * (c) 1999 R. Offermanns (rolf@offermanns.de)
+ * based on the aimslab radio driver from M. Kirkwood
+ * many thanks to Michael Becker and Friedhelm Birth (from TerraTec)
+ * 
+ *
+ * History:
+ * 1999-05-21  First preview release
+ * 
+ *  Notes on the hardware:
+ *  There are two "main" chips on the card:
+ *  - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
+ *  - Philips SAA6588 (http://www-us.semiconductors.philips.com/acrobat/datasheets/SAA6588_1.pdf)
+ *  (you can get the datasheet at the above links)
+ *
+ *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
+ *  Volume Control is done digitally
+ *
+ *  there is a I2C controlled RDS decoder (SAA6588)  onboard, which i would like to support someday
+ *  (as soon i have understand how to get started :)
+ *  If you can help me out with that, please contact me!!
+ *
+ *  
+ */
+
+#include <linux/module.h>      /* Modules                      */
+#include <linux/init.h>                /* Initdata                     */
+#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/delay.h>       /* udelay                       */
+#include <asm/io.h>            /* outb, outb_p                 */
+#include <asm/uaccess.h>       /* copy to/from user            */
+#include <linux/videodev.h>    /* kernel radio structs         */
+#include <linux/config.h>      /* CONFIG_RADIO_TERRATEC_PORT   */
+
+#ifndef CONFIG_RADIO_TERRATEC_PORT
+#define CONFIG_RADIO_TERRATEC_PORT 0x590
+#endif
+
+/**************** this ones are for the terratec *******************/
+#define BASEPORT       0x590
+#define VOLPORT        0x591
+#define WRT_DIS        0x00
+#define CLK_OFF                0x00
+#define IIC_DATA       0x01
+#define IIC_CLK                0x02
+#define DATA           0x04
+#define CLK_ON                 0x08
+#define WRT_EN         0x10
+/*******************************************************************/
+
+static int io = CONFIG_RADIO_TERRATEC_PORT; 
+static int users = 0;
+
+struct tt_device
+{
+       int port;
+       int curvol;
+       unsigned long curfreq;
+       int muted;
+};
+
+
+/* local things */
+
+static void cardWriteVol(int volume)
+{
+       int i;
+       volume = volume+(volume * 32); // change both channels
+       for (i=0;i<8;i++)
+       {
+               if (volume & (0x80>>i))
+                       outb(0x80, VOLPORT);
+               else outb(0x00, VOLPORT);
+       }
+}
+
+
+
+static void tt_mute(struct tt_device *dev)
+{
+       dev->muted = 1;
+       cardWriteVol(0);
+}
+
+static int tt_setvol(struct tt_device *dev, int vol)
+{
+       
+//     printk(KERN_ERR "setvol called, vol = %d\n", vol);
+
+       if(vol == dev->curvol) {        /* requested volume = current */
+               if (dev->muted) {       /* user is unmuting the card  */
+                       dev->muted = 0;
+                       cardWriteVol(vol);      /* enable card */
+               }       
+       
+               return 0;
+       }
+
+       if(vol == 0) {                  /* volume = 0 means mute the card */
+               cardWriteVol(0);        /* "turn off card" by setting vol to 0 */
+               dev->curvol = vol;      /* track the volume state!      */
+               return 0;
+       }
+
+       dev->muted = 0;
+       
+       cardWriteVol(vol);
+        
+       dev->curvol = vol;
+
+       return 0;
+
+}
+
+
+/* this is the worst part in this driver */
+/* many more or less strange things are going on here, but hey, it works :) */
+
+static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
+{      
+       int freq;
+       int i;
+       int p;
+       int  temp;
+       long rest;
+     
+       unsigned char buffer[25];               /* we have to bit shift 25 registers */
+       freq = freq1/160;                       /* convert the freq. to a nice to handel value */
+       for(i=24;i>-1;i--)
+               buffer[i]=0;
+
+       rest = freq*10+10700;           /* i once had understood what is going on here */
+                                       /* maybe some wise guy (friedhelm?) can comment this stuff */
+       i=13;
+       p=10;
+       temp=102400;
+       while (rest!=0)
+       {
+               if (rest%temp  == rest)
+                       buffer[i] = 0;
+               else 
+               {
+                       buffer[i] = 1; 
+                       rest = rest-temp;
+               }
+               i--;
+               p--;
+               temp = temp/2;
+       }
+
+       for (i=24;i>-1;i--)                     /* bit shift the values to the radiocard */
+       {
+               if (buffer[i]==1) 
+               {
+                       outb(WRT_EN|DATA, BASEPORT);
+                       outb(WRT_EN|DATA|CLK_ON  , BASEPORT);
+                       outb(WRT_EN|DATA, BASEPORT);
+               }
+               else
+               {
+                       outb(WRT_EN|0x00, BASEPORT);
+                       outb(WRT_EN|0x00|CLK_ON  , BASEPORT);
+               }
+       }
+       outb(0x00, BASEPORT);     
+  
+       return 0;
+}
+
+int tt_getsigstr(struct tt_device *dev)                /* TODO */
+{
+       if (inb(io) & 2)        /* bit set = no signal present  */
+               return 0;
+       return 1;               /* signal present               */
+}
+
+
+/* implement the video4linux api */
+
+static int tt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+       struct tt_device *tt=dev->priv;
+       
+       switch(cmd)
+       {
+               case VIDIOCGCAP:
+               {
+                       struct video_capability v;
+                       v.type=VID_TYPE_TUNER;
+                       v.channels=1;
+                       v.audios=1;
+                       /* No we don't do pictures */
+                       v.maxwidth=0;
+                       v.maxheight=0;
+                       v.minwidth=0;
+                       v.minheight=0;
+                       strcpy(v.name, "ActiveRadio");
+                       if(copy_to_user(arg,&v,sizeof(v)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCGTUNER:
+               {
+                       struct video_tuner v;
+                       if(copy_from_user(&v, arg,sizeof(v))!=0) 
+                               return -EFAULT;
+                       if(v.tuner)     /* Only 1 tuner */ 
+                               return -EINVAL;
+                       v.rangelow=(87*16000);
+                       v.rangehigh=(108*16000);
+                       v.flags=VIDEO_TUNER_LOW;
+                       v.mode=VIDEO_MODE_AUTO;
+                       strcpy(v.name, "FM");
+                       v.signal=0xFFFF*tt_getsigstr(tt);
+                       if(copy_to_user(arg,&v, sizeof(v)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCSTUNER:
+               {
+                       struct video_tuner v;
+                       if(copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       if(v.tuner!=0)
+                               return -EINVAL;
+                       /* Only 1 tuner so no setting needed ! */
+                       return 0;
+               }
+               case VIDIOCGFREQ:
+                       if(copy_to_user(arg, &tt->curfreq, sizeof(tt->curfreq)))
+                               return -EFAULT;
+                       return 0;
+               case VIDIOCSFREQ:
+                       if(copy_from_user(&tt->curfreq, arg,sizeof(tt->curfreq)))
+                               return -EFAULT;
+                       tt_setfreq(tt, tt->curfreq);
+                       return 0;
+               case VIDIOCGAUDIO:
+               {       
+                       struct video_audio v;
+                       memset(&v,0, sizeof(v));
+                       v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
+                       v.volume=tt->curvol * 6554;
+                       v.step=6554;
+                       strcpy(v.name, "Radio");
+                       if(copy_to_user(arg,&v, sizeof(v)))
+                               return -EFAULT;
+                       return 0;                       
+               }
+               case VIDIOCSAUDIO:
+               {
+                       struct video_audio v;
+                       if(copy_from_user(&v, arg, sizeof(v))) 
+                               return -EFAULT; 
+                       if(v.audio) 
+                               return -EINVAL;
+
+                       if(v.flags&VIDEO_AUDIO_MUTE) 
+                               tt_mute(tt);
+                       else
+                               tt_setvol(tt,v.volume/6554);    
+
+                       return 0;
+               }
+               default:
+                       return -ENOIOCTLCMD;
+       }
+}
+
+static int tt_open(struct video_device *dev, int flags)
+{
+       if(users)
+               return -EBUSY;
+       users++;
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static void tt_close(struct video_device *dev)
+{
+       users--;
+       MOD_DEC_USE_COUNT;
+}
+
+static struct tt_device terratec_unit;
+
+static struct video_device terratec_radio=
+{
+       "TerraTec ActiveRadio",
+       VID_TYPE_TUNER,
+       VID_HARDWARE_TERRATEC,
+       tt_open,
+       tt_close,
+       NULL,   /* Can't read  (no capture ability) */
+       NULL,   /* Can't write */
+       NULL,   /* No poll */
+       tt_ioctl,
+       NULL,
+       NULL
+};
+
+__initfunc(int terratec_init(struct video_init *v))
+{
+       if (check_region(io, 2)) 
+       {
+               printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
+               return -EBUSY;
+       }
+
+       terratec_radio.priv=&terratec_unit;
+       
+       if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1)
+               return -EINVAL;
+               
+       request_region(io, 2, "terratec");
+       printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
+
+       /* mute card - prevents noisy bootups */
+
+       /* this ensures that the volume is all the way down  */
+       cardWriteVol(0);
+       terratec_unit.curvol = 0;
+
+       return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("R.OFFERMANNS & others");
+MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+       if(io==-1)
+       {
+               printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+               return -EINVAL;
+       }
+       return terratec_init(NULL);
+}
+
+void cleanup_module(void)
+{
+       video_unregister_device(&terratec_radio);
+       release_region(io,2);
+       printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");     
+}
+
+#endif
index f54784811a2b42dc865311bf5b904fe20c9682d3..f0d8e37c7a951c279fe02a2dd9c910d18f6e9616 100644 (file)
@@ -333,7 +333,7 @@ static struct video_device zoltrix_radio =
        NULL
 };
 
-__initfunc(int zoltrix_init(struct video_init *v))
+int __init zoltrix_init(struct video_init *v)
 {
        if (check_region(io, 2)) {
                printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
index 8674c4ee06cd3c5207d7cc172e9f8be11666174c..cc0027ebe0ff4a2ee0baceb56856aed9e87c646d 100644 (file)
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
 #endif
-#include <linux/module.h>
 #else /* !NEW_MODULES */
 #ifdef MODVERSIONS
 #define MODULE
 #endif
-#include <linux/module.h>
 #endif /* NEW_MODULES */
 
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/major.h>
 #include <linux/kernel.h>
 /*
  * NB. we must include the kernel idenfication string in to install the module.
  */
-#include <linux/version.h>
 /*static*/ char kernel_version[] = UTS_RELEASE;
 #endif
 
diff --git a/drivers/char/saa7111.c b/drivers/char/saa7111.c
new file mode 100644 (file)
index 0000000..1c14027
--- /dev/null
@@ -0,0 +1,421 @@
+/* 
+   saa7111 - Philips SAA7111A video decoder driver version 0.0.3
+
+   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#define DEBUG(x)               /* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct saa7111 {
+       struct i2c_bus *bus;
+       int addr;
+       unsigned char reg[32];
+
+       int norm;
+       int input;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+};
+
+#define   I2C_SAA7111        0x48
+
+#define   I2C_DELAY   10
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data)
+{
+       int ack;
+       unsigned long flags;
+
+       LOCK_I2C_BUS(dev->bus);
+       i2c_start(dev->bus);
+       i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+       i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+       ack = i2c_sendbyte(dev->bus, data, I2C_DELAY);
+       dev->reg[subaddr] = data;
+       i2c_stop(dev->bus);
+       UNLOCK_I2C_BUS(dev->bus);
+       return ack;
+}
+
+static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len)
+{
+       int ack;
+       unsigned subaddr;
+       unsigned long flags;
+
+       while (len > 1) {
+               LOCK_I2C_BUS(dev->bus);
+               i2c_start(dev->bus);
+               i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+               ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY);
+               ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+               len -= 2;
+               while (len > 1 && *data == ++subaddr) {
+                       data++;
+                       ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+                       len -= 2;
+               }
+               i2c_stop(dev->bus);
+               UNLOCK_I2C_BUS(dev->bus);
+       }
+       return ack;
+}
+
+static int saa7111_read(struct saa7111 *dev, unsigned char subaddr)
+{
+       int data;
+       unsigned long flags;
+
+       LOCK_I2C_BUS(dev->bus);
+       i2c_start(dev->bus);
+       i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+       i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+       i2c_start(dev->bus);
+       i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY);
+       data = i2c_readbyte(dev->bus, 1);
+       i2c_stop(dev->bus);
+       UNLOCK_I2C_BUS(dev->bus);
+       return data;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7111_attach(struct i2c_device *device)
+{
+       int i;
+       struct saa7111 *decoder;
+
+       static const unsigned char init[] =
+       {
+               0x00, 0x00,     /* 00 - ID byte */
+               0x01, 0x00,     /* 01 - reserved */
+
+       /*front end */
+               0x02, 0xd0,     /* 02 - FUSE=3, GUDL=2, MODE=0 */
+               0x03, 0x23,     /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
+               0x04, 0x00,     /* 04 - GAI1=256 */
+               0x05, 0x00,     /* 05 - GAI2=256 */
+
+       /* decoder */
+               0x06, 0xf6,     /* 06 - HSB at  13(50Hz) /  17(60Hz) pixels after end of last line */
+               0x07, 0xdd,     /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */
+               0x08, 0xc8,     /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */
+               0x09, 0x01,     /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */
+               0x0a, 0x80,     /* 0a - BRIG=128 */
+               0x0b, 0x47,     /* 0b - CONT=1.109 */
+               0x0c, 0x40,     /* 0c - SATN=1.0 */
+               0x0d, 0x00,     /* 0d - HUE=0 */
+               0x0e, 0x01,     /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
+               0x0f, 0x00,     /* 0f - reserved */
+               0x10, 0x48,     /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
+               0x11, 0x1c,     /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
+               0x12, 0x00,     /* 12 - output control 2 */
+               0x13, 0x00,     /* 13 - output control 3 */
+               0x14, 0x00,     /* 14 - reserved */
+               0x15, 0x00,     /* 15 - VBI */
+               0x16, 0x00,     /* 16 - VBI */
+               0x17, 0x00,     /* 17 - VBI */
+       };
+
+       device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL);
+       if (decoder == NULL) {
+               return -ENOMEM;
+       }
+       MOD_INC_USE_COUNT;
+
+       memset(decoder, 0, sizeof(struct saa7111));
+       strcpy(device->name, "saa7111");
+       decoder->bus = device->bus;
+       decoder->addr = device->addr;
+       decoder->norm = VIDEO_MODE_NTSC;
+       decoder->input = 0;
+       decoder->enable = 1;
+       decoder->bright = 32768;
+       decoder->contrast = 32768;
+       decoder->hue = 32768;
+       decoder->sat = 32768;
+
+       i = saa7111_write_block(decoder, init, sizeof(init));
+       if (i < 0) {
+               printk(KERN_ERR "%s_attach: init status %d\n", device->name, i);
+       } else {
+               printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00));
+       }
+       return 0;
+}
+
+
+static int saa7111_detach(struct i2c_device *device)
+{
+       kfree(device->data);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg)
+{
+       struct saa7111 *decoder = device->data;
+
+       switch (cmd) {
+
+#if defined(DECODER_DUMP)
+       case DECODER_DUMP:
+               {
+                       int i;
+
+                       for (i = 0; i < 32; i += 16) {
+                               int j;
+
+                               printk("KERN_DEBUG %s: %03x", device->name, i);
+                               for (j = 0; j < 16; ++j) {
+                                       printk(" %02x", saa7111_read(decoder, i + j));
+                               }
+                               printk("\n");
+                       }
+               }
+               break;
+#endif                         /* defined(DECODER_DUMP) */
+
+       case DECODER_GET_CAPABILITIES:
+               {
+                       struct video_decoder_capability *cap = arg;
+
+                       cap->flags
+                           = VIDEO_DECODER_PAL
+                           | VIDEO_DECODER_NTSC
+                           | VIDEO_DECODER_AUTO
+                           | VIDEO_DECODER_CCIR;
+                       cap->inputs = 8;
+                       cap->outputs = 1;
+               }
+               break;
+
+       case DECODER_GET_STATUS:
+               {
+                       int *iarg = arg;
+                       int status;
+                       int res;
+
+                       status = saa7111_read(decoder, 0x1f);
+                       res = 0;
+                       if ((status & (1 << 6)) == 0) {
+                               res |= DECODER_STATUS_GOOD;
+                       }
+                       switch (decoder->norm) {
+                       case VIDEO_MODE_NTSC:
+                               res |= DECODER_STATUS_NTSC;
+                               break;
+                       case VIDEO_MODE_PAL:
+                               res |= DECODER_STATUS_PAL;
+                               break;
+                       default:
+                       case VIDEO_MODE_AUTO:
+                               if ((status & (1 << 5)) != 0) {
+                                       res |= DECODER_STATUS_NTSC;
+                               } else {
+                                       res |= DECODER_STATUS_PAL;
+                               }
+                               break;
+                       }
+                       if ((status & (1 << 0)) != 0) {
+                               res |= DECODER_STATUS_COLOR;
+                       }
+                       *iarg = res;
+               }
+               break;
+
+       case DECODER_SET_NORM:
+               {
+                       int *iarg = arg;
+
+                       switch (*iarg) {
+
+                       case VIDEO_MODE_NTSC:
+                               saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40);
+                               break;
+
+                       case VIDEO_MODE_PAL:
+                               saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00);
+                               break;
+
+                       case VIDEO_MODE_AUTO:
+                               saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80);
+                               break;
+
+                       default:
+                               return -EINVAL;
+
+                       }
+                       decoder->norm = *iarg;
+               }
+               break;
+
+       case DECODER_SET_INPUT:
+               {
+                       int *iarg = arg;
+
+                       if (*iarg < 0 || *iarg > 7) {
+                               return -EINVAL;
+                       }
+                       if (decoder->input != *iarg) {
+                               decoder->input = *iarg;
+                               /* select mode */
+                               saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input);
+                               /* bypass chrominance trap for modes 4..7 */
+                               saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
+                       }
+               }
+               break;
+
+       case DECODER_SET_OUTPUT:
+               {
+                       int *iarg = arg;
+
+                       /* not much choice of outputs */
+                       if (*iarg != 0) {
+                               return -EINVAL;
+                       }
+               }
+               break;
+
+       case DECODER_ENABLE_OUTPUT:
+               {
+                       int *iarg = arg;
+                       int enable = (*iarg != 0);
+
+                       if (decoder->enable != enable) {
+                               decoder->enable = enable;
+
+// RJ: If output should be disabled (for playing videos), we also need a open PLL.
+                               //     The input is set to 0 (where no input source is connected), although this
+                               //     is not necessary.
+                               //
+                               //     If output should be enabled, we have to reverse the above.
+
+                               if (decoder->enable) {
+                                       saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input);
+                                       saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb));
+                                       saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c);
+                               } else {
+                                       saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8));
+                                       saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04);
+                                       saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3));
+                               }
+                       }
+               }
+               break;
+
+       case DECODER_SET_PICTURE:
+               {
+                       struct video_picture *pic = arg;
+
+                       if (decoder->bright != pic->brightness) {
+                               /* We want 0 to 255 we get 0-65535 */
+                               decoder->bright = pic->brightness;
+                               saa7111_write(decoder, 0x0a, decoder->bright >> 8);
+                       }
+                       if (decoder->contrast != pic->contrast) {
+                               /* We want 0 to 127 we get 0-65535 */
+                               decoder->contrast = pic->contrast;
+                               saa7111_write(decoder, 0x0b, decoder->contrast >> 9);
+                       }
+                       if (decoder->sat != pic->colour) {
+                               /* We want 0 to 127 we get 0-65535 */
+                               decoder->sat = pic->colour;
+                               saa7111_write(decoder, 0x0c, decoder->sat >> 9);
+                       }
+                       if (decoder->hue != pic->hue) {
+                               /* We want -128 to 127 we get 0-65535 */
+                               decoder->hue = pic->hue;
+                               saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8);
+                       }
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7111 =
+{
+       "saa7111",              /* name */
+       I2C_DRIVERID_VIDEODECODER,      /* ID */
+       I2C_SAA7111, I2C_SAA7111 + 1,
+
+       saa7111_attach,
+       saa7111_detach,
+       saa7111_command
+};
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+int saa7111_init(void)
+#endif
+{
+       return i2c_register_driver(&i2c_driver_saa7111);
+}
+
+
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+       i2c_unregister_driver(&i2c_driver_saa7111);
+}
+
+#endif
diff --git a/drivers/char/saa7185.c b/drivers/char/saa7185.c
new file mode 100644 (file)
index 0000000..c42b29c
--- /dev/null
@@ -0,0 +1,379 @@
+/* 
+   saa7185 - Philips SAA7185B video encoder driver version 0.0.3
+
+   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/video_encoder.h>
+
+#define DEBUG(x)   x           /* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct saa7185 {
+       struct i2c_bus *bus;
+       int addr;
+       unsigned char reg[128];
+
+       int norm;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+};
+
+#define   I2C_SAA7185        0x88
+
+#define I2C_DELAY   10
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data)
+{
+       int ack;
+       unsigned long flags;
+
+       LOCK_I2C_BUS(dev->bus);
+
+       i2c_start(dev->bus);
+       i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+       i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+       ack = i2c_sendbyte(dev->bus, data, I2C_DELAY);
+       dev->reg[subaddr] = data;
+       i2c_stop(dev->bus);
+       UNLOCK_I2C_BUS(dev->bus);
+       return ack;
+}
+
+static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len)
+{
+       int ack;
+       unsigned subaddr;
+       unsigned long flags;
+
+       while (len > 1) {
+               LOCK_I2C_BUS(dev->bus);
+               i2c_start(dev->bus);
+               i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+               ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY);
+               ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+               len -= 2;
+               while (len > 1 && *data == ++subaddr) {
+                       data++;
+                       ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+                       len -= 2;
+               }
+               i2c_stop(dev->bus);
+               UNLOCK_I2C_BUS(dev->bus);
+       }
+       return ack;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const unsigned char init_common[] =
+{
+       0x3a, 0x0f,             /* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */
+
+       0x42, 0x6b,             /* OVLY0=107 */
+       0x43, 0x00,             /* OVLU0=0     white */
+       0x44, 0x00,             /* OVLV0=0   */
+       0x45, 0x22,             /* OVLY1=34  */
+       0x46, 0xac,             /* OVLU1=172   yellow */
+       0x47, 0x0e,             /* OVLV1=14  */
+       0x48, 0x03,             /* OVLY2=3   */
+       0x49, 0x1d,             /* OVLU2=29    cyan */
+       0x4a, 0xac,             /* OVLV2=172 */
+       0x4b, 0xf0,             /* OVLY3=240 */
+       0x4c, 0xc8,             /* OVLU3=200   green */
+       0x4d, 0xb9,             /* OVLV3=185 */
+       0x4e, 0xd4,             /* OVLY4=212 */
+       0x4f, 0x38,             /* OVLU4=56    magenta */
+       0x50, 0x47,             /* OVLV4=71  */
+       0x51, 0xc1,             /* OVLY5=193 */
+       0x52, 0xe3,             /* OVLU5=227   red */
+       0x53, 0x54,             /* OVLV5=84  */
+       0x54, 0xa3,             /* OVLY6=163 */
+       0x55, 0x54,             /* OVLU6=84    blue */
+       0x56, 0xf2,             /* OVLV6=242 */
+       0x57, 0x90,             /* OVLY7=144 */
+       0x58, 0x00,             /* OVLU7=0     black */
+       0x59, 0x00,             /* OVLV7=0   */
+
+       0x5a, 0x00,             /* CHPS=0    */
+       0x5b, 0x76,             /* GAINU=118 */
+       0x5c, 0xa5,             /* GAINV=165 */
+       0x5d, 0x3c,             /* BLCKL=60  */
+       0x5e, 0x3a,             /* BLNNL=58  */
+       0x5f, 0x3a,             /* CCRS=0, BLNVB=58 */
+       0x60, 0x00,             /* NULL      */
+
+/* 0x61 - 0x66 set according to norm */
+
+       0x67, 0x00,             /* 0 : caption 1st byte odd  field */
+       0x68, 0x00,             /* 0 : caption 2nd byte odd  field */
+       0x69, 0x00,             /* 0 : caption 1st byte even field */
+       0x6a, 0x00,             /* 0 : caption 2nd byte even field */
+
+       0x6b, 0x91,             /* MODIN=2, PCREF=0, SCCLN=17 */
+       0x6c, 0x20,             /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */
+       0x6d, 0x00,             /* SRCM1=0, CCEN=0 */
+
+       0x6e, 0x0e,             /* HTRIG=0x00e, approx. centered, at least for PAL */
+       0x6f, 0x00,             /* HTRIG upper bits */
+       0x70, 0x20,             /* PHRES=0, SBLN=1, VTRIG=0 */
+
+/* The following should not be needed */
+
+       0x71, 0x15,             /* BMRQ=0x115 */
+       0x72, 0x90,             /* EMRQ=0x690 */
+       0x73, 0x61,             /* EMRQ=0x690, BMRQ=0x115 */
+       0x74, 0x00,             /* NULL       */
+       0x75, 0x00,             /* NULL       */
+       0x76, 0x00,             /* NULL       */
+       0x77, 0x15,             /* BRCV=0x115 */
+       0x78, 0x90,             /* ERCV=0x690 */
+       0x79, 0x61,             /* ERCV=0x690, BRCV=0x115 */
+
+/* Field length controls */
+
+       0x7a, 0x70,             /* FLC=0 */
+
+/* The following should not be needed if SBLN = 1 */
+
+       0x7b, 0x16,             /* FAL=22 */
+       0x7c, 0x35,             /* LAL=244 */
+       0x7d, 0x20,             /* LAL=244, FAL=22 */
+};
+
+static const unsigned char init_pal[] =
+{
+       0x61, 0x1e,             /* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */
+       0x62, 0xc8,             /* DECTYP=1, BSTA=72 */
+       0x63, 0xcb,             /* FSC0 */
+       0x64, 0x8a,             /* FSC1 */
+       0x65, 0x09,             /* FSC2 */
+       0x66, 0x2a,             /* FSC3 */
+};
+
+static const unsigned char init_ntsc[] =
+{
+       0x61, 0x1d,             /* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */
+       0x62, 0xe6,             /* DECTYP=1, BSTA=102 */
+       0x63, 0x1f,             /* FSC0 */
+       0x64, 0x7c,             /* FSC1 */
+       0x65, 0xf0,             /* FSC2 */
+       0x66, 0x21,             /* FSC3 */
+};
+
+static int saa7185_attach(struct i2c_device *device)
+{
+       int i;
+       struct saa7185 *encoder;
+
+       device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL);
+       if (encoder == NULL) {
+               return -ENOMEM;
+       }
+       MOD_INC_USE_COUNT;
+
+       memset(encoder, 0, sizeof(struct saa7185));
+       strcpy(device->name, "saa7185");
+       encoder->bus = device->bus;
+       encoder->addr = device->addr;
+       encoder->norm = VIDEO_MODE_NTSC;
+       encoder->enable = 1;
+
+       i = saa7185_write_block(encoder, init_common, sizeof(init_common));
+       if (i >= 0) {
+               i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc));
+       }
+       if (i < 0) {
+               printk(KERN_ERR "%s_attach: init error %d\n", device->name, i);
+       }
+       return 0;
+}
+
+
+static int saa7185_detach(struct i2c_device *device)
+{
+       kfree(device->data);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg)
+{
+       struct saa7185 *encoder = device->data;
+
+       switch (cmd) {
+
+       case ENCODER_GET_CAPABILITIES:
+               {
+                       struct video_encoder_capability *cap = arg;
+
+                       cap->flags
+                           = VIDEO_ENCODER_PAL
+                           | VIDEO_ENCODER_NTSC
+                           | VIDEO_ENCODER_SECAM
+                           | VIDEO_ENCODER_CCIR;
+                       cap->inputs = 1;
+                       cap->outputs = 1;
+               }
+               break;
+
+       case ENCODER_SET_NORM:
+               {
+                       int *iarg = arg;
+
+                       switch (*iarg) {
+
+                       case VIDEO_MODE_NTSC:
+                               saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc));
+                               break;
+
+                       case VIDEO_MODE_PAL:
+                               saa7185_write_block(encoder, init_pal, sizeof(init_pal));
+                               break;
+
+                       case VIDEO_MODE_SECAM:
+                       default:
+                               return -EINVAL;
+
+                       }
+                       encoder->norm = *iarg;
+               }
+               break;
+
+       case ENCODER_SET_INPUT:
+               {
+                       int *iarg = arg;
+
+#if 0
+                       /* not much choice of inputs */
+                       if (*iarg != 0) {
+                               return -EINVAL;
+                       }
+#else
+                       /* RJ: *iarg = 0: input is from SA7111
+                          *iarg = 1: input is from ZR36060 */
+
+                       switch (*iarg) {
+
+                       case 0:
+                               /* Switch RTCE to 1 */
+                               saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
+                               break;
+
+                       case 1:
+                               /* Switch RTCE to 0 */
+                               saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00);
+                               break;
+
+                       default:
+                               return -EINVAL;
+
+                       }
+#endif
+               }
+               break;
+
+       case ENCODER_SET_OUTPUT:
+               {
+                       int *iarg = arg;
+
+                       /* not much choice of outputs */
+                       if (*iarg != 0) {
+                               return -EINVAL;
+                       }
+               }
+               break;
+
+       case ENCODER_ENABLE_OUTPUT:
+               {
+                       int *iarg = arg;
+
+                       encoder->enable = !!*iarg;
+                       saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40));
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7185 =
+{
+       "saa7185",              /* name */
+       I2C_DRIVERID_VIDEOENCODER,      /* ID */
+       I2C_SAA7185, I2C_SAA7185 + 1,
+
+       saa7185_attach,
+       saa7185_detach,
+       saa7185_command
+};
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+int saa7185_init(void)
+#endif
+{
+       return i2c_register_driver(&i2c_driver_saa7185);
+}
+
+
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+       i2c_unregister_driver(&i2c_driver_saa7185);
+}
+
+#endif
index edcf6f2f32970bb9488079751339e8568a88b779..aa22774a5ff3cf42fc4bf1ee6770c821059b90b1 100644 (file)
@@ -127,7 +127,7 @@ unsigned long qic02_tape_debug = TPQD_DEFAULT_FLAGS;
 
 static volatile int ctlbits = 0;     /* control reg bits for tape interface */
 
-static wait_queue_t qic02_tape_transfer; /* sync rw with interrupts */
+static wait_queue_head_t qic02_tape_transfer; /* sync rw with interrupts */
 
 static volatile struct mtget ioctl_status;     /* current generic status */
 
@@ -2889,7 +2889,7 @@ static int qic02_get_resources(void)
     return 0;
 } /* qic02_get_resources */
 
-__initfunc(int qic02_tape_init(void))
+int __init qic02_tape_init(void)
 {
     if (TPSTATSIZE != 6)
     {
index 141fcf1bcd1625cf10b0cd96f374870405da9f0b..39bb5f2569fe6b91ddf633f94329e28f4648a9b6 100644 (file)
@@ -63,6 +63,9 @@ extern int aztech_init(struct video_init *);
 #ifdef CONFIG_RADIO_RTRACK
 extern int rtrack_init(struct video_init *);
 #endif
+#ifdef CONFIG_RADIO_RTRACK2
+extern int rtrack2_init(struct video_init *);
+#endif
 #ifdef CONFIG_RADIO_SF16FMI
 extern int fmi_init(struct video_init *);
 #endif
@@ -78,9 +81,15 @@ extern int typhoon_init(struct video_init *);
 #ifdef CONFIG_RADIO_CADET
 extern int cadet_init(struct video_init *);
 #endif
+#ifdef CONFIG_RADIO_TERRATEC
+extern int terratec_init(struct video_init *);
+#endif
 #ifdef CONFIG_VIDEO_PMS
 extern int init_pms_cards(struct video_init *);
 #endif
+#ifdef CONFIG_VIDEO_ZORAN
+extern int init_zoran_cards(struct video_init *);
+#endif
 
 static struct video_init video_init_list[]={
 #ifdef CONFIG_VIDEO_BT848
@@ -108,6 +117,9 @@ static struct video_init video_init_list[]={
 #ifdef CONFIG_RADIO_RTRACK
        {"RTrack", rtrack_init}, 
 #endif 
+#ifdef CONFIG_RADIO_RTRACK2
+       {"RTrack2", rtrack2_init}, 
+#endif
 #ifdef CONFIG_RADIO_SF16FMI
        {"SF16FMI", fmi_init}, 
 #endif 
@@ -123,6 +135,12 @@ static struct video_init video_init_list[]={
 #ifdef CONFIG_RADIO_TYPHOON
        {"radio-typhoon", typhoon_init},
 #endif
+#ifdef CONFIG_RADIO_TERRATEC
+       {"radio-terratec", terratec_init},
+#endif
+#ifdef CONFIG_VIDEO_ZORAN
+       {"zoran", init_zoran_cards},
+#endif 
        {"end", NULL}
 };
 
diff --git a/drivers/char/zr36057.h b/drivers/char/zr36057.h
new file mode 100644 (file)
index 0000000..b672357
--- /dev/null
@@ -0,0 +1,168 @@
+/* 
+   zr36057.h - zr36057 register offsets
+
+   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ZR36057_H_
+#define _ZR36057_H_
+
+
+/* Zoran ZR36057 registers */
+
+#define ZR36057_VFEHCR          0x000  /* Video Front End, Horizontal Configuration Register */
+#define ZR36057_VFEHCR_HSPol            (1<<30)
+#define ZR36057_VFEHCR_HStart           10
+#define ZR36057_VFEHCR_HEnd            0
+#define ZR36057_VFEHCR_Hmask           0x3ff
+
+#define ZR36057_VFEVCR          0x004  /* Video Front End, Vertical Configuration Register */
+#define ZR36057_VFEVCR_VSPol            (1<<30)
+#define ZR36057_VFEVCR_VStart           10
+#define ZR36057_VFEVCR_VEnd            0
+#define ZR36057_VFEVCR_Vmask           0x3ff
+
+#define ZR36057_VFESPFR         0x008  /* Video Front End, Scaler and Pixel Format Register */
+#define ZR36057_VFESPFR_ExtFl           (1<<26)
+#define ZR36057_VFESPFR_TopField        (1<<25)
+#define ZR36057_VFESPFR_VCLKPol         (1<<24)
+#define ZR36057_VFESPFR_HFilter         21
+#define ZR36057_VFESPFR_HorDcm          14
+#define ZR36057_VFESPFR_VerDcm          8
+#define ZR36057_VFESPFR_DispMode        6
+#define ZR36057_VFESPFR_YUV422          (0<<3)
+#define ZR36057_VFESPFR_RGB888          (1<<3)
+#define ZR36057_VFESPFR_RGB565          (2<<3)
+#define ZR36057_VFESPFR_RGB555          (3<<3)
+#define ZR36057_VFESPFR_ErrDif          (1<<2)
+#define ZR36057_VFESPFR_Pack24          (1<<1)
+#define ZR36057_VFESPFR_LittleEndian    (1<<0)
+
+#define ZR36057_VDTR            0x00c  /* Video Display "Top" Register */
+
+#define ZR36057_VDBR            0x010  /* Video Display "Bottom" Register */
+
+#define ZR36057_VSSFGR          0x014  /* Video Stride, Status, and Frame Grab Register */
+#define ZR36057_VSSFGR_DispStride       16
+#define ZR36057_VSSFGR_VidOvf           (1<<8)
+#define ZR36057_VSSFGR_SnapShot         (1<<1)
+#define ZR36057_VSSFGR_FrameGrab        (1<<0)
+
+#define ZR36057_VDCR            0x018  /* Video Display Configuration Register */
+#define ZR36057_VDCR_VidEn              (1<<31)
+#define ZR36057_VDCR_MinPix             24
+#define ZR36057_VDCR_Triton             (1<<24)
+#define ZR36057_VDCR_VidWinHt           12
+#define ZR36057_VDCR_VidWinWid          0
+
+#define ZR36057_MMTR            0x01c  /* Masking Map "Top" Register */
+
+#define ZR36057_MMBR            0x020  /* Masking Map "Bottom" Register */
+
+#define ZR36057_OCR             0x024  /* Overlay Control Register */
+#define ZR36057_OCR_OvlEnable           (1 << 15)
+#define ZR36057_OCR_MaskStride          0
+
+#define ZR36057_SPGPPCR         0x028  /* System, PCI, and General Purpose Pins Control Register */
+#define ZR36057_SPGPPCR_SoftReset      (1<<24)
+
+#define ZR36057_GPPGCR1         0x02c  /* General Purpose Pins and GuestBus Control Register (1) */
+
+#define ZR36057_MCSAR           0x030  /* MPEG Code Source Address Register */
+
+#define ZR36057_MCTCR           0x034  /* MPEG Code Transfer Control Register */
+#define ZR36057_MCTCR_CodTime           (1 << 30)
+#define ZR36057_MCTCR_CEmpty            (1 << 29)
+#define ZR36057_MCTCR_CFlush            (1 << 28)
+#define ZR36057_MCTCR_CodGuestID       20
+#define ZR36057_MCTCR_CodGuestReg      16
+
+#define ZR36057_MCMPR           0x038  /* MPEG Code Memory Pointer Register */
+
+#define ZR36057_ISR             0x03c  /* Interrupt Status Register */
+#define ZR36057_ISR_GIRQ1               (1<<30)
+#define ZR36057_ISR_GIRQ0               (1<<29)
+#define ZR36057_ISR_CodRepIRQ           (1<<28)
+#define ZR36057_ISR_JPEGRepIRQ          (1<<27)
+
+#define ZR36057_ICR             0x040  /* Interrupt Control Register */
+#define ZR36057_ICR_GIRQ1               (1<<30)
+#define ZR36057_ICR_GIRQ0               (1<<29)
+#define ZR36057_ICR_CodRepIRQ           (1<<28)
+#define ZR36057_ICR_JPEGRepIRQ          (1<<27)
+#define ZR36057_ICR_IntPinEn            (1<<24)
+
+#define ZR36057_I2CBR           0x044  /* I2C Bus Register */
+#define ZR36057_I2CBR_SDA              (1<<1)
+#define ZR36057_I2CBR_SCL              (1<<0)
+
+#define ZR36057_JMC             0x100  /* JPEG Mode and Control */
+#define ZR36057_JMC_JPG                 (1 << 31)
+#define ZR36057_JMC_JPGExpMode          (0 << 29)
+#define ZR36057_JMC_JPGCmpMode          (1 << 29)
+#define ZR36057_JMC_MJPGExpMode         (2 << 29)
+#define ZR36057_JMC_MJPGCmpMode         (3 << 29)
+#define ZR36057_JMC_RTBUSY_FB           (1 << 6)
+#define ZR36057_JMC_Go_en               (1 << 5)
+#define ZR36057_JMC_SyncMstr            (1 << 4)
+#define ZR36057_JMC_Fld_per_buff        (1 << 3)
+#define ZR36057_JMC_VFIFO_FB            (1 << 2)
+#define ZR36057_JMC_CFIFO_FB            (1 << 1)
+#define ZR36057_JMC_Stll_LitEndian      (1 << 0)
+
+#define ZR36057_JPC             0x104  /* JPEG Process Control */
+#define ZR36057_JPC_P_Reset             (1 << 7)
+#define ZR36057_JPC_CodTrnsEn           (1 << 5)
+#define ZR36057_JPC_Active              (1 << 0)
+
+#define ZR36057_VSP             0x108  /* Vertical Sync Parameters */
+#define ZR36057_VSP_VsyncSize           16
+#define ZR36057_VSP_FrmTot              0
+
+#define ZR36057_HSP             0x10c  /* Horizontal Sync Parameters */
+#define ZR36057_HSP_HsyncStart          16
+#define ZR36057_HSP_LineTot             0
+
+#define ZR36057_FHAP            0x110  /* Field Horizontal Active Portion */
+#define ZR36057_FHAP_NAX                16
+#define ZR36057_FHAP_PAX                0
+
+#define ZR36057_FVAP            0x114  /* Field Vertical Active Portion */
+#define ZR36057_FVAP_NAY                16
+#define ZR36057_FVAP_PAY                0
+
+#define ZR36057_FPP             0x118  /* Field Process Parameters */
+#define ZR36057_FPP_Odd_Even            (1 << 0)
+
+#define ZR36057_JCBA            0x11c  /* JPEG Code Base Address */
+
+#define ZR36057_JCFT            0x120  /* JPEG Code FIFO Threshold */
+
+#define ZR36057_JCGI            0x124  /* JPEG Codec Guest ID */
+#define ZR36057_JCGI_JPEGuestID         4
+#define ZR36057_JCGI_JPEGuestReg        0
+
+#define ZR36057_GCR2            0x12c  /* GuestBus Control Register (2) */
+
+#define ZR36057_POR             0x200  /* Post Office Register */
+#define ZR36057_POR_POPen               (1<<25)
+#define ZR36057_POR_POTime              (1<<24)
+#define ZR36057_POR_PODir               (1<<23)
+
+#define ZR36057_STR             0x300  /* "Still" Transfer Register */
+
+#endif
diff --git a/drivers/char/zr36060.h b/drivers/char/zr36060.h
new file mode 100644 (file)
index 0000000..d94f56b
--- /dev/null
@@ -0,0 +1,35 @@
+/* 
+   zr36060.h - zr36060 register offsets
+
+   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ZR36060_H_
+#define _ZR36060_H_
+
+
+/* Zoran ZR36060 registers */
+
+#define ZR36060_LoadParameters         0x000
+#define ZR36060_Load                    (1<<7)
+#define ZR36060_SyncRst                 (1<<0)
+
+#define ZR36060_CodeFifoStatus         0x001
+#define ZR36060_Load                    (1<<7)
+#define ZR36060_SyncRst                 (1<<0)
+
+#endif
index bf76123a6b9dfbbe683c062061fb731d0a9ede3f..60a5f15e17083c6c622c387dc44403cf7dacab69 100644 (file)
@@ -37,7 +37,6 @@ static char *version =
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 
index 4e6d2c16df2029572998044095ae6de72a4d5ac9..3dbe8088a6be19666f26ee4033573631388e965a 100644 (file)
@@ -22,8 +22,15 @@ Deepak Saxena,       Intel Corp.
 Philip Rumpf
        Fixed assorted dumb SMP locking bugs
 
-Juha Sievanen,  University Of Helsinki Finland
+Juha Sievanen,  University of Helsinki Finland
        LAN OSM
+       /proc interface to LAN class
+       Bug fixes
+       Core code extensions
+
+Auvo Häkkinen,  University of Helsinki Finland
+       LAN OSM
+       /Proc interface to LAN class
        Bug fixes
        Core code extensions
 
@@ -41,13 +48,16 @@ Symbios Logic (Now LSI)
 BoxHill Corporation
        Loan of initial FibreChannel disk array used for development work.
 
+European Comission
+       Funding the work done by the University of Helsinki
+
 STATUS:
 
 o      The core setup works within limits.
 o      The scsi layer seems to almost work. I'm still chasing down the hang
        bug.
 o      The block OSM is fairly minimal but does seem to work.
-
+o      LAN OSM works with FDDI cards.
 
 TO DO:
 
@@ -69,10 +79,8 @@ o    Finish Media changers
 SCSI:
 o      Find the right way to associate drives/luns/busses
 
-Net:
-o      Port the existing RCPCI work to the frame work or write a new
-       driver. This one is with the Finns
+Lan:   Batch mode sends
+       Fix the "killing interrupt handler" in i2o_set_multicast_list
 
 Tape:
 o      Anyone seen anything implementing this ?
-
index 1d1ba0f14215ce1a9c77e549a09a7547d4e47d70..cb970810001d82d1d24dfab00b6a2723f6b05714 100644 (file)
@@ -1,5 +1,6 @@
 
        Linux I2O LAN OSM
+
        (c) University of Helsinki, Department of Computer Science
 
        This program is free software; you can redistribute it and/or
@@ -8,14 +9,14 @@
        2 of the License, or (at your option) any later version.
 
 AUTHORS
-Auvo Häkkinen, Auvo.Hakkinen@cs.Helsinki.FI
-Juha Sievänen, Juha.Sievanen@cs.Helsinki.FI
+       Auvo Häkkinen, Auvo.Hakkinen@cs.Helsinki.FI
+       Juha Sievänen, Juha.Sievanen@cs.Helsinki.FI
 
 CREDITS
 
        This work was made possible by 
 
-European Committee
+European Commission
        Funding for the project
 
 SysKonnect
@@ -32,7 +33,6 @@ TO DO:
 
 LAN:
 o      Add support for bactches
-o      Find why big packets flow from I2O box out, but don't want to come in
 o      Find the bug in i2o_set_multicast_list(), which kills interrupt
        handler in i2o_wait_reply()
 o      Add support for Ethernet, Token Ring, AnyLAN, Fibre Channel
index 5d543b1cc86ff41cdd55ab735dca1e9221514110..83634d676868981fb8e468d0bc72fc11af82a824 100644 (file)
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- *     This is an initial test release. Most of the good code was taken
+ *     This is a beta test release. Most of the good code was taken
  *     from the nbd driver by Pavel Machek, who in turn took some of it
  *     from loop.c. Isn't free software great for reusability 8)
  *
  *     Fixes:
  *             Steve Ralston:  Multiple device handling error fixes,
  *                             Added a queue depth.
+ *
+ *     Todo:
+ *             64bit cleanness.
+ *             Remove the queue walk. We can do that better.
  */
 
 #include <linux/major.h>
@@ -31,6 +35,7 @@
 #include <linux/ioctl.h>
 #include <linux/i2o.h>
 #include <linux/blkdev.h>
+#include <linux/blkpg.h>
 #include <linux/malloc.h>
 #include <linux/hdreg.h>
 
@@ -47,7 +52,7 @@
 
 #define MAX_I2OB       16
 
-#define MAX_I2OB_DEPTH 4
+#define MAX_I2OB_DEPTH 8
 
 /*
  *     Some of these can be made smaller later
@@ -61,9 +66,7 @@ static u32 i2ob_max_sectors[MAX_I2OB<<4];
 
 static int i2ob_context;
 
-#ifdef __SMP__
 static spinlock_t i2ob_lock = SPIN_LOCK_UNLOCKED;
-#endif
 
 struct i2ob_device
 {
@@ -175,15 +178,10 @@ static int i2ob_send(u32 m, struct i2ob_device *dev, struct request *req, u32 ba
                msg[5] -= count;
        }
 
-//     printk("Send for %p\n", req);
-
        i2o_post_message(c,m);
        atomic_inc(&queue_depth);
        if(atomic_read(&queue_depth)>old_qd)
-       {
                old_qd=atomic_read(&queue_depth);
-               printk("Depth now %d.\n", old_qd);
-       }
        return 0;
 }
 
@@ -825,7 +823,7 @@ static void i2ob_probe(void)
                                  */
                                 if(i2ob_claim_device(dev, 1)==0)
                                 {
-                                        printk(KERN_INFO "Claimed Dev %x Tid %d Unit %d\n",dev,dev->tid,unit);
+                                        printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit);
                                         i2ob_install_device(c,d,unit);
                                         unit+=16;
  
@@ -836,7 +834,7 @@ static void i2ob_probe(void)
                                          * the block or scsi driver.
                                          */
                                         if (i2ob_claim_device(dev, 0)<0)
-                                                printk(KERN_INFO "Could not unclaim Dev %x Tid %d\n",dev,dev->tid);
+                                                printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid);
  
                                 }
                                 else
@@ -966,14 +964,14 @@ static struct gendisk i2ob_gendisk =
  */
 
 #ifdef MODULE
-#define i2ob_init init_module
+#define i2o_block_init init_module
 #endif
 
-int i2ob_init(void)
+int i2o_block_init(void)
 {
        int i;
 
-       printk("I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n");
+       printk(KERN_INFO "I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n");
        
        /*
         *      Register the block device interfaces
index 8fd93bff96ead49f20c4d3f0235cef6655230a2b..486376c1011ca0119fa49e88286a2a9c7699f1c4 100644 (file)
@@ -5,8 +5,10 @@
  *     
  *     Written by Alan Cox, Building Number Three Ltd
  *
- *      Modified 04/20/199 by Deepak Saxena
+ *      Modified 04/20/1999 by Deepak Saxena
  *         - Added basic ioctl() support
+ *      Modified 06/07/1999 by Deepak Saxena
+ *         - Added software download ioctl (still testing)
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -22,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/miscdevice.h>
-#include <linux/kernel.h>
 #include <linux/mm.h>
 
 #include <asm/uaccess.h>
@@ -210,7 +211,10 @@ int ioctl_gethrt(unsigned long arg)
        workspace = kmalloc(8192, GFP_KERNEL);
        hrt = (pi2o_hrt)workspace;
        if(workspace==NULL)
+       {
+               i2o_unlock_controller(c);
                return -ENOMEM;
+       }
 
        memset(workspace, 0, 8192);
 
@@ -271,7 +275,10 @@ int ioctl_getlct(unsigned long arg)
        workspace = kmalloc(8192, GFP_KERNEL);
        lct = (pi2o_lct)workspace;
        if(workspace==NULL)
+       {
+               i2o_unlock_controller(c);
                return -ENOMEM;
+       }
 
        memset(workspace, 0, 8192);
 
@@ -337,10 +344,14 @@ static int ioctl_parms(unsigned long arg, unsigned int type)
 
        ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL);
        if(!ops)
+       {
+               i2o_unlock_controller(c);
                return -ENOMEM;
+       }
 
        if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen))
        {
+               i2o_unlock_controller(c);
                kfree(ops);
                return -EFAULT;
        }
@@ -352,6 +363,7 @@ static int ioctl_parms(unsigned long arg, unsigned int type)
        res = (u8*)kmalloc(65536, GFP_KERNEL);
        if(!res)
        {
+               i2o_unlock_controller(c);
                kfree(ops);
                return -ENOMEM;
        }
@@ -374,11 +386,12 @@ static int ioctl_parms(unsigned long arg, unsigned int type)
        token = i2o_post_wait(c, kcmd.tid, msg, 9*4, &i2o_cfg_token,10);
        if(token == I2O_POST_WAIT_TIMEOUT)
        {
+               i2o_unlock_controller(c);
                kfree(ops);
                kfree(res);
                return -ETIMEDOUT;
        }
-
+       i2o_unlock_controller(c);
        kfree(ops);
 
        /* 
@@ -448,9 +461,13 @@ int ioctl_html(unsigned long arg)
        {
                query = kmalloc(kcmd.qlen, GFP_KERNEL);
                if(!query)
+               {
+                       i2o_unlock_controller(c);
                        return -ENOMEM;
+               }
                if(copy_from_user(query, kcmd.qbuf, kcmd.qlen))
                {
+                       i2o_unlock_controller(c);
                        printk(KERN_INFO "i2o_config: could not get query\n");
                        kfree(query);
                        return -EFAULT;
@@ -459,7 +476,10 @@ int ioctl_html(unsigned long arg)
 
        res = kmalloc(4096, GFP_KERNEL);
        if(!res)
+       {
+               i2o_unlock_controller(c);
                return -ENOMEM;
+       }
 
        msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid;
        msg[2] = i2o_cfg_context;
@@ -480,11 +500,13 @@ int ioctl_html(unsigned long arg)
        token = i2o_post_wait(c, cmd->tid, msg, 9*4, &i2o_cfg_token, 10);
        if(token == I2O_POST_WAIT_TIMEOUT)
        {
+               i2o_unlock_controller(c);
                kfree(res);
                if(kcmd.qlen) kfree(query);
 
                return -ETIMEDOUT;
        }
+       i2o_unlock_controller(c);
 
        len = strnlen(res, 8192);
        put_user(len, kcmd.reslen);
@@ -500,10 +522,123 @@ int ioctl_html(unsigned long arg)
        return ret;
 }
 
-/* To be written */
 int ioctl_swdl(unsigned long arg)
 {
-       return -ENOSYS;
+       struct i2o_sw_xfer kxfer;
+       struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
+       unsigned char maxfrag = 0, curfrag = 0;
+       unsigned char buffer[8192];
+       u32 msg[MSG_FRAME_SIZE/4];
+       unsigned int token = 0, diff = 0, swlen = 0, swxfer = 0;
+       struct i2o_controller *c;
+       int foo = 0;
+
+       printk("*** foo%d ***\n", foo++);
+       if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+       {
+               printk( "i2o_config: can't copy i2o_sw cmd @ %p\n", pxfer);
+               return -EFAULT;
+       }
+       printk("*** foo%d ***\n", foo++);
+
+       printk("Attempting to copy swlen from %p\n", kxfer.swlen);
+       if(get_user(swlen, kxfer.swlen) < 0)
+       {
+               printk( "i2o_config: can't copy swlen\n");
+               return -EFAULT;
+       }
+       printk("*** foo%d ***\n", foo++);
+
+       maxfrag = swlen >> 13;  // Transfer in 8k fragments
+
+       printk("Attempting to write maxfrag @ %p\n", kxfer.maxfrag);
+       if(put_user(maxfrag, kxfer.maxfrag) < 0)
+       {
+               printk( "i2o_config: can't write maxfrag\n");
+               return -EFAULT;
+       }
+       printk("*** foo%d ***\n", foo++);
+
+       printk("Attempting to write curfrag @ %p\n", kxfer.curfrag);
+       if(put_user(curfrag, kxfer.curfrag) < 0)
+       {
+               printk( "i2o_config: can't write curfrag\n");
+               return -EFAULT;
+       }
+       printk("*** foo%d ***\n", foo++);
+
+       if(!kxfer.buf)
+       {
+               printk( "i2o_config: NULL software buffer\n");
+               return -EFAULT;
+       }
+       printk("*** foo%d ***\n", foo++);
+       
+       // access_ok doesn't check for NULL...
+       if(!access_ok(VERIFY_READ, kxfer.buf, swlen))
+       {
+                printk( "i2o_config: Cannot read sw buffer\n");
+                return -EFAULT;
+       }
+       printk("*** foo%d ***\n", foo++);
+
+       c = i2o_find_controller(kxfer.iop);
+       if(!c)
+               return -ENXIO;
+       printk("*** foo%d ***\n", foo++);
+
+       msg[0]= EIGHT_WORD_MSG_SIZE| SGL_OFFSET_7;
+       msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
+       msg[2]= (u32)cfg_handler.context;
+       msg[3]= 0;
+       msg[4]= ((u32)kxfer.dl_flags)<<24|((u32)kxfer.sw_type)<<16|((u32)maxfrag)<<8|((u32)curfrag);
+       msg[5]= swlen;
+       msg[6]= kxfer.sw_id;
+       msg[7]= (0xD0000000 | 8192);
+       msg[8]= virt_to_phys(buffer);
+
+       printk("*** foo%d ***\n", foo++);
+
+       //
+       // Loop through all fragments but last and transfer them...
+       // We already checked memory, so from now we assume it's all good
+       //
+       for(curfrag = 0; curfrag < maxfrag-1; curfrag++)
+       {
+               printk("Transfering fragment %d\n", curfrag);
+
+               msg[4] |= (u32)curfrag;
+
+               __copy_from_user(buffer, kxfer.buf, 8192);
+               swxfer += 8129;
+
+               // Yes...that's one minute, but the spec states that
+               // transfers take a long time, and I've seen just how
+               // long they can take.
+               token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_cfg_token,60);
+               if( token == I2O_POST_WAIT_TIMEOUT )    // Something very wrong
+               {
+                       printk("Timeout downloading software");
+                       return -ETIMEDOUT;
+               }
+
+               __put_user(curfrag, kxfer.curfrag);
+       }
+
+       // Last frag is special case since it's not exactly 8K
+       diff = swlen - swxfer;
+       msg[4] |= (u32)maxfrag;
+       msg[7] = (0xD0000000 | diff);
+       __copy_from_user(buffer, kxfer.buf, 8192);
+       token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_cfg_token,60);
+       if( token == I2O_POST_WAIT_TIMEOUT )    // Something very wrong
+       {
+               printk("Timeout downloading software");
+               return -ETIMEDOUT;
+       }
+       __put_user(curfrag, kxfer.curfrag);
+
+       return 0;
 }
 
 /* To be written */
@@ -557,7 +692,7 @@ static struct miscdevice i2o_miscdev = {
 #ifdef MODULE
 int init_module(void)
 #else
-int i2o_config_init(void)
+__init int i2o_config_init(void)
 #endif
 {
        printk(KERN_INFO "i2o configuration manager v 0.02\n");
index 7945c79612c1102c641197ab0c8d1046257e91a4..dc5c2e3843b61a3319dcffb8d56f64240dd779e1 100644 (file)
  *     A lot of the I2O message side code from this is taken from the
  *     Red Creek RCPCI45 adapter driver by Red Creek Communications
  *
- *     Some fixes and cleanup by Philipp Rumpf
- *
- *     Additional fixes by Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- *     
+ *     Fixes by Philipp Rumpf
+ *              Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *              Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
  */
  
 #include <linux/module.h>
 
 #include "i2o_lan.h"
 
+
 /*
  *     Size of the I2O module table
  */
  
-
 static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
 static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
 int i2o_num_controllers = 0;
-
+static int core_context = 0;
+static int reply_flag = 0;
 
 extern int i2o_online_controller(struct i2o_controller *c);
+static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
+                          struct i2o_message *);
+
+/* Message handler */ 
+static struct i2o_handler i2o_core_handler =
+{
+       (void *)i2o_core_reply,
+       "I2O core layer",
+       0
+};
 
 /*
  *     I2O configuration spinlock. This isnt a big deal for contention
  *     so we have one only
  */
  
-#ifdef __SMP__
 static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED;
+
+void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
+                   struct i2o_message *m)
+{
+       u32 *msg=(u32 *)m;
+       u32 *flag = (u32 *)msg[3];
+
+#if 0
+       i2o_report_status(KERN_INFO, "i2o_core", msg);
 #endif
+       
+       if (msg[0] & (1<<13)) // Fail bit is set
+        {
+                printk(KERN_ERR "IOP failed to process the msg:\n");
+                printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n",
+                      (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] &
+                      0xFFF);
+                printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n"
+                      "LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
+                      msg[4] >> 24, (msg[4] >> 16) & 0xFF,
+                      (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+                printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
+                      msg[5] >> 16, msg[5] & 0xFFF);
+                return;
+        }
+
+       if (msg[4] >> 24)
+       {
+               i2o_report_status(KERN_WARNING, "i2o_core", msg);
+               *flag = -(msg[4] & 0xFFFF);
+       }
+       else
+               *flag = I2O_POST_WAIT_OK;
+}
 
 /*
  *     Install an I2O handler - these handle the asynchronous messaging
@@ -179,10 +221,11 @@ int i2o_install_controller(struct i2o_controller *c)
 int i2o_delete_controller(struct i2o_controller *c)
 {
        struct i2o_controller **p;
-       
+
        spin_lock(&i2o_configuration_lock);
        if(atomic_read(&c->users))
        {
+               printk("Someones using controller iop%d\n", c->unit);
                spin_unlock(&i2o_configuration_lock);
                return -EBUSY;
        }
@@ -195,21 +238,41 @@ int i2o_delete_controller(struct i2o_controller *c)
                        return -EBUSY;
                }
        }
-       c->destructor(c);
-       
+//     c->destructor(c); /* We dont want to free the IRQ yet */
+
        p=&i2o_controller_chain;
-       
+
+       /* Send first SysQuiesce to other IOPs */
+       while(*p)
+       {
+               if(*p!=c)
+                       if(i2o_quiesce_controller(*p)<0)
+                               printk(KERN_INFO "Unable to quiesce iop%d\n",
+                                      (*p)->unit);
+               p=&((*p)->next);
+       }
+
+       p=&i2o_controller_chain;
+
        while(*p)
        {
                if(*p==c)
                {
-                       /* Prepare for restart */
-//                     i2o_clear_controller(c);
+                       /* Ask the IOP to switch to HOLD state */
+                       if (i2o_clear_controller(c) < 0)
+                               printk("Unable to clear iop%d\n", c->unit);
+
+                       /* Release IRQ */
+                       c->destructor(c);
 
                        *p=c->next;
                        spin_unlock(&i2o_configuration_lock);
                        if(c->page_frame);
                                kfree(c->page_frame);
+                       if(c->hrt)
+                               kfree(c->hrt);
+                       if(c->lct)
+                               kfree(c->lct);
                        i2o_controllers[c->unit]=NULL;
                        kfree(c);
                        i2o_num_controllers--;
@@ -317,7 +380,7 @@ const char *i2o_get_class_name(int class)
                "Device Driver Module",
                "Block Device",
                "Tape Device",
-               "LAN Inteface",
+               "LAN Interface",
                "WAN Interface",
                "Fibre Channel Port",
                "Fibre Channel Device",
@@ -384,7 +447,7 @@ u32 i2o_wait_message(struct i2o_controller *c, char *why)
        {
                if((jiffies-time)>=5*HZ)
                {
-                       printk(KERN_ERR "%s: Timeout waiting for message to send %s.\n", 
+                       printk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", 
                                c->name, why);
                        return 0xFFFFFFFF;
                }
@@ -396,7 +459,7 @@ u32 i2o_wait_message(struct i2o_controller *c, char *why)
 
 
 /*
- *     Wait up to 5 seconds for a reply to be available.
+ *     Wait up to timeout seconds for a reply to be available.
  */
  
 u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout)
@@ -418,173 +481,6 @@ u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout)
 }
        
 
-
-/* Quiesce and clear IOP  */
-int i2o_quiesce_controller(struct i2o_controller *c)
-{
-       u32 m;
-       u32 *msg;
-
-       /* now we stop receiving messages to this IOP */
-       m=i2o_wait_message(c, "Quiesce IOP");
-       if(m==0xFFFFFFFF)
-               return -ETIMEDOUT;
-
-       msg=(u32 *)(c->mem_offset+m);
-
-       msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-       msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2]=0;
-       msg[3]=0;
-
-       printk(KERN_DEBUG "Sending SysQuiesce to %s\n", c->name);
-       i2o_post_message(c,m);
-
-       m=i2o_wait_reply(c, "System Quiesce", 20);
-
-       if (m==0xFFFFFFFF)
-               return -ETIMEDOUT;
-       /* Someday we should check return status... */
-
-       return 0;
-}
-
-int i2o_clear_controller(struct i2o_controller *c)
-{
-       u32 m;
-       u32 *msg;
-
-       m=i2o_wait_message(c, "IOP Clear");
-       if (m==0xFFFFFFFF)
-               return -ETIMEDOUT;
-
-       msg=(u32 *)(c->mem_offset+m);
-
-       msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-       msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2]=0;
-       msg[3]=0;
-
-       printk(KERN_DEBUG "Sending IOPClear to %s\n", c->name);
-       i2o_post_message(c, m);
-
-       m=i2o_wait_reply(c, "IOP Clear timeout", 5);
-
-       if(m==0xFFFFFFFF)
-               return -ETIMEDOUT;
-
-       return 0;
-}
-
-
-/*
- *     i2o table walking. We just provide a single element retrieve. You can
- *     all sorts of fancy lookups in I2O but we have no performance critical
- *     lookups so why write all the code for it.
- */
-#if 0
-static int i2o_query_table_polled(struct i2o_controller *c, int tid, void *buf, int buflen, 
-       int group, int field, u32 *key, int keylen)
-{
-       u32 m;
-       u32 *msg;
-       u16 op[64];
-       u32 *p;
-       int i;
-       u32 *rbuf;
-
-       op[0]=1;                        /* One Operation */
-       op[1]=0;                        /* PAD */
-       op[2]=2;                        /* LIST_GET */
-       op[3]=group;                    /* group number */
-       op[4]=1;                        /* 1 field */
-       op[5]=field;                    /* Field number */
-       op[6]=1;                        /* Key count */
-       memcpy(op+7, key, keylen);      /* Key */
-       
-       m=i2o_wait_message(c, "I2O query table.");
-       if(m==0xFFFFFFFF)
-       {       
-               return -ETIMEDOUT;
-       }
-       
-       msg=(u32 *)(c->mem_offset+m);
-       
-       rbuf=kmalloc(buflen+32, GFP_KERNEL);
-       if(rbuf==NULL)
-       {
-               printk(KERN_ERR "No free memory for table read.\n");
-               return -ENOMEM;
-       }
-       msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-       msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid;
-       msg[2]=0;                       /* Context */
-       msg[3]=0;
-       msg[4]=0;
-       msg[5]=0x54000000|(14);
-       msg[6]=virt_to_bus(op);
-       msg[7]=0xD0000000|(32+buflen);
-       msg[8]=virt_to_bus(rbuf);
-
-       i2o_post_message(c,m);
-       barrier();
-       
-       /*
-        *      Now wait for a reply
-        */
-        
-       
-       m=i2o_wait_reply(c, "Table read timeout", 5);
-       
-       if(m==0xFFFFFFFF)
-       {
-               kfree(rbuf);
-               return -ETIMEDOUT;
-       }
-       
-       msg = (u32 *)bus_to_virt(m);
-
-       if(msg[4]>>24)
-       {
-               i2o_report_status(KERN_WARNING, "i2o_core",
-                                 (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-                                 msg[4]&0xFFFF);
-       }
-       
-       p=rbuf;
-
-       /* Ok 'p' is the reply block - lets see what happened */
-       /* p0->p2 are the header */
-       
-       /* FIXME: endians - turn p3 to little endian */
-       
-       i=(p[0]&0xFFFF)<<2;             /* Message size */
-       if(i<buflen)
-               buflen=i;
-       
-       /* Do we have an error block ? */
-       if(p[0]&0xFF000000)
-       {
-               printk(KERN_ERR "%s: error in field read.\n",
-                       c->name);
-               kfree(rbuf);
-               return -EBADR;
-       }
-               
-       /* p[1] holds the more flag and row count - we dont care */
-       
-       /* Ok it worked p[2]-> hold the data */
-       memcpy(buf,  p+2, buflen);
-       
-       kfree(rbuf);
-       
-       /* Finally return the message */
-       I2O_REPLY_WRITE32(c,m);
-       return buflen;
-}
-#endif
-
 static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf, int buflen, 
        int group, int field)
 {
@@ -602,7 +498,7 @@ static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf,
        op[4]=1;                        /* 1 field */
        op[5]=field;                    /* Field number */
 
-       m=i2o_wait_message(c, "I2O query scalar.");
+       m=i2o_wait_message(c, "ParamsGet");
        if(m==0xFFFFFFFF)
        {       
                return -ETIMEDOUT;
@@ -634,8 +530,7 @@ static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf,
         *      Now wait for a reply
         */
         
-       
-       m=i2o_wait_reply(c, "Scalar read timeout", 5);
+       m=i2o_wait_reply(c, "ParamsGet", 5);
        
        if(m==0xFFFFFFFF)
        {
@@ -646,9 +541,7 @@ static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf,
        msg = (u32 *)bus_to_virt(m);
        if(msg[4]>>24)
        {
-               i2o_report_status(KERN_WARNING, "i2o_core",
-                                 (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-                                 msg[4]&0xFFFF);
+               i2o_report_status(KERN_WARNING, "i2o_core", msg);
        }
        
        p=rbuf;
@@ -729,9 +622,10 @@ void i2o_report_controller_unit(struct i2o_controller *c, int unit)
  *     This is full of endianisms!
  */
  
-static int i2o_parse_hrt(struct i2o_controller *c, u8 *p)
+static int i2o_parse_hrt(struct i2o_controller *c)
 {
-       u32 *rows=(u32 *)p;
+       u32 *rows=c->hrt;
+       u8 *p=(u8 *)c->hrt;
        u8 *d;
        int count;
        int length;
@@ -818,7 +712,7 @@ static int i2o_parse_hrt(struct i2o_controller *c, u8 *p)
  *     on the board. Most of the stuff isn't interesting to us. 
  */
 
-static int i2o_parse_lct(struct i2o_controller *c, u32 *lct)
+static int i2o_parse_lct(struct i2o_controller *c)
 {
        int i;
        int max;
@@ -826,11 +720,18 @@ static int i2o_parse_lct(struct i2o_controller *c, u32 *lct)
        u32 *p;
        struct i2o_device *d;
        char str[22];
+       u32 *lct=(u32 *)c->lct;
 
        max=lct[0]&0xFFFF;
        
        max-=3;
        max/=9;
+
+       if(max==0)
+       {
+               printk(KERN_ERR "LCT is empty????\n");
+               return -1;
+       }
        
        printk(KERN_INFO "LCT has %d entries.\n", max);
        
@@ -891,37 +792,61 @@ static int i2o_parse_lct(struct i2o_controller *c, u32 *lct)
        return 0;
 }
 
-#if 0
-/* Reset the IOP to sane state */
-/* I think we need handler for core (or executive class in I2O terms) */
-static int i2o_reset_adapter(struct i2o_controller *c)
+/* Quiesce IOP */
+int i2o_quiesce_controller(struct i2o_controller *c)
 {
-       u32 m;
-       u8 *work8;
-       u32 *msg;
-       long time;
+       u32 msg[4];
 
-       /* First stop extral operations */
-       m=i2o_wait_message(c, "quiesce IOP");
-       if(m==0xFFFFFFFF)
-               return -ETIMEDOUT;
-       
-       msg=(u32 *)(c->mem_offset+m);
-                               
        msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2]=0;
-       msg[3]=0;
+       msg[2]=core_context;
+       msg[3]=(u32)&reply_flag;
 
-       i2o_post_message(c,m);
+       return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10);
+}
 
-       m=i2o_wait_reply(c, "System Quiesce timeout", 5);
 
-       if(m==0xFFFFFFFF)
-               return -ETIMEDOUT;
+int i2o_clear_controller(struct i2o_controller *c)
+{
+       u32 msg[4];
+
+       /* First stop external operations for this IOP */
+       if(i2o_quiesce_controller(c)<0)
+               printk(KERN_INFO "Unable to quiesce iop%d\n", c->unit);
+       else
+               printk(KERN_INFO "Iop%d quiesced\n", c->unit);
+
+       /* Then clear the IOP */
+       msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+       msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
+       msg[2]=core_context;
+       msg[3]=(u32)&reply_flag;
+
+       return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10);
+}
+
+
+/* Reset the IOP to sane state */
+static int i2o_reset_controller(struct i2o_controller *c)
+{
+       u32 m;
+       u8 *work8;
+       u32 *msg;
+       long time;
+       struct i2o_controller *iop;
+
+       /* First stop external operations */
+       for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
+       {
+               if(i2o_quiesce_controller(iop)<0)
+                       printk(KERN_INFO "Unable to quiesce iop%d\n",
+                              iop->unit);
+               else
+                       printk(KERN_DEBUG "%s quiesced\n", iop->name);
+       }
 
        /* Then reset the IOP */
-       m=i2o_wait_message(c, "reset IOP");
+       m=i2o_wait_message(c, "AdapterReset");
        if(m==0xFFFFFFFF)
                return -ETIMEDOUT;
 
@@ -937,8 +862,8 @@ static int i2o_reset_adapter(struct i2o_controller *c)
        
        msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2]=0;
-       msg[3]=0;
+       msg[2]=core_context;
+       msg[3]=(u32)&reply_flag;
        msg[4]=0;
        msg[5]=0;
        msg[6]=virt_to_phys(work8);
@@ -949,8 +874,10 @@ static int i2o_reset_adapter(struct i2o_controller *c)
        /* Wait for a reply */
        time=jiffies;
 
-       while(work8[0]==0x01) {
-               if((jiffies-time)>=5*HZ) {
+       while(work8[0]==0x01)
+       {
+               if((jiffies-time)>=5*HZ)
+               {
                        printk(KERN_ERR "IOP reset timeout.\n");
                        kfree(work8);
                        return -ETIMEDOUT;
@@ -964,113 +891,186 @@ static int i2o_reset_adapter(struct i2o_controller *c)
 
        return 0;
 }
-#endif
 
-/*
- *     Bring an I2O controller into HOLD state. See the 1.5
- *     spec. Basically we go
- *
- *     Wait for the message queue to initialise. 
- *     If it didnt -> controller is dead
- *     
- *     Send a get status using the message queue
- *     Poll for a reply block 88 bytes long
- *
- *     Send an initialise outbound queue
- *     Poll for a reply
- *
- *     Post our blank messages to the queue FIFO
- *
- *     Send GetHRT, Parse it
- */
 
-int i2o_activate_controller(struct i2o_controller *c)
+int i2o_status_get(struct i2o_controller *c)
 {
        long time;
        u32 m;
-       u8 *workspace;
        u32 *msg;
-       int i;
-       
-       printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n", (u32)c->mem_phys);
+       u8 *status_block;
 
-       /* First reset the IOP to sane state */
-//     i2o_reset_adapter(c)
-       
-       m=i2o_wait_message(c, "initialise");
+       status_block=(void *)kmalloc(88, GFP_KERNEL);
+       if(status_block==NULL)
+       {
+               printk(KERN_ERR "StatusGet failed - no free memory.\n");
+               return -ENOMEM;
+       }
+
+       m=i2o_wait_message(c, "StatusGet");
        if(m==0xFFFFFFFF)
                return -ETIMEDOUT;
 
        msg=(u32 *)(c->mem_offset+m);
-       
-       workspace = (void *)kmalloc(88, GFP_KERNEL);
-       if(workspace==NULL)
-       {
-               printk(KERN_ERR "IOP initialisation failed - no free memory.\n");
-               return -ENOMEM;
-       }
-       
-       memset(workspace, 0, 88);
-       
+
        msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2]=0;
+       msg[2]=core_context;
        msg[3]=0;
        msg[4]=0;
        msg[5]=0;
-       msg[6]=virt_to_phys(workspace);
+       msg[6]=virt_to_phys(status_block);
        msg[7]=0;       /* 64bit host FIXME */
        msg[8]=88;
 
        i2o_post_message(c,m);
 
-       /*
-        *      Wait for a reply
-        */
-
+       /* Wait for a reply */
        time=jiffies;
                 
-       while(workspace[87]!=0xFF)
+       while(status_block[87]!=0xFF)
        {
                if((jiffies-time)>=5*HZ)
                {
                        printk(KERN_ERR "IOP get status timeout.\n");
-                       kfree(workspace);
                        return -ETIMEDOUT;
                }
                schedule();
                barrier();
        }
        
-       /*
-        *      Ok the reply has arrived. Fill in the important stuff
-        */
-        
-       c->status = workspace[10];
-       c->i2oversion = (workspace[9]>>4)&0xFF;
-       c->inbound_size = (workspace[12]|(workspace[13]<<8))*4; /* 32bit words */
-       
+       /* Ok the reply has arrived. Fill in the important stuff */
+       c->status = status_block[10];
+       c->i2oversion = (status_block[9]>>4)&0xFF;
+       c->inbound_size = (status_block[12]|(status_block[13]<<8))*4;
+
+       return 0;
+}
+
+
+int i2o_hrt_get(struct i2o_controller *c)
+{
+       u32 m;
+       u32 *msg;
+
+       c->hrt=kmalloc(2048, GFP_KERNEL);
+       if(c->hrt==NULL)
+       {
+               printk(KERN_ERR "IOP init failed; no memory.\n");
+               return -ENOMEM;
+       }
+
+       m=i2o_wait_message(c, "HRTGet");
+       if(m==0xFFFFFFFF)
+               return -ETIMEDOUT;
+
+       msg=(u32 *)(c->mem_offset+m);
+
+       msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
+       msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
+       msg[2]= core_context;
+       msg[3]= 0x0;                            /* Transaction context */
+       msg[4]= (0xD0000000 | 2048);            /* Simple transaction , 2K */
+       msg[5]= virt_to_phys(c->hrt);           /* Dump it here */
+
+       i2o_post_message(c,m);
+
+       barrier();
+
+       /* Now wait for a reply */
+       m=i2o_wait_reply(c, "HRTGet", 5);
+
+       if(m==0xFFFFFFFF)
+               return -ETIMEDOUT;
+
+       msg=(u32 *)bus_to_virt(m);
+
+       if(msg[4]>>24)
+               i2o_report_status(KERN_WARNING, "i2o_core", msg);
+
+       I2O_REPLY_WRITE32(c,m);
+
+       return 0;
+}
+
+
+/*
+ *     Bring an I2O controller into HOLD state. See the 1.5
+ *     spec. Basically we go
+ *
+ *     Wait for the message queue to initialise. 
+ *     If it didnt -> controller is dead
+ *     
+ *     Send a get status using the message queue
+ *     Poll for a reply block 88 bytes long
+ *
+ *     Send an initialise outbound queue
+ *     Poll for a reply
+ *
+ *     Post our blank messages to the queue FIFO
+ *
+ *     Send GetHRT, Parse it
+ */
+
+int i2o_activate_controller(struct i2o_controller *c)
+{
+       long time;
+       u32 m;
+       u8 *workspace;
+       u32 *msg;
+       int i;
+       int ret;
+
+       printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n",
+              (u32)c->mem_phys);
+
+       if((ret=i2o_status_get(c)))
+               return ret;
+
+       if(c->status == ADAPTER_STATE_FAULTED) /* not likely to be seen */
+       {
+               printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
+                      c->unit);
+               return -1;
+       }
+
        /*
         *      If the board is running, reset it - we have no idea
         *      what kind of a mess the previous owner left it in.
         */
-        
-//     if(c->status == ADAPTER_STATE_OPERATIONAL)
-//             i2o_reset_device(c);
+       if(c->status == ADAPTER_STATE_HOLD ||
+          c->status == ADAPTER_STATE_READY ||
+          c->status == ADAPTER_STATE_OPERATIONAL ||
+          c->status == ADAPTER_STATE_FAILED)
+       {
+               if((ret=i2o_reset_controller(c)))
+                       return ret;
 
-       
-       m=i2o_wait_message(c, "initqueue");
+               if((ret=i2o_status_get(c)))
+                       return ret;
+       }
+
+       workspace = (void *)kmalloc(88, GFP_KERNEL);
+       if(workspace==NULL)
+       {
+               printk(KERN_ERR "IOP initialisation failed - no free memory.\n");
+               return -ENOMEM;
+       }
+
+       memset(workspace, 0, 88);
+
+       m=i2o_wait_message(c, "OutboundInit");
        if(m==0xFFFFFFFF)
        {       
                kfree(workspace);
                return -ETIMEDOUT;
        }
-       
+
        msg=(u32 *)(c->mem_offset+m);
 
        msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
        msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
-       msg[2]= 0;
+       msg[2]= core_context;
        msg[3]= 0x0106;                 /* Transaction context */
        msg[4]= 4096;                   /* Host page frame size */
        msg[5]= MSG_FRAME_SIZE<<16|0x80;        /* Outbound msg frame size and Initcode */
@@ -1099,9 +1099,11 @@ int i2o_activate_controller(struct i2o_controller *c)
                schedule();
                barrier();
        }
-       
+
        kfree(workspace);
 
+       /* TODO: v2.0: Set Executive class group 000Bh - OS Operating Info */
+
        c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
        if(c->page_frame==NULL)
        {
@@ -1124,64 +1126,71 @@ int i2o_activate_controller(struct i2o_controller *c)
         *      Now we need the Hardware Resource Table. We must ask for
         *      this next we can't issue random messages yet.
         */
+       ret=i2o_hrt_get(c);
+       if(ret)
+               return ret;
 
+       ret=i2o_parse_hrt(c);
+       if(ret)
+               return ret;
 
-       workspace=kmalloc(2048, GFP_KERNEL);
-       if(workspace==NULL)
+       return i2o_online_controller(c);
+//     i2o_report_controller_unit(c, ADAPTER_TID);
+}
+
+
+int i2o_lct_get(struct i2o_controller *c)
+{
+       u32 m;
+       u32 *msg;
+
+       m=i2o_wait_message(c, "LCTNotify");
+
+       if(m==0xFFFFFFFF)
+               return -ETIMEDOUT;
+
+       msg=(u32 *)(c->mem_offset+m);
+
+       c->lct = kmalloc(8192, GFP_KERNEL);
+       if(c->lct==NULL)
        {
-               printk(KERN_ERR "IOP init failed; no memory.\n");
+               msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+               msg[1]= HOST_TID<<12|ADAPTER_TID;       /* NOP */
+               i2o_post_message(c,m);
+               printk(KERN_ERR "No free memory for i2o controller buffer.\n");
                return -ENOMEM;
        }
        
-       m=i2o_wait_message(c, "I2O HRT timeout.");
-       if(m==0xFFFFFFFF)
-       {       
-               kfree(workspace);
-               return -ETIMEDOUT;
-       }
+       memset(c->lct, 0, 8192);
        
-       msg=(u32 *)(c->mem_offset+m);
+       msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+       msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+       msg[2] = 0;             /* Context not needed */
+       msg[3] = 0;
+       msg[4] = 0xFFFFFFFF;    /* All devices */
+       msg[5] = 0x00000000;    /* Report now */
+       msg[6] = 0xD0000000|8192;
+       msg[7] = virt_to_bus(c->lct);
 
-       msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
-       msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
-       msg[2]= 0x0;
-       msg[3]= 0x0;                            /* Transaction context */
-       msg[4]= (0xD0000000 | 2048);            /* Simple transaction , 2K */
-       msg[5]= virt_to_phys(workspace);        /* Dump it here */
-       *((u32 *)workspace)=0xFFFFFFFF;
-       
        i2o_post_message(c,m);
-       
+
        barrier();
-       
-       /*
-        *      Now wait for a reply
-        */
-        
-       m=i2o_wait_reply(c, "HRT table", 5);
-        
+
+       /* Now wait for a reply */
+       m=i2o_wait_reply(c, "LCTNotify", 5);
+
        if(m==0xFFFFFFFF)
-       {
-               kfree(workspace);
                return -ETIMEDOUT;
-       }
-       
+
        msg=(u32 *)bus_to_virt(m);
-       
+
+       /* TODO: Check TableSize for big LCTs and send new ExecLctNotify 
+        * with bigger workspace */
+
        if(msg[4]>>24)
-       {
-               i2o_report_status(KERN_WARNING, "i2o_core",
-                                 (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-                                 msg[4]&0xFFFF);
-       }
-       I2O_REPLY_WRITE32(c,m);
-       
-       i2o_parse_hrt(c, workspace);
-       
-       kfree(workspace);
-       
-       return i2o_online_controller(c);
-//     i2o_report_controller_unit(c, ADAPTER_TID);
+               i2o_report_status(KERN_ERR, "i2o_core", msg);
+
+       return 0;
 }
 
 
@@ -1196,7 +1205,7 @@ int i2o_online_controller(struct i2o_controller *c)
        u32 systab[32];
        u32 privmem[2];
        u32 privio[2];
-       u32 *workspace;
+       int ret;
        
        systab[0]=1;
        systab[1]=0;
@@ -1216,7 +1225,7 @@ int i2o_online_controller(struct i2o_controller *c)
        privio[0]=c->priv_io;           /* Private I/O address */
        privio[1]=c->priv_io_size;
        
-       m=i2o_wait_message(c, "SetSysTab");
+       m=i2o_wait_message(c, "SysTabSet");
        if(m==0xFFFFFFFF)
                return -ETIMEDOUT;
        
@@ -1249,7 +1258,7 @@ int i2o_online_controller(struct i2o_controller *c)
         */
         
         
-       m=i2o_wait_reply(c, "Systab read", 5);
+       m=i2o_wait_reply(c, "SysTabSet", 5);
                
        if(m==0xFFFFFFFF)
                return -ETIMEDOUT;
@@ -1258,9 +1267,7 @@ int i2o_online_controller(struct i2o_controller *c)
        
        if(msg[4]>>24)
        {
-               i2o_report_status(KERN_ERR, "i2o_core",
-                                 (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-                                 msg[4]&0xFFFF);
+               i2o_report_status(KERN_ERR, "i2o_core", msg);
        }
        I2O_REPLY_WRITE32(c,m);
        
@@ -1268,7 +1275,7 @@ int i2o_online_controller(struct i2o_controller *c)
         *      Finally we go online
         */
         
-       m=i2o_wait_message(c, "No message for SysEnable");
+       m=i2o_wait_message(c, "SysEnable");
        
        if(m==0xFFFFFFFF)
                return -ETIMEDOUT;
@@ -1289,7 +1296,7 @@ int i2o_online_controller(struct i2o_controller *c)
         */
         
        
-       m=i2o_wait_reply(c, "Enable", 240);
+       m=i2o_wait_reply(c, "SysEnable", 240);
 
        if(m==0xFFFFFFFF)
                return -ETIMEDOUT;
@@ -1298,73 +1305,25 @@ int i2o_online_controller(struct i2o_controller *c)
        
        if(msg[4]>>24)
        {
-               i2o_report_status(KERN_ERR, "i2o_core",
-                                 (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-                                 msg[4]&0xFFFF);
+               i2o_report_status(KERN_ERR, "i2o_core", msg);
        }
        I2O_REPLY_WRITE32(c,m);
        
        /*
         *      Grab the LCT, see what is attached
         */
-        
-       m=i2o_wait_message(c, "No message for LCT");
-       
-       if(m==0xFFFFFFFF)
-               return -ETIMEDOUT;
-       
-       msg=(u32 *)(c->mem_offset+m);
-       
-       
-       workspace = kmalloc(8192, GFP_KERNEL);
-       if(workspace==NULL)
-       {
-               msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-               msg[1]= HOST_TID<<12|ADAPTER_TID;       /* NOP */
-               i2o_post_message(c,m);
-               printk(KERN_ERR "No free memory for i2o controller buffer.\n");
-               return -ENOMEM;
-       }
-       
-       memset(workspace, 0, 8192);
-       
-       msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_6;
-       msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
-       msg[2] = 0;             /* Context not needed */
-       msg[3] = 0;
-       msg[4] = 0xFFFFFFFF;    /* All devices */
-       msg[5] = 0x00000000;    /* Report now */
-       msg[6] = 0xD0000000|8192;
-       msg[7] = virt_to_bus(workspace);
-       
-       i2o_post_message(c,m);
-       
-       barrier();
 
-       /*
-        *      Now wait for a reply
-        */
-        
-       m=i2o_wait_reply(c, "LCT", 5);
-       
-       if(m==0xFFFFFFFF)
+       ret=i2o_lct_get(c);
+       if(ret)
        {
-               kfree(workspace);
-               return -ETIMEDOUT;
+               /* Maybe we should do also sthg else */
+               return ret;
        }
-       
-       msg=(u32 *)bus_to_virt(m);
-       
-       if(msg[4]>>24)
-       {
-               i2o_report_status(KERN_ERR, "i2o_core",
-                                 (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-                                 msg[4]&0xFFFF);
-       }
-       
-       i2o_parse_lct(c, workspace);
-       kfree(workspace);
-       
+
+       ret=i2o_parse_lct(c);
+       if(ret)
+               return ret;
+
        I2O_REPLY_WRITE32(c,m);
        
        return 0;
@@ -1417,16 +1376,21 @@ int i2o_post_wait(struct i2o_controller *c, int tid, u32 *data, int len, int *fl
        *flag = 0;
                
        if(i2o_post_this(c, tid, data, len))
-               return -1;
+               return I2O_POST_WAIT_TIMEOUT;
                
        while(!*flag && (jiffies-t)<timeout*HZ)
        {
                schedule();
                mb();
        }
-       if(*flag <= 0)
-               return -1;
-       return 0;
+
+       if (*flag < 0)
+               return *flag; /* DetailedStatus */
+
+       if (*flag == 0)
+               return I2O_POST_WAIT_TIMEOUT;
+       
+       return I2O_POST_WAIT_OK;
 }
 
 /*
@@ -1452,247 +1416,262 @@ int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, i
        return i2o_post_wait(c, tid, msg, 20, flag,2);
 }
 
-/*
- *     Query a scalar value
+/*     Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
+ *
+ *     This function can be used for all UtilParamsGet/Set operations.
+ *     The OperationBlock is given in opblk-buffer, 
+ *     and results are returned in resblk-buffer.
+ *     Note that the minimum sized resblk is 8 bytes and contains
+ *     ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
  */
-
-int i2o_query_scalar(struct i2o_controller *c, int tid, int context,
-                    int group, int field, void *buf, int buflen, int *flag)
+int i2o_issue_params(int cmd, 
+                struct i2o_controller *iop, int tid, int context, 
+                void *opblk, int oplen, void *resblk, int reslen, 
+                int *flag)
 {
-       u16 *op;
-       u32 *bl;
-       u32 msg[9];
-
-       bl=kmalloc(buflen+64, GFP_KERNEL); /* Enough space for error replys */
-       if(bl==NULL)
+        u32 msg[9]; 
+       u8 *res = (u8 *)resblk;
+       int res_count;
+       int blk_size;
+       int bytes;
+       int wait_status;
+
+        msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
+        msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
+        msg[2] = context | 0x80000000;
+        msg[3] = (u32)flag;
+        msg[4] = 0;
+        msg[5] = 0x54000000 | oplen;   /* OperationBlock */
+        msg[6] = virt_to_bus(opblk);
+        msg[7] = 0xD0000000 | reslen;  /* ResultBlock */
+        msg[8] = virt_to_bus(resblk);
+
+        wait_status = i2o_post_wait(iop, tid, msg, sizeof(msg), flag, 10);
+       if (wait_status < 0)       
+                return wait_status;    /* -DetailedStatus */
+
+        if (res[1]&0x00FF0000)         /* BlockStatus != SUCCESS */
+        {
+                printk(KERN_WARNING "%s - Error:\n  ErrorInfoSize = 0x%02x, " 
+                       "BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+                        (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
+                                                         : "PARAMS_GET",   
+                        res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
+                return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
+        }
+
+       res_count = res[0] & 0xFFFF; /* # of resultblocks */
+       bytes = 4; 
+       res  += 4;
+       while (res_count--)
        {
-               printk(KERN_ERR "i2o: no memory for query buffer.\n");
-               return -ENOMEM;
+               blk_size = (res[0] & 0xFFFF) << 2;
+               bytes   += blk_size;
+               res     += blk_size;
        }
 
-       op = (u16*)bl;
-       op[0]=1;                        /* One Operation */
-       op[1]=0;                        /* PAD */
-       op[2]=1;                        /* FIELD_GET */
-       op[3]=group;                    /* group number */
-       op[4]=1;                        /* field count, default = 1 */
-       op[5]=field;                    /* field index */
-
-       if(field == -1)
-       /* Single value or the whole group? */
-       {
-               op[4]=-1;
-               op[5]=0;
-       }
-
-       msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-       msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid;
-       msg[2]=context|0x80000000;      /* So we can pick it out */
-       msg[3]=(u32)flag;
-       msg[4]=0;
-       msg[5]=0x54000000|12;
-       msg[6]=virt_to_bus(bl);
-               /*
-                *      There are 8 bytes of "overhead" required to pull in
-                *      a Params ResultsList; 2 bytes for ResultCount
-                *      (which should have value=1), plus 2 bytes for pad,
-                *      plus 2 bytes for BlockSize, plus 1 byte BlockStatus,
-                *      plus 1 byte ErrorInfoSize (8 bytes total overhead).
-                *      This is followed finally by actual result value(s).
-                *
-                *      Tell the IOP to return 8 + buflen bytes.
-                */
-       msg[7]=0xD0000000|(8+buflen);
-       msg[8]=virt_to_bus(bl+3);
-       
-       bl[3]=0xFCFCFCFC;               // Pad,ResultCount
-       bl[4]=0xFAFAFCFC;               // ErrorInfoSize,BlockStatus,BlockSize
-
-       /*
-        *      Post the message and await a reply
-        */
+        return bytes; /* total sizeof Result List in bytes */
+}
 
-       if (i2o_post_wait(c, tid, msg, sizeof(msg), flag,2) < 0)
-       {
-               kfree(bl);              
-               return -1;
-       }
+/*
+ *      Query one scalar group value or a whole scalar group.
+ */                    
+int i2o_query_scalar(struct i2o_controller *iop, int tid, int context, 
+                     int group, int field, void *buf, int buflen, int *flag)
+{
+       u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
+       u8  resblk[8+buflen]; /* 8 bytes for header */
+       int size;
+
+       if (field == -1)                /* whole group */
+                       opblk[4] = -1;
+              
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, context, 
+                       opblk, sizeof(opblk), resblk, sizeof(resblk), flag);
+                       
+       if (size < 0)
+               return size;    
 
-       if(bl[4]&0x00FF00000) /* BlockStatus != SUCCESS */
-       {
-               printk(KERN_WARNING "i2o_query_scalar - Error\n"
-                       "ErrorInfoSize = 0x%02x, BlockStatus = 0x%02x, "
-                       "BlockSize = 0x%04x\n", 
-                       bl[4]>>24, (bl[4]>>16)&0xFF, bl[4]&0xFFFF);
-               kfree(bl);
-               return -1;
-       }
-       if((bl[3] & 0xFFFF) != 1)
-       {
-               printk(KERN_ERR "i2o: query ResultCount = 0x%04x\n", bl[3]&0xFFFF);
-       }
-       
-       memcpy(buf, bl+5, buflen);
-       kfree(bl);
-       return 0;
+       memcpy(buf, resblk+8, buflen);  /* cut off header */
+       return buflen;
 }
 
+/*
+ *     Set a scalar group value or a whole group.
+ */
+int i2o_set_scalar(struct i2o_controller *iop, int tid, int context, 
+                  int group, int field, void *buf, int buflen, int *flag)
+{
+       u16 *opblk;
+       u8  resblk[8+buflen]; /* 8 bytes for header */
+        int size;
+
+        opblk = kmalloc(buflen+64, GFP_KERNEL);
+        if (opblk == NULL)
+        {
+                printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+                return -ENOMEM;
+        }
+
+        opblk[0] = 1;                        /* operation count */
+        opblk[1] = 0;                        /* pad */
+        opblk[2] = I2O_PARAMS_FIELD_SET;
+        opblk[3] = group;
+
+        if(field == -1) {               /* whole group */
+                opblk[4] = -1;
+                memcpy(opblk+5, buf, buflen);
+        }
+        else                            /* single field */
+        {
+                opblk[4] = 1;
+                opblk[5] = field;
+                memcpy(opblk+6, buf, buflen);
+        }   
+
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, 
+                       opblk, 12+buflen, resblk, sizeof(resblk), flag);
+
+       kfree(opblk);
+       return size;
+}
 
-#if 0
 /* 
- * Query a table field 
- * FIXME: NOT TESTED! 
+ *     if oper == I2O_PARAMS_TABLE_GET: 
+ *             Get all table group fields from all rows or
+ *             get specific table group fields from all rows.
+ *
+ *             if fieldcount == -1 we query all fields from all rows
+ *                     ibuf is NULL and ibuflen is 0
+ *             else we query specific fields from all rows
+ *                     ibuf contains fieldindexes
+ *
+ *     if oper == I2O_PARAMS_LIST_GET:
+ *             Get all table group fields from specified rows or
+ *             get specific table group fields from specified rows.
+ *
+ *             if fieldcount == -1 we query all fields from specified rows
+ *                     ibuf contains rowcount, keyvalues
+ *             else we query specific fields from specified rows
+ *                     ibuf contains fieldindexes, rowcount, keyvalues
+ *
+ *     You could also use directly function i2o_issue_params().
  */
-int i2o_query_table(struct i2o_controller *c, int tid, int context,
-                   void *buf, int buflen,
-                   int table,
-                   int *field, int fieldlen,
-                   u32 *key, int keylen,
-                   int *flag)
+int i2o_query_table(int oper,
+               struct i2o_controller *iop, int tid, int context, int group,
+               int fieldcount, void *ibuf, int ibuflen,
+               void *resblk, int reslen, int *flag) 
 {
-       static u16 op[32];
-       u32 *bl;
-       u32 msg[9];
-       int i;
+       u16 *opblk;
+       int size;
 
-       bl=kmalloc(buflen+64, GFP_KERNEL);
-       if(bl==NULL)
+       opblk = kmalloc(10 + ibuflen, GFP_KERNEL);
+       if (opblk == NULL)
        {
                printk(KERN_ERR "i2o: no memory for query buffer.\n");
                return -ENOMEM;
        }
 
-       op[0]=1;                        /* Operation count */
-       op[1]=0;                        /* Reserved */
-       op[2]=I2O_PARAMS_LIST_GET;      /* Operation */
-       op[3]=table;                    /* Group */
-       /* Specific fields or the whole group? */
-       if(*field != -1)
-       { /* FIXME: Fields can be variable size */
-               op[4]=fieldlen;
-               for (i=0; i < fieldlen; i++)
-                       op[4+i]=field[i];
-       }
-       else
-       {
-               op[4]=-1;
-               op[5]=0;
-       }
-
-       memcpy(bl, op, 12);
-               
-       msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-       msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid;
-       msg[2]=context|0x80000000;      /* So we can pick it out */
-       msg[3]=(u32)flag;
-       msg[4]=0;
-       msg[5]=0x54000000|12;
-       msg[6]=virt_to_bus(bl);
+       opblk[0] = 1;                           /* operation count */
+       opblk[1] = 0;                           /* pad */
+       opblk[2] = oper;
+       opblk[3] = group;               
+       opblk[4] = fieldcount;
+       memcpy(opblk+5, ibuf, ibuflen);         /* other params */
 
-       msg[7]=0xD0000000|(buflen+48);
-       msg[8]=virt_to_bus(bl+4);
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, context, 
+                       opblk, 10+ibuflen, resblk, reslen, flag);
 
-       /*
-        *      Post the message and await a reply
-        */
+       kfree(opblk);
+       return size;
+}
 
-       if(i2o_post_wait(c, tid, msg, sizeof(msg), flag,2)<0)
-               return -1;
-       
-       if(bl[5]&0x00FF00000)   /* BlockStatus != SUCCESS */
-       {
-               printk(KERN_WARNING "i2o_query_table - Error\n"
-                       "ErrorInfoSize = 0x%02x, BlockStatus = 0x%02x, "
-                       "BlockSize = 0x%04x\n", 
-                       bl[5]>>24, (bl[5]>>16)&0xFF, bl[5]&0xFFFF);
-               kfree(bl);
-               return -1;
-       }
+/*
+ *     Clear table group, i.e. delete all rows.
+ */
 
-       if((bl[4]&0xFFFF)!=1)
-               printk(KERN_ERR "i2o: query ResultCount = %0#4x\n",
-                      bl[4]&0xFFFF);
+int i2o_clear_table(struct i2o_controller *iop, int tid, int context,
+                   int group, int *flag)
+{
+       u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group };
+       u8  resblk[32]; /* min 8 bytes for result header */
 
-       memcpy(buf, bl+6, buflen);
-       kfree(bl);
-       return 0;
+        return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, 
+                       opblk, sizeof(opblk), resblk, sizeof(resblk), flag);
 }
-#endif
 
 /*
- * Set (for now) scalar value
+ *     Add a new row into a table group.
  *
- * TODO: Add support for table groups
- */
-
-int i2o_params_set(struct i2o_controller *c, int tid, int context, int table,
-                  int field, void *buf, int buflen, int *flag)
+ *     if fieldcount==-1 then we add whole rows
+ *             buf contains rowcount, keyvalues
+ *     else just specific fields are given, rest use defaults
+ *             buf contains fieldindexes, rowcount, keyvalues
+ */    
+
+int i2o_row_add_table(struct i2o_controller *iop, int tid, int context,
+                   int group, int fieldcount, void *buf, int buflen,
+                   int *flag)
 {
-       static u16 opdata[]={1,0,6,0,1,4,0};
-       u32 *bl;
-       u32 msg[9];
+       u16 *opblk;
+       u8  resblk[32]; /* min 8 bytes for header */
+       int size;
 
-       bl=kmalloc(buflen+64, GFP_KERNEL);
-       if(bl==NULL)
+       opblk = kmalloc(buflen+64, GFP_KERNEL);
+       if (opblk == NULL)
        {
-               printk(KERN_ERR "i2o: no memory for set buffer.\n");
+               printk(KERN_ERR "i2o: no memory for operation buffer.\n");
                return -ENOMEM;
        }
 
-       opdata[3]=table;
-       /* Single value or the whole group? */
-       if(field != -1) {
-               opdata[4]=1;    
-               opdata[5]=field;
-               opdata[6]=*(u16 *)buf;
-       }
-       else {
-               opdata[4]=-1;
-               opdata[5]=0;
-       }
+       opblk[0] = 1;                   /* operation count */
+       opblk[1] = 0;                   /* pad */
+       opblk[2] = I2O_PARAMS_ROW_ADD;
+       opblk[3] = group;       
+       opblk[4] = fieldcount;
+       memcpy(opblk+5, buf, buflen);
 
-       memcpy(bl, opdata, 14);
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, 
+                       opblk, 10+buflen, resblk, sizeof(resblk), flag);
 
-       msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-       msg[1]=I2O_CMD_UTIL_PARAMS_SET<<24|HOST_TID<<12|tid;
-       msg[2]=context|0x80000000;      /* So we can pick it out */
-       msg[3]=(u32)flag;
-       msg[4]=0;
-       msg[5]=0x54000000|14;
-       msg[6]=virt_to_bus(bl);
-       msg[7]=0xD0000000|(buflen+48);
-       msg[8]=virt_to_bus(bl+4);
-       
-       /* Post the message and wait for a reply */
-       if(i2o_post_wait(c, tid, msg, 36, flag, 5)<0)
-       {
-               kfree(bl);
-               return -1;
-       }
+       kfree(opblk);
+       return size;
+}
 
-       /* Perhaps we should check errors, eh? */
-       if(bl[5]&0x00FF00000)   /* BlockStatus != SUCCESS */
-       {
-               printk(KERN_WARNING "i2o_params_set - Error\n"
-                       "ErrorInfoSize = %0#2x, BlockStatus = %0#2x, "
-                       "BlockSize = %0#4x\n", 
-                       bl[5]>>24, (bl[5]>>16)&0xFF, bl[5]&0xFFFF);
-               kfree(bl);
-               return -1;
-       }
+/*
+ *     Delete rows from a table group.
+ */ 
 
-       if((bl[4] & 0xFFFF) != 1)
+int i2o_row_delete_table(struct i2o_controller *iop, int tid, int context,
+                   int group, int keycount, void *keys, int keyslen,
+                   int *flag)
+{
+       u16 *opblk; 
+       u8  resblk[32]; /* min 8 bytes for header */
+       int size;
+
+       opblk = kmalloc(keyslen+64, GFP_KERNEL);
+       if (opblk == NULL)
        {
-               printk(KERN_ERR "i2o: params set ResultCount = %0#4x\n",
-                      bl[4]&0xFFFF);
+               printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+               return -ENOMEM;
        }
 
-       kfree(bl);
-       return 0;
-}
+       opblk[0] = 1;                   /* operation count */
+       opblk[1] = 0;                   /* pad */
+       opblk[2] = I2O_PARAMS_ROW_DELETE;
+       opblk[3] = group;       
+       opblk[4] = keycount;
+       memcpy(opblk+5, keys, keyslen);
+
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, 
+                       opblk, 10+keyslen, resblk, sizeof(resblk), flag);
 
+       kfree(opblk);
+       return size;
+}
 
-void report_common_status(u8 req_status)
+void i2o_report_common_status(u8 req_status)
 {
        /* the following reply status strings are common to all classes */
 
@@ -1719,7 +1698,7 @@ void report_common_status(u8 req_status)
        return;
 }
 
-static void report_common_dsc(u16 detailed_status)
+static void i2o_report_common_dsc(u16 detailed_status)
 {
        /* The following detailed statuscodes are valid 
           - for executive class, utility class, DDM class and
@@ -1766,7 +1745,7 @@ static void report_common_dsc(u16 detailed_status)
        return;
 }
 
-void report_lan_dsc(u16 detailed_status)
+static void i2o_report_lan_dsc(u16 detailed_status)
 {
        static char *LAN_DSC[] = {      // Lan detailed status code strings
                "SUCCESS",
@@ -1786,10 +1765,11 @@ void report_lan_dsc(u16 detailed_status)
                "DEST_ADDRESS_DETECTED",
                "DEST_ADDRESS_OMITTED",
                "PARTIAL_PACKET_RETURNED",
-               "TEMP_SUSPENDED_STATE"
+               "TEMP_SUSPENDED_STATE", // last Lan detailed status code
+               "INVALID_REQUEST"       // general detailed status code
        };
 
-       if (detailed_status > I2O_LAN_DSC_TEMP_SUSPENDED_STATE)
+       if (detailed_status > I2O_DSC_INVALID_REQUEST)
                printk("%0#4x.\n", detailed_status);
        else
                printk("%s.\n", LAN_DSC[detailed_status]);
@@ -1797,7 +1777,7 @@ void report_lan_dsc(u16 detailed_status)
        return; 
 }
 
-static void report_util_cmd(u8 cmd)
+static void i2o_report_util_cmd(u8 cmd)
 {
        switch (cmd) {
        case I2O_CMD_UTIL_NOP:
@@ -1850,7 +1830,7 @@ static void report_util_cmd(u8 cmd)
 }
 
 
-static void report_exec_cmd(u8 cmd)
+static void i2o_report_exec_cmd(u8 cmd)
 {
        switch (cmd) {
        case I2O_CMD_ADAPTER_ASSIGN:
@@ -1959,7 +1939,7 @@ static void report_exec_cmd(u8 cmd)
        return; 
 }
 
-static void report_lan_cmd(u8 cmd)
+static void i2o_report_lan_cmd(u8 cmd)
 {
        switch (cmd) {
        case LAN_PACKET_SEND:
@@ -1985,30 +1965,32 @@ static void report_lan_cmd(u8 cmd)
 }
 
 /* TODO: Add support for other classes */
-void i2o_report_status(const char *severity, const char *module, u8 cmd,
-                      u8 req_status, u16 detailed_status)
+void i2o_report_status(const char *severity, const char *module, u32 *msg)
 {
-       printk("%s", severity);
-       printk("%s: ", module);
+       u8 cmd = (msg[1]>>24)&0xFF;
+       u8 req_status = (msg[4]>>24)&0xFF;
+       u16 detailed_status = msg[4]&0xFFFF;
+
+       printk("%s%s: ", severity, module);
 
        if (cmd < 0x1F) {                       // Utility Class
-               report_util_cmd(cmd);
-               report_common_status(req_status);
-               report_common_dsc(detailed_status);
+               i2o_report_util_cmd(cmd);
+               i2o_report_common_status(req_status);
+               i2o_report_common_dsc(detailed_status);
                return;
        }
 
        if (cmd >= 0x30 && cmd <= 0x3F) {       // LAN class
-               report_lan_cmd(cmd);
-               report_common_status(req_status);               
-               report_lan_dsc(detailed_status);
+               i2o_report_lan_cmd(cmd);
+               i2o_report_common_status(req_status);           
+               i2o_report_lan_dsc(detailed_status);
                return;
        }
        
        if (cmd >= 0xA0 && cmd <= 0xEF) {       // Executive class
-               report_exec_cmd(cmd);
-               report_common_status(req_status);
-               report_common_dsc(detailed_status);
+               i2o_report_exec_cmd(cmd);
+               i2o_report_common_status(req_status);
+               i2o_report_common_dsc(detailed_status);
                return;
        }
        
@@ -2017,6 +1999,8 @@ void i2o_report_status(const char *severity, const char *module, u8 cmd,
 }
 
 
+#ifdef CONFIG_MODULE
+
 EXPORT_SYMBOL(i2o_install_handler);
 EXPORT_SYMBOL(i2o_remove_handler);
 EXPORT_SYMBOL(i2o_install_device);
@@ -2037,16 +2021,75 @@ EXPORT_SYMBOL(i2o_online_controller);
 EXPORT_SYMBOL(i2o_get_class_name);
 
 EXPORT_SYMBOL(i2o_query_scalar);
-EXPORT_SYMBOL(i2o_params_set);
+EXPORT_SYMBOL(i2o_set_scalar);
+EXPORT_SYMBOL(i2o_query_table);
+EXPORT_SYMBOL(i2o_clear_table);
+EXPORT_SYMBOL(i2o_row_add_table);
+EXPORT_SYMBOL(i2o_row_delete_table);
+
 EXPORT_SYMBOL(i2o_post_this);
 EXPORT_SYMBOL(i2o_post_wait);
 EXPORT_SYMBOL(i2o_issue_claim);
 
 EXPORT_SYMBOL(i2o_report_status);
-EXPORT_SYMBOL(report_common_status);
-EXPORT_SYMBOL(report_lan_dsc);
-
-EXPORT_SYMBOL(i2o_wait_message);
 
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Core");
+
+
+int init_module(void)
+{
+        if (i2o_install_handler(&i2o_core_handler) < 0)
+        {
+                printk(KERN_ERR "i2o_core: Unable to install core handler.\n");
+                return 0;
+        }
+
+        core_context = i2o_core_handler.context;
+
+        return 0;
+}
+
+void cleanup_module(void)
+{
+       i2o_remove_handler(&i2o_core_handler);
+}
+
+#else
+
+extern int i2o_block_init(void);
+extern int i2o_config_init(void);
+extern int i2o_lan_init(void);
+extern int i2o_pci_init(void);
+extern int i2o_proc_init(void);
+extern int i2o_scsi_init(void);
+
+__init int i2o_init(void)
+{
+        if (i2o_install_handler(&i2o_core_handler) < 0)
+        {
+                printk(KERN_ERR "i2o_core: Unable to install core handler.\n");
+                return 0;
+        }
+
+        core_context = i2o_core_handler.context;
+#ifdef CONFIG_I2O_PCI
+       i2o_pci_init();
+#endif
+       i2o_config_init();
+#ifdef CONFIG_I2O_BLOCK
+       i2o_block_init();
+#endif
+#ifdef CONFIG_I2O_SCSI
+       i2o_scsi_init();
+#endif
+#ifdef CONFIG_I2O_LAN
+       i2o_lan_init();
+#endif
+#ifdef CONFIG_I2O_PROC
+       i2o_proc_init();
+#endif
+       return 0;
+}
+
+#endif
\ No newline at end of file
index f15b7476e8122b475988b737834f651dbf8f6290..930c36b7657eef945bb89ae4e5de7ac8fa4b1e33 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     linux/drivers/i2o/i2o_lan.c
  *
- *     I2O LAN CLASS OSM       Prototyping, May 7th 1999
+ *     I2O LAN CLASS OSM       Prototyping, June 4th 1999
  *
  *     (C) Copyright 1999      University of Helsinki,
  *                             Department of Computer Science
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.    
  *
- *     Author:         Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *     Authors:        Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *                     Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
  *
  *     Tested:         in FDDI environment (using SysKonnect's DDM)
- *                     in ETH environment (using Intel 82558 DDM proto)
+ *                     in Ethernet environment (using Intel 82558 DDM proto)
  *
  *     TODO:           batch mode networking
- *                     - this one assumes that we always get one packet in a bucket
- *                     - we've not been able to test batch replies and batch receives
- *                     error checking / timeouts
- *                     - code/test for other LAN classes
+ *                     - this one assumes that we always get one packet 
+ *                       in a bucket
+ *                     - we've not been able to test batch replies and 
+ *                       batch receives
+ *                     - error checking / timeouts
+ *                     - code / test for other LAN classes
  */
 
 #include <linux/config.h>
@@ -35,6 +38,7 @@
 #include <linux/if_arp.h>
 #include <linux/malloc.h>
 #include <linux/trdevice.h>
+#include <linux/init.h>
 #include <asm/io.h>
 
 #include <linux/errno.h>
@@ -56,9 +60,9 @@ static int unit = -1;                         /* device unit number */
 struct i2o_lan_local {
        u8 unit;
        struct i2o_device *i2o_dev;
-       int reply_flag;                 // needed by scalar/table queries
-       struct fddi_statistics stats;
-/*     first fields are same as in struct net_device_stats stats; */ 
+       int reply_flag;                 /* needed by scalar/table queries */
+       u32 packet_tresh;               /* treshold for incoming skb's */       
+       struct fddi_statistics stats;   /* see also struct net_device_stats */ 
        unsigned short (*type_trans)(struct sk_buff *, struct device *);
 };
 
@@ -66,6 +70,11 @@ struct i2o_lan_local {
 static int i2o_lan_receive_post(struct device *dev);
 static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m);
 
+/*
+ * Module params
+ */
+static u32 bucketpost = 64;
+static u32 bucketthresh = 8;
 
 static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, 
                          struct i2o_message *m)
@@ -74,17 +83,25 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
        u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
        struct device *dev = i2o_landevs[unit];
 
-#ifdef DRIVERDEBUG
-       i2o_report_status(KERN_INFO, "i2o_lan", msg[1]>>24, msg[4]>>24,
-                         msg[4]&0xFFFF);
-#endif
        if (msg[0] & (1<<13)) // Fail bit is set
        {
-               printk(KERN_INFO "IOP failed to process the msg\n");
-               printk("From tid=%d to tid=%d",(msg[1]>>12)&0xFFF,msg[1]&0xFFF);
+               printk(KERN_ERR "IOP failed to process the msg:\n");
+               printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid = %d\n",
+                       (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
+               printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n  "
+                       "LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
+                        msg[4] >> 24, (msg[4] >> 16) & 0xFF, 
+                       (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+               printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
+                       msg[5] >> 16, msg[5] & 0xFFF);
                return;
        }       
 
+#ifdef DRIVERDEBUG
+//     if (msg[4] >> 24)       /* ReqStatus != SUCCESS */
+               i2o_report_status(KERN_INFO, "i2o_lan", msg);
+#endif
+
        switch (msg[1] >> 24) {
        case LAN_RECEIVE_POST: 
                if (dev->start) 
@@ -94,11 +111,9 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                        u8 trl_count  = msg[3] & 0x000000FF;    
                        struct i2o_bucket_descriptor *bucket =
                                (struct i2o_bucket_descriptor *)&msg[6];
-                       struct sk_buff *skb;
                        do {    
-                               dprintk("Releasing unused bucket\n");
-                               skb = (struct sk_buff *)bucket->context;
-                               dev_kfree_skb(skb);
+                               dprintk("%s: Releasing unused bucket\n",dev->name);
+                               dev_kfree_skb((struct sk_buff *)bucket->context);
                                bucket++;
                        } while (--trl_count);
                }                       
@@ -110,30 +125,30 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                u8 trl_count  = msg[3] & 0x000000FF;    
                
                if (msg[4] >> 24)       // ReqStatus != SUCCESS
-               {
-                       printk(KERN_WARNING "%s: ",dev->name); 
-                       report_common_status(msg[4]>>24);
-                       report_lan_dsc(msg[4]&0xFFFF);
-               }
+                       i2o_report_status(KERN_WARNING, dev->name, msg);
 
-               do {    // The HDM has handled the outgoing packet
+               do {    // The HDM has handled the outgoing packet
                        dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]);
                        dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
                                dev->name,trl_count);
                } while (--trl_count);
                
-                       dev->tbusy = 0;
-                       mark_bh(NET_BH); /* inform upper layers */
+               dev->tbusy = 0;
+               mark_bh(NET_BH); /* inform upper layers */
        }
        break;  
 
        default: 
-               if (msg[2] & 0x80000000)        // reply to a util get/set
-               {       // flag for the i2o_post_wait
-                       int *flag = (int *)msg[3];
-                       // ReqStatus != I2O_REPLY_STATUS_SUCCESS
-                        *flag = (msg[4] >> 24) ? I2O_POST_WAIT_TIMEOUT 
-                                               : I2O_POST_WAIT_OK ;
+               if (msg[2] & 0x80000000)  // reply to a UtilParamsGet/Set
+               {       
+                       int *flag = (int *)msg[3]; // flag for i2o_post_wait
+                       if (msg[4] >> 24) // ReqStatus != SUCCESS
+                       {
+                               i2o_report_status(KERN_WARNING, dev->name, msg);
+                               *flag = -(msg[4] & 0xFFFF); // DetailedStatus
+                       }
+                       else
+                               *flag = I2O_POST_WAIT_OK;
                }
        }
 }
@@ -155,40 +170,54 @@ static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m)
        struct i2o_packet_info *packet;
        
        u8 trl_count  = msg[3] & 0x000000FF;    
-       struct sk_buff *skb;
+       struct sk_buff *skb, *newskb;
 
-#ifdef 0
+#if 0
        dprintk(KERN_INFO "TrlFlags = 0x%02X, TrlElementSize = %d, TrlCount = %d\n"
                "msgsize = %d, buckets_remaining = %d\n", 
                msg[3]>>24, msg[3]&0x0000FF00, trl_count, msg[0]>>16, msg[5]);  
 #endif
+       dprintk(KERN_INFO "Buckets_remaining = %d\n",msg[5]);
 
-/* 
- * NOTE: here we assume that also in batch mode we will get only 
- * one packet per bucket. This can be ensured by setting the 
- * PacketOrphanLimit to MaxPacketSize, as well as the bucket size.
- */
        do {
-               /* packet is not at all needed here */
+               skb = (struct sk_buff *)(bucket->context);              
                packet = (struct i2o_packet_info *)bucket->packet_info; 
-#ifdef 0
+#if 0
                dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n",
                        packet->flags, packet->offset, packet->status, packet->len);
 #endif
-               skb = (struct sk_buff *)(bucket->context);
-               skb_put(skb,packet->len);
-               skb->dev  = dev;                
-               skb->protocol = priv->type_trans(skb, dev);
-               netif_rx(skb);
+               if (packet->len < priv->packet_tresh) {
+                       newskb = (struct sk_buff *)
+                                       dev_alloc_skb(packet->len+2);   
+                       if (newskb) {
+                               skb_reserve(newskb,2);
+                               memcpy(skb_put(newskb,packet->len), 
+                                      skb->data, packet->len);
+                               newskb->dev = dev;
+                               newskb->protocol = priv->type_trans(newskb, dev);
+
+                               netif_rx(newskb);
+                               dev_kfree_skb(skb); // FIXME: reuse this skb? 
+                       }
+                       else {
+                               printk("Can't allocate skb.\n");
+                               return -ENOMEM;
+                       }
+               } else {
+                       skb_put(skb,packet->len);               
+                       skb->dev  = dev;                
+                       skb->protocol = priv->type_trans(skb, dev);
 
+                       netif_rx(skb);
+               }
                dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered "
                        "to upper level.\n",dev->name,packet->len);
-                       
-               bucket++; // to next Packet Descriptor Block
 
+               bucket++; // to next Packet Descriptor Block
        } while (--trl_count);
 
-       if (msg[5] <= I2O_BUCKET_THRESH)        // BucketsRemaining
+
+       if (msg[5] <= bucketthresh)     // BucketsRemaining
                i2o_lan_receive_post(dev);
 
        return 0;
@@ -198,6 +227,7 @@ static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m)
  *  Interface to i2o:  functions to send lan class request 
  */
 
+
 /* 
  * i2o_lan_receive_post(): Post buckets to receive packets.
  */
@@ -211,25 +241,22 @@ static int i2o_lan_receive_post(struct device *dev)
        
        u32 bucket_len = (dev->mtu + dev->hard_header_len);
        u32 bucket_count;
-       int n_elems = (iop->inbound_size - 16 ) / 12; // msg header + SGLs
+       int n_elems = (iop->inbound_size - 16 ) / 12; /* msg header + SGLs */
        u32 total = 0;
        int i;
 
-       dprintk(KERN_INFO "%s: Allocating %d buckets (size %d).\n", 
-               dev->name, I2O_BUCKET_COUNT, bucket_len);
-
-       while (total < I2O_BUCKET_COUNT)
+       while (total < bucketpost)
        {
                m = I2O_POST_READ32(iop);
                if (m == 0xFFFFFFFF)
                        return -ETIMEDOUT;              
                msg = bus_to_virt(iop->mem_offset + m);
        
-               bucket_count = (total + n_elems < I2O_BUCKET_COUNT)
+               bucket_count = (total + n_elems < bucketpost)
                             ? n_elems
-                            : I2O_BUCKET_COUNT - total;
-                            
-               msg[0] = I2O_MESSAGE_SIZE(4 + 3 *  bucket_count) | 1<<12 | SGL_OFFSET_4;
+                            : bucketpost - total;
+
+               msg[0] = I2O_MESSAGE_SIZE(4 + 3 *  bucket_count) | SGL_OFFSET_4;
                msg[1] = LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->id;
                msg[2] = priv->unit << 16 | lan_context; // InitiatorContext    
                msg[3] = bucket_count;                   // BucketCount
@@ -248,7 +275,7 @@ static int i2o_lan_receive_post(struct device *dev)
                i2o_post_message(iop,m);
 
                dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n",
-                       dev->name,bucket_count,bucket_len);
+                       dev->name, bucket_count, bucket_len);
 
                total += bucket_count;
        }
@@ -264,12 +291,7 @@ static int i2o_lan_reset(struct device *dev)
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
        struct i2o_device *i2o_dev = priv->i2o_dev;
        struct i2o_controller *iop = i2o_dev->controller;       
-       u32 m; u32 *msg;
-
-       m = I2O_POST_READ32(iop);
-       if (m == 0xFFFFFFFF)
-               return -ETIMEDOUT;
-       msg = bus_to_virt(iop->mem_offset + m);
+       u32 msg[5];
 
        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
        msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->id;
@@ -277,7 +299,8 @@ static int i2o_lan_reset(struct device *dev)
        msg[3] = 0;                              // TransactionContext
        msg[4] = 1 << 16;                        // return posted buckets
 
-       i2o_post_message(iop,m);
+       if (i2o_post_this(iop, i2o_dev->id, msg, sizeof(msg)) < 0)
+               return -ETIMEDOUT;              
 
        return 0; 
 }
@@ -292,12 +315,7 @@ static int i2o_lan_suspend(struct device *dev)
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
        struct i2o_device *i2o_dev = priv->i2o_dev;
        struct i2o_controller *iop = i2o_dev->controller;       
-       u32 m; u32 *msg;
-
-       m = I2O_POST_READ32(iop);
-       if (m == 0xFFFFFFFF)
-               return -ETIMEDOUT;
-       msg = bus_to_virt(iop->mem_offset + m);
+       u32 msg[5];
 
        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
        msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->id;
@@ -305,7 +323,8 @@ static int i2o_lan_suspend(struct device *dev)
        msg[3] = 0;                              // TransactionContext
        msg[4] = 1 << 16;                        // return posted buckets
 
-       i2o_post_message(iop,m);
+       if (i2o_post_this(iop, i2o_dev->id, msg, sizeof(msg)) < 0)
+               return -ETIMEDOUT;
 
        return 0;
 }
@@ -330,12 +349,13 @@ static void i2o_set_batch_mode(struct device *dev)
 
        // enable batch mode, toggle automatically
        val = 0x00000000;
-       if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 0,
+//     val = 0x00000001; // turn off batch mode
+       if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0003, 0,
                        &val, 4, &priv->reply_flag) <0)
                printk(KERN_WARNING "Unable to enter I2O LAN batch mode.\n");
        else
                dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name);
-
+//             dprintk(KERN_INFO "%s: I2O LAN batch mode disabled.\n",dev->name);
        /*
         * When PacketOrphanlimit is same as the maximum packet length,
         * the packets will never be split into two separate buckets
@@ -344,46 +364,12 @@ static void i2o_set_batch_mode(struct device *dev)
        /* set LAN_OPERATION attributes */
 
        val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit
-       if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0004, 2,
+       if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0004, 2,
                &val, 4, &priv->reply_flag) < 0)
                printk(KERN_WARNING "i2o_lan: Unable to set PacketOrphanLimit.\n");
        else
-               dprintk(KERN_INFO "PacketOrphanLimit set to %d\n",val);
-
-#ifdef 0
-/*
- * I2O spec 2.0: there should be proper default values for other attributes 
- * used in batch mode.
- */
-
-       /* set LAN_RECEIVE_INFO attributes */
-       
-       val = 10; // RxMaxBucketsReply
-       if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0008, 3,
-               &val, 4, &priv->reply_flag) < 0)
-               printk(KERN_WARNING "%s: Unable to set RxMaxBucketsReply.\n",
-                       dev->name);
-
-       val = 10; // RxMaxPacketsBuckets
-       if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0008, 4,
-               &val, 4, &priv->reply_flag) < 0)
-               printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n",
-                       dev->name);
-
-       /* set LAN_BATCH_CONTROL attributes */
-
-       val = 10; // MaxRxBatchCount
-       if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 5,
-               &val, 4, &priv->reply_flag) < 0)
-               printk(KERN_WARNING "%s: Unable to set MaxRxBatchCount.\n",
-                       dev->name);
-
-       val = 10; // MaxTxBatchCount
-       if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 8,
-               &val, 4, &priv->reply_flag) < 0)
-               printk(KERN_WARNING "%s Unable to set MaxTxBatchCount.\n",
-                       dev->name);
-#endif
+               dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d\n",
+                       dev->name,val);
 
        return; 
 }
@@ -398,24 +384,26 @@ static int i2o_lan_open(struct device *dev)
        struct i2o_device *i2o_dev = priv->i2o_dev;     
        struct i2o_controller *iop = i2o_dev->controller;
 
-       i2o_lan_reset(dev);
-       
        if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 1, 
-               &priv->reply_flag) < 0)
+                           &priv->reply_flag) < 0)
        {
                printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
                return -EAGAIN;
        }
        dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", dev->name, i2o_dev->id);
 
+       i2o_lan_reset(dev);
+       
        dev->tbusy = 0;
        dev->start = 1;
 
+       priv->packet_tresh = dev->mtu - (dev->mtu >> 3);
+
        i2o_set_batch_mode(dev);
        i2o_lan_receive_post(dev);
 
        MOD_INC_USE_COUNT;
-       
+
        return 0;
 }
 
@@ -431,15 +419,16 @@ static int i2o_lan_close(struct device *dev)
        dev->tbusy = 1;
        dev->start = 0;
 
-       if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, 
-           &priv->reply_flag) < 0)
-       {
-               printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device (tid=%d)\n",
-                      dev->name, i2o_dev->id);
-       }
+// This is the right place for LanSuspend, but it seems to cause 
+// a kernel crash when we are using 82558 HDM proto
 
        i2o_lan_suspend(dev);
 
+       if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, 
+                           &priv->reply_flag) < 0)
+               printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
+                      "(tid=%d)\n", dev->name, i2o_dev->id);
+
        MOD_DEC_USE_COUNT;
 
        return 0;
@@ -452,7 +441,7 @@ static int i2o_lan_close(struct device *dev)
  */
 static int i2o_lan_sdu_send(struct sk_buff *skb, struct device *dev)
 {      
-#ifdef 0
+#if 0
 /* not yet tested */
         struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
         struct i2o_device *i2o_dev = priv->i2o_dev;     
@@ -461,13 +450,13 @@ static int i2o_lan_sdu_send(struct sk_buff *skb, struct device *dev)
 
        dprintk(KERN_INFO "LanSDUSend called, skb->len = %d\n", skb->len);
 
-        m = *iop->post_port;
-        if (m == 0xFFFFFFFF)
+        m = I2O_POST_READ32(iop);
+       if (m == 0xFFFFFFFF) 
        {
-                dev_kfree_skb(skb);     
-                return -1;
-        }
-        msg = bus_to_virt(iop->mem_offset + m);
+               dev_kfree_skb(skb);
+               return -ETIMEDOUT;
+       }    
+       msg = bus_to_virt(iop->mem_offset + m);
 
         msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_4;
         msg[1] = LAN_SDU_SEND<<24 | HOST_TID<<12 | i2o_dev->id; 
@@ -483,7 +472,7 @@ static int i2o_lan_sdu_send(struct sk_buff *skb, struct device *dev)
         msg[7] &= 0x0000FFFF;             // followed by two bytes zeros
         msg[8] = virt_to_bus(skb->data);
         dev->trans_start = jiffies;
-        i2o_post_message(iop,m);
+       i2o_post_message(iop,m);
 
        dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n",
                dev->name,skb->len);
@@ -502,16 +491,15 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct device *dev)
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
        struct i2o_device *i2o_dev = priv->i2o_dev;     
        struct i2o_controller *iop = i2o_dev->controller;
-       u32 m; u32 *msg;
+        u32 m; u32 *msg;
 
-       m = *iop->post_port;
+        m = I2O_POST_READ32(iop);
        if (m == 0xFFFFFFFF) {
                dev_kfree_skb(skb);
-               return -1;
-       }
-
+               return -ETIMEDOUT;
+       }    
        msg = bus_to_virt(iop->mem_offset + m);
-
+       
        msg[0] = SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4;
        msg[1] = LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->id;      
        msg[2] = priv->unit << 16 | lan_context; // IntiatorContext
@@ -524,37 +512,130 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct device *dev)
        msg[5] = (u32)skb;                      // TransactionContext
        msg[6] = virt_to_bus(skb->data);
 
-       i2o_post_message(iop,m);
-
+        i2o_post_message(iop,m);
+        
        dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n",
                dev->name, skb->len);
 
        return 0;
 }
 
-/*
- * net_device_stats(): Return statistical information.
- */
 static struct net_device_stats *i2o_lan_get_stats(struct device *dev)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
        struct i2o_device *i2o_dev = priv->i2o_dev;
        struct i2o_controller *iop = i2o_dev->controller;
-       u64 val[16];
+       u64 val64[16];
+       u64 supported_group[4] = { 0, 0, 0, 0 };
+
+        if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, 
+                        val64, sizeof(val64), &priv->reply_flag) < 0)
+               dprintk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name);
+       else {
+               dprintk("%s: LAN_HISTORICAL_STATS queried.\n",dev->name);
+               priv->stats.tx_packets = val64[0];
+               priv->stats.tx_bytes   = val64[1];
+               priv->stats.rx_packets = val64[2];
+               priv->stats.rx_bytes   = val64[3];
+               priv->stats.tx_errors  = val64[4];
+               priv->stats.rx_errors  = val64[5];
+               priv->stats.rx_dropped = val64[6];
+       }
 
-       /* query LAN_HISTORICAL_STATS scalar parameter group 0x0100 */
+        i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0180, -1, 
+                       &supported_group, sizeof(supported_group), &priv->reply_flag);
+
+       if (supported_group[2]) {
+               if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0183, -1, 
+                       val64, sizeof(val64), &priv->reply_flag) < 0)
+                       dprintk("%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n",dev->name);
+               else {
+                       dprintk("%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n",dev->name);
+                       priv->stats.multicast        = val64[4];
+                       priv->stats.rx_length_errors = val64[10];
+                       priv->stats.rx_crc_errors    = val64[0];
+               }
+       }
 
-        i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, 
-                        &val, 16*8, &priv->reply_flag);
-        priv->stats.tx_packets = val[0];
-        priv->stats.tx_bytes   = val[1];
-        priv->stats.rx_packets = val[2];
-        priv->stats.rx_bytes   = val[3];
-        priv->stats.tx_errors  = val[4];
-        priv->stats.rx_errors  = val[5];
-       priv->stats.rx_dropped = val[6];
+       if (i2o_dev->subclass == I2O_LAN_ETHERNET)
+       {
+               u64 supported_stats = 0;                
+
+               if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0200, -1, 
+                                val64, sizeof(val64), &priv->reply_flag) < 0)
+                       dprintk("%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n",dev->name);
+               else {
+                       dprintk("%s: LAN_802_3_HISTORICAL_STATS queried.\n",dev->name);
+                       priv->stats.transmit_collision = val64[1] + val64[2];
+                       priv->stats.rx_frame_errors    = val64[0];              
+                       priv->stats.tx_carrier_errors  = val64[6];
+               }
+       
+               i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0280, -1, 
+                                &supported_stats, 8, &priv->reply_flag);
+                               
+               if (supported_stats != 0) {
+                       if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0281, -1, 
+                                        val64, sizeof(val64), &priv->reply_flag) < 0)
+                               dprintk("%s: Unable to query LAN_OPTIONLA_802_3_HISTORICAL_STATS.\n",dev->name);
+                       else {
+                               dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name);
+                               if (supported_stats & 0x1)
+                                       priv->stats.rx_over_errors = val64[0];
+                               if (supported_stats & 0x4)
+                                       priv->stats.tx_heartbeat_errors = val64[2];
+                       }
+               }
+       }
 
-       // other net_device_stats and FDDI class specific fields follow ...
+#ifdef CONFIG_TR
+       if (i2o_dev->subclass == I2O_LAN_TR)
+       {
+               if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0300, -1, 
+                                val64, sizeof(val64), &priv->reply_flag) < 0)
+                       dprintk("%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n",dev->name);
+               else {
+                       struct tr_statistics *stats = 
+                                       (struct tr_statistics *)&priv->stats;
+                       dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
+
+                       stats->line_errors              = val64[0];
+                       stats->internal_errors          = val64[7];
+                       stats->burst_errors             = val64[4];
+                       stats->A_C_errors               = val64[2];
+                       stats->abort_delimiters         = val64[3];
+                       stats->lost_frames              = val64[1];
+                       /* stats->recv_congest_count    = ?;  FIXME ??*/
+                       stats->frame_copied_errors      = val64[5];
+                       stats->frequency_errors         = val64[6];
+                       stats->token_errors             = val64[9];
+               }
+               /* Token Ring optional stats not yet defined */
+       }
+#endif
+
+#ifdef CONFIG_FDDI
+       if (i2o_dev->subclass == I2O_LAN_FDDI)
+       {
+               if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0400, -1, 
+                                val64, sizeof(val64), &priv->reply_flag) < 0)
+                       dprintk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name);
+               else {
+                       dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name);
+                       priv->stats.smt_cf_state = val64[0];
+                       memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN);
+                       memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN);                 
+                       priv->stats.mac_error_cts = val64[3];
+                       priv->stats.mac_lost_cts  = val64[4];
+                       priv->stats.mac_rmt_state = val64[5];
+                       memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8);
+                       memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8);  
+                       memcpy(priv->stats.port_lem_cts, &val64[8], 8);
+                       memcpy(priv->stats.port_pcm_state, &val64[9], 8);
+               }
+               /* FDDI optional stats not yet defined */
+       }               
+#endif
 
        return (struct net_device_stats *)&priv->stats;
 }
@@ -569,75 +650,78 @@ static void i2o_lan_set_multicast_list(struct device *dev)
        struct i2o_device *i2o_dev = priv->i2o_dev;
        struct i2o_controller *iop = i2o_dev->controller;
        u32 filter_mask;
+       u32 work32[64];
 
-       dprintk(KERN_INFO "Entered i2o_lan_set_multicast_list().\n");
+       dprintk(KERN_INFO "%s: Entered i2o_lan_set_multicast_list().\n", dev->name);
 
 return;
 
-/*
- * FIXME: For some reason this kills interrupt handler in i2o_post_wait :-(
- * 
+/* FIXME: Why does the next call kill the interrupt handler?
+ * The same works fine in function lan_open(), and in i2o_proc.c
+ *
+ *  *because its trying to sleep in an irq - this must be async - Alan
  */
-       dprintk(KERN_INFO "dev->flags = 0x%08X, dev->mc_count = 0x%08X\n",
-               dev->flags,dev->mc_count);
 
-       if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3, 
-                            &filter_mask, 4, &priv->reply_flag) < 0 )
-               printk(KERN_WARNING "i2o_lan: Unable to query filter mask.\n"); 
+       if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, -1,
+                            &work32, sizeof(work32), &priv->reply_flag) < 0 ) 
+       {
+               printk(KERN_WARNING "i2o_lan: Unable to query "
+                       " LAN_MAC_ADDRESS table.\n");   
+               return;
+       }
+       printk(KERN_INFO "capab mask = 0x%08X, filter mask = 0x%08X\n",
+               work32[7], work32[6]);
 
-       dprintk(KERN_INFO "filter_mask = 0x%08X\n",filter_mask);
+       filter_mask = work32[6];
 
        if (dev->flags & IFF_PROMISC)
        {
-               // Enable promiscuous mode
-
                filter_mask |= 0x00000002; 
-               if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3,
-                               &filter_mask, 4, &priv->reply_flag) <0)
-                       printk(KERN_WARNING "i2o_lan: Unable to enable promiscuous multicast mode.\n");
-               else
-                       dprintk(KERN_INFO "i2o_lan: Promiscuous multicast mode enabled.\n");
-
-               return;
+               dprintk(KERN_INFO "i2o_lan: Enabling promiscuous mode...\n");
         }
         
-//     if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS)
-//     {
-//             // Disable promiscuous mode, use normal mode.
-//             hardware_set_filter(NULL);
-//
-//             dprintk(KERN_INFO "i2o_lan: Disabled promiscuous mode, uses normal mode\n"); 
-//
-//             filter_mask = 0x00000000; 
-//             i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3,
-//                             &filter_mask, 4, &priv->reply_flag);
-//             
-//             return;
-//      }
-
-        if (dev->mc_count)
-       {
-               // Walk the address list, and load the filter
-//              hardware_set_filter(dev->mc_list);
+       else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > work32[5])
+       {
+               filter_mask |= 0x00000000; 
+               dprintk(KERN_INFO "i2o_lan: Enabling all multicast mode...\n");
+       }
+
+        else if (dev->mc_count)
+       {       
+               struct dev_mc_list *mclist;
+               int i;
+               u8 *work8 = (u8 *)work32;
 
+               dprintk(KERN_INFO "i2o_lan: Enabling multicast mode...\n");
                 filter_mask = 0x00000004; 
-               if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3,
-                                  &filter_mask, 4, &priv->reply_flag) <0)
-                       printk(KERN_WARNING "i2o_lan: Unable to enable Promiscuous multicast mode.\n");
-               else
-                       dprintk(KERN_INFO "i2o_lan: Promiscuous multicast mode enabled.\n");                    
-        
-                       return;
-       }
-        
-        // Unicast
-        
-        filter_mask |= 0x00000300; // Broadcast, Multicast disabled
-       if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3,
+
+               /* Fill the multicast addresses */
+               mclist = dev->mc_list;
+
+               for (i = 0; i < dev->mc_count; i++)
+               {       
+                       memcpy(work8, mclist->dmi_addr, mclist->dmi_addrlen);
+                       work8 += 8;
+                       mclist = mclist->next;
+               } 
+
+               if (i2o_clear_table(iop, i2o_dev->id, lan_context, 0x0002,
+                               &priv->reply_flag) < 0 ) 
+                       dprintk("%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
+
+               if (i2o_row_add_table(iop, i2o_dev->id, lan_context, 0x0002, -1,
+                       work32, dev->mc_count*8, &priv->reply_flag) < 0)        
+                       dprintk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
+       } 
+       
+       else {
+               filter_mask |= 0x00000300; // Broadcast, Multicast disabled
+               dprintk(KERN_INFO "i2o_lan: Enabling unicast mode...\n");
+        }
+
+       if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3,
                        &filter_mask, 4, &priv->reply_flag) <0)
-               printk(KERN_WARNING "i2o_lan: Unable to enable unicast mode.\n");
-       else
-               dprintk(KERN_INFO "i2o_lan: Unicast mode enabled.\n");  
+               printk(KERN_WARNING "i2o_lan: Unable to set MAC FilterMask.\n");
 
        return;
 }
@@ -648,34 +732,31 @@ struct device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        struct i2o_lan_local *priv = NULL;
        u8 hw_addr[8];
        unsigned short (*type_trans)(struct sk_buff *, struct device *);
+       void (*unregister_dev)(struct device *dev);
 
        switch (i2o_dev->subclass)
        {
        case I2O_LAN_ETHERNET:
-               /* Note: init_etherdev calls 
-                        ether_setup() and register_netdevice() 
-                        and allocates the priv structure        */
-
                dev = init_etherdev(NULL, sizeof(struct i2o_lan_local));
                if (dev == NULL)
                        return NULL;
                type_trans = eth_type_trans;
+               unregister_dev = unregister_netdev;
                break;
 
-/*
 #ifdef CONFIG_ANYLAN
        case I2O_LAN_100VG:
-               printk(KERN_WARNING "i2o_lan: 100base VG not yet supported\n");
+               printk(KERN_ERR "i2o_lan: 100base VG not yet supported\n");
                break;
 #endif
-*/
 
 #ifdef CONFIG_TR
        case I2O_LAN_TR:
                dev = init_trdev(NULL, sizeof(struct i2o_lan_local));
-               if(dev==NULL)
+               if (dev==NULL)
                        return NULL;
                type_trans = tr_type_trans;
+               unregister_dev = unregister_trdev;              
                break;
 #endif
 
@@ -697,23 +778,23 @@ struct device *i2o_lan_register_device(struct i2o_device *i2o_dev)
                        return NULL;
                }
                type_trans = fddi_type_trans;
-
+               unregister_dev = (void *)unregister_netdevice;
+               
                fddi_setup(dev);
                register_netdev(dev);
        }
        break;
 #endif
 
-/*
 #ifdef CONFIG_FIBRE_CHANNEL
        case I2O_LAN_FIBRE_CHANNEL:
-               printk(KERN_WARNING "i2o_lan: Fibre Channel not yet supported\n");
+               printk(KERN_INFO "i2o_lan: Fibre Channel not yet supported\n");
        break;
 #endif
-*/
+
        case I2O_LAN_UNKNOWN:
        default:
-               printk(KERN_WARNING "i2o_lan: LAN type 0x%08X not supported\n",
+               printk(KERN_ERR "i2o_lan: LAN type 0x%08X not supported\n",
                       i2o_dev->subclass);
                return NULL;
        }
@@ -721,16 +802,17 @@ struct device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        priv = (struct i2o_lan_local *)dev->priv;
        priv->i2o_dev = i2o_dev;
        priv->type_trans = type_trans;
-
+       
         if (i2o_query_scalar(i2o_dev->controller, i2o_dev->id, lan_context,
                             0x0001, 0, &hw_addr, 8, &priv->reply_flag) < 0)
        {
-               printk("%s: Unable to query hardware address.\n",
-                      dev->name);
+               printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
+               unregister_dev(dev);
+               kfree(dev);
                return NULL;  
         }
-        
-       dprintk("%s hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+
+       dprintk("%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
                dev->name,hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3],
                hw_addr[4], hw_addr[5]);
 
@@ -747,8 +829,10 @@ struct device *i2o_lan_register_device(struct i2o_device *i2o_dev)
 }
 
 #ifdef MODULE
+#define i2o_lan_init   init_module
+#endif
 
-int init_module(void)
+__init int i2o_lan_init(void)
 {
        struct device *dev;
        struct i2o_lan_local *priv;
@@ -772,13 +856,12 @@ int init_module(void)
 
                 for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next)
                {
-                        int class = i2o_dev->class;
-
-                        if (class != 0x020) /* not I2O_CLASS_LAN device*/ 
+                        if (i2o_dev->class != I2O_CLASS_LAN) 
                                 continue;
 
                        if (unit == MAX_LAN_CARDS)
                        {
+                               i2o_unlock_controller(iop);
                                printk(KERN_WARNING "Too many I2O LAN devices.\n");
                                return -EINVAL;
                        }
@@ -786,7 +869,7 @@ int init_module(void)
                        dev = i2o_lan_register_device(i2o_dev);
                        if (dev == NULL)
                        {
-                               printk(KERN_WARNING "Unable to register I2O LAN device\n");
+                               printk(KERN_ERR "Unable to register I2O LAN device\n");
                                continue; // try next one
                        }
                        priv = (struct i2o_lan_local *)dev->priv;       
@@ -800,6 +883,7 @@ int init_module(void)
                                dev->name, i2o_dev->id, i2o_dev->subclass, 
                                priv->unit);
                 }
+               i2o_unlock_controller(iop);
         }
 
        dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1);
@@ -807,6 +891,8 @@ int init_module(void)
        return 0;
 }
 
+#ifdef MODULE
+
 void cleanup_module(void)
 {
        int i;
@@ -831,7 +917,7 @@ void cleanup_module(void)
 #endif
 #ifdef CONFIG_TR
                case I2O_LAN_TR:
-                       unregister_netdev(dev);
+                       unregister_trdev(dev);
                        kfree(dev);
                        break;
 #endif
@@ -848,7 +934,11 @@ void cleanup_module(void)
 }
 
 EXPORT_NO_SYMBOLS;
+
 MODULE_AUTHOR("Univ of Helsinki, CS Department");
 MODULE_DESCRIPTION("I2O Lan OSM");
 
+MODULE_PARM(bucketpost, "i");           // Number of buckets to post
+MODULE_PARM(bucketthresh, "i"); // Bucket post threshold
+
 #endif    
index c8e82bf415b482cfc52042c05998e6068b329ab4..0f05cd96d297384818d428c46cdf5e0b4f8801e4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     i2o_lan.h               LAN Class specific definitions
  *
- *      I2O LAN CLASS OSM       Prototyping, May 7th 1999
+ *      I2O LAN CLASS OSM       Prototyping, May 17th 1999
  *
  *      (C) Copyright 1999      University of Helsinki,
  *                              Department of Computer Science
@@ -9,16 +9,16 @@
  *      This code is still under development / test.
  *
  *      Author:         Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *    
+ *                     Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>    
  */
 
-#ifndef I2O_LAN_H
-#define I2O_LAN_H
+#ifndef _I2O_LAN_H
+#define _I2O_LAN_H
 
 /* Tunable parameters first */
 
-#define I2O_BUCKET_COUNT       64
-#define I2O_BUCKET_THRESH      5
+#define I2O_BUCKET_COUNT       16
+#define I2O_BUCKET_THRESH      0
 
 /* LAN types */
 #define I2O_LAN_ETHERNET       0x0030
@@ -75,7 +75,7 @@
 #define LAN_SDU_SEND           0x3D
 #define LAN_RECEIVE_POST       0x3E
 #define LAN_RESET              0x35
-#define LAN_SUSPEND    0x37
+#define LAN_SUSPEND            0x37
 
 /* LAN DetailedStatusCode defines */
 #define I2O_LAN_DSC_SUCCESS                    0x00
@@ -109,4 +109,4 @@ struct i2o_bucket_descriptor {
        struct i2o_packet_info packet_info[1];
 };
  
-#endif /* I2O_LAN_H */
+#endif /* _I2O_LAN_H */
index 196d58c858236470bf6bcb914d8b4f797ddbf7a0..d0bcaaa18331537b2624dda0dbbe739954a75181 100644 (file)
@@ -10,6 +10,9 @@
  *     modify it under the terms of the GNU General Public License
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
+ *
+ *     TODO:
+ *             Support polled I2O PCI controllers. 
  */
  
 #include <linux/module.h>
@@ -187,9 +190,9 @@ static void i2o_pci_unload(void)
                c=i2o_find_controller(i);
                if(c==NULL)
                        continue;               
+               i2o_unlock_controller(c);
                if(c->type == I2O_TYPE_PCI)
                        i2o_delete_controller(c);
-               i2o_unlock_controller(c);
        }
 }
 
@@ -209,7 +212,6 @@ static void i2o_pci_activate(void)
                        {
                                printk("I2O: Failed to initialize iop%d\n", c->unit);
                                i2o_unlock_controller(c);
-                               free_irq(c->bus.pci.irq, c);
                                i2o_delete_controller(c);
                                continue;
                        }
@@ -239,4 +241,13 @@ void cleanup_module(void)
        i2o_pci_unload();
 }
 
+#else
+__init void i2o_pci_init(void)
+{
+       if(i2o_pci_scan()>=0)
+       {
+               printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
+               i2o_pci_activate();
+       }
+}
 #endif
index cdadc9cdcba3a7d4669cc5ae3abb9037f47f612f..2bb9fcfc4b038375568832bf32bdb38678a95610 100644 (file)
@@ -17,9 +17,9 @@
  *   DISCLAIMER: This code is still under development/test and may cause
  *   your system to behave unpredictably.  Use at your own discretion.
  *
- *   LAN entries by Juha Sievänen(Juha.Sievanen@cs.Helsinki.FI),
+ *   LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
+ *                 Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
  *   University of Helsinki, Department of Computer Science
- *
  */
 
 /*
@@ -61,8 +61,8 @@
  */
 typedef struct _i2o_proc_entry_t
 {
-       char *name;                                             /* entry name */
-       mode_t mode;                                    /* mode */
+       char *name;                     /* entry name */
+       mode_t mode;                    /* mode */
        read_proc_t *read_proc;         /* read func */
        write_proc_t *write_proc;       /* write func */
 } i2o_proc_entry;
@@ -74,66 +74,66 @@ static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_stat(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_dst(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_ds(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_dev(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_ddm(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *);
 static int print_serial_number(char *, int, u8 *, int);
 static int i2o_proc_create_entries(void *, 
-       i2o_proc_entry *p, struct proc_dir_entry *);
-static void i2o_proc_remove_entries(i2o_proc_entry *p, 
-       struct proc_dir_entry *);
+                                  i2o_proc_entry *, struct proc_dir_entry *);
+static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *);
 static int i2o_proc_add_controller(struct i2o_controller *, 
-       struct proc_dir_entry * );
+                                  struct proc_dir_entry * );
 static void i2o_proc_remove_controller(struct i2o_controller *, 
-       struct proc_dir_entry * );
+                                      struct proc_dir_entry * );
 static int create_i2o_procfs(void);
 static int destroy_i2o_procfs(void);
 static void i2o_proc_reply(struct i2o_handler *, struct i2o_controller *,
-                       struct i2o_message *);
+                          struct i2o_message *);
 
 static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *,
                                      void *);
 static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *,
                                      void *);
-static int i2o_proc_read_lan_curr_addr(char *, char **, off_t, int, int *,
-                                      void *);
-#if 0
 static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *,
                                        void *);
-#endif
 static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *,
                                           void *);
 static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *,
                                       void *);
 static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int,
                                             int *, void *);
-#if 0
 static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *,
                                      void *);
-#endif
 static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *,
                                     void *);
 static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *,
                                     void *);
 static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *,
                                        void *);
+static int i2o_proc_read_lan_supp_opt_stats(char *, char **, off_t, int, int *,
+                                           void *);
 static int i2o_proc_read_lan_opt_tx_hist_stats(char *, char **, off_t, int,
                                               int *, void *);
 static int i2o_proc_read_lan_opt_rx_hist_stats(char *, char **, off_t, int,
                                               int *, void *);
+static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int,
+                                      int *, void *);
+static int i2o_proc_read_lan_supp_eth_stats(char *, char **, off_t, int, int *,
+                                           void *);
+static int i2o_proc_read_lan_opt_eth_stats(char *, char **, off_t, int, int *,
+                                          void *);
+static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *,
+                                     void *);
 static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *,
                                        void *);
 
-#if 0
-/* Do we really need this??? */
-
-static loff_t i2o_proc_lseek(struct file *file, loff_t off, int whence)
-{
-       return 0;
-}
-#endif
-
 static struct proc_dir_entry *i2o_proc_dir_root;
 
 /*
@@ -156,6 +156,9 @@ static i2o_proc_entry generic_iop_entries[] =
        {"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL},
        {"stat", S_IFREG|S_IRUGO, i2o_proc_read_stat, NULL},
        {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL},
+       {"dst", S_IFREG|S_IRUGO, i2o_proc_read_dst, NULL},
+       {"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL},
+       {"ds", S_IFREG|S_IRUGO, i2o_proc_read_ds, NULL},
        {NULL, 0, NULL, NULL}
 };
 
@@ -164,8 +167,11 @@ static i2o_proc_entry generic_iop_entries[] =
  */
 static i2o_proc_entry generic_dev_entries[] = 
 {
+       {"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL},
+       {"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL},
        {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev, NULL},
        {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm, NULL},
+       {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL},
        {"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL},
        {NULL, 0, NULL, NULL}
 };
@@ -200,7 +206,7 @@ static i2o_proc_entry rbs_dev_entries[] =
 /* private */
 
 /*
- * LAN specific entries
+ * Generic LAN specific entries
  * 
  * Should groups with r/w entries have their own subdirectory?
  *
@@ -210,34 +216,79 @@ static i2o_proc_entry lan_entries[] =
        /* LAN param groups 0000h-0008h */
        {"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL},
        {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL},
-#if 0
        {"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR,
         i2o_proc_read_lan_mcast_addr, NULL},
-#endif
        {"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR,
         i2o_proc_read_lan_batch_control, NULL},
        {"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL},
        {"lan_media_operation", S_IFREG|S_IRUGO,
         i2o_proc_read_lan_media_operation, NULL},
-#if 0
        {"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL},
-#endif
        {"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL},
        {"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL},
+       /* LAN param groups 0100h, 0180h, 0182h, 0183h */
        {"lan_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL},
+       {"lan_supp_opt_stats", S_IFREG|S_IRUGO,
+        i2o_proc_read_lan_supp_opt_stats, NULL},
        {"lan_opt_tx_stats", S_IFREG|S_IRUGO,
         i2o_proc_read_lan_opt_tx_hist_stats, NULL},
        {"lan_opt_rx_stats", S_IFREG|S_IRUGO,
         i2o_proc_read_lan_opt_rx_hist_stats, NULL},
-       {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL},
-       /* some useful r/w entries, no write yet */
-       {"lan_curr_addr", S_IFREG|S_IRUGO|S_IWUSR,
-        i2o_proc_read_lan_curr_addr, NULL},
+       /* TODO: LAN param group 0184h */
+       {NULL, 0, NULL, NULL}
+};
+
+/*
+ * Ethernet specific LAN entries
+ * 
+ */
+static i2o_proc_entry lan_eth_entries[] = 
+{
+       /* LAN param groups 0200h, 0280h, 0281h */
+       {"lan_eth_stat", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL},
+        {"lan_supp_eth_stats", S_IFREG|S_IRUGO,
+        i2o_proc_read_lan_supp_eth_stats, NULL},
+        {"lan_opt_eth_stats", S_IFREG|S_IRUGO,
+        i2o_proc_read_lan_opt_eth_stats, NULL},
+       {NULL, 0, NULL, NULL}
+};
+
+/*
+ * Token Ring specific LAN entries
+ * 
+ */
+static i2o_proc_entry lan_tr_entries[] = 
+{
+       /* LAN param group 0300h */
+       {"lan_tr_stats", S_IFREG|S_IRUGO,
+        i2o_proc_read_lan_tr_stats, NULL},
+       /* TODO: LAN param group 0380h, 0381h */
+       {NULL, 0, NULL, NULL}
+};
+
+/*
+ * FDDI specific LAN entries
+ * 
+ */
+static i2o_proc_entry lan_fddi_entries[] = 
+{
+       /* LAN param group 0400h */
+       {"lan_fddi_stats", S_IFREG|S_IRUGO,
+        i2o_proc_read_lan_fddi_stats, NULL},
+       /* TODO: LAN param group 0480h, 0481h */
        {NULL, 0, NULL, NULL}
 };
 
+
 static u32 i2o_proc_token = 0;
 
+static char *chtostr(u8 *chars, int n)
+{
+       char tmp[256];
+       tmp[0] = 0;
+        return strncat(tmp, (char *)chars, n);
+}
+
 static char* bus_strings[] = 
 { 
        "Local Bus", 
@@ -253,13 +304,13 @@ static char* bus_strings[] =
 static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
 
 void i2o_proc_reply(struct i2o_handler *phdlr, struct i2o_controller *pctrl,
-       struct i2o_message *pmsg)
+                   struct i2o_message *pmsg)
 {
        i2o_proc_token = I2O_POST_WAIT_OK;
 }
 
 int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, 
-       int *eof, void *data)
+                     int *eof, void *data)
 {
        struct i2o_controller *c = (struct i2o_controller *)data;
        pi2o_hrt hrt;
@@ -303,8 +354,10 @@ int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len,
 
        if(hrt->hrt_version)
        {
+               kfree(workspace);
                len += sprintf(buf+len, 
-                                       "HRT table for controller is too new a version.\n");
+                              "HRT table for controller is too new a version.\n");
+               spin_unlock(&i2o_proc_lock);
                return len;
        }
 
@@ -312,6 +365,7 @@ int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len,
 
        if((count * hrt->entry_len + 8) > 2048) {
                printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n");
+               kfree(workspace);
                len += sprintf(buf+len,
                               "HRT table too big to fit in buffer.\n");
                spin_unlock(&i2o_proc_lock);
@@ -490,7 +544,8 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
                                                break;
 
                                        default:
-                                               len += sprintf(buf+len, ": Unknown");
+                                               len += sprintf(buf+len, ": Unknown (0x%02x)",
+                                                              lct->lct_entry[i].sub_class);
                                                break;
                                }
                                break;
@@ -519,7 +574,8 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
                                                break;
 
                                        default:
-                                               len += sprintf(buf+len, ": Unknown Sub-Class");
+                                               len += sprintf(buf+len, ": Unknown Sub-Class (0x%02x)",
+                                                              lct->lct_entry[i].sub_class & 0xFF);
                                                break;
                                }
                                break;
@@ -642,6 +698,8 @@ int i2o_proc_read_stat(char *buf, char **start, off_t offset, int len,
                len += sprintf(buf+len, "Lowest I2O version supported: ");
                switch(workspace[2]) {
                case 0x00:
+                       len += sprintf(buf+len, "1.0\n");
+                       break;
                case 0x01:
                        len += sprintf(buf+len, "1.5\n");
                        break;
@@ -653,6 +711,8 @@ int i2o_proc_read_stat(char *buf, char **start, off_t offset, int len,
                len += sprintf(buf+len, "Highest I2O version supported: ");
                switch(workspace[3]) {
                case 0x00:
+                       len += sprintf(buf+len, "1.0\n");
+                       break;
                case 0x01:
                        len += sprintf(buf+len, "1.5\n");
                        break;
@@ -666,10 +726,12 @@ int i2o_proc_read_stat(char *buf, char **start, off_t offset, int len,
        len += sprintf(buf+len, "Host Unit ID: %0#6x\n", work16[3]);
        len += sprintf(buf+len, "Segment Number: %0#5x\n", work16[4]&0XFFF);
 
-       len += sprintf(buf+len, "I2O Version: ");
+       len += sprintf(buf+len, "I2O version: ");
        switch(version)
        {
        case 0x00:
+               len += sprintf(buf+len, "1.0\n");
+               break;
        case 0x01:
                len += sprintf(buf+len, "1.5\n");
                break;
@@ -722,7 +784,7 @@ int i2o_proc_read_stat(char *buf, char **start, off_t offset, int len,
        switch (workspace[11])
        {
        case 0x00:
-               len += sprintf(buf+len, "Memory Mapped\n");
+               len += sprintf(buf+len, "Memory mapped\n");
                break;
        case 0x01:
                len += sprintf(buf+len, "Memory mapped only\n");
@@ -749,26 +811,27 @@ int i2o_proc_read_stat(char *buf, char **start, off_t offset, int len,
 
        len += sprintf(buf+len, "LCT Size: %d\n", work32[13]);
 
-       len += sprintf(buf+len, "Desired Private Memory Space: %d kB\n", 
+       len += sprintf(buf+len, "Desired private memory space: %d kB\n", 
                                                work32[15]>>10);
-       len += sprintf(buf+len, "Allocated Private Memory Space: %d kB\n", 
+       len += sprintf(buf+len, "Allocated private memory space: %d kB\n", 
                                                work32[16]>>10);
-       len += sprintf(buf+len, "Private Memory Base Address: %0#10x\n", 
+       len += sprintf(buf+len, "Private memory base address: %0#10x\n", 
                                                work32[17]);
-       len += sprintf(buf+len, "Desired Private I/O Space: %d kB\n", 
+       len += sprintf(buf+len, "Desired private I/O space: %d kB\n", 
                                                work32[18]>>10);
-       len += sprintf(buf+len, "Allocated Private I/O Space: %d kB\n", 
+       len += sprintf(buf+len, "Allocated private I/O space: %d kB\n", 
                                                work32[19]>>10);
-       len += sprintf(buf+len, "Private I/O Base Address: %0#10x\n", 
+       len += sprintf(buf+len, "Private I/O base address: %0#10x\n", 
                                                work32[20]);
 
+       kfree(workspace);
        spin_unlock(&i2o_proc_lock);
 
        return len;
 }
 
 int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, 
-       int *eof, void *data)
+                    int *eof, void *data)
 {
        struct i2o_controller *c = (struct i2o_controller*)data;
        static u32 work32[5];
@@ -779,14 +842,14 @@ int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len,
 
        static char *cpu_table[] =
        {
-               "Intel 80960 Series",
-               "AMD2900 Series",
-               "Motorola 68000 Series",
-               "ARM Series",
-               "MIPS Series",
-               "Sparc Series",
-               "PowerPC Series",
-               "Intel x86 Series"
+               "Intel 80960 series",
+               "AMD2900 series",
+               "Motorola 68000 series",
+               "ARM series",
+               "MIPS series",
+               "Sparc series",
+               "PowerPC series",
+               "Intel x86 series"
        };
 
        spin_lock(&i2o_proc_lock);
@@ -807,15 +870,15 @@ int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       len += sprintf(buf, "IOP Hardware Information Table\n");
+       len += sprintf(buf, "IOP Hardware Information Table (group = 0x0000)\n");
 
-       len += sprintf(buf+len, "I2O Vendor ID: %0#6x\n", work16[0]);
-       len += sprintf(buf+len, "Product ID: %0#6x\n", work16[1]);
-       len += sprintf(buf+len, "RAM: %dkB\n", work32[1]>>10);
-       len += sprintf(buf+len, "Non-Volatile Storage: %dkB\n", work32[2]>>10);
+       len += sprintf(buf+len, "I2O Vendor ID        : %0#6x\n", work16[0]);
+       len += sprintf(buf+len, "Product ID           : %0#6x\n", work16[1]);
+       len += sprintf(buf+len, "RAM                  : %dkB\n", work32[1]>>10);
+       len += sprintf(buf+len, "Non-Volatile Storage : %dkB\n", work32[2]>>10);
 
        hwcap = work32[3];
-       len += sprintf(buf+len, "Capabilities:\n");
+       len += sprintf(buf+len, "Capabilities :\n");
        if(hwcap&0x00000001)
                len += sprintf(buf+len, "   Self-booting\n");
        if(hwcap&0x00000002)
@@ -827,7 +890,7 @@ int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len,
        if(hwcap&0x00000010)
                len += sprintf(buf+len, "   Battery-backed RAM\n");
 
-       len += sprintf(buf+len, "CPU: ");
+       len += sprintf(buf+len, "CPU                 : ");
        if(work8[16] > 8)
                len += sprintf(buf+len, "Unknown\n");
        else
@@ -839,14 +902,407 @@ int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len,
        return len;
 }
 
+
+/* Executive group 0003h - Executing DDM List (table) */
+int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, 
+                           int *eof, void *data)
+{
+       struct i2o_controller *c = (struct i2o_controller*)data;
+       int token;
+       int i;
+
+       typedef struct _i2o_exec_execute_ddm_table {
+               u16 ddm_tid;
+               u8  module_type;
+               u8  reserved;
+               u16 i2o_vendor_id;
+               u16 module_id;
+               u8  module_name[24];
+               u8  module_version[4];
+               u32 data_size;
+               u32 code_size;
+       } i2o_exec_execute_ddm_table, *pi2o_exec_execute_ddm_table;
+
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES];
+       } result;
+
+       i2o_exec_execute_ddm_table ddm_table;
+
+       spin_lock(&i2o_proc_lock);
+       len = 0;
+
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                               c, ADAPTER_TID, proc_context,
+                               0x0003, -1,
+                               NULL, 0,
+                               &result, sizeof(result), &i2o_proc_token);
+
+       if (token<0)
+               switch (token)
+               {
+               case -ETIMEDOUT:
+                       len += sprintf(buf, "Timeout reading table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               case -ENOMEM:
+                       len += sprintf(buf, "No free memory to read the table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               default:
+                       len += sprintf(buf, "Error reading group. BlockStatus %d\n",
+                                      token);
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
+
+       len += sprintf(buf+len, "Tid   Type            Vendor Id     Name                     Vrs  Data_size Code_size\n");
+       ddm_table=result.ddm_table[0];
+
+       for(i=0; i < result.row_count; ddm_table=result.ddm_table[++i])
+       {
+               len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF);
+
+               switch(ddm_table.module_type)
+               {
+               case 0x01:
+                       len += sprintf(buf+len, "Downloaded DDM  ");
+                       break;                  
+               case 0x22:
+                       len += sprintf(buf+len, "Embedded DDM    ");
+                       break;
+               default:
+                       len += sprintf(buf+len, "                ");
+               }
+
+               len += sprintf(buf+len, "%-0#7x", ddm_table.i2o_vendor_id);
+               len += sprintf(buf+len, "%-0#7x", ddm_table.module_id);
+               len += sprintf(buf+len, "%-25s", chtostr(ddm_table.module_name, 24));
+               len += sprintf(buf+len, "%-6s", chtostr(ddm_table.module_version,4));
+               len += sprintf(buf+len, "%8d  ", ddm_table.data_size);
+               len += sprintf(buf+len, "%8d", ddm_table.code_size);
+
+               len += sprintf(buf+len, "\n");
+       }
+
+       spin_unlock(&i2o_proc_lock);
+
+       return len;
+}
+
+
+/* Executive group 0004h - Driver Store (scalar) */
+int i2o_proc_read_ds(char *buf, char **start, off_t offset, int len, 
+                    int *eof, void *data)
+{
+       struct i2o_controller *c = (struct i2o_controller*)data;
+       u32 work32[8];
+       int token;
+
+       spin_lock(&i2o_proc_lock);
+
+       len = 0;
+
+       token = i2o_query_scalar(c, ADAPTER_TID, proc_context, 0x0004, -1, 
+                                &work32, sizeof(work32), &i2o_proc_token);
+
+       if (token<0)
+       {
+               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       len += sprintf(buf+len, "Module limit  : %d\n"
+                               "Module count  : %d\n"
+                               "Current space : %d kB\n"
+                               "Free space    : %d kB\n", 
+                       work32[0], work32[1], work32[2]>>10, work32[3]>>10);
+
+       spin_unlock(&i2o_proc_lock);
+
+       return len;
+}
+
+
+/* Executive group 0005h - Driver Store Table (table) */
+int i2o_proc_read_dst(char *buf, char **start, off_t offset, int len, 
+                     int *eof, void *data)
+{
+       typedef struct _i2o_driver_store {
+               u16 stored_ddm_index;
+               u8  module_type;
+               u8  reserved;
+               u16 i2o_vendor_id;
+               u16 module_id;
+               u8  module_name_version[28];
+               u8  date[8];
+               u32 module_size;
+               u32 mpb_size;
+               u32 module_flags;
+       } i2o_driver_store_table;
+
+       struct i2o_controller *c = (struct i2o_controller*)data;
+       int token;
+       int i;
+
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               i2o_driver_store_table dst[MAX_I2O_MODULES];
+       } result;
+
+       i2o_driver_store_table dst;
+
+       spin_lock(&i2o_proc_lock);
+
+       len = 0;
+
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                               c, ADAPTER_TID, proc_context,
+                               0x0005, -1,
+                               NULL, 0,
+                               &result, sizeof(result), &i2o_proc_token);
+
+       if (token<0)
+               switch (token)
+               {
+               case -ETIMEDOUT:
+                       len += sprintf(buf, "Timeout reading table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               case -ENOMEM:
+                       len += sprintf(buf, "No free memory to read the table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               default:
+                       len += sprintf(buf, "Error reading group. "
+                                       "BlockStatus %d\n",token);
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
+
+       len += sprintf(buf+len, "#  Type            Vendor Id      Name                    Vrs  Date     Mod_size Par_size Flags\n");   
+
+       for(i=0, dst=result.dst[0]; i < result.row_count; dst=result.dst[++i])
+       {
+               len += sprintf(buf+len, "%-3d", dst.stored_ddm_index);
+               switch(dst.module_type)
+               {
+               case 0x01:
+                       len += sprintf(buf+len, "Downloaded DDM  ");
+                       break;                  
+               case 0x22:
+                       len += sprintf(buf+len, "Embedded DDM    ");
+                       break;
+               default:
+                       len += sprintf(buf+len, "                ");
+               }
+
+#if 0
+               if(c->i2oversion == 0x02)
+                       len += sprintf(buf+len, "%-d", dst.module_state);
+#endif
+
+               len += sprintf(buf+len, "%-0#7x", dst.i2o_vendor_id);
+               len += sprintf(buf+len, "%-0#8x", dst.module_id);
+               len += sprintf(buf+len, "%-29s", chtostr(dst.module_name_version,28));
+               len += sprintf(buf+len, "%-9s", chtostr(dst.date,8));
+               len += sprintf(buf+len, "%8d ", dst.module_size);
+               len += sprintf(buf+len, "%8d ", dst.mpb_size);
+               len += sprintf(buf+len, "0x%04x", dst.module_flags);
+#if 0
+               if(c->i2oversion == 0x02)
+                       len += sprintf(buf+len, "%d",
+                                      dst.notification_level);
+#endif
+               len += sprintf(buf+len, "\n");
+       }
+
+       spin_unlock(&i2o_proc_lock);
+
+       return len;
+}
+
+
+/* Generic group F000h - Params Descriptor (table) */
+int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, 
+                        int *eof, void *data)
+{
+       struct i2o_controller *c = (struct i2o_controller*)data;
+       int token;
+       int i;
+       int rows;
+       u16 work16[2048];
+       u16 *group=work16;
+       int more;
+       
+       spin_lock(&i2o_proc_lock);
+
+       len = 0;
+
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                               c, ADAPTER_TID, proc_context,
+                               0xF000, -1,
+                               NULL, 0,
+                               &work16, sizeof(work16), &i2o_proc_token);
+
+       if (token<0)
+               switch (token)
+               {
+               case -ETIMEDOUT:
+                       len += sprintf(buf, "Timeout reading table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               case -ENOMEM:
+                       len += sprintf(buf, "No free memory to read the table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               default:
+                       len += sprintf(buf, "Error reading table. BlockStatus %d\n",
+                                      token);
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
+
+       rows=work16[4];
+       more=work16[5];
+
+       len += sprintf(buf+len, "\nPARAMS DESCRIPTOR TABLE:\n\n");
+       len += sprintf(buf+len, "#  Group   FieldCount RowCount Type   Add Del Clear\n");
+
+       group+=64;
+
+       for(i=0; i < rows; i++, group+=16)
+       {
+               len += sprintf(buf+len, "%-3d", i);
+
+               len += sprintf(buf+len, "%-0#6x ", group[0]);
+               len += sprintf(buf+len, "%10d ", group[1]);
+               len += sprintf(buf+len, "%8d ", group[2]);
+
+               if(group[3]&0x1)
+                       len += sprintf(buf+len, "Table  ");
+               else
+                       len += sprintf(buf+len, "Scalar ");
+               if(group[3]&0x2)
+                       len += sprintf(buf+len, "x   ");
+               else
+                       len += sprintf(buf+len, "    ");
+               if(group[3]&0x4)
+                       len += sprintf(buf+len, "x   ");
+               else
+                       len += sprintf(buf+len, "    ");
+               if(group[3]&0x8)
+                       len += sprintf(buf+len, "x   ");
+               else
+                       len += sprintf(buf+len, "    ");
+
+               len += sprintf(buf+len, "\n");
+       }
+
+       if(more)
+               len += sprintf(buf+len, "There is more...\n");
+
+       spin_unlock(&i2o_proc_lock);
+
+       return len;
+}
+
+
+/* Generic group F005h - Private message extensions (table) */
+int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, 
+                           int *eof, void *data)
+{
+       struct i2o_controller *c = (struct i2o_controller*)data;
+       int token;
+       int i;
+       int rows;
+       int more;
+       u16 work16[1024];
+       u16 *field=work16;
+
+       spin_lock(&i2o_proc_lock);
+
+       len = 0;
+
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                               c, ADAPTER_TID, proc_context,
+                               0xF000, -1,
+                               NULL, 0,
+                               &work16, sizeof(work16), &i2o_proc_token);
+
+       if (token<0)
+               switch (token)
+               {
+               case -ETIMEDOUT:
+                       len += sprintf(buf, "Timeout reading table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               case -ENOMEM:
+                       len += sprintf(buf, "No free memory to read the table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               default:
+                       len += sprintf(buf, "Error reading field. BlockStatus %d\n",
+                                      token);
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
+
+       rows=work16[4];
+       more=work16[5];
+       
+       len += sprintf(buf+len, "Instance#  OrgId  FunctionCode\n");
+
+       field+=64;
+       for(i=0; i < rows; i++, field+=16)
+       {
+               len += sprintf(buf+len, "%0#9x ", field[0]);
+               len += sprintf(buf+len, "%0#6x ", work16[1]);
+               len += sprintf(buf+len, "%0#6x", work16[2]);
+
+               len += sprintf(buf+len, "\n");
+       }
+
+       if(more)
+               len += sprintf(buf+len, "There is more...\n");
+
+       spin_unlock(&i2o_proc_lock);
+
+       return len;
+}
+
+
 int i2o_proc_read_dev(char *buf, char **start, off_t offset, int len, 
-       int *eof, void *data)
+                     int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
        static u32 work32[128];         // allow for "stuff" + up to 256 byte (max) serial number
                                        // == (allow) 512d bytes (max)
        static u16 *work16 = (u16*)work32;
-       char sz[17];
        int token;
 
        spin_lock(&i2o_proc_lock);
@@ -866,34 +1322,21 @@ int i2o_proc_read_dev(char *buf, char **start, off_t offset, int len,
                spin_unlock(&i2o_proc_lock);
                return len;
        }
-
-       len += sprintf(buf, "Device Class: %s\n", i2o_get_class_name(work16[0]));
-
-       len += sprintf(buf+len, "Owner TID:    %0#5x\n", work16[2]);
-       len += sprintf(buf+len, "Parent TID:   %0#5x\n", work16[3]);
-
-       memcpy(sz, work32+2, 16);
-       sz[16] = '\0';
-       len += sprintf(buf+len, "Vendor Info:  %s\n", sz);
-
-       memcpy(sz, work32+6, 16);
-       sz[16] = '\0';
-       len += sprintf(buf+len, "Product Info: %s\n", sz);
-
-       memcpy(sz, work32+10, 16);
-       sz[16] = '\0';
-       len += sprintf(buf+len, "Description:  %s\n", sz);
-
-       memcpy(sz, work32+14, 8);
-       sz[8] = '\0';
-       len += sprintf(buf+len, "Product Revision: %s\n", sz);
-
-       len += sprintf(buf+len, "Serial Number: ");
+       
+       len += sprintf(buf,     "Device Class  : %s\n", i2o_get_class_name(work16[0]));
+       len += sprintf(buf+len, "Owner TID     : %0#5x\n", work16[2]);
+       len += sprintf(buf+len, "Parent TID    : %0#5x\n", work16[3]);
+       len += sprintf(buf+len, "Vendor info   : %s\n", chtostr((u8 *)(work32+2), 16));
+       len += sprintf(buf+len, "Product info  : %s\n", chtostr((u8 *)(work32+6), 16));
+       len += sprintf(buf+len, "Description   : %s\n", chtostr((u8 *)(work32+10), 16));
+       len += sprintf(buf+len, "Product rev.  : %s\n", chtostr((u8 *)(work32+14), 8));
+
+       len += sprintf(buf+len, "Serial number : ");
        len = print_serial_number(buf, len,
                        (u8*)(work32+16),
-                                                       /* allow for SNLen plus
-                                                        * possible trailing '\0'
-                                                        */
+                                               /* allow for SNLen plus
+                                                * possible trailing '\0'
+                                                */
                        sizeof(work32)-(16*sizeof(u32))-2
                                );
        len +=  sprintf(buf+len, "\n");
@@ -920,13 +1363,12 @@ int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len,
 
 
 int i2o_proc_read_ddm(char *buf, char **start, off_t offset, int len, 
-       int *eof, void *data)
+                     int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
        static u32 work32[128];
        static u16 *work16 = (u16*)work32;
        int token;
-       char mod[25];
 
        spin_lock(&i2o_proc_lock);
        
@@ -946,22 +1388,16 @@ int i2o_proc_read_ddm(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       len += sprintf(buf, "Registering DDM TID: 0x%03x\n", work16[0]&0xFFF);
-
-       memcpy(mod, (char*)(work16+1), 24);
-       mod[24] = '\0';
-       len += sprintf(buf+len, "Module Name: %s\n", mod);
-
-       memcpy(mod, (char*)(work16+13), 8);
-       mod[8] = '\0';
-       len += sprintf(buf+len, "Module Rev: %s\n", mod);
+       len += sprintf(buf,     "Registering DDM TID : 0x%03x\n", work16[0]&0xFFF);
+       len += sprintf(buf+len, "Module name         : %s\n", chtostr((u8 *)(work16+1), 24));
+       len += sprintf(buf+len, "Module revision     : %s\n", chtostr((u8 *)(work16+13), 8));
 
-       len += sprintf(buf+len, "Serial Number: ");
+       len += sprintf(buf+len, "Serial number       : ");
        len = print_serial_number(buf, len,
                        (u8*)(work16+17),
-                                                       /* allow for SNLen plus
-                                                        * possible trailing '\0'
-                                                        */
+                                       /* allow for SNLen plus
+                                        * possible trailing '\0'
+                                        */
                        sizeof(work32)-(17*sizeof(u16))-2
                                );
        len += sprintf(buf+len, "\n");
@@ -972,13 +1408,12 @@ int i2o_proc_read_ddm(char *buf, char **start, off_t offset, int len,
 }
 
 int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, 
-       int *eof, void *data)
+                       int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 work32[128];
+       static u32 work32[256];
        int token;
-       char sz[65];
-
        spin_lock(&i2o_proc_lock);
        
        len = 0;
@@ -997,27 +1432,73 @@ int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       memcpy(sz, (char*)work32, 64);
-       sz[64] = '\0';
-       len += sprintf(buf, "Device Name: %s\n", sz);
+       len += sprintf(buf,     "Device name     : %s\n", chtostr((u8 *)work32, 64));
+       len += sprintf(buf+len, "Service name    : %s\n", chtostr((u8 *)(work32+16), 64));
+       len += sprintf(buf+len, "Physical name   : %s\n", chtostr((u8 *)(work32+32), 64));
+       len += sprintf(buf+len, "Instance number : %s\n", chtostr((u8 *)(work32+48), 4));
+        
+       spin_unlock(&i2o_proc_lock);
+
+       return len;
+}
+
+
+int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, 
+                            int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       static u32 work32[12];
+       static u16 *work16 = (u16 *)work32;
+       static u8 *work8 = (u8 *)work32;
+       int token;
+
+       spin_lock(&i2o_proc_lock);
+       
+       len = 0;
+
+       token = i2o_query_scalar(d->controller, d->id, proc_context, 
+                                0xF103,        // ParamGroup F103h (SGL Operating Limits)
+                                -1,            // all fields
+                                &work32,
+                                sizeof(work32),
+                                &i2o_proc_token);
 
-       memcpy(sz, (char*)(work32+16), 64);
-       sz[64] = '\0';
-       len += sprintf(buf+len, "Service Name: %s\n", sz);
+       if(token < 0)
+       {
+               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
 
-       memcpy(sz, (char*)(work32+32), 64);
-       sz[64] = '\0';
-       len += sprintf(buf+len, "Physical Name: %s\n", sz);
+       len += sprintf(buf,     "SGL chain size        : %d\n", work32[0]);
+       len += sprintf(buf+len, "Max SGL chain size    : %d\n", work32[1]);
+       len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]);
+       len += sprintf(buf+len, "SGL frag count        : %d\n", work16[6]);
+       len += sprintf(buf+len, "Max SGL frag count    : %d\n", work16[7]);
+       len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]);
 
-       memcpy(sz, (char*)(work32+48), 4);
-       sz[4] = '\0';
-       len += sprintf(buf+len, "Instance Number: %s\n", sz);
+       if (d->i2oversion == 0x02)
+       {
+               len += sprintf(buf+len, "SGL data alignment    : %d\n", work16[8]);
+               len += sprintf(buf+len, "SGL addr limit        : %d\n", work8[20]);
+               len += sprintf(buf+len, "SGL addr sizes supported : ");
+               if (work8[21] & 0x01)
+                       len += sprintf(buf+len, "32 bit ");
+               if (work8[21] & 0x02)
+                       len += sprintf(buf+len, "64 bit ");
+               if (work8[21] & 0x04)
+                       len += sprintf(buf+len, "96 bit ");
+               if (work8[21] & 0x08)
+                       len += sprintf(buf+len, "128 bit ");
+               len += sprintf(buf+len, "\n");
+       }
 
        spin_unlock(&i2o_proc_lock);
 
        return len;
 }
 
+
 static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len)
 {
        int i;
@@ -1068,22 +1549,22 @@ static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len)
 
                case I2O_SNFORMAT_LAN48_MAC:            /* LAN-48 MAC Address */
                        pos += sprintf(buff+pos, 
-                                               "LAN-48 MAC Address @ %02X:%02X:%02X:%02X:%02X:%02X",
+                                               "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X",
                                                serialno[2], serialno[3],
                                                serialno[4], serialno[5],
                                                serialno[6], serialno[7]);
+                       break;
 
                case I2O_SNFORMAT_WAN:                  /* WAN MAC Address */
                        /* FIXME: Figure out what a WAN access address looks like?? */
                        pos += sprintf(buff+pos, "WAN Access Address");
                        break;
 
-
 /* plus new in v2.0 */
                case I2O_SNFORMAT_LAN64_MAC:            /* LAN-64 MAC Address */
                        /* FIXME: Figure out what a LAN-64 address really looks like?? */
                        pos += sprintf(buff+pos, 
-                                               "LAN-64 MAC Address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X",
+                                               "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X",
                                                serialno[8], serialno[9],
                                                serialno[2], serialno[3],
                                                serialno[4], serialno[5],
@@ -1114,13 +1595,222 @@ static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len)
                case I2O_SNFORMAT_UNKNOWN:              /* Unknown 0    */
                case I2O_SNFORMAT_UNKNOWN2:             /* Unknown 0xff */
                default:
-                       pos += sprintf(buff+pos, "Unknown Data Format");
+                       pos += sprintf(buff+pos, "Unknown data format (0x%02x)",
+                                      serialno[0]);
                        break;
        }
 
        return pos;
 }
 
+const char * i2o_get_connector_type(int conn)
+{
+       int idx = 16;
+       static char *i2o_connector_type[] = {
+               "OTHER",
+               "UNKNOWN",
+               "AUI",
+               "UTP",
+               "BNC",
+               "RJ45",
+               "STP DB9",
+               "FIBER MIC",
+               "APPLE AUI",
+               "MII",
+               "DB9",
+               "HSSDC",
+               "DUPLEX SC FIBER",
+               "DUPLEX ST FIBER",
+               "TNC/BNC",
+               "HW DEFAULT"
+       };
+
+       switch(conn)
+       {
+       case 0x00000000:
+               idx = 0;
+               break;
+       case 0x00000001:
+               idx = 1;
+               break;
+       case 0x00000002:
+               idx = 2;
+               break;
+       case 0x00000003:
+               idx = 3;
+               break;
+       case 0x00000004:
+               idx = 4;
+               break;
+       case 0x00000005:
+               idx = 5;
+               break;
+       case 0x00000006:
+               idx = 6;
+               break;
+       case 0x00000007:
+               idx = 7;
+               break;
+       case 0x00000008:
+               idx = 8;
+               break;
+       case 0x00000009:
+               idx = 9;
+               break;
+       case 0x0000000A:
+               idx = 10;
+               break;
+       case 0x0000000B:
+               idx = 11;
+               break;
+       case 0x0000000C:
+               idx = 12;
+               break;
+       case 0x0000000D:
+               idx = 13;
+               break;
+       case 0x0000000E:
+               idx = 14;
+               break;
+       case 0xFFFFFFFF:
+               idx = 15;
+               break;
+       }
+
+       return i2o_connector_type[idx];
+}
+
+
+const char * i2o_get_connection_type(int conn)
+{
+       int idx = 0;
+       static char *i2o_connection_type[] = {
+               "Unknown",
+               "AUI",
+               "10BASE5",
+               "FIORL",
+               "10BASE2",
+               "10BROAD36",
+               "10BASE-T",
+               "10BASE-FP",
+               "10BASE-FB",
+               "10BASE-FL",
+               "100BASE-TX",
+               "100BASE-FX",
+               "100BASE-T4",
+               "1000BASE-SX",
+               "1000BASE-LX",
+               "1000BASE-CX",
+               "1000BASE-T",
+               "100VG-ETHERNET",
+               "100VG-TOKEN RING",
+               "4MBIT TOKEN RING",
+               "16 Mb Token Ring",
+               "125 MBAUD FDDI",
+               "Point-to-point",
+               "Arbitrated loop",
+               "Public loop",
+               "Fabric",
+               "Emulation",
+               "Other",
+               "HW default"
+       };
+
+       switch(conn)
+       {
+       case I2O_LAN_UNKNOWN:
+               idx = 0;
+               break;
+       case I2O_LAN_AUI:
+               idx = 1;
+               break;
+       case I2O_LAN_10BASE5:
+               idx = 2;
+               break;
+       case I2O_LAN_FIORL:
+               idx = 3;
+               break;
+       case I2O_LAN_10BASE2:
+               idx = 4;
+               break;
+       case I2O_LAN_10BROAD36:
+               idx = 5;
+               break;
+       case I2O_LAN_10BASE_T:
+               idx = 6;
+               break;
+       case I2O_LAN_10BASE_FP:
+               idx = 7;
+               break;
+       case I2O_LAN_10BASE_FB:
+               idx = 8;
+               break;
+       case I2O_LAN_10BASE_FL:
+               idx = 9;
+               break;
+       case I2O_LAN_100BASE_TX:
+               idx = 10;
+               break;
+       case I2O_LAN_100BASE_FX:
+               idx = 11;
+               break;
+       case I2O_LAN_100BASE_T4:
+               idx = 12;
+               break;
+       case I2O_LAN_1000BASE_SX:
+               idx = 13;
+               break;
+       case I2O_LAN_1000BASE_LX:
+               idx = 14;
+               break;
+       case I2O_LAN_1000BASE_CX:
+               idx = 15;
+               break;
+       case I2O_LAN_1000BASE_T:
+               idx = 16;
+               break;
+       case I2O_LAN_100VG_ETHERNET:
+               idx = 17;
+               break;
+       case I2O_LAN_100VG_TR:
+               idx = 18;
+               break;
+       case I2O_LAN_4MBIT:
+               idx = 19;
+               break;
+       case I2O_LAN_16MBIT:
+               idx = 20;
+               break;
+       case I2O_LAN_125MBAUD:
+               idx = 21;
+               break;
+       case I2O_LAN_POINT_POINT:
+               idx = 22;
+               break;
+       case I2O_LAN_ARB_LOOP:
+               idx = 23;
+               break;
+       case I2O_LAN_PUBLIC_LOOP:
+               idx = 24;
+               break;
+       case I2O_LAN_FABRIC:
+               idx = 25;
+               break;
+       case I2O_LAN_EMULATION:
+               idx = 26;
+               break;
+       case I2O_LAN_OTHER:
+               idx = 27;
+               break;
+       case I2O_LAN_DEFAULT:
+               idx = 28;
+               break;
+       }
+
+       return i2o_connection_type[idx];
+}
+
+
 /* LAN group 0000h - Device info (scalar) */
 int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, 
                               int *eof, void *data)
@@ -1145,7 +1835,7 @@ int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       len += sprintf(buf, "LAN Type ........... ");
+       len += sprintf(buf, "LAN Type            : ");
        switch (work16[0])
        {
        case 0x0030:
@@ -1164,7 +1854,7 @@ int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len,
                len += sprintf(buf+len, "Fibre Channel, ");
                break;
        default:
-               len += sprintf(buf+len, "Unknown type, ");
+               len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]);
                break;
        }
 
@@ -1178,7 +1868,7 @@ int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len,
        else
                len += sprintf(buf+len, "simplex\n");
 
-       len += sprintf(buf+len, "Address format:      ");
+       len += sprintf(buf+len, "Address format      : ");
        switch(work8[4]) {
        case 0x00:
                len += sprintf(buf+len, "IEEE 48bit\n");
@@ -1187,11 +1877,11 @@ int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len,
                len += sprintf(buf+len, "FC IEEE\n");
                break;
        default:
-               len += sprintf(buf+len, "Unknown\n");
+               len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]);
                break;
        }
 
-       len += sprintf(buf+len, "State:               ");
+       len += sprintf(buf+len, "State               : ");
        switch(work8[5])
        {
        case 0x00:
@@ -1210,7 +1900,14 @@ int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len,
                len += sprintf(buf+len, "Resetting\n");
                break;
        case 0x05:
-               len += sprintf(buf+len, "Error\n");
+               len += sprintf(buf+len, "ERROR: ");
+               if(work16[3]&0x0001)
+                       len += sprintf(buf+len, "TxCU inoperative ");
+               if(work16[3]&0x0002)
+                       len += sprintf(buf+len, "RxCU inoperative ");
+               if(work16[3]&0x0004)
+                       len += sprintf(buf+len, "Local mem alloc ");
+               len += sprintf(buf+len, "\n");
                break;
        case 0x06:
                len += sprintf(buf+len, "Operational no Rx\n");
@@ -1223,27 +1920,18 @@ int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len,
                break;
        }
 
-       len += sprintf(buf+len, "Error status:      ");
-       if(work16[3]&0x0001)
-               len += sprintf(buf+len, "Transmit Control Unit Inoperative ");
-       if(work16[3]&0x0002)
-               len += sprintf(buf+len, "Receive Control Unit Inoperative\n");
-       if(work16[3]&0x0004)
-               len += sprintf(buf+len, "Local memory Allocation Error\n");
-       len += sprintf(buf+len, "\n");
-
-       len += sprintf(buf+len, "Min Packet size:     %d\n", work32[2]);
-       len += sprintf(buf+len, "Max Packet size:     %d\n", work32[3]);
-       len += sprintf(buf+len, "HW Address:          "
+       len += sprintf(buf+len, "Min packet size     : %d\n", work32[2]);
+       len += sprintf(buf+len, "Max packet size     : %d\n", work32[3]);
+       len += sprintf(buf+len, "HW address          : "
                       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
                       work8[16],work8[17],work8[18],work8[19],
                       work8[20],work8[21],work8[22],work8[23]);
 
-       len += sprintf(buf+len, "Max Tx Wire Speed:   " FMT_U64_HEX " bps\n", U64_VAL(&work64[3]));
-       len += sprintf(buf+len, "Max Rx Wire Speed:   " FMT_U64_HEX " bps\n", U64_VAL(&work64[4]));
+       len += sprintf(buf+len, "Max Tx wire speed   : %d bps\n", work64[3]);
+       len += sprintf(buf+len, "Max Rx wire speed   : %d bps\n", work64[4]);
 
-       len += sprintf(buf+len, "Min SDU packet size: 0x%08x\n", work32[10]);
-       len += sprintf(buf+len, "Max SDU packet size: 0x%08x\n", work32[11]);
+       len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]);
+       len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]);
 
        spin_unlock(&i2o_proc_lock);
        return len;
@@ -1270,60 +1958,65 @@ int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       len += sprintf(buf, "Active address: "
+       len += sprintf(buf,     "Active address          : "
                       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
                       work8[0],work8[1],work8[2],work8[3],
                       work8[4],work8[5],work8[6],work8[7]);
-       len += sprintf(buf+len, "Current address: "
+       len += sprintf(buf+len, "Current address         : "
                       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
                       work8[8],work8[9],work8[10],work8[11],
                       work8[12],work8[13],work8[14],work8[15]);
-       len += sprintf(buf+len, "Functional address mask: "
+       len += sprintf(buf+len, "Functional address mask : "
                       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
                       work8[16],work8[17],work8[18],work8[19],
                       work8[20],work8[21],work8[22],work8[23]);
 
-       len += sprintf(buf+len, "Filter mask: 0x%08x\n", work32[6]);
-       len += sprintf(buf+len, "HW/DDM capabilities: 0x%08x\n", work32[7]);
-       len += sprintf(buf+len, "    Unicast packets %ssupported (%sabled)\n",
-                      (work32[7]&0x00000001)?"":"not ",
-                      (work32[6]&0x00000001)?"en":"dis");
-       len += sprintf(buf+len, "    Promiscuous mode %ssupported (%sabled)\n",
-                      (work32[7]&0x00000002)?"":"not",
-                      (work32[6]&0x00000002)?"en":"dis");
-       len += sprintf(buf+len,
-                      "    Multicast promiscuous mode %ssupported (%sabled)\n",
-                      (work32[7]&0x00000004)?"":"not ",
-                      (work32[6]&0x00000004)?"en":"dis");
-       len += sprintf(buf+len,
-                      "    Broadcast Reception disabling %ssupported (%sabled)\n",
-                      (work32[7]&0x00000100)?"":"not ",
-                      (work32[6]&0x00000100)?"en":"dis");
-       len += sprintf(buf+len,
-                      "    Multicast Reception disabling %ssupported (%sabled)\n",
-                      (work32[7]&0x00000200)?"":"not ",
-                      (work32[6]&0x00000200)?"en":"dis");
-       len += sprintf(buf+len,
-                      "    Functional address disabling %ssupported (%sabled)\n",
-                      (work32[7]&0x00000400)?"":"not ",
-                      (work32[6]&0x00000400)?"en":"dis");
+       len += sprintf(buf+len, "HW/DDM capabilities : 0x%08x\n", work32[7]);
+       len += sprintf(buf+len, "    Unicast packets %ssupported\n",
+                      (work32[7]&0x00000001)?"":"not ");
+       len += sprintf(buf+len, "    Promiscuous mode %ssupported\n",
+                      (work32[7]&0x00000002)?"":"not");
+       len += sprintf(buf+len, "    Promiscuous multicast mode %ssupported\n",
+                      (work32[7]&0x00000004)?"":"not ");
+       len += sprintf(buf+len,"    Broadcast reception disabling %ssupported\n",
+                      (work32[7]&0x00000100)?"":"not ");
+       len += sprintf(buf+len,"    Multicast reception disabling %ssupported\n",
+                      (work32[7]&0x00000200)?"":"not ");
+       len += sprintf(buf+len,"    Functional address disabling %ssupported\n",
+                      (work32[7]&0x00000400)?"":"not ");
        len += sprintf(buf+len, "    MAC reporting %ssupported\n",
-                      (work32[7]&0x00000800)?"":"not ");                      
-
-       len += sprintf(buf+len, "    MAC Reporting mode: ");
-       if (work32[6]&0x00000800)
-               len += sprintf(buf+len, "Pass only priority MAC packets\n");
-       else if (work32[6]&0x00001000)
-               len += sprintf(buf+len, "Pass all MAC packets\n");
-       else if (work32[6]&0x00001800)
-               len += sprintf(buf+len, "Pass all MAC packets (promiscuous)\n");
-       else
-               len += sprintf(buf+len, "Do not pass MAC packets\n");
-
-       len += sprintf(buf+len, "Number of multicast addesses: %d\n", work32[8]);
-       len += sprintf(buf+len, "Perfect filtering for max %d multicast addesses\n",
+                      (work32[7]&0x00000800)?"":"not ");
+
+       len += sprintf(buf+len, "Filter mask : 0x%08x\n", work32[6]);
+       len += sprintf(buf+len, "    Unicast packets %s\n",
+               (work32[6]&0x00000001)?"rejected":"enabled");
+       len += sprintf(buf+len, "    Promiscuous mode %s\n",
+               (work32[6]&0x00000002)?"enabled":"disabled");
+       len += sprintf(buf+len, "    Promiscuous multicast mode %s\n",
+               (work32[6]&0x00000004)?"enabled":"disabled");   
+       len += sprintf(buf+len, "    Broadcast packets %s\n",
+               (work32[6]&0x00000100)?"rejected":"enabled");
+       len += sprintf(buf+len, "    Multicast packets %s\n",
+               (work32[6]&0x00000200)?"rejected":"enabled");
+       len += sprintf(buf+len, "    Functional address %s\n",
+                      (work32[6]&0x00000400)?"ignored":"enabled");
+                      
+       if (work32[7]&0x00000800)
+       {                      
+               len += sprintf(buf+len, "    MAC reporting mode : ");
+               if (work32[6]&0x00000800)
+                       len += sprintf(buf+len, "Pass only priority MAC packets to user\n");
+               else if (work32[6]&0x00001000)
+                       len += sprintf(buf+len, "Pass all MAC packets to user\n");
+               else if (work32[6]&0x00001800)
+                       len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n");
+               else
+                       len += sprintf(buf+len, "Do not pass MAC packets to user\n");
+       }
+       len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]);
+       len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n",
                       work32[9]);
-       len += sprintf(buf+len, "Imperfect filtering for max %d multicast addesses\n",
+       len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n",
                       work32[10]);
 
        spin_unlock(&i2o_proc_lock);
@@ -1331,97 +2024,76 @@ int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len,
        return len;
 }
 
-/* LAN group 0001h, field 1 - Current MAC (scalar) */
-int i2o_proc_read_lan_curr_addr(char *buf, char **start, off_t offset, int len,
-                               int *eof, void *data)
+/* LAN group 0002h - Multicast MAC address table (table) */
+int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset,
+                                int len, int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 work32[2];
-       static u8 *work8 = (u8*)work32;
+       static u32 field32[64];
+       static u8 *field8 = (u8 *)field32;
+       static u16 *field16 = (u16 *)field32;
        int token;
+       int i;
 
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
-       token = i2o_query_scalar(d->controller, d->id, proc_context, 
-                                0x0001, 2, &work32, 8, &i2o_proc_token);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
-       }
-
-       len += sprintf(buf, "Current address: "
-                      "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                      work8[0],work8[1],work8[2],work8[3],
-                      work8[4],work8[5],work8[6],work8[7]);
-
-       spin_unlock(&i2o_proc_lock);
-       return len;
-}
-
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                       d->controller, d->id, proc_context, 0x0002, -1, 
+                       NULL, 0, &field32, sizeof(field32),
+                       &i2o_proc_token);
 
-#if 0
-/* LAN group 0002h - Multicast MAC address table (table) */
-int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, int len, 
-                                int *eof, void *data)
-{
-       struct i2o_device *d = (struct i2o_device*)data;
-       static u8 work8[32];
-       static u32 field32[8];
-       static u8 *field8 = (u8 *)field32;
-       int token;
+       if (token<0)
+               switch (token) {
+               case -ETIMEDOUT:
+                       len += sprintf(buf, "Timeout reading table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               case -ENOMEM:
+                       len += sprintf(buf, "No free memory to read the table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               default:
+                       len += sprintf(buf, "Error reading field. BlockStatus %d\n",
+                                      token);
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
 
-       spin_lock(&i2o_proc_lock);      
-       len = 0;
+       len += sprintf(buf, "RowCount=%d, MoreFlag=%d\n", 
+                      field16[0], field16[1]);
 
-       token = i2o_query_table_polled(d->controller, d->id, &work8, 32,
-                                      0x0002, 0, field32, 8);
+       field8=(u8 *)&field16[2];
 
-       switch (token) {
-       case -ETIMEDOUT:
-               len += sprintf(buf, "Timeout reading table.\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
-               break;
-       case -ENOMEM:
-               len += sprintf(buf, "No free memory to read the table.\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
-               break;
-       case -EBADR:
-               len += sprintf(buf, "Error reading field.\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
-               break;
-       default:
-               break;
+       for(i=0; i<field16[0]; i++, field8+=8)
+       {
+               len += sprintf(buf+len, "MC MAC address[%d]: "
+                              "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+                              i,
+                              field8[0], field8[1], field8[2],
+                              field8[3], field8[4], field8[5],
+                              field8[6], field8[7]);
        }
 
-       len += sprintf(buf, "Multicast MAC address: "
-                      "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                      field8[0],field8[1],field8[2],field8[3],
-                      field8[4],field8[5],field8[6],field8[7]);
-
        spin_unlock(&i2o_proc_lock);
        return len;
 }
-#endif
 
 /* LAN group 0003h - Batch Control (scalar) */
 int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset,
                                    int len, int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 work32[18];
+       static u32 work32[9];
        int token;
 
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->id, proc_context, 
-                                0x0003, -1, &work32, 72, &i2o_proc_token);
+                                0x0003, -1, &work32, 9*4, &i2o_proc_token);
        if(token < 0)
        {
                len += sprintf(buf, "Timeout waiting for reply from IOP\n");
@@ -1443,26 +2115,26 @@ int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset,
        len += sprintf(buf+len, "\n");
 
        if(d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */
-               len += sprintf(buf+len, "Rising Load Delay: %d ms\n",
+               len += sprintf(buf+len, "Rising load delay      : %d ms\n",
                               work32[1]/10);
-               len += sprintf(buf+len, "Rising Load Threshold: %d ms\n",
+               len += sprintf(buf+len, "Rising load threshold  : %d ms\n",
                               work32[2]/10);
-               len += sprintf(buf+len, "Falling Load Delay: %d ms\n",
+               len += sprintf(buf+len, "Falling load delay     : %d ms\n",
                               work32[3]/10);
-               len += sprintf(buf+len, "Falling Load Threshold: %d ms\n",
+               len += sprintf(buf+len, "Falling load threshold : %d ms\n",
                               work32[4]/10);
        }
 
-       len += sprintf(buf+len, "Max Rx Batch Count: %d\n", work32[5]);
-       len += sprintf(buf+len, "Max Rx Batch Delay: %d\n", work32[6]);
+       len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]);
+       len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]);
 
        if(d->i2oversion == 0x00) {
                len += sprintf(buf+len,
-                              "Transmission Completion Reporting Delay: %d ms\n",
+                              "Transmission completion reporting delay : %d ms\n",
                               work32[7]);
        } else {
-               len += sprintf(buf+len, "Max Tx Batch Delay: %d\n", work32[7]);
-               len += sprintf(buf+len, "Max Tx Batch Count: %d\n", work32[8]);
+               len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]);
+               len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]);
        }
 
        spin_unlock(&i2o_proc_lock);
@@ -1489,14 +2161,14 @@ int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       len += sprintf(buf, "Packet prepadding (32b words): %d\n", work32[0]);
-       len += sprintf(buf+len, "Transmission error reporting: %s\n",
+       len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]);
+       len += sprintf(buf+len, "Transmission error reporting  : %s\n",
                       (work32[1]&1)?"on":"off");
-       len += sprintf(buf+len, "Bad packet handling: %s\n",
+       len += sprintf(buf+len, "Bad packet handling           : %s\n",
                       (work32[1]&0x2)?"by host":"by DDM");                   
-       len += sprintf(buf+len, "Packet orphan limit: %d\n", work32[2]);
+       len += sprintf(buf+len, "Packet orphan limit           : %d\n", work32[2]);
 
-       len += sprintf(buf+len, "Tx modes:\n");
+       len += sprintf(buf+len, "Tx modes :\n");
        if (work32[3]&0x00000004)
                len += sprintf(buf+len, "    HW CRC supressed\n");
        else
@@ -1514,7 +2186,7 @@ int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len,
        if (work32[3]&0x00002000)
                len += sprintf(buf+len, "    Loopback packet not delivered\n");
 
-       len += sprintf(buf+len, "Rx modes:\n");
+       len += sprintf(buf+len, "Rx modes :\n");
        if (work32[4]&0x00000004)
                len += sprintf(buf+len, "    FCS in payload\n");
        if (work32[4]&0x00000100)
@@ -1554,159 +2226,17 @@ int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset,
                return len;
        }
 
-       len += sprintf(buf, "Connector type: ");
-       switch(work32[0])
-       {
-       case 0x00000000:
-               len += sprintf(buf+len, "OTHER\n");
-               break;
-       case 0x00000001:
-               len += sprintf(buf+len, "UNKNOWN\n");
-               break;
-       case 0x00000002:
-               len += sprintf(buf+len, "AUI\n");
-               break;
-       case 0x00000003:
-               len += sprintf(buf+len, "UTP\n");
-               break;
-       case 0x00000004:
-               len += sprintf(buf+len, "BNC\n");
-               break;
-       case 0x00000005:
-               len += sprintf(buf+len, "RJ45\n");
-               break;
-       case 0x00000006:
-               len += sprintf(buf+len, "STP DB9\n");
-               break;
-       case 0x00000007:
-               len += sprintf(buf+len, "FIBER MIC\n");
-               break;
-       case 0x00000008:
-               len += sprintf(buf+len, "APPLE AUI\n");
-               break;
-       case 0x00000009:
-               len += sprintf(buf+len, "MII\n");
-               break;
-       case 0x0000000A:
-               len += sprintf(buf+len, "DB9\n");
-               break;
-       case 0x0000000B:
-               len += sprintf(buf+len, "HSSDC\n");
-               break;
-       case 0x0000000C:
-               len += sprintf(buf+len, "DUPLEX SC FIBER\n");
-               break;
-       case 0x0000000D:
-               len += sprintf(buf+len, "DUPLEX ST FIBER\n");
-               break;
-       case 0x0000000E:
-               len += sprintf(buf+len, "TNC/BNC\n");
-               break;
-       case 0xFFFFFFFF:
-               len += sprintf(buf+len, "HW DEFAULT\n");
-               break;
-       }
+       len += sprintf(buf, "Connector type         : %s\n",
+                      i2o_get_connector_type(work32[0]));
+       len += sprintf(buf+len, "Connection type        : %s\n",
+                      i2o_get_connection_type(work32[1]));
 
-       len += sprintf(buf+len, "Connection type: ");
-       switch(work32[1])
-       {
-       case I2O_LAN_UNKNOWN:
-               len += sprintf(buf+len, "UNKNOWN\n");
-               break;
-       case I2O_LAN_AUI:
-               len += sprintf(buf+len, "AUI\n");
-               break;
-       case I2O_LAN_10BASE5:
-               len += sprintf(buf+len, "10BASE5\n");
-               break;
-       case I2O_LAN_FIORL:
-               len += sprintf(buf+len, "FIORL\n");
-               break;
-       case I2O_LAN_10BASE2:
-               len += sprintf(buf+len, "10BASE2\n");
-               break;
-       case I2O_LAN_10BROAD36:
-               len += sprintf(buf+len, "10BROAD36\n");
-               break;
-       case I2O_LAN_10BASE_T:
-               len += sprintf(buf+len, "10BASE-T\n");
-               break;
-       case I2O_LAN_10BASE_FP:
-               len += sprintf(buf+len, "10BASE-FP\n");
-               break;
-       case I2O_LAN_10BASE_FB:
-               len += sprintf(buf+len, "10BASE-FB\n");
-               break;
-       case I2O_LAN_10BASE_FL:
-               len += sprintf(buf+len, "10BASE-FL\n");
-               break;
-       case I2O_LAN_100BASE_TX:
-               len += sprintf(buf+len, "100BASE-TX\n");
-               break;
-       case I2O_LAN_100BASE_FX:
-               len += sprintf(buf+len, "100BASE-FX\n");
-               break;
-       case I2O_LAN_100BASE_T4:
-               len += sprintf(buf+len, "100BASE-T4\n");
-               break;
-       case I2O_LAN_1000BASE_SX:
-               len += sprintf(buf+len, "1000BASE-SX\n");
-               break;
-       case I2O_LAN_1000BASE_LX:
-               len += sprintf(buf+len, "1000BASE-LX\n");
-               break;
-       case I2O_LAN_1000BASE_CX:
-               len += sprintf(buf+len, "1000BASE-CX\n");
-               break;
-       case I2O_LAN_1000BASE_T:
-               len += sprintf(buf+len, "1000BASE-T\n");
-               break;
-       case I2O_LAN_100VG_ETHERNET:
-               len += sprintf(buf+len, "100VG-ETHERNET\n");
-               break;
-       case I2O_LAN_100VG_TR:
-               len += sprintf(buf+len, "100VG-TOKEN RING\n");
-               break;
-       case I2O_LAN_4MBIT:
-               len += sprintf(buf+len, "4MBIT TOKEN RING\n");
-               break;
-       case I2O_LAN_16MBIT:
-               len += sprintf(buf+len, "16 Mb Token Ring\n");
-               break;
-       case I2O_LAN_125MBAUD:
-               len += sprintf(buf+len, "125 MBAUD FDDI\n");
-               break;
-       case I2O_LAN_POINT_POINT:
-               len += sprintf(buf+len, "Point-to-point\n");
-               break;
-       case I2O_LAN_ARB_LOOP:
-               len += sprintf(buf+len, "Arbitrated loop\n");
-               break;
-       case I2O_LAN_PUBLIC_LOOP:
-               len += sprintf(buf+len, "Public loop\n");
-               break;
-       case I2O_LAN_FABRIC:
-               len += sprintf(buf+len, "Fabric\n");
-               break;
-       case I2O_LAN_EMULATION:
-               len += sprintf(buf+len, "Emulation\n");
-               break;
-       case I2O_LAN_OTHER:
-               len += sprintf(buf+len, "Other\n");
-               break;
-       case I2O_LAN_DEFAULT:
-               len += sprintf(buf+len, "HW default\n");
-               break;
-       }
-
-       len += sprintf(buf+len, "Current Tx Wire Speed: " FMT_U64_HEX " bps\n",
-                      U64_VAL(&work64[1]));
-       len += sprintf(buf+len, "Current Rx Wire Speed: " FMT_U64_HEX " bps\n",
-                      U64_VAL(&work64[2]));
-
-       len += sprintf(buf+len, "%s duplex\n", (work8[24]&1)?"Full":"Half");
+       len += sprintf(buf+len, "Current Tx wire speed  : %d bps\n", work64[1]);
+       len += sprintf(buf+len, "Current Rx wire speed  : %d bps\n", work64[2]);
 
-       len += sprintf(buf+len, "Link status: ");
+       len += sprintf(buf+len, "Duplex mode            : %s duplex\n", 
+                       (work8[24]&1)?"Full":"Half");
+       len += sprintf(buf+len, "Link status            : ");
        if(work8[25] == 0x00)
                len += sprintf(buf+len, "Unknown\n");
        else if(work8[25] == 0x01)
@@ -1719,237 +2249,104 @@ int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset,
                len += sprintf(buf+len, "Unspecified\n");
 
        if (d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */
-               len += sprintf(buf+len, "Bad packets handled by: %s\n",
+               len += sprintf(buf+len, "Bad packets handled by : %s\n",
                               (work8[26] == 0xFF)?"host":"DDM");
        }
        if (d->i2oversion != 0x00) {
-               len += sprintf(buf+len, "Duplex mode target: ");
+               len += sprintf(buf+len, "Duplex mode target     : ");
                switch (work8[27]) {
                case 0:
-                       len += sprintf(buf+len, "Half Duplex\n");
+                       len += sprintf(buf+len, "Half duplex\n");
                        break;
                case 1:
-                       len += sprintf(buf+len, "Full Duplex\n");
-                       break;
-               default:
-                       len += sprintf(buf+len, "\n");
-                       break;
-               }
-
-               len += sprintf(buf+len, "Connector type target: ");
-               switch(work32[7])
-               {
-               case 0x00000000:
-                       len += sprintf(buf+len, "OTHER\n");
-                       break;
-               case 0x00000001:
-                       len += sprintf(buf+len, "UNKNOWN\n");
-                       break;
-               case 0x00000002:
-                       len += sprintf(buf+len, "AUI\n");
-                       break;
-               case 0x00000003:
-                       len += sprintf(buf+len, "UTP\n");
-                       break;
-               case 0x00000004:
-                       len += sprintf(buf+len, "BNC\n");
-                       break;
-               case 0x00000005:
-                       len += sprintf(buf+len, "RJ45\n");
-                       break;
-               case 0x00000006:
-                       len += sprintf(buf+len, "STP DB9\n");
-                       break;
-               case 0x00000007:
-                       len += sprintf(buf+len, "FIBER MIC\n");
-                       break;
-               case 0x00000008:
-                       len += sprintf(buf+len, "APPLE AUI\n");
-                       break;
-               case 0x00000009:
-                       len += sprintf(buf+len, "MII\n");
-                       break;
-               case 0x0000000A:
-                       len += sprintf(buf+len, "DB9\n");
-                       break;
-               case 0x0000000B:
-                       len += sprintf(buf+len, "HSSDC\n");
-                       break;
-               case 0x0000000C:
-                       len += sprintf(buf+len, "DUPLEX SC FIBER\n");
-                       break;
-               case 0x0000000D:
-                       len += sprintf(buf+len, "DUPLEX ST FIBER\n");
-                       break;
-               case 0x0000000E:
-                       len += sprintf(buf+len, "TNC/BNC\n");
-                       break;
-               case 0xFFFFFFFF:
-                       len += sprintf(buf+len, "HW DEFAULT\n");
+                       len += sprintf(buf+len, "Full duplex\n");
                        break;
                default:
                        len += sprintf(buf+len, "\n");
                        break;
                }
 
-               len += sprintf(buf+len, "Connection type target: ");
-               switch(work32[8])
-               {
-               case I2O_LAN_UNKNOWN:
-                       len += sprintf(buf+len, "UNKNOWN\n");
-                       break;
-               case I2O_LAN_AUI:
-                       len += sprintf(buf+len, "AUI\n");
-                       break;
-               case I2O_LAN_10BASE5:
-                       len += sprintf(buf+len, "10BASE5\n");
-                       break;
-               case I2O_LAN_FIORL:
-                       len += sprintf(buf+len, "FIORL\n");
-                       break;
-               case I2O_LAN_10BASE2:
-                       len += sprintf(buf+len, "10BASE2\n");
-                       break;
-               case I2O_LAN_10BROAD36:
-                       len += sprintf(buf+len, "10BROAD36\n");
-                       break;
-               case I2O_LAN_10BASE_T:
-                       len += sprintf(buf+len, "10BASE-T\n");
-                       break;
-               case I2O_LAN_10BASE_FP:
-                       len += sprintf(buf+len, "10BASE-FP\n");
-                       break;
-               case I2O_LAN_10BASE_FB:
-                       len += sprintf(buf+len, "10BASE-FB\n");
-                       break;
-               case I2O_LAN_10BASE_FL:
-                       len += sprintf(buf+len, "10BASE-FL\n");
-                       break;
-               case I2O_LAN_100BASE_TX:
-                       len += sprintf(buf+len, "100BASE-TX\n");
-                       break;
-               case I2O_LAN_100BASE_FX:
-                       len += sprintf(buf+len, "100BASE-FX\n");
-                       break;
-               case I2O_LAN_100BASE_T4:
-                       len += sprintf(buf+len, "100BASE-T4\n");
-                       break;
-               case I2O_LAN_1000BASE_SX:
-                       len += sprintf(buf+len, "1000BASE-SX\n");
-                       break;
-               case I2O_LAN_1000BASE_LX:
-                       len += sprintf(buf+len, "1000BASE-LX\n");
-                       break;
-               case I2O_LAN_1000BASE_CX:
-                       len += sprintf(buf+len, "1000BASE-CX\n");
-                       break;
-               case I2O_LAN_1000BASE_T:
-                       len += sprintf(buf+len, "1000BASE-T\n");
-                       break;
-               case I2O_LAN_100VG_ETHERNET:
-                       len += sprintf(buf+len, "100VG-ETHERNET\n");
-                       break;
-               case I2O_LAN_100VG_TR:
-                       len += sprintf(buf+len, "100VG-TOKEN RING\n");
-                       break;
-               case I2O_LAN_4MBIT:
-                       len += sprintf(buf+len, "4MBIT TOKEN RING\n");
-                       break;
-               case I2O_LAN_16MBIT:
-                       len += sprintf(buf+len, "16 Mb Token Ring\n");
-                       break;
-               case I2O_LAN_125MBAUD:
-                       len += sprintf(buf+len, "125 MBAUD FDDI\n");
-                       break;
-               case I2O_LAN_POINT_POINT:
-                       len += sprintf(buf+len, "Point-to-point\n");
-                       break;
-               case I2O_LAN_ARB_LOOP:
-                       len += sprintf(buf+len, "Arbitrated loop\n");
-                       break;
-               case I2O_LAN_PUBLIC_LOOP:
-                       len += sprintf(buf+len, "Public loop\n");
-                       break;
-               case I2O_LAN_FABRIC:
-                       len += sprintf(buf+len, "Fabric\n");
-                       break;
-               case I2O_LAN_EMULATION:
-                       len += sprintf(buf+len, "Emulation\n");
-                       break;
-               case I2O_LAN_OTHER:
-                       len += sprintf(buf+len, "Other\n");
-                       break;
-               case I2O_LAN_DEFAULT:
-                       len += sprintf(buf+len, "HW default\n");
-                       break;
-               default:
-                       len += sprintf(buf+len, "\n");
-                       break;
-               }
+               len += sprintf(buf+len, "Connector type target  : %s\n",
+                              i2o_get_connector_type(work32[7]));
+               len += sprintf(buf+len, "Connection type target : %s\n",
+                              i2o_get_connection_type(work32[8]));
        }
+
        spin_unlock(&i2o_proc_lock);
        return len;
 }
 
-#if 0
 /* LAN group 0006h - Alternate address (table) */
 int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len,
                               int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u8 work8[32];
-       static u32 field32[2];
+       static u32 field32[64];
        static u8 *field8 = (u8 *)field32;
+       static u16 *field16 = (u16 *)field32;
        int token;
+       int i;
 
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
-       token = i2o_query_table_polled(d->controller, d->id, &work8, 32,
-                                      0x0006, 0, field32, 8);
-       switch (token) {
-       case -ETIMEDOUT:
-               len += sprintf(buf, "Timeout reading table.\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
-               break;
-       case -ENOMEM:
-               len += sprintf(buf, "No free memory to read the table.\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
-               break;
-       case -EBADR:
-               len += sprintf(buf, "Error reading field.\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
-               break;
-       default:
-               break;
-       }
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                       d->controller, d->id, proc_context, 0x0006, -1, 
+                       NULL, 0, &field32, sizeof(field32),
+                       &i2o_proc_token);
 
-       len += sprintf(buf, "Alternate Address: "
-                      "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                       field8[0],field8[1],field8[2],field8[3],
-                       field8[4],field8[5],field8[6],field8[7]);
+       if (token<0)
+               switch (token) {
+               case -ETIMEDOUT:
+                       len += sprintf(buf, "Timeout reading table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               case -ENOMEM:
+                       len += sprintf(buf, "No free memory to read the table.\n");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+                       break;
+               default:
+                       len += sprintf(buf, "Error reading field. BlockStatus %d\n",
+                                      token);
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
+
+       len += sprintf(buf,"RowCount=%d, MoreFlag=%d\n", field16[0],
+                      field16[1]);
+
+       field8=(u8 *)&field16[2];
+
+       for(i=0; i<field16[0]; i++, field8+=8)
+       {
+               len += sprintf(buf+len, "Alternate address[%d]: "
+                              "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+                              i,
+                              field8[0], field8[1], field8[2],
+                              field8[3], field8[4], field8[5],
+                              field8[6], field8[7]);
+       }
 
        spin_unlock(&i2o_proc_lock);
        return len;
 }
-#endif
+
 
 /* LAN group 0007h - Transmit info (scalar) */
 int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, 
-                                   int *eof, void *data)
+                             int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 work32[10];
+       static u32 work32[8];
        int token;
 
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->id, proc_context, 
-                                0x0007, -1, &work32, 8, &i2o_proc_token);
+                                0x0007, -1, &work32, 8*4, &i2o_proc_token);
        if(token < 0)
        {
                len += sprintf(buf, "Timeout waiting for reply from IOP\n");
@@ -1957,12 +2354,12 @@ int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       len += sprintf(buf, "Max SG Elements per packet: %d\n", work32[0]);
-       len += sprintf(buf+len, "Max SG Elements per chain: %d\n", work32[1]);
-       len += sprintf(buf+len, "Max outstanding packets: %d\n", work32[2]);
-       len += sprintf(buf+len, "Max packets per request: %d\n", work32[3]);
+       len += sprintf(buf,     "Max SG Elements per packet : %d\n", work32[0]);
+       len += sprintf(buf+len, "Max SG Elements per chain  : %d\n", work32[1]);
+       len += sprintf(buf+len, "Max outstanding packets    : %d\n", work32[2]);
+       len += sprintf(buf+len, "Max packets per request    : %d\n", work32[3]);
 
-       len += sprintf(buf+len, "Tx modes:\n");
+       len += sprintf(buf+len, "Tx modes :\n");
        if(work32[4]&0x00000002)
                len += sprintf(buf+len, "    No DA in SGL\n");
        if(work32[4]&0x00000004)
@@ -1974,25 +2371,25 @@ int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len,
        if(work32[4]&0x00000020)
                len += sprintf(buf+len, "    RIF insertion\n");
        if(work32[4]&0x00000100)
-               len += sprintf(buf+len, "    IPv4 Checksum\n");
+               len += sprintf(buf+len, "    IPv4 checksum\n");
        if(work32[4]&0x00000200)
-               len += sprintf(buf+len, "    TCP Checksum\n");
+               len += sprintf(buf+len, "    TCP checksum\n");
        if(work32[4]&0x00000400)
-               len += sprintf(buf+len, "    UDP Checksum\n");
+               len += sprintf(buf+len, "    UDP checksum\n");
        if(work32[4]&0x00000800)
-               len += sprintf(buf+len, "    RSVP Checksum\n");
+               len += sprintf(buf+len, "    RSVP checksum\n");
        if(work32[4]&0x00001000)
-               len += sprintf(buf+len, "    ICMP Checksum\n");
+               len += sprintf(buf+len, "    ICMP checksum\n");
        if (d->i2oversion == 0x00) {
                if(work32[4]&0x00008000)
-                       len += sprintf(buf+len, "    Loopback Enabled\n");
+                       len += sprintf(buf+len, "    Loopback enabled\n");
                if(work32[4]&0x00010000)
-                       len += sprintf(buf+len, "    Loopback Suppression Enabled\n");
+                       len += sprintf(buf+len, "    Loopback suppression enabled\n");
        } else {
                if(work32[4]&0x00010000)
-                       len += sprintf(buf+len, "    Loopback Enabled\n");
+                       len += sprintf(buf+len, "    Loopback enabled\n");
                if(work32[4]&0x00020000)
-                       len += sprintf(buf+len, "    Loopback Suppression Enabled\n");
+                       len += sprintf(buf+len, "    Loopback suppression enabled\n");
        }
 
        spin_unlock(&i2o_proc_lock);
@@ -2001,17 +2398,17 @@ int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len,
 
 /* LAN group 0008h - Receive info (scalar) */
 int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, 
-                                   int *eof, void *data)
+                             int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 work32[10];
+       static u32 work32[8];
        int token;
 
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->id, proc_context, 
-                                0x0008, -1, &work32, 8, &i2o_proc_token);
+                                0x0008, -1, &work32, 8*4, &i2o_proc_token);
        if(token < 0)
        {
                len += sprintf(buf, "Timeout waiting for reply from IOP\n");
@@ -2019,14 +2416,14 @@ int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       len += sprintf(buf, "Max size of chain element: %d\n", work32[0]);
-       len += sprintf(buf+len, "Max number of buckets: %d\n", work32[1]);
+       len += sprintf(buf,"Max size of chain element : %d\n", work32[0]);
+       len += sprintf(buf+len, "Max number of buckets     : %d\n", work32[1]);
 
        if (d->i2oversion > 0x00) { /* not in 1.5 */
-               len += sprintf(buf+len, "Rx modes: %d\n", work32[2]);
-               len += sprintf(buf+len, "RxMaxBucketsReply: %d\n", work32[3]);
-               len += sprintf(buf+len, "RxMaxPacketsPerBuckets: %d\n", work32[4]);
-               len += sprintf(buf+len, "RxMaxPostBuckets: %d\n", work32[5]);
+               len += sprintf(buf+len, "RxModes                   : %d\n", work32[2]);
+               len += sprintf(buf+len, "RxMaxBucketsReply         : %d\n", work32[3]);
+               len += sprintf(buf+len, "RxMaxPacketsPerBuckets    : %d\n", work32[4]);
+               len += sprintf(buf+len, "RxMaxPostBuckets          : %d\n", work32[5]);
        }
 
        spin_unlock(&i2o_proc_lock);
@@ -2054,15 +2451,63 @@ int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len,
                return len;
        }
 
-       len += sprintf(buf, "Tx packets: " FMT_U64_HEX "\n", U64_VAL(&work64[0]));
-       len += sprintf(buf+len, "Tx bytes: " FMT_U64_HEX "\n", U64_VAL(&work64[1]));
-       len += sprintf(buf+len, "Rx packets: " FMT_U64_HEX "\n", U64_VAL(&work64[2]));
-       len += sprintf(buf+len, "Rx bytes: " FMT_U64_HEX "\n", U64_VAL(&work64[3]));
-       len += sprintf(buf+len, "Tx errors: " FMT_U64_HEX "\n", U64_VAL(&work64[4]));
-       len += sprintf(buf+len, "Rx errors: " FMT_U64_HEX "\n", U64_VAL(&work64[5]));
-       len += sprintf(buf+len, "Rx dropped: " FMT_U64_HEX "\n", U64_VAL(&work64[6]));
-       len += sprintf(buf+len, "Adapter resets: " FMT_U64_HEX "\n", U64_VAL(&work64[7]));
-       len += sprintf(buf+len, "Adapter suspends: " FMT_U64_HEX "\n", U64_VAL(&work64[8]));
+       len += sprintf(buf,     "Tx packets       : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[0]));
+       len += sprintf(buf+len, "Tx bytes         : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[1]));
+       len += sprintf(buf+len, "Rx packets       : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[2]));
+       len += sprintf(buf+len, "Rx bytes         : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[3]));
+       len += sprintf(buf+len, "Tx errors        : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[4]));
+       len += sprintf(buf+len, "Rx errors        : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[5]));
+       len += sprintf(buf+len, "Rx dropped       : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[6]));
+       len += sprintf(buf+len, "Adapter resets   : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[7]));
+       len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[8]));
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
+
+
+/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */
+int i2o_proc_read_lan_supp_opt_stats(char *buf, char **start, off_t offset,
+                                    int len, int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       static u64 work64[4];
+       int token;
+
+       spin_lock(&i2o_proc_lock);      
+
+       len = 0;
+
+       token = i2o_query_scalar(d->controller, d->id, proc_context, 
+                                0x0180, -1, &work64, 4*8, &i2o_proc_token);
+       if(token < 0)
+       {
+               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       if (d->i2oversion == 0x00)
+               len += sprintf(buf, "Supported stats : " FMT_U64_HEX " \n",
+                              U64_VAL(&work64[0]));
+       else
+       {
+               len += sprintf(buf, "Supported stats (0182h) : " FMT_U64_HEX " \n",
+                              U64_VAL(&work64[1]));
+               len += sprintf(buf, "Supported stats (0183h) : " FMT_U64_HEX " \n",
+                              U64_VAL(&work64[2]));
+               len += sprintf(buf, "Supported stats (0184h) : " FMT_U64_HEX " \n",
+                              U64_VAL(&work64[3]));
+       }
 
        spin_unlock(&i2o_proc_lock);
        return len;
@@ -2091,15 +2536,24 @@ int i2o_proc_read_lan_opt_tx_hist_stats(char *buf, char **start, off_t offset,
                return len;
        }
 
-       len += sprintf(buf, "TxRetryCount: " FMT_U64_HEX "\n", U64_VAL(&work64[0]));
-       len += sprintf(buf+len, "DirectedBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[1]));
-       len += sprintf(buf+len, "DirectedPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[2]));
-       len += sprintf(buf+len, "MulticastBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[3]));
-       len += sprintf(buf+len, "MulticastPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[4]));
-       len += sprintf(buf+len, "BroadcastBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[5]));
-       len += sprintf(buf+len, "BroadcastPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[6]));
-       len += sprintf(buf+len, "TotalGroupAddrTxCount: " FMT_U64_HEX "\n", U64_VAL(&work64[7]));
-       len += sprintf(buf+len, "TotalTxPacketsTooShort: " FMT_U64_HEX "\n", U64_VAL(&work64[8]));
+       len += sprintf(buf,     "TxRetryCount           : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[0]));
+       len += sprintf(buf+len, "DirectedBytesTx        : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[1]));
+       len += sprintf(buf+len, "DirectedPacketsTx      : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[2]));
+       len += sprintf(buf+len, "MulticastBytesTx       : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[3]));
+       len += sprintf(buf+len, "MulticastPacketsTx     : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[4]));
+       len += sprintf(buf+len, "BroadcastBytesTx       : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[5]));
+       len += sprintf(buf+len, "BroadcastPacketsTx     : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[6]));
+       len += sprintf(buf+len, "TotalGroupAddrTxCount  : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[7]));
+       len += sprintf(buf+len, "TotalTxPacketsTooShort : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[8]));
 
        spin_unlock(&i2o_proc_lock);
        return len;
@@ -2127,22 +2581,206 @@ int i2o_proc_read_lan_opt_rx_hist_stats(char *buf, char **start, off_t offset,
                return len;
        }
 
-       len += sprintf(buf, "ReceiveCRCErrorCount: " FMT_U64_HEX "\n", U64_VAL(&work64[0]));
-       len += sprintf(buf+len, "DirectedBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[1]));
-       len += sprintf(buf+len, "DirectedPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[2]));
-       len += sprintf(buf+len, "MulticastBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[3]));
-       len += sprintf(buf+len, "MulticastPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[4]));
-       len += sprintf(buf+len, "BroadcastBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[5]));
-       len += sprintf(buf+len, "BroadcastPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[6]));
-       len += sprintf(buf+len, "TotalGroupAddrRxCount: " FMT_U64_HEX "\n", U64_VAL(&work64[7]));
-       len += sprintf(buf+len, "TotalRxPacketsTooShort: " FMT_U64_HEX "\n", U64_VAL(&work64[8]));
-       len += sprintf(buf+len, "TotalRxPacketsTooLong: " FMT_U64_HEX "\n", U64_VAL(&work64[9]));
-       len += sprintf(buf+len, "TotalRuntPacketsReceived: " FMT_U64_HEX "\n", U64_VAL(&work64[10]));
+       len += sprintf(buf,     "ReceiveCRCErrorCount     : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[0]));
+       len += sprintf(buf+len, "DirectedBytesRx          : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[1]));
+       len += sprintf(buf+len, "DirectedPacketsRx        : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[2]));
+       len += sprintf(buf+len, "MulticastBytesRx         : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[3]));
+       len += sprintf(buf+len, "MulticastPacketsRx       : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[4]));
+       len += sprintf(buf+len, "BroadcastBytesRx         : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[5]));
+       len += sprintf(buf+len, "BroadcastPacketsRx       : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[6]));
+       len += sprintf(buf+len, "TotalGroupAddrRxCount    : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[7]));
+       len += sprintf(buf+len, "TotalRxPacketsTooShort   : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[8]));
+       len += sprintf(buf+len, "TotalRxPacketsTooLong    : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[9]));
+       len += sprintf(buf+len, "TotalRuntPacketsReceived : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[10]));
 
        spin_unlock(&i2o_proc_lock);
        return len;
 }
 
+/* LAN group 0200h - Required Ethernet Statistics (scalar) */
+int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset,
+                               int len, int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       static u64 work64[8];
+       int token;
+
+
+       spin_lock(&i2o_proc_lock);
+       
+       len = 0;
+
+       token = i2o_query_scalar(d->controller, d->id, proc_context, 
+                                0x0200, -1, &work64, 8*8, &i2o_proc_token);
+       if(token < 0)
+       {
+               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       len += sprintf(buf,     "Rx alignment errors    : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[0]));
+       len += sprintf(buf+len, "Tx one collisions      : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[1]));
+       len += sprintf(buf+len, "Tx multicollisions     : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[2]));
+       len += sprintf(buf+len, "Tx deferred            : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[3]));
+       len += sprintf(buf+len, "Tx late collisions     : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[4]));
+       len += sprintf(buf+len, "Tx max collisions      : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[5]));
+       len += sprintf(buf+len, "Tx carrier lost        : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[6]));
+       len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[7]));
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
+
+/* LAN group 0280h - Supported Ethernet Historical Statistics (scalar) */
+int i2o_proc_read_lan_supp_eth_stats(char *buf, char **start, off_t offset,
+                                    int len, int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       static u64 work64[1];
+       int token;
+
+       spin_lock(&i2o_proc_lock);      
+
+       len = 0;
+
+       token = i2o_query_scalar(d->controller, d->id, proc_context, 
+                                0x0280, -1, &work64, 8, &i2o_proc_token);
+       if(token < 0)
+       {
+               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       len += sprintf(buf, "Supported stats : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[0]));
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
+
+/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */
+int i2o_proc_read_lan_opt_eth_stats(char *buf, char **start, off_t offset,
+                                   int len, int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       static u64 work64[3];
+       int token;
+
+       spin_lock(&i2o_proc_lock);      
+
+       len = 0;
+
+       token = i2o_query_scalar(d->controller, d->id, proc_context, 
+                                0x0281, -1, &work64, 3*8, &i2o_proc_token);
+       if(token < 0)
+       {
+               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       len += sprintf(buf, "Rx overrun           : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[0]));
+       len += sprintf(buf, "Tx underrun          : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[1]));
+       len += sprintf(buf, "Tx heartbeat failure : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[2]));
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
+
+/* LAN group 0300h - Required Token Ring Statistics (scalar) */
+int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset,
+                              int len, int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       static u64 work64[13];
+       int token;
+
+       static char *ring_status[] =
+       {
+               "",
+               "",
+               "",
+               "",
+               "",
+               "Ring Recovery",
+               "Single Station",
+               "Counter Overflow",
+               "Remove Received",
+               "",
+               "Auto-Removal Error 1",
+               "Lobe Wire Fault",
+               "Transmit Beacon",
+               "Soft Error",
+               "Hard Error",
+               "Signal Loss"
+       };
+
+       spin_lock(&i2o_proc_lock);
+       
+       len = 0;
+
+       token = i2o_query_scalar(d->controller, d->id, proc_context, 
+                                0x0300, -1, &work64, 13*8, &i2o_proc_token);
+       if(token < 0)
+       {
+               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       len += sprintf(buf,     "LineErrors          : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[0]));
+       len += sprintf(buf+len, "LostFrames          : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[1]));
+       len += sprintf(buf+len, "ACError             : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[2]));
+       len += sprintf(buf+len, "TxAbortDelimiter    : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[3]));
+       len += sprintf(buf+len, "BursErrors          : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[4]));
+       len += sprintf(buf+len, "FrameCopiedErrors   : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[5]));
+       len += sprintf(buf+len, "FrequencyErrors     : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[6]));
+       len += sprintf(buf+len, "InternalErrors      : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[7]));
+       len += sprintf(buf+len, "LastRingStatus      : %s\n", ring_status[work64[8]]);
+       len += sprintf(buf+len, "TokenError          : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[9]));
+       len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[10]));
+       len += sprintf(buf+len, "LastRingID          : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[11]));
+       len += sprintf(buf+len, "LastBeaconType      : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[12]));
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
 
 /* LAN group 0400h - Required FDDI Statistics (scalar) */
 int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset,
@@ -2208,23 +2846,31 @@ int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset,
                return len;
        }
 
-       len += sprintf(buf, "ConfigurationState: %s\n", conf_state[work64[0]]);
-       len += sprintf(buf+len, "UpstreamNode: " FMT_U64_HEX "\n", U64_VAL(&work64[1]));
-       len += sprintf(buf+len, "DownStreamNode: " FMT_U64_HEX "\n", U64_VAL(&work64[2]));
-       len += sprintf(buf+len, "FrameErrors: " FMT_U64_HEX "\n", U64_VAL(&work64[3]));
-       len += sprintf(buf+len, "FramesLost: " FMT_U64_HEX "\n", U64_VAL(&work64[4]));
-       len += sprintf(buf+len, "RingMgmtState: %s\n", ring_state[work64[5]]);
-       len += sprintf(buf+len, "LCTFailures: " FMT_U64_HEX "\n", U64_VAL(&work64[6]));
-       len += sprintf(buf+len, "LEMRejects: " FMT_U64_HEX "\n", U64_VAL(&work64[7]));
-       len += sprintf(buf+len, "LEMCount: " FMT_U64_HEX "\n", U64_VAL(&work64[8]));
-       len += sprintf(buf+len, "LConnectionState: %s\n", link_state[work64[9]]);
+       len += sprintf(buf,     "ConfigurationState : %s\n", conf_state[work64[0]]);
+       len += sprintf(buf+len, "UpstreamNode       : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[1]));
+       len += sprintf(buf+len, "DownStreamNode     : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[2]));
+       len += sprintf(buf+len, "FrameErrors        : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[3]));
+       len += sprintf(buf+len, "FramesLost         : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[4]));
+       len += sprintf(buf+len, "RingMgmtState      : %s\n", ring_state[work64[5]]);
+       len += sprintf(buf+len, "LCTFailures: " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[6]));
+       len += sprintf(buf+len, "LEMRejects         : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[7]));
+       len += sprintf(buf+len, "LEMCount           : " FMT_U64_HEX "\n",
+                      U64_VAL(&work64[8]));
+       len += sprintf(buf+len, "LConnectionState   : %s\n",
+                      link_state[work64[9]]);
 
        spin_unlock(&i2o_proc_lock);
        return len;
 }
 
-static int i2o_proc_create_entries(void *data,
-       i2o_proc_entry *pentry, struct proc_dir_entry *parent)
+static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry,
+                                  struct proc_dir_entry *parent)
 {
        struct proc_dir_entry *ent;
        
@@ -2245,7 +2891,7 @@ static int i2o_proc_create_entries(void *data,
 }
 
 static void i2o_proc_remove_entries(i2o_proc_entry *pentry, 
-       struct proc_dir_entry *parent)
+                                   struct proc_dir_entry *parent)
 {
        while(pentry->name != NULL)
        {
@@ -2255,7 +2901,7 @@ static void i2o_proc_remove_entries(i2o_proc_entry *pentry,
 }
 
 static int i2o_proc_add_controller(struct i2o_controller *pctrl, 
-       struct proc_dir_entry *root )
+                                  struct proc_dir_entry *root )
 {
        struct proc_dir_entry *dir, *dir1;
        struct i2o_device *dev;
@@ -2291,6 +2937,23 @@ static int i2o_proc_add_controller(struct i2o_controller *pctrl,
                        break;
                case I2O_CLASS_LAN:
                        i2o_proc_create_entries(dev, lan_entries, dir1);
+                       switch(dev->subclass)
+                       {
+                       case I2O_LAN_ETHERNET:
+                               i2o_proc_create_entries(dev, lan_eth_entries,
+                                                       dir1);
+                               break;
+                       case I2O_LAN_FDDI:
+                               i2o_proc_create_entries(dev, lan_fddi_entries,
+                                                       dir1);
+                               break;
+                       case I2O_LAN_TR:
+                               i2o_proc_create_entries(dev, lan_tr_entries,
+                                                       dir1);
+                               break;
+                       default:
+                               break;
+                       }
                        break;
                default:
                        break;
@@ -2301,17 +2964,58 @@ static int i2o_proc_add_controller(struct i2o_controller *pctrl,
 }
 
 static void i2o_proc_remove_controller(struct i2o_controller *pctrl, 
-       struct proc_dir_entry *parent)
+                                      struct proc_dir_entry *parent)
 {
        char buff[10];
+       char dev_id[10];
+       struct proc_dir_entry *de;
+       struct i2o_device *dev;
 
-       sprintf(buff, "iop%d", pctrl->unit);
+       /* Remove unused device entries */
+       for(dev=pctrl->devices; dev; dev=dev->next)
+       {
+               de=dev->proc_entry;
+               sprintf(dev_id, "%0#5x", dev->id);
+
+               /* Would it be safe to remove _files_ even if they are in use? */
+               if((de) && (!de->count))
+               {
+                       i2o_proc_remove_entries(generic_dev_entries, de);
+
+                       switch(dev->class)
+                       {
+                       case I2O_CLASS_SCSI_PERIPHERAL:
+                       case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+                               i2o_proc_remove_entries(rbs_dev_entries, de);
+                               break;
+                       case I2O_CLASS_LAN:
+                               i2o_proc_remove_entries(lan_entries, de);
+                               switch(dev->subclass)
+                               {
+                               case I2O_LAN_ETHERNET:
+                                       i2o_proc_remove_entries(lan_eth_entries, de);
+                                       break;
+                               case I2O_LAN_FDDI:
+                                       i2o_proc_remove_entries(lan_fddi_entries, de);
+                                       break;
+                               case I2O_LAN_TR:
+                                       i2o_proc_remove_entries(lan_tr_entries, de);
+                                       break;
+                               }
+                       }
+                       remove_proc_entry(dev_id, parent);
+               }
+       }
 
-       i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
+       if(!pctrl->proc_entry->count)
+       {
+               sprintf(buff, "iop%d", pctrl->unit);
 
-       remove_proc_entry(buff, parent);
+               i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
 
-       pctrl->proc_entry = NULL;
+               remove_proc_entry(buff, parent);
+               pctrl->proc_entry = NULL;
+       }
 }
 
 static int create_i2o_procfs(void)
@@ -2327,7 +3031,10 @@ static int create_i2o_procfs(void)
        {
                pctrl = i2o_find_controller(i);
                if(pctrl)
+               {
                        i2o_proc_add_controller(pctrl, i2o_proc_dir_root);
+                       i2o_unlock_controller(pctrl);
+               }
        };
 
        return 0;
@@ -2345,19 +3052,25 @@ static int destroy_i2o_procfs(void)
        {
                pctrl = i2o_find_controller(i);
                if(pctrl)
+               {
                        i2o_proc_remove_controller(pctrl, i2o_proc_dir_root);
+                       i2o_unlock_controller(pctrl);
+               }
        };
 
-       remove_proc_entry("i2o", 0);
+       if(!i2o_proc_dir_root->count)
+               remove_proc_entry("i2o", 0);
+       else
+               return -1;
+
        return 0;
 }
                
 #ifdef MODULE
+#define i2o_proc_init init_module
+#endif
 
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("I2O procfs Handler");
-
-int init_module(void)
+__init int i2o_proc_init(void)
 {
        if(create_i2o_procfs())
                return -EBUSY;
@@ -2373,6 +3086,12 @@ int init_module(void)
        return 0;
 }
 
+#ifdef MODULE
+
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("I2O procfs Handler");
+
 void cleanup_module(void)
 {
        destroy_i2o_procfs();
index fd659c396cd64ca8de4d17e0df8298a3f72e977f..f2fe7185465fe9b59bfd30810d676f0069939ced 100644 (file)
@@ -32,110 +32,5 @@ typedef struct _i2o_mult_reply_message {
        u8 reserved;
        u8 req_status;
 } i2o_mult_reply_msg, *pi2o_mult_reply_msg;
-
-/**************************************************************************
- * HRT related constants and structures
- **************************************************************************/
-#define    I2O_BUS_LOCAL                               0
-#define    I2O_BUS_ISA                                 1
-#define    I2O_BUS_EISA                                2
-#define    I2O_BUS_MCA                                 3
-#define    I2O_BUS_PCI                                 4
-#define    I2O_BUS_PCMCIA                              5
-#define    I2O_BUS_NUBUS                               6
-#define    I2O_BUS_CARDBUS                             7
-#define    I2O_BUS_UNKNOWN                            0x80
-
-typedef struct _i2o_pci_bus {
-       u8 PciFunctionNumber;
-       u8 PciDeviceNumber;
-       u8 PciBusNumber;
-       u8 reserved;
-       u16 PciVendorID;
-       u16 PciDeviceID;
-} i2o_pci_bus, *pi2o_pci_bus;
-
-typedef struct _i2o_local_bus {
-       u16 LbBaseIOPort;
-       u16 reserved;
-       u32 LbBaseMemoryAddress;
-} i2o_local_bus, *pi2o_local_bus;
-
-typedef struct _i2o_isa_bus {
-       u16 IsaBaseIOPort;
-       u8 CSN;
-       u8 reserved;
-       u32 IsaBaseMemoryAddress;
-} i2o_isa_bus, *pi2o_isa_bus;
-
-/* I2O_EISA_BUS_INFO  */
-typedef struct _i2o_eisa_bus_info {
-       u16 EisaBaseIOPort;
-       u8 reserved;
-       u8 EisaSlotNumber;
-       u32 EisaBaseMemoryAddress;
-} i2o_eisa_bus, *pi2o_eisa_bus;
-
-typedef struct _i2o_mca_bus {
-       u16 McaBaseIOPort;
-       u8 reserved;
-       u8 McaSlotNumber;
-       u32 McaBaseMemoryAddress;
-} i2o_mca_bus, *pi2o_mca_bus;
-
-typedef struct _i2o_other_bus {
-       u16 BaseIOPort;
-       u16 reserved;
-       u32 BaseMemoryAddress;
-} i2o_other_bus, *pi2o_other_bus;
-
-
-typedef struct _i2o_hrt_entry {
-       u32 adapter_id;
-       u32 parent_tid:12;
-       u32 state:4;
-       u32 bus_num:8;
-       u32 bus_type:8;
-       union {
-               i2o_pci_bus pci_bus;
-               i2o_local_bus local_bus;
-               i2o_isa_bus isa_bus;
-               i2o_eisa_bus eisa_bus;
-               i2o_mca_bus mca_bus;
-               i2o_other_bus other_bus;
-       } bus;
-} i2o_hrt_entry, *pi2o_hrt_entry;
-
-typedef struct _i2o_hrt {
-       u16 num_entries;
-       u8 entry_len;
-       u8 hrt_version;
-       u32 change_ind;
-       i2o_hrt_entry hrt_entry[1];
-} i2o_hrt, *pi2o_hrt;
-
-typedef struct _i2o_lct_entry {
-       u32 entry_size:16;
-       u32 tid:12;
-       u32 reserved:4;
-       u32 change_ind;
-       u32 device_flags;
-       u32 class_id;
-       u32 sub_class;
-       u32 user_tid:12;
-       u32 parent_tid:12;
-       u32 bios_info:8;
-       u8 identity_tag[8];
-       u32 event_capabilities;
-} i2o_lct_entry, *pi2o_lct_entry;
-
-typedef struct _i2o_lct {
-       u32 table_size:16;
-       u32 boot_tid:12;
-       u32 lct_ver:4;
-       u32 iop_flags;
-       u32 current_change_ind;
-       i2o_lct_entry lct_entry[1];
-} i2o_lct, *pi2o_lct;
-
+   
 #endif                         /* i2oproc_h */
index 505e3c22d879e4b09dba0f17547d6130c0ab0e71..45ed85973152ece76d81a2e4e693562d2b9b88e7 100644 (file)
@@ -26,6 +26,9 @@
  *     Fixes:
  *             Steve Ralston   :       Scatter gather now works
  *
+ *     To Do
+ *             64bit cleanups
+ *             Fix the resource management problems.
  */
 
 #include <linux/module.h>
@@ -37,7 +40,6 @@
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -83,6 +85,7 @@ static atomic_t queue_depth;
 /*
  *     SG Chain buffer support...
  */
+
 #define SG_MAX_FRAGS           64
 
 /*
@@ -204,9 +207,12 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru
        }
                        
        
-       /* Low byte is the adapter status, next is the device */
-       as=(u8)m[4]; 
-       ds=(u8)(m[4]>>8);
+       /*
+        *      Low byte is device status, next is adapter status,
+        *      (then one byte reserved), then request status.
+        */
+       ds=(u8)m[4]; 
+       as=(u8)(m[4]>>8);
        st=(u8)(m[4]>>24);
        
        dprintk(("i2o got a scsi reply %08X: ", m[0]));
@@ -264,10 +270,10 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru
 
                dprintk((KERN_DEBUG "SCSI error %08X", m[4]));
                        
-               if (ds == 0x0E) 
+               if (as == 0x0E) 
                        /* SCSI Reset */
                        current_command->result = DID_RESET << 16;
-               else if (ds == 0x0F)
+               else if (as == 0x0F)
                        current_command->result = DID_PARITY << 16;
                else
                        current_command->result = DID_ERROR << 16;
@@ -433,7 +439,6 @@ int i2o_scsi_detect(Scsi_Host_Template * tpnt)
                          )
                                continue;
                
-//                     printk("Found a controller.\n");        
                        shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host));
                        save_flags(flags);
                        cli();
@@ -443,7 +448,6 @@ int i2o_scsi_detect(Scsi_Host_Template * tpnt)
                        shpnt->irq = 0;
                        shpnt->this_id = /* Good question */15;
                        restore_flags(flags);
-//                     printk("Scanning I2O port %d.\n", d->id);
                        i2o_scsi_init(c, d, shpnt);
                        count++;
                }
@@ -534,24 +538,11 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        int direction;
        int scsidir;
        u32 len;
+       u32 reqlen;
+       u32 tag;
        
        static int max_qd = 1;
        
-       /*
-        *      The scsi layer should be handling this stuff
-        */
-
-       if(is_dir_out(SCpnt))
-       {
-               direction=0x04000000;
-               scsidir=0x80000000;
-       }
-       else
-       {
-               scsidir=0x40000000;
-               direction=0x00000000;
-       }
-       
        /*
         *      Do the incoming paperwork
         */
@@ -604,13 +595,45 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
         *      Put together a scsi execscb message
         */
        
+       len = SCpnt->request_bufflen;
+       direction = 0x00000000;                 // SGL IN  (osm<--iop)
+       
+       /*
+        *      The scsi layer should be handling this stuff
+        */
+       
+       scsidir = 0x00000000;                   // DATA NO XFER
+       if(len)
+       {
+               if(is_dir_out(SCpnt))
+               {
+                       direction=0x04000000;   // SGL OUT  (osm-->iop)
+                       scsidir  =0x80000000;   // DATA OUT (iop-->dev)
+               }
+               else
+               {
+                       scsidir  =0x40000000;   // DATA IN  (iop<--dev)
+               }
+       }
+       
        msg[1] = I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid;
        msg[2] = scsi_context;          /* So the I2O layer passes to us */
        /* Sorry 64bit folks. FIXME */
        msg[3] = (u32)SCpnt;            /* We want the SCSI control block back */
-       /* Direction, disconnect ok, no tagging (yet) */
-       msg[4] = scsidir|(1<<29)|SCpnt->cmd_len;
 
+       /* LSI_920_PCI_QUIRK
+        *
+        *      Intermittant observations of msg frame word data corruption
+        *      observed on msg[4] after:
+        *        WRITE, READ-MODIFY-WRITE
+        *      operations.  19990606 -sralston
+        *
+        *      (Hence we build this word via tag. Its good practice anyway
+        *       we don't want fetches over PCI needlessly)
+        */
+
+       tag=0;
+       
        /*
         *      Attach tags to the devices
         */     
@@ -623,25 +646,24 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
                 */
                if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ))
                {
-                       msg[4]|=(1<<23)|(1<<24);
+                       tag=0x01800000;         /* ORDERED! */
                        hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies;
                }
-               else switch(SCpnt->tag)
+               else
                {
-                       case SIMPLE_QUEUE_TAG:
-                               msg[4]|=(1<<23);
-                               break;
-                       case HEAD_OF_QUEUE_TAG:
-                               msg[4]|=(1<<24);
-                               break;
-                       case ORDERED_QUEUE_TAG:
-                               msg[4]|=(1<<23)|(1<<24);
-                               break;
-                       default:
-                               msg[4]|=(1<<23);
+                       /* Hmmm...  I always see value of 0 here,
+                        *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston
+                        */
+                       if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
+                               tag=0x01000000;
+                       else if(SCpnt->tag == ORDERED_QUEUE_TAG)
+                               tag=0x01800000;
                }
        }
 
+       /* Direction, disconnect ok, tag, CDBLen */
+       msg[4] = scsidir|0x20000000|SCpnt->cmd_len|tag;
+
        mptr=msg+5;
 
        /* 
@@ -652,7 +674,7 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        mptr+=4;
        lenptr=mptr++;          /* Remember me - fill in when we know */
        
-                       
+       reqlen = 12;            // SINGLE SGE
        /*
         *      Now fill in the SGList and command 
         *
@@ -664,21 +686,22 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        if(SCpnt->use_sg)
        {
                struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
+               int chain = 0;
                
                if((sg_max_frags > 11) && (SCpnt->use_sg > 11))
                {
+                       chain = 1;
                        /*
                         *      Need to chain!
                         */
-                       SCpnt->host_scribble = (void*)(sg_chain_pool + sg_chain_tag);
                        *mptr++=direction|0xB0000000|(SCpnt->use_sg*2*4);
-                       *mptr=virt_to_bus(SCpnt->host_scribble);
-                       mptr = (u32*)SCpnt->host_scribble;
+                       *mptr=virt_to_bus(sg_chain_pool + sg_chain_tag);
+                       mptr = (u32*)(sg_chain_pool + sg_chain_tag);
                        if (SCpnt->use_sg > max_sg_len)
                        {
                                max_sg_len = SCpnt->use_sg;
                                printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n",
-                                       SCpnt, SCpnt->use_sg, (chain_buf*)SCpnt->host_scribble-sg_chain_pool);
+                                       SCpnt, SCpnt->use_sg, sg_chain_tag);
                        }
                        if ( ++sg_chain_tag == SG_MAX_BUFS )
                                sg_chain_tag = 0;
@@ -693,7 +716,15 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
                        *mptr++=virt_to_bus(sg->address);
                        sg++;
                }
-               mptr[-2]|=0xC0000000;   /* End of List and block */
+
+               /* Make this an end of list. Again evade the 920 bug and
+                  unwanted PCI read traffic */
+               
+               mptr[-2]=direction|0xD0000000|(sg-1)->length;
+               
+               if(!chain)
+                       reqlen = mptr - msg;
+               
                *lenptr=len;
                if(len != SCpnt->underflow)
                        printk("Cmd len %08X Cmd underflow %08X\n",
@@ -703,19 +734,23 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        {
                dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,
                                SCpnt->request_bufflen));
-               *mptr++=0xD0000000|direction|SCpnt->request_bufflen;
-               *mptr++=virt_to_bus(SCpnt->request_buffer);
                *lenptr = len = SCpnt->request_bufflen;
-               /* No transfer ? - fix up the request */
                if(len == 0)
-                       msg[4]&=~0xC0000000;
+               {
+                       reqlen = 9;
+               }
+               else
+               {
+                       *mptr++=0xD0000000|direction|SCpnt->request_bufflen;
+                       *mptr++=virt_to_bus(SCpnt->request_buffer);
+               }
        }
        
        /*
         *      Stick the headers on 
         */
 
-       msg[0] = (mptr-msg)<<16 | SGL_OFFSET_10;
+       msg[0] = reqlen<<16 | SGL_OFFSET_10;
        
        /* Queue the message */
        i2o_post_message(c,m);
@@ -757,7 +792,7 @@ int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
        u32 m;
        int tid;
        
-       printk("i2o_scsi_abort\n");
+       printk("i2o_scsi: Aborting command block.\n");
        
        host = SCpnt->host;
        hostdata = (struct i2o_scsi_host *)host->hostdata;
@@ -790,8 +825,6 @@ int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
        wmb();
        i2o_post_message(c,m);
        wmb();
-//     SCpnt->result = DID_RESET << 16;
-//     SCpnt->scsi_done(SCpnt);
        return SCSI_ABORT_PENDING;
 }
 
@@ -804,12 +837,12 @@ int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
        u32 m;
        u32 *msg;
 
-       printk("i2o_scsi_reset\n");
-       
        /*
         *      Find the TID for the bus
         */
 
+       printk("i2o_scsi: Attempting to reset the bus.\n");
+       
        host = SCpnt->host;
        hostdata = (struct i2o_scsi_host *)host->hostdata;
        tid = hostdata->bus_task;
index 7eb0c33cfa98719d0ea1821f30e8af25f038c825..80a2eccdb2c6cc6eb234a622faf5af633903f3b7 100644 (file)
@@ -1386,13 +1386,14 @@ static void capidrv_signal(__u16 applid, __u32 dummy)
                        handle_data(&s_cmsg, skb);
                        continue;
                }
-               kfree_skb(skb);
                if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
                        handle_controller(&s_cmsg);
                else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
                        handle_plci(&s_cmsg);
                else
                        handle_ncci(&s_cmsg);
+
+               kfree_skb(skb);
        }
 }
 
index 92012c8e5c7b44ce1c4cb03a85b21416f6671b49..e5cc0ea30be552fed8e594948a1899410b0797f4 100644 (file)
@@ -64,7 +64,6 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>       /* to get the struct task_struct */
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
 
diff --git a/drivers/net/arlan-proc.c b/drivers/net/arlan-proc.c
new file mode 100644 (file)
index 0000000..4bd4f5d
--- /dev/null
@@ -0,0 +1,1059 @@
+
+#include "arlan.h"
+
+#ifdef CONFIG_PROC_FS
+
+
+#include <linux/sysctl.h>
+#include <linux/version.h>
+
+/* void enableReceive(struct device* dev);
+*/
+
+static  int    arlan_command(struct device * dev, int command);
+
+
+#define ARLAN_STR_SIZE         0x2ff0
+#define DEV_ARLAN_INFO         1
+#define DEV_ARLAN      1
+#define SARLG(type,var) {\
+       pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n", #var, READSHMB(priva->card->var));        \
+       }
+
+#define SARLBN(type,var,nn) {\
+       pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x",#var);\
+       for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\
+       pos += sprintf(arlan_drive_info+pos, "\n");     \
+       }
+
+#define SARLBNpln(type,var,nn) {\
+       for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\
+       }
+
+#define SARLSTR(var,nn) {\
+       char tmpStr[400];\
+       int  tmpLn = nn;\
+       if (nn > 399 ) tmpLn = 399; \
+       memcpy(tmpStr,(char *) priva->conf->var,tmpLn);\
+       tmpStr[tmpLn] = 0; \
+       pos += sprintf(arlan_drive_info+pos, "%s\t=\t%s \n",#var,priva->conf->var);\
+       }
+
+#define SARLUC(var)    SARLG(u_char, var)
+#define SARLUCN(var,nn) SARLBN(u_char,var, nn)
+#define SARLUS(var)    SARLG(u_short, var)
+#define SARLUSN(var,nn)        SARLBN(u_short,var, nn)
+#define SARLUI(var)    SARLG(u_int, var)
+
+#define SARLUSA(var) {\
+       u_short tmpVar;\
+       memcpy(&tmpVar, (short *) priva->conf->var,2); \
+       pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\
+}
+
+#define SARLUIA(var) {\
+       u_int tmpVar;\
+       memcpy(&tmpVar, (int* )priva->conf->var,4); \
+       pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\
+}
+
+
+const char *arlan_diagnostic_info_string(struct device *dev)
+{
+
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+       u_char diagnosticInfo;
+
+       READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char);
+
+       switch (diagnosticInfo)
+       {
+               case 0xFF:
+                       return "Diagnostic info is OK";
+               case 0xFE:
+                       return "ERROR EPROM Checksum error ";
+               case 0xFD:
+                       return "ERROR Local Ram Test Failed ";
+               case 0xFC:
+                       return "ERROR SCC failure ";
+               case 0xFB:
+                       return "ERROR BackBone failure ";
+               case 0xFA:
+                       return "ERROR tranceiver not found ";
+               case 0xF9:
+                       return "ERROR no more address space ";
+               case 0xF8:
+                       return "ERROR Checksum error  ";
+               case 0xF7:
+                       return "ERROR Missing SS Code";
+               case 0xF6:
+                       return "ERROR Invalid config format";
+               case 0xF5:
+                       return "ERROR Reserved errorcode F5";
+               case 0xF4:
+                       return "ERROR Invalid spreading code/channel number";
+               case 0xF3:
+                       return "ERROR Load Code Error";
+               case 0xF2:
+                       return "ERROR Reserver errorcode F2 ";
+               case 0xF1:
+                       return "ERROR Invalid command receivec by LAN card ";
+               case 0xF0:
+                       return "ERROR Invalid parameter found in command ";
+               case 0xEF:
+                       return "ERROR On-chip timer failure ";
+               case 0xEE:
+                       return "ERROR T410 timer failure ";
+               case 0xED:
+                       return "ERROR Too Many TxEnable commands ";
+               case 0xEC:
+                       return "ERROR EEPROM error on radio module ";
+               default:
+                       return "ERROR unknown Diagnostic info reply code ";
+         }
+};
+
+static const char *arlan_hardware_type_string(struct device *dev)
+{
+       u_char hardwareType;
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+       READSHM(hardwareType, arlan->hardwareType, u_char);
+       switch (hardwareType)
+       {
+               case 0x00:
+                       return "type A450";
+               case 0x01:
+                       return "type A650 ";
+               case 0x04:
+                       return "type TMA coproc";
+               case 0x0D:
+                       return "type A650E ";
+               case 0x18:
+                       return "type TMA coproc Australian";
+               case 0x19:
+                       return "type A650A ";
+               case 0x26:
+                       return "type TMA coproc European";
+               case 0x2E:
+                       return "type A655 ";
+               case 0x2F:
+                       return "type A655A ";
+               case 0x30:
+                       return "type A655E ";
+               case 0x0B:
+                       return "type A670 ";
+               case 0x0C:
+                       return "type A670E ";
+               case 0x2D:
+                       return "type A670A ";
+               case 0x0F:
+                       return "type A411T";
+               case 0x16:
+                       return "type A411TA";
+               case 0x1B:
+                       return "type A440T";
+               case 0x1C:
+                       return "type A412T";
+               case 0x1E:
+                       return "type A412TA";
+               case 0x22:
+                       return "type A411TE";
+               case 0x24:
+                       return "type A412TE";
+               case 0x27:
+                       return "type A671T ";
+               case 0x29:
+                       return "type A671TA ";
+               case 0x2B:
+                       return "type A671TE ";
+               case 0x31:
+                       return "type A415T ";
+               case 0x33:
+                       return "type A415TA ";
+               case 0x35:
+                       return "type A415TE ";
+               case 0x37:
+                       return "type A672";
+               case 0x39:
+                       return "type A672A ";
+               case 0x3B:
+                       return "type A672T";
+               case 0x6B:
+                       return "type IC2200";
+               default:
+                       return "type A672T";
+       }
+}
+
+static void arlan_print_diagnostic_info(struct device *dev)
+{
+       int i;
+       u_char diagnosticInfo;
+       u_short diagnosticOffset;
+       u_char hardwareType;
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+       //  ARLAN_DEBUG_ENTRY("arlan_print_diagnostic_info");
+
+       if (READSHMB(arlan->configuredStatusFlag) == 0)
+               printk("Arlan: Card NOT configured\n");
+       else
+               printk("Arlan: Card is configured\n");
+
+       READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char);
+       READSHM(diagnosticOffset, arlan->diagnosticOffset, u_short);
+
+       printk(KERN_INFO "%s\n", arlan_diagnostic_info_string(dev));
+
+       if (diagnosticInfo != 0xff)
+               printk("%s arlan: Diagnostic Offset %d \n", dev->name, diagnosticOffset);
+
+       printk("arlan: LAN CODE ID = ");
+       for (i = 0; i < 6; i++)
+               DEBUGSHM(1, "%03d:", arlan->lanCardNodeId[i], u_char);
+       printk("\n");
+
+       printk("arlan: Arlan BroadCast address  = ");
+       for (i = 0; i < 6; i++)
+               DEBUGSHM(1, "%03d:", arlan->broadcastAddress[i], u_char);
+       printk("\n");
+
+       READSHM(hardwareType, arlan->hardwareType, u_char);
+       printk(KERN_INFO "%s\n", arlan_hardware_type_string(dev));
+
+
+       DEBUGSHM(1, "arlan: channelNumber=%d\n", arlan->channelNumber, u_char);
+       DEBUGSHM(1, "arlan: channelSet=%d\n", arlan->channelSet, u_char);
+       DEBUGSHM(1, "arlan: spreadingCode=%d\n", arlan->spreadingCode, u_char);
+       DEBUGSHM(1, "arlan: radioNodeId=%d\n", arlan->radioNodeId, u_short);
+       DEBUGSHM(1, "arlan: SID =%d\n", arlan->SID, u_short);
+       DEBUGSHM(1, "arlan: rxOffset=%d\n", arlan->rxOffset, u_short);
+
+       DEBUGSHM(1, "arlan: registration mode is %d\n", arlan->registrationMode, u_char);
+
+       printk("arlan: name= ");
+       IFDEBUG(1)
+       
+       for (i = 0; i < 16; i++)
+       {
+               char c;
+               READSHM(c, arlan->name[i], char);
+               if (c)
+                       printk("%c", c);
+       }
+       printk("\n");
+
+//   ARLAN_DEBUG_EXIT("arlan_print_diagnostic_info");
+
+}
+
+
+/******************************                TEST    MEMORY  **************/
+
+static int arlan_hw_test_memory(struct device *dev)
+{
+       u_char *ptr;
+       int i;
+       int memlen = sizeof(struct arlan_shmem) - 0xF;  /* avoid control register */
+       volatile char *arlan_mem = (char *) (dev->mem_start);
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+       char pattern;
+
+       ptr = NULL;
+
+       /* hold card in reset state */
+       setHardwareReset(dev);
+
+       /* test memory */
+       pattern = 0;
+       for (i = 0; i < memlen; i++)
+               WRITESHM(arlan_mem[i], ((u_char) pattern++), u_char);
+
+       pattern = 0;
+       for (i = 0; i < memlen; i++)
+       {
+               char res;
+               READSHM(res, arlan_mem[i], char);
+               if (res != pattern++)
+               {
+                       printk(KERN_ERR "Arlan driver memory test 1 failed \n");
+                       return -1;
+               }
+       }
+
+       pattern = 0;
+       for (i = 0; i < memlen; i++)
+               WRITESHM(arlan_mem[i], ~(pattern++), char);
+
+       pattern = 0;
+       for (i = 0; i < memlen; i++)
+       {
+               char res;
+               READSHM(res, arlan_mem[i], char);
+               if (res != ~(pattern++))
+               {
+                       printk(KERN_ERR "Arlan driver memory test 2 failed \n");
+                       return -1;
+               }
+       }
+
+       /* zero memory */
+       for (i = 0; i < memlen; i++)
+               WRITESHM(arlan_mem[i], 0x00, char);
+
+       IFDEBUG(1) printk(KERN_INFO "Arlan: memory tests ok\n");
+
+       /* set reset flag and then release reset */
+       WRITESHM(arlan->resetFlag, 0xff, u_char);
+
+       clearChannelAttention(dev);
+       clearHardwareReset(dev);
+
+       /* wait for reset flag to become zero, we'll wait for two seconds */
+       if (arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW))
+       {
+               printk(KERN_ERR "%s arlan: failed to come back from memory test\n", dev->name);
+               return -1;
+       }
+       return 0;
+}
+
+
+static int arlan_setup_card_by_book(struct device *dev)
+{
+       u_char irqLevel, configuredStatusFlag;
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+//     ARLAN_DEBUG_ENTRY("arlan_setup_card");
+
+       READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char);
+
+       IFDEBUG(10)
+       if (configuredStatusFlag != 0)
+               IFDEBUG(10) printk("arlan: CARD IS CONFIGURED\n");
+       else
+               IFDEBUG(10) printk("arlan: card is NOT configured\n");
+
+       if (testMemory || (READSHMB(arlan->diagnosticInfo) != 0xff))
+               if (arlan_hw_test_memory(dev))
+                       return -1;
+
+       DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char);
+       DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char);
+
+       /* issue nop command - no interupt */
+       arlan_command(dev, ARLAN_COMMAND_NOOP);
+       if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0)
+               return -1;
+
+       IFDEBUG(50) printk("1st Noop successfully executed !!\n");
+
+       /* try to turn on the arlan interrupts */
+       clearClearInterrupt(dev);
+       setClearInterrupt(dev);
+       setInterruptEnable(dev);
+
+       /* issue nop command - with interrupt */
+
+       arlan_command(dev, ARLAN_COMMAND_NOOPINT);
+       if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0)
+               return -1;
+
+
+       IFDEBUG(50) printk("2nd Noop successfully executed !!\n");
+
+       READSHM(irqLevel, arlan->irqLevel, u_char)
+       
+       if (irqLevel != dev->irq)
+       {
+               IFDEBUG(1) printk(KERN_WARNING "arlan dip switches set irq to %d\n", irqLevel);
+               printk(KERN_WARNING "device driver irq set to %d - does not match\n", dev->irq);
+               dev->irq = irqLevel;
+       }
+       else
+               IFDEBUG(2) printk("irq level is OK\n");
+
+
+       IFDEBUG(3) arlan_print_diagnostic_info(dev);
+
+       arlan_command(dev, ARLAN_COMMAND_CONF);
+
+       READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char);
+       if (configuredStatusFlag == 0)
+       {
+               printk(KERN_WARNING "arlan configure failed\n");
+               return -1;
+       }
+       arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW);
+       arlan_command(dev, ARLAN_COMMAND_RX);
+       arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW);
+       printk(KERN_NOTICE "%s: arlan driver version %s loaded\n",
+              dev->name, arlan_version);
+
+//     ARLAN_DEBUG_EXIT("arlan_setup_card");
+
+       return 0;               /* no errors */
+}
+
+
+#ifdef ARLAN_PROC_INTERFACE
+#ifdef ARLAN_PROC_SHM_DUMP
+
+static char arlan_drive_info[ARLAN_STR_SIZE] = "A655\n\0";
+
+static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp,
+                     void *buffer, size_t * lenp)
+{
+       int i;
+       int retv, pos, devnum;
+       struct arlan_private *priva = NULL;
+       struct device *dev;
+       pos = 0;
+       if (write)
+       {
+               printk("wrirte: ");
+               for (i = 0; i < 100; i++)
+                       printk("adi %x \n", arlan_drive_info[i]);
+       }
+       if (ctl->procname == NULL || arlan_drive_info == NULL)
+       {
+               printk(KERN_WARNING " procname is NULL in sysctl_table or arlan_drive_info is NULL \n at arlan module\n ");
+               return -1;
+       }
+       devnum = ctl->procname[5] - '0';
+       if (devnum < 0 || devnum > MAX_ARLANS - 1)
+       {
+               printk(KERN_WARNING "too strange devnum in procfs parse\n ");
+               return -1;
+       }
+       else if (arlan_device[devnum] == NULL)
+       {
+               if (ctl->procname)
+                       pos += sprintf(arlan_drive_info + pos, "\t%s\n\n", ctl->procname);
+               pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+               goto final;
+       }
+       else
+               priva = arlan_device[devnum]->priv;
+
+       if (priva == NULL)
+       {
+               printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+               return -1;
+       }
+       dev = arlan_device[devnum];
+
+       memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+
+       pos = sprintf(arlan_drive_info, "Arlan  info \n");
+       /* Header Signature */
+       SARLSTR(textRegion, 48);
+       SARLUC(resetFlag);
+       pos += sprintf(arlan_drive_info + pos, "diagnosticInfo\t=\t%s \n", arlan_diagnostic_info_string(dev));
+       SARLUC(diagnosticInfo);
+       SARLUS(diagnosticOffset);
+       SARLUCN(_1, 12);
+       SARLUCN(lanCardNodeId, 6);
+       SARLUCN(broadcastAddress, 6);
+       pos += sprintf(arlan_drive_info + pos, "hardwareType =\t  %s \n", arlan_hardware_type_string(dev));
+       SARLUC(hardwareType);
+       SARLUC(majorHardwareVersion);
+       SARLUC(minorHardwareVersion);
+       SARLUC(radioModule);
+       SARLUC(defaultChannelSet);
+       SARLUCN(_2, 47);
+
+       /* Control/Status Block - 0x0080 */
+       SARLUC(interruptInProgress);
+       SARLUC(cntrlRegImage);
+
+       SARLUCN(_3, 14);
+       SARLUC(commandByte);
+       SARLUCN(commandParameter, 15);
+
+       /* Receive Status - 0x00a0 */
+       SARLUC(rxStatus);
+       SARLUC(rxFrmType);
+       SARLUS(rxOffset);
+       SARLUS(rxLength);
+       SARLUCN(rxSrc, 6);
+       SARLUC(rxBroadcastFlag);
+       SARLUC(rxQuality);
+       SARLUC(scrambled);
+       SARLUCN(_4, 1);
+
+       /* Transmit Status - 0x00b0 */
+       SARLUC(txStatus);
+       SARLUC(txAckQuality);
+       SARLUC(numRetries);
+       SARLUCN(_5, 14);
+       SARLUCN(registeredRouter, 6);
+       SARLUCN(backboneRouter, 6);
+       SARLUC(registrationStatus);
+       SARLUC(configuredStatusFlag);
+       SARLUCN(_6, 1);
+       SARLUCN(ultimateDestAddress, 6);
+       SARLUCN(immedDestAddress, 6);
+       SARLUCN(immedSrcAddress, 6);
+       SARLUS(rxSequenceNumber);
+       SARLUC(assignedLocaltalkAddress);
+       SARLUCN(_7, 27);
+
+       /* System Parameter Block */
+
+       /* - Driver Parameters (Novell Specific) */
+
+       SARLUS(txTimeout);
+       SARLUS(transportTime);
+       SARLUCN(_8, 4);
+
+       /* - Configuration Parameters */
+       SARLUC(irqLevel);
+       SARLUC(spreadingCode);
+       SARLUC(channelSet);
+       SARLUC(channelNumber);
+       SARLUS(radioNodeId);
+       SARLUCN(_9, 2);
+       SARLUC(scramblingDisable);
+       SARLUC(radioType);
+       SARLUS(routerId);
+       SARLUCN(_10, 9);
+       SARLUC(txAttenuation);
+       SARLUIA(systemId);
+       SARLUS(globalChecksum);
+       SARLUCN(_11, 4);
+       SARLUS(maxDatagramSize);
+       SARLUS(maxFrameSize);
+       SARLUC(maxRetries);
+       SARLUC(receiveMode);
+       SARLUC(priority);
+       SARLUC(rootOrRepeater);
+       SARLUCN(specifiedRouter, 6);
+       SARLUS(fastPollPeriod);
+       SARLUC(pollDecay);
+       SARLUSA(fastPollDelay);
+       SARLUC(arlThreshold);
+       SARLUC(arlDecay);
+       SARLUCN(_12, 1);
+       SARLUS(specRouterTimeout);
+       SARLUCN(_13, 5);
+
+       /* Scrambled Area */
+       SARLUIA(SID);
+       SARLUCN(encryptionKey, 12);
+       SARLUIA(_14);
+       SARLUSA(waitTime);
+       SARLUSA(lParameter);
+       SARLUCN(_15, 3);
+       SARLUS(headerSize);
+       SARLUS(sectionChecksum);
+
+       SARLUC(registrationMode);
+       SARLUC(registrationFill);
+       SARLUS(pollPeriod);
+       SARLUS(refreshPeriod);
+       SARLSTR(name, 16);
+       SARLUCN(NID, 6);
+       SARLUC(localTalkAddress);
+       SARLUC(codeFormat);
+       SARLUC(numChannels);
+       SARLUC(channel1);
+       SARLUC(channel2);
+       SARLUC(channel3);
+       SARLUC(channel4);
+       SARLUCN(SSCode, 59);
+
+/*      SARLUCN( _16, 0x140);
+ */
+       /* Statistics Block - 0x0300 */
+       SARLUC(hostcpuLock);
+       SARLUC(lancpuLock);
+       SARLUCN(resetTime, 18);
+       SARLUIA(numDatagramsTransmitted);
+       SARLUIA(numReTransmissions);
+       SARLUIA(numFramesDiscarded);
+       SARLUIA(numDatagramsReceived);
+       SARLUIA(numDuplicateReceivedFrames);
+       SARLUIA(numDatagramsDiscarded);
+       SARLUS(maxNumReTransmitDatagram);
+       SARLUS(maxNumReTransmitFrames);
+       SARLUS(maxNumConsecutiveDuplicateFrames);
+       /* misaligned here so we have to go to characters */
+       SARLUIA(numBytesTransmitted);
+       SARLUIA(numBytesReceived);
+       SARLUIA(numCRCErrors);
+       SARLUIA(numLengthErrors);
+       SARLUIA(numAbortErrors);
+       SARLUIA(numTXUnderruns);
+       SARLUIA(numRXOverruns);
+       SARLUIA(numHoldOffs);
+       SARLUIA(numFramesTransmitted);
+       SARLUIA(numFramesReceived);
+       SARLUIA(numReceiveFramesLost);
+       SARLUIA(numRXBufferOverflows);
+       SARLUIA(numFramesDiscardedAddrMismatch);
+       SARLUIA(numFramesDiscardedSIDMismatch);
+       SARLUIA(numPollsTransmistted);
+       SARLUIA(numPollAcknowledges);
+       SARLUIA(numStatusTimeouts);
+       SARLUIA(numNACKReceived);
+       SARLUS(auxCmd);
+       SARLUCN(dumpPtr, 4);
+       SARLUC(dumpVal);
+       SARLUC(wireTest);
+       
+       /* next 4 seems too long for procfs, over single page ?
+       SARLUCN( _17, 0x86);
+       SARLUCN( txBuffer, 0x800);
+       SARLUCN( rxBuffer,  0x800); 
+       SARLUCN( _18, 0x0bff);
+        */
+
+       pos += sprintf(arlan_drive_info + pos, "rxRing\t=\t0x");
+       for (i = 0; i < 0x50; i++)
+               pos += sprintf(arlan_drive_info + pos, "%02x", ((char *) priva->conf)[priva->conf->rxOffset + i]);
+       pos += sprintf(arlan_drive_info + pos, "\n");
+
+       SARLUC(configStatus);
+       SARLUC(_22);
+       SARLUC(progIOCtrl);
+       SARLUC(shareMBase);
+       SARLUC(controlRegister);
+
+       pos += sprintf(arlan_drive_info + pos, " total %d chars\n", pos);
+       if (ctl)
+               if (ctl->procname)
+                       pos += sprintf(arlan_drive_info + pos, " driver name : %s\n", ctl->procname);
+final:
+       *lenp = pos;
+
+       if (!write)
+               retv = proc_dostring(ctl, write, filp, buffer, lenp);
+       else
+       {
+               *lenp = 0;
+               return -1;
+       }
+       return retv;
+}
+
+
+static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp,
+                           void *buffer, size_t * lenp)
+{
+       int i;
+       int retv, pos, devnum;
+       struct arlan_private *priva = NULL;
+
+       pos = 0;
+       devnum = ctl->procname[5] - '0';
+       if (arlan_device[devnum] == NULL)
+       {
+               pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+               goto final;
+       }
+       else
+               priva = arlan_device[devnum]->priv;
+       if (priva == NULL)
+       {
+               printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+               return -1;
+       }
+       memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+       SARLUCN(_16, 0xC0);
+       SARLUCN(_17, 0x6A);
+       SARLUCN(_18, 14);
+       SARLUCN(_19, 0x86);
+       SARLUCN(_21, 0x3fd);
+
+final:
+       *lenp = pos;
+       retv = proc_dostring(ctl, write, filp, buffer, lenp);
+       return retv;
+}
+
+static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp,
+                           void *buffer, size_t * lenp)
+{
+       int i;
+       int retv, pos, devnum;
+       struct arlan_private *priva = NULL;
+
+       pos = 0;
+       devnum = ctl->procname[5] - '0';
+       if (arlan_device[devnum] == NULL)
+       {
+                 pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+                 goto final;
+       }
+       else
+               priva = arlan_device[devnum]->priv;
+       if (priva == NULL)
+       {
+               printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+               return -1;
+       }
+       memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+       SARLBNpln(u_char, txBuffer, 0x800);
+final:
+       *lenp = pos;
+       retv = proc_dostring(ctl, write, filp, buffer, lenp);
+       return retv;
+}
+
+static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp,
+                           void *buffer, size_t * lenp)
+{
+       int i;
+       int retv, pos, devnum;
+       struct arlan_private *priva = NULL;
+
+       pos = 0;
+       devnum = ctl->procname[5] - '0';
+       if (arlan_device[devnum] == NULL)
+       {
+                 pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+                 goto final;
+       } else
+               priva = arlan_device[devnum]->priv;
+       if (priva == NULL)
+       {
+               printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+               return -1;
+       }
+       memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+       SARLBNpln(u_char, rxBuffer, 0x800);
+final:
+       *lenp = pos;
+       retv = proc_dostring(ctl, write, filp, buffer, lenp);
+       return retv;
+}
+
+static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp,
+                       void *buffer, size_t * lenp)
+{
+       int i;
+       int retv, pos, devnum;
+       struct arlan_private *priva = NULL;
+
+       pos = 0;
+       devnum = ctl->procname[5] - '0';
+       if (arlan_device[devnum] == NULL)
+       {
+               pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+               goto final;
+       }
+       else
+               priva = arlan_device[devnum]->priv;
+       if (priva == NULL)
+       {
+               printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+               return -1;
+       }
+       memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+       SARLBNpln(u_char, _18, 0x800);
+
+final:
+       *lenp = pos;
+       retv = proc_dostring(ctl, write, filp, buffer, lenp);
+       return retv;
+}
+
+
+#endif                         /* #ifdef ARLAN_PROC_SHM_DUMP */
+
+
+static char conf_reset_result[200];
+
+static int arlan_configure(ctl_table * ctl, int write, struct file *filp,
+                   void *buffer, size_t * lenp)
+{
+       int pos = 0;
+       int devnum = ctl->procname[6] - '0';
+       struct arlan_private *priv;
+
+       if (devnum < 0 || devnum > MAX_ARLANS - 1)
+       {
+                 printk(KERN_WARNING "too strange devnum in procfs parse\n ");
+                 return -1;
+       }
+       else if (arlan_device[devnum] != NULL)
+       {
+                 priv = arlan_device[devnum]->priv;
+
+                 arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF);
+       }
+       else
+               return -1;
+
+       *lenp = pos;
+       return proc_dostring(ctl, write, filp, buffer, lenp);
+}
+
+int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp,
+                      void *buffer, size_t * lenp)
+{
+       int pos = 0;
+       int devnum = ctl->procname[5] - '0';
+       struct arlan_private *priv;
+
+       if (devnum < 0 || devnum > MAX_ARLANS - 1)
+       {
+                 printk(KERN_WARNING "too strange devnum in procfs parse\n ");
+                 return -1;
+       }
+       else if (arlan_device[devnum] != NULL)
+       {
+               priv = arlan_device[devnum]->priv;
+               arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET);
+
+       } else
+               return -1;
+       *lenp = pos + 3;
+       return proc_dostring(ctl, write, filp, buffer, lenp);
+}
+
+
+/* Place files in /proc/sys/dev/arlan */
+#define CTBLN(num,card,nam) \
+        {num , #nam, &(arlan_conf[card].nam), \
+         sizeof(int), 0600, NULL, &proc_dointvec}
+
+
+#define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\
+       CTBLN(1,cardNo,spreadingCode),\
+       CTBLN(2,cardNo, channelNumber),\
+       CTBLN(3,cardNo, scramblingDisable),\
+       CTBLN(4,cardNo, txAttenuation),\
+       CTBLN(5,cardNo, systemId), \
+       CTBLN(6,cardNo, maxDatagramSize),\
+       CTBLN(7,cardNo, maxFrameSize),\
+       CTBLN(8,cardNo, maxRetries),\
+       CTBLN(9,cardNo, receiveMode),\
+       CTBLN(10,cardNo, priority),\
+       CTBLN(11,cardNo, rootOrRepeater),\
+       CTBLN(12,cardNo, SID),\
+       CTBLN(13,cardNo, registrationMode),\
+       CTBLN(14,cardNo, registrationFill),\
+       CTBLN(15,cardNo, localTalkAddress),\
+       CTBLN(16,cardNo, codeFormat),\
+       CTBLN(17,cardNo, numChannels),\
+       CTBLN(18,cardNo, channel1),\
+       CTBLN(19,cardNo, channel2),\
+       CTBLN(20,cardNo, channel3),\
+       CTBLN(21,cardNo, channel4),\
+       CTBLN(22,cardNo, txClear),\
+       CTBLN(23,cardNo, txRetries),\
+       CTBLN(24,cardNo, txRouting),\
+       CTBLN(25,cardNo, txScrambled),\
+       CTBLN(26,cardNo, rxParameter),\
+       CTBLN(27,cardNo, txTimeoutMs),\
+       CTBLN(28,cardNo, waitCardTimeout),\
+       CTBLN(29,cardNo, channelSet), \
+       {30, "name", arlan_conf[cardNo].siteName, \
+                16, 0600, NULL, &proc_dostring},\
+       CTBLN(31,cardNo,waitTime),\
+       CTBLN(32,cardNo,lParameter),\
+       CTBLN(33,cardNo,_15),\
+       CTBLN(34,cardNo,headerSize),\
+       CTBLN(35,cardNo,async),\
+       CTBLN(36,cardNo,tx_delay_ms),\
+       CTBLN(37,cardNo,retries),\
+       CTBLN(38,cardNo,ReTransmitPacketMaxSize),\
+       CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\
+       CTBLN(40,cardNo,fastReTransCount),\
+       CTBLN(41,cardNo,driverRetransmissions),\
+       CTBLN(42,cardNo,txAckTimeoutMs),\
+       CTBLN(43,cardNo,registrationInterrupts),\
+       CTBLN(44,cardNo,hardwareType),\
+       CTBLN(45,cardNo,radioType),\
+       CTBLN(46,cardNo,writeEEPROM),\
+       CTBLN(47,cardNo,writeRadioType),\
+       {48, "entry_exit_debug", &arlan_entry_and_exit_debug, \
+                sizeof(int), 0600, NULL, &proc_dointvec},\
+       {49, "debug", &arlan_debug, \
+                sizeof(int), 0600, NULL, &proc_dointvec},\
+       CTBLN(50,cardNo,in_speed),\
+       CTBLN(51,cardNo,out_speed),\
+       CTBLN(52,cardNo,in_speed10),\
+       CTBLN(53,cardNo,out_speed10),\
+       CTBLN(54,cardNo,in_speed_max),\
+       CTBLN(55,cardNo,out_speed_max),\
+       CTBLN(56,cardNo,measure_rate),\
+       CTBLN(57,cardNo,pre_Command_Wait),\
+       CTBLN(58,cardNo,rx_tweak1),\
+       CTBLN(59,cardNo,rx_tweak2),\
+       CTBLN(60,cardNo,tx_queue_len),\
+
+
+
+static ctl_table arlan_conf_table0[] =
+{
+       ARLAN_SYSCTL_TABLE_TOTAL(0)
+
+#ifdef ARLAN_PROC_SHM_DUMP
+       {150, "arlan0-txRing", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing},
+       {151, "arlan0-rxRing", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing},
+       {152, "arlan0-18", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18},
+       {153, "arlan0-ring", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719},
+       {154, "arlan0-shm-cpy", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info},
+#endif
+       {155, "config0", &conf_reset_result, \
+        100, 0400, NULL, &arlan_configure}, \
+       {156, "reset0", &conf_reset_result, \
+        100, 0400, NULL, &arlan_sysctl_reset}, \
+       {0}
+};
+
+static ctl_table arlan_conf_table1[] =
+{
+
+       ARLAN_SYSCTL_TABLE_TOTAL(1)
+
+#ifdef ARLAN_PROC_SHM_DUMP
+       {150, "arlan1-txRing", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing},
+       {151, "arlan1-rxRing", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing},
+       {152, "arlan1-18", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18},
+       {153, "arlan1-ring", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719},
+       {154, "arlan1-shm-cpy", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info},
+#endif
+       {155, "config1", &conf_reset_result,
+        100, 0400, NULL, &arlan_configure},
+       {156, "reset1", &conf_reset_result,
+        100, 0400, NULL, &arlan_sysctl_reset},
+       {0}
+};
+
+static ctl_table arlan_conf_table2[] =
+{
+
+       ARLAN_SYSCTL_TABLE_TOTAL(2)
+
+#ifdef ARLAN_PROC_SHM_DUMP
+       {150, "arlan2-txRing", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing},
+       {151, "arlan2-rxRing", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing},
+       {152, "arlan2-18", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18},
+       {153, "arlan2-ring", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719},
+       {154, "arlan2-shm-cpy", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info},
+#endif
+       {155, "config2", &conf_reset_result,
+        100, 0400, NULL, &arlan_configure},
+       {156, "reset2", &conf_reset_result,
+        100, 0400, NULL, &arlan_sysctl_reset},
+       {0}
+};
+
+static ctl_table arlan_conf_table3[] =
+{
+
+       ARLAN_SYSCTL_TABLE_TOTAL(3)
+
+#ifdef ARLAN_PROC_SHM_DUMP
+       {150, "arlan3-txRing", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing},
+       {151, "arlan3-rxRing", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing},
+       {152, "arlan3-18", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18},
+       {153, "arlan3-ring", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719},
+       {154, "arlan3-shm-cpy", &arlan_drive_info,
+        ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info},
+#endif
+       {155, "config3", &conf_reset_result,
+        100, 0400, NULL, &arlan_configure},
+       {156, "reset3", &conf_reset_result,
+        100, 0400, NULL, &arlan_sysctl_reset},
+       {0}
+};
+
+
+
+static ctl_table arlan_table[] =
+{
+       {0, "arlan0", NULL, 0, 0600, arlan_conf_table0},
+       {0, "arlan1", NULL, 0, 0600, arlan_conf_table1},
+       {0, "arlan2", NULL, 0, 0600, arlan_conf_table2},
+       {0, "arlan3", NULL, 0, 0600, arlan_conf_table3},
+       {0}
+};
+
+#else
+
+static ctl_table arlan_table[MAX_ARLANS + 1] =
+{
+       {0}
+};
+#endif
+#endif
+
+static int mmtu = 1234;
+
+static ctl_table arlan_root_table[] =
+{
+       {254, "arlan", NULL, 0, 0555, arlan_table},
+       {0}
+};
+
+/* Make sure that /proc/sys/dev is there */
+static ctl_table arlan_device_root_table[] =
+{
+       {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table},
+       {0}
+};
+
+
+
+static struct ctl_table_header *arlan_device_sysctl_header = NULL;
+
+int init_arlan_proc(void)
+{
+
+       int i = 0;
+       if (arlan_device_sysctl_header)
+               return 0;
+       for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++)
+               arlan_table[i].ctl_name = i + 1;
+       arlan_device_sysctl_header = register_sysctl_table(arlan_root_table, 0);
+       if (!arlan_device_sysctl_header)
+               return -1;
+
+       return 0;
+
+};
+
+
+
+#ifdef MODULE
+
+int init_module(void)
+{
+
+       return init_arlan_proc();
+};
+
+void cleanup_module(void)
+{
+       unregister_sysctl_table(arlan_device_sysctl_header);
+       arlan_device_sysctl_header = NULL;
+
+       return;
+};
+
+#endif                         // MODULE
diff --git a/drivers/net/arlan.c b/drivers/net/arlan.c
new file mode 100644 (file)
index 0000000..fcd5fa4
--- /dev/null
@@ -0,0 +1,2079 @@
+/*
+ *  Copyright (C) 1997 Cullen Jennings
+ *  Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500        
+ *  Gnu Public License applies
+ * This module provides support for the Arlan 655 card made by Aironet
+ */
+
+
+#include "arlan.h"
+
+static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee  Oct'98, http://www.ylenurme.ee/~elmer/655/";
+
+struct device *arlan_device[MAX_ARLANS];
+int last_arlan = 0;
+
+static int SID = SIDUNKNOWN;
+static int radioNodeId = radioNodeIdUNKNOWN;
+static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};
+static char *siteName = siteNameUNKNOWN;
+static int irq = irqUNKNOWN;
+static int mem = memUNKNOWN;
+static int arlan_debug = debugUNKNOWN;
+static int probe = probeUNKNOWN;
+static int numDevices = numDevicesUNKNOWN;
+static int testMemory = testMemoryUNKNOWN;
+static int spreadingCode = spreadingCodeUNKNOWN;
+static int channelNumber = channelNumberUNKNOWN;
+static int channelSet = channelSetUNKNOWN;
+static int systemId = systemIdUNKNOWN;
+static int registrationMode = registrationModeUNKNOWN;
+static int txScrambled = 1;
+static int keyStart = 0;
+static int mdebug = 0;
+static int tx_delay_ms = 0;
+static int retries = 5;
+static int async = 1;
+static int tx_queue_len = 1;
+static int arlan_entry_debug = 0;
+static int arlan_exit_debug = 0;
+static int arlan_entry_and_exit_debug = 0;
+static int arlan_EEPROM_bad = 0;
+
+#if LINUX_VERSION_CODE > 0x20100
+MODULE_PARM(irq, "i");
+MODULE_PARM(mem, "i");
+MODULE_PARM(probe, "i");
+MODULE_PARM(arlan_debug, "i");
+MODULE_PARM(numDevices, "i");
+MODULE_PARM(testMemory, "i");
+MODULE_PARM(spreadingCode, "i");
+MODULE_PARM(channelNumber, "i");
+MODULE_PARM(channelSet, "i");
+MODULE_PARM(systemId, "i");
+MODULE_PARM(registrationMode, "i");
+MODULE_PARM(radioNodeId, "i");
+MODULE_PARM(SID, "i");
+MODULE_PARM(txScrambled, "i");
+MODULE_PARM(keyStart, "i");
+MODULE_PARM(mdebug, "i");
+MODULE_PARM(tx_delay_ms, "i");
+MODULE_PARM(retries, "i");
+MODULE_PARM(async, "i");
+MODULE_PARM(tx_queue_len, "i");
+MODULE_PARM(arlan_entry_debug, "i");
+MODULE_PARM(arlan_exit_debug, "i");
+MODULE_PARM(arlan_entry_and_exit_debug, "i");
+MODULE_PARM(arlan_EEPROM_bad, "i");
+
+EXPORT_SYMBOL(arlan_device);
+EXPORT_SYMBOL(last_arlan);
+
+
+//        #warning kernel 2.1.110 tested
+#define myATOMIC_INIT(a,b) atomic_set(&(a),b)
+#define __initfunctio(a)                __initfunc(a)
+
+#else
+#define test_and_set_bit       set_bit
+#define __initfunctio(a)        a
+#if LINUX_VERSION_CODE != 0x20024
+ //        #warning kernel  2.0.36  tested
+#endif
+#define myATOMIC_INIT(a,b) a = b;
+
+#endif
+
+struct arlan_conf_stru arlan_conf[MAX_ARLANS];
+int arlans_found = 0;
+
+static  int    arlan_probe_here(struct device *dev, int ioaddr);
+static  int    arlan_open(struct device *dev);
+static  int    arlan_tx(struct sk_buff *skb, struct device *dev);
+static  void   arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static  int    arlan_close(struct device *dev);
+static  struct enet_statistics *
+               arlan_statistics                (struct device *dev);
+static  void   arlan_set_multicast             (struct device *dev);
+static  int    arlan_hw_tx                     (struct device* dev, char *buf, int length );
+static  int    arlan_hw_config                 (struct device * dev);
+static  void   arlan_tx_done_interrupt         (struct device * dev, int status);
+static  void   arlan_rx_interrupt              (struct device * dev, u_char rxStatus, u_short, u_short);
+static  void   arlan_process_interrupt         (struct device * dev);
+static  int    arlan_command(struct device * dev, int command);
+
+EXPORT_SYMBOL(arlan_command);
+
+extern inline long long arlan_time(void)
+{
+       struct timeval timev;
+       do_gettimeofday(&timev);
+       return ((long long) timev.tv_sec * 1000000 + timev.tv_usec);
+};
+
+#ifdef ARLAN_ENTRY_EXIT_DEBUGING
+#define ARLAN_DEBUG_ENTRY(name) \
+       {\
+       struct timeval timev;\
+       do_gettimeofday(&timev);\
+               if (arlan_entry_debug || arlan_entry_and_exit_debug)\
+                       printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\
+       }
+#define ARLAN_DEBUG_EXIT(name) \
+       {\
+       struct timeval timev;\
+       do_gettimeofday(&timev);\
+               if (arlan_exit_debug || arlan_entry_and_exit_debug)\
+                       printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\
+       }
+#else
+#define ARLAN_DEBUG_ENTRY(name)
+#define ARLAN_DEBUG_EXIT(name)
+#endif
+
+
+#define arlan_interrupt_ack(dev)\
+        clearClearInterrupt(dev);\
+        setClearInterrupt(dev);
+
+
+#define ARLAN_COMMAND_LOCK(dev) \
+       if (atomic_dec_and_test(&((struct arlan_private * )dev->priv)->card_users))\
+               arlan_wait_command_complete_short(dev,__LINE__);
+#define ARLAN_COMMAND_UNLOCK(dev) \
+       atomic_inc(&((struct arlan_private * )dev->priv)->card_users);
+
+
+#define ARLAN_COMMAND_INC(dev) \
+       {((struct arlan_private *) dev->priv)->under_command++;}
+#define ARLAN_COMMAND_ZERO(dev) \
+       {((struct arlan_private *) dev->priv)->under_command =0;}
+#define ARLAN_UNDER_COMMAND(dev)\
+       (((struct arlan_private *) dev->priv)->under_command)
+
+#define ARLAN_COMMAND_START(dev) ARLAN_COMMAND_INC(dev)
+#define ARLAN_COMMAND_END(dev) ARLAN_COMMAND_ZERO(dev)
+#define ARLAN_TOGGLE_START(dev)\
+       {((struct arlan_private *) dev->priv)->under_toggle++;}
+#define ARLAN_TOGGLE_END(dev)\
+       {((struct arlan_private *) dev->priv)->under_toggle=0;}
+#define ARLAN_UNDER_TOGGLE(dev)\
+       (((struct arlan_private *) dev->priv)->under_toggle)
+
+
+
+extern inline int arlan_drop_tx(struct device *dev)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+       priv->stats.tx_errors++;
+       if (priv->Conf->tx_delay_ms)
+       {
+               priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1;
+       }
+       else
+       {
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_TX;
+               TXHEAD(dev).offset = 0;
+               TXTAIL(dev).offset = 0;
+               priv->txLast = 0;
+               priv->txOffset = 0;
+               priv->bad = 0;
+               if (!priv->under_reset && !priv->under_config)
+               {
+                       dev->tbusy = 0;
+                       mark_bh(NET_BH);
+               }
+       }
+       return 1;
+};
+
+
+static int arlan_command(struct device *dev, int command_p)
+{
+
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+       struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+       int udelayed = 0;
+       int i = 0;
+       long long time_mks = arlan_time();
+
+       ARLAN_DEBUG_ENTRY("arlan_command");
+
+       if (priv->card_polling_interval)
+               priv->card_polling_interval = 1;
+
+       if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
+               printk(KERN_DEBUG "arlan_command, %lx lock %x  commandByte %x waiting %x incoming %x \n",
+               jiffies, priv->command_lock, READSHMB(arlan->commandByte),
+                      priv->waiting_command_mask, command_p);
+
+       priv->waiting_command_mask |= command_p;
+
+       if (priv->waiting_command_mask & ARLAN_COMMAND_RESET)
+               if (jiffies - priv->lastReset < 5 * HZ)
+                       priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET;
+
+       if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK)
+       {
+               arlan_interrupt_ack(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK;
+       }
+       if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE)
+       {
+               setInterruptEnable(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE;
+       }
+
+       /* Card access serializing lock */
+
+       if (test_and_set_bit(0, (void *) &priv->command_lock))
+       {
+               if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
+                       printk(KERN_DEBUG "arlan_command: entered when command locked \n");
+               goto command_busy_end;
+       }
+       /* Check cards status and waiting */
+
+       if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW))
+       {
+               while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW))
+               {
+                       if (READSHMB(arlan->resetFlag) ||
+                               READSHMB(arlan->commandByte))   /* || 
+                                                                  (readControlRegister(dev) & ARLAN_ACCESS))
+                                                                */
+                               udelay(40);
+                       else
+                               priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW);
+
+                       udelayed++;
+
+                       if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW)
+                       {
+                               if (udelayed * 40 > 1000000)
+                               {
+                                       printk(KERN_ERR "%s long wait too long \n", dev->name);
+                                       priv->waiting_command_mask |= ARLAN_COMMAND_RESET;
+                                       break;
+                               }
+                       }
+                       else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW)
+                       {
+                               if (udelayed * 40 > 1000)
+                               {
+                                       printk(KERN_ERR "%s short wait too long \n", dev->name);
+                                       goto bad_end;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               i = 0;
+               while ((READSHMB(arlan->resetFlag) ||
+                       READSHMB(arlan->commandByte)) &&
+                       conf->pre_Command_Wait > (i++) * 10)
+                       udelay(10);
+
+
+               if ((READSHMB(arlan->resetFlag) ||
+                       READSHMB(arlan->commandByte)) &&
+                       !(priv->waiting_command_mask & ARLAN_COMMAND_RESET))
+               {
+                       goto card_busy_end;
+               }
+       }
+       if (priv->waiting_command_mask & ARLAN_COMMAND_RESET)
+       {
+               priv->under_reset = 1;
+               dev->start = 0;
+       }
+       if (priv->waiting_command_mask & ARLAN_COMMAND_CONF)
+       {
+               priv->under_config = 1;
+               dev->start = 0;
+       }
+
+       /* Issuing command */
+       arlan_lock_card_access(dev);
+       if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP)
+       {
+       //     if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER))
+               setPowerOn(dev);
+               arlan_interrupt_lancpu(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP;
+               priv->waiting_command_mask |= ARLAN_COMMAND_RESET;
+               priv->card_polling_interval = HZ / 10;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE)
+       {
+               WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE);
+               arlan_interrupt_lancpu(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE;
+               priv->card_polling_interval = HZ / 10;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT)
+       {
+               if (priv->rx_command_given)
+               {
+                       WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT);
+                       arlan_interrupt_lancpu(dev);
+                       priv->rx_command_given = 0;
+               }
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT;
+               priv->card_polling_interval = 1;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT)
+       {
+               if (priv->tx_command_given)
+               {
+                       WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT);
+                       arlan_interrupt_lancpu(dev);
+                       priv->tx_command_given = 0;
+               }
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT;
+               priv->card_polling_interval = 1;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET)
+       {
+               arlan_drop_tx(dev);
+               if (priv->tx_command_given || priv->rx_command_given)
+               {
+                       printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name);
+               };
+               if (arlan_debug & ARLAN_DEBUG_RESET)
+                       printk(KERN_ERR "%s: Doing chip reset\n", dev->name);
+               priv->lastReset = jiffies;
+               WRITESHM(arlan->commandByte, 0, u_char);
+               /* hold card in reset state */
+               setHardwareReset(dev);
+               /* set reset flag and then release reset */
+               WRITESHM(arlan->resetFlag, 0xff, u_char);
+               clearChannelAttention(dev);
+               clearHardwareReset(dev);
+               priv->numResets++;
+               priv->card_polling_interval = HZ / 4;
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET;
+               priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK;
+//             priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; 
+//             priv->waiting_command_mask |= ARLAN_COMMAND_RX;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK)
+       {
+               clearHardwareReset(dev);
+               clearClearInterrupt(dev);
+               setClearInterrupt(dev);
+               setInterruptEnable(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK;
+               priv->waiting_command_mask |= ARLAN_COMMAND_CONF;
+               priv->under_config = 1;
+               priv->under_reset = 0;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE)
+       {
+               setInterruptEnable(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF)
+       {
+               if (priv->tx_command_given || priv->rx_command_given)
+               {
+                       printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name);
+               }
+               dev->start = 0;
+               arlan_drop_tx(dev);
+               setInterruptEnable(dev);
+               arlan_hw_config(dev);
+               arlan_interrupt_lancpu(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF;
+               priv->card_polling_interval = HZ / 10;
+//             priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK;   
+//             priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; 
+               priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT)
+       {
+               if (READSHMB(arlan->configuredStatusFlag) != 0 &&
+                       READSHMB(arlan->diagnosticInfo) == 0xff)
+               {
+                       priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT;
+                       priv->waiting_command_mask |= ARLAN_COMMAND_RX;
+                       priv->card_polling_interval = HZ / 10;
+                       priv->tx_command_given = 0;
+                       priv->under_config = 0;
+                       if (dev->tbusy || !dev->start)
+                       {
+                               dev->tbusy = 0;
+                               dev->start = 1;
+                               mark_bh(NET_BH);
+                       };
+               }
+               else
+               {
+                       priv->card_polling_interval = 1;
+                       if (arlan_debug & ARLAN_DEBUG_TIMING)
+                               printk(KERN_ERR "configure delayed \n");
+               }
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_RX)
+       {
+               if (!registrationBad(dev))
+               {
+                       setInterruptEnable(dev);
+                       memset_io((void *) arlan->commandParameter, 0, 0xf);
+                       WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE);
+                       WRITESHMB(arlan->commandParameter[0], conf->rxParameter);
+                       arlan_interrupt_lancpu(dev);
+                       priv->rx_command_given;
+                       priv->last_rx_time = arlan_time();
+                       priv->waiting_command_mask &= ~ARLAN_COMMAND_RX;
+                       priv->card_polling_interval = 1;
+               }
+               else
+                       priv->card_polling_interval = 2;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_TX)
+       {
+               if (!test_and_set_bit(0, (void *) &priv->tx_command_given))
+               {
+                       if ((time_mks - priv->last_tx_time > conf->rx_tweak1) ||
+                               (time_mks - priv->last_rx_int_ack_time < conf->rx_tweak2))
+                       {
+                               setInterruptEnable(dev);
+                               memset_io((void *) arlan->commandParameter, 0, 0xf);
+                               WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT);
+                               memcpy_toio((void *) arlan->commandParameter, &TXLAST(dev), 14);
+//                             for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i]));
+                               priv->last_command_was_rx = 0;
+                               priv->tx_last_sent = jiffies;
+                               arlan_interrupt_lancpu(dev);
+                               priv->last_tx_time = arlan_time();
+                               priv->tx_command_given = 1;
+                               priv->waiting_command_mask &= ~ARLAN_COMMAND_TX;
+                               priv->card_polling_interval = 1;
+                       }
+                       else
+                       {
+                               priv->tx_command_given = 0;
+                               priv->card_polling_interval = 1;
+                       }
+               } 
+               else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
+                       printk(KERN_ERR "tx command when tx chain locked \n");
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT)
+       {
+               {
+                       WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT);
+               }
+               arlan_interrupt_lancpu(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT;
+               priv->card_polling_interval = HZ / 3;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP)
+       {
+               WRITESHMB(arlan->commandByte, ARLAN_COM_NOP);
+               arlan_interrupt_lancpu(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP;
+               priv->card_polling_interval = HZ / 3;
+       }
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL)
+       {
+               WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL);
+               arlan_interrupt_lancpu(dev);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL;
+               priv->card_polling_interval = HZ / 3;
+       } 
+       else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN)
+       {
+               setPowerOff(dev);
+               if (arlan_debug & ARLAN_DEBUG_CARD_STATE)
+                       printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name);
+               priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN;
+               priv->card_polling_interval = 3 * HZ;
+       }
+       arlan_unlock_card_access(dev);
+       for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++)
+               udelay(10);
+       if (READSHMB(arlan->commandByte))
+               if (arlan_debug & ARLAN_DEBUG_CARD_STATE)
+                       printk(KERN_ERR "card busy leaving command %x \n", priv->waiting_command_mask);
+
+       priv->command_lock = 0;
+       ARLAN_DEBUG_EXIT("arlan_command");
+       priv->last_command_buff_free_time = jiffies;
+       return 0;
+
+card_busy_end:
+       if (jiffies - priv->last_command_buff_free_time > HZ)
+               priv->waiting_command_mask |= ARLAN_COMMAND_CLEAN_AND_RESET;
+
+       if (arlan_debug & ARLAN_DEBUG_CARD_STATE)
+               printk(KERN_ERR "%s arlan_command card busy end \n", dev->name);
+       priv->command_lock = 0;
+       ARLAN_DEBUG_EXIT("arlan_command");
+       return 1;
+
+bad_end:
+       printk(KERN_ERR "%s arlan_command bad end \n", dev->name);
+
+       priv->command_lock = 0;
+       ARLAN_DEBUG_EXIT("arlan_command");
+
+       return -1;
+
+command_busy_end:
+       if (arlan_debug & ARLAN_DEBUG_CARD_STATE)
+               printk(KERN_ERR "%s arlan_command command busy end \n", dev->name);
+       ARLAN_DEBUG_EXIT("arlan_command");
+       return 2;
+
+};
+
+extern inline void arlan_command_process(struct device *dev)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+       int times = 0;
+       while (priv->waiting_command_mask && times < 8)
+       {
+               if (priv->waiting_command_mask)
+               {
+                       if (arlan_command(dev, 0))
+                               break;
+                       times++;
+               }
+               /* if long command, we wont repeat trying */ ;
+               if (priv->card_polling_interval > 1)
+                       break;
+               times++;
+       }
+}
+
+
+extern inline void arlan_retransmit_now(struct device *dev)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+
+       ARLAN_DEBUG_ENTRY("arlan_retransmit_now");
+       if (TXLAST(dev).offset == 0)
+       {
+               if (TXHEAD(dev).offset)
+               {
+                       priv->txLast = 0;
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to head \n");
+
+               }
+               else if (TXTAIL(dev).offset)
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to tail \n");
+                       priv->txLast = 1;
+               }
+               else
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "ReTransmit buff empty");
+               priv->txOffset = 0;
+               dev->tbusy = 0;
+               mark_bh(NET_BH);
+               return;
+
+       }
+       arlan_command(dev, ARLAN_COMMAND_TX);
+
+       priv->nof_tx++;
+
+       priv->Conf->driverRetransmissions++;
+       priv->retransmissions++;
+
+       IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("Retransmit %d bytes \n", TXLAST(dev).length);
+
+       ARLAN_DEBUG_EXIT("arlan_retransmit_now");
+}
+
+
+
+static void arlan_registration_timer(unsigned long data)
+{
+       struct device *dev = (struct device *) data;
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+
+       int lostTime = ((int) (jiffies - priv->registrationLastSeen)) * 1000 / HZ;
+       int bh_mark_needed = 0;
+       int next_tick = 1;
+
+
+       priv->timer_chain_active = 1;
+
+
+       if (registrationBad(dev))
+       {
+               //debug=100;
+               priv->registrationLostCount++;
+               if (lostTime > 7000 && lostTime < 7200)
+               {
+                       printk(KERN_NOTICE "%s registration Lost \n", dev->name);
+               }
+               if (lostTime / priv->reRegisterExp > 2000)
+                       arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF);
+               if (lostTime / (priv->reRegisterExp) > 3500)
+                       arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET);
+               if (priv->reRegisterExp < 400)
+                       priv->reRegisterExp += 2;
+               if (lostTime > 7200)
+               {
+                       next_tick = HZ;
+                       arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET);
+               }
+       }
+       else
+       {
+               if (priv->Conf->registrationMode && lostTime > 10000 &&
+                       priv->registrationLostCount)
+               {
+                       printk(KERN_NOTICE "%s registration is back after %d milliseconds\n", dev->name,
+                               ((int) (jiffies - priv->registrationLastSeen) * 1000) / HZ);
+               }
+               priv->registrationLastSeen = jiffies;
+               priv->registrationLostCount = 0;
+               priv->reRegisterExp = 1;
+               if (dev->start == 0)
+               {
+                       dev->start = 1;
+                       mark_bh(NET_BH);
+               }
+       }
+
+
+       if (!registrationBad(dev) && priv->ReTransmitRequested)
+       {
+               IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                       printk(KERN_ERR "Retranmit from timer \n");
+               priv->ReTransmitRequested = 0;
+               arlan_retransmit_now(dev);
+       }
+       if (!registrationBad(dev) &&
+               priv->tx_done_delayed < jiffies &&
+               priv->tx_done_delayed != 0)
+       {
+               TXLAST(dev).offset = 0;
+               if (priv->txLast)
+                       priv->txLast = 0;
+               else if (TXTAIL(dev).offset)
+                       priv->txLast = 1;
+               if (TXLAST(dev).offset)
+               {
+                       arlan_retransmit_now(dev);
+                       dev->trans_start = jiffies;
+               }
+               if (!(TXHEAD(dev).offset && TXTAIL(dev).offset))
+               {
+                       priv->txOffset = 0;
+                       dev->tbusy = 0;
+                       mark_bh(NET_BH);
+               }
+               priv->tx_done_delayed = 0;
+               bh_mark_needed = 1;
+       }
+       if (bh_mark_needed)
+       {
+               priv->txOffset = 0;
+               dev->tbusy = 0;
+               mark_bh(NET_BH);
+       }
+       arlan_process_interrupt(dev);
+
+       if (next_tick < priv->card_polling_interval)
+               next_tick = priv->card_polling_interval;
+
+       priv->timer_chain_active = 0;
+       priv->timer.expires = jiffies + next_tick;
+
+       add_timer(&priv->timer);
+}
+
+
+
+
+static void arlan_print_registers(struct device *dev, int line)
+{
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+       u_char hostcpuLock, lancpuLock, controlRegister, cntrlRegImage,
+               txStatus, rxStatus, interruptInProgress, commandByte;
+
+
+       ARLAN_DEBUG_ENTRY("arlan_print_registers");
+       READSHM(interruptInProgress, arlan->interruptInProgress, u_char);
+       READSHM(hostcpuLock, arlan->hostcpuLock, u_char);
+       READSHM(lancpuLock, arlan->lancpuLock, u_char);
+       READSHM(controlRegister, arlan->controlRegister, u_char);
+       READSHM(cntrlRegImage, arlan->cntrlRegImage, u_char);
+       READSHM(txStatus, arlan->txStatus, u_char);
+       READSHM(rxStatus, arlan->rxStatus, u_char);
+       READSHM(commandByte, arlan->commandByte, u_char);
+
+       printk(KERN_WARNING "line %04d IP %02x HL %02x LL %02x CB %02x CR %02x CRI %02x TX %02x RX %02x\n",
+               line, interruptInProgress, hostcpuLock, lancpuLock, commandByte,
+               controlRegister, cntrlRegImage, txStatus, rxStatus);
+
+       ARLAN_DEBUG_EXIT("arlan_print_registers");
+}
+
+
+static int arlan_hw_tx(struct device *dev, char *buf, int length)
+{
+       int i;
+
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+       volatile struct arlan_shmem *arlan = priv->card;
+       struct arlan_conf_stru *conf = priv->Conf;
+
+       int tailStarts = 0x800;
+       int headEnds = 0x0;
+
+
+       ARLAN_DEBUG_ENTRY("arlan_hw_tx");
+       if (TXHEAD(dev).offset)
+               headEnds = (((TXHEAD(dev).offset + TXHEAD(dev).length - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 1) * 64;
+       if (TXTAIL(dev).offset)
+               tailStarts = 0x800 - (((TXTAIL(dev).offset - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 2) * 64;
+
+
+       if (!TXHEAD(dev).offset && length < tailStarts)
+       {
+               IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                       printk(KERN_ERR "TXHEAD insert, tailStart %d\n", tailStarts);
+
+               TXHEAD(dev).offset =
+                       (((int) arlan->txBuffer) - ((int) arlan));
+               TXHEAD(dev).length = length - ARLAN_FAKE_HDR_LEN;
+               for (i = 0; i < 6; i++)
+                       TXHEAD(dev).dest[i] = buf[i];
+               TXHEAD(dev).clear = conf->txClear;
+               TXHEAD(dev).retries = conf->txRetries;  /* 0 is use default */
+               TXHEAD(dev).routing = conf->txRouting;
+               TXHEAD(dev).scrambled = conf->txScrambled;
+               memcpy_toio(((char *) arlan + TXHEAD(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXHEAD(dev).length);
+       }
+       else if (!TXTAIL(dev).offset && length < (0x800 - headEnds))
+       {
+               IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                       printk(KERN_ERR "TXTAIL insert, headEnd %d\n", headEnds);
+
+               TXTAIL(dev).offset =
+                       (((int) arlan->txBuffer) - ((int) arlan)) + 0x800 - (length / 64 + 2) * 64;
+               TXTAIL(dev).length = length - ARLAN_FAKE_HDR_LEN;
+               for (i = 0; i < 6; i++)
+                       TXTAIL(dev).dest[i] = buf[i];
+               TXTAIL(dev).clear = conf->txClear;
+               TXTAIL(dev).retries = conf->txRetries;
+               TXTAIL(dev).routing = conf->txRouting;
+               TXTAIL(dev).scrambled = conf->txScrambled;
+               memcpy_toio(((char *) arlan + TXTAIL(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXTAIL(dev).length);
+       }
+       else
+       {
+               dev->tbusy = 1;
+               return -1;
+               IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                       printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds);
+       }
+       priv->out_bytes += length;
+       priv->out_bytes10 += length;
+       if (conf->measure_rate < 1)
+               conf->measure_rate = 1;
+       if (jiffies - priv->out_time > conf->measure_rate * HZ)
+       {
+               conf->out_speed = priv->out_bytes / conf->measure_rate;
+               priv->out_bytes = 0;
+               priv->out_time = jiffies;
+       }
+       if (jiffies - priv->out_time10 > conf->measure_rate * HZ * 10)
+       {
+               conf->out_speed10 = priv->out_bytes10 / (10 * conf->measure_rate);
+               priv->out_bytes10 = 0;
+               priv->out_time10 = jiffies;
+       }
+       if (TXHEAD(dev).offset && TXTAIL(dev).offset)
+       {
+               dev->tbusy = 1;
+               return 0;
+       }
+       else
+               dev->tbusy = 0;
+
+
+       IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
+               printk(KERN_WARNING "%s Transmit t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name,
+                  (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3],
+                  (unsigned char) buf[4], (unsigned char) buf[5], (unsigned char) buf[6], (unsigned char) buf[7],
+                  (unsigned char) buf[8], (unsigned char) buf[9], (unsigned char) buf[10], (unsigned char) buf[11]);
+
+       IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "TX command prepare for buffer %d\n", priv->txLast);
+
+       arlan_command(dev, ARLAN_COMMAND_TX);
+
+       priv->last_command_was_rx = 0;
+       priv->tx_last_sent = jiffies;
+       priv->nof_tx++;
+
+       IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("%s TX Qued %d bytes \n", dev->name, length);
+
+       ARLAN_DEBUG_EXIT("arlan_hw_tx");
+
+       return 0;
+}
+
+
+static int arlan_hw_config(struct device *dev)
+{
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+       struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+
+       ARLAN_DEBUG_ENTRY("arlan_hw_config");
+
+       printk(KERN_NOTICE "%s arlan configure called \n", dev->name);
+       if (arlan_EEPROM_bad)
+               printk(KERN_NOTICE "arlan configure with eeprom bad option \n");
+
+
+       WRITESHM(arlan->spreadingCode, conf->spreadingCode, u_char);
+       WRITESHM(arlan->channelSet, conf->channelSet, u_char);
+
+       if (arlan_EEPROM_bad)
+               WRITESHM(arlan->defaultChannelSet, conf->channelSet, u_char);
+
+       WRITESHM(arlan->channelNumber, conf->channelNumber, u_char);
+
+       WRITESHM(arlan->scramblingDisable, conf->scramblingDisable, u_char);
+       WRITESHM(arlan->txAttenuation, conf->txAttenuation, u_char);
+
+       WRITESHM(arlan->systemId, conf->systemId, u_int);
+
+       WRITESHM(arlan->maxRetries, conf->maxRetries, u_char);
+       WRITESHM(arlan->receiveMode, conf->receiveMode, u_char);
+       WRITESHM(arlan->priority, conf->priority, u_char);
+       WRITESHM(arlan->rootOrRepeater, conf->rootOrRepeater, u_char);
+       WRITESHM(arlan->SID, conf->SID, u_int);
+
+       WRITESHM(arlan->registrationMode, conf->registrationMode, u_char);
+
+       WRITESHM(arlan->registrationFill, conf->registrationFill, u_char);
+       WRITESHM(arlan->localTalkAddress, conf->localTalkAddress, u_char);
+       WRITESHM(arlan->codeFormat, conf->codeFormat, u_char);
+       WRITESHM(arlan->numChannels, conf->numChannels, u_char);
+       WRITESHM(arlan->channel1, conf->channel1, u_char);
+       WRITESHM(arlan->channel2, conf->channel2, u_char);
+       WRITESHM(arlan->channel3, conf->channel3, u_char);
+       WRITESHM(arlan->channel4, conf->channel4, u_char);
+       WRITESHM(arlan->radioNodeId, conf->radioNodeId, u_short);
+       WRITESHM(arlan->SID, conf->SID, u_int);
+       WRITESHM(arlan->waitTime, conf->waitTime, u_short);
+       WRITESHM(arlan->lParameter, conf->lParameter, u_short);
+       memcpy_toio(&(arlan->_15), &(conf->_15), 3);
+       WRITESHM(arlan->_15, conf->_15, u_short);
+       WRITESHM(arlan->headerSize, conf->headerSize, u_short);
+       if (arlan_EEPROM_bad)
+               WRITESHM(arlan->hardwareType, conf->hardwareType, u_char);
+       WRITESHM(arlan->radioType, conf->radioType, u_char);
+       if (arlan_EEPROM_bad)
+               WRITESHM(arlan->radioModule, conf->radioType, u_char);
+
+       memcpy_toio(arlan->encryptionKey + keyStart, encryptionKey, 8);
+       memcpy_toio(arlan->name, conf->siteName, 16);
+
+       WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_CONF);  /* do configure */
+       memset_io(arlan->commandParameter, 0, 0xf);     /* 0xf */
+       memset_io(arlan->commandParameter + 1, 0, 2);
+       if (conf->writeEEPROM)
+       {
+                 memset_io(arlan->commandParameter, conf->writeEEPROM, 1);
+//             conf->writeEEPROM=0;
+       }
+       if (conf->registrationMode && conf->registrationInterrupts)
+               memset_io(arlan->commandParameter + 3, 1, 1);
+       else
+               memset_io(arlan->commandParameter + 3, 0, 1);
+
+       priv->irq_test_done = 0;
+
+       if (conf->tx_queue_len)
+               dev->tx_queue_len = conf->tx_queue_len;
+       udelay(100);
+
+       ARLAN_DEBUG_EXIT("arlan_hw_config");
+       return 0;
+}
+
+
+static int arlan_read_card_configuration(struct device *dev)
+{
+       u_char tlx415;
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+       struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+
+       ARLAN_DEBUG_ENTRY("arlan_read_card_configuration");
+
+       if (radioNodeId == radioNodeIdUNKNOWN)
+       {
+               READSHM(conf->radioNodeId, arlan->radioNodeId, u_short);
+       }
+       else
+               conf->radioNodeId = radioNodeId;
+               
+       if (SID == SIDUNKNOWN)
+       {
+               READSHM(conf->SID, arlan->SID, u_int);
+       }
+       else conf->SID = SID;
+               
+       if (spreadingCode == spreadingCodeUNKNOWN)
+       {
+                 READSHM(conf->spreadingCode, arlan->spreadingCode, u_char);
+       }
+       else
+               conf->spreadingCode = spreadingCode;
+               
+       if (channelSet == channelSetUNKNOWN)
+       {
+               READSHM(conf->channelSet, arlan->channelSet, u_char);
+       }
+       else conf->channelSet = channelSet;
+
+       if (channelNumber == channelNumberUNKNOWN)
+       {
+               READSHM(conf->channelNumber, arlan->channelNumber, u_char);
+       }
+       else conf->channelNumber = channelNumber;
+       
+       READSHM(conf->scramblingDisable, arlan->scramblingDisable, u_char);
+       READSHM(conf->txAttenuation, arlan->txAttenuation, u_char);
+       
+       if (systemId == systemIdUNKNOWN)
+       {
+               READSHM(conf->systemId, arlan->systemId, u_int);
+       } 
+       else conf->systemId = systemId;
+       
+       READSHM(conf->maxDatagramSize, arlan->maxDatagramSize, u_short);
+       READSHM(conf->maxFrameSize, arlan->maxFrameSize, u_short);
+       READSHM(conf->maxRetries, arlan->maxRetries, u_char);
+       READSHM(conf->receiveMode, arlan->receiveMode, u_char);
+       READSHM(conf->priority, arlan->priority, u_char);
+       READSHM(conf->rootOrRepeater, arlan->rootOrRepeater, u_char);
+
+       if (SID == SIDUNKNOWN)
+       {
+                 READSHM(conf->SID, arlan->SID, u_int);
+       }
+       else conf->SID = SID;
+       
+       if (registrationMode == registrationModeUNKNOWN)
+       {
+                 READSHM(conf->registrationMode, arlan->registrationMode, u_char);
+       }
+       else conf->registrationMode = registrationMode;
+       
+       READSHM(conf->registrationFill, arlan->registrationFill, u_char);
+       READSHM(conf->localTalkAddress, arlan->localTalkAddress, u_char);
+       READSHM(conf->codeFormat, arlan->codeFormat, u_char);
+       READSHM(conf->numChannels, arlan->numChannels, u_char);
+       READSHM(conf->channel1, arlan->channel1, u_char);
+       READSHM(conf->channel2, arlan->channel2, u_char);
+       READSHM(conf->channel3, arlan->channel3, u_char);
+       READSHM(conf->channel4, arlan->channel4, u_char);
+       READSHM(conf->waitTime, arlan->waitTime, u_short);
+       READSHM(conf->lParameter, arlan->lParameter, u_short);
+       READSHM(conf->_15, arlan->_15, u_short);
+       READSHM(conf->headerSize, arlan->headerSize, u_short);
+       READSHM(conf->hardwareType, arlan->hardwareType, u_char);
+       READSHM(conf->radioType, arlan->radioModule, u_char);
+       
+       if (conf->radioType == 0)
+               conf->radioType = 0xc;
+
+       WRITESHM(arlan->configStatus, 0xA5, u_char);
+       READSHM(tlx415, arlan->configStatus, u_char);
+       
+       if (tlx415 != 0xA5)
+               printk(KERN_INFO "%s tlx415 chip \n", dev->name);
+       
+       conf->txClear = 0;
+       conf->txRetries = 1;
+       conf->txRouting = 1;
+       conf->txScrambled = 0;
+       conf->rxParameter = 1;
+       conf->txTimeoutMs = 4000;
+       conf->waitCardTimeout = 100000;
+       conf->receiveMode = ARLAN_RCV_CLEAN;
+       memcpy_fromio(conf->siteName, arlan->name, 16);
+       conf->siteName[16] = '\0';
+       conf->retries = retries;
+       conf->tx_delay_ms = tx_delay_ms;
+       conf->async = async;
+       conf->ReTransmitPacketMaxSize = 200;
+       conf->waitReTransmitPacketMaxSize = 200;
+       conf->txAckTimeoutMs = 900;
+       conf->fastReTransCount = 3;
+
+       ARLAN_DEBUG_EXIT("arlan_read_card_configuration");
+
+       return 0;
+}
+
+
+static int lastFoundAt = 0xbe000;
+
+
+/*
+ * 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.
+ */
+
+__initfunctio(static int arlan_check_fingerprint(int memaddr))
+{
+       static char probeText[] = "TELESYSTEM SLW INC.    ARLAN \0";
+       char tempBuf[49];
+       volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr;
+
+       ARLAN_DEBUG_ENTRY("arlan_check_fingerprint");
+       memcpy_fromio(tempBuf, arlan->textRegion, 29);
+       tempBuf[30] = 0;
+
+       /* check for card at this address */
+       if (0 != strncmp(tempBuf, probeText, 29))
+               return -ENODEV;
+
+//   printk(KERN_INFO "arlan found at 0x%x \n",memaddr);
+       ARLAN_DEBUG_EXIT("arlan_check_fingerprint");
+
+       return 0;
+
+
+}
+
+__initfunctio(int arlan_probe_everywhere(struct device *dev))
+{
+       int m;
+       int probed = 0;
+       int found = 0;
+
+       ARLAN_DEBUG_ENTRY("arlan_probe_everywhere");
+       if (mem != 0 && numDevices == 1)        /* Check a single specified location. */
+       {
+               if (arlan_probe_here(dev, mem) == 0)
+                       return 0;
+               else
+                       return -ENODEV;
+       }
+       for (m = lastFoundAt + 0x2000; m <= 0xDE000; m += 0x2000)
+       {
+               if (arlan_probe_here(dev, m) == 0)
+               {
+                       found++;
+                       lastFoundAt = m;
+                       break;
+               }
+               probed++;
+       }
+       if (found == 0 && probed != 0)
+       {
+               if (lastFoundAt == 0xbe000)
+                       printk(KERN_ERR "arlan: No Arlan devices found \n");
+               return ENODEV;
+       }
+       else
+               return 0;
+
+       ARLAN_DEBUG_EXIT("arlan_probe_everywhere");
+
+       return ENODEV;
+}
+
+__initfunctio(int arlan_find_devices(void))
+{
+       int m;
+       int found = 0;
+
+       ARLAN_DEBUG_ENTRY("arlan_find_devices");
+       if (mem != 0 && numDevices == 1)        /* Check a single specified location. */
+               return 1;
+       for (m = 0xc000; m <= 0xDE000; m += 0x2000)
+       {
+               if (arlan_check_fingerprint(m) == 0)
+                       found++;
+       }
+       ARLAN_DEBUG_EXIT("arlan_find_devices");
+
+       return found;
+}
+
+
+static int arlan_change_mtu(struct device *dev, int new_mtu)
+{
+       struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+
+       ARLAN_DEBUG_ENTRY("arlan_change_mtu");
+       if ((new_mtu < 68) || (new_mtu > 2032))
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       if (new_mtu < 256)
+               new_mtu = 256;  /* cards book suggests 1600 */
+       conf->maxDatagramSize = new_mtu;
+       conf->maxFrameSize = new_mtu + 48;
+
+       arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF);
+       printk(KERN_NOTICE "%s mtu changed to %d \n", dev->name, new_mtu);
+
+       ARLAN_DEBUG_EXIT("arlan_change_mtu");
+
+       return 0;
+}
+
+static int arlan_mac_addr(struct device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+
+
+       ARLAN_DEBUG_ENTRY("arlan_mac_addr");
+       return -EINVAL;
+
+       if (dev->start)
+               return -EBUSY;
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       ARLAN_DEBUG_EXIT("arlan_mac_addr");
+       return 0;
+}
+
+
+
+
+__initfunctio(static int
+             arlan_allocate_device(int num, struct device *devs))
+{
+
+       struct device *dev;
+
+       ARLAN_DEBUG_ENTRY("arlan_allocate_device");
+
+       if (!devs)
+               dev = init_etherdev(0, sizeof(struct arlan_private));
+       else
+       {
+               dev = devs;
+               dev->priv = kmalloc(sizeof(struct arlan_private), GFP_KERNEL);
+       };
+
+       if (dev == NULL || dev->priv == NULL)
+       {
+               printk(KERN_CRIT "init_etherdev failed ");
+               return 0;
+       }
+       ((struct arlan_private *) dev->priv)->conf =
+           kmalloc(sizeof(struct arlan_shmem), GFP_KERNEL);
+
+       if (dev == NULL || dev->priv == NULL ||
+           ((struct arlan_private *) dev->priv)->conf == NULL)
+       {
+               return 0;
+               printk(KERN_CRIT " No memory at arlan_allocate_device \n");
+       }
+       /* Fill in the 'dev' fields. */
+       dev->base_addr = 0;
+       dev->mem_start = 0;
+       dev->mem_end = 0;
+       dev->mtu = 1500;
+       dev->flags = 0;         /* IFF_BROADCAST & IFF_MULTICAST & IFF_PROMISC; */
+       dev->irq = 0;
+       dev->dma = 0;
+       dev->tx_queue_len = tx_queue_len;
+       ether_setup(dev);
+       dev->tx_queue_len = tx_queue_len;
+       dev->open = arlan_open;
+       dev->stop = arlan_close;
+       dev->hard_start_xmit = arlan_tx;
+       dev->get_stats = arlan_statistics;
+       dev->set_multicast_list = arlan_set_multicast;
+       dev->change_mtu = arlan_change_mtu;
+       dev->set_mac_address = arlan_mac_addr;
+       ((struct arlan_private *) dev->priv)->irq_test_done = 0;
+       arlan_device[num] = dev;
+       ((struct arlan_private *) arlan_device[num]->priv)->Conf = &(arlan_conf[num]);
+
+       ((struct arlan_private *) dev->priv)->Conf->pre_Command_Wait = 40;
+       ((struct arlan_private *) dev->priv)->Conf->rx_tweak1 = 30;
+       ((struct arlan_private *) dev->priv)->Conf->rx_tweak2 = 0;
+
+       ARLAN_DEBUG_EXIT("arlan_allocate_device");
+       return (int) dev;
+}
+
+
+__initfunctio(int arlan_probe_here(struct device *dev, int memaddr))
+{
+       volatile struct arlan_shmem *arlan;
+
+       ARLAN_DEBUG_ENTRY("arlan_probe_here");
+
+       if (arlan_check_fingerprint(memaddr))
+               return -ENODEV;
+
+       printk(KERN_NOTICE "%s: Arlan found at %#5x, \n ", dev->name, memaddr);
+
+       if (!arlan_allocate_device(arlans_found, dev))
+               return -1;
+
+       ((struct arlan_private *) dev->priv)->card = (struct arlan_shmem *) memaddr;
+       arlan = (void *) memaddr;
+
+       dev->mem_start = memaddr;
+       dev->mem_end = memaddr + 0x1FFF;
+
+       if (dev->irq < 2)
+       {
+               READSHM(dev->irq, arlan->irqLevel, u_char);
+       } else if (dev->irq == 2)
+               dev->irq = 9;
+
+       arlan_read_card_configuration(dev);
+
+       ARLAN_DEBUG_EXIT("arlan_probe_here");
+       return 0;
+}
+
+
+
+
+static int arlan_open(struct device *dev)
+{
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+       volatile struct arlan_shmem *arlan = priv->card;
+       int ret = 0;
+
+       ARLAN_DEBUG_ENTRY("arlan_open");
+
+       if (dev->mem_start == 0)
+               ret = arlan_probe_everywhere(dev);
+       if (ret != 0)
+               return ret;
+
+       arlan = ((struct arlan_private *) dev->priv)->card;
+
+       if (request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev))
+       {
+               printk(KERN_ERR "%s: unable to get IRQ %d .\n",
+                       dev->name, dev->irq);
+               return -EAGAIN;
+       }
+       arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW);
+
+       priv->bad = 0;
+       priv->lastReset = 0;
+       priv->reset = 0;
+       priv->open_time = jiffies;
+       memcpy_fromio(dev->dev_addr, arlan->lanCardNodeId, 6);
+       memset(dev->broadcast, 0xff, 6);
+       dev->tbusy = 1;
+       priv->txOffset = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+       dev->tx_queue_len = tx_queue_len;
+       init_timer(&priv->timer);
+       priv->timer.expires = jiffies + HZ / 10;
+       priv->timer.data = (unsigned long) dev;
+       priv->timer.function = &arlan_registration_timer;       /* timer handler */
+       priv->interrupt_processing_active = 0;
+       priv->command_lock = 0;
+       add_timer(&priv->timer);
+
+       init_mutex(&priv->card_lock);
+       myATOMIC_INIT(priv->card_users, 1);     /* damn 2.0.33 */
+       priv->registrationLostCount = 0;
+       priv->registrationLastSeen = jiffies;
+       priv->txLast = 0;
+       priv->tx_command_given = 0;
+
+       priv->reRegisterExp = 1;
+       priv->nof_tx = 0;
+       priv->nof_tx_ack = 0;
+       priv->last_command_was_rx = 0;
+       priv->tx_last_sent = jiffies - 1;
+       priv->tx_last_cleared = jiffies;
+       priv->Conf->writeEEPROM = 0;
+       priv->Conf->registrationInterrupts = 1;
+
+       dev->tbusy = 0;
+
+       MOD_INC_USE_COUNT;
+#ifdef CONFIG_PROC_FS
+#ifndef MODULE
+       if (arlan_device[0])
+               init_arlan_proc();
+#endif
+#endif
+       ARLAN_DEBUG_EXIT("arlan_open");
+       return 0;
+}
+
+
+
+
+static int arlan_tx(struct sk_buff *skb, struct device *dev)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+       struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+
+       ARLAN_DEBUG_ENTRY("arlan_tx");
+
+       if (dev->tbusy)
+       {
+               /*
+                * If we get here, some higher level has decided we are broken.
+                * There should really be a "kick me" function call instead.
+                */
+               int tickssofar = jiffies - dev->trans_start;
+
+               if (((tickssofar * 1000) / HZ) * 2 > conf->txTimeoutMs)
+                       arlan_command(dev, ARLAN_COMMAND_TX_ABORT);
+
+               if (((tickssofar * 1000) / HZ) < conf->txTimeoutMs)
+               {
+                       // up(&priv->card_lock);
+                       goto bad_end;
+               }
+               printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name);
+               /* Try to restart the adaptor. */
+               arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET);
+               dev->trans_start = jiffies;
+               goto bad_end;
+
+       }
+       /*
+        * Block a timer-based transmit from overlapping. This could better be
+        * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+        */
+       if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
+       {
+               printk(KERN_ERR "%s: Transmitter access conflict.\n",
+                       dev->name);
+       }
+       else
+       {
+               short length;
+               unsigned char *buf;
+               
+               /*
+                * If some higher layer thinks we've missed an tx-done interrupt
+                * we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+                * itself.
+                */
+
+               length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+               buf = skb->data;
+
+               if (priv->txOffset + length + 0x12 > 0x800)
+                       printk(KERN_ERR "TX RING overflow \n");
+
+               if (arlan_hw_tx(dev, buf, length) == -1)
+                       goto bad_end;
+
+               dev->trans_start = jiffies;
+       }
+       dev_kfree_skb(skb);
+
+       arlan_process_interrupt(dev);
+       priv->tx_chain_active = 0;
+       ARLAN_DEBUG_EXIT("arlan_tx");
+       return 0;
+
+bad_end:
+       arlan_process_interrupt(dev);
+       priv->tx_chain_active = 0;
+       ARLAN_DEBUG_EXIT("arlan_tx");
+       return 1;
+}
+
+
+extern inline int DoNotReTransmitCrap(struct device *dev)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+       if (TXLAST(dev).length < priv->Conf->ReTransmitPacketMaxSize)
+               return 1;
+       return 0;
+
+}
+
+extern inline int DoNotWaitReTransmitCrap(struct device *dev)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+       if (TXLAST(dev).length < priv->Conf->waitReTransmitPacketMaxSize)
+               return 1;
+       return 0;
+}
+
+extern inline void arlan_queue_retransmit(struct device *dev)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+       ARLAN_DEBUG_ENTRY("arlan_queue_retransmit");
+
+       if (DoNotWaitReTransmitCrap(dev))
+       {
+                 arlan_drop_tx(dev);
+       } else
+               priv->ReTransmitRequested++;
+
+       ARLAN_DEBUG_EXIT("arlan_queue_retransmit");
+};
+
+extern inline void RetryOrFail(struct device *dev)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+       ARLAN_DEBUG_ENTRY("RetryOrFail");
+
+       if (priv->retransmissions > priv->Conf->retries ||
+           DoNotReTransmitCrap(dev))
+       {
+               arlan_drop_tx(dev);
+       }
+       else if (priv->bad <= priv->Conf->fastReTransCount)
+       {
+               arlan_retransmit_now(dev);
+       }
+       else arlan_queue_retransmit(dev);
+
+       ARLAN_DEBUG_EXIT("RetryOrFail");
+}
+
+
+static void arlan_tx_done_interrupt(struct device *dev, int status)
+{
+       struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+       ARLAN_DEBUG_ENTRY("arlan_tx_done_interrupt");
+
+       priv->tx_last_cleared = jiffies;
+       priv->tx_command_given = 0;
+       priv->nof_tx_ack++;
+       switch (status)
+       {
+               case 1:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                               printk("arlan intr: transmit OK\n");
+                       priv->stats.tx_packets++;
+                       priv->bad = 0;
+                       priv->reset = 0;
+                       priv->retransmissions = 0;
+                       if (priv->Conf->tx_delay_ms)
+                       {
+                               priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1;;
+                       }
+                       else
+                       {
+                               TXLAST(dev).offset = 0;
+                               if (priv->txLast)
+                                       priv->txLast = 0;
+                               else if (TXTAIL(dev).offset)
+                                       priv->txLast = 1;
+                               if (TXLAST(dev).offset)
+                               {
+                                       arlan_retransmit_now(dev);
+                                       dev->trans_start = jiffies;
+                               }
+                               if (!TXHEAD(dev).offset || !TXTAIL(dev).offset)
+                               {
+                                       priv->txOffset = 0;
+                                       dev->tbusy = 0;
+                                       mark_bh(NET_BH);
+                               }
+                       }
+               }
+               break;
+               
+               case 2:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                               printk("arlan intr: transmit timed out\n");
+                       priv->bad += 1;
+                       //arlan_queue_retransmit(dev);
+                       RetryOrFail(dev);
+               }
+               break;
+
+               case 3:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                               printk("arlan intr: transmit max retries\n");
+                       priv->bad += 1;
+                       priv->reset = 0;
+                       //arlan_queue_retransmit(dev);
+                       RetryOrFail(dev);
+               }
+               break;
+               
+               case 4:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                               printk("arlan intr: transmit aborted\n");
+                       priv->bad += 1;
+                       arlan_queue_retransmit(dev);
+                       //RetryOrFail(dev);
+               }
+               break;
+
+               case 5:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                               printk("arlan intr: transmit not registered\n");
+                       priv->bad += 1;
+                       //debug=101;
+                       arlan_queue_retransmit(dev);
+               }
+               break;
+
+               case 6:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN) 
+                               printk("arlan intr: transmit destination full\n");
+                       priv->bad += 1;
+                       priv->reset = 0;
+                       //arlan_drop_tx(dev);
+                       arlan_queue_retransmit(dev);
+               }
+               break;
+
+               case 7:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                               printk("arlan intr: transmit unknown ack\n");
+                       priv->bad += 1;
+                       priv->reset = 0;
+                       arlan_queue_retransmit(dev);
+               }
+               break;
+               
+               case 8:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                               printk("arlan intr: transmit dest mail box full\n");
+                       priv->bad += 1;
+                       priv->reset = 0;
+                       //arlan_drop_tx(dev);
+                       arlan_queue_retransmit(dev);
+               }
+               break;
+
+               case 9:
+               {
+                       IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+                               printk("arlan intr: transmit root dest not reg.\n");
+                       priv->bad += 1;
+                       priv->reset = 1;
+                       //arlan_drop_tx(dev);
+                       arlan_queue_retransmit(dev);
+               }
+               break;
+
+               default:
+               {
+                       printk(KERN_ERR "arlan intr: transmit status unknown\n");
+                       priv->bad += 1;
+                       priv->reset = 1;
+                       arlan_drop_tx(dev);
+               }
+       }
+
+       ARLAN_DEBUG_EXIT("arlan_tx_done_interrupt");
+}
+
+
+static void arlan_rx_interrupt(struct device *dev, u_char rxStatus, u_short rxOffset, u_short pkt_len)
+{
+       char *skbtmp;
+       int i = 0;
+
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+       volatile struct arlan_shmem *arlan = priv->card;
+       struct arlan_conf_stru *conf = priv->Conf;
+
+
+       ARLAN_DEBUG_ENTRY("arlan_rx_interrupt");
+       // by spec,   not                WRITESHMB(arlan->rxStatus,0x00);
+       // prohibited here              arlan_command(dev, ARLAN_COMMAND_RX);
+
+       if (pkt_len < 10 || pkt_len > 2048)
+       {
+               printk(KERN_WARNING "%s: got too short or long packet, len %d \n", dev->name, pkt_len);
+               return;
+       }
+       if (rxOffset + pkt_len > 0x2000)
+       {
+               printk("%s: got too long packet, len %d offset %x\n", dev->name, pkt_len, rxOffset);
+               return;
+       }
+       priv->in_bytes += pkt_len;
+       priv->in_bytes10 += pkt_len;
+       if (conf->measure_rate < 1)
+               conf->measure_rate = 1;
+       if (jiffies - priv->in_time > conf->measure_rate * HZ)
+       {
+               conf->in_speed = priv->in_bytes / conf->measure_rate;
+               priv->in_bytes = 0;
+               priv->in_time = jiffies;
+       }
+       if (jiffies - priv->in_time10 > conf->measure_rate * HZ * 10)
+       {
+               conf->in_speed10 = priv->in_bytes10 / (10 * conf->measure_rate);
+               priv->in_bytes10 = 0;
+               priv->in_time10 = jiffies;
+       }
+       DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char);
+       switch (rxStatus)
+       {
+               case 1:
+               case 2:
+               case 3:
+               {
+                       /* Malloc up new buffer. */
+                       struct sk_buff *skb;
+
+                       DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short);
+                       DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char);
+                       DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char);
+
+                       /* here we do multicast filtering to avoid slow 8-bit memcopy */
+#ifdef ARLAN_MULTICAST
+                       if (!(dev->flags & IFF_ALLMULTI) &&
+                               !(dev->flags & IFF_PROMISC) &&
+                               dev->mc_list)
+                       {
+                               char hw_dst_addr[6];
+                               struct dev_mc_list *dmi = dev->mc_list;
+                               int i;
+
+                               memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6);
+                               if (hw_dst_addr[0] == 0x01)
+                               {
+                                       if (mdebug)
+                                               if (hw_dst_addr[1] == 0x00)
+                                                       printk(KERN_ERR "%s mcast 0x0100 \n", dev->name);
+                                               else if (hw_dst_addr[1] == 0x40)
+                                                       printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name);
+                                       while (dmi)
+                                       {                                                       if (dmi->dmi_addrlen == 6)
+                                               {
+                                                       if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
+                                                               printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name,
+                                                                                dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
+                                                                                dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+                                                       for (i = 0; i < 6; i++)
+                                                               if (dmi->dmi_addr[i] != hw_dst_addr[i])
+                                                                       break;
+                                                       if (i == 6)
+                                                               break;
+                                               }
+                                               else
+                                                       printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name);
+                                               dmi = dmi->next;
+                                       }
+                                       /* we reach here if multicast filtering is on and packet 
+                                        * is multicast and not for receive */
+                                       goto end_of_interupt;
+                               }
+                       }
+#endif                         // ARLAN_MULTICAST
+                       /* multicast filtering ends here */
+                       pkt_len += ARLAN_FAKE_HDR_LEN;
+
+                       skb = dev_alloc_skb(pkt_len + 4);
+                       if (skb == NULL)
+                       {
+                               printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
+                               priv->stats.rx_dropped++;
+                               break;
+                       }
+                       skb_reserve(skb, 2);
+                       skb->dev = dev;
+                       skbtmp = skb_put(skb, pkt_len);
+
+                       memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN);
+                       memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6);
+                       memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6);
+                       WRITESHMB(arlan->rxStatus, 0x00);
+                       arlan_command(dev, ARLAN_COMMAND_RX);
+
+                       IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
+                       {
+                               char immedDestAddress[6];
+                               char immedSrcAddress[6];
+                               memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
+                               memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
+
+                               printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name,
+                                       (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3],
+                                       (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7],
+                                       (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11],
+                                       immedDestAddress[0], immedDestAddress[1], immedDestAddress[2],
+                                       immedDestAddress[3], immedDestAddress[4], immedDestAddress[5],
+                                       immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2],
+                                       immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]);
+                       }
+                       skb->protocol = eth_type_trans(skb, dev);
+                       IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
+                               if (skb->protocol != 0x608 && skb->protocol != 0x8)
+                               {
+                                       for (i = 0; i <= 22; i++)
+                                               printk("%02x:", (u_char) skbtmp[i + 12]);
+                                       printk(KERN_ERR "\n");
+                                       printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol);
+                               }
+                       netif_rx(skb);
+                       priv->stats.rx_packets++;
+               }
+               break;
+               
+               default:
+                       printk(KERN_ERR "arlan intr: recieved unknown status\n");
+                       priv->stats.rx_crc_errors++;
+                       break;
+       }
+       ARLAN_DEBUG_EXIT("arlan_rx_interrupt");
+}
+
+static void arlan_process_interrupt(struct device *dev)
+{
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+       volatile struct arlan_shmem *arlan = priv->card;
+       u_char rxStatus = READSHMB(arlan->rxStatus);
+       u_char txStatus = READSHMB(arlan->txStatus);
+       u_short rxOffset = READSHMS(arlan->rxOffset);
+       u_short pkt_len = READSHMS(arlan->rxLength);
+       int interrupt_count = 0;
+
+       ARLAN_DEBUG_ENTRY("arlan_process_interrupt");
+
+       if (test_and_set_bit(0, (void *) &priv->interrupt_processing_active))
+       {
+               if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
+                       printk(KERN_ERR "interrupt chain reentering \n");
+               goto end_int_process;
+       }
+       while ((rxStatus || txStatus || priv->interrupt_ack_requested)
+                       && (interrupt_count < 5))
+       {
+               if (rxStatus)
+                       priv->last_rx_int_ack_time = arlan_time();
+
+               arlan_command(dev, ARLAN_COMMAND_INT_ACK);
+               arlan_command(dev, ARLAN_COMMAND_INT_ENABLE);
+               
+               IFDEBUG(ARLAN_DEBUG_INTERRUPT)
+                       printk(KERN_ERR "%s:  got IRQ rx %x tx %x comm %x rxOff %x rxLen %x \n",
+                                       dev->name, rxStatus, txStatus, READSHMB(arlan->commandByte),
+                                       rxOffset, pkt_len);
+
+               if (rxStatus == 0 && txStatus == 0)
+               {
+                       priv->last_command_was_rx = 0;
+                       if (priv->irq_test_done)
+                       {
+                               if (!registrationBad(dev))
+                                       IFDEBUG(ARLAN_DEBUG_INTERRUPT) printk(KERN_ERR "%s unknown interrupt(nop? regLost ?) reason tx %d rx %d ",
+                                                                                   dev->name, txStatus, rxStatus);
+                       } else {
+                               IFDEBUG(ARLAN_DEBUG_INTERRUPT)
+                                       printk(KERN_INFO "%s irq $%d test OK \n", dev->name, dev->irq);
+
+                       }
+                       priv->interrupt_ack_requested = 0;
+                       goto ends;
+               }
+               if (txStatus != 0)
+               {
+                       WRITESHMB(arlan->txStatus, 0x00);
+                       arlan_tx_done_interrupt(dev, txStatus);
+                       goto ends;
+               }
+               if (rxStatus == 1 || rxStatus == 2)
+               {               /* a packet waiting */
+                       arlan_rx_interrupt(dev, rxStatus, rxOffset, pkt_len);
+                       goto ends;
+               }
+               if (rxStatus > 2 && rxStatus < 0xff)
+               {
+                       priv->last_command_was_rx = 0;
+                       WRITESHMB(arlan->rxStatus, 0x00);
+                       printk(KERN_ERR "%s unknown rxStatus reason tx %d rx %d ",
+                               dev->name, txStatus, rxStatus);
+                       goto ends;
+               }
+               if (rxStatus == 0xff)
+               {
+                       priv->last_command_was_rx = 0;
+                       WRITESHMB(arlan->rxStatus, 0x00);
+                       arlan_command(dev, ARLAN_COMMAND_RX);
+                       if (registrationBad(dev))
+                               dev->start = 0;
+                       if (!registrationBad(dev))
+                       {
+                               priv->registrationLastSeen = jiffies;
+                               if (!dev->tbusy && !priv->under_reset && !priv->under_config)
+                               {
+                                       mark_bh(NET_BH);
+                                       dev->start = 1;
+                               }
+                       }
+                       goto ends;
+               }
+ends:
+
+               arlan_command_process(dev);
+
+               rxStatus = READSHMB(arlan->rxStatus);
+               txStatus = READSHMB(arlan->txStatus);
+               rxOffset = READSHMS(arlan->rxOffset);
+               pkt_len = READSHMS(arlan->rxLength);
+
+
+               priv->irq_test_done = 1;
+
+               interrupt_count++;
+       }
+       priv->interrupt_processing_active = 0;
+
+end_int_process:
+       arlan_command_process(dev);
+
+       ARLAN_DEBUG_EXIT("arlan_process_interrupt");
+       return;
+}
+
+static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct device *dev = dev_id;
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+       volatile struct arlan_shmem *arlan = priv->card;
+       u_char rxStatus = READSHMB(arlan->rxStatus);
+       u_char txStatus = READSHMB(arlan->txStatus);
+
+       ARLAN_DEBUG_ENTRY("arlan_interrupt");
+
+
+       if (!rxStatus && !txStatus)
+               priv->interrupt_ack_requested++;
+       dev->interrupt++;
+
+       arlan_process_interrupt(dev);
+       
+       priv->irq_test_done = 1;
+       dev->interrupt--;
+
+       ARLAN_DEBUG_EXIT("arlan_interrupt");
+       return;
+
+}
+
+
+static int arlan_close(struct device *dev)
+{
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+
+       if (!dev)
+       {
+               printk(KERN_CRIT "arlan: No Device\n");
+               return 0;
+       }
+       priv = (struct arlan_private *) dev->priv;
+       if (!priv)
+       {
+               printk(KERN_CRIT "arlan: No Device priv \n");
+               return 0;
+       }
+       ARLAN_DEBUG_ENTRY("arlan_close");
+
+       IFDEBUG(ARLAN_DEBUG_STARTUP)
+               printk(KERN_NOTICE "%s: Closing device\n", dev->name);
+
+       priv->open_time = 0;
+       dev->tbusy = 1;
+       dev->start = 0;
+       del_timer(&priv->timer);
+       free_irq(dev->irq, dev);
+
+       MOD_DEC_USE_COUNT;
+
+       ARLAN_DEBUG_EXIT("arlan_close");
+       return 0;
+}
+
+
+static long alignLong(volatile u_char * ptr)
+{
+       long ret;
+       memcpy_fromio(&ret, (void *) ptr, 4);
+       return ret;
+}
+
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+
+static struct enet_statistics *arlan_statistics(struct device *dev)
+{
+       struct arlan_private *priv = (struct arlan_private *) dev->priv;
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+
+       ARLAN_DEBUG_ENTRY("arlan_statistics");
+
+       /* Update the statistics from the device registers. */
+
+       READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int);
+       READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int);
+       READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int);
+       READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int);
+       READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int);
+       READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int);
+       READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int);
+       READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int);
+       READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int);
+       READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int);
+       READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int);
+       READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int);
+       READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int);
+
+       ARLAN_DEBUG_EXIT("arlan_statistics");
+
+       return &priv->stats;
+}
+
+
+static void arlan_set_multicast(struct device *dev)
+{
+       volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+       struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+       int board_conf_needed = 0;
+
+
+       ARLAN_DEBUG_ENTRY("arlan_set_multicast");
+
+       if (dev->flags & IFF_PROMISC)
+       {
+               unsigned char recMode;
+               READSHM(recMode, arlan->receiveMode, u_char);
+               conf->receiveMode = (ARLAN_RCV_PROMISC | ARLAN_RCV_CONTROL);
+               if (conf->receiveMode != recMode)
+                       board_conf_needed = 1;
+       }
+       else
+       {
+               /* turn off promiscuous mode  */
+               unsigned char recMode;
+               READSHM(recMode, arlan->receiveMode, u_char);
+               conf->receiveMode = ARLAN_RCV_CLEAN | ARLAN_RCV_CONTROL;
+               if (conf->receiveMode != recMode)
+                       board_conf_needed = 1;
+       }
+       if (board_conf_needed)
+               arlan_command(dev, ARLAN_COMMAND_CONF);
+
+       ARLAN_DEBUG_EXIT("arlan_set_multicast");
+}
+
+
+__initfunctio(int arlan_probe(struct device *dev))
+{
+       printk("Arlan driver %s\n", arlan_version);
+
+       if (arlan_probe_everywhere(dev))
+               return ENODEV;
+
+       arlans_found++;
+
+       if (arlans_found == 1)
+               siteName = kmalloc(100, GFP_KERNEL);
+       return 0;
+}
+
+#ifdef  MODULE
+
+int init_module(void)
+{
+       int i = 0;
+
+       ARLAN_DEBUG_ENTRY("init_module");
+
+       if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN)
+       {
+               printk(KERN_WARNING "arlan: wrong module params for multiple devices\n ");
+               return -1;
+       }
+       numDevices = arlan_find_devices();
+       if (numDevices == 0)
+       {
+               printk(KERN_ERR "arlan: no devices found \n");
+               return -1;
+       }
+
+       siteName = kmalloc(100, GFP_KERNEL);
+       if(siteName==NULL)
+       {
+               printk(KERN_ERR "arlan: No memory for site name.\n");
+               return -1;
+       }
+       for (i = 0; i < numDevices && i < MAX_ARLANS; i++)
+       {
+               if (!arlan_allocate_device(i, NULL))
+                       return -1;
+               if (arlan_device[i] == NULL)
+               {
+                       printk(KERN_CRIT "arlan: Not Enough memory \n");
+                       return -1;
+               }
+               if (probe)
+                       arlan_probe_everywhere(arlan_device[i]);
+       }
+       printk(KERN_INFO "Arlan driver %s\n", arlan_version);
+       ARLAN_DEBUG_EXIT("init_module");
+       return 0;
+}
+
+
+void cleanup_module(void)
+{
+       int i = 0;
+
+       ARLAN_DEBUG_ENTRY("cleanup_module");
+
+       IFDEBUG(ARLAN_DEBUG_SHUTDOWN)
+               printk(KERN_INFO "arlan: unloading module\n");
+       for (i = 0; i < MAX_ARLANS; i++)
+       {
+               if (arlan_device[i])
+               {
+                       unregister_netdev(arlan_device[i]);
+                       if (arlan_device[i]->priv)
+                       {
+                               if (((struct arlan_private *) arlan_device[i]->priv)->conf)
+                                       kfree(((struct arlan_private *) arlan_device[i]->priv)->conf);
+                               kfree(arlan_device[i]);
+                       }
+                       arlan_device[i] = NULL;
+               }
+       }
+       ARLAN_DEBUG_EXIT("cleanup_module");
+}
+
+
+#endif
diff --git a/drivers/net/arlan.h b/drivers/net/arlan.h
new file mode 100644 (file)
index 0000000..7074335
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ *  Copyright (C) 1997 Cullen Jennings
+ *  Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500       
+ *  Gnu Public License applies
+ */
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>    /* For the statistics structure. */
+#include <linux/if_arp.h>      /* For ARPHRD_ETHER */
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+
+#define DEBUG 1
+
+#define ARLAN_PROC_INTERFACE
+#define MAX_ARLANS 4 /* not more than 4 ! */
+#define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */
+
+#define ARLAN_MAX_MULTICAST_ADDRS 16
+#define ARLAN_RCV_CLEAN        0
+#define ARLAN_RCV_PROMISC 1
+#define ARLAN_RCV_CONTROL 2
+
+
+#ifdef CONFIG_PROC_FS
+extern int     init_arlan_proc(void);
+#endif
+
+extern struct device *arlan_device[MAX_ARLANS];
+static int     arlan_debug;
+static char *  siteName;
+static int     arlan_entry_debug;
+static int     arlan_exit_debug;
+static int     arlan_entry_and_exit_debug;
+static int     testMemory;
+static const char* arlan_version;
+#define SIDUNKNOWN -1
+#define radioNodeIdUNKNOWN -1
+#define encryptionKeyUNKNOWN '\0';
+#define irqUNKNOWN 0
+#define memUNKNOWN 0
+#define debugUNKNOWN 0
+#define probeUNKNOWN 1
+#define numDevicesUNKNOWN 1
+#define testMemoryUNKNOWN 1
+#define spreadingCodeUNKNOWN 0
+#define channelNumberUNKNOWN 0
+#define channelSetUNKNOWN 0
+#define systemIdUNKNOWN -1
+#define registrationModeUNKNOWN -1
+#define siteNameUNKNOWN "LinuxSite"
+
+
+
+#define IFDEBUG( L ) if ( (L) & arlan_debug ) 
+#define ARLAN_FAKE_HDR_LEN 12 
+
+#ifdef DEBUG
+       #define ARLAN_ENTRY_EXIT_DEBUGING 1
+       #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b)
+#else
+       #define ARLAN_DEBUG(a,b) 
+#endif
+
+struct arlan_shmem
+{
+      /* Header Signature */ 
+      volatile char textRegion[48];
+      volatile u_char resetFlag;
+      volatile u_char  diagnosticInfo;
+      volatile u_short diagnosticOffset;
+      volatile u_char _1[12];
+      volatile u_char lanCardNodeId[6];
+      volatile u_char broadcastAddress[6];
+      volatile u_char hardwareType;
+      volatile u_char majorHardwareVersion;
+      volatile u_char minorHardwareVersion;
+      volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111
+      volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A
+      volatile u_char _2[47];
+      
+      /* Control/Status Block - 0x0080 */
+      volatile u_char interruptInProgress; /* not used by lancpu */
+      volatile u_char cntrlRegImage; /* not used by lancpu */
+      volatile u_char _3[13];
+      volatile u_char dumpByte;
+      volatile u_char commandByte; /* non-zero = active */
+      volatile u_char commandParameter[15];
+
+      /* Receive Status - 0x00a0 */
+      volatile u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */
+      volatile u_char rxFrmType;
+      volatile u_short rxOffset;
+      volatile u_short rxLength;
+      volatile u_char rxSrc[6];
+      volatile u_char rxBroadcastFlag;
+      volatile u_char rxQuality;
+      volatile u_char scrambled;
+      volatile u_char _4[1];
+      
+      /* Transmit Status - 0x00b0 */
+      volatile u_char txStatus;
+      volatile u_char txAckQuality;
+      volatile u_char numRetries;
+      volatile u_char _5[14];
+      volatile u_char registeredRouter[6];
+      volatile u_char backboneRouter[6];
+      volatile u_char registrationStatus;
+      volatile u_char configuredStatusFlag;
+      volatile u_char _6[1];
+      volatile u_char ultimateDestAddress[6];
+      volatile u_char immedDestAddress[6];
+      volatile u_char immedSrcAddress[6];
+      volatile u_short rxSequenceNumber;
+      volatile u_char assignedLocaltalkAddress;
+      volatile u_char _7[27];
+
+      /* System Parameter Block */
+
+      /* - Driver Parameters (Novell Specific) */
+
+      volatile u_short txTimeout;
+      volatile u_short transportTime;
+      volatile u_char _8[4];
+
+      /* - Configuration Parameters */
+      volatile u_char irqLevel;
+      volatile u_char spreadingCode;
+      volatile u_char channelSet;
+      volatile u_char channelNumber;
+      volatile u_short radioNodeId;
+      volatile u_char _9[2];
+      volatile u_char scramblingDisable;
+      volatile u_char radioType;
+      volatile u_short routerId;
+      volatile u_char _10[9];
+      volatile u_char txAttenuation;
+      volatile u_char systemId[4]; 
+      volatile u_short globalChecksum;
+      volatile u_char _11[4];
+      volatile u_short maxDatagramSize;
+      volatile u_short maxFrameSize;
+      volatile u_char maxRetries;
+      volatile u_char receiveMode;
+      volatile u_char priority;
+      volatile u_char rootOrRepeater;
+      volatile u_char specifiedRouter[6];
+      volatile u_short fastPollPeriod;
+      volatile u_char pollDecay;
+      volatile u_char fastPollDelay[2];
+      volatile u_char arlThreshold;
+      volatile u_char arlDecay;
+      volatile u_char _12[1];
+      volatile u_short specRouterTimeout;
+      volatile u_char _13[5];
+
+      /* Scrambled Area */
+      volatile u_char SID[4];
+      volatile u_char encryptionKey[12];
+      volatile u_char _14[2];
+      volatile u_char waitTime[2];
+      volatile u_char lParameter[2];
+      volatile u_char _15[3];
+      volatile u_short headerSize;
+      volatile u_short sectionChecksum;
+
+      volatile u_char registrationMode;
+      volatile u_char registrationFill;
+      volatile u_short pollPeriod;
+      volatile u_short refreshPeriod;
+      volatile u_char name[16];
+      volatile u_char NID[6];
+      volatile u_char localTalkAddress;
+      volatile u_char codeFormat;
+      volatile u_char numChannels;
+      volatile u_char channel1;
+      volatile u_char channel2;
+      volatile u_char channel3;
+      volatile u_char channel4;
+      volatile u_char SSCode[59];
+
+      volatile u_char _16[0xC0];
+      volatile u_short auxCmd;
+      volatile u_char  dumpPtr[4];
+      volatile u_char dumpVal;
+      volatile u_char _17[0x6A];
+      volatile u_char wireTest;
+      volatile u_char _18[14];
+
+      /* Statistics Block - 0x0300 */
+      volatile u_char hostcpuLock;
+      volatile u_char lancpuLock;
+      volatile u_char resetTime[18];
+      
+      volatile u_char numDatagramsTransmitted[4];
+      volatile u_char numReTransmissions[4];
+      volatile u_char numFramesDiscarded[4];
+      volatile u_char numDatagramsReceived[4];
+      volatile u_char numDuplicateReceivedFrames[4];
+      volatile u_char numDatagramsDiscarded[4];
+      
+      volatile u_short maxNumReTransmitDatagram;
+      volatile u_short maxNumReTransmitFrames;
+      volatile u_short maxNumConsecutiveDuplicateFrames;
+      /* misaligned here so we have to go to characters */
+     
+      volatile u_char numBytesTransmitted[4];
+      volatile u_char numBytesReceived[4];
+      volatile u_char numCRCErrors[4];
+      volatile u_char numLengthErrors[4];
+      volatile u_char numAbortErrors[4];
+      volatile u_char numTXUnderruns[4];
+      volatile u_char numRXOverruns[4];
+      volatile u_char numHoldOffs[4];
+      volatile u_char numFramesTransmitted[4];
+      volatile u_char numFramesReceived[4];
+      volatile u_char numReceiveFramesLost[4];
+      volatile u_char numRXBufferOverflows[4];
+      volatile u_char numFramesDiscardedAddrMismatch[4];
+      volatile u_char numFramesDiscardedSIDMismatch[4];
+      volatile u_char numPollsTransmistted[4];
+      volatile u_char numPollAcknowledges[4];
+      volatile u_char numStatusTimeouts[4];
+      volatile u_char numNACKReceived[4];
+
+      volatile u_char _19[0x86];
+
+      volatile u_char txBuffer[0x800];
+      volatile u_char rxBuffer[0x800];
+
+      volatile u_char _20[0x800];
+      volatile u_char _21[0x3fb];
+      volatile u_char configStatus;
+      volatile u_char _22;
+      volatile u_char progIOCtrl;
+      volatile u_char shareMBase;
+      volatile u_char controlRegister;
+};
+
+struct arlan_conf_stru {
+      int spreadingCode;
+      int channelSet;
+      int channelNumber;
+      int scramblingDisable;
+      int txAttenuation;
+      int systemId; 
+      int maxDatagramSize;
+      int maxFrameSize;
+      int maxRetries;
+      int receiveMode;
+      int priority;
+      int rootOrRepeater;
+      int SID;
+      int radioNodeId;
+      int registrationMode;
+      int registrationFill;
+      int localTalkAddress;
+      int codeFormat;
+      int numChannels;
+      int channel1;
+      int channel2;
+      int channel3;
+      int channel4;
+      int txClear;
+      int txRetries;
+      int txRouting;
+      int txScrambled;
+      int rxParameter;
+      int txTimeoutMs;
+      int txAckTimeoutMs;
+      int waitCardTimeout;
+      int      waitTime;
+      int      lParameter;
+      int      _15;
+      int      headerSize;
+      int async;
+      int retries;
+      int tx_delay_ms;
+      int waitReTransmitPacketMaxSize;
+      int ReTransmitPacketMaxSize;
+      int fastReTransCount;
+      int driverRetransmissions;
+      int registrationInterrupts;
+      int hardwareType;
+      int radioType;
+      int writeRadioType;
+      int writeEEPROM;
+      char siteName[17];
+      int measure_rate;
+      int in_speed;
+      int out_speed;
+      int in_speed10;
+      int out_speed10;
+      int in_speed_max;
+      int out_speed_max;
+      int pre_Command_Wait;
+      int rx_tweak1;
+      int rx_tweak2;
+      int tx_queue_len;
+};
+
+struct arlan_conf_stru arlan_conf[MAX_ARLANS];
+
+struct TxParam
+{
+      volatile short           offset;
+      volatile         short           length;
+      volatile u_char          dest[6];
+      volatile unsigned        char clear;
+      volatile unsigned        char retries;
+      volatile unsigned        char routing;
+      volatile unsigned        char scrambled;
+};
+
+struct TxRingPoint  {
+       struct TxParam txParam;
+       
+       
+};
+
+#define TX_RING_SIZE 2
+/* Information that need to be kept for each board. */
+struct arlan_private {
+      struct enet_statistics stats;
+      long open_time;                  /* Useless example local info. */
+      struct arlan_shmem * card;
+      struct arlan_shmem * conf;
+      struct TxParam txParam;      
+      int multicastLength;
+      char  multicastList[ARLAN_MAX_MULTICAST_ADDRS][6];
+      int promiscModeEnabled;
+      struct arlan_conf_stru * Conf;        
+      int      bad;
+      int      reset;
+      long long lastReset;
+      struct timer_list timer;
+      struct timer_list tx_delay_timer;
+      struct timer_list tx_retry_timer;
+      struct timer_list rx_check_timer;
+      struct semaphore card_lock;
+      atomic_t         card_users;
+      atomic_t delay_on;
+      atomic_t  retr_on;
+      int registrationLostCount;
+      int reRegisterExp;
+      int nof_tx;
+      int nof_tx_ack;
+      int last_nof_tx;
+      int last_nof_tx_ack;
+      int irq_test_done;
+      int last_command_was_rx;
+      struct TxParam txRing[TX_RING_SIZE];
+      char reTransmitBuff[0x800];
+      volatile int txLast;
+      volatile int txNew;
+      volatile int txOffset;
+      volatile char ReTransmitRequested;
+      volatile long long tx_done_delayed;
+      volatile long long registrationLastSeen;
+      volatile char under_command;
+      volatile char under_toggle;
+      volatile long long tx_last_sent;
+      volatile long long tx_last_cleared;
+      volatile u_char under_tx;
+      volatile int     retransmissions;
+      volatile int     tx_chain_active;
+      volatile int     timer_chain_active;
+      volatile int     interrupt_ack_requested;
+      volatile int     command_lock;
+      volatile int     rx_command_needed;
+      volatile int     tx_command_needed;
+      volatile int     waiting_command_mask;
+      volatile int     card_polling_interval;
+      volatile int     last_command_buff_free_time;
+      volatile int     numResets;
+      volatile int     under_reset;
+      volatile int     under_config;
+      volatile int     rx_command_given;
+      volatile int     tx_command_given;
+      volatile int     interrupt_processing_active;
+      volatile long long       last_tx_time;
+      volatile long long       last_rx_time;
+      volatile long long       last_rx_int_ack_time;
+      int      in_bytes;
+      int      out_bytes;
+      int      in_time;
+      int      out_time;
+      int      in_time10;
+      int      out_time10;
+      int      in_bytes10;
+      int      out_bytes10;
+};
+
+
+
+#define ARLAN_CLEAR            0x00
+#define ARLAN_RESET            0x01
+#define ARLAN_CHANNEL_ATTENTION 0x02
+#define ARLAN_INTERRUPT_ENABLE         0x04
+#define ARLAN_CLEAR_INTERRUPT  0x08
+#define ARLAN_POWER            0x40
+#define ARLAN_ACCESS           0x80
+
+#define ARLAN_COM_CONF                0x01
+#define ARLAN_COM_RX_ENABLE           0x03
+#define ARLAN_COM_RX_ABORT            0x04
+#define ARLAN_COM_TX_ENABLE           0x05
+#define ARLAN_COM_TX_ABORT            0x06
+#define ARLAN_COM_NOP                0x07
+#define ARLAN_COM_STANDBY             0x08
+#define ARLAN_COM_ACTIVATE            0x09
+#define ARLAN_COM_GOTO_SLOW_POLL      0x0a
+#define ARLAN_COM_INT                 0x80
+
+
+#define TXLAST(dev) (((struct arlan_private *)dev->priv)->txRing[((struct arlan_private *)dev->priv)->txLast])
+#define TXHEAD(dev) (((struct arlan_private *)dev->priv)->txRing[0])
+#define TXTAIL(dev) (((struct arlan_private *)dev->priv)->txRing[1])
+
+#define TXBuffStart(dev) \
+ ((int)(((struct arlan_private *)dev->priv)->card)->txBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) )
+#define TXBuffEnd(dev) \
+ ((int)(((struct arlan_private *)dev->priv)->card)->rxBuffer) - ((int)(((struct arlan_private *)dev->priv)->card)
+#define READSHM(to,from,atype) {\
+       atype tmp;\
+       memcpy_fromio(&(tmp),&(from),sizeof(atype));\
+       to = tmp;\
+       }
+
+#define READSHMEM(from,atype)\
+       atype from; \
+       READSHM(from, arlan->from, atype);
+
+#define WRITESHM(to,from,atype) \
+       { atype tmpSHM = from;\
+       memcpy_toio(&(to),&tmpSHM,sizeof(atype));\
+       }
+
+#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \
+       {       atype tmpSHM; \
+               memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\
+               IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\
+       }
+
+#define WRITESHMB(to, val) \
+       writeb(val,&(to))
+#define READSHMB(to) \
+       readb(&(to))
+#define WRITESHMS(to, val) \
+       writew(val,&(to))
+#define READSHMS(to) \
+       readw(&(to))
+#define WRITESHMI(to, val) \
+       writel(val,&(to))
+#define READSHMI(to) \
+       readl(&(to))
+
+
+
+
+
+#define registrationBad(dev)\
+   ( (   READSHMB(((struct arlan_private *)dev->priv)->card->registrationMode)    > 0) && \
+     (   READSHMB(((struct arlan_private *)dev->priv)->card->registrationStatus) == 0)    )
+
+
+#define readControlRegister(dev)\
+       READSHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage)
+
+#define writeControlRegister(dev, v){\
+   WRITESHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage  ,((v) &0xF) );\
+   WRITESHMB(((struct arlan_private *)dev->priv)->card->controlRegister        ,(v)    );}
+
+
+#define arlan_interrupt_lancpu(dev) {\
+   int cr;   \
+   \
+   priv->under_toggle++;   \
+   cr = readControlRegister(dev);\
+   if (cr & ARLAN_CHANNEL_ATTENTION){ \
+      writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\
+   }else  \
+      writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\
+   priv->under_toggle=0;     \
+}
+
+#define clearChannelAttention(dev){ \
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);}
+#define setHardwareReset(dev) {\
+   writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);}
+#define clearHardwareReset(dev) {\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);}
+#define setInterruptEnable(dev){\
+   writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE)  ;}
+#define clearInterruptEnable(dev){\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE)  ;}
+#define setClearInterrupt(dev){\
+   writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT)   ;}
+#define clearClearInterrupt(dev){\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);}
+#define setPowerOff(dev){\
+   writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);}
+#define setPowerOn(dev){\
+   writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER));   }
+#define arlan_lock_card_access(dev){\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);}
+#define arlan_unlock_card_access(dev){\
+   writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); }  
+
+
+
+
+#define ARLAN_COMMAND_RX               0x00001
+#define ARLAN_COMMAND_NOOP             0x00002
+#define ARLAN_COMMAND_NOOPINT          0x00004
+#define ARLAN_COMMAND_TX               0x00008
+#define ARLAN_COMMAND_CONF             0x00010
+#define ARLAN_COMMAND_RESET            0x00020
+#define ARLAN_COMMAND_TX_ABORT         0x00040
+#define ARLAN_COMMAND_RX_ABORT         0x00080
+#define ARLAN_COMMAND_POWERDOWN                0x00100
+#define ARLAN_COMMAND_POWERUP          0x00200
+#define ARLAN_COMMAND_SLOW_POLL        0x00400
+#define ARLAN_COMMAND_ACTIVATE                 0x00800
+#define ARLAN_COMMAND_INT_ACK          0x01000
+#define ARLAN_COMMAND_INT_ENABLE       0x02000
+#define ARLAN_COMMAND_WAIT_NOW         0x04000
+#define ARLAN_COMMAND_LONG_WAIT_NOW    0x08000
+#define ARLAN_COMMAND_STANDBY          0x10000
+#define ARLAN_COMMAND_INT_RACK         0x20000
+#define ARLAN_COMMAND_INT_RENABLE      0x40000
+#define ARLAN_COMMAND_CONF_WAIT                0x80000
+#define ARLAN_COMMAND_CLEAN_AND_CONF   (ARLAN_COMMAND_TX_ABORT\
+                                       | ARLAN_COMMAND_RX_ABORT\
+                                       | ARLAN_COMMAND_CONF)
+#define ARLAN_COMMAND_CLEAN_AND_RESET   (ARLAN_COMMAND_TX_ABORT\
+                                       | ARLAN_COMMAND_RX_ABORT\
+                                       | ARLAN_COMMAND_RESET)
+
+
+#define ARLAN_DEBUG_CHAIN_LOCKS                0x00001
+#define ARLAN_DEBUG_RESET              0x00002
+#define ARLAN_DEBUG_TIMING             0x00004
+#define ARLAN_DEBUG_CARD_STATE         0x00008
+#define ARLAN_DEBUG_TX_CHAIN           0x00010
+#define ARLAN_DEBUG_MULTICAST          0x00020
+#define ARLAN_DEBUG_HEADER_DUMP                0x00040
+#define ARLAN_DEBUG_INTERRUPT          0x00080
+#define ARLAN_DEBUG_STARTUP            0x00100
+#define ARLAN_DEBUG_SHUTDOWN           0x00200
\ No newline at end of file
index 56858bc45ed5ac6191ddf278287abc026eff701a..69d383a453c777e634c5000a5264335940341aa4 100644 (file)
@@ -41,7 +41,7 @@ static int rx_copybreak = 200;
 static int max_interrupt_work = 200;
 
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
+static int multicast_filter_limit = 3;
 
 #include <linux/module.h>
 
@@ -343,7 +343,8 @@ struct speedo_private {
        const char *product_name;
        struct device *next_module;
        spinlock_t lock;
-       struct TxFD     tx_ring[TX_RING_SIZE];  /* Commands (usually CmdTxPacket). */
+       struct TxFD     tx_ring[TX_RING_SIZE]   /* Commands (usually CmdTxPacket). */
+                               __attribute__ ((aligned (L1_CACHE_BYTES)));;
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        struct sk_buff* tx_skbuff[TX_RING_SIZE];
        struct descriptor  *last_cmd;   /* Last command sent. */
index 165d4fefee490d21f7bd244eb14e33791fe5fea8..d677dbf1bd7182050a3ee19cbb3c0e6b0aba7be8 100644 (file)
@@ -209,7 +209,7 @@ static void eql_timer(unsigned long param); /*  */
    ---------------------------------------------------------
    */
 
-__initfunc(int eql_init(struct device *dev))
+int __init eql_init(struct device *dev)
 {
        static unsigned version_printed = 0;
        /* static unsigned num_masters     = 0; */
@@ -411,16 +411,15 @@ static int eql_enslave(struct device *dev, slaving_request_t *srqp)
        slaving_request_t srq;
        int err;
 
-       err = verify_area(VERIFY_READ, (void *)srqp, sizeof (slaving_request_t));
+       err = copy_from_user(&srq, srqp, sizeof (slaving_request_t));
        if (err)  
          {
 #ifdef EQL_DEBUG
        if (eql_debug >= 20)
-               printk ("EQL enslave: error detected by verify_area\n");
+               printk ("EQL enslave: error detected by copy_from_user\n");
 #endif  
                return err;
          }
-       copy_from_user (&srq, srqp, sizeof (slaving_request_t));
 
 #ifdef EQL_DEBUG
        if (eql_debug >= 20)
@@ -473,11 +472,10 @@ static int eql_emancipate(struct device *dev, slaving_request_t *srqp)
        slaving_request_t srq;
        int err;
 
-       err = verify_area(VERIFY_READ, (void *)srqp, sizeof (slaving_request_t));
+       err = copy_from_user(&srq, srqp, sizeof (slaving_request_t));
        if (err) 
                return err;
 
-       copy_from_user (&srq, srqp, sizeof (slaving_request_t));
 #ifdef EQL_DEBUG
        if (eql_debug >= 20)
                printk ("%s: emancipate `%s`\n", dev->name, srq.slave_name);
@@ -504,11 +502,10 @@ static int eql_g_slave_cfg(struct device *dev, slave_config_t *scp)
        slave_config_t sc;
        int err;
 
-       err = verify_area(VERIFY_READ, (void *)scp, sizeof (slave_config_t));
+       err = copy_from_user (&sc, scp, sizeof (slave_config_t));
        if (err) 
                return err;
 
-       copy_from_user (&sc, scp, sizeof (slave_config_t));
 #ifdef EQL_DEBUG
        if (eql_debug >= 20)
                printk ("%s: get config for slave `%s'\n", dev->name, sc.slave_name);
@@ -541,7 +538,7 @@ static int eql_s_slave_cfg(struct device *dev, slave_config_t *scp)
        slave_config_t sc;
        int err;
 
-       err = verify_area(VERIFY_READ, (void *)scp, sizeof (slave_config_t));
+       err = copy_from_user (&sc, scp, sizeof (slave_config_t));
        if (err) 
                return err;
 
@@ -550,7 +547,6 @@ static int eql_s_slave_cfg(struct device *dev, slave_config_t *scp)
                printk ("%s: set config for slave `%s'\n", dev->name, sc.slave_name);
 #endif
   
-       copy_from_user (&sc, scp, sizeof (slave_config_t));
 
        eql = (equalizer_t *) dev->priv;
        slave_dev = dev_get (sc.slave_name);
@@ -583,13 +579,12 @@ static int eql_g_master_cfg(struct device *dev, master_config_t *mcp)
        if ( eql_is_master (dev) )
        {
                int err;
-               err = verify_area(VERIFY_WRITE, (void *)mcp, sizeof (master_config_t));
-               if (err) 
-                       return err;
                eql = (equalizer_t *) dev->priv;
                mc.max_slaves = eql->max_slaves;
                mc.min_slaves = eql->min_slaves;
-               copy_to_user (mcp, &mc, sizeof (master_config_t));
+               err = copy_to_user (mcp, &mc, sizeof (master_config_t));
+               if (err) 
+                       return err;
                return 0;
        }
        return -EINVAL;
@@ -602,14 +597,13 @@ static int eql_s_master_cfg(struct device *dev, master_config_t *mcp)
        master_config_t mc;
        int err;
 
-       err = verify_area(VERIFY_READ, (void *)mcp, sizeof (master_config_t));
+       err = copy_from_user (&mc, mcp, sizeof (master_config_t));
        if (err)
                return err;
 #if EQL_DEBUG
        if (eql_debug >= 20)
                printk ("%s: set master config\n", dev->name);
 #endif
-       copy_from_user (&mc, mcp, sizeof (master_config_t));
        if ( eql_is_master (dev) )
        {
                eql = (equalizer_t *) dev->priv;
index 391f6194a072ff4b8357e40abf3632ef3c887c79..8958374d448224dbad0102cd3001ee196bc88703 100644 (file)
@@ -450,7 +450,7 @@ static char *cardname = "ICL EtherTeam 16i/32";
 
 #else  /* Not HAVE_DEVLIST */
 
-__initfunc(int eth16i_probe(struct device *dev))
+int __init eth16i_probe(struct device *dev)
 {
        int i;
        int ioaddr;
@@ -484,7 +484,7 @@ __initfunc(int eth16i_probe(struct device *dev))
 }
 #endif  /* Not HAVE_DEVLIST */
 
-__initfunc(static int eth16i_probe1(struct device *dev, int ioaddr))
+static int __init eth16i_probe1(struct device *dev, int ioaddr)
 {
        static unsigned version_printed = 0;
        boot = 1;  /* To inform initilization that we are in boot probe */
@@ -886,7 +886,7 @@ static int eth16i_check_signature(int ioaddr)
        creg[0] &= 0x0F;      /* Mask collision cnr */
        creg[2] &= 0x7F;      /* Mask DCLEN bit */
 
-#ifdef 0
+#if 0
        /* 
           This was removed because the card was sometimes left to state
           from which it couldn't be find anymore. If there is need
index 5618f1fcd626cfa9fcc634b2a2e362f22f5f512b..5f3b8d744020e7e653e51ccbfae82cb6c34d8668 100644 (file)
@@ -342,11 +342,8 @@ static int num_ewrk3s = 0, num_eth = 0;
     outb(EEPROM_INIT, EWRK3_IOPR);\
     mdelay(1);\
 }
-\f
-
-
 
-__initfunc(int ewrk3_probe(struct device *dev))
+int __init ewrk3_probe(struct device *dev)
 {
        int tmp = num_ewrk3s, status = -ENODEV;
        u_long iobase = dev->base_addr;
@@ -378,8 +375,8 @@ __initfunc(int ewrk3_probe(struct device *dev))
        return status;
 }
 
-__initfunc(static int
-          ewrk3_hw_init(struct device *dev, u_long iobase))
+static int __init 
+ewrk3_hw_init(struct device *dev, u_long iobase)
 {
        struct ewrk3_private *lp;
        int i, status = 0;
@@ -1285,7 +1282,7 @@ static void SetMulticastFilter(struct device *dev)
 /*
    ** ISA bus I/O device probe
  */
-__initfunc(static void isa_probe(struct device *dev, u_long ioaddr))
+static void __init isa_probe(struct device *dev, u_long ioaddr)
 {
        int i = num_ewrk3s, maxSlots;
        u_long iobase;
@@ -1325,7 +1322,7 @@ __initfunc(static void isa_probe(struct device *dev, u_long ioaddr))
    ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
    ** the motherboard.
  */
-__initfunc(static void eisa_probe(struct device *dev, u_long ioaddr))
+static void __init eisa_probe(struct device *dev, u_long ioaddr)
 {
        int i, maxSlots;
        u_long iobase;
@@ -1372,8 +1369,8 @@ __initfunc(static void eisa_probe(struct device *dev, u_long ioaddr))
    ** are not available then insert a new device structure at the end of
    ** the current list.
  */
-__initfunc(static struct device *
-          alloc_device(struct device *dev, u_long iobase))
+static struct device * __init 
+alloc_device(struct device *dev, u_long iobase)
 {
        struct device *adev = NULL;
        int fixed = 0, new_dev = 0;
@@ -1417,8 +1414,8 @@ __initfunc(static struct device *
    ** If at end of eth device list and can't use current entry, malloc
    ** one up. If memory could not be allocated, print an error message.
  */
-__initfunc(static struct device *
-          insert_device(struct device *dev, u_long iobase, int (*init) (struct device *)))
+static __init struct device *
+insert_device(struct device *dev, u_long iobase, int (*init) (struct device *))
 {
        struct device *new;
 
@@ -1443,8 +1440,8 @@ __initfunc(static struct device *
        return dev;
 }
 
-__initfunc(static int
-          ewrk3_dev_index(char *s))
+static int __init 
+ewrk3_dev_index(char *s)
 {
        int i = 0, j = 0;
 
@@ -1499,7 +1496,7 @@ static int Write_EEPROM(short data, u_long iobase, u_char eaddr)
 /*
    ** Look for a particular board name in the on-board EEPROM.
  */
-__initfunc(static void EthwrkSignature(char *name, char *eeprom_image))
+static void __init EthwrkSignature(char *name, char *eeprom_image)
 {
        u_long i, j, k;
        char *signatures[] = EWRK3_SIGNATURE;
@@ -1536,7 +1533,7 @@ __initfunc(static void EthwrkSignature(char *name, char *eeprom_image))
    ** ethernet address for later read out.
  */
 
-__initfunc(static int DevicePresent(u_long iobase))
+static int __init DevicePresent(u_long iobase)
 {
        union {
                struct {
@@ -1573,7 +1570,7 @@ __initfunc(static int DevicePresent(u_long iobase))
        return status;
 }
 
-__initfunc(static u_char get_hw_addr(struct device *dev, u_char * eeprom_image, char chipType))
+static u_char __init get_hw_addr(struct device *dev, u_char * eeprom_image, char chipType)
 {
        int i, j, k;
        u_short chksum;
@@ -1624,7 +1621,7 @@ __initfunc(static u_char get_hw_addr(struct device *dev, u_char * eeprom_image,
 /*
    ** Look for a particular board name in the EISA configuration space
  */
-__initfunc(static int EISA_signature(char *name, s32 eisa_id))
+static int __init EISA_signature(char *name, s32 eisa_id)
 {
        u_long i;
        char *signatures[] = EWRK3_SIGNATURE;
@@ -1679,18 +1676,20 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                        tmp.addr[i] = dev->dev_addr[i];
                }
                ioc->len = ETH_ALEN;
-               if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len))) {
-                       copy_to_user(ioc->data, tmp.addr, ioc->len);
+               if (copy_to_user(ioc->data, tmp.addr, ioc->len)) {
+                       status = -EFAULT;
+                       break;
                }
-               break;
        case EWRK3_SET_HWADDR:  /* Set the hardware address */
                if (capable(CAP_NET_ADMIN)) {
-                       if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN))) {
                                csr = inb(EWRK3_CSR);
                                csr |= (CSR_TXD | CSR_RXD);
                                outb(csr, EWRK3_CSR);   /* Disable the TX and RX */
 
-                               copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
+                               if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) {
+                                       status = -EFAULT;
+                                       break;
+                               }
                                for (i = 0; i < ETH_ALEN; i++) {
                                        dev->dev_addr[i] = tmp.addr[i];
                                        outb(tmp.addr[i], EWRK3_PAR0 + i);
@@ -1698,7 +1697,6 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 
                                csr &= ~(CSR_TXD | CSR_RXD);    /* Enable the TX and RX */
                                outb(csr, EWRK3_CSR);
-                       }
                } else {
                        status = -EPERM;
                }
@@ -1730,7 +1728,6 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 
                break;
        case EWRK3_GET_MCA:     /* Get the multicast address table */
-               if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
                        while (test_and_set_bit(0, (void *) &lp->lock) != 0);   /* Wait for lock to free */
                        if (lp->shmem_length == IO_ONLY) {
                                outb(0, EWRK3_IOPR);
@@ -1743,17 +1740,21 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                                memcpy_fromio(tmp.addr, (char *) (lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3));
                        }
                        ioc->len = (HASH_TABLE_LEN >> 3);
-                       copy_to_user(ioc->data, tmp.addr, ioc->len);
-               }
+                       if (copy_to_user(ioc->data, tmp.addr, ioc->len)) {
+                               status = -EFAULT;
+                               break;
+                       }
+
                lp->lock = 0;   /* Unlock the page register */
 
                break;
        case EWRK3_SET_MCA:     /* Set a multicast address */
                if (capable(CAP_NET_ADMIN)) {
-                       if (!(status = verify_area(VERIFY_READ, ioc->data, ETH_ALEN * ioc->len))) {
-                               copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
-                               set_multicast_list(dev);
+                       if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) {
+                               status = -EFAULT;
+                               break;
                        }
+                       set_multicast_list(dev);
                } else {
                        status = -EPERM;
                }
@@ -1781,9 +1782,8 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        case EWRK3_GET_STATS:   /* Get the driver statistics */
                cli();
                ioc->len = sizeof(lp->pktStats);
-               if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-                       copy_to_user(ioc->data, &lp->pktStats, ioc->len);
-               }
+               if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
+                       status = -EFAULT;
                sti();
 
                break;
@@ -1800,16 +1800,16 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        case EWRK3_GET_CSR:     /* Get the CSR Register contents */
                tmp.addr[0] = inb(EWRK3_CSR);
                ioc->len = 1;
-               if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-                       copy_to_user(ioc->data, tmp.addr, ioc->len);
-               }
+               if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+                       status = -EFAULT;
                break;
        case EWRK3_SET_CSR:     /* Set the CSR Register contents */
                if (capable(CAP_NET_ADMIN)) {
-                       if (!(status = verify_area(VERIFY_READ, ioc->data, 1))) {
-                               copy_from_user(tmp.addr, ioc->data, 1);
-                               outb(tmp.addr[0], EWRK3_CSR);
+                       if (copy_from_user(tmp.addr, ioc->data, 1)) {
+                               status = -EFAULT;
+                               break;
                        }
+                       outb(tmp.addr[0], EWRK3_CSR);
                } else {
                        status = -EPERM;
                }
@@ -1826,9 +1826,8 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                                tmp.addr[i++] = inb(EWRK3_PAR0 + j);
                        }
                        ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
-                       if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-                               copy_to_user(ioc->data, tmp.addr, ioc->len);
-                       }
+                       if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+                               status = -EFAULT;
                } else {
                        status = -EPERM;
                }
@@ -1836,11 +1835,12 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                break;
        case EWRK3_SET_EEPROM:  /* Set the EEPROM contents */
                if (capable(CAP_NET_ADMIN)) {
-                       if (!(status = verify_area(VERIFY_READ, ioc->data, EEPROM_MAX))) {
-                               copy_from_user(tmp.addr, ioc->data, EEPROM_MAX);
-                               for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-                                       Write_EEPROM(tmp.val[i], iobase, i);
-                               }
+                       if (copy_from_user(tmp.addr, ioc->data, EEPROM_MAX)) {
+                               status = -EFAULT;
+                               break;
+                       }
+                       for (i = 0; i < (EEPROM_MAX >> 1); i++) {
+                               Write_EEPROM(tmp.val[i], iobase, i);
                        }
                } else {
                        status = -EPERM;
@@ -1850,9 +1850,8 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        case EWRK3_GET_CMR:     /* Get the CMR Register contents */
                tmp.addr[0] = inb(EWRK3_CMR);
                ioc->len = 1;
-               if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-                       copy_to_user(ioc->data, tmp.addr, ioc->len);
-               }
+               if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+                       status = -EFAULT;
                break;
        case EWRK3_SET_TX_CUT_THRU:     /* Set TX cut through mode */
                if (suser()) {
index b2358447d2b3ff4561812a1f6f7385ed2dabdd95..5fb420e2e3a79615d5a36dca3fa050e8532286bd 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/in.h>
index 66e8f936c0a0524db0ea13cc6b6a38c1ee847cbe..68799e20ec5fbedec129872fe8926c03298e9fac 100644 (file)
@@ -296,8 +296,6 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y)
 
 #ifdef __i386__
 
-#include <asm/processor.h>
-
 #define HAS_RDTSC (current_cpu_data.x86_capability & X86_FEATURE_TSC)
 
 /*
index fe20840a48fb915915f78b1330da53257b5ade6f..d4f0dec2dba824a9745c6769d667fd59a8093d11 100644 (file)
@@ -389,7 +389,8 @@ static void sv11_shutdown(struct sv11_device *dev)
        free_irq(dev->sync.irq, dev);
        if(dma)
        {
-               free_dma(dev->sync.chanA.rxdma);
+               if(dma==1)
+                       free_dma(dev->sync.chanA.rxdma);
                free_dma(dev->sync.chanA.txdma);
        }
        release_region(dev->sync.chanA.ctrlio-1, 8);
index 29356bbbf3556a89c14b534604434a5137227b13..81420f0446e4dab537353cff242aadb3b60e628d 100644 (file)
@@ -138,11 +138,9 @@ static char mcchannelid[] = {
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/in.h>
 #include <linux/ioport.h>
-#include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
index 4daa5f7e21103d5c87b77b94ac7b437225d531dc..9a5a31a09afac13c2c1c58f189e9021ac30d1101 100644 (file)
@@ -33,8 +33,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
index c7ef984ea0346ec0a64e6c769470b206e8ce63eb..0986211f11d8c534b751142c409bebb798ca1b8b 100644 (file)
@@ -568,11 +568,11 @@ toshoboe_net_open (struct device *dev)
   self->rxs = inb_p (OBOE_RCVT);
   self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET;
 
-#ifdef 0
+#if 0
   self->rxs = 0;
   self->txs = 0;
 #endif
-#ifdef 0
+#if 0
   self->rxs = RX_SLOTS - 1;
   self->txs = 0;
 #endif
@@ -838,7 +838,7 @@ toshoboe_open (struct pci_dev *pci_dev)
   return (0);
 }
 
-__initfunc (int toshoboe_init (void))
+int __init toshoboe_init (void)
 {
   struct pci_dev *pci_dev = NULL;
   int found = 0;
index d9e1e107f574a244ac72e16051f7692c6b293e9e..2c7d69268a9716cb44f732580e17710fde272e9a 100644 (file)
@@ -36,8 +36,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
index 1b48abd365796b4936b3ea28d00c07f64c9d3989..cd809d56251bca35f752c5b6ef5823708f2b542a 100644 (file)
 
 /* Our copyright info must remain in the binary. */
 static const char *version =
-"ne2k-pci.c:v0.99L 2/7/98 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
+"ne2k-pci.c:vpre-1.00e 5/27/99 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
 
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -44,6 +41,13 @@ static const char *version =
 #include <linux/etherdevice.h>
 #include "8390.h"
 
+#if defined(__powerpc__)
+#define inl_le(addr)  le32_to_cpu(inl(addr))
+#define inw_le(addr)  le16_to_cpu(inw(addr))
+#define insl insl_ns
+#define outsl outsl_ns
+#endif
+
 /* Set statically or when loading the driver module. */
 static int debug = 1;
 
@@ -58,19 +62,34 @@ static int debug = 1;
 /* Do we have a non std. amount of memory? (in units of 256 byte pages) */
 /* #define PACKETBUF_MEMSIZE   0x40 */
 
+#define ne2k_flags reg0                        /* Rename an existing field to store flags! */
+
+/* Only the low 8 bits are usable for non-init-time flags! */
+enum {
+       HOLTEK_FDX=1,           /* Full duplex -> set 0x80 at offset 0x20. */
+       ONLY_16BIT_IO=2, ONLY_32BIT_IO=4,       /* Chip can do only 16/32-bit xfers. */
+       STOP_PG_0x60=0x100,
+};
+
+/* This will eventually be converted to the standard PCI probe table. */
+
 static struct {
        unsigned short vendor, dev_id;
        char *name;
+       int flags;
 }
 pci_clone_list[] __initdata = {
-       {0x10ec, 0x8029, "RealTek RTL-8029"},
-       {0x1050, 0x0940, "Winbond 89C940"},
-       {0x11f6, 0x1401, "Compex RL2000"},
-       {0x8e2e, 0x3000, "KTI ET32P2"},
-       {0x4a14, 0x5000, "NetVin NV5000SC"},
-       {0x1106, 0x0926, "Via 82C926"},
-       {0x10bd, 0x0e34, "SureCom NE34"},
-       {0x1050, 0x5a5a, "Winbond"},
+       {0x10ec, 0x8029, "RealTek RTL-8029", 0},
+       {0x1050, 0x0940, "Winbond 89C940", 0},
+       {0x11f6, 0x1401, "Compex RL2000", 0},
+       {0x8e2e, 0x3000, "KTI ET32P2", 0},
+       {0x4a14, 0x5000, "NetVin NV5000SC", 0},
+       {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO},
+       {0x10bd, 0x0e34, "SureCom NE34", 0},
+       {0x1050, 0x5a5a, "Winbond", 0},
+       {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
+       {0x12c3, 0x5598, "Holtek HT80229",
+        ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
        {0,}
 };
 
@@ -86,7 +105,8 @@ pci_clone_list[] __initdata = {
 #define NESM_STOP_PG   0x80    /* Last page +1 of RX ring */
 
 int ne2k_pci_probe(struct device *dev);
-static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq);
+static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq,
+                                                                         int chip_idx);
 
 static int ne2k_pci_open(struct device *dev);
 static int ne2k_pci_close(struct device *dev);
@@ -115,17 +135,13 @@ static struct ne2k_pci_card *ne2k_card_list = NULL;
 int
 init_module(void)
 {
-       int retval;
-
        /* We must emit version information. */
        if (debug)
                printk(KERN_INFO "%s", version);
 
-       retval = ne2k_pci_probe(0);
-
-       if (retval) {
-               printk(KERN_NOTICE "ne2k-pci.c: no (useable) cards found, driver NOT installed.\n");
-               return retval;
+       if (ne2k_pci_probe(0)) {
+               printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n");
+               return -ENODEV;
        }
        lock_8390_module();
        return 0;
@@ -170,7 +186,7 @@ struct netdev_entry netcard_drv =
 {"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0};
 #endif
 
-__initfunc (int ne2k_pci_probe(struct device *dev))
+int __init ne2k_pci_probe(struct device *dev)
 {
        struct pci_dev *pdev = NULL;
        int cards_found = 0;
@@ -225,7 +241,7 @@ __initfunc (int ne2k_pci_probe(struct device *dev))
 
                printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n",
                           pci_clone_list[i].name, pci_ioaddr, pci_irq_line);
-               dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line);
+               dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line, i);
                if (dev == 0) {
                        /* Should not happen. */
                        printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n",
@@ -247,11 +263,10 @@ __initfunc (int ne2k_pci_probe(struct device *dev))
        return cards_found ? 0 : -ENODEV;
 }
 
-__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq))
+static struct device __init *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq, int chip_idx)
 {
        int i;
        unsigned char SA_prom[32];
-       const char *name = NULL;
        int start_page, stop_page;
        int reg0 = inb(ioaddr);
 
@@ -273,6 +288,8 @@ __initfunc (static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr
                }
        }
 
+       dev = init_etherdev(dev, 0);
+
        /* Reset card. Who knows what dain-bramaged state it was left in. */
        {
                unsigned long reset_start_time = jiffies;
@@ -321,59 +338,47 @@ __initfunc (static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr
 
        }
 
-#ifdef notdef
-       /* Some broken PCI cards don't respect the byte-wide
-          request in program_seq above, and hence don't have doubled up values.
-       */
-       for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
-               SA_prom[i] = inb(ioaddr + NE_DATAPORT);
-               SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
-               if (SA_prom[i] != SA_prom[i+1])
-                       sa_prom_doubled = 0;
-       }
-
-       if (sa_prom_doubled)
-               for (i = 0; i < 16; i++)
-                       SA_prom[i] = SA_prom[i+i];
-#else
-       for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
-               SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+       /* Note: all PCI cards have at least 16 bit access, so we don't have
+          to check for 8 bit cards.  Most cards permit 32 bit access. */
 
-#endif
+       if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) {
+               for (i = 0; i < 4 ; i++)
+                       ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
+       } else
+               for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
+                       SA_prom[i] = inb(ioaddr + NE_DATAPORT);
 
        /* We always set the 8390 registers for word mode. */
        outb(0x49, ioaddr + EN0_DCFG);
        start_page = NESM_START_PG;
-       stop_page = NESM_STOP_PG;
-
-       /* Set up the rest of the parameters. */
-       name = "PCI NE2000";
 
-       dev = init_etherdev(dev, 0);
+       stop_page =
+               pci_clone_list[chip_idx].flags&STOP_PG_0x60 ? 0x60 : NESM_STOP_PG;
 
+       /* Set up the rest of the parameters. */
        dev->irq = irq;
        dev->base_addr = ioaddr;
 
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
        if (ethdev_init(dev)) {
                printk ("%s: unable to get memory for dev->priv.\n", dev->name);
-               kfree(dev);
                return 0;
        }
 
        request_region(ioaddr, NE_IO_EXTENT, dev->name);
 
        printk("%s: %s found at %#x, IRQ %d, ",
-                  dev->name, name, ioaddr, dev->irq);
+                  dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq);
        for(i = 0; i < 6; i++) {
                printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
                dev->dev_addr[i] = SA_prom[i];
        }
 
-       ei_status.name = name;
+       ei_status.name = pci_clone_list[chip_idx].name;
        ei_status.tx_start_page = start_page;
        ei_status.stop_page = stop_page;
        ei_status.word16 = 1;
+       ei_status.ne2k_flags = pci_clone_list[chip_idx].flags;
 
        ei_status.rx_start_page = start_page + TX_PAGES;
 #ifdef PACKETBUF_MEMSIZE
@@ -447,9 +452,9 @@ ne2k_pci_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_pa
        /* This *shouldn't* happen. If it does, it's the last thing you'll see */
        if (ei_status.dmaing) {
                printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr "
-                          "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
+                          "[DMAstat:%d][irqlock:%d][intr:%d].\n",
                           dev->name, ei_status.dmaing, ei_status.irqlock,
-                          dev->interrupt);
+                          (int)dev->interrupt);
                return;
        }
 
@@ -461,11 +466,12 @@ ne2k_pci_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_pa
        outb(ring_page, nic_base + EN0_RSARHI);
        outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
 
-#if defined(USE_LONGIO)
-       *(u32*)hdr = inl(NE_BASE + NE_DATAPORT);
-#else
-       insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-#endif
+       if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+               insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+       } else {
+               *(u32*)hdr = le32_to_cpu(inl(NE_BASE + NE_DATAPORT));
+               le16_to_cpus(&hdr->count);
+       }
 
        outb(ENISR_RDC, nic_base + EN0_ISR);    /* Ack intr. */
        ei_status.dmaing &= ~0x01;
@@ -485,12 +491,14 @@ ne2k_pci_block_input(struct device *dev, int count, struct sk_buff *skb, int rin
        /* This *shouldn't* happen. If it does, it's the last thing you'll see */
        if (ei_status.dmaing) {
                printk("%s: DMAing conflict in ne2k_pci_block_input "
-                          "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
+                          "[DMAstat:%d][irqlock:%d][intr:%d].\n",
                           dev->name, ei_status.dmaing, ei_status.irqlock,
-                          dev->interrupt);
+                          (int)dev->interrupt);
                return;
        }
        ei_status.dmaing |= 0x01;
+       if (ei_status.ne2k_flags & ONLY_32BIT_IO)
+               count = (count + 3) & 0xFFFC;
        outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
        outb(count & 0xff, nic_base + EN0_RCNTLO);
        outb(count >> 8, nic_base + EN0_RCNTHI);
@@ -498,21 +506,21 @@ ne2k_pci_block_input(struct device *dev, int count, struct sk_buff *skb, int rin
        outb(ring_offset >> 8, nic_base + EN0_RSARHI);
        outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
 
-#if defined(USE_LONGIO)
-       insl(NE_BASE + NE_DATAPORT, buf, count>>2);
-       if (count & 3) {
-               buf += count & ~3;
-               if (count & 2)
-                       *((u16*)buf)++ = inw(NE_BASE + NE_DATAPORT);
-               if (count & 1)
-                       *buf = inb(NE_BASE + NE_DATAPORT);
-       }
-#else
-       insw(NE_BASE + NE_DATAPORT,buf,count>>1);
-       if (count & 0x01) {
-               buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+       if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+               insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+               if (count & 0x01) {
+                       buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+               }
+       } else {
+               insl(NE_BASE + NE_DATAPORT, buf, count>>2);
+               if (count & 3) {
+                       buf += count & ~3;
+                       if (count & 2)
+                               *((u16*)buf)++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT));
+                       if (count & 1)
+                               *buf = inb(NE_BASE + NE_DATAPORT);
+               }
        }
-#endif
 
        outb(ENISR_RDC, nic_base + EN0_ISR);    /* Ack intr. */
        ei_status.dmaing &= ~0x01;
@@ -527,15 +535,18 @@ ne2k_pci_block_output(struct device *dev, int count,
 
        /* On little-endian it's always safe to round the count up for
           word writes. */
-       if (count & 0x01)
-               count++;
+       if (ei_status.ne2k_flags & ONLY_32BIT_IO)
+               count = (count + 3) & 0xFFFC;
+       else
+               if (count & 0x01)
+                       count++;
 
        /* This *shouldn't* happen. If it does, it's the last thing you'll see */
        if (ei_status.dmaing) {
                printk("%s: DMAing conflict in ne2k_pci_block_output."
-                          "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
+                          "[DMAstat:%d][irqlock:%d][intr:%d]\n",
                           dev->name, ei_status.dmaing, ei_status.irqlock,
-                          dev->interrupt);
+                          (int)dev->interrupt);
                return;
        }
        ei_status.dmaing |= 0x01;
@@ -561,16 +572,16 @@ ne2k_pci_block_output(struct device *dev, int count,
        outb(0x00, nic_base + EN0_RSARLO);
        outb(start_page, nic_base + EN0_RSARHI);
        outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
-#if defined(USE_LONGIO)
-       outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
-       if (count & 3) {
-               buf += count & ~3;
-               if (count & 2)
-                       outw(*((u16*)buf)++, NE_BASE + NE_DATAPORT);
+       if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+               outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+       } else {
+               outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
+               if (count & 3) {
+                       buf += count & ~3;
+                       if (count & 2)
+                               outw(cpu_to_le16(*((u16*)buf)++), NE_BASE + NE_DATAPORT);
+               }
        }
-#else
-       outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
-#endif
 
        dma_start = jiffies;
 
diff --git a/drivers/net/olympic.c b/drivers/net/olympic.c
new file mode 100644 (file)
index 0000000..53061d3
--- /dev/null
@@ -0,0 +1,1663 @@
+/*
+ *   olympic.c (c) 1999 Peter De Schrijver All Rights Reserved
+ *                1999 Mike Phillips (phillim@amtrak.com)
+ *
+ *  Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic
+ *  chipset. 
+ *
+ *  Base Driver Skeleton:
+ *      Written 1993-94 by Donald Becker.
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *  Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their 
+ *  assistance and perserverance with the testing of this driver.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ * 
+ *  4/27/99 - Alpha Release 0.1.0
+ *            First release to the public
+ *
+ *  6/8/99  - Official Release 0.2.0   
+ *            Merged into the kernel code 
+ *  
+ *  To Do:
+ *
+ *  Sanitize for smp
+ *
+ *  If Problems do Occur
+ *  Most problems can be rectified by either closing and opening the interface
+ *  (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult
+ *  if compiled into the kernel).
+ */
+
+/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */
+
+#define OLYMPIC_DEBUG 0
+
+/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel.
+ * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the
+ * kernel.
+ * Intended to be used to create a ring-error reporting network module 
+ * i.e. it will give you the source address of beaconers on the ring 
+ */
+
+#define OLYMPIC_NETWORK_MONITOR 0
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/trdevice.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <net/checksum.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include "olympic.h"
+
+/* I've got to put some intelligence into the version number so that Peter and I know
+ * which version of the code somebody has got. 
+ * Version Number = a.b.c.d  where a.b.c is the level of code and d is the latest author.
+ * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike
+ * 
+ * Official releases will only have an a.b.c version number format.
+ */
+
+static char *version = 
+"Olympic.c v0.2.0 6/8/99 - Peter De Schrijver & Mike Phillips" ; 
+
+static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
+                                  "Address Verification", "Neighbor Notification (Ring Poll)",
+                                  "Request Parameters","FDX Registration Request",
+                                  "FDX Duplicate Address Check", "Station registration Query Wait",
+                                  "Unknown stage"};
+
+static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost", "Wire Fault",
+                                  "Ring Speed Mismatch", "Timeout","Ring Failure","Ring Beaconing",
+                                  "Duplicate Node Address","Request Parameters","Remove Received",
+                                  "Reserved", "Reserved", "No Monitor Detected for RPL", 
+                                  "Monitor Contention failer for RPL", "FDX Protocol Error"};
+
+/* Module paramters */
+
+/* Ring Speed 0,4,16,100 
+ * 0 = Autosense         
+ * 4,16 = Selected speed only, no autosense
+ * This allows the card to be the first on the ring
+ * and become the active monitor.
+ * 100 = Nothing at present, 100mbps is autodetected
+ * if FDX is turned on. May be implemented in the future to 
+ * fail if 100mpbs is not detected.
+ *
+ * WARNING: Some hubs will allow you to insert
+ * at the wrong speed
+ */
+
+static int ringspeed[OLYMPIC_MAX_ADAPTERS] = {0,} ;
+
+MODULE_PARM(ringspeed, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i");
+
+/* Packet buffer size */
+
+static int pkt_buf_sz[OLYMPIC_MAX_ADAPTERS] = {0,} ;
+MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
+
+/* Message Level */
+
+static int message_level[OLYMPIC_MAX_ADAPTERS] = {0,} ; 
+
+MODULE_PARM(message_level, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
+
+static int olympic_scan(struct device *dev);
+static int olympic_init(struct device *dev);
+static int olympic_open(struct device *dev);
+static int olympic_xmit(struct sk_buff *skb, struct device *dev);
+static int olympic_close(struct device *dev);
+static void olympic_set_rx_mode(struct device *dev);
+static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct net_device_stats * olympic_get_stats(struct device *dev);
+static int olympic_set_mac_address(struct device *dev, void *addr) ; 
+static void olympic_arb_cmd(struct device *dev);
+static int olympic_change_mtu(struct device *dev, int mtu);
+static void olympic_srb_bh(struct device *dev) ; 
+static void olympic_asb_bh(struct device *dev) ; 
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+static int sprintf_info(char *buffer, struct device *dev) ; 
+#endif
+#endif
+
+__initfunc(int olympic_probe(struct device *dev)) 
+{
+       int cards_found;
+
+       cards_found=olympic_scan(dev);
+       return cards_found ? 0 : -ENODEV;
+}
+
+__initfunc(static int olympic_scan(struct device *dev)) 
+{
+       struct pci_dev *pci_device = NULL ;
+       struct olympic_private *olympic_priv;
+       int card_no = 0 ;
+       if (pci_present()) {
+
+               while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
+
+                       pci_set_master(pci_device);
+
+                       /* Check to see if io has been allocated, if so, we've already done this card,
+                          so continue on the card discovery loop  */
+
+                       if (check_region(pci_device->base_address[0] & (~3), OLYMPIC_IO_SPACE)) {
+                               card_no++ ; 
+                               continue ; 
+                       }
+
+                       olympic_priv=kmalloc(sizeof (struct olympic_private), GFP_KERNEL);
+                       memset(olympic_priv, 0, sizeof(struct olympic_private));
+                       init_waitqueue_head(&olympic_priv->srb_wait);
+                       init_waitqueue_head(&olympic_priv->trb_wait);
+#ifndef MODULE
+                       dev=init_trdev(dev, 0);
+#endif
+                       dev->priv=(void *)olympic_priv;
+#if OLYMPIC_DEBUG  
+                       printk("pci_device: %p, dev:%p, dev->priv: %p\n", pci_device, dev, dev->priv);
+#endif 
+                       dev->irq=pci_device->irq;
+                       dev->base_addr=pci_device->base_address[0] & (~3);
+                       dev->init=&olympic_init;
+                       olympic_priv->olympic_mmio=ioremap(pci_device->base_address[1],256);
+                       olympic_priv->olympic_lap=ioremap(pci_device->base_address[2],2048);
+                       
+                       if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) )
+                               olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; 
+                       else
+                               olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; 
+
+                       olympic_priv->olympic_ring_speed = ringspeed[card_no] ; 
+                       olympic_priv->olympic_message_level = message_level[card_no] ; 
+                       olympic_priv->olympic_multicast_set  = 0 ; 
+       
+                       if(olympic_init(dev)==-1) {
+                               unregister_netdevice(dev);
+                               kfree(dev->priv);
+                               return 0;
+                       }                               
+
+                       dev->open=&olympic_open;
+                       dev->hard_start_xmit=&olympic_xmit;
+                       dev->change_mtu=&olympic_change_mtu;
+
+                       dev->stop=&olympic_close;
+                       dev->do_ioctl=NULL;
+                       dev->set_multicast_list=&olympic_set_rx_mode;
+                       dev->get_stats=&olympic_get_stats ;
+                       dev->set_mac_address=&olympic_set_mac_address ;  
+                       return 1; 
+               }
+       }
+       return  0 ;
+}
+
+
+__initfunc(static int olympic_init(struct device *dev)) 
+{
+       struct olympic_private *olympic_priv;
+       __u8 *olympic_mmio, *init_srb,*adapter_addr;
+       unsigned long t; 
+       unsigned int uaa_addr;
+
+       olympic_priv=(struct olympic_private *)dev->priv;
+       olympic_mmio=olympic_priv->olympic_mmio;
+
+       printk("%s \n", version);
+       printk("%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n",dev->name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq);
+
+       request_region(dev->base_addr, OLYMPIC_IO_SPACE, "olympic");
+       writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL);
+       t=jiffies;
+       while((readl(olympic_priv->olympic_mmio+BCTL)) & BCTL_SOFTRESET) {
+               schedule();             
+               if(jiffies-t > 40*HZ) {
+                       printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
+                       release_region(dev->base_addr, OLYMPIC_IO_SPACE) ; 
+                       return -1;
+               }
+       }
+
+#if OLYMPIC_DEBUG
+       printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
+       printk("GPR: %x\n",readw(olympic_mmio+GPR));
+       printk("SISRMASK: %x\n",readl(olympic_mmio+SISR_MASK));
+#endif
+       /* Aaaahhh, You have got to be real careful setting GPR, the card
+          holds the previous values from flash memory, including autosense 
+           and ring speed */
+
+       writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL);
+       
+       if (olympic_priv->olympic_ring_speed  == 0) { /* Autosense */
+               writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
+               if (olympic_priv->olympic_message_level) 
+                       printk(KERN_INFO "%s: Ringspeed autosense mode on\n",dev->name);
+       } else if (olympic_priv->olympic_ring_speed == 16) {
+               if (olympic_priv->olympic_message_level) 
+                       printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", dev->name);
+               writel(GPR_16MBPS, olympic_mmio+GPR);
+       } else if (olympic_priv->olympic_ring_speed == 4) {
+               if (olympic_priv->olympic_message_level) 
+                       printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", dev->name) ; 
+               writel(0, olympic_mmio+GPR);
+       } 
+       
+       writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
+
+#if OLYMPIC_DEBUG
+       printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; 
+#endif
+       /* start solo init */
+       writel((1<<15),olympic_mmio+SISR_MASK_SUM);
+
+       t=jiffies;
+       while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) {
+               schedule();             
+               if(jiffies-t > 40*HZ) {
+                       printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
+                       release_region(dev->base_addr, OLYMPIC_IO_SPACE); 
+                       return -1;
+               }
+       }
+       
+       writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+
+#if OLYMPIC_DEBUG
+       printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+#endif
+
+       init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+
+#if OLYMPIC_DEBUG              
+{
+       int i;
+       printk("init_srb(%p): ",init_srb);
+       for(i=0;i<20;i++)
+               printk("%x ",readb(init_srb+i));
+       printk("\n");
+}
+#endif 
+       if(readw(init_srb+6)) {
+               printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",readw(init_srb+6));
+               release_region(dev->base_addr, OLYMPIC_IO_SPACE);
+               return -1;
+       }
+
+       uaa_addr=ntohs(readw(init_srb+8));
+
+#if OLYMPIC_DEBUG
+       printk("UAA resides at %x\n",uaa_addr);
+#endif
+
+       writel(uaa_addr,olympic_mmio+LAPA);
+       adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800));
+
+#if OLYMPIC_DEBUG
+       printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2),
+                       readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5));
+#endif
+
+       memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
+
+       olympic_priv->olympic_addr_table_addr = ntohs(readw(init_srb + 12)) ; 
+       olympic_priv->olympic_parms_addr      = ntohs(readw(init_srb + 14)) ; 
+
+       return 0;
+
+}
+
+static int olympic_open(struct device *dev) 
+{
+       struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+       __u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
+       unsigned long flags;
+       char open_error[255] ; 
+       int i, open_finished = 1 ;
+
+#if OLYMPIC_NETWORK_MONITOR
+       __u8 *oat ; 
+       __u8 *opt ; 
+#endif
+
+       if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) {
+               return -EAGAIN;
+       }
+
+#if OLYMPIC_DEBUG
+       printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
+       printk("pending ints: %x\n",readl(olympic_mmio+SISR_RR));
+#endif
+
+       writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
+
+       writel(SISR_MI | SISR_SRB_REPLY, olympic_mmio+SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */
+
+       writel(LISR_LIE,olympic_mmio+LISR); /* more ints later */
+
+       /* adapter is closed, so SRB is pointed to by LAPWWO */
+
+       writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+       init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+       
+#if OLYMPIC_DEBUG
+       printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+       printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK));
+       printk("Before the open command \n");
+#endif 
+       do {
+               int i;
+
+               save_flags(flags);
+               cli();
+               for(i=0;i<SRB_COMMAND_SIZE;i+=4)
+                       writel(0,init_srb+i);
+               if(SRB_COMMAND_SIZE & 2)
+                       writew(0,init_srb+(SRB_COMMAND_SIZE & ~3));
+               if(SRB_COMMAND_SIZE & 1)
+                       writeb(0,init_srb+(SRB_COMMAND_SIZE & ~1));
+
+               writeb(SRB_OPEN_ADAPTER,init_srb) ;     /* open */
+               writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2);
+
+               /* If Network Monitor, instruct card to copy MAC frames through the ARB */
+
+#if OLYMPIC_NETWORK_MONITOR
+               writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON),init_srb+8);
+#else
+               writew(OPEN_ADAPTER_ENABLE_FDX,init_srb+8);
+#endif         
+
+               if (olympic_priv->olympic_laa[0]) {
+                       writeb(olympic_priv->olympic_laa[0],init_srb+12);
+                       writeb(olympic_priv->olympic_laa[1],init_srb+13);
+                       writeb(olympic_priv->olympic_laa[2],init_srb+14);
+                       writeb(olympic_priv->olympic_laa[3],init_srb+15);
+                       writeb(olympic_priv->olympic_laa[4],init_srb+16);
+                       writeb(olympic_priv->olympic_laa[5],init_srb+17);
+                       memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ;  
+               }       
+               writeb(1,init_srb+30);
+       
+               olympic_priv->srb_queued=1;
+
+               writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+               while(olympic_priv->srb_queued) {        
+                       interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ);
+                       if(signal_pending(current))     {            
+                               printk(KERN_WARNING "%s: SRB timed out.\n",
+                                       dev->name);
+                               printk(KERN_WARNING "SISR=%x MISR=%x\n",
+                                       readl(olympic_mmio+SISR),
+                                       readl(olympic_mmio+LISR));
+                               olympic_priv->srb_queued=0;
+                               break;
+                       }
+               }
+               restore_flags(flags);
+#if OLYMPIC_DEBUG
+               printk("init_srb(%p): ",init_srb);
+               for(i=0;i<20;i++)
+                       printk("%x ",readb(init_srb+i));
+               printk("\n");
+#endif
+               
+               /* If we get the same return response as we set, the interrupt wasn't raised and the open
+                 * timed out.
+                */
+
+               if(readb(init_srb+2)== OLYMPIC_CLEAR_RET_CODE) {
+                       printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; 
+                       return -EIO ; 
+               }       
+
+               if(readb(init_srb+2)!=0) {
+                       if (readb(init_srb+2) == 0x07) {  
+                               if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */
+                                       printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); 
+                                       open_finished = 0 ;  
+                               } else {
+
+                                       strcpy(open_error, open_maj_error[(readb(init_srb+7) & 0xf0) >> 4]) ; 
+                                       strcat(open_error," - ") ; 
+                                       strcat(open_error, open_min_error[(readb(init_srb+7) & 0x0f)]) ;
+
+                                       if (!olympic_priv->olympic_ring_speed && ((readb(init_srb+7) & 0x0f) == 0x0d)) { 
+                                               printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name);
+                                               printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name);
+                                               free_irq(dev->irq, dev);
+                                               return -EIO ;
+                                       }
+
+                                       printk(KERN_WARNING "%s: %s\n",dev->name,open_error);
+                                       free_irq(dev->irq,dev) ; 
+                                       return -EIO ; 
+                               }       /* if autosense && open_finished */
+                       } else {  
+                               printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]);
+                               free_irq(dev->irq, dev);
+                               return -EIO;
+                       } 
+               } else 
+                       open_finished = 1 ; 
+       } while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */   
+
+       if (readb(init_srb+18) & (1<<3)) 
+               if (olympic_priv->olympic_message_level) 
+                       printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name);
+
+       if (readb(init_srb+18) & (1<<1))
+               olympic_priv->olympic_ring_speed = 100 ; 
+       else if (readb(init_srb+18) & 1)
+               olympic_priv->olympic_ring_speed = 16 ; 
+       else
+               olympic_priv->olympic_ring_speed = 4 ; 
+
+       if (olympic_priv->olympic_message_level) 
+               printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed);
+
+       olympic_priv->asb=ntohs(readw(init_srb+8));
+       olympic_priv->srb=ntohs(readw(init_srb+10));
+       olympic_priv->arb=ntohs(readw(init_srb+12));
+       olympic_priv->trb=ntohs(readw(init_srb+16));
+
+       olympic_priv->olympic_receive_options = 0x01 ; 
+       olympic_priv->olympic_copy_all_options = 0 ; 
+       
+       /* setup rx ring */
+       
+       writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ 
+
+       writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */
+
+       for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
+
+               struct sk_buff *skb;
+               
+               skb=dev_alloc_skb(olympic_priv->pkt_buf_sz);
+               if(skb == NULL)
+                       break;
+
+               skb->dev = dev;
+
+               olympic_priv->olympic_rx_ring[i].buffer=virt_to_bus(skb->data);
+               olympic_priv->olympic_rx_ring[i].res_length = olympic_priv->pkt_buf_sz ; 
+               olympic_priv->rx_ring_skb[i]=skb;
+       }
+
+       if (i==0) {
+               printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name);
+               free_irq(dev->irq, dev);
+               return -EIO;
+       }
+
+       writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXDESCQ);
+       writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXCDA);
+       writew(i,olympic_mmio+RXDESCQCNT);
+               
+       writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXSTATQ);
+       writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXCSA);
+       
+       olympic_priv->rx_ring_last_received=OLYMPIC_RX_RING_SIZE-1;     /* last processed rx status */
+       olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE-1;  
+
+       writew(i,olympic_mmio+RXSTATQCNT);
+
+#if OLYMPIC_DEBUG 
+       printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
+       printk("RXCSA: %x, rx_status_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
+       printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) );
+       printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) );
+       printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
+
+       printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
+#endif
+
+       writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
+
+#if OLYMPIC_DEBUG 
+       printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
+       printk("RXCSA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
+       printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
+#endif 
+
+       writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM);
+
+       /* setup tx ring */
+
+       writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */
+       for(i=0;i<OLYMPIC_TX_RING_SIZE;i++) 
+               olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef;
+
+       olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE;
+       writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXDESCQ_1);
+       writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXCDA_1);
+       writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXDESCQCNT_1);
+       
+       writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1);
+       writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1);
+       writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1);
+               
+       olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */
+       olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */
+
+       writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM);
+
+#if OLYMPIC_DEBUG 
+       printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
+       printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK));
+#endif
+
+#if OLYMPIC_NETWORK_MONITOR
+       oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+       opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+
+       printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
+       printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, 
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
+                   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
+
+       printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
+                       readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
+                       readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
+                       readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
+                       readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
+                       readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
+                       readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));
+
+
+#endif         
+       
+       dev->start = 1;
+       dev->interrupt=0;
+       dev->tbusy=0;
+
+       MOD_INC_USE_COUNT ;
+       return 0;
+       
+}      
+
+/*
+ *     When we enter the rx routine we do not know how many frames have been 
+ *     queued on the rx channel.  Therefore we start at the next rx status
+ *     position and travel around the receive ring until we have completed
+ *     all the frames.
+ *
+ *     This means that we may process the frame before we receive the end
+ *     of frame interrupt. This is why we always test the status instead
+ *     of blindly processing the next frame.
+ *     
+ */
+static void olympic_rx(struct device *dev)
+{
+       struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+       __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+       struct olympic_rx_status *rx_status;
+       struct olympic_rx_desc *rx_desc ; 
+       int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len;
+       struct sk_buff *skb, *skb2;
+       int i;
+
+       rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; 
+       while (rx_status->status_buffercnt) { 
+
+               olympic_priv->rx_status_last_received++ ;
+               olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+#if OLYMPIC_DEBUG
+               printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); 
+               printk("rx status: %x rx len: %x \n",rx_status->status_buffercnt,rx_status->fragmentcnt_framelen);      
+#endif
+               length=rx_status->fragmentcnt_framelen & 0xffff;
+               buffer_cnt = rx_status->status_buffercnt & 0xffff ; 
+               i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ 
+               frag_len = rx_status->fragmentcnt_framelen >> 16 ; 
+
+#if OLYMPIC_DEBUG 
+               printk("length: %x, frag_len: %x, buffer_cnt: %x\n",length,frag_len,buffer_cnt);
+#endif
+
+               if(rx_status->status_buffercnt & 0xC0000000) {
+                       if (rx_status->status_buffercnt & 0x3B000000) {
+                               if (olympic_priv->olympic_message_level) {
+                                       if (rx_status->status_buffercnt & (1<<29))  /* Rx Frame Truncated */
+                                               printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name);
+                                       if (rx_status->status_buffercnt & (1<<28)) /*Rx receive overrun */
+                                               printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name);
+                                       if (rx_status->status_buffercnt & (1<<27)) /* No receive buffers */
+                                               printk(KERN_WARNING "%s: No receive buffers \n",dev->name);
+                                       if (rx_status->status_buffercnt & (1<<25)) /* Receive frame error detect */
+                                               printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name);
+                                       if (rx_status->status_buffercnt & (1<<24)) /* Received Error Detect */
+                                               printk(KERN_WARNING "%s: Received Error Detect \n",dev->name);
+                               } 
+                               olympic_priv->rx_ring_last_received += i ; 
+                               olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; 
+                               olympic_priv->olympic_stats.rx_errors++;         
+                       } else {        
+                       
+                               if (buffer_cnt == 1) {
+                                       skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; 
+                               } else {
+                                       skb = dev_alloc_skb(length) ; 
+                               }
+
+                               if (skb == NULL) {
+                                       printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",dev->name) ;
+                                       olympic_priv->olympic_stats.rx_dropped++ ; 
+                                       /* Update counters even though we don't transfer the frame */
+                                       olympic_priv->rx_ring_last_received += i ; 
+                                       olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ;  
+                               } else  {
+                                       skb->dev = dev ; 
+
+                                       /* Optimise based upon number of buffers used. 
+                                          If only one buffer is used we can simply swap the buffers around.
+                                          If more than one then we must use the new buffer and copy the information
+                                          first. Ideally all frames would be in a single buffer, this can be tuned by
+                                                  altering the buffer size. */
+                               
+                                       if (buffer_cnt==1) {
+                                               olympic_priv->rx_ring_last_received++ ; 
+                                               olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+                                               rx_ring_last_received = olympic_priv->rx_ring_last_received ;
+                                               skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; 
+                                               skb_put(skb2,length);
+                                               skb2->protocol = tr_type_trans(skb2,dev);
+                                               olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer=virt_to_bus(skb->data);
+                                               olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = olympic_priv->pkt_buf_sz ; 
+                                               olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; 
+                                               netif_rx(skb2) ; 
+                                       } else {
+                                               do { /* Walk the buffers */ 
+                                                       olympic_priv->rx_ring_last_received++ ; 
+                                                       olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+                                                       rx_ring_last_received = olympic_priv->rx_ring_last_received ; 
+                                                       rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]);
+                                                       cpy_length = (i == 1 ? frag_len : rx_desc->res_length); 
+                                                       memcpy(skb_put(skb, cpy_length), bus_to_virt(rx_desc->buffer), cpy_length) ; 
+                                               } while (--i) ; 
+               
+                                               skb->protocol = tr_type_trans(skb,dev);
+                                               netif_rx(skb) ; 
+                                       } 
+                                       olympic_priv->olympic_stats.rx_packets++ ; 
+                                       olympic_priv->olympic_stats.rx_bytes += length ; 
+                               } /* if skb == null */
+                       } /* If status & 0x3b */
+
+               } else { /*if buffercnt & 0xC */
+                       olympic_priv->rx_ring_last_received += i ; 
+                       olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE - 1) ; 
+               } 
+
+               rx_status->fragmentcnt_framelen = 0 ; 
+               rx_status->status_buffercnt = 0 ; 
+               rx_status = &(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received+1) & (OLYMPIC_RX_RING_SIZE -1) ]);
+
+               writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) |  buffer_cnt , olympic_mmio+RXENQ); 
+       } /* while */
+
+}
+
+static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
+{
+       struct device *dev= (struct device *)dev_id;
+       struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+       __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+       __u32 sisr;
+       __u8 *adapter_check_area ; 
+       
+       sisr=readl(olympic_mmio+SISR_RR) ; /* Reset sisr */ 
+       
+       if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ 
+               return ;
+
+       if (dev->interrupt) 
+               printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ; 
+
+       dev->interrupt = 1 ; 
+
+       if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK |  
+                       SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) {  
+       
+               if(sisr & SISR_SRB_REPLY) {
+                       if(olympic_priv->srb_queued==1) {
+                               wake_up_interruptible(&olympic_priv->srb_wait);
+                       } else if (olympic_priv->srb_queued==2) { 
+                               olympic_srb_bh(dev) ; 
+                       }
+                       olympic_priv->srb_queued=0;
+               } /* SISR_SRB_REPLY */
+
+               if (sisr & SISR_TX1_EOF) {
+                       olympic_priv->tx_ring_last_status++;
+                       olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1);
+                       olympic_priv->free_tx_ring_entries++;
+                       olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len;
+                       olympic_priv->olympic_stats.tx_packets++ ; 
+                       dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
+                       olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
+                       olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
+
+                       if(dev->tbusy) {
+                               dev->tbusy=0;
+                               mark_bh(NET_BH);
+                       }
+               } /* SISR_TX1_EOF */
+       
+               if (sisr & SISR_RX_STATUS) {
+                       olympic_rx(dev);
+               } /* SISR_RX_STATUS */
+       
+               if (sisr & SISR_ADAPTER_CHECK) {
+                       printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
+                       writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+                       adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; 
+                       printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; 
+                       dev->interrupt = 0  ;   
+                       free_irq(dev->irq, dev) ; 
+       
+               } /* SISR_ADAPTER_CHECK */
+       
+               if (sisr & SISR_ASB_FREE) {
+                       /* Wake up anything that is waiting for the asb response */  
+                       if (olympic_priv->asb_queued) {
+                               olympic_asb_bh(dev) ; 
+                       }
+               } /* SISR_ASB_FREE */
+       
+               if (sisr & SISR_ARB_CMD) {
+                       olympic_arb_cmd(dev) ; 
+               } /* SISR_ARB_CMD */
+       
+               if (sisr & SISR_TRB_REPLY) {
+                       /* Wake up anything that is waiting for the trb response */
+                       if (olympic_priv->trb_queued) {
+                               wake_up_interruptible(&olympic_priv->trb_wait);
+                       }
+                       olympic_priv->trb_queued = 0 ; 
+               } /* SISR_TRB_REPLY */  
+       
+               if (sisr & SISR_RX_NOBUF) {
+                       /* According to the documentation, we don't have to do anything, but trapping it keeps it out of
+                                  /var/log/messages.  */
+               } /* SISR_RX_NOBUF */
+       } else { 
+               printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",dev->name, sisr);
+               printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ;
+       } /* One if the interrupts we want */
+
+       dev->interrupt = 0 ;  
+
+       writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
+
+}      
+
+static int olympic_xmit(struct sk_buff *skb, struct device *dev) 
+{
+       struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+    __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+
+       if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+               return 1;
+       }
+
+       if(olympic_priv->free_tx_ring_entries) {
+               olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer=virt_to_bus(skb->data);
+               olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length=skb->len | (0x80000000);
+               olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb;
+               olympic_priv->free_tx_ring_entries--;
+
+               olympic_priv->tx_ring_free++;
+               olympic_priv->tx_ring_free &= (OLYMPIC_TX_RING_SIZE-1);
+
+
+               writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
+
+               dev->tbusy=0;           
+
+               return 0;
+       } else 
+               return 1;
+
+}
+       
+
+static int olympic_close(struct device *dev) 
+{
+       struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+       __u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
+       unsigned long flags;
+       int i;
+
+       writel(olympic_priv->srb,olympic_mmio+LAPA);
+       srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+       
+       writeb(SRB_CLOSE_ADAPTER,srb+0);
+       writeb(0,srb+1);
+       writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+
+       save_flags(flags);
+       cli();  
+
+       olympic_priv->srb_queued=1;
+
+       writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+       while(olympic_priv->srb_queued) {
+               interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ);
+               if(signal_pending(current))     {            
+                       printk(KERN_WARNING "%s: SRB timed out.\n",
+                               dev->name);
+                       printk(KERN_WARNING "SISR=%x MISR=%x\n",
+                       readl(olympic_mmio+SISR),
+                       readl(olympic_mmio+LISR));
+                       olympic_priv->srb_queued=0;
+                       break;
+               }
+       }
+
+       restore_flags(flags) ; 
+       olympic_priv->rx_status_last_received++;
+       olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
+       
+       for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
+               dev_kfree_skb(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
+               olympic_priv->rx_status_last_received++;
+               olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
+       }
+
+       /* reset tx/rx fifo's and busmaster logic */
+
+       writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
+       udelay(1);
+       writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
+
+#if OLYMPIC_DEBUG
+       printk("srb(%p): ",srb);
+       for(i=0;i<4;i++)
+               printk("%x ",readb(srb+i));
+       printk("\n");
+#endif
+       dev->start = 0;
+       free_irq(dev->irq,dev);
+
+       MOD_DEC_USE_COUNT ; 
+       return 0;
+       
+}
+
+static void olympic_set_rx_mode(struct device *dev) 
+{
+       struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+       __u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
+       __u8 options = 0, set_mc_list = 0 ; 
+       __u8 *srb, *ata ;
+       struct dev_mc_list *dmi ; 
+
+       writel(olympic_priv->srb,olympic_mmio+LAPA);
+       srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+       options = olympic_priv->olympic_copy_all_options; 
+
+       if (dev->flags&IFF_PROMISC)  
+               options |= (3<<5) ; /* All LLC and MAC frames, all through the main rx channel */  
+       else
+               options &= ~(3<<5) ; 
+
+       if (dev->mc_count) {  
+               set_mc_list = 1 ; 
+       }
+
+       /* Only issue the srb if there is a change in options */
+
+       if ((options ^ olympic_priv->olympic_copy_all_options)) { 
+       
+               /* Now to issue the srb command to alter the copy.all.options */
+       
+               writeb(SRB_MODIFY_RECEIVE_OPTIONS,srb);
+               writeb(0,srb+1);
+               writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+               writeb(0,srb+3);
+               writeb(olympic_priv->olympic_receive_options,srb+4);
+               writeb(options,srb+5);
+
+               olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+               writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+               olympic_priv->olympic_copy_all_options = options ;
+               
+               return ;  
+       } 
+
+       if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */ 
+
+               dmi = dev->mc_list ; 
+
+               if (set_mc_list) { /* Turn multicast on */
+
+                       /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
+                         * We do this with a set functional address mask.
+                        */
+                                               
+                       ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
+                       if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */ 
+                               writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+                               writeb(0,srb+1);
+                               writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+                               writeb(0,srb+3);
+                               writeb(0,srb+4);
+                               writeb(0,srb+5);
+                               writeb(readb(ata+10),srb+6);
+                               writeb(readb(ata+11)|4,srb+7);
+                               writeb(readb(ata+12),srb+8);
+                               writeb(readb(ata+13),srb+9);
+                       
+                               olympic_priv->srb_queued = 2 ; 
+                               writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+                               olympic_priv->olympic_multicast_set = 1 ;  
+                       }    
+
+
+               } else { /* Turn multicast off */
+       
+                       ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
+                       if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */ 
+                               writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+                               writeb(0,srb+1);
+                               writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+                               writeb(0,srb+3);
+                               writeb(0,srb+4);
+                               writeb(0,srb+5);
+                               writeb(readb(ata+10),srb+6);
+                               writeb(readb(ata+11) & ~4,srb+7);
+                               writeb(readb(ata+12),srb+8);
+                               writeb(readb(ata+13),srb+9);
+                       
+                               olympic_priv->srb_queued = 2 ; 
+                               writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);     
+
+                               olympic_priv->olympic_multicast_set = 0 ; 
+                       }
+               }               
+
+       }
+
+
+}
+
+static void olympic_srb_bh(struct device *dev) 
+{ 
+       struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+       __u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
+       __u8 *srb;
+
+       writel(olympic_priv->srb,olympic_mmio+LAPA);
+       srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+
+       switch (readb(srb)) { 
+
+               /* SRB_MODIFY_RECEIVE_OPTIONS i.e. set_multicast_list options (promiscuous) 
+                 * At some point we should do something if we get an error, such as
+                 * resetting the IFF_PROMISC flag in dev
+                */
+
+               case SRB_MODIFY_RECEIVE_OPTIONS:
+                       switch (readb(srb+2)) { 
+                               case 0x01:
+                                       printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name) ; 
+                                       break ; 
+                               case 0x04:
+                                       printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name);
+                                       break ; 
+                               default:
+                                       if (olympic_priv->olympic_message_level) 
+                                               printk(KERN_WARNING "%s: Receive Options Modified to %x,%x\n",dev->name,olympic_priv->olympic_copy_all_options, olympic_priv->olympic_receive_options) ; 
+                                       break ;         
+                       } /* switch srb[2] */ 
+                       break ;
+               
+               /* SRB_SET_GROUP_ADDRESS - Multicast group setting 
+                 */
+
+               case SRB_SET_GROUP_ADDRESS:
+                       switch (readb(srb+2)) { 
+                               case 0x00:
+                                       olympic_priv->olympic_multicast_set = 1 ; 
+                                       break ; 
+                               case 0x01:
+                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       break ;
+                               case 0x04:
+                                       printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); 
+                                       break ;
+                               case 0x3c:
+                                       printk(KERN_WARNING "%s: Group/Functional address indicator bits not set correctly\n",dev->name) ; 
+                                       break ;
+                               case 0x3e: /* If we ever implement individual multicast addresses, will need to deal with this */
+                                       printk(KERN_WARNING "%s: Group address registers full\n",dev->name) ; 
+                                       break ;  
+                               case 0x55:
+                                       printk(KERN_INFO "%s: Group Address already set.\n",dev->name) ; 
+                                       break ;
+                               default:
+                                       break ; 
+                       } /* switch srb[2] */ 
+                       break ; 
+
+               /* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list
+                */
+
+               case SRB_RESET_GROUP_ADDRESS:
+                       switch (readb(srb+2)) { 
+                               case 0x00:
+                                       olympic_priv->olympic_multicast_set = 0 ; 
+                                       break ; 
+                               case 0x01:
+                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       break ; 
+                               case 0x04:
+                                       printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+                                       break ; 
+                               case 0x39: /* Must deal with this if individual multicast addresses used */
+                                       printk(KERN_INFO "%s: Group address not found \n",dev->name); 
+                                       break ;
+                               default:
+                                       break ; 
+                       } /* switch srb[2] */
+                       break ; 
+
+               
+               /* SRB_SET_FUNC_ADDRESS - Called by the set_rx_mode 
+                */
+
+               case SRB_SET_FUNC_ADDRESS:
+                       switch (readb(srb+2)) { 
+                               case 0x00:
+                                       if (olympic_priv->olympic_message_level)
+                                               printk(KERN_INFO "%s: Functional Address Mask Set \n",dev->name) ; 
+                                       break ;
+                               case 0x01:
+                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       break ; 
+                               case 0x04:
+                                       printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+                                       break ; 
+                               default:
+                                       break ; 
+                       } /* switch srb[2] */
+                       break ; 
+       
+               /* SRB_READ_LOG - Read and reset the adapter error counters
+                */
+
+               case SRB_READ_LOG:
+                       switch (readb(srb+2)) { 
+                               case 0x00: 
+                                       if (olympic_priv->olympic_message_level) 
+                                               printk(KERN_INFO "%s: Read Log issued\n",dev->name) ; 
+                                       break ; 
+                               case 0x01:
+                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       break ; 
+                               case 0x04:
+                                       printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+                                       break ; 
+                       
+                       } /* switch srb[2] */
+                       break ; 
+               
+               /* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */
+
+               case SRB_READ_SR_COUNTERS:
+                       switch (readb(srb+2)) { 
+                               case 0x00: 
+                                       if (olympic_priv->olympic_message_level) 
+                                               printk(KERN_INFO "%s: Read Source Routing Counters issued\n",dev->name) ; 
+                                       break ; 
+                               case 0x01:
+                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       break ; 
+                               case 0x04:
+                                       printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+                                       break ; 
+                               default:
+                                       break ; 
+                       } /* switch srb[2] */
+                       break ;
+               default:
+                       printk(KERN_WARNING "%s: Unrecognized srb bh return value.\n",dev->name);
+                       break ; 
+       } /* switch srb[0] */
+
+} 
+
+static struct net_device_stats * olympic_get_stats(struct device *dev)
+{
+       struct olympic_private *olympic_priv ;
+       olympic_priv=(struct olympic_private *) dev->priv;
+       return (struct net_device_stats *) &olympic_priv->olympic_stats; 
+}
+
+static int olympic_set_mac_address (struct device *dev, void *addr) 
+{
+       struct sockaddr *saddr = addr ; 
+       struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; 
+
+       if (dev->start) { 
+               printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; 
+               return -EIO ; 
+       }
+
+       memcpy(olympic_priv->olympic_laa, saddr->sa_data,dev->addr_len) ; 
+       
+       if (olympic_priv->olympic_message_level) { 
+               printk(KERN_INFO "%s: MAC/LAA Set to  = %x.%x.%x.%x.%x.%x\n",dev->name, olympic_priv->olympic_laa[0],
+               olympic_priv->olympic_laa[1], olympic_priv->olympic_laa[2],
+               olympic_priv->olympic_laa[3], olympic_priv->olympic_laa[4],
+               olympic_priv->olympic_laa[5]);
+       } 
+
+       return 0 ; 
+}
+
+static void olympic_arb_cmd(struct device *dev)
+{
+       struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+       __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+       __u8 *arb_block, *asb_block, *srb  ; 
+       __u8 header_len ; 
+       __u16 frame_len, buffer_len ;
+       struct sk_buff *mac_frame ;  
+       __u8 *buf_ptr ;
+       __u8 *frame_data ;  
+       __u16 buff_off ; 
+       __u16 lan_status = 0, lan_status_diff  ; /* Initialize to stop compiler warning */
+       __u8 fdx_prot_error ; 
+       __u16 next_ptr;
+
+#if OLYMPIC_NETWORK_MONITOR
+       struct trh_hdr *mac_hdr ; 
+#endif
+
+       arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
+       asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
+       srb = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
+       writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO);
+
+       if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
+
+               header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */  
+               frame_len = ntohs(readw(arb_block + 10)) ; 
+
+               buff_off = ntohs(readw(arb_block + 6)) ;
+               
+               buf_ptr = olympic_priv->olympic_lap + buff_off ; 
+
+#if OLYMPIC_DEBUG
+{
+               int i;
+               frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; 
+
+               for (i=0 ;  i < 14 ; i++) { 
+                       printk("Loc %d = %02x\n",i,readb(frame_data + i)); 
+               }
+
+               printk("next %04x, fs %02x, len %04x \n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
+}
+#endif 
+               mac_frame = dev_alloc_skb(frame_len) ; 
+
+               /* Walk the buffer chain, creating the frame */
+
+               do {
+                       frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; 
+                       buffer_len = ntohs(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
+                       memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ;
+                       next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); 
+
+               } while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr)));
+
+#if OLYMPIC_NETWORK_MONITOR
+               printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
+               mac_hdr = (struct trh_hdr *)mac_frame->data ; 
+               printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; 
+               printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; 
+#endif
+               mac_frame->dev = dev ; 
+               mac_frame->protocol = tr_type_trans(mac_frame,dev);
+               netif_rx(mac_frame) ;   
+
+               /* Now tell the card we have dealt with the received frame */
+
+               /* Set LISR Bit 1 */
+               writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM);
+
+               /* Is the ASB free ? */         
+               
+               if (!(readl(olympic_priv->olympic_mmio + SISR) & SISR_ASB_FREE)) {
+                       olympic_priv->asb_queued = 1 ; 
+                       writel(LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); 
+                       return ;        
+                       /* Drop out and wait for the bottom half to be run */
+               }
+               
+               writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */
+               writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */
+               writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */
+               writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */                
+
+               writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM);
+               
+               olympic_priv->asb_queued = 2 ; 
+       
+               return ;        
+               
+       } else if (readb(arb_block) == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */
+               lan_status = readw(arb_block+6);
+               fdx_prot_error = readb(arb_block+8) ; 
+               
+               /* Issue ARB Free */
+               writel(LISR_ARB_FREE,olympic_priv->olympic_mmio+LISR_SUM);
+
+               lan_status_diff = olympic_priv->olympic_lan_status ^ lan_status ; 
+
+               if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { 
+                       if (lan_status_diff & LSC_LWF) 
+                                       printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name);
+                       if (lan_status_diff & LSC_ARW) 
+                                       printk(KERN_WARNING "%s: Auto removal error\n",dev->name);
+                       if (lan_status_diff & LSC_FPE)
+                                       printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name);
+                       if (lan_status_diff & LSC_RR) 
+                                       printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name);
+               
+                       /* Adapter has been closed by the hardware */
+               
+                       /* reset tx/rx fifo's and busmaster logic */
+
+                       writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
+                       udelay(1);
+                       writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
+                       dev->tbusy = 1 ;
+                       dev->interrupt = 1 ; 
+                       dev->start = 0 ; 
+                       olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; 
+                       free_irq(dev->irq,dev);
+                       
+                       printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; 
+       
+               } /* If serious error */
+               
+               if (olympic_priv->olympic_message_level) { 
+                       if (lan_status_diff & LSC_SIG_LOSS) 
+                                       printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; 
+                       if (lan_status_diff & LSC_HARD_ERR)
+                                       printk(KERN_INFO "%s: Beaconing \n",dev->name);
+                       if (lan_status_diff & LSC_SOFT_ERR)
+                                       printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name);
+                       if (lan_status_diff & LSC_TRAN_BCN) 
+                                       printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name);
+                       if (lan_status_diff & LSC_SS) 
+                                       printk(KERN_INFO "%s: Single Station on the ring \n", dev->name);
+                       if (lan_status_diff & LSC_RING_REC)
+                                       printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name);
+                       if (lan_status_diff & LSC_FDX_MODE)
+                                       printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name);
+               }       
+               
+               if (lan_status_diff & LSC_CO) { 
+                                       
+                               if (olympic_priv->olympic_message_level) 
+                                       printk(KERN_INFO "%s: Counter Overflow \n", dev->name);
+                                       
+                               /* Issue READ.LOG command */
+
+                               writeb(SRB_READ_LOG, srb);
+                               writeb(0,srb+1);
+                               writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+                               writeb(0,srb+3);
+                               writeb(0,srb+4);
+                               writeb(0,srb+5);
+                                       
+                               olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+                               writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+                                       
+               }
+
+               if (lan_status_diff & LSC_SR_CO) { 
+
+                               if (olympic_priv->olympic_message_level)
+                                       printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name);
+
+                               /* Issue a READ.SR.COUNTERS */
+                               
+                               writeb(SRB_READ_SR_COUNTERS,srb);
+                               writeb(0,srb+1);
+                               writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+                               writeb(0,srb+3);
+                               
+                               olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+                               writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+               }
+
+               olympic_priv->olympic_lan_status = lan_status ; 
+       
+       }  /* Lan.change.status */
+       else
+               printk(KERN_WARNING "%s: Unknown arb command \n", dev->name);
+}
+
+static void olympic_asb_bh(struct device *dev) 
+{
+       struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+       __u8 *arb_block, *asb_block ; 
+
+       arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
+       asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
+
+       if (olympic_priv->asb_queued == 1) {   /* Dropped through the first time */
+
+               writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */
+               writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */
+               writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */
+               writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */                
+
+               writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM);
+               olympic_priv->asb_queued = 2 ; 
+
+               return ; 
+       }
+
+       if (olympic_priv->asb_queued == 2) { 
+               switch (readb(asb_block+2)) {
+                       case 0x01:
+                               printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name);
+                               break ;
+                       case 0x26:
+                               printk(KERN_WARNING "%s: Unrecognized buffer address \n", dev->name);
+                               break ;
+                       case 0xFF:
+                               /* Valid response, everything should be ok again */
+                               break ;
+                       default:
+                               printk(KERN_WARNING "%s: Invalid return code in asb\n",dev->name);
+                               break ;
+               }
+       }
+       olympic_priv->asb_queued = 0 ; 
+}
+static int olympic_change_mtu(struct device *dev, int mtu) 
+{
+       struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+       __u16 max_mtu ; 
+
+       if (olympic_priv->olympic_ring_speed == 4)
+               max_mtu = 4500 ; 
+       else
+               max_mtu = 18000 ; 
+       
+       if (mtu > max_mtu)
+               return -EINVAL ; 
+       if (mtu < 100) 
+               return -EINVAL ; 
+
+       dev->mtu = mtu ; 
+       olympic_priv->pkt_buf_sz = mtu + TR_HLEN ; 
+
+       return 0 ; 
+}
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+       struct pci_dev *pci_device = NULL ;
+       int len=0;
+       off_t begin=0;
+       off_t pos=0;
+       int size;
+       
+       struct device *dev;
+
+
+       size = sprintf(buffer, 
+               "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapters\n");
+       
+       pos+=size;
+       len+=size;
+       
+
+       while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
+       
+               for (dev = dev_base; dev != NULL; dev = dev->next) 
+               {
+                       if (dev->base_addr == (pci_device->base_address[0] & (~3)) ) { /* Yep, an Olympic device */     
+                               size = sprintf_info(buffer+len, dev);
+                               len+=size;
+                               pos=begin+len;
+                               
+                               if(pos<offset)
+                               {
+                                       len=0;
+                                       begin=pos;
+                               }
+                               if(pos>offset+length)
+                                       break;
+                       } /* if */
+               } /* for */
+       } /* While */
+
+       *start=buffer+(offset-begin);   /* Start of wanted data */
+       len-=(offset-begin);            /* Start slop */
+       if(len>length)
+               len=length;             /* Ending slop */
+       return len;
+}
+
+static int sprintf_info(char *buffer, struct device *dev)
+{
+       struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+       __u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+       __u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+       int size = 0 ; 
+               
+       size = sprintf(buffer, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n",
+          dev->name); 
+
+       size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
+          dev->name,
+           dev->dev_addr[0],
+          dev->dev_addr[1],
+          dev->dev_addr[2],
+          dev->dev_addr[3],
+          dev->dev_addr[4],
+          dev->dev_addr[5],
+          readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
+          readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
+          readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
+          readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
+          readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
+          readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5),
+          readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
+          readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
+          readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
+          readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
+        
+       size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name);
+
+       size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address   : Poll Address      : AccPri : Auth Src : Att Code :\n",
+         dev->name) ; 
+          
+       size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x   : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x   : %04x     :  %04x    :\n",
+         dev->name,
+         readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
+         readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
+         readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2),
+         readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3),
+         readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
+         readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
+         readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
+         readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
+         readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
+         readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5),
+         readb(opt+offsetof(struct olympic_parameters_table, poll_addr)),
+         readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1),
+         readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2),
+         readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3),
+         readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4),
+         readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
+
+       size += sprintf(buffer+size, "%6s: Source Address    : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
+         dev->name) ; 
+       
+       size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
+         dev->name,
+         readb(opt+offsetof(struct olympic_parameters_table, source_addr)),
+         readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1),
+         readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2),
+         readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3),
+         readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4),
+         readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, lan_status))),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, local_ring))),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, mon_error))),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, frame_correl))));
+
+       size += sprintf(buffer+size, "%6s: Beacon Details :  Tx  :  Rx  : NAUN Node Address : NAUN Node Phys : \n",
+         dev->name) ; 
+
+       size += sprintf(buffer+size, "%6s:                :  %02x  :  %02x  : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x    : \n",
+         dev->name,
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
+         ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
+         readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3));
+
+       return size;
+}
+#endif
+#endif 
+
+#ifdef MODULE
+
+static struct device* dev_olympic[OLYMPIC_MAX_ADAPTERS];
+
+int init_module(void)
+{
+        int i;
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *ent ; 
+
+       ent = create_proc_entry("net/olympic_tr",0,0); 
+       ent->read_proc = &olympic_proc_info ; 
+#endif
+#endif
+        for (i = 0; (i<OLYMPIC_MAX_ADAPTERS); i++) {
+               dev_olympic[i] = NULL;
+                dev_olympic[i] = init_trdev(dev_olympic[i], 0);
+                if (dev_olympic[i] == NULL)
+                        return -ENOMEM;
+
+               dev_olympic[i]->init      = &olympic_probe;
+
+               if (register_trdev(dev_olympic[i]) != 0) {
+                       kfree_s(dev_olympic[i], sizeof(struct device));
+                       dev_olympic[i] = NULL;
+                       if (i == 0) {
+                               printk("Olympic: No IBM PCI Token Ring cards found in system.\n");
+                               return -EIO;
+                       } else {
+                               printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; 
+                               return 0;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void cleanup_module(void)
+{
+        int i;
+
+        for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++)
+               if (dev_olympic[i]) {
+                        unregister_trdev(dev_olympic[i]);
+                        release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE);
+                        kfree_s(dev_olympic[i]->priv, sizeof(struct olympic_private));
+                        kfree_s(dev_olympic[i], sizeof(struct device));
+                        dev_olympic[i] = NULL;
+                }
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry("net/olympic_tr", NULL) ; 
+#endif 
+#endif
+}
+#endif /* MODULE */
+
diff --git a/drivers/net/olympic.h b/drivers/net/olympic.h
new file mode 100644 (file)
index 0000000..6f98b3b
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ *  olympic.h (c) 1999 Peter De Schrijver All Rights Reserved
+ *                1999 Mike Phillips (phillim@amtrak.com)
+ *
+ *  Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset.
+ *
+ *  Base Driver Skeleton:
+ *      Written 1993-94 by Donald Becker.
+ *
+ *      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.
+ */
+
+#define CID 0x4e
+
+#define BCTL 0x70
+#define BCTL_SOFTRESET (1<<15)
+#define BCTL_MIMREB (1<<6)
+
+#define GPR 0x4a
+#define GPR_OPTI_BF (1<<6)
+#define GPR_NEPTUNE_BF (1<<4) 
+#define GPR_AUTOSENSE (1<<2)
+#define GPR_16MBPS (1<<3) 
+
+#define PAG 0x85
+#define LBC 0x8e
+
+#define LISR 0x10
+#define LISR_SUM 0x14
+#define LISR_RWM 0x18
+
+#define LISR_LIE (1<<15)
+#define LISR_SLIM (1<<13)
+#define LISR_SLI (1<<12)
+#define LISR_PCMSRMASK (1<<11)
+#define LISR_PCMSRINT (1<<10)
+#define LISR_WOLMASK (1<<9)
+#define LISR_WOL (1<<8)
+#define LISR_SRB_CMD (1<<5)
+#define LISR_ASB_REPLY (1<<4)
+#define LISR_ASB_FREE_REQ (1<<2)
+#define LISR_ARB_FREE (1<<1)
+#define LISR_TRB_FRAME (1<<0)
+
+#define SISR 0x20
+#define SISR_SUM 0x24
+#define SISR_RWM 0x28
+#define SISR_RR 0x2C
+#define SISR_RESMASK 0x30
+#define SISR_MASK 0x54
+#define SISR_MASK_SUM 0x58
+#define SISR_MASK_RWM 0x5C
+
+#define SISR_TX2_IDLE (1<<31)
+#define SISR_TX2_HALT (1<<29)
+#define SISR_TX2_EOF (1<<28)
+#define SISR_TX1_IDLE (1<<27)
+#define SISR_TX1_HALT (1<<25)
+#define SISR_TX1_EOF (1<<24)
+#define SISR_TIMEOUT (1<<23)
+#define SISR_RX_NOBUF (1<<22)
+#define SISR_RX_STATUS (1<<21)
+#define SISR_RX_HALT (1<<18)
+#define SISR_RX_EOF_EARLY (1<<16)
+#define SISR_MI (1<<15)
+#define SISR_PI (1<<13)
+#define SISR_ERR (1<<9)
+#define SISR_ADAPTER_CHECK (1<<6)
+#define SISR_SRB_REPLY (1<<5)
+#define SISR_ASB_FREE (1<<4)
+#define SISR_ARB_CMD (1<<3)
+#define SISR_TRB_REPLY (1<<2)
+
+#define EISR 0x34
+#define EISR_RWM 0x38
+#define EISR_MASK 0x3c
+
+#define LAPA 0x60
+#define LAPWWO 0x64
+#define LAPWWC 0x68
+#define LAPCTL 0x6C
+#define LAIPD 0x78
+#define LAIPDDINC 0x7C
+
+#define TIMER 0x50
+
+#define CLKCTL 0x74
+
+#define PM_CON 0x4
+
+#define BMCTL_SUM 0x40
+#define BMCTL_RWM 0x44
+#define BMCTL_TX2_DIS (1<<30) 
+#define BMCTL_TX1_DIS (1<<26) 
+#define BMCTL_RX_DIS (1<<22) 
+
+#define BMASR 0xcc
+
+#define RXDESCQ 0x90
+#define RXDESCQCNT 0x94
+#define RXCDA 0x98
+#define RXENQ 0x9C
+#define RXSTATQ 0xA0
+#define RXSTATQCNT 0xA4
+#define RXCSA 0xA8
+#define RXCLEN 0xAC
+#define RXHLEN 0xAE
+
+#define TXDESCQ_1 0xb0
+#define TXDESCQ_2 0xd0
+#define TXDESCQCNT_1 0xb4
+#define TXDESCQCNT_2 0xd4
+#define TXCDA_1 0xb8
+#define TXCDA_2 0xd8
+#define TXENQ_1 0xbc
+#define TXENQ_2 0xdc
+#define TXSTATQ_1 0xc0
+#define TXSTATQ_2 0xe0
+#define TXSTATQCNT_1 0xc4
+#define TXSTATQCNT_2 0xe4
+#define TXCSA_1 0xc8
+#define TXCSA_2 0xe8
+
+#define OLYMPIC_IO_SPACE 256
+
+#define SRB_COMMAND_SIZE 50
+
+#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */
+
+/* Defines for LAN STATUS CHANGE reports */
+#define LSC_SIG_LOSS 0x8000
+#define LSC_HARD_ERR 0x4000
+#define LSC_SOFT_ERR 0x2000
+#define LSC_TRAN_BCN 0x1000
+#define LSC_LWF      0x0800
+#define LSC_ARW      0x0400
+#define LSC_FPE      0x0200
+#define LSC_RR       0x0100
+#define LSC_CO       0x0080
+#define LSC_SS       0x0040
+#define LSC_RING_REC 0x0020
+#define LSC_SR_CO    0x0010
+#define LSC_FDX_MODE 0x0004
+
+/* Defines for OPEN ADAPTER command */
+
+#define OPEN_ADAPTER_EXT_WRAP (1<<15)
+#define OPEN_ADAPTER_DIS_HARDEE (1<<14)
+#define OPEN_ADAPTER_DIS_SOFTERR (1<<13)
+#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12)
+#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11)
+#define OPEN_ADAPTER_ENABLE_EC (1<<10)
+#define OPEN_ADAPTER_CONTENDER (1<<8)
+#define OPEN_ADAPTER_PASS_BEACON (1<<7)
+#define OPEN_ADAPTER_ENABLE_FDX (1<<6)
+#define OPEN_ADAPTER_ENABLE_RPL (1<<5)
+#define OPEN_ADAPTER_INHIBIT_ETR (1<<4)
+#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3)
+#define OPEN_ADAPTER_USE_OPTS2 (1<<0)
+
+#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15)
+
+/* Defines for SRB Commands */
+
+#define SRB_ACCESS_REGISTER 0x1f
+#define SRB_CLOSE_ADAPTER 0x04
+#define SRB_CONFIGURE_BRIDGE 0x0c
+#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a
+#define SRB_MODIFY_BRIDGE_PARMS 0x15
+#define SRB_MODIFY_OPEN_OPTIONS 0x01
+#define SRB_MODIFY_RECEIVE_OPTIONS 0x17
+#define SRB_NO_OPERATION 0x00
+#define SRB_OPEN_ADAPTER 0x03
+#define SRB_READ_LOG 0x08
+#define SRB_READ_SR_COUNTERS 0x16
+#define SRB_RESET_GROUP_ADDRESS 0x02
+#define SRB_SAVE_CONFIGURATION 0x1b
+#define SRB_SET_BRIDGE_PARMS 0x09
+#define SRB_SET_BRIDGE_TARGETS 0x10
+#define SRB_SET_FUNC_ADDRESS 0x07
+#define SRB_SET_GROUP_ADDRESS 0x06
+#define SRB_SET_GROUP_ADDR_OPTIONS 0x11
+#define SRB_UPDATE_WAKEUP_PATTERN 0x19
+
+/* Clear return code */
+
+#define OLYMPIC_CLEAR_RET_CODE 0xfe 
+
+/* ARB Commands */
+#define ARB_RECEIVE_DATA 0x81
+#define ARB_LAN_CHANGE_STATUS 0x84
+/* ASB Response commands */
+
+#define ASB_RECEIVE_DATA 0x81
+
+
+/* Olympic defaults for buffers */
+#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */
+#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */
+
+#define PKT_BUF_SZ 4096 /* Default packet size */
+
+/* Olympic data structures */
+
+struct olympic_tx_desc {
+       __u32 buffer;
+       __u32 status_length;
+};
+
+struct olympic_tx_status {
+       __u32 status;
+};
+
+struct olympic_rx_desc {
+       __u32 buffer;
+       __u32 res_length ; 
+};
+
+struct olympic_rx_status {
+       __u32 fragmentcnt_framelen;
+       __u32 status_buffercnt;
+};
+
+struct mac_receive_buffer {
+       __u16 next ; 
+       __u8 padding ; 
+       __u8 frame_status ;
+       __u16 buffer_length ; 
+       __u8 frame_data ; 
+};
+
+struct olympic_private {
+       
+       __u16 srb;
+       __u16 trb;
+       __u16 arb;
+       __u16 asb;
+
+       __u8 *olympic_mmio;
+       __u8 *olympic_lap;
+
+       volatile int srb_queued;    /* True if an SRB is still posted */        
+       wait_queue_head_t srb_wait;
+
+       volatile int asb_queued;    /* True if an ASB is posted */
+
+       volatile int trb_queued;   /* True if a TRB is posted */
+       wait_queue_head_t trb_wait ; 
+
+       struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE];
+       struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE];
+       struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE];  
+       struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE];  
+       struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE];  
+       int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries;
+
+       struct net_device_stats olympic_stats ;
+       __u16 olympic_lan_status ;
+       __u8 olympic_ring_speed ;
+       __u16 pkt_buf_sz ; 
+       __u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level;  
+       __u8 olympic_multicast_set ; 
+       __u16 olympic_addr_table_addr, olympic_parms_addr ; 
+       __u8 olympic_laa[6] ; 
+};
+
+struct olympic_adapter_addr_table {
+
+       __u8 node_addr[6] ; 
+       __u8 reserved[4] ; 
+       __u8 func_addr[4] ; 
+} ; 
+
+struct olympic_parameters_table { 
+       
+       __u8  phys_addr[4] ; 
+       __u8  up_node_addr[6] ; 
+       __u8  up_phys_addr[6] ; 
+       __u8  poll_addr[6] ; 
+       __u16 reserved ; 
+       __u16 acc_priority ; 
+       __u16 auth_source_class ; 
+       __u16 att_code ; 
+       __u8  source_addr[6] ; 
+       __u16 beacon_type ; 
+       __u16 major_vector ; 
+       __u16 lan_status ; 
+       __u16 soft_error_time ; 
+       __u16 reserved1 ; 
+       __u16 local_ring ; 
+       __u16 mon_error ; 
+       __u16 beacon_transmit ; 
+       __u16 beacon_receive ; 
+       __u16 frame_correl ; 
+       __u8  beacon_naun[6] ; 
+       __u32 reserved2 ; 
+       __u8  beacon_phys[4] ;  
+}; 
index ab73353ac2f58c1a6d9eb921541bae6b40965777..42514f2bda9d6ef0ecfba33be1f4ad0d5bb8c4e9 100644 (file)
@@ -60,7 +60,6 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>       /* to get the struct task_struct */
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
 #include <asm/system.h>
index 21f69fa3bc84f99728dfb6028d404654056daf3c..d8a5b63b74c0f0dd9a045473a68114b4a9b25388 100644 (file)
@@ -1,6 +1,6 @@
 /* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
 /*
-       Written 1997-1998 by Donald Becker.
+       Written 1997-1999 by Donald Becker.
 
        This software may be used and distributed according to the terms
        of the GNU Public License, incorporated herein by reference.
        Support and updates available at
        http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
 
-       Twister-tuning code contributed by Kinston <shangh@realtek.com.tw>.
+       Twister-tuning table provided by Kinston <shangh@realtek.com.tw>.
 */
 
 static const char *version =
-"rtl8139.c:v1.04 9/22/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+"rtl8139.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
 
 /* A few user-configurable values. */
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
@@ -178,7 +178,9 @@ static struct pci_id_info pci_tbl[] =
    0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
  { "RealTek RTL8139 Fast Ethernet",
    0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
- { "RealTek RTL8139 Fast Ethernet (mislabeled)",
+ { "SMC1211TX EZCard 10/100 (RealTek RTL8139)",
+   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+ { "Accton MPX5030 (RealTek RTL8139)",
    0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
  {0,},                                         /* 0 terminated list. */
 };
@@ -235,13 +237,13 @@ enum RxStatusBits {
        RxBadAlign=0x0002, RxStatusOK=0x0001,
 };
 
+/* Twister tuning parameters from RealTek.
+   Completely undocumented, but required to tune bad links. */
 enum CSCRBits {
        CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
        CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
        CSCR_LinkDownCmd=0x0f3c0,
-};     
-
-/* Twister tuning parameters from RealTek.  Completely undocumented. */
+};
 unsigned long param[4][4]={
        {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
        {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
@@ -270,9 +272,10 @@ struct rtl8129_private {
        unsigned char *rx_ring;
        unsigned char *tx_bufs;                         /* Tx bounce buffer region. */
        char phys[4];                                           /* MII device addresses. */
+       char twistie, twist_cnt;                        /* Twister tune state. */
        unsigned int tx_full:1;                         /* The Tx queue is full. */
        unsigned int full_duplex:1;                     /* Full-duplex operation requested. */
-       unsigned int duplex_lock:1;                     /* Full-duplex operation requested. */
+       unsigned int duplex_lock:1;
        unsigned int default_port:4;            /* Last dev->if_port value. */
        unsigned int media2:4;                          /* Secondary monitored media port. */
        unsigned int medialock:1;                       /* Don't sense media type. */
@@ -325,7 +328,7 @@ int rtl8139_probe(struct device *dev)
        if ( ! pcibios_present())
                return -ENODEV;
 
-       for (;pci_index < 0xff; pci_index++) {
+       for (; pci_index < 0xff; pci_index++) {
                u16 vendor, device, pci_command, new_command;
                int chip_idx, irq;
                long ioaddr;
@@ -402,9 +405,9 @@ int rtl8139_probe(struct device *dev)
        return cards_found ? 0 : -ENODEV;
 }
 
-static struct device * rtl8129_probe1(int pci_bus, int pci_devfn,
-                                                                         struct device *dev, long ioaddr,
-                                                                         int irq, int chip_idx, int found_cnt)
+static struct device *rtl8129_probe1(int pci_bus, int pci_devfn,
+                                                                        struct device *dev, long ioaddr,
+                                                                        int irq, int chip_idx, int found_cnt)
 {
        static int did_version = 0;                     /* Already printed version info. */
        struct rtl8129_private *tp;
@@ -470,9 +473,8 @@ static struct device * rtl8129_probe1(int pci_bus, int pci_devfn,
                                   dev->name);
                        tp->phys[0] = -1;
                }
-       } else {
-                       tp->phys[0] = 32;
-       }
+       } else
+               tp->phys[0] = 32;
 
        /* Put the chip into low-power mode. */
        outb(0xC0, ioaddr + Cfg9346);
@@ -601,7 +603,7 @@ static int mdio_read(struct device *dev, int phy_id, int location)
        int retval = 0;
        int i;
 
-       if ((phy_id & 0x1f) == 0) {     /* Really a 8139.  Use internal registers. */
+       if (phy_id > 31) {      /* Really a 8139.  Use internal registers. */
                return location < 8 && mii_2_8139_map[location] ?
                        inw(dev->base_addr + mii_2_8139_map[location]) : 0;
        }
@@ -633,7 +635,7 @@ static void mdio_write(struct device *dev, int phy_id, int location, int value)
        int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
        int i;
 
-       if (phy_id == 32) {                     /* Really a 8139.  Use internal registers. */
+       if (phy_id > 31) {      /* Really a 8139.  Use internal registers. */
                if (location < 8  &&  mii_2_8139_map[location])
                        outw(value, dev->base_addr + mii_2_8139_map[location]);
                return;
@@ -736,7 +738,7 @@ rtl8129_open(struct device *dev)
 
        /* Enable all known interrupts by setting the interrupt mask. */
        outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-               | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
+                | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
 
        if (rtl8129_debug > 1)
                printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
@@ -749,7 +751,7 @@ rtl8129_open(struct device *dev)
        init_timer(&tp->timer);
        tp->timer.expires = RUN_AT((24*HZ)/10);                 /* 2.4 sec. */
        tp->timer.data = (unsigned long)dev;
-       tp->timer.function = &rtl8129_timer;                            /* timer handler */
+       tp->timer.function = &rtl8129_timer;
        add_timer(&tp->timer);
 
        return 0;
@@ -760,7 +762,7 @@ static void rtl8129_timer(unsigned long data)
        struct device *dev = (struct device *)data;
        struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
        long ioaddr = dev->base_addr;
-       int next_tick = 0;
+       int next_tick = 60*HZ;
        int mii_reg5 = mdio_read(dev, tp->phys[0], 5);
 
        if (! tp->duplex_lock  &&  mii_reg5 != 0xffff) {
@@ -774,8 +776,65 @@ static void rtl8129_timer(unsigned long data)
                        outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
                        outb(0x00, ioaddr + Cfg9346);
                }
-               next_tick = 60*HZ;
        }
+       /* Check for bogusness. */
+       if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
+               int status = inw(ioaddr + IntrStatus);
+               if (status & (TxOK | RxOK)) {   /* Double check */
+                       printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n",
+                                  dev->name, status);
+                       rtl8129_interrupt(dev->irq, dev, 0);
+               }
+       }
+       if (dev->tbusy  &&  jiffies - dev->trans_start >= 2*TX_TIMEOUT)
+               rtl8129_tx_timeout(dev);
+
+#if 0
+       if (tp->twistie) {
+               unsigned int CSCRval = inw(ioaddr + CSCR);              /* Read link status. */
+               if (tp->twistie == 1) {
+                       if (CSCRval & CSCR_LinkOKBit) {
+                               outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);
+                               tp->twistie = 2;
+                               next_tick = HZ/10;
+                       } else {
+                               outw(CSCR_LinkDownCmd, ioaddr + CSCR);
+                               outl(FIFOTMS_default,ioaddr + FIFOTMS);
+                               outl(PARA78_default ,ioaddr + PARA78);
+                               outl(PARA7c_default ,ioaddr + PARA7c);
+                               tp->twistie = 0;
+                       }
+               } else if (tp->twistie == 2) {
+                       int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12;
+                       int row;
+                       if (linkcase >= 0x7000) row = 3;
+                       else if (linkcase >= 0x3000) row = 2;
+                       else if (linkcase >= 0x1000) row = 1;
+                       else row = 0;
+                       tp->twistie == row + 3;
+                       outw(0,ioaddr+FIFOTMS);
+                       outl(param[row][0], ioaddr+PARA7c);
+                       tp->twist_cnt = 1;
+               } else {
+                       outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c);
+                       if (++tp->twist_cnt < 4) {
+                               next_tick = HZ/10;
+                       } else if (tp->twistie-3 == 3) {
+                               if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) {
+                                       outl(PARA7c_xxx, ioaddr+PARA7c);
+                                       next_tick = HZ/10;              /* 100ms. */
+                                       outl(FIFOTMS_default, ioaddr+FIFOTMS);
+                                       outl(PARA78_default,  ioaddr+PARA78);
+                                       outl(PARA7c_default,  ioaddr+PARA7c);
+                                       tp->twistie == 3 + 3;
+                                       outw(0,ioaddr+FIFOTMS);
+                                       outl(param[3][0], ioaddr+PARA7c);
+                                       tp->twist_cnt = 1;
+                               }
+                       }
+               }
+       }
+#endif
 
        if (rtl8129_debug > 2) {
                if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)
@@ -792,10 +851,8 @@ static void rtl8129_timer(unsigned long data)
                           dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
        }
 
-       if (next_tick) {
-               tp->timer.expires = RUN_AT(next_tick);
-               add_timer(&tp->timer);
-       }
+       tp->timer.expires = RUN_AT(next_tick);
+       add_timer(&tp->timer);
 }
 
 static void rtl8129_tx_timeout(struct device *dev)
@@ -861,7 +918,7 @@ static void rtl8129_tx_timeout(struct device *dev)
                }
                tp->cur_tx = i;
                while (i < NUM_TX_DESC)
-                       tp->tx_skbuff[i] = 0;
+                       tp->tx_skbuff[i++] = 0;
                if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
                        dev->tbusy = 0;
                        tp->tx_full = 0;
@@ -906,9 +963,8 @@ rtl8129_start_xmit(struct sk_buff *skb, struct device *dev)
        /* Block a timer-based transmit from overlapping.  This could better be
           done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
        if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-               if (jiffies - dev->trans_start < TX_TIMEOUT)
-                       return 1;
-               rtl8129_tx_timeout(dev);
+               if (jiffies - dev->trans_start >= TX_TIMEOUT)
+                       rtl8129_tx_timeout(dev);
                return 1;
        }
 
@@ -925,7 +981,7 @@ rtl8129_start_xmit(struct sk_buff *skb, struct device *dev)
        outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
                 ioaddr + TxStatus0 + entry*4);
 
-       if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
+       if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {        /* Typical path */
                clear_bit(0, (void*)&dev->tbusy);
        } else {
                tp->tx_full = 1;
@@ -946,7 +1002,7 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
        struct device *dev = (struct device *)dev_instance;
        struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
        int boguscnt = max_interrupt_work;
-       int status;
+       int status, link_changed = 0;
        long ioaddr = dev->base_addr;
 
 #if defined(__i386__)
@@ -967,7 +1023,10 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 
        do {
                status = inw(ioaddr + IntrStatus);
-               /* Acknowledge all of the current interrupt sources ASAP. */
+               /* Acknowledge all of the current interrupt sources ASAP, but
+                  an first get an additional status bit from CSCR. */
+               if ((status & RxUnderrun)  &&  inw(ioaddr+CSCR) & CSCR_LinkChangeBit)
+                       link_changed = 1;
                outw(status, ioaddr + IntrStatus);
 
                if (rtl8129_debug > 4)
@@ -982,9 +1041,9 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                        rtl8129_rx(dev);
 
                if (status & (TxOK | TxErr)) {
-                       unsigned int dirty_tx;
+                       unsigned int dirty_tx = tp->dirty_tx;
 
-                       for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {
+                       while (tp->cur_tx - dirty_tx > 0) {
                                int entry = dirty_tx % NUM_TX_DESC;
                                int txstatus = inl(ioaddr + TxStatus0 + entry*4);
 
@@ -994,11 +1053,9 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                /* Note: TxCarrierLost is always asserted at 100mbps. */
                                if (txstatus & (TxOutOfWindow | TxAborted)) {
                                        /* There was an major error, log it. */
-#ifndef final_version
                                        if (rtl8129_debug > 1)
                                                printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",
                                                           dev->name, txstatus);
-#endif
                                        tp->stats.tx_errors++;
                                        if (txstatus&TxAborted) {
                                                tp->stats.tx_aborted_errors++;
@@ -1011,9 +1068,6 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                                tp->stats.collisions16++;
 #endif
                                } else {
-#ifdef ETHER_STATS
-                                       /* No count for tp->stats.tx_deferred */
-#endif
                                        if (txstatus & TxUnderrun) {
                                                /* Add 64 to the Tx FIFO threshold. */
                                                if (tp->tx_flag <  0x00300000)
@@ -1030,6 +1084,13 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                /* Free the original skb. */
                                dev_free_skb(tp->tx_skbuff[entry]);
                                tp->tx_skbuff[entry] = 0;
+                               if (tp->tx_full) {
+                                       /* The ring is no longer full, clear tbusy. */
+                                       tp->tx_full = 0;
+                                       clear_bit(0, (void*)&dev->tbusy);
+                                       mark_bh(NET_BH);
+                               }
+                               dirty_tx++;
                        }
 
 #ifndef final_version
@@ -1039,14 +1100,6 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                dirty_tx += NUM_TX_DESC;
                        }
 #endif
-
-                       if (tp->tx_full  &&  dirty_tx > tp->cur_tx - NUM_TX_DESC) {
-                               /* The ring is no longer full, clear tbusy. */
-                               tp->tx_full = 0;
-                               dev->tbusy = 0;
-                               mark_bh(NET_BH);
-                       }
-
                        tp->dirty_tx = dirty_tx;
                }
 
@@ -1063,7 +1116,7 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                        tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
                        outl(0, ioaddr + RxMissed);
 
-                       if ((status & RxUnderrun)  &&
+                       if ((status & RxUnderrun)  &&  link_changed  &&
                                (rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) {
                                /* Really link-change on new chips. */
                                int lpar = inw(ioaddr + NWayLPAR);
@@ -1284,12 +1337,12 @@ static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                data[0] = tp->phys[0] & 0x3f;
                /* Fall Through */
        case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
-               data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+               data[3] = mdio_read(dev, data[0], data[1] & 0x1f);
                return 0;
        case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
-               if (!suser())
+               if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
-               mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+               mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
                return 0;
        default:
                return -EOPNOTSUPP;
@@ -1318,7 +1371,7 @@ static inline u32 ether_crc(int length, unsigned char *data)
 {
     int crc = -1;
 
-    while(--length >= 0) {
+    while (--length >= 0) {
                unsigned char current_octet = *data++;
                int bit;
                for (bit = 0; bit < 8; bit++, current_octet >>= 1)
diff --git a/drivers/net/sealevel.c b/drivers/net/sealevel.c
new file mode 100644 (file)
index 0000000..03e9082
--- /dev/null
@@ -0,0 +1,471 @@
+#define LINUX_21
+
+/*
+ *     Sealevel Systems 4021 driver.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     (c) Copyright 1999 Building Number Three Ltd
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <net/arp.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+#include "syncppp.h"
+#include "z85230.h"
+
+
+struct slvl_device
+{
+       struct z8530_channel *chan;
+       struct ppp_device netdev;
+       char name[16];
+       int channel;
+};
+
+
+struct slvl_board
+{
+       struct slvl_device dev[2];
+       struct z8530_dev board;
+       int iobase;
+};
+
+/*
+ *     Network driver support routines
+ */
+
+/*
+ *     Frame receive. Simple for our card as we do sync ppp and there
+ *     is no funny garbage involved
+ */
+static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb)
+{
+       /* Drop the CRC - its not a good idea to try and negotiate it ;) */
+       skb_trim(skb, skb->len-2);
+       skb->protocol=htons(ETH_P_WAN_PPP);
+       skb->mac.raw=skb->data;
+       skb->dev=c->netdevice;
+       /*
+        *      Send it to the PPP layer. We dont have time to process
+        *      it right now.
+        */
+       netif_rx(skb);
+}
+/*
+ *     We've been placed in the UP state
+ */ 
+static int sealevel_open(struct device *d)
+{
+       struct slvl_device *slvl=d->priv;
+       int err = -1;
+       int unit = slvl->channel;
+       
+       /*
+        *      Link layer up. 
+        */
+
+       switch(unit)
+       {
+               case 0:
+                       err=z8530_sync_dma_open(d, slvl->chan);
+                       break;
+               case 1:
+                       err=z8530_sync_open(d, slvl->chan);
+                       break;
+       }
+       
+       if(err)
+               return err;
+       /*
+        *      Begin PPP
+        */
+       err=sppp_open(d);
+       if(err)
+       {
+               switch(unit)
+               {
+                       case 0:
+                               z8530_sync_dma_close(d, slvl->chan);
+                               break;
+                       case 1:
+                               z8530_sync_close(d, slvl->chan);
+                               break;
+               }                               
+               return err;
+       }
+       
+       slvl->chan->rx_function=sealevel_input;
+       
+       /*
+        *      Go go go
+        */
+       d->tbusy=0;
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static int sealevel_close(struct device *d)
+{
+       struct slvl_device *slvl=d->priv;
+       int unit = slvl->channel;
+       
+       /*
+        *      Discard new frames
+        */
+       
+       slvl->chan->rx_function=z8530_null_rx;
+               
+       /*
+        *      PPP off
+        */
+       sppp_close(d);
+       /*
+        *      Link layer down
+        */
+       d->tbusy=1;
+       
+       switch(unit)
+       {
+               case 0:
+                       z8530_sync_dma_close(d, slvl->chan);
+                       break;
+               case 1:
+                       z8530_sync_close(d, slvl->chan);
+                       break;
+       }
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int sealevel_ioctl(struct device *d, struct ifreq *ifr, int cmd)
+{
+       /* struct slvl_device *slvl=d->priv;
+          z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */
+       return sppp_do_ioctl(d, ifr,cmd);
+}
+
+static struct enet_statistics *sealevel_get_stats(struct device *d)
+{
+       struct slvl_device *slvl=d->priv;
+       if(slvl)
+               return z8530_get_stats(slvl->chan);
+       else
+               return NULL;
+}
+
+/*
+ *     Passed PPP frames, fire them downwind.
+ */
+static int sealevel_queue_xmit(struct sk_buff *skb, struct device *d)
+{
+       struct slvl_device *slvl=d->priv;
+       return z8530_queue_xmit(slvl->chan, skb);
+}
+
+#ifdef LINUX_21
+static int sealevel_neigh_setup(struct neighbour *n)
+{
+       if (n->nud_state == NUD_NONE) {
+               n->ops = &arp_broken_ops;
+               n->output = n->ops->output;
+       }
+       return 0;
+}
+
+static int sealevel_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+       if (p->tbl->family == AF_INET) {
+               p->neigh_setup = sealevel_neigh_setup;
+               p->ucast_probes = 0;
+               p->mcast_probes = 0;
+       }
+       return 0;
+}
+
+#else
+
+static int return_0(struct device *d)
+{
+       return 0;
+}
+
+#endif
+
+/*
+ *     Description block for a Comtrol Hostess SV11 card
+ */
+static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow)
+{
+       struct z8530_dev *dev;
+       struct slvl_device *sv;
+       struct slvl_board *b;
+       
+       int i;
+       unsigned long flags;
+       int u;
+       
+       /*
+        *      Get the needed I/O space
+        */
+        
+       if(check_region(iobase, 8))
+       {       
+               printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase);
+               return NULL;
+       }
+       request_region(iobase, 8, "Sealevel 4021");
+       
+       b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
+       if(!b)
+               goto fail3;
+                       
+       memset(b, 0, sizeof(*sv));
+
+       b->dev[0].chan = &b->board.chanA;       
+       b->dev[1].chan = &b->board.chanB;
+       
+       dev=&b->board;
+       
+       /*
+        *      Stuff in the I/O addressing
+        */
+        
+       dev->active = 0;
+
+       b->iobase = iobase;
+       
+       /*
+        *      Select 8530 delays for the old board
+        */
+        
+       if(slow)
+               iobase |= Z8530_PORT_SLEEP;
+               
+       dev->chanA.ctrlio=iobase+1;
+       dev->chanA.dataio=iobase;
+       dev->chanB.ctrlio=iobase+3;
+       dev->chanB.dataio=iobase+2;
+       
+       dev->chanA.irqs=&z8530_nop;
+       dev->chanB.irqs=&z8530_nop;
+       
+       /*
+        *      Assert DTR enable DMA
+        */
+        
+       outb(3|(1<<7), b->iobase+4);    
+       
+
+       /* We want a fast IRQ for this device. Actually we'd like an even faster
+          IRQ ;) - This is one driver RtLinux is made for */
+   
+       if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0)
+       {
+               printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq);
+               goto fail2;
+       }
+       
+       dev->irq=irq;
+       dev->chanA.private=&b->dev[0];
+       dev->chanB.private=&b->dev[1];
+       dev->chanA.netdevice=&b->dev[0].netdev.dev;
+       dev->chanB.netdevice=&b->dev[1].netdev.dev;
+       dev->chanA.dev=dev;
+       dev->chanB.dev=dev;
+       dev->name=b->dev[0].name;
+
+       dev->chanA.txdma=3;
+       dev->chanA.rxdma=1;
+       if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0)
+               goto fail;
+               
+       if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0)
+               goto dmafail;
+       
+       save_flags(flags);
+       cli();
+       
+       /*
+        *      Begin normal initialise
+        */
+        
+       if(z8530_init(dev)!=0)
+       {
+               printk(KERN_ERR "Z8530 series device not found.\n");
+               goto dmafail2;
+       }
+       if(dev->type==Z85C30)
+       {
+               z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream);
+               z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream);
+       }
+       else
+       {
+               z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230);
+               z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230);
+       }
+
+       /*
+        *      Now we can take the IRQ
+        */
+       
+       restore_flags(flags);
+
+       for(u=0; u<2; u++)
+       {
+               sv=&b->dev[u];
+               sv->channel = u;
+       
+               for(i=0;i<999;i++)
+               {
+                       sprintf(sv->name,"hdlc%d", i);
+                       if(dev_get(sv->name)==NULL)
+                       {
+                               struct device *d=sv->chan->netdevice;
+       
+                               /* 
+                                *      Initialise the PPP components
+                                */
+                               sppp_attach(&sv->netdev);
+                       
+                               /*
+                                *      Local fields
+                                */     
+                               sprintf(sv->name,"hdlc%d", i);
+                               
+                               d->name = sv->name;
+                               d->base_addr = iobase;
+                               d->irq = irq;
+                               d->priv = sv;
+                               d->init = NULL;
+                       
+                               d->open = sealevel_open;
+                               d->stop = sealevel_close;
+                               d->hard_start_xmit = sealevel_queue_xmit;
+                               d->get_stats = sealevel_get_stats;
+                               d->set_multicast_list = NULL;
+                               d->do_ioctl = sealevel_ioctl;
+#ifdef LINUX_21                        
+                               d->neigh_setup = sealevel_neigh_setup_dev;
+                               dev_init_buffers(d);
+#else
+                               d->init = return_0;
+#endif
+                               d->set_mac_address = NULL;
+                       
+                               if(register_netdev(d)==-1)
+                               {
+                                       printk(KERN_ERR "%s: unable to register device.\n",
+                                               sv->name);
+                                       goto fail_unit;
+                               }                               
+
+                               break;
+                       }
+               }
+       }
+       z8530_describe(dev, "I/O", iobase);
+       dev->active=1;
+       return b;
+
+fail_unit:
+       if(u==1)
+               unregister_netdev(b->dev[0].chan->netdevice);
+       
+dmafail2:
+       free_dma(dev->chanA.rxdma);
+dmafail:
+       free_dma(dev->chanA.txdma);
+fail:
+       free_irq(irq, dev);
+fail2:
+       kfree(b);
+fail3:
+       release_region(iobase,8);
+       return NULL;
+}
+
+static void slvl_shutdown(struct slvl_board *b)
+{
+       int u;
+
+       z8530_shutdown(&b->board);
+       
+       for(u=0; u<2; u++)
+       {
+               sppp_detach(&b->dev[u].netdev.dev);
+               unregister_netdev(&b->dev[u].netdev.dev);
+       }
+       
+       free_irq(b->board.irq, &b->board);
+       free_dma(b->board.chanA.rxdma);
+       free_dma(b->board.chanA.txdma);
+       /* DMA off on the card, drop DTR */
+       outb(0, b->iobase);
+       release_region(b->iobase, 8);
+}
+
+#ifdef MODULE
+
+static int io=0x238;
+static int txdma=1;
+static int rxdma=3;
+static int irq=5;
+static int slow=0;
+
+#ifdef LINUX_21
+MODULE_PARM(io,"i");
+MODULE_PARM_DESC(io, "The I/O base of the Sealevel card");
+MODULE_PARM(txdma,"i");
+MODULE_PARM_DESC(txdma, "Transmit DMA channel");
+MODULE_PARM(rxdma,"i");
+MODULE_PARM_DESC(rxdma, "Receive DMA channel");
+MODULE_PARM(irq,"i");
+MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card");
+MODULE_PARM(slow,"i");
+MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012");
+
+MODULE_AUTHOR("Bulding Number Three Ltd");
+MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021");
+#endif
+
+static struct slvl_board *slvl_unit;
+
+int init_module(void)
+{
+       printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n");
+       printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n");   
+       if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL)
+               return -ENODEV;
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       if(slvl_unit)
+               slvl_shutdown(slvl_unit);
+}
+
+#endif
+
index c01c31d5ba4f6e7a835e014841098c2c05525284..ee8104b6ec3998a1bcbfb57230981fe5f1d7fede 100644 (file)
@@ -108,8 +108,8 @@ static inline void wait_for_buffer(struct device *dev);
 struct netdev_entry seeq8005_drv =
 {"seeq8005", seeq8005_probe1, SEEQ8005_IO_EXTENT, seeq8005_portlist};
 #else
-__initfunc(int
-seeq8005_probe(struct device *dev))
+int __init 
+seeq8005_probe(struct device *dev)
 {
        int i;
        int base_addr = dev ? dev->base_addr : 0;
@@ -135,7 +135,7 @@ seeq8005_probe(struct device *dev))
    probes on the ISA bus.  A good device probes avoids doing writes, and
    verifies that the correct device exists and functions.  */
 
-__initfunc(static int seeq8005_probe1(struct device *dev, int ioaddr))
+static int __init seeq8005_probe1(struct device *dev, int ioaddr)
 {
        static unsigned version_printed = 0;
        int i,j;
@@ -736,6 +736,54 @@ inline void wait_for_buffer(struct device * dev)
                outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
 }
        
+#ifdef MODULE
+
+static char devicename[9] = { 0, };
+
+static struct device dev_seeq =
+{
+       devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+       0, 0, 0, 0,
+       0x300, 5,
+       0, 0, 0, NULL, seeq8005_probe
+};
+
+static int io=0x320;
+static int irq=10;
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+
+int init_module(void)
+{
+       dev_seeq.irq=irq;
+       dev_seeq.base_addr=io;
+       if (register_netdev(&dev_seeq) != 0)
+               return -EIO;
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       /*
+        *      No need to check MOD_IN_USE, as sys_delete_module() checks.
+        */
+
+       unregister_netdev(&dev_seeq);
+
+       /*
+        *      Free up the private structure, or leak memory :-)
+        */
+
+       kfree(dev_seeq.priv);
+       dev_seeq.priv = NULL;   /* gets re-allocated by el1_probe1 */
+
+       /*
+        *      If we don't do this, we can't re-insmod it later.
+        */
+       release_region(dev_seeq.base_addr, EL1_IO_EXTENT);
+}
+
+#endif /* MODULE */
 \f
 /*
  * Local variables:
index 118a0e1ec53c393ba48e70f318504262ef3493a0..690c75e84fa9cdac5d9bd1cd6e24775db9c0d095 100644 (file)
@@ -77,7 +77,6 @@
 #include <linux/timer.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <linux/mm.h>
 #include <linux/init.h>
 #include <net/checksum.h>
 #include <net/slhc_vj.h>
index 772f50649eb8581f3f4ceffb927c01c44d41eb91..b9f773e5db09bf5b0608d415738a1a2638fd15e3 100644 (file)
@@ -32,7 +32,6 @@ static char *version =
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 
 #include <linux/netdevice.h>
index 3485a2a84d8ab129b44cc998c67e54cb91a1e4c2..0d5311080ddf6fbc27cb007dd7f38c04aa75028b 100644 (file)
@@ -108,7 +108,6 @@ static char *lancedma = "LANCE DMA";
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#include <asm/idprom.h>
 #include <asm/machines.h>
 
 /* Define: 2^4 Tx buffers and 2^4 Rx buffers */
index 555776826cad644d8219e2de9e216b7b29f973ab..c8c3297310bf421a5b47fc2234cd7cc596405749 100644 (file)
@@ -327,6 +327,10 @@ enum status_bits {
        TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
 };
 
+enum desc_status_bits {
+       DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+        
 /* The Tulip Rx and Tx buffer descriptors. */
 struct tulip_rx_desc {
        s32 status;
@@ -469,10 +473,12 @@ int tulip_probe(struct device *dev)
                        (PCI_CLASS_NETWORK_ETHERNET << 8,
                         reverse_probe ? 0xfe - pci_index : pci_index,
                         &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+               {
                        if (reverse_probe)
                                continue;
                        else
                                break;
+               }
                pcibios_read_config_word(pci_bus, pci_device_fn,
                                                                 PCI_VENDOR_ID, &vendor);
                pcibios_read_config_word(pci_bus, pci_device_fn,
@@ -1536,10 +1542,12 @@ static void select_media(struct device *dev, int startup)
                outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
        } else {                                        /* Unknown chip type with no media table. */
                if (tp->default_port == 0)
-                       if (tp->mii_cnt) {
+               {
+                       if (tp->mii_cnt)
                                dev->if_port = 11;
-                       else
+                       else
                                dev->if_port = 3;
+               }
                if (media_cap[dev->if_port] & MediaIsMII) {
                        new_csr6 = 0x020E0000;
                } else if (media_cap[dev->if_port] & MediaIsFx) {
@@ -2698,8 +2706,8 @@ static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
                        /* Same setup recently queued, we need not add it. */
                } else {
                        unsigned long flags;
-                       unsigned int entry;
-                       
+                       unsigned int entry, dummy = 0;
+
                        save_flags(flags); cli();
                        entry = tp->cur_tx++ % TX_RING_SIZE;
 
@@ -2709,7 +2717,8 @@ static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
                                tp->tx_ring[entry].length =
                                        (entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
                                tp->tx_ring[entry].buffer1 = 0;
-                               tp->tx_ring[entry].status = 0x80000000;
+                               /* race with chip, set DescOwned later */
+                               dummy = entry;
                                entry = tp->cur_tx++ % TX_RING_SIZE;
                        }
 
@@ -2724,6 +2733,8 @@ static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
                                dev->tbusy = 1;
                                tp->tx_full = 1;
                        }
+                       if (dummy >= 0)
+                               tp->tx_ring[dummy].status = DescOwned;
                        restore_flags(flags);
                        /* Trigger an immediate transmit demand. */
                        outl(0, ioaddr + CSR1);
index 3b22143ea6029527e471f345e26cb3c5929f72ba..be7646b6564e1a9e94c1b56db190ca4bee960730 100644 (file)
@@ -1,6 +1,6 @@
 /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */
 /*
-       Written 1998 by Donald Becker.
+       Written 1998-1999 by Donald Becker.
 
        This software may be used and distributed according to the terms
        of the GNU Public License (GPL), incorporated herein by reference.
@@ -20,7 +20,7 @@
 */
 
 static const char *versionA =
-"via-rhine.c:v1.00 9/5/98  Written by Donald Becker\n";
+"via-rhine.c:v1.01 2/27/99  Written by Donald Becker\n";
 static const char *versionB =
 "  http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
 
@@ -81,9 +81,11 @@ static const int multicast_filter_limit = 32;
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-/* This driver was written to use PCI memory space, however some boards
-   only work with I/O space accesses. */
+/* This driver was written to use PCI memory space, however some x86
+   motherboards only configure I/O space accesses correctly. */
+#if defined(__i386__)  &&  !defined(VIA_USE_MEMORY)
 #define VIA_USE_IO
+#endif
 #ifdef VIA_USE_IO
 #undef readb
 #undef readw
@@ -105,6 +107,7 @@ static const int multicast_filter_limit = 32;
 #define RUN_AT(x) (jiffies + (x))
 
 #if (LINUX_VERSION_CODE >= 0x20100)
+char kernel_version[] = UTS_RELEASE;
 #else
 #ifndef __alpha__
 #define ioremap vremap
@@ -502,6 +505,7 @@ static int pci_etherdev_probe(struct device *dev, struct pci_id_info pci_tbl[])
 #ifndef MODULE
 int via_rhine_probe(struct device *dev)
 {
+       printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
        return pci_etherdev_probe(dev, pci_tbl);
 }
 #endif
@@ -510,13 +514,9 @@ static struct device *via_probe1(int pci_bus, int pci_devfn,
                                                                 struct device *dev, long ioaddr, int irq,
                                                                 int chip_id, int card_idx)
 {
-       static int did_version = 0;             /* Already printed version info */
        struct netdev_private *np;
        int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 
-       if (debug > 0 && did_version++ == 0)
-               printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-
        dev = init_etherdev(dev, 0);
 
        printk(KERN_INFO "%s: %s at 0x%lx, ",
@@ -685,6 +685,8 @@ static int netdev_open(struct device *dev)
                   ioaddr + IntrEnable);
 
        np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
+       if (np->duplex_lock)
+               np->chip_cmd |= CmdFDuplex;
        writew(np->chip_cmd, ioaddr + ChipCmd);
 
        check_duplex(dev);
@@ -1053,7 +1055,6 @@ static int netdev_rx(struct device *dev)
                        skb->protocol = eth_type_trans(skb, dev);
                        netif_rx(skb);
                        dev->last_rx = jiffies;
-                       np->stats.rx_bytes += pkt_len;
                        np->stats.rx_packets++;
                }
                entry = (++np->cur_rx) % RX_RING_SIZE;
@@ -1182,7 +1183,7 @@ static void set_rx_mode(struct device *dev)
                }
                writel(mc_filter[0], ioaddr + MulticastFilter0);
                writel(mc_filter[1], ioaddr + MulticastFilter1);
-               rx_mode = 0x0C;
+               rx_mode = 0x08;
        }
        writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
 }
index 889a82d90e75610407edf2f8df0c5e842ca8bdd1..9fea5980de5a4b457fec58b6f8d4daa350203f36 100644 (file)
@@ -23,7 +23,8 @@
  *     Z85230:
  *     Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud
  *     X.25 is not unrealistic on all machines. DMA mode can in theory
- *     handle T1/E1 quite nicely.
+ *     handle T1/E1 quite nicely. In practice the limit seems to be about
+ *     512Kbit->1Mbit depending on motherboard.
  *
  *     Z85C30:
  *     64K will take DMA, 9600 baud X.25 should be ok.
@@ -187,7 +188,6 @@ u8 z8530_hdlc_kilostream_85230[]=
        1,      EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
        9,      NV|MIE|NORESET,
        23,     3,              /* Extended mode AUTO TX and EOM*/
-       31,     3,              /* Extended mode AUTO TX and EOM*/
        
        255
 };
@@ -834,6 +834,8 @@ EXPORT_SYMBOL(z8530_sync_dma_close);
 
 int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c)
 {
+       unsigned long flags;
+
        printk("Opening sync interface for TX-DMA\n");
        c->sync = 1;
        c->mtu = dev->mtu+64;
@@ -889,14 +891,21 @@ int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c)
        c->regs[R14]|= DTRREQ;
        write_zsreg(c, R14, c->regs[R14]);     
        
+       c->regs[R1]&= ~TxINT_ENAB;
+       write_zsreg(c, R1, c->regs[R1]);
+       
        /*
         *      Set up the DMA configuration
         */     
         
+       flags = claim_dma_lock();
+
        disable_dma(c->txdma);
        clear_dma_ff(c->txdma);
        set_dma_mode(c->txdma, DMA_MODE_WRITE);
        disable_dma(c->txdma);
+
+       release_dma_lock(flags);
        
        /*
         *      Select the DMA interrupt handlers
@@ -918,6 +927,7 @@ EXPORT_SYMBOL(z8530_sync_txdma_open);
        
 int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c)
 {
+       unsigned long flags;
        u8 chk;
        c->irqs = &z8530_nop;
        c->max = 0;
@@ -927,11 +937,15 @@ int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c)
         *      Disable the PC DMA channels
         */
         
+       flags = claim_dma_lock();
+
        disable_dma(c->txdma);
        clear_dma_ff(c->txdma);
        c->txdma_on = 0;
        c->tx_dma_used = 0;
 
+       release_dma_lock(flags);
+
        /*
         *      Disable DMA control mode
         */
index e8db586d88fd4f625ffa5ec5d1cb3096f7ea0aad..6595b3e41f9b154464a0260e96bcd9f911919565 100644 (file)
@@ -5113,10 +5113,6 @@ z_streamp z;
 
 /* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
 
-#ifdef DEBUG_ZLIB
-#include <stdio.h>
-#endif
-
 /* #include "zutil.h" */
 
 #ifndef NO_DUMMY_DECL
index 9f5ecd98ddf9571d037e3ce6168c00b8a56d7e09..3d92293bd84b8f486f2aa65c15ae5dedb302fa3e 100644 (file)
@@ -138,7 +138,7 @@ pci_set_master(struct pci_dev *dev)
        }
 }
 
-__initfunc(void pci_read_bases(struct pci_dev *dev, unsigned int howmany))
+void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany)
 {
        unsigned int reg;
        u32 l;
@@ -166,7 +166,7 @@ __initfunc(void pci_read_bases(struct pci_dev *dev, unsigned int howmany))
 }
 
 
-__initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
+unsigned int __init pci_scan_bus(struct pci_bus *bus)
 {
        unsigned int devfn, l, max, class;
        unsigned char cmd, irq, tmp, hdr_type, is_multi = 0;
@@ -192,6 +192,11 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
                        continue;
 
                dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
+               if(dev==NULL)
+               {
+                       printk(KERN_ERR "pci: out of memory.\n");
+                       continue;
+               }
                memset(dev, 0, sizeof(*dev));
                dev->bus = bus;
                dev->devfn  = devfn;
@@ -300,6 +305,11 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
                         * Insert it into the tree of buses.
                         */
                        child = kmalloc(sizeof(*child), GFP_ATOMIC);
+                       if(child==NULL)
+                       {
+                               printk(KERN_ERR "pci: out of memory for bridge.\n");
+                               continue;
+                       }
                        memset(child, 0, sizeof(*child));
                        child->next = bus->children;
                        bus->children = child;
@@ -389,7 +399,7 @@ struct pci_bus * __init pci_scan_peer_bridge(int bus)
        return b;
 }
 
-__initfunc(void pci_init(void))
+void __init pci_init(void)
 {
        pcibios_init();
 
@@ -415,7 +425,7 @@ __initfunc(void pci_init(void))
 #endif
 }
 
-__initfunc(void pci_setup (char *str, int *ints))
+void __init pci_setup (char *str, int *ints)
 {
        while (str) {
                char *k = strchr(str, ',');
index 86914758ba0f83e87f814b89cc41b117a86c8087..a19028c6f137001c1a1d61e46a943cfc5eb73d40 100644 (file)
 #include <linux/ioport.h>
 #include <linux/major.h>
 
-#include  <asm/uaccess.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
 
 #if defined(__i386__)
-# include <asm/io.h>
 # include <asm/system.h>
 # include <asm/segment.h>
 #endif
@@ -34,7 +34,6 @@
 
 # include <asm/oplib.h>           /* OpenProm Library */
 # include <asm/sbus.h>            /* struct linux_sbus *SBus_chain */
-# include <asm/io.h>              /* sparc_alloc_io() */
 #endif
 
 #include <asm/bpp.h>
index 7bdadace8656eaeb517108c32cfb197f603e792a..8b18c6875000d9a8db8c243f8bc14754a989ffd1 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/malloc.h>
 #include <linux/config.h>
 #include <linux/init.h>
-#include <linux/malloc.h>
 #include <linux/pci.h>
 
 #include <asm/system.h>
index c280618260234a92caf2de4dccac810b1284939e..475fb9ad539db768b1a2dd3c432bd6ee68ad69d0 100644 (file)
 #include <linux/time.h>
 #include <linux/blk.h>
 #include <asm/spinlock.h>
+#include <asm/pgtable.h>
 
 #ifdef CONFIG_AMIGA
-#include <asm/pgtable.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/irq.h>
 #endif
 
 #ifdef CONFIG_MVME16x
-#include <asm/pgtable.h>
 #include <asm/mvme16xhw.h>
 
 #define BIG_ENDIAN
 #endif
 
 #ifdef CONFIG_BVME6000
-#include <asm/pgtable.h>
 #include <asm/bvme6000hw.h>
 
 #define BIG_ENDIAN
index c997cba65b4b29baafe7595f5554121a0aa75e32..2a3497eeca633b0bc2a1e0c9b71992d85bca2e09 100644 (file)
@@ -3390,6 +3390,7 @@ inline void esp_handle(struct NCR_ESP *esp)
        struct ESP_regs *eregs;
        Scsi_Cmnd *SCptr;
        int what_next = do_intr_end;
+       unsigned long flags;
 #ifdef CONFIG_SCSI_SUNESP
        struct sparc_dma_registers *dregs = 
          (struct sparc_dma_registers*) esp->dregs;
@@ -3610,7 +3611,9 @@ again:
                        }
                        SCptr->result = (DID_RESET << 16);
 
+                       spin_lock_irqsave(&io_request_lock,flags);
                        SCptr->scsi_done(SCptr);
+                       spin_unlock_irqrestore(&io_request_lock, flags);
                }
                esp->current_SC = NULL;
                if(esp->disconnected_SC) {
@@ -3625,7 +3628,9 @@ again:
                                }
                                SCptr->result = (DID_RESET << 16);
 
+                               spin_lock_irqsave(&io_request_lock,flags);
                                SCptr->scsi_done(SCptr);
+                               spin_unlock_irqrestore(&io_request_lock, flags);
                        }
                }
                esp->resetting_bus = 0;
index df7fa30e63a8e23eac1d76ba1d546ed466d542df..fe4569c1e65c31c41e7ec5c6b4bec092c3725350 100644 (file)
@@ -270,7 +270,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.17"
+#define AIC7XXX_C_VERSION  "5.1.18"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -7186,7 +7186,7 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
 static int
 acquire_seeprom(struct aic7xxx_host *p)
 {
-  int wait;
+  int count=0;
 
   /*
    * Request access of the memory port.  When access is
@@ -7196,11 +7196,10 @@ acquire_seeprom(struct aic7xxx_host *p)
    * should be no contention.
    */
   aic_outb(p, SEEMS, SEECTL);
-  wait = 1000;  /* 1000 msec = 1 second */
-  while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
-  {
-    wait--;
-    mdelay(1);  /* 1 msec */
+  while( ((aic_inb(p, SEECTL) & SEERDY) == 0) && count < 1000) {
+    mb();
+    udelay(1);
+    count++;
   }
   if ((aic_inb(p, SEECTL) & SEERDY) == 0)
   {
@@ -7412,73 +7411,78 @@ read_seeprom(struct aic7xxx_host *p, int offset,
 
 /*+F*************************************************************************
  * Function:
- *   write_brdctl
+ *   read_brdctl
  *
  * Description:
- *   Writes a value to the BRDCTL register.
+ *   Reads the BRDCTL register.
  *-F*************************************************************************/
-static void
-write_brdctl(struct aic7xxx_host *p, unsigned char value)
+static unsigned char
+read_brdctl(struct aic7xxx_host *p)
 {
   unsigned char brdctl;
 
   if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
   {
-    brdctl = BRDSTB;
+    brdctl = BRDRW;
     if (p->flags & AHC_CHNLB)
       brdctl |= BRDCS;
   }
   else if (p->features & AHC_ULTRA2)
-    brdctl = 0;
-  else
-    brdctl = BRDSTB | BRDCS;
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
-  brdctl |= value;
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
-  if (p->features & AHC_ULTRA2)
-    brdctl |= BRDSTB_ULTRA2;
-  else
-    brdctl &= ~BRDSTB;
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
-  if (p->features & AHC_ULTRA2)
-    brdctl = 0;
+    brdctl = BRDRW_ULTRA2;
   else
-    brdctl &= ~BRDCS;
+    brdctl = BRDRW | BRDCS;
   aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
+  udelay(10);
+  return (aic_inb(p, BRDCTL));
 }
 
 /*+F*************************************************************************
  * Function:
- *   read_brdctl
+ *   write_brdctl
  *
  * Description:
- *   Reads the BRDCTL register.
+ *   Writes a value to the BRDCTL register.
  *-F*************************************************************************/
-static unsigned char
-read_brdctl(struct aic7xxx_host *p)
+static void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
 {
-  unsigned char brdctl, value;
+  unsigned char brdctl;
 
   if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
   {
-    brdctl = BRDRW;
+    brdctl = BRDSTB;
     if (p->flags & AHC_CHNLB)
       brdctl |= BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(4);
+    brdctl |= value;
   }
   else if (p->features & AHC_ULTRA2)
-    brdctl = BRDRW_ULTRA2;
+  {
+    brdctl = value;
+  }
   else
-    brdctl = BRDRW | BRDCS;
+  {
+    brdctl = BRDSTB | BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(4);
+    brdctl |= value;
+  }
   aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
-  value = aic_inb(p, BRDCTL);
-  aic_outb(p, 0, BRDCTL);
-  udelay(1);
-  return (value);
+  udelay(4);
+  if (p->features & AHC_ULTRA2)
+    brdctl |= BRDSTB_ULTRA2;
+  else
+    brdctl &= ~BRDSTB;
+  aic_outb(p, brdctl, BRDCTL);
+  udelay(4);
+  if (p->features & AHC_ULTRA2)
+    brdctl &= ~BRDSTB_ULTRA2;
+  else
+    brdctl &= ~BRDCS;
+  aic_outb(p, brdctl, BRDCTL);
+  udelay(4);
+  read_brdctl(p);
 }
 
 /*+F*************************************************************************
@@ -7495,11 +7499,10 @@ aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
   unsigned char brdctl;
 
   aic_outb(p, BRDRW | BRDCS, BRDCTL);
-  udelay(1);
+  udelay(4);
   aic_outb(p, 0, BRDCTL);
-  udelay(1);
+  udelay(4);
   brdctl = aic_inb(p, BRDCTL);
-  udelay(1);
   *int_50 = !(brdctl & BRDDAT5);
   *ext_present = !(brdctl & BRDDAT6);
   *eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
@@ -7608,6 +7611,7 @@ configure_termination(struct aic7xxx_host *p)
     else
       max_target = 8;
     aic_outb(p, SEEMS | SEECS, SEECTL);
+    udelay(4);
     sxfrctl1 &= ~STPWEN;
     if ( (p->adapter_control & CFAUTOTERM) ||
          (p->features & AHC_ULTRA2) )
@@ -7732,25 +7736,33 @@ configure_termination(struct aic7xxx_host *p)
                  p->host_no);
       }
 
-      if (enableLVD_low != 0)
+      if (enableLVD_high != 0)
       {
-        sxfrctl1 |= STPWEN;
-        p->flags |= AHC_TERM_ENB_LVD;
+        brddat |= BRDDAT4;
         if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n",
+          printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n",
                  p->host_no);
       }
           
-      if (enableLVD_high != 0)
+      if (enableLVD_low != 0)
       {
-        brddat |= BRDDAT4;
+        sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_LVD;
         if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n",
+          printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n",
                  p->host_no);
       }
     }
     else
     {
+      if (p->adapter_control & CFWSTERM)
+      {
+        brddat |= BRDDAT6;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                 p->host_no);
+      }
+
       if (p->adapter_control & CFSTERM)
       {
         if (p->features & AHC_ULTRA2)
@@ -7761,18 +7773,10 @@ configure_termination(struct aic7xxx_host *p)
           printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
                  p->host_no);
       }
-
-      if (p->adapter_control & CFWSTERM)
-      {
-        brddat |= BRDDAT6;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
-                 p->host_no);
-      }
     }
+    aic_outb(p, sxfrctl1, SXFRCTL1);
     write_brdctl(p, brddat);
     release_seeprom(p);
-    aic_outb(p, sxfrctl1, SXFRCTL1);
   }
 }
 
@@ -8086,7 +8090,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
     /* Select channel B */
     aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
 
-    term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0;
+    term = (aic_inb(p, SXFRCTL1) & STPWEN);
     aic_outb(p, p->scsi_id_b, SCSIID);
     scsi_conf = aic_inb(p, SCSICONF + 1);
     aic_outb(p, DFON | SPIOEN, SXFRCTL0);
@@ -8100,11 +8104,15 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
     aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
   }
 
-  term = ((p->flags & AHC_TERM_ENB_SE_LOW) != 0) ? STPWEN : 0;
   if (p->features & AHC_ULTRA2)
+  {
     aic_outb(p, p->scsi_id, SCSIID_ULTRA2);
+  }
   else
+  {
     aic_outb(p, p->scsi_id, SCSIID);
+  }
+  term = (aic_inb(p, SXFRCTL1) & STPWEN);
   scsi_conf = aic_inb(p, SCSICONF);
   aic_outb(p, DFON | SPIOEN, SXFRCTL0);
   aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
@@ -8794,27 +8802,33 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
     }
     if (p->flags & AHC_NEWEEPROM_FMT)
     {
-      if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
-          !(p->features & AHC_ULTRA2) )
+      if ( !(p->features & AHC_ULTRA2) )
       {
         /*
          * I know of two different Ultra BIOSes that do this differently.
          * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
-         * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s
+         * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s
          * while on the IBM Netfinity 5000 they want the same thing
          * to be something else, while flags[i] & CFXFER == 0x03 and
-         * SYNCISULTRA false should be 40MByte/s.  So, we set both to
+         * SYNCHISULTRA false should be 40MByte/s.  So, we set both to
          * 40MByte/s and the lower speeds be damned.  People will have
          * to select around the conversely mapped lower speeds in order
          * to select lower speeds on these boards.
          */
-        if ((sc->device_flags[i] & (CFXFER)) == 0x03)
+        if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+            ((sc->device_flags[i] & CFXFER) == 0x03) )
         {
           sc->device_flags[i] &= ~CFXFER;
           sc->device_flags[i] |= CFSYNCHISULTRA;
         }
+        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        {
+          p->ultraenb |= mask;
+        }
       }
-      if (sc->device_flags[i] & CFSYNCHISULTRA)
+      else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+                 (p->features & AHC_ULTRA2) &&
+                (sc->device_flags[i] & CFSYNCHISULTRA) )
       {
         p->ultraenb |= mask;
       }
@@ -9293,6 +9307,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7860_FE,                                       7,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7860_FE,                                       7,
index 7f348aa9393ac25d0a8330da19069bc2772f0746..6cc347d5b82b2bd9e130b6deca0fb68e5597add7 100644 (file)
@@ -845,7 +845,7 @@ register CRCCONTROL1 {
        bit     CRCENDCHKEN     0x20 /* CRC End Check Enable */
        bit     CRCREQCHKEN     0x10
        bit     TARGCRCENDEN    0x08 /* Enable End CRC transfer when target */
-       bit     TARGCRCCNTEN    0x40 /* Enable CRC transfer when target */
+       bit     TARGCRCCNTEN    0x04 /* Enable CRC transfer when target */
 }
 
 /*
index b42750864288e66e2a1143273a5fca561c333229..f86e1bec8a264f2503716485a7518fd023e2bce7 100644 (file)
 
 #define        CRCCONTROL1                     0x9d
 #define                CRCONSEEN               0x80
-#define                TARGCRCCNTEN            0x40
 #define                CRCVALCHKEN             0x40
 #define                CRCENDCHKEN             0x20
 #define                CRCREQCHKEN             0x10
 #define                TARGCRCENDEN            0x08
+#define                TARGCRCCNTEN            0x04
 
 #define        SCSIPHASE                       0x9e
 #define                SP_STATUS               0x20
index ada7235b88db9dbd4367c3b3c1db369cbb084eff..29468801b913c67456c00f3e72677efb2b39c368 100644 (file)
@@ -3,7 +3,9 @@
  *
  *  Copyright (C) 1997 Wu Ching Chen
  *  2.1.x update (C) 1998  Krzysztof G. Baranowski
- *
+ *   
+ * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes 
+ * 
  */
 
 #include <linux/module.h>
@@ -17,6 +19,7 @@
 #include <linux/proc_fs.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/spinlock.h>
 #include <linux/pci.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -60,6 +63,7 @@ static struct Scsi_Host * atp_host[2]={NULL,NULL};
 
 static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
+        unsigned long flags;
     unsigned short int tmpcip,id;
     unsigned char      i,j,h,tarid,lun;
     unsigned char  *prd;
@@ -364,7 +368,10 @@ get_sens:
             outb(0x80,tmport);
          }   */
 go_42:
+         spin_lock_irqsave(&io_request_lock, flags);
          (*workrequ->scsi_done)(workrequ);
+         spin_unlock_irqrestore(&io_request_lock, flags);
+
          curr_req[h][tarid]=0;
          workingu[h]--;
          if (wide_idu[h] != 0)
index d6c766635cb3a1fe22a4862f27d505871ff5a040..7e9fb2ab34398576c9f50856ab35865457e3be5e 100644 (file)
@@ -1,6 +1,8 @@
 /* 
  * ASCII values for a number of symbolic constants, printing functions,
  * etc.
+ * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422)
+ *
  */
 
 #define __NO_VERSION__
@@ -37,7 +39,7 @@ static const char * group_0_commands[] = {
 /* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks",
 /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown,
 /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
-/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve",
+/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve",
 /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
 /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", 
 /* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
@@ -46,37 +48,57 @@ static const char * group_0_commands[] = {
 
 static const char *group_1_commands[] = {
 /* 20-22 */  unknown, unknown, unknown,
-/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", 
-/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, 
+/* 23-28 */ unknown, "Define window parameters", "Read Capacity", 
+            unknown, unknown, "Read (10)", 
+/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", 
+            "Read updated block", 
 /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", 
 /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", 
 /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", 
-/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", 
+/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", 
+            "Read Buffer", 
 /* 3d-3f */ "Update Block", "Read Long",  "Write Long",
 };
 
 
 static const char *group_2_commands[] = {
 /* 40-41 */ "Change Definition", "Write Same", 
-/* 42-48 */ unknown, "Read TOC", unknown, unknown, unknown, unknown, unknown, 
-/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown,
+/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", 
+            "Play audio (10)", unknown, "Play audio msf",
+            "Play audio track/index", 
+/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume", 
+            "Log Select", "Log Sense", unknown, unknown,
 /* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
 /* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
 /* 5c-5f */ unknown, unknown, unknown,
 };
 
 
+/* The following are 12 byte commands in group 5 */
+static const char *group_5_commands[] = {
+/* a0-a5 */ unknown, unknown, unknown, unknown, unknown,
+            "Move medium/play audio(12)",
+/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)", 
+/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown, 
+            "Write and verify(12)", 
+/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)",
+/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown,
+/* b5-b6 */ "Request volume element address", "Send volume tag",
+/* b7-b9 */ "Read defect data(12)", "Read element status", unknown,
+/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown,
+};
+
+
 
 #define group(opcode) (((opcode) >> 5) & 7)
 
 #define RESERVED_GROUP  0
 #define VENDOR_GROUP    1
-#define NOTEXT_GROUP    2
 
 static const char **commands[] = {
     group_0_commands, group_1_commands, group_2_commands, 
     (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
-    (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
+    group_5_commands, (const char **) VENDOR_GROUP, 
     (const char **) VENDOR_GROUP
 };
 
@@ -89,9 +111,6 @@ static void print_opcode(int opcode) {
     case RESERVED_GROUP:
        printk("%s(0x%02x) ", reserved, opcode); 
        break;
-    case NOTEXT_GROUP:
-       printk("%s(0x%02x) ", unknown, opcode); 
-       break;
     case VENDOR_GROUP:
        printk("%s(0x%02x) ", vendor, opcode); 
        break;
@@ -119,15 +138,18 @@ void print_command (unsigned char *command) {
 
 #if (CONSTANTS & CONST_STATUS)
 static const char * statuses[] = {
-/* 0-4 */ "Good", "Check Condition", "Condition Good", unknown, "Busy", 
-/* 5-9 */ unknown, unknown, unknown, "Intermediate Good", unknown, 
-/* a-d */ "Intermediate Good", unknown, "Reservation Conflict", unknown,
-/* e-f */ unknown, unknown,
+/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", 
+/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, 
+/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict",
+/* d-10 */ unknown, unknown, unknown, unknown,
+/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full",
+/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown,
+/* 1b-1f */ unknown, unknown, unknown, unknown, unknown,
 };
 #endif
 
 void print_status (int status) {
-    status = (status >> 1) & 0xf;
+    status = (status >> 1) & 0x1f;
 #if (CONSTANTS & CONST_STATUS)
     printk("%s ",statuses[status]);
 #else
@@ -405,8 +427,10 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
            s = sizeof(SCpnt->sense_buffer);
        
        if (!valid)
-           printk("extra data not valid ");
-       
+           printk("[valid=0] ");
+       printk("Info fld=0x%x, ", (int)((sense_buffer[3] << 24) |
+              (sense_buffer[4] << 16) | (sense_buffer[5] << 8) |
+              sense_buffer[6]));
        if (sense_buffer[2] & 0x80)
            printk( "FMK ");    /* current command has read a filemark */
        if (sense_buffer[2] & 0x40)
@@ -427,7 +451,7 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
            error = "Invalid";
        }
        
-       printk("%s error ", error);
+       printk("%s ", error);
        
 #if (CONSTANTS & CONST_SENSE)
        printk( "%s%s: sense key %s\n", devclass,
@@ -603,7 +627,8 @@ void print_Scsi_Cmnd (Scsi_Cmnd *cmd) {
 #if (CONSTANTS & CONST_HOST)
 static const char * hostbyte_table[]={
 "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", 
-"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",NULL};
+"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
+"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL};
 
 void print_hostbyte(int scsiresult)
 {   static int maxcode=0;
index 6e8e650b0339d15e7c6f5c6fa27bc6dfabccb27b..bc5652a09c2695681e75f2e2592cafbdbda9cf1f 100644 (file)
@@ -765,11 +765,11 @@ int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
                if (inia100_adpt[i].ADPT_BIOS < wBIOS)
                        continue;
                if (inia100_adpt[i].ADPT_BIOS == wBIOS) {
-                       if (inia100_adpt[i].ADPT_BASE == wBASE)
+                       if (inia100_adpt[i].ADPT_BASE == wBASE) {
                                if (inia100_adpt[i].ADPT_Bus != 0xFF)
                                        return (FAILURE);
-                               else if (inia100_adpt[i].ADPT_BASE < wBASE)
-                                       continue;
+                       } else if (inia100_adpt[i].ADPT_BASE < wBASE)
+                               continue;
                }
                for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
                        inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE;
index 6dba96b62539eb6238d1922ffa6d9c379c5a472d..c6ce1c7378eaf9bbab1b51f0cfb2f7c0faf7faf2 100644 (file)
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 #include <stdarg.h>
-#include <asm/io.h>
 #include <asm/irq.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
 #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
 #include <linux/bios32.h>
 #endif
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
 #include <linux/init.h>
 #endif
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
 #include <asm/spinlock.h>
 #endif
-#include "sd.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "ini9100u.h"
 #include <linux/stat.h>
-#include <linux/malloc.h>
 #include <linux/config.h>
 
 #else
 
-#include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
+#include <asm/system.h>
+#include "../block/blk.h"
+#endif
+
+#include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
-
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
-#include <asm/system.h>
 #include <asm/io.h>
-#include "../block/blk.h"
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
 #include <linux/malloc.h>
 #include "ini9100u.h"
-#endif
-
-#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93)
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-#endif
 
 #ifdef DEBUG_i91u
 unsigned int i91u_debug = DEBUG_DEFAULT;
index b6f4eb34f8f1fb0b695d294b42ce4e4d3ae3b545..870b24e6c97cd6c0114aaa056b087c384ccf8aa2 100644 (file)
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 #include <stdarg.h>
-#include <asm/io.h>
 #include <asm/irq.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
 #include <linux/bios32.h>
 #endif
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
 #include <linux/init.h>
 #endif
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
 #include <asm/spinlock.h>
 #endif
-#include "sd.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "inia100.h"
 #include <linux/stat.h>
-#include <linux/malloc.h>
-
 
 #else
 
-#include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
+#include <asm/system.h>
+#include "../block/blk.h"
+#endif
+
+#include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
-
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
-#include <asm/system.h>
 #include <asm/io.h>
-#include "../block/blk.h"
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
 #include <linux/malloc.h>
 #include "inia100.h"
-#endif
 
 #ifdef MODULE
 Scsi_Host_Template driver_template = INIA100;
index 3551f3863204a47212a7e7e6222ed43ce9d38558..e90e4132f3e5d6dc6693a808b6326880a5944e07 100644 (file)
@@ -129,9 +129,7 @@ MODULE_DESCRIPTION ("AMI MegaRAID driver");
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
 
-#include <linux/sched.h>
 #include <linux/stat.h>
-#include <linux/malloc.h>      /* for kmalloc() */
 #if LINUX_VERSION_CODE < 0x20100
 #include <linux/bios32.h>
 #else
index 8d9210dba283b71d0e94d6b7eb0d96055efddc34..085b41615e424bb2746aca7d1a9a5656a4460d9f 100644 (file)
@@ -18,7 +18,6 @@
 #include "hosts.h"
 #include "53c7xx.h"
 #include "mvme16x.h"
-#include "asm/mvme16xhw.h"
 
 #include<linux/stat.h>
 
index 0414f19ffc74200f68a4126df8e4b1406b639236..a65ab21c9734defaa2c9afad3773897ecae19ecb 100644 (file)
@@ -577,6 +577,5 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
 /* Eventually this will go into an include file, but this will be later */
 Scsi_Host_Template driver_template = MV_PAS16;
 
-#include <linux/module.h>
 #include "scsi_module.c"
 #endif
index e82d8f4fffc6c4bbb2f28a730a7ee902eaa543f9..8d8cb22ca67c12cdf7ab8c90614fd1361ddf606c 100644 (file)
@@ -155,16 +155,16 @@ struct {
 #endif                         /* DEBUG ISP2100_INTR */
 
 
-#if defined(__i386__)
-#define virt_to_bus_low32(x)   virt_to_bus(x)
-#define virt_to_bus_high32(x)  0x0
-#define bus_to_virt_low32(x)   bus_to_virt(x)
-#define bus_to_virt_high32(x)  0x0
-#elif defined(__alpha__)
+#if BITS_PER_LONG > 32
 #define virt_to_bus_low32(x)   ((u32) (0xffffffff & virt_to_bus(x)))
 #define virt_to_bus_high32(x)  ((u32) (0xffffffff & (virt_to_bus(x)>>32)))
 #define bus_to_virt_low32(x)   ((u32) (0xffffffff & bus_to_virt(x)))
 #define bus_to_virt_high32(x)  ((u32) (0xffffffff & (bus_to_virt(x)>>32)))
+#else
+#define virt_to_bus_low32(x)   virt_to_bus(x)
+#define virt_to_bus_high32(x)  0x0
+#define bus_to_virt_low32(x)   bus_to_virt(x)
+#define bus_to_virt_high32(x)  0x0
 #endif
 
 #define ISP2100_REV_ID 1
@@ -228,19 +228,47 @@ struct Entry_header {
 };
 
 /* entry header type commands */
+#if BITS_PER_LONG > 32
 #define ENTRY_COMMAND          0x19
 #define ENTRY_CONTINUATION     0x0a
+#else
+#define ENTRY_COMMAND          0x11
+#define ENTRY_CONTINUATION     0x02
+#endif
 #define ENTRY_STATUS           0x03
 #define ENTRY_MARKER           0x04
 
+
 /* entry header flag definitions */
 #define EFLAG_BUSY             2
 #define EFLAG_BAD_HEADER       4
 #define EFLAG_BAD_PAYLOAD      8
 
+#if BITS_PER_LONG > 32
+struct dataseg {
+       u_int d_base;
+       u_int d_base_hi;
+       u_int d_count;
+};
+
+struct Command_Entry {
+       struct Entry_header hdr;
+       u_int handle;
+       u_char target_lun;
+       u_char target_id;
+       u_short rsvd1;
+       u_short control_flags;
+       u_short rsvd2;
+       u_short time_out;
+       u_short segment_cnt;
+       u_char cdb[16];
+       u_int total_byte_cnt;
+       struct dataseg dataseg[DATASEGS_PER_COMMAND];
+};
+
+#else
 struct dataseg {
-       u_int d_base_lo;
-       u_int d_base_high;
+       u_int d_base;
        u_int d_count;
 };
 
@@ -256,9 +284,12 @@ struct Command_Entry {
        u_short segment_cnt;
        u_char cdb[16];
        u_int total_byte_cnt;
-       struct dataseg dataseg[2];
+       struct dataseg dataseg[DATASEGS_PER_COMMAND];
 };
 
+#endif
+
+
 /* command entry control flag definitions */
 #define CFLAG_NODISC           0x01
 #define CFLAG_HEAD_TAG         0x02
@@ -281,10 +312,18 @@ struct Ext_Command_Entry {
        u_char cdb[44];
 };
 
+#if BITS_PER_LONG > 32
+struct Continuation_Entry {
+       struct Entry_header hdr;
+       struct dataseg dataseg[DATASEGS_PER_CONT];
+};
+#else
 struct Continuation_Entry {
        struct Entry_header hdr;
-       struct dataseg dataseg[5];
+        u32 rsvd;
+       struct dataseg dataseg[DATASEGS_PER_CONT];
 };
+#endif
 
 struct Marker_Entry {
        struct Entry_header hdr;
@@ -549,7 +588,7 @@ struct sns_cb {
        u_int response_high;
        u_short sub_len;
        u_short res2;
-       u_short data[22];
+       u_char data[44];
 };
 
 /* address of instance of this struct is passed to adapter to initialize things
@@ -586,9 +625,17 @@ struct init_cb {
 #if ISP2100_FABRIC
 #define QLOGICFC_MAX_ID    0xff
 #else
-#define QLOGICFC_MAX_ID    0x80
+#define QLOGICFC_MAX_ID    0x7d
 #endif
 
+#define QLOGICFC_MAX_LOOP_ID 0x7d
+
+/* adapter_state values */
+#define AS_FIRMWARE_DEAD      -1
+#define AS_LOOP_DOWN           0
+#define AS_LOOP_GOOD           1
+#define AS_REDO_PORTDB         2
+
 struct isp2100_hostdata {
        u_char revision;
        struct pci_dev *pci_dev;
@@ -602,7 +649,7 @@ struct isp2100_hostdata {
        char res[RES_QUEUE_LEN + 1][QUEUE_ENTRY_LEN];
        char req[QLOGICFC_REQ_QUEUE_LEN + 1][QUEUE_ENTRY_LEN];
        struct init_cb control_block;
-       int loop_up;
+       int adapter_state;
        unsigned long int tag_ages[126];
        Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1];
        unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1];
@@ -611,6 +658,7 @@ struct isp2100_hostdata {
        u64 wwn;
        u_int port_id;
        u_char queued;
+       u_char host_id;
 };
 
 
@@ -643,7 +691,9 @@ static u_short isp2100_read_nvram_word(struct Scsi_Host *, u_short);
 static void isp2100_print_scsi_cmd(Scsi_Cmnd *);
 #endif
 
+#if DEBUG_ISP2100_INTR
 static void isp2100_print_status_entry(struct Status_Entry *);
+#endif
 
 static struct proc_dir_entry proc_scsi_isp2100 =
 {
@@ -693,7 +743,7 @@ int isp2100_detect(Scsi_Host_Template * tmpt)
                hostdata->queued = 0;
                /* set up the control block */
                hostdata->control_block.version = 0x0f;
-               hostdata->control_block.firm_opts = 0x010c;
+               hostdata->control_block.firm_opts = 0x0108;
                hostdata->control_block.max_frame_len = 2048;
                hostdata->control_block.max_iocb = 256;
                hostdata->control_block.exec_throttle = 8;
@@ -711,8 +761,9 @@ int isp2100_detect(Scsi_Host_Template * tmpt)
                hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(&hostdata->req);
                hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(&hostdata->req);
 
-               hostdata->loop_up = 0;
-
+               hostdata->adapter_state = AS_LOOP_DOWN;
+               hostdata->host_id = hosts;
+               
                if (isp2100_init(host) || isp2100_reset_hardware(host)) {
                        scsi_unregister(host);
                        continue;
@@ -720,15 +771,15 @@ int isp2100_detect(Scsi_Host_Template * tmpt)
                host->this_id = 0;
 
                if (request_irq(host->irq, do_isp2100_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) {
-                       printk("qlogicfc : interrupt %d already in use\n",
-                              host->irq);
+                       printk("qlogicfc%d : interrupt %d already in use\n",
+                              hostdata->host_id, host->irq);
                        scsi_unregister(host);
                        continue;
                }
                if (check_region(host->io_port, 0xff)) {
-                       printk("qlogicfc : i/o region 0x%lx-0x%lx already "
+                       printk("qlogicfc%d : i/o region 0x%lx-0x%lx already "
                               "in use\n",
-                              host->io_port, host->io_port + 0xff);
+                              hostdata->host_id, host->io_port, host->io_port + 0xff);
                        free_irq(host->irq, host);
                        scsi_unregister(host);
                        continue;
@@ -739,15 +790,11 @@ int isp2100_detect(Scsi_Host_Template * tmpt)
                outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
                isp2100_enable_irqs(host);
                /* wait for the loop to come up */
-               for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->loop_up == 0;)
+               for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;)
                        barrier();
 
-               if (hostdata->loop_up == 0) {
-                       printk("qlogicfc: loop is not up\n");
-                       release_region(host->io_port, 0xff);
-                       free_irq(host->irq, host);
-                       scsi_unregister(host);
-                       continue;
+               if (hostdata->adapter_state == AS_LOOP_DOWN) {
+                       printk("qlogicfc%d : loop is not up\n", hostdata->host_id);
                }
                hosts++;
        }
@@ -790,7 +837,7 @@ static int isp2100_make_portdb(struct Scsi_Host *host)
                isp2100_mbox_command(host, param);
 
                if (param[0] != MBOX_COMMAND_COMPLETE) {
-                       printk("logout failed %x  %x\n", i, param[0]);
+                       printk("qlogicfc%d : logout failed %x  %x\n", hostdata->host_id, i, param[0]);
                }
        }
 #endif
@@ -807,13 +854,14 @@ static int isp2100_make_portdb(struct Scsi_Host *host)
                temp[0].wwn = hostdata->wwn;
        }
        else {
-               printk("qlogicfc: error getting scsi id.\n");
+               printk("qlogicfc%d : error getting scsi id.\n", hostdata->host_id);
        }
 
-       for (i = 1, j = 1; i <= QLOGICFC_MAX_ID; i++) {
-               temp[i].loop_id = temp[0].loop_id;
-
-               param[0] = MBOX_GET_PORT_NAME;
+        for (i = 0; i <=QLOGICFC_MAX_ID; i++)
+                temp[i].loop_id = temp[0].loop_id;
+   
+        for (i = 0, j = 1; i <= QLOGICFC_MAX_LOOP_ID; i++) {
+                param[0] = MBOX_GET_PORT_NAME;
                param[1] = (i << 8) & 0xff00;
 
                isp2100_mbox_command(host, param);
@@ -856,7 +904,7 @@ static int isp2100_make_portdb(struct Scsi_Host *host)
                                }
                        }
                        if (j == QLOGICFC_MAX_ID + 1)
-                               printk("qlogicfc.c: Too many scsi devices, no more room in port map.\n");
+                               printk("qlogicfc%d : Too many scsi devices, no more room in port map.\n", hostdata->host_id);
                        if (!hostdata->port_db[j].wwn) {
                                hostdata->port_db[j].loop_id = temp[i].loop_id;
                                hostdata->port_db[j].wwn = temp[i].wwn;
@@ -874,14 +922,18 @@ static int isp2100_make_portdb(struct Scsi_Host *host)
 
 #if ISP2100_FABRIC
 
-int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int j)
+#define FABRIC_PORT          0x7e
+#define FABRIC_CONTROLLER    0x7f
+#define FABRIC_SNS           0x80
+
+int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id)
 {
 
        u_short param[8];
        u64 wwn;
        int done = 0;
        u_short loop_id = 0x81;
-       u_short scsi_id = j;
+       u_short scsi_id = cur_scsi_id;
        u_int port_id;
        struct sns_cb req;
        u_char sns_response[608];
@@ -889,18 +941,42 @@ int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
 
        hostdata = (struct isp2100_hostdata *) host->hostdata;
 
-       DEBUG_FABRIC(printk("qlogicfc.c: Checking for a fabric.\n"));
+       DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id));
        param[0] = MBOX_GET_PORT_NAME;
-       param[1] = 0x7E00;
+       param[1] = (u16)FABRIC_PORT << 8;
 
        isp2100_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               DEBUG_FABRIC(printk("fabric check result %x\n", param[0]));
+               DEBUG_FABRIC(printk("qlogicfc%d : fabric check result %x\n", hostdata->host_id, param[0]));
                return 0;
        }
-       printk("qlogicfc.c: Fabric found.\n");
-
+       printk("qlogicfc%d : Fabric found.\n", hostdata->host_id);
+
+
+       memset(&req, 0, sizeof(req));
+       
+       req.len = 8;
+       req.response_low = virt_to_bus_low32(sns_response);
+       req.response_high = virt_to_bus_high32(sns_response);
+       req.sub_len = 22;
+       req.data[0] = 0x17;
+       req.data[1] = 0x02;
+       req.data[8] = (u_char) (hostdata->port_id & 0xff);
+       req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff);
+       req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff);
+       req.data[13] = 0x01;
+       param[0] = MBOX_SEND_SNS;
+       param[1] = 30;
+       param[2] = virt_to_bus_low32(&req) >> 16;
+       param[3] = virt_to_bus_low32(&req);
+       param[6] = virt_to_bus_high32(&req) >> 16;
+       param[7] = virt_to_bus_high32(&req);
+       
+       isp2100_mbox_command(host, param);
+       
+       if (param[0] != MBOX_COMMAND_COMPLETE)
+               printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id);               
 
        port_id = hostdata->port_id;
        while (!done) {
@@ -910,9 +986,11 @@ int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
                req.response_low = virt_to_bus_low32(sns_response);
                req.response_high = virt_to_bus_high32(sns_response);
                req.sub_len = 6;
-               req.data[0] = 0x0100;
-               req.data[4] = (u_short) (port_id & 0xffff);
-               req.data[5] = (u_short) (port_id >> 16 & 0xffff);
+               req.data[0] = 0x00;
+               req.data[1] = 0x01;
+               req.data[8] = (u_char) (port_id & 0xff);
+               req.data[9] = (u_char) (port_id >> 8 & 0xff);
+               req.data[10] = (u_char) (port_id >> 16 & 0xff);
 
                param[0] = MBOX_SEND_SNS;
                param[1] = 14;
@@ -924,7 +1002,7 @@ int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
                isp2100_mbox_command(host, param);
 
                if (param[0] == MBOX_COMMAND_COMPLETE) {
-                       DEBUG_FABRIC(printk("found node %02x%02x%02x%02x%02x%02x%02x%02x ", sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27]));
+                       DEBUG_FABRIC(printk("qlogicfc%d : found node %02x%02x%02x%02x%02x%02x%02x%02x ", hostdata->host_id, sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27]));
                        DEBUG_FABRIC(printk("  port id: %02x%02x%02x\n", sns_response[17], sns_response[18], sns_response[19]));
                        port_id = ((u_int) sns_response[17]) << 16;
                        port_id |= ((u_int) sns_response[18]) << 8;
@@ -938,7 +1016,7 @@ int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
                        wwn |= ((u64) sns_response[26]) << 8;
                        wwn |= ((u64) sns_response[27]);
                        if (hostdata->port_id >> 8 != port_id >> 8) {
-                               DEBUG_FABRIC(printk("adding a fabric port: %x\n", port_id));
+                               DEBUG_FABRIC(printk("qlogicfc%d : adding a fabric port: %x\n", hostdata->host_id, port_id));
                                param[0] = MBOX_PORT_LOGIN;
                                param[1] = loop_id << 8;
                                param[2] = (u_short) (port_id >> 16);
@@ -952,15 +1030,15 @@ int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
                                        loop_id++;
                                        scsi_id++;
                                } else {
-                                       printk("qlogicfc.c: Error performing port login %x\n", param[0]);
-                                       DEBUG_FABRIC(printk("loop_id: %x\n", loop_id));
+                                       printk("qlogicfc%d : Error performing port login %x\n", hostdata->host_id, param[0]);
+                                       DEBUG_FABRIC(printk("qlogicfc%d : loop_id: %x\n", hostdata->host_id, loop_id));
                                }
 
                        }
                        if (hostdata->port_id == port_id)
                                done = 1;
                } else {
-                       printk("qlogicfc.c: Get All Next failed %x.\n", param[0]);
+                       printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]);
                        return 0;
                }
        }
@@ -1034,15 +1112,16 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
 
        DEBUG(isp2100_print_scsi_cmd(Cmnd));
 
-       if (hostdata->loop_up == 2) {
-               hostdata->loop_up = 1;
+       if (hostdata->adapter_state == AS_REDO_PORTDB) {
+               hostdata->adapter_state = AS_LOOP_GOOD;
                isp2100_make_portdb(host);
+               printk("qlogicfc%d : Port Database\n", hostdata->host_id);
                for (i = 0; hostdata->port_db[i].wwn != 0; i++) {
-                       DEBUG(printk("wwn: %08x%08x  scsi_id: %x  loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id));
+                       printk("wwn: %08x%08x  scsi_id: %x  loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id);
                }
        }
-       if (hostdata->loop_up == -1) {
-               printk("qlogicfc.c: The firmware is dead, just return.\n");
+       if (hostdata->adapter_state == AS_FIRMWARE_DEAD) {
+               printk("qlogicfc%d : The firmware is dead, just return.\n", hostdata->host_id);
                host->max_id = 0;
                return 0;
        }
@@ -1050,13 +1129,13 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
        out_ptr = inw(host->io_port + MBOX4);
        in_ptr = hostdata->req_in_ptr;
 
-       DEBUG(printk("qlogicfc : request queue depth %d\n",
+       DEBUG(printk("qlogicfc%d : request queue depth %d\n", hostdata->host_id,
                     REQ_QUEUE_DEPTH(in_ptr, out_ptr)));
 
        cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0];
        in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN;
        if (in_ptr == out_ptr) {
-               DEBUG(printk("qlogicfc : request queue overflow\n"));
+               DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id));
                return 1;
        }
        if (hostdata->send_marker) {
@@ -1064,7 +1143,7 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
 
                TRACE("queue marker", in_ptr, 0);
 
-               DEBUG(printk("qlogicfc : adding marker entry\n"));
+               DEBUG(printk("qlogicfc%d : adding marker entry\n", hostdata->host_id));
                marker = (struct Marker_Entry *) cmd;
                memset(marker, 0, sizeof(struct Marker_Entry));
 
@@ -1077,7 +1156,7 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
                if (((in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN) == out_ptr) {
                        outw(in_ptr, host->io_port + MBOX4);
                        hostdata->req_in_ptr = in_ptr;
-                       DEBUG(printk("qlogicfc : request queue overflow\n"));
+                       DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id));
                        return 1;
                }
                cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0];
@@ -1094,8 +1173,15 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
                cmd->handle = i;
                hostdata->handle_ptrs[i] = Cmnd;
                hostdata->handle_serials[i] = Cmnd->serial_number;
-       } else
-               printk("qlogicfc: no handle slots, this should not happen.\n");
+       } else {
+               printk("qlogicfc%d : no handle slots, this should not happen.\n", hostdata->host_id);
+               printk("hostdata->queued is %x, in_ptr: %x\n", hostdata->queued, in_ptr);
+               for (i = 0; i <= QLOGICFC_REQ_QUEUE_LEN; i++){
+                       if (!hostdata->handle_ptrs[i]){
+                               printk("slot %d has %p\n", i, hostdata->handle_ptrs[i]);
+                       }
+               }
+       }
 
        cmd->hdr.entry_type = ENTRY_COMMAND;
        cmd->hdr.entry_cnt = 1;
@@ -1106,7 +1192,7 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
        cmd->target_id = Cmnd->target;
 #endif
        cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen;
-       cmd->time_out = (SCSI_TIMEOUT / HZ) * 5;
+       cmd->time_out = 0;
        memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
 
        if (Cmnd->use_sg) {
@@ -1115,15 +1201,18 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
                ds = cmd->dataseg;
                /* fill in first two sg entries: */
                n = sg_count;
-               if (n > 2)
-                       n = 2;
+               if (n > DATASEGS_PER_COMMAND)
+                       n = DATASEGS_PER_COMMAND;
+
                for (i = 0; i < n; i++) {
-                       ds[i].d_base_lo = virt_to_bus_low32(sg->address);
-                       ds[i].d_base_high = virt_to_bus_high32(sg->address);
+                       ds[i].d_base = virt_to_bus_low32(sg->address);
+#if BITS_PER_LONG > 32
+                       ds[i].d_base_hi = virt_to_bus_high32(sg->address);
+#endif
                        ds[i].d_count = sg->length;
                        ++sg;
                }
-               sg_count -= 2;
+               sg_count -= DATASEGS_PER_COMMAND;
 
                while (sg_count > 0) {
                        ++cmd->hdr.entry_cnt;
@@ -1132,28 +1221,31 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
                        memset(cont, 0, sizeof(struct Continuation_Entry));
                        in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN;
                        if (in_ptr == out_ptr) {
-                               DEBUG(printk("isp2100: unexpected request queue overflow\n"));
+                               DEBUG(printk("qlogicfc%d : unexpected request queue overflow\n", hostdata->host_id));
                                return 1;
                        }
                        TRACE("queue continuation", in_ptr, 0);
                        cont->hdr.entry_type = ENTRY_CONTINUATION;
                        ds = cont->dataseg;
                        n = sg_count;
-                       if (n > 5)
-                               n = 5;
+                       if (n > DATASEGS_PER_CONT)
+                               n = DATASEGS_PER_CONT;
                        for (i = 0; i < n; ++i) {
-                               ds[i].d_base_lo = virt_to_bus_low32(sg->address);
-                               ds[i].d_base_high = virt_to_bus_high32(sg->address);
+                               ds[i].d_base = virt_to_bus_low32(sg->address);
+#if BITS_PER_LONG > 32
+                               ds[i].d_base_hi = virt_to_bus_high32(sg->address);
+#endif
                                ds[i].d_count = sg->length;
                                ++sg;
                        }
                        sg_count -= n;
                }
        } else {
-               cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->request_buffer);
-               cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->request_buffer);
-               cmd->dataseg[0].d_count =
-                   (u_int) Cmnd->request_bufflen;
+               cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->request_buffer);
+#if BITS_PER_LONG > 32
+               cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer);
+#endif
+               cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen;
                cmd->segment_cnt = 1;
        }
 
@@ -1161,12 +1253,15 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
        case WRITE_10:
        case WRITE_6:
        case WRITE_BUFFER:
+       case MODE_SELECT:
                cmd->control_flags = CFLAG_WRITE;
                break;
        case REQUEST_SENSE:
                /* scsi.c expects sense info in a different buffer */
-               cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->sense_buffer);
-               cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->sense_buffer);
+               cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer);
+#if BITS_PER_LONG > 32
+               cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer);
+#endif
                cmd->segment_cnt = 1;
                cmd->control_flags = CFLAG_READ;
                break;
@@ -1197,6 +1292,7 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
        hostdata->req_in_ptr = in_ptr;
 
        hostdata->queued++;
+
        num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
        num_free = (num_free > 2) ? num_free - 2 : 0;
        host->can_queue = hostdata->queued + num_free;
@@ -1207,7 +1303,7 @@ int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
        /* this is really gross */
        if (host->can_queue <= host->host_busy){
                if (host->can_queue+2 < host->host_busy) 
-                       DEBUG(printk("qlogicfc.c crosses its fingers.\n"));
+                       DEBUG(printk("qlogicfc%d.c crosses its fingers.\n", hostdata->host_id));
                host->can_queue = host->host_busy + 1;
        }
 
@@ -1242,11 +1338,11 @@ void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
 
        hostdata = (struct isp2100_hostdata *) host->hostdata;
 
-       DEBUG_INTR(printk("qlogicfc : interrupt on line %d\n", irq));
+       DEBUG_INTR(printk("qlogicfc%d : interrupt on line %d\n", hostdata->host_id, irq));
 
        if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) {
                /* spurious interrupts can happen legally */
-               DEBUG_INTR(printk("qlogicfc: got spurious interrupt\n"));
+               DEBUG_INTR(printk("qlogicfc%d : got spurious interrupt\n", hostdata->host_id));
                return;
        }
        in_ptr = inw(host->io_port + MBOX5);
@@ -1255,26 +1351,28 @@ void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
        if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) {
                status = inw(host->io_port + MBOX0);
 
-               DEBUG_INTR(printk("qlogicfc : mbox completion status: %x\n",
-                                 status));
+               DEBUG_INTR(printk("qlogicfc%d : mbox completion status: %x\n",
+                                 hostdata->host_id, status));
 
                switch (status) {
                case LOOP_UP:
-                       hostdata->loop_up = 2;
+                       printk("qlogicfc%d : loop is up\n", hostdata->host_id);
+                       hostdata->adapter_state = AS_REDO_PORTDB;
                        break;
                case LOOP_DOWN:
-                       hostdata->loop_up = 0;
+                       printk("qlogicfc%d : loop is down\n", hostdata->host_id);
+                       hostdata->adapter_state = AS_LOOP_DOWN;
                        break;
                case LIP_OCCURED:
                case CHANGE_NOTIFICATION:
                case PORT_DB_CHANGED:
                case LIP_RECEIVED:
-                       if (hostdata->loop_up == 1)
-                               hostdata->loop_up = 2;
+                       if (hostdata->adapter_state == AS_LOOP_GOOD)
+                               hostdata->adapter_state = AS_REDO_PORTDB;
                        break;
                case SYSTEM_ERROR:
-                       printk("The firmware just choked.\n");
-                       hostdata->loop_up = -1;
+                       printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id);
+                       hostdata->adapter_state = AS_FIRMWARE_DEAD;
                        break;
                case SCSI_COMMAND_COMPLETE:
                        handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16);
@@ -1286,7 +1384,7 @@ void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
                                Cmnd->result = 0x0;
                                (*Cmnd->scsi_done) (Cmnd);
                        } else
-                               printk("qlogicfc.c: got a null value out of handle_ptrs, this sucks\n");
+                               printk("qlogicfc%d.c : got a null value out of handle_ptrs, this sucks\n", hostdata->host_id);
                        break;
                case MBOX_COMMAND_COMPLETE:
                case INVALID_COMMAND:
@@ -1301,12 +1399,12 @@ void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
                        outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
                        return;
                default:
-                       printk("qlogicfc: got an unknown status? %x\n", status);
+                       printk("qlogicfc%d : got an unknown status? %x\n", hostdata->host_id, status);
                }
                outw(0x0, host->io_port + PCI_SEMAPHORE);
        } else {
-               DEBUG_INTR(printk("qlogicfc : response queue update\n"));
-               DEBUG_INTR(printk("qlogicfc : response queue depth %d\n", RES_QUEUE_DEPTH(in_ptr, out_ptr)));
+               DEBUG_INTR(printk("qlogicfc%d : response queue update\n", hostdata->host_id));
+               DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr)));
 
                while (out_ptr != in_ptr) {
                        sts = (struct Status_Entry *) &hostdata->res[out_ptr][0];
@@ -1314,24 +1412,41 @@ void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
                  
                        TRACE("done", out_ptr, Cmnd);
                        DEBUG_INTR(isp2100_print_status_entry(sts));
-                       if (sts->hdr.entry_type == ENTRY_STATUS) {
-                               Cmnd = hostdata->handle_ptrs[sts->handle];
+                       if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) {
                                Cmnd->result = isp2100_return_status(sts);
                                hostdata->handle_ptrs[sts->handle] = NULL;
                                hostdata->queued--;
-                               if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number) {
+
+                               /* 
+                                * if any of the following are true we do not
+                                * call scsi_done.  if the status is CS_ABORTED
+                                * we dont have to call done because the upper
+                                * level should already know its aborted.
+                                */
+                               if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number 
+                                   || sts->completion_status == CS_ABORTED){
                                        hostdata->handle_serials[sts->handle] = 0;
                                        outw(out_ptr, host->io_port + MBOX5);
                                        continue;
                                }
-                               hostdata->handle_serials[sts->handle] = 0;
+                               /*
+                                * if we get back an error indicating the port
+                                * is not there or if the loop is down and 
+                                * this is a device that used to be there 
+                                * allow the command to timeout.
+                                * the device may well be back in a couple of
+                                * seconds.
+                                */
+                               if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == CS_PORT_UNAVAILABLE || sts->completion_status == CS_PORT_LOGGED_OUT || sts->completion_status == CS_PORT_CONFIG_CHANGED) && hostdata->port_db[Cmnd->target].wwn){
+                                       outw(out_ptr, host->io_port + MBOX5);
+                                       continue;
+                               }
                        } else {
                                outw(out_ptr, host->io_port + MBOX5);
                                continue;
                        }
 
                        if (sts->completion_status == CS_RESET_OCCURRED
-                           || sts->completion_status == CS_ABORTED
                            || (sts->status_flags & STF_BUS_RESET))
                                hostdata->send_marker = 1;
 
@@ -1345,7 +1460,7 @@ void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
                        if (Cmnd->scsi_done != NULL) {
                                (*Cmnd->scsi_done) (Cmnd);
                        } else
-                               printk("Ouch, scsi done is NULL\n");
+                               printk("qlogicfc%d : Ouch, scsi done is NULL\n", hostdata->host_id);
                }
                hostdata->res_out_ptr = out_ptr;
        }
@@ -1363,7 +1478,7 @@ void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
 
        if (host->can_queue <= host->host_busy){
                if (host->can_queue+2 < host->host_busy) 
-                       DEBUG(printk("qlogicfc crosses its fingers.\n"));
+                       DEBUG(printk("qlogicfc%d : crosses its fingers.\n", hostdata->host_id));
                host->can_queue = host->host_busy + 1;
        }
 
@@ -1448,7 +1563,7 @@ int isp2100_abort(Scsi_Cmnd * Cmnd)
        int i;
        struct Scsi_Host *host;
        struct isp2100_hostdata *hostdata;
-       int return_status = SCSI_ABORT_SUCCESS;
+       int return_status = SUCCESS;
 
        ENTER("isp2100_abort");
 
@@ -1459,27 +1574,39 @@ int isp2100_abort(Scsi_Cmnd * Cmnd)
                if (hostdata->handle_ptrs[i] == Cmnd)
                        break;
 
-       if (i == QLOGICFC_REQ_QUEUE_LEN)
-               return SCSI_ABORT_ERROR;
+       if (i == QLOGICFC_REQ_QUEUE_LEN){
+               return SUCCESS;
+       }
 
        isp2100_disable_irqs(host);
 
        param[0] = MBOX_ABORT_IOCB;
+#if ISP2100_PORTDB
+       param[1] = (((u_short) hostdata->port_db[Cmnd->target].loop_id) << 8) | Cmnd->lun;
+#else
        param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;
-       param[2] = i >> 16;
-       param[3] = i & 0xffff;
+#endif
+       param[2] = i & 0xffff;
+       param[3] = i >> 16;
 
        isp2100_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               printk("qlogicfc : scsi abort failure: %x\n", param[0]);
+               printk("qlogicfc%d : scsi abort failure: %x\n", hostdata->host_id, param[0]);
                if (param[0] == 0x4005)
                        Cmnd->result = DID_ERROR << 16;
                if (param[0] == 0x4006)
                        Cmnd->result = DID_BAD_TARGET << 16;
-               (*Cmnd->scsi_done) (Cmnd);
-               return_status = SCSI_ABORT_ERROR;
+               return_status = FAILED;
        }
+
+       if (return_status != SUCCESS){
+               param[0] = MBOX_GET_FIRMWARE_STATE;
+               isp2100_mbox_command(host, param);
+               printk("qlogicfc%d : abort failed\n", hostdata->host_id);
+               printk("qlogicfc%d : firmware status is %x %x\n", hostdata->host_id, param[0], param[1]);
+       }
+
        isp2100_enable_irqs(host);
 
        LEAVE("isp2100_abort");
@@ -1507,7 +1634,7 @@ int isp2100_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags)
        isp2100_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               printk("qlogicfc : scsi bus reset failure: %x\n", param[0]);
+               printk("qlogicfc%d : scsi bus reset failure: %x\n", hostdata->host_id, param[0]);
                return_status = SCSI_RESET_ERROR;
        }
        isp2100_enable_irqs(host);
@@ -1546,6 +1673,8 @@ static int isp2100_reset_hardware(struct Scsi_Host *host)
 
        ENTER("isp2100_reset_hardware");
 
+       hostdata = (struct isp2100_hostdata *) host->hostdata;
+
        outw(0x01, host->io_port + ISP_CTRL_STATUS);
        outw(HCCR_RESET, host->io_port + HOST_HCCR);
        outw(HCCR_RELEASE, host->io_port + HOST_HCCR);
@@ -1555,22 +1684,22 @@ static int isp2100_reset_hardware(struct Scsi_Host *host)
        while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY)
                barrier();
        if (!loop_count)
-               printk("qlogicfc: reset_hardware loop timeout\n");
+               printk("qlogicfc%d : reset_hardware loop timeout\n", hostdata->host_id);
 
 
 
 #if DEBUG_ISP2100
-       printk("qlogicfc : mbox 0 0x%04x \n", inw(host->io_port + MBOX0));
-       printk("qlogicfc : mbox 1 0x%04x \n", inw(host->io_port + MBOX1));
-       printk("qlogicfc : mbox 2 0x%04x \n", inw(host->io_port + MBOX2));
-       printk("qlogicfc : mbox 3 0x%04x \n", inw(host->io_port + MBOX3));
-       printk("qlogicfc : mbox 4 0x%04x \n", inw(host->io_port + MBOX4));
-       printk("qlogicfc : mbox 5 0x%04x \n", inw(host->io_port + MBOX5));
-       printk("qlogicfc : mbox 6 0x%04x \n", inw(host->io_port + MBOX6));
-       printk("qlogicfc : mbox 7 0x%04x \n", inw(host->io_port + MBOX7));
+       printk("qlogicfc%d : mbox 0 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX0));
+       printk("qlogicfc%d : mbox 1 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX1));
+       printk("qlogicfc%d : mbox 2 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX2));
+       printk("qlogicfc%d : mbox 3 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX3));
+       printk("qlogicfc%d : mbox 4 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX4));
+       printk("qlogicfc%d : mbox 5 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX5));
+       printk("qlogicfc%d : mbox 6 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX6));
+       printk("qlogicfc%d : mbox 7 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX7));
 #endif                         /* DEBUG_ISP2100 */
 
-       DEBUG(printk("qlogicfc : verifying checksum\n"));
+       DEBUG(printk("qlogicfc%d : verifying checksum\n", hostdata->host_id));
 
 #if RELOAD_FIRMWARE
        {
@@ -1583,7 +1712,7 @@ static int isp2100_reset_hardware(struct Scsi_Host *host)
                        isp2100_mbox_command(host, param);
 
                        if (param[0] != MBOX_COMMAND_COMPLETE) {
-                               printk("qlogicfc : firmware load failure\n");
+                               printk("qlogicfc%d : firmware load failure\n", hostdata->host_id);
                                return 1;
                        }
                }
@@ -1596,10 +1725,10 @@ static int isp2100_reset_hardware(struct Scsi_Host *host)
        isp2100_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               printk("qlogicfc : ram checksum failure\n");
+               printk("qlogicfc%d : ram checksum failure\n", hostdata->host_id);
                return 1;
        }
-       DEBUG(printk("qlogicfc : executing firmware\n"));
+       DEBUG(printk("qlogicfc%d : executing firmware\n", hostdata->host_id));
 
        param[0] = MBOX_EXEC_FIRMWARE;
        param[1] = risc_code_addr01;
@@ -1611,18 +1740,16 @@ static int isp2100_reset_hardware(struct Scsi_Host *host)
        isp2100_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               printk("qlogicfc : about firmware failure\n");
+               printk("qlogicfc%d : about firmware failure\n", hostdata->host_id);
                return 1;
        }
-       DEBUG(printk("qlogicfc : firmware major revision %d\n", param[1]));
-       DEBUG(printk("qlogicfc : firmware minor revision %d\n", param[2]));
-
-       hostdata = (struct isp2100_hostdata *) host->hostdata;
+       DEBUG(printk("qlogicfc%d : firmware major revision %d\n", hostdata->host_id,  param[1]));
+       DEBUG(printk("qlogicfc%d : firmware minor revision %d\n", hostdata->host_id,  param[2]));
 
 #ifdef USE_NVRAM_DEFAULTS
 
        if (isp2100_get_nvram_defaults(host, &hostdata->control_block) != 0) {
-               printk("qlogicfc: Could not read from NVRAM\n");
+               printk("qlogicfc%d : Could not read from NVRAM\n", hostdata->host_id);
        }
 #endif
 
@@ -1644,13 +1771,13 @@ static int isp2100_reset_hardware(struct Scsi_Host *host)
        param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff);
        isp2100_mbox_command(host, param);
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               printk("qlogicfc.c: Ouch 0x%04x\n", param[0]);
+               printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id,  param[0]);
                return 1;
        }
        param[0] = MBOX_GET_FIRMWARE_STATE;
        isp2100_mbox_command(host, param);
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               printk("qlogicfc.c: 0x%04x\n", param[0]);
+               printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id,  param[0]);
                return 1;
        }
 
@@ -1698,7 +1825,7 @@ static int isp2100_init(struct Scsi_Host *sh)
 
        if (pci_read_config_word(pdev, PCI_COMMAND, &command)
          || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision)) {
-               printk("qlogicfc : error reading PCI configuration\n");
+               printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id);
                return 1;
        }
        io_base = pdev->base_address[0];
@@ -1707,28 +1834,28 @@ static int isp2100_init(struct Scsi_Host *sh)
 
 
        if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) {
-               printk("qlogicfc : 0x%04x is not QLogic vendor ID\n",
+               printk("qlogicfc%d : 0x%04x is not QLogic vendor ID\n", hostdata->host_id, 
                       pdev->vendor);
                return 1;
        }
        if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100) {
-               printk("qlogicfc : 0x%04x does not match ISP2100 device id\n",
+               printk("qlogicfc%d : 0x%04x does not match ISP2100 device id\n", hostdata->host_id, 
                       pdev->device);
                return 1;
        }
        if (command & PCI_COMMAND_IO && (io_base & 3) == 1)
                io_base &= PCI_BASE_ADDRESS_IO_MASK;
        else {
-               printk("qlogicfc : i/o mapping is disabled\n");
+               printk("qlogicfc%d : i/o mapping is disabled\n", hostdata->host_id);
                return 1;
        }
 
        if (!(command & PCI_COMMAND_MASTER)) {
-               printk("qlogicfc : bus mastering is disabled\n");
+               printk("qlogicfc%d : bus mastering is disabled\n", hostdata->host_id);
                return 1;
        }
        if (revision != ISP2100_REV_ID && revision != ISP2100_REV_ID3)
-               printk("qlogicfc : new isp2100 revision ID (%d)\n", revision);
+               printk("qlogicfc%d : new isp2100 revision ID (%d)\n", hostdata->host_id,  revision);
 
 
        hostdata->revision = revision;
@@ -1800,21 +1927,22 @@ static int isp2100_mbox_command(struct Scsi_Host *host, u_short param[])
        int loop_count;
        struct isp2100_hostdata *hostdata = (struct isp2100_hostdata *) host->hostdata;
 
-       if (mbox_param[param[0]] == 0)
+       if (mbox_param[param[0]] == 0 || hostdata->adapter_state == AS_FIRMWARE_DEAD)
                return 1;
 
        loop_count = DEFAULT_LOOP_COUNT;
        while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080)
                barrier();
        if (!loop_count) {
-               printk("qlogicfc: mbox_command loop timeout #1\n");
+               printk("qlogicfc%d : mbox_command loop timeout #1\n", hostdata->host_id);
                param[0] = 0x4006;
+               hostdata->adapter_state = AS_FIRMWARE_DEAD;
                return 1;
        }
        hostdata->mbox_done = 0;
 
        if (mbox_param[param[0]] == 0)
-               printk("qlogicfc: invalid mbox command\n");
+               printk("qlogicfc%d : invalid mbox command\n", hostdata->host_id);
 
        if (mbox_param[param[0]] & 0x80)
                outw(param[7], host->io_port + MBOX7);
@@ -1843,7 +1971,8 @@ static int isp2100_mbox_command(struct Scsi_Host *host, u_short param[])
                }
 
                if (!loop_count) {
-                       printk("qlogicfc: mbox_command loop timeout #2\n");
+                       hostdata->adapter_state = AS_FIRMWARE_DEAD;
+                       printk("qlogicfc%d : mbox_command loop timeout #2\n", hostdata->host_id);
                        break;
                }
                isp2100_intr_handler(host->irq, host, NULL);
@@ -1858,7 +1987,7 @@ static int isp2100_mbox_command(struct Scsi_Host *host, u_short param[])
                barrier();
        }
        if (!loop_count)
-               printk("qlogicfc: mbox_command loop timeout #3\n");
+               printk("qlogicfc%d : mbox_command loop timeout #3\n", hostdata->host_id);
 
        param[7] = inw(host->io_port + MBOX7);
        param[6] = inw(host->io_port + MBOX6);
@@ -1873,19 +2002,21 @@ static int isp2100_mbox_command(struct Scsi_Host *host, u_short param[])
        outw(0x0, host->io_port + PCI_SEMAPHORE);
 
        if (inw(host->io_port + HOST_HCCR) & 0x0080) {
-               printk("mbox op is still pending\n");
+               hostdata->adapter_state = AS_FIRMWARE_DEAD;
+               printk("qlogicfc%d : mbox op is still pending\n", hostdata->host_id);
        }
        return 0;
 }
 
+#if DEBUG_ISP2100_INTR
 
 void isp2100_print_status_entry(struct Status_Entry *status)
 {
-       printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n",
+       printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", 
        status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
        printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n",
               status->scsi_status, status->completion_status);
-       printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n",
+       printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", 
               status->state_flags, status->status_flags);
        printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n",
               status->res_info_len, status->req_sense_len);
@@ -1893,6 +2024,7 @@ void isp2100_print_status_entry(struct Status_Entry *status)
 
 }
 
+#endif                         /* DEBUG_ISP2100_INTR */
 
 
 #if DEBUG_ISP2100
@@ -1901,7 +2033,7 @@ void isp2100_print_scsi_cmd(Scsi_Cmnd * cmd)
 {
        int i;
 
-       printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
+       printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", 
               cmd->target, cmd->lun, cmd->cmd_len);
        printk("qlogicfc : command = ");
        for (i = 0; i < cmd->cmd_len; i++)
index ad35329621ec55d1f15138dd2f13f4526428d732..f1f5d3c0e7515bd390dc1224ea3add4131175586 100644 (file)
  * requests are queued serially and the scatter/gather limit is
  * determined for each queue request anew.
  */
-#define QLOGICFC_REQ_QUEUE_LEN 63      /* must be power of two - 1 */
-#define QLOGICFC_MAX_SG(ql)    (2 + (((ql) > 0) ? 5*((ql) - 1) : 0))
+
+#if BITS_PER_LONG > 32
+#define DATASEGS_PER_COMMAND 2
+#define DATASEGS_PER_CONT 5
+#else
+#define DATASEGS_PER_COMMAND 3
+#define DATASEGS_PER_CONT 7
+#endif
+
+#define QLOGICFC_REQ_QUEUE_LEN 127     /* must be power of two - 1 */
+#define QLOGICFC_MAX_SG(ql)    (DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0))
 #define QLOGICFC_CMD_PER_LUN    8
 
 int isp2100_detect(Scsi_Host_Template *);
@@ -84,16 +93,16 @@ extern struct proc_dir_entry proc_scsi_isp2100;
         release:                isp2100_release,                           \
         info:                   isp2100_info,                              \
         queuecommand:           isp2100_queuecommand,                      \
-        abort:                  isp2100_abort,                             \
+        eh_abort_handler:       isp2100_abort,                             \
         reset:                  isp2100_reset,                             \
         bios_param:             isp2100_biosparam,                         \
         can_queue:              QLOGICFC_REQ_QUEUE_LEN,                    \
         this_id:                -1,                                        \
         sg_tablesize:           QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN),   \
-        cmd_per_lun:            QLOGICFC_CMD_PER_LUN,                      \
+       cmd_per_lun:            QLOGICFC_CMD_PER_LUN,                      \
         present:                0,                                         \
         unchecked_isa_dma:      0,                                         \
-        use_clustering:         DISABLE_CLUSTERING                         \
+        use_clustering:         ENABLE_CLUSTERING                         \
 }
 
 #endif /* _QLOGICFC_H */
index 436a95d01d6f49c8530670dfcf07f28a807f777d..46f1f253c76fb0f245e11aef55f648011ce7f5fd 100644 (file)
@@ -1065,8 +1065,10 @@ int isp1020_biosparam(Disk *disk, kdev_t n, int ip[])
                ip[0] = 255;
                ip[1] = 63;
                ip[2] = size / (ip[0] * ip[1]);
+#if 0
                if (ip[2] > 1023)
                        ip[2] = 1023;
+#endif                 
        }
 
        LEAVE("isp1020_biosparam");
index 8536f69b433f6bb4efcb2609be36bbb82a51b032..2eac00ff4bb51c93c7b100b95a848c3e4bc8c25f 100644 (file)
 #include <asm/system.h>
 #include <asm/io.h>
 
-#ifdef MODULE
-#include <linux/module.h>
-#endif
-
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
index 166a66df23717bf76019a69adcc7b5e6070ee7e8..e13cda2bb7775fc0b9fea06813d335103ce3d7ff 100644 (file)
@@ -3,6 +3,10 @@
  *  Low-level SCSI driver for sym53c416 chip.
  *  Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com)
  * 
+ *  Changes : 
+ * 
+ *  Marcelo Tosatti <marcelo@conectiva.com.br> : Added io_request_lock locking
+ * 
  *  LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>]
  *
  *  This program is free software; you can redistribute it and/or modify it
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/spinlock.h>
 #include <linux/blk.h>
 #include <linux/version.h>
 #include "scsi.h"
@@ -371,7 +375,9 @@ static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
     printk("sym53c416: Warning: Reset received\n");
     current_command->SCp.phase = idle;
     current_command->result = DID_RESET << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(int_reg & ILCMD)       /* Illegal Command */
@@ -379,7 +385,9 @@ static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
     printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG));
     current_command->SCp.phase = idle;
     current_command->result = DID_ERROR << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(status_reg & GE)         /* Gross Error */
@@ -387,7 +395,9 @@ static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
     printk("sym53c416: Warning: Gross Error\n");
     current_command->SCp.phase = idle;
     current_command->result = DID_ERROR << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(status_reg & PE)         /* Parity Error */
@@ -395,7 +405,9 @@ static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
     printk("sym53c416: Warning: Parity Error\n");
     current_command->SCp.phase = idle;
     current_command->result = DID_PARITY << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(pio_int_reg & (CE | OUE))
@@ -403,7 +415,9 @@ static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
     printk("sym53c416: Warning: PIO Interrupt Error\n");
     current_command->SCp.phase = idle;
     current_command->result = DID_ERROR << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(int_reg & DIS)           /* Disconnect */
@@ -413,7 +427,10 @@ static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
     else
       current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
     current_command->SCp.phase = idle;
+
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   /* Now we handle SCSI phases         */
index 40db75465589cf610650b823cd49f4a80a0fbc5d..ae2c59e1e7e7aeba89804da6a28b84146549b69b 100644 (file)
@@ -53,7 +53,7 @@ sgi_usema_attach (usattach_t * attach, struct irix_usema *usema)
        if (newfd < 0)
                return newfd;
        
-       get_file(usema);
+       get_file(usema->filp);
        fd_install(newfd, usema->filp);
        /* Is that it? */
        printk("UIOCATTACHSEMA: new usema fd is %d", newfd);
index c6f4f45c692e9fa9f062e868830101f7462f5797..d85429745d765ef2d75392a6ac49207ac467f955 100644 (file)
@@ -2311,9 +2311,7 @@ __initfunc(int init_cmpci(void))
                index++;
                continue;
 
-       err_dev4:
                unregister_sound_midi(s->dev_midi);
-       err_dev3:
                unregister_sound_mixer(s->dev_mixer);
        err_dev2:
                unregister_sound_dsp(s->dev_audio);
@@ -2328,7 +2326,6 @@ __initfunc(int init_cmpci(void))
 #ifdef CONFIG_SOUND_CMPCI_MIDI
                release_region(s->iomidi, CM_EXTENT_MIDI);
 #endif
-       err_region4:
                release_region(s->iobase, CM_EXTENT_CODEC);
        err_region5:
                kfree_s(s, sizeof(struct cm_state));
index 7043885f0d1a631ff37d2db8d48750a6810aa5a1..af72621c05f5830309e04ab2f05b3762ad8931b4 100644 (file)
 #define SNDCARD_DESKPROXL              27      /* Compaq Deskpro XL */
 #define SNDCARD_VIDC                   28      /* ARMs VIDC */
 #define SNDCARD_SBPNP                  29
-#define SNDCARD_OPL3SA1                        38
-#define SNDCARD_OPL3SA1_SB             39
-#define SNDCARD_OPL3SA1_MPU            40
 #define SNDCARD_SOFTOSS                        36
 #define SNDCARD_VMIDI                  37
+#define SNDCARD_OPL3SA1                        38      /* Note: clash in msnd.h */
+#define SNDCARD_OPL3SA1_SB             39
+#define SNDCARD_OPL3SA1_MPU            40
 #define SNDCARD_WAVEFRONT               41
 #define SNDCARD_OPL3SA2                 42
 #define SNDCARD_OPL3SA2_MPU             43
 #define SNDCARD_WAVEARTIST             44
+#define SNDCARD_OPL3SA2_MSS             45     /* Originally missed */
 #define SNDCARD_AD1816                  88
 
-void attach_opl3sa_wss (struct address_info *hw_config);
-int probe_opl3sa_wss (struct address_info *hw_config);
-void attach_opl3sa_sb (struct address_info *hw_config);
-int probe_opl3sa_sb (struct address_info *hw_config);
-void attach_opl3sa_mpu (struct address_info *hw_config);
-int probe_opl3sa_mpu (struct address_info *hw_config);
-void unload_opl3sa_wss(struct address_info *hw_info);
-void unload_opl3sa_sb(struct address_info *hw_info);
-void unload_opl3sa_mpu(struct address_info *hw_info);
-void attach_softsyn_card (struct address_info *hw_config);
-int probe_softsyn (struct address_info *hw_config);
-void unload_softsyn (struct address_info *hw_config);
-
 /*
  *     NOTE!   NOTE!   NOTE!   NOTE!
  *
@@ -424,6 +412,7 @@ struct driver_info sound_drivers[] =
 
 #ifdef CONFIG_SOUND_OPL3SA2
        {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2",              attach_opl3sa2, probe_opl3sa2, unload_opl3sa2},
+       {"OPL3SA2MSS", 1, SNDCARD_OPL3SA2_MSS,  "OPL3SA2 MSS",          attach_opl3sa2_mss, probe_opl3sa2_mss, unload_opl3sa2_mss},
        {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU,  "OPL3SA2 MIDI",         attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu},
 #endif
 
@@ -587,10 +576,11 @@ struct card_info snd_installed_cards[] =
 #ifndef CONFIG_OPL3SA2_DMA2
 #define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA
 #endif
+       {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_CTRL_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE},
+       {SNDCARD_OPL3SA2_MSS, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE},
 #ifdef CONFIG_OPL3SA2_MPU_BASE
-       {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+       {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, CONFIG_OPL3SA2_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
-       {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifdef CONFIG_SGALAXY
index d7579ffa4f4e1283cd81ddcbed86fbe588144bac..7c2093a43911b706ad77d989cd0f2115d9f2ed6f 100644 (file)
@@ -2308,9 +2308,9 @@ static struct initvol {
 };
 
 #ifdef MODULE
-__initfunc(int init_module(void))
+int __init init_module(void)
 #else
-__initfunc(int init_es1370(void))
+int __init init_es1370(void)
 #endif
 {
        struct es1370_state *s;
index a0f3969e01882f2685a22905b7adc5544cfff7c2..80812de15371d3ea46397932e4de10dbaa9ba065 100644 (file)
@@ -2723,9 +2723,9 @@ static struct initvol {
 };
 
 #ifdef MODULE
-__initfunc(int init_module(void))
+int __init init_module(void)
 #else
-__initfunc(int init_es1371(void))
+int __init init_es1371(void)
 #endif
 {
        struct es1371_state *s;
index cbb01dc5c56c3df6422c5d76a88d96895b68e2ba..9b00cc6f9612b3dcab5c7e3af82e399cf2c1b87c 100644 (file)
@@ -51,7 +51,6 @@
 
 #ifdef AWE_OBSOLETE_VOXWARE
 
-#include <i386/isa/sound/sound_config.h>
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32)
 #define CONFIG_AWE32_SYNTH
 #endif
index d6b12e07b03547c9d62194172008760b6316e75b..531957453cf995683747c098f78086e7ba638d0f 100644 (file)
  *                                     system
  *
  *     Status:
- *             Untested
+ *             Andrew J. Kroll         Tested 06/01/1999 with:
+ *                                     * OSWF.MOT File Version: 1.15
+ *                                     * OSWF.MOT File Dated: 09/12/94
+ *                                     * Older versions will cause problems.
  */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <asm/init.h>
index 05845cf96f86e90fa98ff15038ea3b1e9f97cd5c..0528acbc506a37822a55e91ff55c69069b684700 100644 (file)
@@ -1165,7 +1165,7 @@ static int reset_dsp(void)
        return -EIO;
 }
 
-__initfunc(static int probe_multisound(void))
+static int __init probe_multisound(void)
 {
 #ifndef MSND_CLASSIC
        char *xv, *rev = NULL;
@@ -1305,7 +1305,7 @@ static int init_sma(void)
        return 0;
 }
 
-__initfunc(static int calibrate_adc(WORD srate))
+static int __init calibrate_adc(WORD srate)
 {
        writew(srate, dev.SMA + SMA_wCalFreqAtoD);
        if (dev.calibrate_signal == 0)
@@ -1427,7 +1427,7 @@ static int dsp_full_reset(void)
        return rv;
 }
 
-__initfunc(static int attach_multisound(void))
+static int __init attach_multisound(void)
 {
        int err;
 
@@ -1491,7 +1491,7 @@ static void unload_multisound(void)
 
 /* Pinnacle/Fiji Logical Device Configuration */
 
-__initfunc(static int msnd_write_cfg(int cfg, int reg, int value))
+static int __init msnd_write_cfg(int cfg, int reg, int value)
 {
        outb(reg, cfg);
        outb(value, cfg + 1);
@@ -1502,7 +1502,7 @@ __initfunc(static int msnd_write_cfg(int cfg, int reg, int value))
        return 0;
 }
 
-__initfunc(static int msnd_write_cfg_io0(int cfg, int num, WORD io))
+static int __init msnd_write_cfg_io0(int cfg, int num, WORD io)
 {
        if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
                return -EIO;
@@ -1513,7 +1513,7 @@ __initfunc(static int msnd_write_cfg_io0(int cfg, int num, WORD io))
        return 0;
 }
 
-__initfunc(static int msnd_write_cfg_io1(int cfg, int num, WORD io))
+static int __init msnd_write_cfg_io1(int cfg, int num, WORD io)
 {
        if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
                return -EIO;
@@ -1524,7 +1524,7 @@ __initfunc(static int msnd_write_cfg_io1(int cfg, int num, WORD io))
        return 0;
 }
 
-__initfunc(static int msnd_write_cfg_irq(int cfg, int num, WORD irq))
+static int __init msnd_write_cfg_irq(int cfg, int num, WORD irq)
 {
        if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
                return -EIO;
@@ -1535,7 +1535,7 @@ __initfunc(static int msnd_write_cfg_irq(int cfg, int num, WORD irq))
        return 0;
 }
 
-__initfunc(static int msnd_write_cfg_mem(int cfg, int num, int mem))
+static int __init msnd_write_cfg_mem(int cfg, int num, int mem)
 {
        WORD wmem;
 
@@ -1553,7 +1553,7 @@ __initfunc(static int msnd_write_cfg_mem(int cfg, int num, int mem))
        return 0;
 }
 
-__initfunc(static int msnd_activate_logical(int cfg, int num))
+static int __init msnd_activate_logical(int cfg, int num)
 {
        if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
                return -EIO;
@@ -1562,7 +1562,7 @@ __initfunc(static int msnd_activate_logical(int cfg, int num))
        return 0;
 }
 
-__initfunc(static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem))
+static int __init msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem)
 {
        if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
                return -EIO;
@@ -1584,7 +1584,7 @@ typedef struct msnd_pinnacle_cfg_device {
        int mem;
 } msnd_pinnacle_cfg_t[4];
 
-__initfunc(static int msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device))
+static int __init msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device)
 {
        int i;
 
@@ -1767,9 +1767,9 @@ static int
 calibrate_signal __initdata =          CONFIG_MSND_CALSIGNAL;
 
 #ifdef MSND_CLASSIC
-__initfunc(int msnd_classic_init(void))
+int __init msnd_classic_init(void)
 #else
-__initfunc(int msnd_pinnacle_init(void))
+int __init msnd_pinnacle_init(void)
 #endif /* MSND_CLASSIC */
 
 #endif /* MODULE */
index 2c996da64201b918b8aa999984a2fd756eb3bd87..68c37778f841ed75a89cacee4ca3beb965b45151 100644 (file)
@@ -467,13 +467,13 @@ void unload_opl3sa2_mpu(struct address_info *hw_config)
 }
 
 
-static int probe_opl3sa2_mss(struct address_info *hw_config)
+int probe_opl3sa2_mss(struct address_info *hw_config)
 {
        return probe_ms_sound(hw_config);
 }
 
 
-static void attach_opl3sa2_mss(struct address_info *hw_config)
+void attach_opl3sa2_mss(struct address_info *hw_config)
 {
        char mixer_name[64];
 
@@ -516,7 +516,7 @@ static void attach_opl3sa2_mss(struct address_info *hw_config)
 }
 
 
-static void unload_opl3sa2_mss(struct address_info *hw_config)
+void unload_opl3sa2_mss(struct address_info *hw_config)
 {
        unload_ms_sound(hw_config);
 }
@@ -592,6 +592,9 @@ int probe_opl3sa2(struct address_info *hw_config)
        {
                /* Generate a pretty name */
                sprintf(chipset_name, "OPL3-SA%c", tag);
+#if defined(CONFIG_OPL3SA2_MPU_BASE) && !defined(MODULE)
+               sound_getconf(SNDCARD_OPL3SA2_MPU)->always_detect = 1;
+#endif
                return 1;
        }
        return 0;
index 3f55b74cf777a5c8f8e1277bc71a1624e160b95b..723e88aa108b49227c0934ce5b7334ad2aca20dc 100644 (file)
  *                                                             recording problems for high samplerates. I
  *                                                             fixed this by removing ess_calc_best_speed ()
  *                                                             and just doing what the documentation says. 
- *Javier Achirica(May 15 1999): Major cleanup, MPU IRQ sharing, hardware
- *                                                             volume support, PNP chip configuration,
- *                                                             full duplex in most cards, sample rate fine
- *                                                             tuning.
+ * Andy Sloane  (June 4 1999):  Stole some code from ALSA to fix the playback
+ * andy@guildsoftware.com              speed on ES1869, ES1879, ES1887, and ES1888.
+ *                                                             1879's were previously ignored by this driver;
+ *                                                             added (untested) support for those.
  *
  * This files contains ESS chip specifics. It's based on the existing ESS
  * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This
 #define ESSTYPE_LIKE20 -1              /* Mimic 2.0 behaviour                                  */
 #define ESSTYPE_DETECT 0               /* Mimic 2.0 behaviour                                  */
 
-int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */
+int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */
 
-#define SUBMDL_ES688   0x00    /* Subtype ES688 for specific handling */
-#define SUBMDL_ES1688  0x08    /* Subtype ES1688 for specific handling */
 #define SUBMDL_ES1788  0x10    /* Subtype ES1788 for specific handling */
 #define SUBMDL_ES1868  0x11    /* Subtype ES1868 for specific handling */
 #define SUBMDL_ES1869  0x12    /* Subtype ES1869 for specific handling */
 #define SUBMDL_ES1878  0x13    /* Subtype ES1878 for specific handling */
-#define SUBMDL_ES1879  0x14    /* Subtype ES1879 for specific handling */
-#define SUBMDL_ES1887  0x15    /* Subtype ES1887 for specific handling */
-#define SUBMDL_ES1888  0x16    /* Subtype ES1888 for specific handling */
-
-       /* Recording mixer, stereo full duplex */
-#define ESSCAP_NEW             0x00000100
-       /* ISA PnP configuration */
-#define ESSCAP_PNP             0x00000200
-       /* Full duplex, 6-bit volume, hardware volume controls */
-#define ESSCAP_ES18            0x00000400
-       /* New interrupt handling system (ESS 1887) */
-#define ESSCAP_IRQ             0x00000800
-
-#define ESSFMT_16              0x00000001
-#define ESSFMT_SIGNED  0x00000004
+#define SUBMDL_ES1879  0x16    /* ES1879 was initially forgotten */
+#define SUBMDL_ES1887  0x14    /* Subtype ES1887 for specific handling */
+#define SUBMDL_ES1888  0x15    /* Subtype ES1888 for specific handling */
+
+#define SB_CAP_ES18XX_RATE 0x100
+
+#define ES1688_CLOCK1 795444 /* 128 - div */
+#define ES1688_CLOCK2 397722 /* 256 - div */
+#define ES18XX_CLOCK1 793800 /* 128 - div */
+#define ES18XX_CLOCK2 768000 /* 256 - div */
 
 #ifdef FKS_LOGGING
 static void ess_show_mixerregs (sb_devc *devc);
@@ -233,6 +226,52 @@ static void ess_chgmixer
  *                                                                                                                                                     *
  ****************************************************************************/
 
+struct ess_command {short cmd; short data;};
+
+/*
+ * Commands for initializing Audio 1 for input (record)
+ */
+static struct ess_command ess_i08m[] =         /* input 8 bit mono */
+       { {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} };
+static struct ess_command ess_i16m[] =         /* input 16 bit mono */
+       { {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} };
+static struct ess_command ess_i08s[] =         /* input 8 bit stereo */
+       { {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} };
+static struct ess_command ess_i16s[] =         /* input 16 bit stereo */
+       { {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} };
+
+static struct ess_command *ess_inp_cmds[] =
+       { ess_i08m, ess_i16m, ess_i08s, ess_i16s };
+
+
+/*
+ * Commands for initializing Audio 1 for output (playback)
+ */
+static struct ess_command ess_o08m[] =         /* output 8 bit mono */
+       { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} };
+static struct ess_command ess_o16m[] =         /* output 16 bit mono */
+       { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} };
+static struct ess_command ess_o08s[] =         /* output 8 bit stereo */
+       { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} };
+static struct ess_command ess_o16s[] =         /* output 16 bit stereo */
+       { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} };
+
+static struct ess_command *ess_out_cmds[] =
+       { ess_o08m, ess_o16m, ess_o08s, ess_o16s };
+
+static void ess_exec_commands
+       (sb_devc *devc, struct ess_command *cmdtab[])
+{
+       struct ess_command *cmd;
+
+       cmd = cmdtab [ ((devc->channels != 1) << 1) + (devc->bits != AFMT_U8) ];
+
+       while (cmd->cmd != -1) {
+               ess_write (devc, cmd->cmd, cmd->data);
+               cmd++;
+       }
+}
+
 static void ess_change
        (sb_devc *devc, unsigned int reg, unsigned int mask, unsigned int val)
 {
@@ -272,21 +311,53 @@ static void ess_set_input_parms
        devc->irq_mode = IMODE_INPUT;
 }
 
-static int ess_calc_div (int clock, int *speedp, int *diffp)
+static int ess_calc_div (int clock, int revert, int *speedp, int *diffp)
 {
        int divider;
        int speed, diff;
+       int retval;
 
        speed   = *speedp;
        divider = (clock + speed / 2) / speed;
-       if (divider > 127) {
-               divider = 127;
+       retval  = revert - divider;
+       if (retval > revert - 1) {
+               retval  = revert - 1;
+               divider = revert - retval;
        }
+       /* This line is suggested. Must be wrong I think
+       *speedp = (clock + divider / 2) / divider;
+       So I chose the next one */
+
        *speedp = clock / divider;
        diff    = speed - *speedp;
-       *diffp = diff < 0 ? -diff : diff;
+       if (diff < 0) diff =-diff;
+       *diffp  = diff;
+
+       return retval;
+}
+
+static int ess_calc_best_speed
+       (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp)
+{
+       int speed1 = *speedp, speed2 = *speedp;
+       int div1, div2;
+       int diff1, diff2;
+       int retval;
+
+       div1 = ess_calc_div (clock1, rev1, &speed1, &diff1);
+       div2 = ess_calc_div (clock2, rev2, &speed2, &diff2);
+
+       if (diff1 < diff2) {
+               *divp   = div1;
+               *speedp = speed1;
+               retval  = 1;
+       } else {
+               *divp   = div2;
+               *speedp = speed2;
+               retval  = 2;
+       }
 
-       return 128 - divider;
+       return retval;
 }
 
 /*
@@ -299,30 +370,24 @@ static int ess_calc_div (int clock, int *speedp, int *diffp)
  */
 static void ess_common_speed (sb_devc *devc, int *speedp, int *divp)
 {
-       int speed1 = *speedp, speed2 = *speedp;
-       int div1, div2;
-       int diff1, diff2;
+       int diff = 0, div;
 
-       if (devc->caps & ESSCAP_NEW) {
-               div1 = 0x000 | ess_calc_div (793800, &speed1, &diff1);
-               div2 = 0x080 | ess_calc_div (768000, &speed2, &diff2);
+       if (devc->duplex) {
+               /*
+                * The 0x80 is important for the first audio channel
+                */
+               div = 0x80 | ess_calc_div (795500, 128, speedp, &diff);
+       } else if(devc->caps & SB_CAP_ES18XX_RATE) {
+               ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, 
+                                               &div, speedp);
        } else {
                if (*speedp > 22000) {
-                       div1 = 0x080 | ess_calc_div (795444, &speed1, &diff1);
-                       div2 = 0x180 | ess_calc_div (793800, &speed2, &diff2);
+                       div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff);
                } else {
-                       div1 = 0x000 | ess_calc_div (397722, &speed1, &diff1);
-                       div2 = 0x100 | ess_calc_div (396900, &speed2, &diff2);
+                       div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff);
                }
        }
-
-       if (diff1 < diff2) {
-               *divp   = div1;
-               *speedp = speed1;
-       } else {
-               *divp   = div2;
-               *speedp = speed2;
-       }
+       *divp = div;
 }
 
 static void ess_speed (sb_devc *devc, int audionum)
@@ -341,13 +406,21 @@ printk (KERN_INFO "FKS: ess_speed (%d) b speed = %d, div=%x\n", audionum, devc->
 
        div2 = 256 - 7160000 / (speed * 82);
 
-       if ((devc->caps & ESSCAP_NEW) && audionum != 1) {
-               ess_setmixer (devc, 0x70, div);
-               ess_setmixer (devc, 0x72, div2);
+       if (!devc->duplex) audionum = 1;
+
+       if (audionum == 1) {
+               /* Change behaviour of register A1 *
+               sb_chg_mixer(devc, 0x71, 0x20, 0x20)
+               * For ES1869 only??? */
+               ess_write (devc, 0xa1, div);
+               ess_write (devc, 0xa2, div2);
        } else {
-               ess_change (devc, 0xba, 0x40, (div & 0x100) ? 0x40 : 0x00);
-               ess_write (devc, 0xa1, div & 0xff);
+               ess_setmixer (devc, 0x70, div);
+               /*
+                * FKS: fascinating: 0x72 doesn't seem to work.
+                */
                ess_write (devc, 0xa2, div2);
+               ess_setmixer (devc, 0x72, div2);
        }
 }
 
@@ -355,14 +428,77 @@ static int ess_audio_prepare_for_input(int dev, int bsize, int bcount)
 {
        sb_devc *devc = audio_devs[dev]->devc;
 
+       ess_speed(devc, 1);
+
+       sb_dsp_command(devc, DSP_CMD_SPKOFF);
+
        ess_write (devc, 0xb8, 0x0e);   /* Auto init DMA mode */
-       ess_change (devc, 0xa8, 0x0b, 3 - devc->channels);      /* Mono/stereo */
+       ess_change (devc, 0xa8, 0x03, 3 - devc->channels);      /* Mono/stereo */
+       ess_write (devc, 0xb9, 2);      /* Demand mode (4 bytes/DMA request) */
 
+       ess_exec_commands (devc, ess_inp_cmds);
+
+       ess_change (devc, 0xb1, 0xf0, 0x50);
+       ess_change (devc, 0xb2, 0xf0, 0x50);
+
+       devc->trigger_bits = 0;
+       return 0;
+}
+
+static int ess_audio_prepare_for_output_audio1 (int dev, int bsize, int bcount)
+{
+       sb_devc *devc = audio_devs[dev]->devc;
+
+       sb_dsp_reset(devc);
        ess_speed(devc, 1);
+       ess_write (devc, 0xb8, 4);      /* Auto init DMA mode */
+       ess_change (devc, 0xa8, 0x03, 3 - devc->channels);      /* Mono/stereo */
+       ess_write (devc, 0xb9, 2);      /* Demand mode (4 bytes/request) */
+
+       ess_exec_commands (devc, ess_out_cmds);
+
+       ess_change (devc, 0xb1, 0xf0, 0x50);    /* Enable DMA */
+       ess_change (devc, 0xb2, 0xf0, 0x50);    /* Enable IRQ */
 
-    ess_write (devc, 0xb7, (devc->bits & ESSFMT_SIGNED) ? 0x71 : 0x51);
-    ess_write (devc, 0xb7, 0x90 | ((devc->bits & ESSFMT_SIGNED) ? 0x20 : 0) |
-               ((devc->bits & ESSFMT_16) ? 4 : 0) | ((devc->channels > 1) ? 8 : 0x40));
+       sb_dsp_command(devc, DSP_CMD_SPKON);    /* There be sound! */
+
+       devc->trigger_bits = 0;
+       return 0;
+}
+
+static int ess_audio_prepare_for_output_audio2 (int dev, int bsize, int bcount)
+{
+       sb_devc *devc = audio_devs[dev]->devc;
+       unsigned char bits;
+
+/* FKS: qqq
+       sb_dsp_reset(devc);
+*/
+
+       /*
+        * Auto-Initialize:
+        * DMA mode + demand mode (8 bytes/request, yes I want it all!)
+        * But leave 16-bit DMA bit untouched!
+        */
+       ess_chgmixer (devc, 0x78, 0xd0, 0xd0);
+
+       ess_speed(devc, 2);
+
+       /* bits 4:3 on ES1887 represent recording source. Keep them! */
+       bits = ess_getmixer (devc, 0x7a) & 0x18;
+
+       /* Set stereo/mono */
+       if (devc->channels != 1) bits |= 0x02;
+
+       /* Init DACs; UNSIGNED mode for 8 bit; SIGNED mode for 16 bit */
+       if (devc->bits != AFMT_U8) bits |= 0x05;        /* 16 bit */
+
+       /* Enable DMA, IRQ will be shared (hopefully)*/
+       bits |= 0x60;
+
+       ess_setmixer (devc, 0x7a, bits);
+
+       ess_mixer_reload (devc, SOUND_MIXER_PCM);       /* There be sound! */
 
        devc->trigger_bits = 0;
        return 0;
@@ -378,79 +514,144 @@ printk(KERN_INFO "ess_audio_prepare_for_output: dma_out=%d,dma_in=%d\n"
 #endif
 
        if (devc->duplex) {
-               ess_speed(devc, 2);
+               return ess_audio_prepare_for_output_audio2 (dev, bsize, bcount);
+       } else {
+               return ess_audio_prepare_for_output_audio1 (dev, bsize, bcount);
+       }
+}
+
+static void ess_audio_halt_xfer(int dev)
+{
+       unsigned long flags;
+       sb_devc *devc = audio_devs[dev]->devc;
 
-           ess_chgmixer (devc, 0x7a, 0x07, ((devc->bits & ESSFMT_SIGNED) ? 4 : 0) |
-                       ((devc->bits & ESSFMT_16) ? 1 : 0) | ((devc->channels > 1) ? 2 : 0));
+       save_flags(flags);
+       cli();
+       sb_dsp_reset(devc);
+       restore_flags(flags);
 
-               if (devc->caps & ESSCAP_NEW)
-                       ess_mixer_reload (devc, SOUND_MIXER_PCM);       /* There be sound! */
-               else
-                       sb_dsp_command(devc, DSP_CMD_SPKON);    /* There be sound! */
-       } else {
-               ess_write (devc, 0xb8, 4);      /* Auto init DMA mode */
-               ess_change (devc, 0xa8, 0x03, 3 - devc->channels);      /* Mono/stereo */
+       /*
+        * Audio 2 may still be operational! Creates awful sounds!
+        */
+       if (devc->duplex) ess_chgmixer(devc, 0x78, 0x03, 0x00);
+}
 
-               ess_speed(devc, 1);
+static void ess_audio_start_input
+       (int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+       int count = nr_bytes;
+       sb_devc *devc = audio_devs[dev]->devc;
+       short c = -nr_bytes;
 
-           ess_write (devc, 0xb6, (devc->bits & ESSFMT_SIGNED) ? 0 : 0x80);
-           ess_write (devc, 0xb7, (devc->bits & ESSFMT_SIGNED) ? 0x71 : 0x51);
-           ess_write (devc, 0xb7, 0x90 | ((devc->bits & ESSFMT_SIGNED) ? 0x20 : 0) |
-                       ((devc->bits & ESSFMT_16) ? 4 : 0) | ((devc->channels > 1) ? 8 : 0x40));
+       /*
+        * Start a DMA input to the buffer pointed by dmaqtail
+        */
 
-               sb_dsp_command(devc, DSP_CMD_SPKON);    /* There be sound! */
-       }
-       devc->trigger_bits = 0;
-       return 0;
+       if (audio_devs[dev]->dmap_in->dma > 3) count >>= 1;
+       count--;
+
+       devc->irq_mode = IMODE_INPUT;
+
+       ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
+       ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+
+       ess_change (devc, 0xb8, 0x0f, 0x0f);    /* Go */
+       devc->intr_active = 1;
 }
 
-static void ess_audio_halt_xfer(int dev)
+static void ess_audio_output_block_audio1
+       (int dev, unsigned long buf, int nr_bytes, int intrflag)
 {
+       int count = nr_bytes;
        sb_devc *devc = audio_devs[dev]->devc;
+       short c = -nr_bytes;
 
-       sb_dsp_command (devc, DSP_CMD_SPKOFF);
+       if (audio_devs[dev]->dmap_out->dma > 3)
+               count >>= 1;
+       count--;
 
-       if (devc->caps & ESSCAP_NEW) {
-               ess_setmixer (devc, 0x7c, 0);
-       }
+       devc->irq_mode = IMODE_OUTPUT;
+
+       ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
+       ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+
+       ess_change (devc, 0xb8, 0x05, 0x05);    /* Go */
+       devc->intr_active = 1;
+}
 
-       ess_change (devc, 0xb8, 0x0f, 0x00);    /* Stop */
+static void ess_audio_output_block_audio2
+       (int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+       int count = nr_bytes;
+       sb_devc *devc = audio_devs[dev]->devc;
+       short c = -nr_bytes;
 
-       if (devc->duplex) {                     /* Audio 2 may still be operational! */
-               ess_chgmixer (devc, 0x78, 0x03, 0x00);
+       if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1;
+       count--;
+
+       ess_setmixer (devc, 0x74, (unsigned char) ((unsigned short) c & 0xff));
+       ess_setmixer (devc, 0x76, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+       ess_chgmixer (devc, 0x78, 0x03, 0x03);   /* Go */
+
+       devc->irq_mode_16 = IMODE_OUTPUT;
+               devc->intr_active_16 = 1;
+}
+
+static void ess_audio_output_block
+       (int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+       sb_devc *devc = audio_devs[dev]->devc;
+
+       if (devc->duplex) {
+               ess_audio_output_block_audio2 (dev, buf, nr_bytes, intrflag);
+       } else {
+               ess_audio_output_block_audio1 (dev, buf, nr_bytes, intrflag);
        }
 }
 
+/*
+ * FKS: the if-statements for both bits and bits_16 are quite alike.
+ * Combine this...
+ */
 static void ess_audio_trigger(int dev, int bits)
 {
        sb_devc *devc = audio_devs[dev]->devc;
 
-       int bits_16 = bits & devc->irq_mode_16 & IMODE_OUTPUT;
+       int bits_16 = bits & devc->irq_mode_16;
        bits &= devc->irq_mode;
 
        if (!bits && !bits_16) {
-               sb_dsp_command (devc, 0xd0);                    /* Halt DMA */
-               ess_chgmixer (devc, 0x78, 0x04, 0x00);  /* Halt DMA 2 */
+               /* FKS oh oh.... wrong?? for dma 16? */
+               sb_dsp_command(devc, 0xd0);     /* Halt DMA */
        }
 
        if (bits) {
-               short c = -devc->trg_bytes;
-
-               ess_write (devc, 0xa4, (unsigned char)((unsigned short) c & 0xff));
-               ess_write (devc, 0xa5, (unsigned char)((unsigned short) c >> 8));
-               ess_change (devc, 0xb8, 0x0f, (devc->irq_mode==IMODE_INPUT)?0x0f:0x05);
+               switch (devc->irq_mode)
+               {
+                       case IMODE_INPUT:
+                               ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
+                                       devc->trg_intrflag);
+                               break;
 
-               devc->intr_active = 1;
+                       case IMODE_OUTPUT:
+                               ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
+                                       devc->trg_intrflag);
+                               break;
+               }
        }
 
        if (bits_16) {
-               short c = -devc->trg_bytes_16;
-
-               ess_setmixer (devc, 0x74, (unsigned char)((unsigned short) c & 0xff));
-               ess_setmixer (devc, 0x76, (unsigned char)((unsigned short) c >> 8));
-               ess_chgmixer (devc, 0x78, 0x03, 0x03);   /* Go */
+               switch (devc->irq_mode_16) {
+               case IMODE_INPUT:
+                       ess_audio_start_input(dev, devc->trg_buf_16, devc->trg_bytes_16,
+                                       devc->trg_intrflag_16);
+                       break;
 
-               devc->intr_active_16 = 1;
+               case IMODE_OUTPUT:
+                       ess_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16,
+                                       devc->trg_intrflag_16);
+                       break;
+               }
        }
 
        devc->trigger_bits = bits | bits_16;
@@ -462,8 +663,8 @@ static int ess_audio_set_speed(int dev, int speed)
        int minspeed, maxspeed, dummydiv;
 
        if (speed > 0) {
-               minspeed = (devc->caps & ESSCAP_NEW) ? 6047  : 3125;
-               maxspeed = 48000;
+               minspeed = (devc->duplex ? 6215  : 5000 );
+               maxspeed = (devc->duplex ? 44100 : 48000);
                if (speed < minspeed) speed = minspeed;
                if (speed > maxspeed) speed = maxspeed;
 
@@ -474,46 +675,38 @@ static int ess_audio_set_speed(int dev, int speed)
        return devc->speed;
 }
 
+/*
+ * FKS: This is a one-on-one copy of sb1_audio_set_bits
+ */
 static unsigned int ess_audio_set_bits(int dev, unsigned int bits)
 {
        sb_devc *devc = audio_devs[dev]->devc;
 
-       switch (bits) {
-               case 0:
-                       break;
-               case AFMT_S16_LE:
-                       devc->bits = ESSFMT_16 | ESSFMT_SIGNED;
-                       break;
-               case AFMT_U16_LE:
-                       devc->bits = ESSFMT_16;
-                       break;
-               case AFMT_S8:
-                       devc->bits = ESSFMT_SIGNED;
-                       break;
-               default:
-                       devc->bits = 0;
-                       break;
+       if (bits != 0) {
+               if (bits == AFMT_U8 || bits == AFMT_S16_LE) {
+                       devc->bits = bits;
+               } else {
+                       devc->bits = AFMT_U8;
+               }
        }
 
        return devc->bits;
 }
 
+/*
+ * FKS: This is a one-on-one copy of sbpro_audio_set_channels
+ * (*) Modified it!!
+ */
 static short ess_audio_set_channels(int dev, short channels)
 {
        sb_devc *devc = audio_devs[dev]->devc;
 
-       if (devc->fullduplex && !(devc->caps & ESSCAP_NEW)) {
-               devc->channels = 1;
-       } else {
-               if (channels == 1 || channels == 2) {
-                       devc->channels = channels;
-               }
-       }
+       if (channels == 1 || channels == 2) devc->channels = channels;
 
        return devc->channels;
 }
 
-static struct audio_driver ess_audio_driver =   /* ESS ES688/1688/18xx */
+static struct audio_driver ess_audio_driver =   /* ESS ES688/1688 */
 {
        sb_audio_open,
        sb_audio_close,
@@ -540,7 +733,7 @@ struct audio_driver *ess_audio_init
                (sb_devc *devc, int *audio_flags, int *format_mask)
 {
        *audio_flags = DMA_AUTOMODE;
-       *format_mask |= AFMT_S16_LE | AFMT_U16_LE | AFMT_S8;
+       *format_mask |= AFMT_S16_LE;
 
        if (devc->duplex) {
                int tmp_dma;
@@ -563,8 +756,10 @@ struct audio_driver *ess_audio_init
  *                                                             ESS common                                                                      *
  *                                                                                                                                                     *
  ****************************************************************************/
-static void ess_handle_channel (int dev, int irq_mode)
+static void ess_handle_channel
+       (char *channel, int dev, int intr_active, unsigned char flag, int irq_mode)
 {
+       if (!intr_active || !flag) return;
 #ifdef FKS_REG_LOGGING
 printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode);
 #endif
@@ -586,77 +781,48 @@ printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode);
 }
 
 /*
- * In the ESS 1888 model, how do we found out if the MPU interrupted ???
+ * FKS: TODO!!! Finish this!
+ *
+ * I think midi stuff uses uart401, without interrupts.
+ * So IMODE_MIDI isn't a value for devc->irq_mode.
  */
 void ess_intr (sb_devc *devc)
 {
        int                             status;
        unsigned char   src;
 
-       if (devc->caps & ESSCAP_PNP) {
-               outb (devc->pcibase + 7, 0);            /* Mask IRQs */
-               src = inb (devc->pcibase + 6) & 0x0f;
-       } else if (devc->caps & ESSCAP_IRQ) {
+       if (devc->submodel == SUBMDL_ES1887) {
                src = ess_getmixer (devc, 0x7f) >> 4;
        } else {
-               src = inb (DSP_STATUS) & 0x01;
-               if (devc->duplex && (ess_getmixer (devc, 0x7a) & 0x80)) {
-                       src |= 0x02;
-               }
-               if ((devc->caps & ESSCAP_ES18) && (ess_getmixer (devc, 0x64) & 0x10)) {
-                       src |= 0x04;
-               }
-#if defined(CONFIG_MIDI) && defined(CONFIG_SOUND_MPU401)
-               /*
-                * This should work if dev_conf wasn't local to mpu401.c
-                */
-#if 0
-               if ((int)devc->midi_irq_cookie >= 0 &&
-                       !(inb(dev_conf[(int)devc->midi_irq_cookie].base + 1) & 0x80)) {
-                       src |= 0x08;
-               }
-#endif
-#endif
+               src = 0xff;
        }
 
 #ifdef FKS_REG_LOGGING
 printk(KERN_INFO "FKS: sbintr src=%x\n",(int)src);
 #endif
-       if (src & 0x01) {
-               status = inb(DSP_DATA_AVAIL);   /* Acknowledge interrupt */
-               if (devc->intr_active)
-                       ess_handle_channel (devc->dev, devc->irq_mode   );
-       }
-
-       if (src & 0x02) {
-               ess_chgmixer (devc, 0x7a, 0x80, 0x00);  /* Acknowledge interrupt */
-               if (devc->intr_active_16)
-                       ess_handle_channel (devc->dev, devc->irq_mode_16);
+       ess_handle_channel
+               ( "Audio 1"
+               , devc->dev, devc->intr_active   , src & 0x01, devc->irq_mode   );
+       ess_handle_channel
+               ( "Audio 2"
+               , devc->dev, devc->intr_active_16, src & 0x02, devc->irq_mode_16);
+       /*
+        * Acknowledge interrupts
+        */
+       if (devc->submodel == SUBMDL_ES1887 && (src & 0x02)) {
+               ess_chgmixer (devc, 0x7a, 0x80, 0x00);
        }
 
-       if (src & 0x04) {
-               int left, right;
-
-               ess_setmixer (devc, 0x66, 0x00);        /* Hardware volume IRQ ack */
-
-               left = ess_getmixer (devc, 0x60);
-               right = ess_getmixer (devc, 0x62);
-
-               left = (left & 0x40) ? 0 : ((left * 100 + 31)/ 63);     /* Mute or scale */
-               right = (right & 0x40) ? 0 : ((right * 100 + 31)/ 63);
-
-               devc->levels[SOUND_MIXER_VOLUME] = left | (right << 8);
+       if (src & 0x01) {
+               status = inb(DSP_DATA_AVAIL);
        }
+}
 
-#if defined(CONFIG_MIDI) && defined(CONFIG_SOUND_MPU401)
-       if ((int)devc->midi_irq_cookie >= 0 && (src & 0x08)) {
-               mpuintr (devc->irq, devc->midi_irq_cookie, NULL);
-       }
-#endif
+static void ess_extended (sb_devc * devc)
+{
+       /* Enable extended mode */
 
-       if (devc->caps & ESSCAP_PNP) {
-               outb (devc->pcibase + 7, 0xff);         /* Unmask IRQs */
-       }
+       sb_dsp_command(devc, 0xc6);
 }
 
 static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data)
@@ -686,7 +852,7 @@ static int ess_read (sb_devc * devc, unsigned char reg)
 
 int ess_dsp_reset(sb_devc * devc)
 {
-       int loopc, val;
+       int loopc;
 
 #ifdef FKS_REG_LOGGING
 printk(KERN_INFO "FKS: ess_dsp_reset 1\n");
@@ -707,102 +873,79 @@ ess_show_mixerregs (devc);
                DDB(printk("sb: No response to RESET\n"));
                return 0;   /* Sorry */
        }
+       ess_extended (devc);
 
-       sb_dsp_command(devc, 0xc6);                     /* Enable extended mode */
-       if (!(devc->caps & ESSCAP_PNP)) {
-               ess_setmixer (devc, 0x40, 0x03);        /* Enable joystick and OPL3 */
+       DEB(printk("sb_dsp_reset() OK\n"));
 
-               switch (devc->irq) {
-                       case 2:
-                       case 9:
-                               val = 1;
-                               break;
-                       case 5:
-                               val = 2;
-                               break;
-                       case 7:
-                               val = 3;
-                               break;
-                       case 10:
-                               val = 4;
-                               break;
-                       case 11:
-                               val = 5;
-                               break;
-                       default:
-                               val = 0;
-               }                                               /* IRQ config */
-               ess_write (devc, 0xb1, 0xf0 | ((val && val != 5) ? val - 1 : 0));
+#ifdef FKS_LOGGING
+printk(KERN_INFO "FKS: dsp_reset 2\n");
+ess_show_mixerregs (devc);
+#endif
 
-               if (devc->caps & ESSCAP_IRQ) {
-                       ess_setmixer (devc, 0x7f, 0x01 | (val << 1)); /* IRQ config */
-               }
+       return 1;
+}
 
-               switch ((devc->duplex) ? devc->dma16 : devc->dma8) {
-                       case 0:
-                               val = 0x54;
-                               break;
-                       case 1:
-                               val = 0x58;
-                               break;
-                       case 3:
-                               val = 0x5c;
-                               break;
-                       default:
-                               val = 0;
-               }
-               ess_write (devc, 0xb2, val); /* DMA1 config */
+static int ess_irq_bits (int irq)
+{
+       switch (irq) {
+       case 2:
+       case 9:
+               return 0;
 
-               if (devc->duplex) {
-                       switch (devc->dma8) {
-                               case 0:
-                                       val = 0x04;
-                                       break;
-                               case 1:
-                                       val = 0x05;
-                                       break;
-                               case 3:
-                                       val = 0x06;
-                                       break;
-                               case 5:
-                                       val = 0x07;
-                                       break;
-                               default:
-                                       val = 0;
-                       }
-                       ess_write (devc, 0x7d, val); /* DMA2 config */
-               }
-       }
-       ess_change (devc, 0xb1, 0xf0, 0x50);    /* Enable IRQ 1 */
-       ess_change (devc, 0xb2, 0xf0, 0x50);    /* Enable DMA 1 */
-       ess_write (devc, 0xb9, 2);                      /* Demand mode (4 bytes/DMA request) */
-       ess_setmixer (devc, 0x7a, 0x40);        /* Enable IRQ 2 */
-                       /* Auto-Initialize DMA mode + demand mode (8 bytes/request) */
-       if (devc->caps & ESSCAP_PNP) {
-               ess_setmixer (devc, 0x78, 0xd0);
-               ess_setmixer (devc, 0x64, 0x82);                /* Enable HW volume interrupt */
-       } else {
-               ess_setmixer (devc, 0x78, (devc->dma8 > 4) ? 0xf0 : 0xd0);
-               ess_setmixer (devc, 0x64, 0x42);                /* Enable HW volume interrupt */
-       }
+       case 5:
+               return 1;
 
-    if (devc->caps & ESSCAP_NEW) {
-               ess_setmixer (devc, 0x71, 0x32); /* Change behaviour of register A1 */
-               ess_setmixer (devc, 0x1c, 0x05); /* Recording source is mixer */
-       } else {
-               ess_change (devc, 0xb7, 0x80, 0x80); /* Enable DMA FIFO */
+       case 7:
+               return 2;
+
+       case 10:
+               return 3;
+
+       default:
+               printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", irq);
+               return -1;
        }
+}
 
-       DEB(printk("sb_dsp_reset() OK\n"));
+/*
+ *     Set IRQ configuration register for all ESS models
+ */
+static int ess_common_set_irq_hw (sb_devc * devc)
+{
+       int irq_bits;
 
-#ifdef FKS_LOGGING
-printk(KERN_INFO "FKS: dsp_reset 2\n");
-ess_show_mixerregs (devc);
-#endif
+       if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return 0;
 
+       if (!ess_write (devc, 0xb1, 0x50 | (irq_bits << 2))) {
+               printk(KERN_ERR "ES1688: Failed to write to IRQ config register\n");
+               return 0;
+       }
        return 1;
 }
 
+/*
+ * I wanna use modern ES1887 mixer irq handling. Funny is the
+ * fact that my BIOS wants the same. But suppose someone's BIOS
+ * doesn't do this!
+ * This is independent of duplex. If there's a 1887 this will
+ * prevent it from going into 1888 mode.
+ */
+static void ess_es1887_set_irq_hw (sb_devc * devc)
+{
+       int irq_bits;
+
+       if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return;
+
+       ess_chgmixer (devc, 0x7f, 0x0f, 0x01 | ((irq_bits + 1) << 1));
+}
+
+static int ess_set_irq_hw (sb_devc * devc)
+{
+       if (devc->submodel == SUBMDL_ES1887) ess_es1887_set_irq_hw (devc);
+
+       return ess_common_set_irq_hw (devc);
+}
+
 #ifdef FKS_TEST
 
 /*
@@ -826,7 +969,7 @@ printk (KERN_INFO "FKS: FKS_test %02x, %02x\n", (val1 & 0x0ff), (val2 & 0x0ff));
 };
 #endif
 
-static unsigned int ess_identify (sb_devc * devc, int *control)
+static unsigned int ess_identify (sb_devc * devc)
 {
        unsigned int val;
        unsigned long flags;
@@ -840,15 +983,8 @@ static unsigned int ess_identify (sb_devc * devc, int *control)
        udelay(20);
        val |= inb(MIXER_DATA);
        udelay(20);
-       *control  = inb(MIXER_DATA) << 8;
-       udelay(20);
-       *control |= inb(MIXER_DATA);
-       udelay(20);
        restore_flags(flags);
 
-       if (*control < 0 || *control > 0x3ff || check_region (*control, 8))
-               *control = 0;
-
        return val;
 }
 
@@ -875,6 +1011,7 @@ static int ess_probe (sb_devc * devc, int reg, int xorval)
 
 int ess_init(sb_devc * devc, struct address_info *hw_config)
 {
+       unsigned char cfg;
        int ess_major = 0, ess_minor = 0;
        int i;
        static char name[100], modelname[10];
@@ -882,7 +1019,6 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
        /*
         * Try to detect ESS chips.
         */
-       devc->pcibase = 0;
 
        sb_dsp_command(devc, 0xe7); /* Return identification */
 
@@ -934,10 +1070,10 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
                case ESSTYPE_LIKE20:
                        break;
                case 688:
-                       submodel = SUBMDL_ES688;
+                       submodel = 0x00;
                        break;
                case 1688:
-                       submodel = SUBMDL_ES1688;
+                       submodel = 0x08;
                        break;
                case 1868:
                        submodel = SUBMDL_ES1868;
@@ -986,7 +1122,7 @@ FKS_test (devc);
                if (chip == NULL) {
                        int type;
 
-                       type = ess_identify (devc, &devc->pcibase);
+                       type = ess_identify (devc);
 
                        switch (type) {
                        case 0x1868:
@@ -1063,72 +1199,139 @@ FKS_test (devc);
                strcpy(name, "Jazz16");
        }
 
-       switch (devc->submodel) {
-       case SUBMDL_ES1869:
-       case SUBMDL_ES1879:
-               devc->caps |= ESSCAP_NEW;
-       case SUBMDL_ES1868:
-       case SUBMDL_ES1878:
-               devc->caps |= ESSCAP_PNP | ESSCAP_ES18;
-               break;
-       case SUBMDL_ES1887:
-               devc->caps |= ESSCAP_IRQ;
-       case SUBMDL_ES1888:
-               devc->caps |= ESSCAP_NEW | ESSCAP_ES18;
+       /* AAS: info stolen from ALSA: these boards have different clocks */
+       switch(devc->submodel) {
+               case SUBMDL_ES1869:
+               case SUBMDL_ES1887:
+               case SUBMDL_ES1888:
+                       devc->caps |= SB_CAP_ES18XX_RATE;
+                       break;
        }
-    if (devc->caps & ESSCAP_PNP) {
-               if (!devc->pcibase) {
-                       printk (KERN_ERR "ESS PnP chip without PnP registers. Ignored\n");
-                       return 0;
-               }
-               request_region (devc->pcibase, 8, "ESS18xx ctrl");
-
-               outb (0x07, devc->pcibase);             /* Selects logical device #1 */
-               outb (0x01, devc->pcibase + 1);
-               outb (0x28, devc->pcibase);
-               i = inb (devc->pcibase + 1) & 0x0f;
-               outb (0x28, devc->pcibase);             /* Sets HW volume IRQ */
-               outb (devc->irq << 4 | i, devc->pcibase + 1);
-               outb (0x70, devc->pcibase);             /* Sets IRQ 1 */
-               outb (devc->irq, devc->pcibase + 1);
-               outb (0x72, devc->pcibase);             /* Sets IRQ 2 */
-               outb (devc->irq, devc->pcibase + 1);
-               outb (0x74, devc->pcibase);             /* Sets DMA 1 */
-               outb (hw_config->dma, devc->pcibase + 1);
-               outb (0x75, devc->pcibase);             /* Sets DMA 2 */
-               outb (hw_config->dma2 >= 0 ? hw_config->dma2 : 4, devc->pcibase + 1);
-       } else if (devc->pcibase) {
-               printk (KERN_INFO "Non-PnP ESS card with PnP registers at %04Xh, ignoring them.\n", devc->pcibase);
-               devc->pcibase = 0;
+
+       hw_config->name = name;
+       /* FKS: sb_dsp_reset to enable extended mode???? */
+       sb_dsp_reset(devc); /* Turn on extended mode */
+
+       /*
+        *  Enable joystick and OPL3
+        */
+       cfg = ess_getmixer (devc, 0x40);
+       ess_setmixer (devc, 0x40, cfg | 0x03);
+       if (devc->submodel >= 8) {              /* ES1688 */
+               devc->caps |= SB_NO_MIDI;   /* ES1688 uses MPU401 MIDI mode */
        }
+       sb_dsp_reset (devc);
 
-       devc->caps |= SB_NO_MIDI;   /* ES1688 uses MPU401 MIDI mode */
+       /*
+        * This is important! If it's not done, the IRQ probe in sb_dsp_init
+        * may fail.
+        */
+       return ess_set_irq_hw (devc);
+}
 
-       hw_config->name = name;
+static int ess_set_dma_hw(sb_devc * devc)
+{
+       unsigned char cfg, dma_bits = 0, dma16_bits;
+       int dma;
 
-       sb_dsp_reset(devc); /* Turn on extended mode */
+#ifdef FKS_LOGGING
+printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n"
+, devc->dma8, devc->dma16, devc->duplex);
+#endif
+
+       /*
+        * FKS: It seems as if this duplex flag isn't set yet. Check it.
+        */
+       dma = devc->dma8;
+
+       if (dma > 3 || dma < 0 || dma == 2) {
+               dma_bits = 0;
+               printk(KERN_ERR "ESS1688: Invalid DMA8 %d\n", dma);
+               return 0;
+       } else {
+               /* Extended mode DMA enable */
+               cfg = 0x50;
+
+               if (dma == 3) {
+                       dma_bits = 3;
+               } else {
+                       dma_bits = dma + 1;
+               }
+       }
+
+       if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) {
+               printk(KERN_ERR "ESS1688: Failed to write to DMA config register\n");
+               return 0;
+       }
 
-       ess_setmixer (devc, 0x00, 0x00);        /* Reset mixer registers */
+       if (devc->duplex) {
+               dma = devc->dma16;
+               dma16_bits = 0;
 
+               if (dma >= 0) {
+                       switch (dma) {
+                       case 0:
+                               dma_bits = 0x04;
+                               break;
+                       case 1:
+                               dma_bits = 0x05;
+                               break;
+                       case 3:
+                               dma_bits = 0x06;
+                               break;
+                       case 5:
+                               dma_bits   = 0x07;
+                               dma16_bits = 0x20;
+                               break;
+                       default:
+                               printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma);
+                               return 0;
+                       };
+                       ess_chgmixer (devc, 0x78, 0x20, dma16_bits);
+                       ess_chgmixer (devc, 0x7d, 0x07, dma_bits);
+               }
+       }
        return 1;
 }
 
 /*
  * This one is called from sb_dsp_init.
+ *
+ * Return values:
+ *  0: Failed
+ *  1: Succeeded or doesn't apply (not SUBMDL_ES1887)
  */
 int ess_dsp_init (sb_devc *devc, struct address_info *hw_config)
 {
        /*
+        * This for ES1887 to run Full Duplex. Actually ES1888
+        * is allowed to do so too. I have no idea yet if this
+        * will work for ES1888 however.
+        *
         * For SB16 having both dma8 and dma16 means enable
-        * Full Duplex. Let's try this too
+        * Full Duplex. Let's try this for ES1887 too
+        *
         */
-       if ((devc->caps & ESSCAP_ES18) && hw_config->dma2 >= 0) {
-               devc->dma16 = hw_config->dma2;
-               if (devc->dma8 != devc->dma16) {
+       if (devc->submodel == SUBMDL_ES1887) {
+               if (hw_config->dma2 != -1) {
+                       devc->dma16 = hw_config->dma2;
+               }
+               /*
+                * devc->duplex initialization is put here, cause
+                * ess_set_dma_hw needs it.
+                */
+               if (devc->dma8 != devc->dma16 && devc->dma16 != -1) {
                        devc->duplex = 1;
                }
+
+               if (!ess_set_dma_hw (devc)) {
+                       free_irq(devc->irq, devc);
+                       return 0;
+               }
+               return 1;
+       } else {
+               return -1;
        }
-       return 1;
 }
 
 /****************************************************************************
@@ -1149,13 +1352,13 @@ int ess_dsp_init (sb_devc *devc, struct address_info *hw_config)
 #define ES1688_MIXER_DEVICES           \
                        ( ES688_MIXER_DEVICES | SOUND_MASK_RECLEV       )
 
-#define ES_NEW_RECORDING_DEVICES       \
+#define ES1887_RECORDING_DEVICES       \
                        ( ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 | SOUND_MASK_SYNTH)
-#define ES_NEW_MIXER_DEVICES           \
+#define ES1887_MIXER_DEVICES           \
                        ( ES1688_MIXER_DEVICES                                                                                  )
 
 /*
- * Mixer registers of ES18xx with new capabilities
+ * Mixer registers of ES1887
  *
  * These registers specifically take care of recording levels. To make the
  * mapping from playback devices to recording devices every recording
@@ -1285,11 +1488,11 @@ MIX_ENT(ES_REC_MIXER_RECLINE3,          0x00, 0, 0, 0x00, 0, 0)
 };
 
 /*
- * This one is for new ES's. It's little different from es_rec_mix: it
- * has 0x7c for PCM playback level. This is because uses
+ * This one is for ES1887. It's little different from es_rec_mix: it
+ * has 0x7c for PCM playback level. This is because ES1887 uses
  * Audio 2 for playback.
  */
-static mixer_tab es_new_mix = {
+static mixer_tab es1887_mix = {
 MIX_ENT(SOUND_MIXER_VOLUME,                    0x60, 5, 6, 0x62, 5, 6),
 MIX_ENT(SOUND_MIXER_BASS,                      0x00, 0, 0, 0x00, 0, 0),
 MIX_ENT(SOUND_MIXER_TREBLE,                    0x00, 0, 0, 0x00, 0, 0),
@@ -1323,6 +1526,16 @@ MIX_ENT(ES_REC_MIXER_RECLINE2,           0x6c, 7, 4, 0x6c, 3, 4),
 MIX_ENT(ES_REC_MIXER_RECLINE3,         0x00, 0, 0, 0x00, 0, 0)
 };
 
+static int ess_has_rec_mixer (int submodel)
+{
+       switch (submodel) {
+       case SUBMDL_ES1887:
+               return 1;
+       default:
+               return 0;
+       };
+};
+
 #ifdef FKS_LOGGING
 static int ess_mixer_mon_regs[]
        = { 0x70, 0x71, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7f
@@ -1353,13 +1566,15 @@ printk(KERN_INFO "FKS: write mixer %x: %x\n", port, value);
 
        save_flags(flags);
        cli();
+       if (port >= 0xa0) {
+               ess_write (devc, port, value);
+       } else {
+               outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
 
-       outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
-
-       udelay(20);
-       outb(((unsigned char) (value & 0xff)), MIXER_DATA);
-       udelay(20);
-
+               udelay(20);
+               outb(((unsigned char) (value & 0xff)), MIXER_DATA);
+               udelay(20);
+       };
        restore_flags(flags);
 }
 
@@ -1371,12 +1586,15 @@ unsigned int ess_getmixer (sb_devc * devc, unsigned int port)
        save_flags(flags);
        cli();
 
-       outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
-
-       udelay(20);
-       val = inb(MIXER_DATA);
-       udelay(20);
+       if (port >= 0xa0) {
+               val = ess_read (devc, port);
+       } else {
+               outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
 
+               udelay(20);
+               val = inb(MIXER_DATA);
+               udelay(20);
+       }
        restore_flags(flags);
 
        return val;
@@ -1400,21 +1618,23 @@ void ess_mixer_init (sb_devc * devc)
        devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
 
        /*
-       * Take care of new ES's specifics...
+       * Take care of ES1887 specifics...
        */
-       if (devc->caps & ESSCAP_NEW) {
-               devc->supported_devices         = ES_NEW_MIXER_DEVICES;
-               devc->supported_rec_devices     = ES_NEW_RECORDING_DEVICES;
+       switch (devc->submodel) {
+       case SUBMDL_ES1887:
+               devc->supported_devices         = ES1887_MIXER_DEVICES;
+               devc->supported_rec_devices     = ES1887_RECORDING_DEVICES;
 #ifdef FKS_LOGGING
 printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);
 #endif
                if (devc->duplex) {
-                       devc->iomap                             = &es_new_mix;
+                       devc->iomap                             = &es1887_mix;
                } else {
                        devc->iomap                             = &es_rec_mix;
                }
-       } else {
-               if (devc->submodel == SUBMDL_ES688) {
+               break;
+       default:
+               if (devc->submodel < 8) {
                        devc->supported_devices         = ES688_MIXER_DEVICES;
                        devc->supported_rec_devices     = ES688_RECORDING_DEVICES;
                        devc->iomap                                     = &es688_mix;
@@ -1425,10 +1645,10 @@ printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);
                         */
                        devc->supported_devices         = ES1688_MIXER_DEVICES;
                        devc->supported_rec_devices     = ES1688_RECORDING_DEVICES;
-                       if (devc->caps & ESSCAP_ES18) {
-                               devc->iomap                             = &es1688later_mix;
-                       } else {
+                       if (devc->submodel < 0x10) {
                                devc->iomap                             = &es1688_mix;
+                       } else {
+                               devc->iomap                             = &es1688later_mix;
                        }
                }
        }
@@ -1440,15 +1660,9 @@ printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);
  */
 int ess_mixer_set(sb_devc *devc, int dev, int left, int right)
 {
-       if ((devc->caps & ESSCAP_NEW) && (devc->recmask & (1 << dev))) {
+       if (ess_has_rec_mixer (devc->submodel) && (devc->recmask & (1 << dev))) {
                sb_common_mixer_set (devc, dev + ES_REC_MIXER_RECDIFF, left, right);
        }
-       /* Set & unmute master volume */
-       if ((devc->caps & ESSCAP_ES18) && (dev == SOUND_MIXER_VOLUME)) {
-               ess_chgmixer (devc, 0x60, 0x7f, 0x3f & ((left * 0x3f + 50) / 100));
-               ess_chgmixer (devc, 0x62, 0x7f, 0x3f & ((right * 0x3f + 50) / 100));
-               return left | (right << 8);
-       }
        return sb_common_mixer_set (devc, dev, left, right);
 }
 
@@ -1493,6 +1707,7 @@ printk (KERN_INFO "FKS: es_rec_set_recmask mask = %x\n", mask);
                                left  = value & 0x000000ff;
                                right = (value & 0x0000ff00) >> 8;
                        } else {                                /* Turn it off (3)  */
+                               left  = 0;
                                left  = 0;
                                right = 0;
                        }
@@ -1506,7 +1721,7 @@ int ess_set_recmask(sb_devc * devc, int *mask)
 {
        /* This applies to ESS chips with record mixers only! */
 
-       if (devc->caps & ESSCAP_NEW) {
+       if (ess_has_rec_mixer (devc->submodel)) {
                *mask   = es_rec_set_recmask (devc, *mask);
                return 1;                                                                       /* Applied              */
        } else {
@@ -1522,7 +1737,18 @@ int ess_mixer_reset (sb_devc * devc)
        /*
         * Separate actions for ESS chips with a record mixer:
         */
-       if (devc->caps & ESSCAP_NEW) {
+       if (ess_has_rec_mixer (devc->submodel)) {
+               switch (devc->submodel) {
+               case SUBMDL_ES1887:
+                       /*
+                        * Separate actions for ES1887:
+                        * Change registers 7a and 1c to make the record mixer the
+                        * actual recording source.
+                        */
+                       ess_chgmixer(devc, 0x7a, 0x18, 0x08);
+                       ess_chgmixer(devc, 0x1c, 0x07, 0x07);
+                       break;
+               };
                /*
                 * Call set_recmask for proper initialization
                 */
@@ -1542,80 +1768,50 @@ int ess_mixer_reset (sb_devc * devc)
  *                                                                                                                                                     *
  ****************************************************************************/
 
+/*
+ * FKS: IRQ may be shared. Hm. And if so? Then What?
+ */
 int ess_midi_init(sb_devc * devc, struct address_info *hw_config)
 {
-       int val;
+       unsigned char   cfg, tmp;
 
-       if (devc->submodel == SUBMDL_ES688) {
-               return 0;                               /* ES688 doesn't support MPU401 mode */
+       cfg = ess_getmixer (devc, 0x40) & 0x03;
+
+       if (devc->submodel < 8) {
+               ess_setmixer (devc, 0x40, cfg | 0x03);  /* Enable OPL3 & joystick */
+               return 0;                                        /* ES688 doesn't support MPU401 mode */
        }
+       tmp = (hw_config->io_base & 0x0f0) >> 4;
 
-       if (hw_config->irq < 2) {
-               hw_config->irq = devc->irq;
+       if (tmp > 3) {
+               ess_setmixer (devc, 0x40, cfg);
+               return 0;
        }
+       cfg |= tmp << 3;
 
-       if (devc->caps & ESSCAP_PNP) {
-               outb (0x07, devc->pcibase);             /* Selects logical device #1 */
-               outb (0x01, devc->pcibase + 1);
-               outb (0x28, devc->pcibase);
-               val = inb (devc->pcibase + 1) & 0xf0;
-               outb (0x28, devc->pcibase);             /* Sets MPU IRQ */
-               outb (hw_config->irq | val, devc->pcibase + 1);
-               if (hw_config->io_base) {
-                       outb (0x64, devc->pcibase);             /* Sets MPU I/O address */
-                       outb ((hw_config->io_base & 0xf00) >> 8, devc->pcibase + 1);
-                       outb (0x65, devc->pcibase);             /* Sets MPU I/O address */
-                       outb (hw_config->io_base & 0xfc, devc->pcibase + 1);
-               } else {
-                       outb (0x64, devc->pcibase);             /* Read MPU I/O address */
-                       hw_config->io_base = (inb (devc->pcibase + 1) & 0x0f) << 8;
-                       outb (0x65, devc->pcibase);             /* Read MPU I/O address */
-                       hw_config->io_base |= inb (devc->pcibase + 1) & 0xfc;
-               }
+       tmp = 1;                /* MPU enabled without interrupts */
 
-               ess_setmixer (devc, 0x64, 0xc2);        /* Enable MPU interrupt */
-       } else {
-               if (devc->irq == hw_config->irq && (devc->caps & ESSCAP_IRQ)) {
-                       val = 0x43;
-               }
-               else switch (hw_config->irq) {
-                       case 11:
-                               if (!(devc->caps & ESSCAP_IRQ)) {
-                                       return 0;
-                               }
-                               val = 0x63;
-                               break;
-                       case 2:
-                       case 9:
-                               val = 0x83;
-                               break;
-                       case 5:
-                               val = 0xa3;
-                               break;
-                       case 7:
-                               val = 0xc3;
-                               break;
-                       case 10:
-                               val = 0xe3;
-                               break;
-                       default:
-                               return 0;
-               }
-               switch (hw_config->io_base) {
-                       case 0x300:
-                       case 0x310:
-                       case 0x320:
-                       case 0x330:
-                               ess_setmixer (devc, 0x40, val
-                                                               | ((hw_config->io_base & 0x0f0) >> 1));
-                               break;
-                       default:
-                               return 0;
-               }
+       /* May be shared: if so the value is -ve */
+
+       switch (abs(hw_config->irq)) {
+               case 9:
+                       tmp = 0x4;
+                       break;
+               case 5:
+                       tmp = 0x5;
+                       break;
+               case 7:
+                       tmp = 0x6;
+                       break;
+               case 10:
+                       tmp = 0x7;
+                       break;
+               default:
+                       return 0;
        }
 
-       if (devc->irq == hw_config->irq)        /* Shared IRQ */
-               hw_config->irq = -devc->irq;
+       cfg |= tmp << 5;
+       ess_setmixer (devc, 0x40, cfg | 0x03);
 
        return 1;
 }
index 06af0f434ba567aa4fcc945d08184e659b4af76a..0bad5eb58aedffa278261236932d907f2644ebc5 100644 (file)
@@ -13,6 +13,7 @@
  *
  * Thomas Sailer                               : ioctl code reworked (vmalloc/vfree removed)
  * Rolf Fokkens (Dec 20 1998)  : Moved ESS stuff into sb_ess.[ch]
+ * Stanislav Voronyi <stas@esc.kharkov.com>    : Support for AWE 3DSE device (Jun 7 1999)
  */
 
 #include <linux/config.h>
@@ -550,14 +551,37 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
        int val, ret;
 
        /*
-        * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1).
+        * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1).
+        * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1)
+        *                                            or mode==2 put 3DSE state to mode.
         */
-       if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) 
-       {
-               if (get_user(val, (int *)arg))
-                       return -EFAULT;
-               sb_setmixer(devc, 0x43, (~val) & 0x01);
-               return 0;
+       if (devc->model == MDL_SB16) {
+               if (cmd == SOUND_MIXER_AGC) 
+               {
+                       if (get_user(val, (int *)arg))
+                               return -EFAULT;
+                       sb_setmixer(devc, 0x43, (~val) & 0x01);
+                       return 0;
+               }
+               if (cmd == SOUND_MIXER_3DSE) 
+               {
+                       /* I put here 15, but I don't know the exact version.
+                          At least my 4.13 havn't 3DSE, 4.16 has it. */
+                       if (devc->minor < 15)
+                               return -EINVAL;
+                       if (get_user(val, (int *)arg))
+                               return -EFAULT;
+                       if (val == 0 || val == 1)
+                               sb_chgmixer(devc, AWE_3DSE, 0x01, val);
+                       else if (val == 2)
+                       {
+                               ret = sb_getmixer(devc, AWE_3DSE)&0x01;
+                               return put_user(ret, (int *)arg);
+                       }
+                       else
+                               return -EINVAL;
+                       return 0;
+               }
        }
        if (((cmd >> 8) & 0xff) == 'M') 
        {
index f8627ce6ca1c9e5defadc9334f155f0c1582babe..d53df66ffea8c5e5c9ba5e8077d4ebe36af814d2 100644 (file)
 #define LEFT_CHN       0
 #define RIGHT_CHN      1
 
+/*
+ * 3DSE register of AWE32/64
+ */
+#define AWE_3DSE       0x90
+
 /*
  * Mixer registers of ALS007
  */
index baff3e5ccc7a13c11fbd4daa5c03a251ceddd848..7bbd3665700808a660236cf44cb62d19c34ec968 100644 (file)
@@ -2,7 +2,7 @@
  * sound/sgalaxy.c
  *
  * Low level driver for Aztech Sound Galaxy cards.
- * Copyright 1998 Artur Skawina
+ * Copyright 1998 Artur Skawina <skawina@geocities.com>
  *
  * Supported cards:
  *    Aztech Sound Galaxy Waverider Pro 32 - 3D
index 83c5c88c008504a9e1ba18c7a67439b3cb3073e3..0e696b1134aeaeadd33771cee2143d502fccd6c2 100644 (file)
@@ -2312,9 +2312,9 @@ static struct initvol {
 };
 
 #ifdef MODULE
-__initfunc(int init_module(void))
+int __init init_module(void)
 #else
-__initfunc(int init_sonicvibes(void))
+int __init init_sonicvibes(void)
 #endif
 {
        struct sv_state *s;
index e162d8edced39469c5a1f9aa33c249fb946d62ca..8fa4685ff3570af1ddfed2483981c5d0e84df3a5 100644 (file)
@@ -256,21 +256,39 @@ void unload_trix_sb(struct address_info *hw_info);
 void unload_trix_mpu(struct address_info *hw_info);
 void unload_cs4232(struct address_info *hw_info);
 void unload_cs4232_mpu(struct address_info *hw_info);
+void unload_opl3sa_wss(struct address_info *hw_info);
+void unload_opl3sa_sb(struct address_info *hw_info);
+void unload_opl3sa_mpu(struct address_info *hw_info);
 void unload_opl3sa2(struct address_info *hw_info);
 void unload_opl3sa2_mpu(struct address_info *hw_info);
+void unload_opl3sa2_mss(struct address_info *hw_info);
+void unload_softsyn (struct address_info *hw_config);
 
-/* From cs4232.c */
-
+/*     From cs4232.c */
 int probe_cs4232 (struct address_info *hw_config);
 void attach_cs4232 (struct address_info *hw_config);
 int probe_cs4232_mpu (struct address_info *hw_config);
 void attach_cs4232_mpu (struct address_info *hw_config);
 
-/* From opl3sa2.c */
+/*     From opl3sa.c */
+void attach_opl3sa_wss (struct address_info *hw_config);
+int probe_opl3sa_wss (struct address_info *hw_config);
+void attach_opl3sa_sb (struct address_info *hw_config);
+int probe_opl3sa_sb (struct address_info *hw_config);
+void attach_opl3sa_mpu (struct address_info *hw_config);
+int probe_opl3sa_mpu (struct address_info *hw_config);
+
+/*     From opl3sa2.c */
 int probe_opl3sa2 (struct address_info *hw_config);
 void attach_opl3sa2 (struct address_info *hw_config);
 int probe_opl3sa2_mpu (struct address_info *hw_config);
 void attach_opl3sa2_mpu (struct address_info *hw_config);
+int probe_opl3sa2_mss (struct address_info *hw_config);
+void attach_opl3sa2_mss (struct address_info *hw_config);
+
+/*     From softoss.c */
+void attach_softsyn_card (struct address_info *hw_config);
+int probe_softsyn (struct address_info *hw_config);
 
 /*     From maui.c */
 void attach_maui(struct address_info * hw_config);
@@ -291,12 +309,12 @@ void attach_waveartist(struct address_info *hw_config);
 int probe_waveartist(struct address_info *hw_config);
 void unload_waveartist(struct address_info *hw_config);
 
-/*      From wavefront.c */
+/*     From wavefront.c */
 void attach_wavefront (struct address_info *hw_config);
 int probe_wavefront (struct address_info *hw_config);
 void unload_wavefront (struct address_info *hw_config);
 
-/*      From wf_midi.c */
+/*     From wf_midi.c */
 void attach_wf_mpu(struct address_info * hw_config);
 int probe_wf_mpu(struct address_info *hw_config);
 void unload_wf_mpu(struct address_info *hw_config);
index b0568d82ab523cb624ccc26fbd6b67a4bdfd07a4..bf3ff10fec13a051faa9e4733814c1de7b12fdaf 100644 (file)
@@ -3,6 +3,9 @@
  *     modulespace.
  *
  *      (C) Copyright 1997      Alan Cox, Licensed under the GNU GPL
+ *
+ *     Thu May 27 1999 Andrew J. Kroll <ag784@freenet..buffalo..edu>
+ *     left out exported symbol... fixed
  */
 
 #include <linux/module.h>
@@ -43,6 +46,7 @@ EXPORT_SYMBOL(sound_unload_synthdev);
 
 EXPORT_SYMBOL(load_mixer_volumes);
 
+EXPORT_SYMBOL(trace_init); /* oops! this is needed for maui.c -- AJK */
 
 EXPORT_SYMBOL(conf_printf);
 EXPORT_SYMBOL(conf_printf2);
index 70b4af6d381bb5a473366dfc0cae40c5e533eace..b54d009926730fae6af33190232ec12996f93cdc 100644 (file)
@@ -42,6 +42,12 @@ static int *trix_osp = NULL;
 
 static int mpu = 0;
 
+#ifdef TRIX_JOYSTICK
+static int joystick=1;
+#else
+static int joystick=0;
+#endif
+
 static unsigned char trix_read(int addr)
 {
        outb(((unsigned char) addr), 0x390);    /* MT-0002-PC ASIC address */
@@ -196,9 +202,8 @@ int probe_trix_wss(struct address_info *hw_config)
 
        if (ret)
        {
-#ifdef TRIX_ENABLE_JOYSTICK
-               trix_write(0x15, 0x80);
-#endif
+               if(joystick==1)
+                       trix_write(0x15, 0x80);
                request_region(0x390, 2, "AudioTrix");
        }
        return ret;
@@ -477,7 +482,7 @@ MODULE_PARM(sb_dma,"i");
 MODULE_PARM(sb_irq,"i");
 MODULE_PARM(mpu_io,"i");
 MODULE_PARM(mpu_irq,"i");
-
+MODULE_PARM(joystick, "i");
 struct address_info config;
 struct address_info sb_config;
 struct address_info mpu_config;
index ac58b97dab5612e6b7ea5a825308b63d28ab48c9..f365c24341de227bb0bf33d1d20cd7203586ea2a 100644 (file)
@@ -2474,8 +2474,7 @@ wavefront_hw_reset (void)
        return (1);
 }
 
-__initfunc (static int detect_wavefront (int irq, int io_base))
-
+static int __init detect_wavefront (int irq, int io_base)
 {
        unsigned char   rbuf[4], wbuf[4];
 
@@ -2653,8 +2652,7 @@ wavefront_download_firmware (char *path)
        return 1;
 }
 
-__initfunc (static int wavefront_config_midi (void)) 
-
+static int __init wavefront_config_midi (void)
 {
        unsigned char rbuf[4], wbuf[4];
     
@@ -2728,7 +2726,6 @@ __initfunc (static int wavefront_config_midi (void))
 
 static int
 wavefront_do_reset (int atboot)
-
 {
        char voices[1];
 
@@ -2832,7 +2829,6 @@ wavefront_do_reset (int atboot)
 
 static int
 wavefront_init (int atboot)
-
 {
        int samples_are_from_rom;
 
@@ -2861,7 +2857,7 @@ wavefront_init (int atboot)
        return (0);
 }
 
-__initfunc (static int install_wavefront (void))
+static int __init install_wavefront (void)
 
 {
        if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) {
@@ -2919,7 +2915,7 @@ uninstall_wavefront (void)
 #endif OSS_SUPPORT_SEQ
        uninstall_wf_mpu ();
 }
-\f
+
 /***********************************************************************/
 /*   WaveFront FX control                                              */
 /***********************************************************************/
@@ -2955,8 +2951,7 @@ wffx_idle (void)
        return (1);
 }
 
-__initfunc (static int detect_wffx (void))
-
+static int __init detect_wffx (void)
 {
        /* This is a crude check, but its the best one I have for now.
           Certainly on the Maui and the Tropez, wffx_idle() will
@@ -2972,8 +2967,7 @@ __initfunc (static int detect_wffx (void))
        return 0;
 }      
 
-__initfunc (static int attach_wffx (void))
-
+static int __init attach_wffx (void)
 {
        if ((dev.fx_mididev = sound_alloc_mididev ()) < 0) {
                printk (KERN_WARNING LOGNAME "cannot install FX Midi driver\n");
index a8c6fc829cc984cf68a5d398d6f0b24d01cfc9c4..45db0f8b1a8afe98a54ca2141b1ac4ab28460314 100644 (file)
@@ -803,7 +803,7 @@ virtual_midi_disable (void)
        return 0;
 }
 
-__initfunc (static int detect_wf_mpu (int irq, int io_base))
+static int __init detect_wf_mpu (int irq, int io_base)
 
 {
        if (check_region (io_base, 2)) {
@@ -820,8 +820,7 @@ __initfunc (static int detect_wf_mpu (int irq, int io_base))
        return 0;
 }
 
-__initfunc (int install_wf_mpu (void)) 
-
+int __init install_wf_mpu (void)
 {
        if ((phys_dev->devno = sound_alloc_mididev()) < 0){
 
index 23718517cb255a09d9546d3005fdd09084ef60f4..1aa1a0eea6cce1d12d47ddee829718aefb36192f 100644 (file)
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
-
-#include <linux/sched.h>
 #include <linux/unistd.h>
-#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
-
-
 #include <asm/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -104,7 +99,7 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
                if (status) {
                        /* must reset the toggle on first error */
                        if (uhci_debug) {
-                           printk("Set toggle from %x rval %d\n", (unsigned int)tmp, rval ? *rval : 0);
+                           printk("Set toggle from %x rval %ld\n", (unsigned int)tmp, rval ? *rval : 0);
                        }
                        usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), usb_pipeout(tmp->info), (tmp->info >> 19) & 1);
                        break;
index bd3c8f490fa51943c682d7cd0bbd7b4ed45db94e..e3087a18b962708f43a6b919231d914c980132ef 100644 (file)
@@ -443,6 +443,8 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 
        retval = -ENOMEM;
        size = elf_ex.e_phentsize * elf_ex.e_phnum;
+       if (size > 65536)
+               goto out;
        elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
        if (!elf_phdata)
                goto out;
index 49359f260c3a9397b3a8467feca77ac1b9f320d0..bbcf8a85feffaeeab47e48d9a8c2f17b0c95a092 100644 (file)
@@ -22,8 +22,6 @@
 #include <asm/uaccess.h>
 
 #include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
 #include <linux/vmalloc.h>
 #include <asm/segment.h>
 
index b4fb29776fd98fa5c047317bfef49ba0e6f12500..be92bb62cbca06c3f89bdb9c0eb03fad1fd0c0af 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -563,7 +563,7 @@ int prepare_binprm(struct linux_binprm *bprm)
        if ((retval = permission(inode, MAY_EXEC)) != 0)
                return retval;
        /* better not execute files which are being written to */
-       if (inode->i_writecount > 0)
+       if (atomic_read(&inode->i_writecount) > 0)
                return -ETXTBSY;
 
        bprm->e_uid = current->euid;
index bcf36de99805b84c3e5d5b32e424deb832ad4b47..242696d8776e38eeeddbd12683af48f2e13b74fd 100644 (file)
@@ -130,6 +130,7 @@ static inline void init_once(struct inode * inode)
        INIT_LIST_HEAD(&inode->i_hash);
        INIT_LIST_HEAD(&inode->i_dentry);
        sema_init(&inode->i_sem, 1);
+       spin_lock_init(&inode->i_shared_lock);
 }
 
 static inline void write_inode(struct inode *inode)
@@ -523,7 +524,7 @@ void clean_inode(struct inode *inode)
        inode->i_sock = 0;
        inode->i_op = NULL;
        inode->i_nlink = 1;
-       inode->i_writecount = 0;
+       atomic_set(&inode->i_writecount, 0);
        inode->i_size = 0;
        inode->i_generation = 0;
        memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
index aded88dd76fe02fd544fedc6ceaba44f68f7808c..b9f2363e6d875b0fd3732f872e90311597e9e761 100644 (file)
@@ -25,6 +25,8 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
                                return -EBADF;
                        if (inode->i_op->get_block == NULL)
                                return -EINVAL;
+                       if (!capable(CAP_SYS_RAWIO))
+                               return -EPERM;
                        if ((error = get_user(block, (int *) arg)) != 0)
                                return error;
 
index 8a280dbb1170afb8108fa03d10218fddf2a81c55..5cb3243741a4082f37c3d5235c286af4376ebd20 100644 (file)
@@ -341,7 +341,11 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
                error = filp->f_op->lock(filp, F_GETLK, &file_lock);
                if (error < 0)
                        goto out_putf;
-               fl = &file_lock;
+               else if (error == LOCK_USE_CLNT)
+                 /* Bypass for NFS with no locking - 2.0.36 compat */
+                 fl = posix_test_lock(filp, &file_lock);
+               else
+                 fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
        } else {
                fl = posix_test_lock(filp, &file_lock);
        }
@@ -402,14 +406,17 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
         * and shared.
         */
        if (IS_MANDLOCK(inode) &&
-           (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
-           inode->i_mmap) {
-               struct vm_area_struct *vma = inode->i_mmap;
-               error = -EAGAIN;
-               do {
-                       if (vma->vm_flags & VM_MAYSHARE)
-                               goto out_putf;
-               } while ((vma = vma->vm_next_share) != NULL);
+           (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+               struct vm_area_struct *vma;
+               spin_lock(&inode->i_shared_lock);
+               for(vma = inode->i_mmap;vma;vma = vma->vm_next_share) {
+                       if (!(vma->vm_flags & VM_MAYSHARE))
+                               continue;
+                       spin_unlock(&inode->i_shared_lock);
+                       error = -EAGAIN;
+                       goto out_putf;
+               }
+               spin_unlock(&inode->i_shared_lock);
        }
 
        error = -EINVAL;
index 14d478bde77f57257e70771f981c06f9ee82d081..6683c393cc6487abc9ece8bac4cd7fbb6fe33a90 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/sched.h>
-#include <linux/minix_fs.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/fcntl.h>
index 9769ce1bb229cd35c57e9b89b77cb698770539e6..e39cd24e1bc67d80e24d37dfcf0f2b031b68a7e8 100644 (file)
@@ -171,18 +171,22 @@ int permission(struct inode * inode,int mask)
  * 0: no writers, no VM_DENYWRITE mappings
  * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
  * > 0: (i_writecount) users are writing to the file.
+ *
+ * WARNING: as soon as we will move get_write_access(), do_mmap() or
+ * prepare_binfmt() out of the big lock we will need a spinlock protecting
+ * the checks in all 3. For the time being it is not needed.
  */
 int get_write_access(struct inode * inode)
 {
-       if (inode->i_writecount < 0)
+       if (atomic_read(&inode->i_writecount) < 0)
                return -ETXTBSY;
-       inode->i_writecount++;
+       atomic_inc(&inode->i_writecount);
        return 0;
 }
 
 void put_write_access(struct inode * inode)
 {
-       inode->i_writecount--;
+       atomic_dec(&inode->i_writecount);
 }
 
 /*
index 1f92a89fba2eab14de07daaf9ce4481bc811ea54..cf4c13fdefb3d0915ebcea4194e9b841a82dbbb3 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
-#include <linux/errno.h>
 #include <linux/locks.h>
 
 #include <linux/ncp_fs.h>
index fd7a5b227a636c5c268851634526a286d769fb19..150acc6d9a7c598a6b05ee09eb9ac0ab9929b99d 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/fcntl.h>
 #include <linux/net.h>
 #include <linux/in.h>
-#include <linux/version.h>
 #include <linux/unistd.h>
 #include <linux/malloc.h>
 #include <linux/proc_fs.h>
index 63294ae294495d7a8c75c2b2d6cc6a44c0c504cb..14cb7d50f7bef6282f1e386076fcb11b1b5820c0 100644 (file)
@@ -585,7 +585,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
                 * nice and simple solution (IMHO), and it seems to
                 * work:-)
                 */
-               if (EX_WGATHER(exp) && (inode->i_writecount > 1
+               if (EX_WGATHER(exp) && (atomic_read(&inode->i_writecount) > 1
                 || (last_ino == inode->i_ino && last_dev == inode->i_dev))) {
 #if 0
                        interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000);
index dd81531ec32088fb01bde137c8eb4ab94ab748d3..c0f806f6921e6d0336e0d34c24e04bbbf6a7ba6a 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -37,8 +37,6 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf)
 asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
 {
        struct file * file;
-       struct inode * inode;
-       struct dentry * dentry;
        struct super_block * sb;
        int error;
 
index c08ebda4a5175ccafffc86bf68fd620d7a21c201..6f5c63ec3359e88b81d8cdf645660111cdbee90c 100644 (file)
@@ -150,6 +150,9 @@ static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
        char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
        int len;
 
+       if(tmp==NULL)
+               return -ENOMEM;
+               
        /* Check for special dentries.. */
        pattern = NULL;
        inode = dentry->d_inode;
index 8b27142a32852e033235b978bb386d6508d9c407..0fbae7262f8cc55dc51348cd8c5d0ebc2ab840df 100644 (file)
@@ -41,6 +41,11 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        while (filp->f_pos < inode->i_size) {
                bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
+               if(bh==NULL)
+               {
+                       printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
+                       break;
+               }
                i = (filp->f_pos - (((filp->f_pos >> 6) >> 3) << 9)) & 0x3f;
                while (i < QNX4_INODES_PER_BLOCK) {
                        offset = i * QNX4_DIR_ENTRY_SIZE;
index c360d8b722a7d30f73bf550dda9be6fbe29ad475..0b3f9ae03d6cb4459b1c158296a96bc892a9ce02 100644 (file)
@@ -98,12 +98,12 @@ static int qnx4_readlink(struct dentry *dentry, char *buffer, int buflen)
        }
        bh = bread(inode->i_dev, qnx4_ino->i_first_xtnt.xtnt_blk,
                   QNX4_BLOCK_SIZE);
-       QNX4DEBUG(("qnx4: qnx4_bread sym called -> [%s]\n",
-                  bh->b_data));
        if (bh == NULL) {
                QNX4DEBUG(("qnx4: NULL symlink bh\n"));
                return 0;
        }
+       QNX4DEBUG(("qnx4: qnx4_bread sym called -> [%s]\n",
+                  bh->b_data));
        if (bh->b_data[0] != 0) {
                i = 0;
                while (i < buflen && (c = bh->b_data[i])) {
index 3019c913faab050d0dd5840d211d8c74a1b6f317..36650f14171df6f2d2e560a7b5db9ce2741d4f71 100644 (file)
@@ -30,9 +30,6 @@
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
-
 /*
  * Write to a file (through the page cache).
  */
index b464318a7620647c4b93b4d28fac4917065157df..c75a3a405a517c9ea3b784445ab8cd5afda04a02 100644 (file)
@@ -360,14 +360,22 @@ unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
        if (result) {
                for (i = 0; i < oldcount; i++) {
                        bh = bread (sb->s_dev, tmp + i, sb->s_blocksize);
-                       mark_buffer_clean (bh);
-                       bh->b_blocknr = result + i;
-                       mark_buffer_dirty (bh, 0);
-                       if (IS_SYNC(inode)) {
-                               ll_rw_block (WRITE, 1, &bh);
-                               wait_on_buffer (bh);
+                       if(bh)
+                       {
+                               mark_buffer_clean (bh);
+                               bh->b_blocknr = result + i;
+                               mark_buffer_dirty (bh, 0);
+                               if (IS_SYNC(inode)) {
+                                       ll_rw_block (WRITE, 1, &bh);
+                                       wait_on_buffer (bh);
+                               }
+                               brelse (bh);
+                       }
+                       else
+                       {
+                               printk(KERN_ERR "ufs_new_fragments: bread fail\n");
+                               return 0;
                        }
-                       brelse (bh);
                }
                *p = SWAB32(result);
                *err = 0;
index d3d8a74e641aac4cb91a8bbf1d02f67eda465165..b930c46ae63425d5410312bd4d57c7d169e5c07c 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/errno.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
-#include <linux/msdos_fs.h>
 #include <linux/umsdos_fs.h>
 
 #include <asm/uaccess.h>
index 2ceaa977dbd3d34e0cf5e23e57a9c0add6909c7a..046fd52784f6a770dd5a6cf44d7bfdca2d55a310 100644 (file)
@@ -356,22 +356,6 @@ __initfunc(static void check_cyrix_cpu(void))
 
 __initfunc(static void check_cyrix_coma(void))
 {
-       if (boot_cpu_data.coma_bug) {
-               unsigned char ccr3, tmp;
-               cli();
-               ccr3 = getCx86(CX86_CCR3);
-               setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
-               tmp = getCx86(0x31);
-               setCx86(0x31, tmp | 0xf8);
-               tmp = getCx86(0x32);
-               setCx86(0x32, tmp | 0x7f);
-               setCx86(0x33, 0);
-               tmp = getCx86(0x3c);
-               setCx86(0x3c, tmp | 0x87);
-               setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-               sti();
-               printk("Cyrix processor with \"coma bug\" found, workaround enabled\n");
-       }
 }
  
 /*
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h
new file mode 100644 (file)
index 0000000..fc12444
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ *     Just a place holder. We don't want to have to test x86 before
+ *     we include stuff
+ */
index 04a6f1454127b86d13e0bd32a2a69e91c92b8552..a264617a3f0fafdeb801fa53b9071e53f449e93f 100644 (file)
@@ -201,9 +201,6 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t)
        return ((unsigned long*)t->reg29)[17];
 }
 
-struct pt_regs;
-extern int (*user_mode)(struct pt_regs *);
-
 /*
  * Do necessary setup to start up a newly executed thread.
  */
index 0b7bbc7e14e1744e713fdebe00971118d3ac1fa0..81aeb70ca7a12a8f297648819700df64d68da8a3 100644 (file)
@@ -59,7 +59,7 @@ struct pt_regs {
 /*
  * Does the process account for user or for system time?
  */
-#define user_mode(regs) ((regs)->cp0_status & 0x10)
+extern int (*user_mode)(struct pt_regs *);
 
 #define instruction_pointer(regs) ((regs)->cp0_epc)
 
index 27543806bd947569983243700e33ef32e1adc6f1..01bebaf731f9e0391e2f3ab73886a483ee17b4db 100644 (file)
@@ -237,7 +237,6 @@ typedef struct audio_device {
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
index 27543806bd947569983243700e33ef32e1adc6f1..01bebaf731f9e0391e2f3ab73886a483ee17b4db 100644 (file)
@@ -237,7 +237,6 @@ typedef struct audio_device {
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
index dcb407c614160b56e61b214852a8d118628d05eb..fa4272075543dac07e273788f0096e9525d18ad2 100644 (file)
@@ -359,6 +359,24 @@ static void floppy_off(unsigned int nr);
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == I2O_MAJOR)
+
+#define DEVICE_NAME "I2O block"
+#define DEVICE_REQUEST do_i2ob_request
+#define DEVICE_NR(device) (MINOR(device)>>4)
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == COMPAQ_SMART2_MAJOR)
+
+#define DEVICE_NAME "ida"
+#define DEVICE_INTR do_ida
+#define TIMEOUT_VALUE (25*HZ)
+#define DEVICE_REQUEST do_ida_request0
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
 #endif /* MAJOR_NR == whatever */
 
 #if (MAJOR_NR != SCSI_TAPE_MAJOR)
@@ -435,7 +453,7 @@ void end_that_request_last(struct request *req);
 
 #ifndef LOCAL_END_REQUEST      /* If we have our own end_request, we do not want to include this mess */
 
-#if ! SCSI_BLK_MAJOR(MAJOR_NR)
+#if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR)
 
 static void end_request(int uptodate) {
        struct request *req = CURRENT;
index 14d71253df55e43bc03874cbb3fbae2975b47c53..e95879146ed76addaf0eae9051f41a0cc7425834 100644 (file)
@@ -346,6 +346,7 @@ struct inode {
        struct file_lock        *i_flock;
        struct vm_area_struct   *i_mmap;
        struct page             *i_pages;
+       spinlock_t              i_shared_lock;
        struct dquot            *i_dquot[MAXQUOTAS];
        struct pipe_inode_info  *i_pipe;
 
@@ -354,7 +355,7 @@ struct inode {
        unsigned int            i_flags;
        unsigned char           i_sock;
 
-       int                     i_writecount;
+       atomic_t                i_writecount;
        unsigned int            i_attr_flags;
        __u32                   i_generation;
        union {
@@ -664,6 +665,10 @@ struct file_system_type {
 extern int register_filesystem(struct file_system_type *);
 extern int unregister_filesystem(struct file_system_type *);
 
+/* Return value for VFS lock functions - tells locks.c to lock conventionally
+ * REALLY kosha for root NFS and nfs_lock
+ */ 
+#define LOCK_USE_CLNT 1
 
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
@@ -922,10 +927,6 @@ extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start, un
 extern int inode_change_ok(struct inode *, struct iattr *);
 extern void inode_setattr(struct inode *, struct iattr *);
 
-/* kludge to get SCSI modules working */
-#include <linux/minix_fs.h>
-#include <linux/minix_fs_sb.h>
-
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_FS_H */
index 29e9766ea92d923a1e1ed39200d4fccead911557..feb877ed0d103cb422845e941f4bc904af42f814 100644 (file)
@@ -32,13 +32,15 @@ struct i2c_bus;
 struct i2c_driver;
 struct i2c_device;
 
-#define I2C_DRIVERID_MSP3400     1
-#define I2C_DRIVERID_TUNER       2
-#define I2C_DRIVERID_VIDEOTEXT  3
+#define I2C_DRIVERID_MSP3400            1
+#define I2C_DRIVERID_TUNER              2
+#define I2C_DRIVERID_VIDEOTEXT          3
+#define I2C_DRIVERID_VIDEODECODER       4
+#define I2C_DRIVERID_VIDEOENCODER       5
 
 #define I2C_BUSID_BT848                1       /* I2C bus on a BT848 */
 #define I2C_BUSID_PARPORT      2       /* Bit banging on a parallel port */
-
+#define I2C_BUSID_BUZ          3
 /*
  * struct for a driver for a i2c chip (tuner, soundprocessor,
  * videotext, ... ).
index 04079577e81130332938fd1c36da140b2c983e8c..03118dd5f46f020a44b8f99183cac15ce22a933f 100644 (file)
@@ -24,9 +24,6 @@
  * message structures
  */
 
-#define    TID_SZ                                  12
-#define    FUNCTION_SZ                             8
-
 struct i2o_message
 {
        u32     version_size;
@@ -35,6 +32,110 @@ struct i2o_message
        /* List follows */
 };
 
+/**************************************************************************
+ * HRT related constants and structures
+ **************************************************************************/
+#define I2O_BUS_LOCAL  0
+#define I2O_BUS_ISA    1
+#define I2O_BUS_EISA   2
+#define I2O_BUS_MCA    3
+#define I2O_BUS_PCI    4
+#define I2O_BUS_PCMCIA 5
+#define I2O_BUS_NUBUS  6
+#define I2O_BUS_CARDBUS        7
+#define I2O_BUS_UNKNOWN        0x80
+
+typedef struct _i2o_pci_bus {
+       u8 PciFunctionNumber;
+       u8 PciDeviceNumber;
+       u8 PciBusNumber;
+       u8 reserved;
+       u16 PciVendorID;
+       u16 PciDeviceID;
+} i2o_pci_bus, *pi2o_pci_bus;
+
+typedef struct _i2o_local_bus {
+       u16 LbBaseIOPort;
+       u16 reserved;
+       u32 LbBaseMemoryAddress;
+} i2o_local_bus, *pi2o_local_bus;
+
+typedef struct _i2o_isa_bus {
+       u16 IsaBaseIOPort;
+       u8 CSN;
+       u8 reserved;
+       u32 IsaBaseMemoryAddress;
+} i2o_isa_bus, *pi2o_isa_bus;
+
+typedef struct _i2o_eisa_bus_info {
+       u16 EisaBaseIOPort;
+       u8 reserved;
+       u8 EisaSlotNumber;
+       u32 EisaBaseMemoryAddress;
+} i2o_eisa_bus, *pi2o_eisa_bus;
+
+typedef struct _i2o_mca_bus {
+       u16 McaBaseIOPort;
+       u8 reserved;
+       u8 McaSlotNumber;
+       u32 McaBaseMemoryAddress;
+} i2o_mca_bus, *pi2o_mca_bus;
+
+typedef struct _i2o_other_bus {
+       u16 BaseIOPort;
+       u16 reserved;
+       u32 BaseMemoryAddress;
+} i2o_other_bus, *pi2o_other_bus;
+
+
+typedef struct _i2o_hrt_entry {
+       u32 adapter_id;
+       u32 parent_tid:12;
+       u32 state:4;
+       u32 bus_num:8;
+       u32 bus_type:8;
+       union {
+               i2o_pci_bus pci_bus;
+               i2o_local_bus local_bus;
+               i2o_isa_bus isa_bus;
+               i2o_eisa_bus eisa_bus;
+               i2o_mca_bus mca_bus;
+               i2o_other_bus other_bus;
+       } bus;
+} i2o_hrt_entry, *pi2o_hrt_entry;
+
+typedef struct _i2o_hrt {
+       u16 num_entries;
+       u8 entry_len;
+       u8 hrt_version;
+       u32 change_ind;
+       i2o_hrt_entry hrt_entry[1];
+} i2o_hrt, *pi2o_hrt;
+
+typedef struct _i2o_lct_entry {
+       u32 entry_size:16;
+       u32 tid:12;
+       u32 reserved:4;
+       u32 change_ind;
+       u32 device_flags;
+       u32 class_id;
+       u32 sub_class;
+       u32 user_tid:12;
+       u32 parent_tid:12;
+       u32 bios_info:8;
+       u8 identity_tag[8];
+       u32 event_capabilities;
+} i2o_lct_entry, *pi2o_lct_entry;
+
+typedef struct _i2o_lct {
+       u32 table_size:16;
+       u32 boot_tid:12;
+       u32 lct_ver:4;
+       u32 iop_flags;
+       u32 current_change_ind;
+       i2o_lct_entry lct_entry[1];
+} i2o_lct, *pi2o_lct;
+
 
 /*
  *     Each I2O device entity has one or more of these. There is one
@@ -85,6 +186,8 @@ struct i2o_controller
        volatile u32 *post_port;                /* Messaging ports */
        volatile u32 *reply_port;
        volatile u32 *irq_mask;                 /* Interrupt port */
+       u32 *lct;
+       u32 *hrt;
        u32 mem_offset;                         /* MFA offset */
        u32 mem_phys;                           /* MFA physical */
        u32 priv_mem;
@@ -185,18 +288,22 @@ extern int i2o_release_device(struct i2o_device *);
 extern int i2o_post_this(struct i2o_controller *, int, u32 *, int);
 extern int i2o_post_wait(struct i2o_controller *, int, u32 *, int, int *, int);
 extern int i2o_issue_claim(struct i2o_controller *, int, int, int, int *);
-extern int i2o_query_scalar(struct i2o_controller *, int, int, int, int, void *,
-                           int, int *);
-extern int i2o_params_set(struct i2o_controller *c, int, int, int, int, void *,
-                         int, int *);
 
-extern void i2o_run_queue(struct i2o_controller *);
+extern int i2o_query_scalar(struct i2o_controller *, int, int, int, int, 
+                       void *, int, int *);
+extern int i2o_set_scalar(struct i2o_controller *, int, int, int, int, 
+                       void *, int, int *);
 
-extern void i2o_report_status(const char *, const char *, u8, u8, u16);
-extern void report_common_status(u8);
-extern void report_lan_dsc(u16);
+extern int i2o_query_table(int, struct i2o_controller *, int, int, int, int, 
+                       void *, int, void *, int, int *);
+extern int i2o_clear_table(struct i2o_controller *, int, int, int, int *); 
+extern int i2o_row_add_table(struct i2o_controller *, int, int, int, int,
+                       void *, int, int *);
+extern int i2o_row_delete_table(struct i2o_controller *, int, int, int, int,
+                       void *, int, int *);
 
-extern u32 i2o_wait_message(struct i2o_controller *, char *);
+extern void i2o_run_queue(struct i2o_controller *);
+extern void i2o_report_status(const char *, const char *, u32 *);
 
 extern const char *i2o_get_class_name(int);
 
@@ -278,28 +385,12 @@ extern const char *i2o_get_class_name(int);
 #define    I2O_SNFORMAT_IEEE_REG128                    9
 #define    I2O_SNFORMAT_UNKNOWN2                       0xff
 
-
-/*
- *     "Special" TID assignments
- */
-#define    I2O_IOP_TID                                 0
-#define    I2O_HOST_TID                                1
-
-
 /* Transaction Reply Lists (TRL) Control Word structure */
 
 #define TRL_SINGLE_FIXED_LENGTH                0x00
 #define TRL_SINGLE_VARIABLE_LENGTH     0x40
 #define TRL_MULTIPLE_FIXED_LENGTH      0x80
 
-/* LAN Class specific functions */
-
-#define    LAN_PACKET_SEND                     0x3B
-#define    LAN_SDU_SEND                                0x3D
-#define    LAN_RECEIVE_POST                    0x3E
-#define    LAN_RESET                           0x35
-#define    LAN_SUSPEND                         0x37
-
 /*
  *     Messaging API values
  */
@@ -468,7 +559,7 @@ extern const char *i2o_get_class_name(int);
 #define I2O_DSC_UNSUPPORTED_VERSION            0x001A
 #define I2O_DSC_DEVICE_BUSY                    0x001B
 #define I2O_DSC_DEVICE_NOT_AVAILABLE           0x001C
-
 /* Message header defines for VersionOffset */
 #define I2OVER15       0x0001
 #define I2OVER20       0x0002
@@ -478,7 +569,9 @@ extern const char *i2o_get_class_name(int);
 #define SGL_OFFSET_4    (0x0040 | I2OVERSION)
 #define SGL_OFFSET_5    (0x0050 | I2OVERSION)
 #define SGL_OFFSET_6    (0x0060 | I2OVERSION)
+#define SGL_OFFSET_7    (0x0070 | I2OVERSION)
 #define SGL_OFFSET_8    (0x0080 | I2OVERSION)
+#define SGL_OFFSET_9    (0x0090 | I2OVERSION)
 #define SGL_OFFSET_10   (0x00A0 | I2OVERSION)
 
 #define TRL_OFFSET_5    (0x0050 | I2OVERSION)
@@ -492,9 +585,6 @@ extern const char *i2o_get_class_name(int);
 #define MSG_LAST       0x4000
 #define MSG_REPLY      0x8000
 
-  /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
-#define LAN_MSG_REQST  (MSG_MULTI_TRANS | SGL_OFFSET_4)
-
  /* minimum size msg */
 #define THREE_WORD_MSG_SIZE    0x00030000
 #define FOUR_WORD_MSG_SIZE     0x00040000
@@ -518,7 +608,7 @@ extern const char *i2o_get_class_name(int);
 #define MSG_POOL_SIZE          16384
 
 #define I2O_POST_WAIT_OK       1
-#define I2O_POST_WAIT_TIMEOUT  -1
+#define I2O_POST_WAIT_TIMEOUT  -ETIMEDOUT
 
 #endif /* __KERNEL__ */
 
index d6daa0f2d9cc83a58928036f8256b7ad968e7373..5156d0d753f9c8fc25f22e96c49f035dd4a5e227 100644 (file)
@@ -265,6 +265,7 @@ typedef struct ide_drive_s {
 #if FAKE_FDISK_FOR_EZDRIVE
        unsigned remap_0_to_1   : 1;    /* flag: partitioned with ezdrive */
 #endif /* FAKE_FDISK_FOR_EZDRIVE */
+       unsigned ata_flash      : 1;    /* 1=present, 0=default */
        byte            media;          /* disk, cdrom, tape, floppy, ... */
        select_t        select;         /* basic drive/head select reg value */
        byte            ctl;            /* "normal" value for IDE_CONTROL_REG */
@@ -388,6 +389,7 @@ typedef struct hwif_s {
        unsigned        sharing_irq: 1; /* 1 = sharing irq with another hwif */
        unsigned        reset      : 1; /* reset after probe */
        unsigned        autodma    : 1; /* automatically try to enable DMA at boot */
+       unsigned        udma_four  : 1; /* 1=ATA-66 capable, 0=default */
        byte            channel;        /* for dual-port chips: 0=primary, 1=secondary */
        struct pci_dev  *pci_dev;       /* for pci chipsets */
        ide_pci_devid_t pci_devid;      /* for pci chipsets: {VID,DID} */
index cfefdf0ac1a5e812b1c441a4af990f4a96f55684..20b267b9fcc305edda5cfff478e8b6f5a153e909 100644 (file)
 #define SCSI_DISK7_MAJOR       71
 
 
+#define LVM_BLK_MAJOR  58      /* Logical Volume Manager */
+
+#define COMPAQ_SMART2_MAJOR    72
+#define COMPAQ_SMART2_MAJOR1   73
+#define COMPAQ_SMART2_MAJOR2   74
+#define COMPAQ_SMART2_MAJOR3   75
+#define COMPAQ_SMART2_MAJOR4   76
+#define COMPAQ_SMART2_MAJOR5   77
+#define COMPAQ_SMART2_MAJOR6   78
+#define COMPAQ_SMART2_MAJOR7   79
+
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
+#define LVM_CHAR_MAJOR 109     /* Logical Volume Manager */
+
 #define I2O_MAJOR              80      /* 80->87 */
 
 #define IDE6_MAJOR     88
index 7b511f008b7ab01ef47600bbc8853aa0540ae5f4..80afb41c781ac53c1ef2deefdac1108731f0c437 100644 (file)
@@ -317,6 +317,8 @@ extern void vmtruncate(struct inode * inode, unsigned long offset);
 extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
+extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
+extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
 
 extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
index a349c3a7c92ef283e0346231df013522cde587cf..bbe90c2293c80aca96a10ea2cf4922a8a1c583a7 100644 (file)
@@ -457,12 +457,12 @@ extern void proc_device_tree_init(void);
 
 #else
 
-extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) {};
-extern inline int proc_unregister(struct proc_dir_entry *a, int b) {};
-extern inline int proc_net_register(struct proc_dir_entry *a) {};
-extern inline int proc_net_unregister(int x) {};
-extern inline int proc_scsi_register(struct proc_dir_entry *b, struct proc_dir_entry *c) {};
-extern inline int proc_scsi_unregister(struct proc_dir_entry *a, int x);
+extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) { return 0; }
+extern inline int proc_unregister(struct proc_dir_entry *a, int b) { return 0; }
+extern inline int proc_net_register(struct proc_dir_entry *a) { return 0; }
+extern inline int proc_net_unregister(int x) { return 0; }
+extern inline int proc_scsi_register(struct proc_dir_entry *b, struct proc_dir_entry *c) { return 0; }
+extern inline int proc_scsi_unregister(struct proc_dir_entry *a, int x) { return 0; }
 
 extern inline struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
                                         struct proc_dir_entry *parent)
index 52ff06b5f7ad1f20d876daaf12b552fd04b32f55..2d5128dc43141c9d26c715801c7398953d9d29f1 100644 (file)
@@ -890,6 +890,12 @@ typedef unsigned char mixer_record[128];
 
 #define SOUND_MIXER_ACCESS             _SIOWR('M', 102, mixer_record)
 
+/*
+ * Two ioctls for special souncard function
+ */
+#define SOUND_MIXER_AGC  _SIOWR('M', 103, int)
+#define SOUND_MIXER_3DSE  _SIOWR('M', 104, int)
+
 /*
  * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers.
  * These features can be used when accessing device specific features.
diff --git a/include/linux/video_decoder.h b/include/linux/video_decoder.h
new file mode 100644 (file)
index 0000000..1302c7f
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _LINUX_VIDEO_DECODER_H
+#define _LINUX_VIDEO_DECODER_H
+
+struct video_decoder_capability { /* this name is too long */
+       __u32   flags;
+#define        VIDEO_DECODER_PAL       1       /* can decode PAL signal */
+#define        VIDEO_DECODER_NTSC      2       /* can decode NTSC */
+#define        VIDEO_DECODER_SECAM     4       /* can decode SECAM */
+#define        VIDEO_DECODER_AUTO      8       /* can autosense norm */
+#define        VIDEO_DECODER_CCIR      16      /* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
+       int     inputs;                 /* number of inputs */
+       int     outputs;                /* number of outputs */
+};
+
+/*
+DECODER_GET_STATUS returns the following flags.  The only one you need is
+DECODER_STATUS_GOOD, the others are just nice things to know.
+*/
+#define        DECODER_STATUS_GOOD     1       /* receiving acceptable input */
+#define        DECODER_STATUS_COLOR    2       /* receiving color information */
+#define        DECODER_STATUS_PAL      4       /* auto detected */
+#define        DECODER_STATUS_NTSC     8       /* auto detected */
+#define        DECODER_STATUS_SECAM    16      /* auto detected */
+
+
+#define        DECODER_GET_CAPABILITIES _IOR('d', 1, struct video_decoder_capability)
+#define        DECODER_GET_STATUS      _IOR('d', 2, int)
+#define        DECODER_SET_NORM        _IOW('d', 3, int)
+#define        DECODER_SET_INPUT       _IOW('d', 4, int)       /* 0 <= input < #inputs */
+#define        DECODER_SET_OUTPUT      _IOW('d', 5, int)       /* 0 <= output < #outputs */
+#define        DECODER_ENABLE_OUTPUT   _IOW('d', 6, int)       /* boolean output enable control */
+#define        DECODER_SET_PICTURE     _IOW('d', 7, struct video_picture)
+
+#define        DECODER_DUMP            _IO('d', 192)           /* debug hook */
+
+
+#endif
diff --git a/include/linux/video_encoder.h b/include/linux/video_encoder.h
new file mode 100644 (file)
index 0000000..4b0e690
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _LINUX_VIDEO_ENCODER_H
+#define _LINUX_VIDEO_ENCODER_H
+
+struct video_encoder_capability { /* this name is too long */
+       __u32   flags;
+#define        VIDEO_ENCODER_PAL       1       /* can encode PAL signal */
+#define        VIDEO_ENCODER_NTSC      2       /* can encode NTSC */
+#define        VIDEO_ENCODER_SECAM     4       /* can encode SECAM */
+#define        VIDEO_ENCODER_CCIR      16      /* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
+       int     inputs;                 /* number of inputs */
+       int     outputs;                /* number of outputs */
+};
+
+#define        ENCODER_GET_CAPABILITIES _IOR('e', 1, struct video_encoder_capability)
+#define        ENCODER_SET_NORM        _IOW('e', 2, int)
+#define        ENCODER_SET_INPUT       _IOW('e', 3, int)       /* 0 <= input < #inputs */
+#define        ENCODER_SET_OUTPUT      _IOW('e', 4, int)       /* 0 <= output < #outputs */
+#define        ENCODER_ENABLE_OUTPUT   _IOW('e', 5, int)       /* boolean output enable control */
+
+
+#endif
index 52c1e0f312e5cf3f418c3d035131bf3d05ab38a0..590d4b10f8780f29b47bad944ff062d402beb2c0 100644 (file)
@@ -279,6 +279,7 @@ struct video_unit
 #define VID_HARDWARE_VINO      20      /* Reserved for SGI Indy Vino */
 #define VID_HARDWARE_CADET     21      /* Cadet radio */
 #define VID_HARDWARE_CPIA      22
+#define VID_HARDWARE_TERRATEC  23      /* TerraTec ActiveRadio */
 
 /*
  *     Initialiser list
index 9612a55720b45c81cdcd0e63af1c5387a4e363d3..ba551b7d4de6d18fbf35242961332ddd08a67f7b 100644 (file)
@@ -90,7 +90,7 @@ struct irda_todo {
  */
 struct irda_cb {
        struct miscdevice dev;  
-       wait_queue_head_t *wait_queue;
+       wait_queue_head_t wait_queue;
 
        int in_use;
 
index 4b8581cf06a9da4bf0f6129c22fa6105c84d49d7..7141a91526087fa55b1613bb3b3b943c7d30c95e 100644 (file)
@@ -332,6 +332,9 @@ extern void mdacon_setup(char *str, int *ints);
 #ifdef CONFIG_LTPC
 extern void ltpc_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_BLK_CPQ_DA
+extern void cpqarray_setup(char *str, int *ints);
+#endif
 
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
@@ -864,6 +867,9 @@ static struct kernel_param cooked_params[] __initdata = {
 #endif
 #ifdef CONFIG_LTPC
        { "ltpc=", ltpc_setup },
+#endif
+#ifdef CONFIG_BLK_CPQ_DA
+       { "smart2=", cpqarray_setup },
 #endif
        { 0, 0 }
 };
index 418b6e4b3ebc9d4b02ed06bcf153857e95a043d1..12c580852928f347a6b2f984ae18bdbe26f21965 100644 (file)
@@ -251,14 +251,16 @@ static inline int dup_mmap(struct mm_struct * mm)
                if (file) {
                        get_file(file);
                        if (tmp->vm_flags & VM_DENYWRITE)
-                               file->f_dentry->d_inode->i_writecount--;
+                               atomic_dec(&file->f_dentry->d_inode->i_writecount);
       
                        /* insert tmp into the share list, just after mpnt */
+                       spin_lock(&file->f_dentry->d_inode->i_shared_lock);
                        if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
                                mpnt->vm_next_share->vm_pprev_share =
                                        &tmp->vm_next_share;
                        mpnt->vm_next_share = tmp;
                        tmp->vm_pprev_share = &mpnt->vm_next_share;
+                       spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
                }
 
                /* Copy the pages, but defer checking for errors */
@@ -361,6 +363,10 @@ static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct
        struct mm_struct * mm;
        int retval;
 
+       tsk->min_flt = tsk->maj_flt = 0;
+       tsk->cmin_flt = tsk->cmaj_flt = 0;
+       tsk->nswap = tsk->cnswap = 0;
+
        if (clone_flags & CLONE_VM) {
                mmget(current->mm);
                /*
@@ -377,9 +383,6 @@ static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct
                goto fail_nomem;
 
        tsk->mm = mm;
-       tsk->min_flt = tsk->maj_flt = 0;
-       tsk->cmin_flt = tsk->cmaj_flt = 0;
-       tsk->nswap = tsk->cnswap = 0;
        copy_segments(nr, tsk, mm);
        retval = new_page_tables(tsk);
        if (retval)
index 8a30af4dbda998101de365a469744fe207537ff3..798015eaaf23dd4f9994d46c099301dcbb56bdc1 100644 (file)
@@ -232,6 +232,7 @@ EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(max_sectors);
 EXPORT_SYMBOL(max_readahead);
+EXPORT_SYMBOL(file_moveto);
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
index 21f306a055e25a905914e13b6b19133ef2aaa178..0d007d4926b1c63e276eb6d71647d8d0099ad5cf 100644 (file)
@@ -115,7 +115,8 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
 {
        int copied = 0;
-       while (len) {
+
+       while (len > 0) {
                char buf[128];
                int this_len, retval;
 
@@ -139,7 +140,8 @@ int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int l
 int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
 {
        int copied = 0;
-       while (len) {
+
+       while (len > 0) {
                char buf[128];
                int this_len, retval;
 
index b6ae00178cab90868b28f88e18135f7bbf576f20..53ee45120823cdcaf5b89c2b5a04393377373000 100644 (file)
@@ -29,7 +29,7 @@
 
 static kmem_cache_t *signal_queue_cachep;
 
-int nr_queued_signals;
+atomic_t nr_queued_signals;
 int max_queued_signals = 1024;
 
 void __init signals_init(void)
@@ -60,7 +60,7 @@ flush_signals(struct task_struct *t)
        while (q) {
                n = q->next;
                kmem_cache_free(signal_queue_cachep, q);
-               nr_queued_signals--;
+               atomic_dec(&nr_queued_signals);
                q = n;
        }
 }
@@ -157,7 +157,7 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
                                        current->sigqueue_tail = pp;
                                *info = q->info;
                                kmem_cache_free(signal_queue_cachep,q);
-                               nr_queued_signals--;
+                               atomic_dec(&nr_queued_signals);
                                
                                /* then see if this signal is still pending. */
                                q = *pp;
@@ -323,13 +323,13 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
 
                struct signal_queue *q = 0;
 
-               if (nr_queued_signals < max_queued_signals) {
+               if (atomic_read(&nr_queued_signals) < max_queued_signals) {
                        q = (struct signal_queue *)
                            kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
                }
                
                if (q) {
-                       nr_queued_signals++;
+                       atomic_inc(&nr_queued_signals);
                        q->next = NULL;
                        *t->sigqueue_tail = q;
                        t->sigqueue_tail = &q->next;
@@ -872,7 +872,7 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact)
                                        else {
                                                *pp = q->next;
                                                kmem_cache_free(signal_queue_cachep, q);
-                                               nr_queued_signals--;
+                                               atomic_dec(&nr_queued_signals);
                                        }
                                        q = *pp;
                                }
@@ -1067,7 +1067,9 @@ sys_ssetmask(int newmask)
 
        return old;
 }
+#endif /* !defined(__alpha__) */
 
+#if !defined(__alpha__) && !defined(__mips__)
 /*
  * For backwards compatibility.  Functionality superseded by sigaction.
  */
@@ -1084,4 +1086,4 @@ sys_signal(int sig, __sighandler_t handler)
 
        return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
 }
-#endif /* !alpha && !__ia64__ */
+#endif /* !alpha && !__ia64__ && !defined(__mips__) */
index d7b460fc9af62a9927b0cde75c2b3f0c5da7d990..195c2cb5bdb54147842a0cd5d2ba836b4a4589ce 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/proc_fs.h>
 #include <linux/ctype.h>
 #include <linux/utsname.h>
-#include <linux/swapctl.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
index dbd37cb819d8f10f002ac3a94024ea67927808b9..866cd1f1ed916841b1454afd7ff2e5594cb08033 100644 (file)
@@ -362,3 +362,17 @@ char * strstr(const char * s1,const char * s2)
        return NULL;
 }
 #endif
+
+#ifndef __HAVE_ARCH_MEMCHR
+void *memchr(const void *s, int c, size_t n)
+{
+       unsigned char *p = s;
+       while (n-- != 0) {
+               if ((unsigned char)c == *p++) {
+                       return p-1;
+               }
+       }
+       return NULL;
+}
+
+#endif
index 04d0f534d0c286dcf4108f30e8b7fe171bd536eb..ce9c722c406e8b857ecce92718da11db0baaa102 100644 (file)
@@ -726,8 +726,9 @@ void vmtruncate(struct inode * inode, unsigned long offset)
        struct vm_area_struct * mpnt;
 
        truncate_inode_pages(inode, offset);
+       spin_lock(&inode->i_shared_lock);
        if (!inode->i_mmap)
-               return;
+               goto out_unlock;
        mpnt = inode->i_mmap;
        do {
                struct mm_struct *mm = mpnt->vm_mm;
@@ -758,6 +759,8 @@ void vmtruncate(struct inode * inode, unsigned long offset)
                zap_page_range(mm, start, len);
                flush_tlb_range(mm, start, end);
        } while ((mpnt = mpnt->vm_next_share) != NULL);
+out_unlock:
+       spin_unlock(&inode->i_shared_lock);
 }
 
 
index c9d07a2916794b70611c4b5d0c29b03891b651d8..84a9140970785a45f8a77e84882d53fbc8ca2b11 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -77,10 +77,12 @@ static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
 
        if (file) {
                if (vma->vm_flags & VM_DENYWRITE)
-                       file->f_dentry->d_inode->i_writecount++;
+                       atomic_inc(&file->f_dentry->d_inode->i_writecount);
+               spin_lock(&file->f_dentry->d_inode->i_shared_lock);
                if(vma->vm_next_share)
                        vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
                *vma->vm_pprev_share = vma->vm_next_share;
+               spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
        }
 }
 
@@ -294,7 +296,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
        if (file) {
                int correct_wcount = 0;
                if (vma->vm_flags & VM_DENYWRITE) {
-                       if (file->f_dentry->d_inode->i_writecount > 0) {
+                       if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) {
                                error = -ETXTBSY;
                                goto free_vma;
                        }
@@ -303,13 +305,13 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
                         * might). In any case, this takes care of any
                         * race that this might cause.
                         */
-                       file->f_dentry->d_inode->i_writecount--;
+                       atomic_dec(&file->f_dentry->d_inode->i_writecount);
                        correct_wcount = 1;
                }
                error = file->f_op->mmap(file, vma);
                /* Fix up the count if necessary, then check for an error */
                if (correct_wcount)
-                       file->f_dentry->d_inode->i_writecount++;
+                       atomic_inc(&file->f_dentry->d_inode->i_writecount);
                if (error)
                        goto unmap_and_free_vma;
                vma->vm_file = file;
@@ -878,13 +880,15 @@ void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
        if (file) {
                struct inode * inode = file->f_dentry->d_inode;
                if (vmp->vm_flags & VM_DENYWRITE)
-                       inode->i_writecount--;
+                       atomic_dec(&inode->i_writecount);
       
                /* insert vmp into inode's share list */
+               spin_lock(&inode->i_shared_lock);
                if((vmp->vm_next_share = inode->i_mmap) != NULL)
                        inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
                inode->i_mmap = vmp;
                vmp->vm_pprev_share = &inode->i_mmap;
+               spin_unlock(&inode->i_shared_lock);
        }
 }
 
index 32228f25ec2354b33f87a28c254821baf3d1b515..b9ef2efd5869e34efd3f06eba9e16b774037a85b 100644 (file)
@@ -894,7 +894,7 @@ int atif_ioctl(int cmd, void *arg)
                        else
                        {
                                limit = ntohs(nr->nr_lastnet);
-                               if(limit - ntohs(nr->nr_firstnet) > 256)
+                               if(limit - ntohs(nr->nr_firstnet) > 4096)
                                {
                                        printk(KERN_WARNING "Too many routes/iface.\n");
                                        return (-EINVAL);
@@ -938,6 +938,8 @@ int atif_ioctl(int cmd, void *arg)
                                 return (-EPERM);
                         if(sa->sat_family != AF_APPLETALK)
                                 return (-EINVAL);
+                        if (atif == NULL)
+                                return (-EADDRNOTAVAIL);
 
                         /*
                          * for now, we only support proxy AARP on ELAP;
index a2ad7111f9298bd54c1c9f630bdf20bb2347cfa5..f6ae5e6774f3be35c43fd815c523b0ce5bb443a6 100644 (file)
@@ -462,6 +462,9 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
        if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
                return -ENODEV;
 
+       if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
+               return -EINVAL;
+
        digi.ndigi = ax25_ctl.digi_count;
        for (k = 0; k < digi.ndigi; k++)
                digi.calls[k] = ax25_ctl.digi_addr[k];
index 996aeb7180b3b129d0230d591c92a90ea05facf2..5fbd188d27c53a2071910beef32ab7e4705ebb0b 100644 (file)
@@ -1831,12 +1831,8 @@ static int br_flood(struct sk_buff *skb, int port)
                        
 /*                     printk("Flood to port %d\n",i);*/
                        nskb->nh.raw = nskb->data + ETH_HLEN;
-#if LINUX_VERSION_CODE >= 0x20100
                        nskb->priority = 1;
                        dev_queue_xmit(nskb);
-#else
-                       dev_queue_xmit(nskb,nskb->dev,1);
-#endif
                }
        }
        return(0);
index 16f2e3e03b7a706d5ae1f8d3445452b5cde046a9..1e9de20f2649350276929e6b207986810e5e817d 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/timer.h>
-#include <linux/rtnetlink.h>
 #include <asm/spinlock.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
index 9456c7f299ba931c5c65c93cd8411f5961f2b8eb..78b5d8f9b062edf36949302878386471b4e7560d 100644 (file)
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <net/raw.h>
-#include <net/snmp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <linux/errno.h>
index b52a2998805dc264b3379a8a7969a1eaadbe1370..2125f8a91968e7b07b32b12c49e954476dc88b94 100644 (file)
@@ -1339,7 +1339,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                break;
        }
 
-       if(copied > 0 && msg->msg_name)
+       if (copied > 0 && msg->msg_name)
                tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)
                                               msg->msg_name);       
 
index 957ea9d38af530eeadec5c86681f3fd76372f2c5..3c5102b42435db042c399e8e3c3775c1f5ca93ba 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.181 1999/07/02 11:26:31 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.182 1999/07/05 01:34:07 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -167,7 +167,7 @@ static __inline__ int tcp_bucket_check(unsigned short snum)
        tb = tcp_bhash[tcp_bhashfn(snum)];
        for( ; (tb && (tb->port != snum)); tb = tb->next)
                ;
-       ret = 0
+       ret = 0;
        if (tb == NULL) {
                if ((tb = tcp_bucket_create(snum)) == NULL)
                        ret = 1;
index 2696a05cdde1d665720bb3e1c2650ff3a039fcc2..c99dffff06f78a7784eb25e1300bdb3adb95713c 100644 (file)
@@ -776,8 +776,8 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
        /*
         *      Check any passed addresses
         */
-       if (addr_len) 
-               *addr_len=sizeof(*sin);
+       if (addr_len)
+               *addr_len=sizeof(*sin);
 
        if (flags & MSG_ERRQUEUE)
                return ip_recv_error(sk, msg, len);
index a6263d41cef424378db8b8e91cd4e8cb38d71689..bf63c8c0b8171c871223ab54e141e327e91b253b 100644 (file)
@@ -92,12 +92,11 @@ static __inline__ struct ip6_fw_rule * ip6_fwrule_alloc(void)
        struct ip6_fw_rule *rl;
 
        rl = kmalloc(sizeof(struct ip6_fw_rule), GFP_ATOMIC);
-
-       memset(rl, 0, sizeof(struct ip6_fw_rule));
-
        if (rl)
+       {
+               memset(rl, 0, sizeof(struct ip6_fw_rule));
                rl->flowr.ops = &ip6_fw_ops;
-
+       }
        return rl;
 }
 
index e0c78772382fe34f121f044ee1abfee7a8f8238f..f6c0a42ac3f058df96dd074cbbb05862926af09c 100644 (file)
@@ -39,8 +39,6 @@
 
 #include <net/rawv6.h>
 
-#include <asm/uaccess.h>
-
 struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
 
 static void raw_v6_hash(struct sock *sk)
index 5f8ff914b21cb1066578fe8135e619125cb5c230..9e9a7358533ddbf09eb17fc906019277eb3d98d2 100644 (file)
@@ -37,7 +37,6 @@
 #include <net/ndisc.h>
 #include <net/addrconf.h>
 #include <net/tcp.h>
-#include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
 #include <asm/uaccess.h>
index 929278b68fa4d5adb7842502995691a40715bb08..b6ccfa7117fea8405e9193a6284c4db83e43721e 100644 (file)
@@ -794,7 +794,8 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
                                        if(call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb) == FW_ACCEPT)
                                        {
                                                skb2=skb_clone(skb, GFP_ATOMIC);
-                                               ipxrtr_route_skb(skb2);
+                                               if(skb2)
+                                                       ipxrtr_route_skb(skb2);
                                        }
                                }
                        }
index a78f372ebb9dd6522a58a4bb064d152212d1b702..bfb9212772fe103c960e40cda85c0881465d8650 100644 (file)
@@ -54,7 +54,6 @@
 #include <linux/malloc.h>
 #include <linux/vmalloc.h> 
 #include <linux/errno.h>
-#include <linux/sched.h>       /* to get the struct task_struct */
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
 
index ab7354e1d2dace4dbbc40fda2ecd867179302a21..cab4a11af5bf8888bd0b344f7eb8591c01021035 100644 (file)
@@ -218,6 +218,8 @@ __initfunc(int irda_init(void))
        misc_register( &irda.dev);
 
        irda.in_use = FALSE;
+       
+       init_waitqueue_head(&irda.wait_queue);
 
        /* 
         * Initialize modules that got compiled into the kernel 
index a7732d76dafb3e2fd08f925e8fcbbc84f412d523..1cff39fa171782e6e075d12e862a718ad20041c6 100644 (file)
@@ -63,7 +63,6 @@
 #include <linux/proc_fs.h>
 #include <net/ip.h>
 #include <net/arp.h>
-#include <linux/if_arp.h>
 #include <linux/init.h>
 
 int nr_ndevs = 4;
@@ -1311,6 +1310,11 @@ __initfunc(void nr_proto_init(struct net_proto *pro))
 
        for (i = 0; i < nr_ndevs; i++) {
                dev_nr[i].name = kmalloc(20, GFP_KERNEL);
+               if(dev_nr[i].name==NULL)
+               {
+                       printk(KERN_ERR "Netrom: unable to register devices.\n");
+                       break;
+               }
                sprintf(dev_nr[i].name, "nr%d", i);
                dev_nr[i].init = nr_init;
                register_netdev(&dev_nr[i]);
index b67fe251d03bf000703af11b0a1a5dca525f3091..f96167bc86ca5dbae43979d9691e57a444de5648 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/hippidevice.h>
 #endif
 #include <net/pkt_sched.h>
+#include <net/scm.h>
 
 #ifdef CONFIG_BRIDGE
 #include <net/br.h>
@@ -32,7 +33,6 @@
 
 #ifdef CONFIG_INET
 #include <linux/ip.h>
-#include <linux/etherdevice.h>
 #include <net/protocol.h>
 #include <net/arp.h>
 #include <net/ip.h>
@@ -40,9 +40,7 @@
 #include <net/tcp.h>
 #include <net/icmp.h>
 #include <net/route.h>
-#include <net/scm.h>
 #include <net/inet_common.h>
-#include <net/pkt_sched.h>
 #include <linux/inet.h>
 #include <linux/mroute.h>
 #include <linux/igmp.h>
@@ -56,7 +54,6 @@ extern __u32 sysctl_rmem_max;
 #include <linux/icmpv6.h>
 #include <net/ipv6.h>
 #include <net/ndisc.h>
-#include <net/dst.h>
 #include <net/transp_v6.h>
 
 extern int tcp_tw_death_row_slot;
@@ -69,8 +66,6 @@ extern int udp_port_rover;
 
 #include <linux/rtnetlink.h>
 
-#include <net/scm.h>
-
 #if    defined(CONFIG_ULTRA)   ||      defined(CONFIG_WD80x3)          || \
        defined(CONFIG_EL2)     ||      defined(CONFIG_NE2000)          || \
        defined(CONFIG_E2100)   ||      defined(CONFIG_HPLAN_PLUS)      || \
@@ -93,10 +88,6 @@ extern void destroy_8023_client(struct datalink_proto *);
 
 #ifdef CONFIG_ATALK_MODULE
 #include <net/sock.h>
-#include <net/dst.h>
-#include <net/checksum.h>
-#include <linux/etherdevice.h>
-#include <net/pkt_sched.h>
 #endif
 
 #ifdef CONFIG_SYSCTL
index 1c27a4724106f2909b8fb8b1a8964f3f81490418..acba673958289e3e6fd3bcc52effb9fbcf468f4e 100644 (file)
@@ -54,7 +54,6 @@
 #include <linux/proc_fs.h>
 #include <net/ip.h>
 #include <net/arp.h>
-#include <linux/if_arp.h>
 #include <linux/init.h>
 
 int rose_ndevs = 10;
@@ -1509,6 +1508,11 @@ __initfunc(void rose_proto_init(struct net_proto *pro))
 
        for (i = 0; i < rose_ndevs; i++) {
                dev_rose[i].name = kmalloc(20, GFP_KERNEL);
+               if(dev_rose[i].name == NULL)
+               {
+                       printk(KERN_ERR "Rose: unable to register ROSE devices.\n");
+                       break;
+               }
                sprintf(dev_rose[i].name, "rose%d", i);
                dev_rose[i].init = rose_init;
                register_netdev(&dev_rose[i]);
index 1e6ff87d91f7ee4540647e99b76480bec19b95d9..23c8cc20587159bcfba5c8ea392885945028dd3a 100644 (file)
@@ -87,7 +87,6 @@
 #include <linux/un.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>
-#include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
 #include <linux/in.h>
index a4f0700230f5a9ccec4bac73e9853c9a9cad81a5..e65c1e86ff0783897772f33460a2bc3b09ecbc17 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
-#include <linux/if_arp.h>
 #include <linux/init.h>
 #include <net/x25.h>
 
index bcbf31b0dfca2cb26b538b02dccc16b939c0b00e..5db6a58a5c467b738f464b635859ab28f56c803a 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
-#include <linux/if_arp.h>
 #include <linux/firewall.h>
 #include <net/x25.h>
 
index 4725ebfeb3cc414a6d8b585fa4cef1d73d0b22c0..a1b8642a45a4302b907a05e5e932b006d74c3cab 100644 (file)
@@ -21,10 +21,12 @@ ls -l /usr/lib/lib{g,stdc}++.so  2>/dev/null | awk -F. \
 ps --version 2>&1 | awk 'NR==1{print "Procps                ", $NF}'
 mount --version | awk -F\- '{print "Mount                 ", $NF}'
 hostname -V 2>&1 | awk 'NR==1{print "Net-tools             ", $NF}'
+# Kbd needs 'loadkeys -h',
 loadkeys -h 2>&1 | awk \
-'(NR==1 && $3) {ver=$3}
- (NR==2 && $1 ~ /console-tools/) {print "Console-tools         ",$3; done=1}
- END {if (!done) print "Kbd                   ",ver}'
+'(NR==1 && ($3 !~ /option/)) {print "Kbd                   ", $3}'
+# while console-tools needs 'loadkeys -V'.
+loadkeys -V 2>&1 | awk \
+'(NR==1 && ($2 ~ /console-tools/)) {print "Console-tools         ", $3}'
 expr --v | awk '{print "Sh-utils              ", $NF}'
 X=`cat /proc/modules | sed -e "s/ .*$//"`
 echo "Modules Loaded         "$X