]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.36pre1 2.3.36pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:29:40 +0000 (15:29 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:29:40 +0000 (15:29 -0500)
101 files changed:
Documentation/Configure.help
Documentation/i2c/writing-clients
Documentation/telephony/ixj.txt [new file with mode: 0644]
Documentation/video4linux/bttv/CARDLIST
Documentation/video4linux/bttv/Insmod-options
Documentation/video4linux/bttv/README
Documentation/video4linux/bttv/Sound-FAQ
MAINTAINERS
Makefile
arch/alpha/kernel/entry.S
arch/alpha/kernel/osf_sys.c
arch/i386/config.in
drivers/Makefile
drivers/char/Config.in
drivers/char/bttv.c
drivers/char/bttv.h
drivers/char/buz.c
drivers/char/mem.c
drivers/char/saa7110.c
drivers/char/saa7111.c
drivers/char/saa7185.c
drivers/char/tda9855.c
drivers/char/tea6300.c
drivers/char/tuner.c
drivers/char/videodev.c
drivers/char/zr36120.c
drivers/char/zr36120.h
drivers/char/zr36120_i2c.c
drivers/char/zr36120_mem.c
drivers/char/zr36120_mem.h
drivers/i2c/i2c-algo-bit.c
drivers/i2c/i2c-algo-pcf.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/i2c/i2c-elektor.c
drivers/i2c/i2c-elv.c
drivers/i2c/i2c-pcf8584.h
drivers/i2c/i2c-philips-par.c
drivers/i2c/i2c-velleman.c
drivers/i2o/i2o_core.c
drivers/i2o/i2o_lan.c
drivers/net/eepro.c
drivers/net/eth16i.c
drivers/net/irda/irport.c
drivers/net/irda/irtty.c
drivers/net/irda/pc87108.c
drivers/net/irda/toshoboe.c
drivers/net/irda/w83977af_ir.c
drivers/net/sis900.c
drivers/pcmcia/yenta.c
drivers/scsi/Makefile
drivers/scsi/README.aha152x [new file with mode: 0644]
drivers/scsi/advansys.c
drivers/scsi/advansys.h
drivers/scsi/aha152x.c
drivers/scsi/aha152x.h
drivers/scsi/aha1542.c
drivers/scsi/megaraid.c
drivers/scsi/scsi.c
drivers/sound/msnd.h
drivers/sound/msnd_pinnacle.c
drivers/sound/trident.c
drivers/sound/trident.h
drivers/telephony/Config.in [new file with mode: 0644]
drivers/telephony/Makefile [new file with mode: 0644]
drivers/telephony/ixj.c [new file with mode: 0644]
drivers/telephony/ixj.h [new file with mode: 0644]
drivers/telephony/phonedev.c [new file with mode: 0644]
fs/cramfs/Makefile
fs/exec.c
fs/ext2/super.c
include/linux/ext2_fs.h
include/linux/i2c-algo-bit.h
include/linux/i2c-algo-pcf.h
include/linux/i2c-dev.h
include/linux/i2c-elektor.h
include/linux/i2c-id.h
include/linux/i2c.h
include/linux/irda.h
include/linux/ixjuser.h [new file with mode: 0644]
include/linux/major.h
include/linux/mm.h
include/linux/phonedev.h [new file with mode: 0644]
include/linux/telephony.h [new file with mode: 0644]
include/linux/videodev.h
include/net/irda/irlap_event.h
include/net/irda/irlap_frame.h
kernel/sched.c
mm/highmem.c
mm/memory.c
net/bridge/br.c
net/irda/af_irda.c
net/irda/ircomm/ircomm_core.c
net/irda/ircomm/ircomm_tty.c
net/irda/irda_device.c
net/irda/iriap.c
net/irda/iriap_event.c
net/irda/irlap_event.c
net/irda/irlap_frame.c
net/irda/irmod.c
net/irda/irttp.c

index 76f0ead06d27f6319c64e1b8f9c3e5e0af6860af..8ad9b31966dc000d5acdab82344246cfc4a02618 100644 (file)
@@ -12621,6 +12621,25 @@ CONFIG_BLK_CPQ_DA
    boards supported by this driver, and for further information 
    on the use of this driver. 
 
+QuickNet Internet LineJack/PhoneJack support
+CONFIG_PHONE_IXJ
+  Say M if you have a telephony card manufactured by Quicknet
+  Technologies, Inc.  These include the Internet PhoneJACK and
+  Internet LineJACK Telephony Cards.
+
+  For the ISA versions of these products, you can configure the
+  cards using the isapnp tools (pnpdump/isapnp) or you can use the
+  isapnp support.  Please read:
+
+  /usr/src/linux/Documentation/telephony/ixj.txt.
+
+  For more information on these cards, see Quicknet's website at:
+  http://www.quicknet.net/
+
+  If you do not have any Quicknet telephony cards, you can safely
+  ignore this option.
+
 #
 # ARM options
 #
index 42754961be222ae9cf1c08ee8fb0c9e63d4b0ffb..cbacdf8a7069462dbc8eaf1838f2047d08c7a335 100644 (file)
@@ -356,7 +356,8 @@ so you do not have to define it yourself.
 
 The i2c_probe or sensors_detect function will call the foo_detect_client
 function only for those i2c addresses that actually have a device on
-them (unless a `force' parameter was used).
+them (unless a `force' parameter was used). In addition, addresses that
+are already in use (by some other registered client) are skipped.
 
 
 The detect client function
@@ -667,12 +668,6 @@ need this. You may even set it to NULL.
     return 0;
   }
 
-You should never directly call this function, but instead use the 
-general function below:
-
-  extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
-
-
 
 Sending and receiving
 =====================
diff --git a/Documentation/telephony/ixj.txt b/Documentation/telephony/ixj.txt
new file mode 100644 (file)
index 0000000..ce67a82
--- /dev/null
@@ -0,0 +1,406 @@
+Linux Quicknet-Drivers-Howto
+Quicknet Technologies, Inc. (www.quicknet.net)
+Version 0.3.4  December 18, 1999
+
+1.0  Introduction
+
+This document describes the first GPL release version of the Linux
+driver for the Quicknet Internet PhoneJACK and Internet LineJACK
+cards.  More information about these cards is available at
+www.quicknet.net.  The driver version discussed in this document is
+0.3.4.
+
+These cards offer nice telco style interfaces to use your standard
+telephone/key system/PBX as the user interface for VoIP applications.
+The Internet LineJACK also offers PSTN connectivity for a single line
+Internet to PSTN gateway.  Of course, you can add more than one card
+to a system to obtain multi-line functionality.  At this time, the
+driver supports the POTS port on both the Internet PhoneJACK and the
+Internet LineJACK, but the PSTN port on the latter card is not yet
+supported.
+
+This document, and the drivers for the cards, are intended for a
+limited audience that includes technically capable programmers who
+would like to experiment with Quicknet cards.  The drivers are
+considered in ALPHA status and are not yet considered stable enough
+for general, widespread use in an unlimited audience.
+
+That's worth saying again:
+
+THE LINUX DRIVERS FOR QUICKNET CARDS ARE PRESENTLY IN A ALPHA STATE
+AND SHOULD NOT BE CONSIDERED AS READY FOR NORMAL WIDESPREAD USE.
+
+They are released early in the spirit of Internet development and to
+make this technology available to innovators who would benefit from
+early exposure.
+
+When we promote the device driver to "beta" level it will be
+considered ready for non-programmer, non-technical users.  Until then,
+please be aware that these drivers may not be stable and may affect
+the performance of your system.
+
+
+1.1 Latest Additions/Improvements
+
+The 0.3.4 version of the driver is the first GPL release.  Several
+features had to be removed from the prior binary only module, mostly
+for reasons of Intellectual Property rights.  We can't release
+information that is not ours - so certain aspects of the driver had to
+be removed to protect the rights of others.  
+
+Specifically, very old Internet PhoneJACK cards have non-standard
+G.723.1 codecs (due to the early nature of the DSPs in those days).
+The auto-conversion code to bring those cards into compliance with
+todays standards is available as a binary only module to those people
+needing it.  If you bought your card after 1997 or so, you are OK -
+it's only the very old cards that are affected.
+
+Also, the code to download G.728/G.729/G.729a codecs to the DSP is
+available as a binary only module as well.  This IP is not ours to
+release.  
+
+Hooks are built into the GPL driver to allow it to work with other
+companion modules that are completely separate from this module.
+
+1.2 Copyright, Trademarks, Disclaimer, & Credits 
+
+Copyright
+
+Copyright (c) 1999 Quicknet Technologies, Inc.  Permission is granted
+to freely copy and distribute this document provided you preserve it
+in its original form. For corrections and minor changes contact the
+maintainer at linux@quicknet.net.
+
+Trademarks
+
+Internet PhoneJACK and Internet LineJACK are registered trademarks of
+Quicknet Technologies, Inc.
+
+Disclaimer
+
+Much of the info in this HOWTO is early information released by
+Quicknet Technologies, Inc. for the express purpose of allowing early
+testing and use of the Linux drivers developed for their products.
+While every attempt has been made to be thorough, complete and
+accurate, the information contained here may be unreliable and there
+are likely a number of errors in this document. Please let the
+maintainer know about them. Since this is free documentation, it
+should be obvious that neither I nor previous authors can be held
+legally responsible for any errors.
+
+Credits
+
+This HOWTO was written by:
+
+       Greg Herlein <gherlein@quicknet.net>
+       Ed Okerson <eokerson@quicknet.net> 
+
+1.3  Future Plans: You Can Help 
+
+Please let the maintainer know of any errors in facts, opinions,
+logic, spelling, grammar, clarity, links, etc.  But first, if the date
+is over a month old, check to see that you have the latest
+version. Please send any info that you think belongs in this document.
+
+You can also contribute code and/or bug-fixes for the sample
+applications.
+
+
+1.4  Where to get things
+
+You can download the latest versions of the driver from:
+
+http://www.quicknet.net/develop.htm
+
+You can download the latest version of this document from:
+
+http://www.quicknet.net/develop.htm
+
+
+1.5  Mailing List
+
+Quicknet operates a mailing list to provide a public forum on using
+these drivers.
+
+To subscribe to the linux-sdk mailing list, send an email to:
+
+   majordomo@linux.quicknet.net
+
+In the body of the email, type:
+
+   subscribe linux-sdk <your-email-address>
+
+Please delete any signature block that you would normally add to the
+bottom of your email - it tends to confuse majordomo.
+
+To send mail to the list, address your mail to 
+
+   linux-sdk@linux.quicknet.net
+
+Your message will go out to everyone on the list.
+
+To unsubscribe to the linux-sdk mailing list, send an email to:
+
+   majordomo@linux.quicknet.net
+
+In the body of the email, type:
+
+   unsubscribe linux-sdk <your-email-address>
+
+
+
+2.0  Requirements
+
+2.1  Quicknet Card(s)
+
+You will need at least one Internet PhoneJACK or Internet LineJACK
+cards.  These are ISA or PCI bus devices that use Plug-n-Play for
+configuration, and use no IRQs.  The driver will support up to 16
+cards in any one system, of any mix between the two types.
+
+Note that you will need two cards to do any useful testing alone, since
+you will need a card on both ends of the connection.  Of course, if
+you are doing collaborative work, perhaps your friends or coworkers
+have cards too.  If not, we'll gladly sell them some!
+
+
+2.2  ISAPNP
+
+Since the Quicknet cards are Plug-n-Play devices, you will need the
+isapnp tools package to configure the cards, or you can use the isapnp
+module to autoconfigure them.  The former package probably came with
+your Linux distribution.  Documentation on this package is available
+online at:
+
+http://mailer.wiwi.uni-marburg.de/linux/LDP/HOWTO/Plug-and-Play-HOWTO.html
+
+The isapnp autoconfiguration is available on the Quicknet website at:
+
+    http://www.quicknet.net/develop.htm
+
+though it may be in the kernel by the time you read this.
+
+
+3.0  Card Configuration 
+
+If you did not get your drivers as part of the linux kernel, do the
+following to install them:
+
+   a.  untar the distribution file.  We use the following command:
+        tar -xvzf ixj-0.x.x.tgz
+
+This creates a subdirectory holding all the necessary files.  Go to that
+subdirectory.
+
+   b.  run the "ixj_dev_create" script to remove any stray device
+files left in the /dev directory, and to create the new officially
+designated device files.  Note that the old devices were called 
+/dev/ixj, and the new method uses /dev/phone.  
+
+   c.  type "make;make install" - this will compile and install the
+module.
+
+   d.  type "depmod -av" to rebuild all your kernel version dependencies.
+
+   e.  if you are using the isapnp module to configure the cards
+       automatically, then skip to step f.  Otherwise, ensure that you
+       have run the isapnp configuration utility to properly configure
+       the cards.
+
+       e1. The Internet PhoneJACK has one configuration register that
+           requires 16 IO ports.  The Internet LineJACK card has two
+           configuration registers and isapnp reports that IO 0
+           requires 16 IO ports and IO 1 requires 8.  The Quicknet
+           driver assumes that these registers are configured to be
+           contiguous, i.e. if IO 0 is set to 0x340 then IO 1 should
+           be set to 0x350.
+
+           Make sure that none of the cards overlap if you have
+           multiple cards in the system.
+
+           If you are new to the isapnp tools, you can jumpstart
+           yourself by doing the following:
+
+      e2.  go to the /etc directory and run pnpdump to get a blank
+           isapnp.conf file.
+
+               pnpdump > /etc/isapnp.conf
+
+      e3.  edit the /etc/isapnp.conf file to set the IO warnings and
+           the register IO addresses. The IO warnings means that you
+           should find the line in the file that looks like this:
+
+          (CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
+
+          and you should edit the line to look like this:
+
+          (CONFLICT (IO WARNING)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) #
+          or WARNING
+
+           The next step is to set the IO port addresses.  The issue
+           here is that isapnp does not identify all of the ports out
+           there.  Specifically any device that does not have a driver
+           or module loaded by Linux will not be registered.  This
+           includes older sound cards and network cards.  We have
+           found that the IO port 0x300 is often used even though
+           isapnp claims that no-one is using those ports.  We
+           recommend that for a single card installation that port
+           0x340 (and 0x350) be used.  The IO port line should change
+           from this:
+
+          (IO 0 (SIZE 16) (BASE 0x0300) (CHECK))
+
+          to this:
+
+          (IO 0 (SIZE 16) (BASE 0x0340) )
+
+       e4.  if you have multiple Quicknet cards, make sure that you do
+            not have any overlaps.  Be especially careful if you are
+            mixing Internet PhoneJACK and Internet LineJACK cards in
+            the same system.  In these cases we recommend moving the
+            IO port addresses to the 0x400 block.  Please note that on
+            a few machines the 0x400 series are used.  Feel free to
+            experiment with other addresses.  Our cards have been
+            proven to work using IO addresses of up to 0xFF0.
+
+       e5.  the last step is to uncomment the activation line so the
+            drivers will be associated with the port.  This means the
+            line (immediately below) the IO line should go from this:
+
+            # (ACT Y)
+
+            to this:
+
+           (ACT Y)
+
+            Once you have finished editing the isapnp.conf file you
+            must submit it into the pnp driverconfigure the cards.
+            This is done using the following command:
+
+           isapnp isapnp.conf
+
+           If this works you should see a line that identifies the
+            Quicknet device, the IO port(s) chosen, and a message
+            "Enabled OK".
+
+   f.  if you are loading the module by hand, use insmod.  An example
+of this would look like this:
+
+       insmod phonedev
+       insmod ixj dspio=0x320,0x310 xio=0,0x330
+
+Then verify the module loaded by running lsmod. If you are not using a
+module that matches your kernel version, you may need to "force" the
+load using the -f option in the insmod command.
+
+       insmod phonedev
+       insmod -f ixj dspio=0x320,0x310 xio=0,0x330
+
+
+If you are using isapnp to autoconfigure your card, then you do NOT
+need any of the above, though you need to use depmod to load the
+driver, like this:
+
+       depmod ixj
+
+which will result in the needed drivers getting loaded automatically.
+
+   g.  if you are planning on using kerneld to automatically load the 
+module for you, then you need to edit /etc/conf.modules and add the 
+following lines:
+
+       options ixj dspio=0x340 xio=0x330 ixjdebug=0
+
+If you do this, then when you execute an application that uses the
+module kerneld will load the module for you.  Note that to do this,
+you need to have your kernel set to support kerneld.  You can check
+for this by looking at /usr/src/linux/.config and you should see this:
+
+       # Loadable module support
+       #
+       <snip>
+       CONFIG_KMOD=y
+
+  h.  if you want non-root users to be able to read and write to the 
+ixj devices (this is a good idea!) you should do the following:
+
+     - decide upon a group name to use and create that group if 
+       needed.  Add the user names to that group that you wish to 
+       have access to the device.  For example, we typically will
+       create a group named "ixj" in /etc/group and add all users
+       to that group that we want to run software that can use the 
+       ixjX devices.
+
+     - change the permissions on the device files, like this:
+       
+       chgrp ixj /dev/ixj*     
+       chmod 660 /dev/ixj*
+       
+Once this is done, then non-root users should be able to use the
+devices.  If you have enabled autoloading of modules, then the user
+should be able to open the device and have the module loaded
+automatically for them.
+
+
+4.0 Driver Installation problems.
+
+We have tested these drivers on the 2.2.9, 2.2.10, 2.2.12, and 2.2.13 kernels
+and in all cases have eventually been able to get the drivers to load and 
+run.  We have found four types of problems that prevent this from happening.
+The problems and solutions are:
+
+  a. A step was missed in the installation.  Go back and use section 3
+as a checklist.  Many people miss running the ixj_dev_create script and thus
+never load the device names into the filesystem.
+
+  b. The kernel is inconsistently linked.  We have found this problem in
+the Out Of the Box installation of several distributions.  The symptoms 
+are that neither driver will load, and that the unknown symbols include "jiffy"
+and "kmalloc".  The solution is to recompile both the kernel and the
+modules.  The command string for the final compile looks like this:
+
+    In the kernel directory:
+    1.  cp .config /tmp
+    2.  make mrproper
+    3.  cp /tmp/.config .
+    4. make dep;make clean;make bzImage;make modules;make modules_install
+
+This rebuilds both the kernel and all the modules and makes sure they all 
+have the same linkages.  This generally solves the problem once the new 
+kernel is installed and the system rebooted.
+
+  c. The kernel has been patched, then unpatched.  This happens when
+someone decides to use an earlier kernel after they load a later kernel.
+The symptoms are proceeding through all three above steps and still not
+being able to load the driver.  What has happened is that the generated
+header files are out of sync with the kernel itself.  The solution is
+to recompile (again) using "make mrproper".  This will remove and then
+regenerate all the necessary header files.  Once this is done, then you 
+need to install and reboot the kernel.  We have not seen any problem
+loading one of our drivers after this treatment.
+
+5.0  Known Limitations
+
+We cannot currently play "dial-tone" and listen for DTMF digits at the
+same time using the ISA PhoneJACK.  This is a bug in the 8020 DSP chip
+used on that product.  All other Quicknet products function normally
+in this regard.  We have a work-around, but it's not done yet.  Until
+then, if you want dial-tone, you can always play a recorded dial-tone
+sound into the audio until you have gathered the DTMF digits.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
index f63d59a343c6c718f0722ae77b9dab92d41c875c..5fd5b826bc775bbfcfe49abed6118d3cda4288d8 100644 (file)
@@ -1,4 +1,3 @@
-make[1]: Entering directory `/home/kraxel/2/src/bttv-0.7.10/driver'
 bttv.o
   card=0 - unknown
   card=1 - MIRO PCTV
@@ -34,6 +33,7 @@ bttv.o
   card=31 - iProTV
   card=32 - Intel Create and Share PCI
   card=33 - Askey/Typhoon/Anubis Magic TView
+  card=34 - Terratec TerraTValue
 
 tuner.o
   type=0 - Temic PAL
@@ -50,4 +50,3 @@ tuner.o
   type=11 - Alps TSBB5
   type=12 - Alps TSBE5
   type=13 - Alps TSBC5
-make[1]: Leaving directory `/home/kraxel/2/src/bttv-0.7.10/driver'
index 05cbb44368fa41f5ef85b64b34f7f3e749fac56d..43dbdf53d804784c68954493d8e7ad26480bb0a1 100644 (file)
@@ -17,6 +17,8 @@ bttv.o
                fieldnr=1       Count fields.  Some TV descrambling software
                                needs this, for others it only generates
                                50 useless IRQs/sec.
+               autoload=0/1    autoload helper modules (tuner, audio).
+                               default is 1 (on).
 
        remap, card, radio and pll accept up to four comma-separted arguments
        (for multiple boards).
index a25485584d071064b013cab603ff8ad68390e012..7b087654f94c15f0f25d6f2480e5f39e337a76b3 100644 (file)
@@ -7,7 +7,9 @@ changes.  Bugfixes, merged patches from other people, merged fixes
 from the kernel version, port to the new i2c stack, removed support
 for 2.0.x, code cleanups, ...
 
-You'll need the new i2c stack, download it from
+To compile this bttv version, you'll the new i2c stack.  Kernels
+newer than 2.3.34 have this already included.  If you have a older
+kernel, download it from:
        http://www2.lm-sensors.nu/~lm78/download.html
 
 You'll find Ralphs original (mostly outdated) documentation in the
index 5b9b9404add73f619295413ef4f0240e4ad92495..cf774575831e2f20d850c4a8ef56c660d1233e88 100644 (file)
@@ -17,11 +17,11 @@ telling which card type is used.  Like this one:
 
 You should verify this is correct.  If it is'nt, you have to pass the
 correct board type as insmod argument, "insmod bttv card=2" for
-example.  The file MODULES in the driver directory has a list of valid
-arguments.  If your card is'nt listed there, you might check the
-source code for new entries which are not listed yet.  If there is'nt
-one for your card, you can check if one of the existing entries does
-work for you (just trial and error...).
+example.  The file CARDLIST has a list of valid arguments for card.
+If your card is'nt listed there, you might check the source code for
+new entries which are not listed yet.  If there is'nt one for your
+card, you can check if one of the existing entries does work for you
+(just trial and error...).
 
 Some boards have an extra processor for sound to do stereo decoding
 and other nice features.  The msp34xx chips are used by Hauppauge for
@@ -78,13 +78,19 @@ What you have to do is figure out the correct values for gpiomask and
 the audiomux array.  If you have Windows and the drivers four your
 card installed, you might to check out if you can read these registers
 values used by the windows driver.  A tool to do this is available
-from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil
-If you hav'nt Windows installed, this is a trial and error game...
+from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil.  There is
+some #ifdef'ed code in bttv.c (search for "new card") which prints
+these values before board initialization, this might help too: boot
+win, start tv app, softboot (loadlin) into linux and load bttv with
+this enabled.  If you hav'nt Windows installed, this is a trial and
+error game...
 
 Good luck,
 
   Gerd
 
 
-PS: If you have a new working entry, mail it to Ralph.  So it can be
-    included into next driver version...
+PS: If you have a new working entry, mail it to me.
+
+-- 
+Gerd Knorr <kraxel@goldbach.in-berlin.de>
index 010550c720d2de4a3c52a118fb7e2bebeb303f8b..373ad16eead5c1e4398dc1cc087742c35016689e 100644 (file)
@@ -410,6 +410,15 @@ M: mikulas@artax.karlin.mff.cuni.cz
 W:     http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
 S:     Maintained
 
+I2C DRIVERS
+P:     Simon Vogl
+M:     simon@tk.uni-linz.ac.at
+P:     Frodo Looijaard
+M:     frodol@dds.nl
+L:     linux-i2c@pelican.tk.uni-linz.ac.at
+W:     http://www.tk.uni-linz.ac.at/~simon/private/i2c
+S:     Maintained
+
 i386 BOOT CODE
 P:     Riley H. Williams
 M:     rhw@memalpha.cx
index e2ef41653d40422e668f7a6d28beeb2d27ff1780..c69fa52d363bff06bfb03b35fb5c1bb551beb5b5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 35
+SUBLEVEL = 36
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -238,6 +238,10 @@ ifeq ($(CONFIG_I2C),y)
 DRIVERS := $(DRIVERS) drivers/i2c/i2c.a
 endif
 
+ifeq ($(CONFIG_PHONE),y)
+DRIVERS := $(DRIVERS) drivers/telephony/telephony.a
+endif
+
 include arch/$(ARCH)/Makefile
 
 .S.s:
index 927d4aa81906e339eb6258c58e699c2d4bd7e881..6b37bd23c90710ac0a2b38f211ba15218e1b4b19 100644 (file)
@@ -985,7 +985,7 @@ sys_call_table:
        .quad osf_utsname
        .quad sys_lchown
        .quad osf_shmat
-       .quad sys_shmctl                        /* 210 */
+       .quad sys_shmctlold                     /* 210 */
        .quad sys_shmdt
        .quad sys_shmget
        .quad alpha_ni_syscall
@@ -1150,3 +1150,4 @@ sys_call_table:
        .quad sys_setresgid
        .quad sys_getresgid
        .quad sys_ni_syscall                    /* sys_dipc */
+       .quad sys_shmctl
index e888c91e31cd120bfbf7c6c8ae3463cb94d174d3..7c0624c000ddf9f1063e7ac021ee16ddbcee1b3c 100644 (file)
@@ -31,6 +31,9 @@
 #include <linux/shm.h>
 #include <linux/poll.h>
 #include <linux/file.h>
+#include <linux/types.h>
+#include <linux/ipc.h>
+#include <linux/shm.h>
 
 #include <asm/fpu.h>
 #include <asm/io.h>
@@ -38,6 +41,7 @@
 #include <asm/system.h>
 #include <asm/sysinfo.h>
 #include <asm/hwrpb.h>
+#include <asm/processor.h>
 
 extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
 extern int do_pipe(int *);
@@ -1442,3 +1446,103 @@ asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
 
        return ret;
 }
+
+struct shmid_ds_old {
+       struct ipc_perm         shm_perm;       /* operation perms */
+       int                     shm_segsz;      /* size of segment (bytes) */
+       __kernel_time_t         shm_atime;      /* last attach time */
+       __kernel_time_t         shm_dtime;      /* last detach time */
+       __kernel_time_t         shm_ctime;      /* last change time */
+       __kernel_ipc_pid_t      shm_cpid;       /* pid of creator */
+       __kernel_ipc_pid_t      shm_lpid;       /* pid of last operator */
+       unsigned short          shm_nattch;     /* no. of current attaches */
+       unsigned short          shm_unused;     /* compatibility */
+       void                    *shm_unused2;   /* ditto - used by DIPC */
+       void                    *shm_unused3;   /* unused */
+};
+
+struct  shminfo_old {
+       int shmmax;
+       int shmmin;
+       int shmmni;
+       int shmseg;
+       int shmall;
+};
+
+asmlinkage long sys_shmctlold(int shmid, int cmd, struct shmid_ds_old *buf)
+{
+       struct shmid_ds arg;
+       long ret;
+       mm_segment_t old_fs;
+
+       if (cmd == IPC_SET) {
+               struct shmid_ds_old tbuf;
+
+               if(copy_from_user (&tbuf, buf, sizeof(*buf)))
+                       return -EFAULT;
+               arg.shm_perm = tbuf.shm_perm;
+               arg.shm_segsz = tbuf.shm_segsz;
+               arg.shm_atime = tbuf.shm_atime;
+               arg.shm_dtime = tbuf.shm_dtime;
+               arg.shm_ctime = tbuf.shm_ctime;
+               arg.shm_cpid = tbuf.shm_cpid;
+               arg.shm_lpid = tbuf.shm_lpid;
+               arg.shm_nattch = tbuf.shm_nattch;
+               arg.shm_unused = tbuf.shm_unused;
+               arg.shm_unused2 = tbuf.shm_unused2;
+               arg.shm_unused3 = tbuf.shm_unused3;
+       }
+       old_fs = get_fs ();
+       set_fs (KERNEL_DS);
+       ret = sys_shmctl(shmid, cmd, &arg);
+       set_fs (old_fs);
+       if (ret < 0)
+               return(ret);
+       switch(cmd) {
+               case IPC_INFO:
+               {
+                       struct shminfo *tbuf = (struct shminfo *) &arg;
+                       struct shminfo_old shminfo_oldst;
+
+                       shminfo_oldst.shmmax = (tbuf->shmmax > INT_MAX ?
+                                               INT_MAX : tbuf->shmmax);
+                       shminfo_oldst.shmmin = tbuf->shmmin;
+                       shminfo_oldst.shmmni = tbuf->shmmni;
+                       shminfo_oldst.shmseg = tbuf->shmseg;
+                       shminfo_oldst.shmall = tbuf->shmall;
+                       if (copy_to_user(buf, &shminfo_oldst, 
+                                               sizeof(struct shminfo_old)))
+                               return -EFAULT;
+                       return(ret);
+               }
+               case SHM_INFO:
+               {
+                       struct shm_info *tbuf = (struct shm_info *) &arg;
+
+                       if (copy_to_user (buf, tbuf, sizeof(struct shm_info)))
+                               return -EFAULT;
+                       return(ret);
+               }
+               case SHM_STAT:
+               case IPC_STAT:
+               {
+                       struct shmid_ds_old tbuf;
+
+                       tbuf.shm_perm = arg.shm_perm;
+                       tbuf.shm_segsz = arg.shm_segsz;
+                       tbuf.shm_atime = arg.shm_atime;
+                       tbuf.shm_dtime = arg.shm_dtime;
+                       tbuf.shm_ctime = arg.shm_ctime;
+                       tbuf.shm_cpid = arg.shm_cpid;
+                       tbuf.shm_lpid = arg.shm_lpid;
+                       tbuf.shm_nattch = arg.shm_nattch;
+                       tbuf.shm_unused = arg.shm_unused;
+                       tbuf.shm_unused2 = arg.shm_unused2;
+                       tbuf.shm_unused3 = arg.shm_unused3;
+                       if (copy_to_user (buf, &tbuf, sizeof(tbuf)))
+                               return -EFAULT;
+                       return(ret);
+               }
+       }
+       return(ret);
+}
index c9aced8a37fb73a0f53d80ad9b799d6b71f0dece..4ba8ee9b96f7960c9ffa13e0728de865ccc2057b 100644 (file)
@@ -145,6 +145,8 @@ if [ "$CONFIG_NET" = "y" ]; then
    source net/Config.in
 fi
 
+source drivers/telephony/Config.in
+
 mainmenu_option next_comment
 comment 'SCSI support'
 
index 79ece21302236a5a277a5bc2709ad49bb899cfd8..f04d7bb2ba8fd2cb2ddbd038b696b8a648b8d5c5 100644 (file)
@@ -11,7 +11,7 @@ SUB_DIRS     := block char net parport sound misc
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \
                                macintosh video dio zorro fc4 usb \
-                               nubus tc ap1000 atm pcmcia i2c
+                               nubus tc ap1000 atm pcmcia i2c telephony
 
 ifdef CONFIG_DIO
 SUB_DIRS += dio
@@ -66,6 +66,15 @@ else
   endif
 endif 
 
+ifeq ($(CONFIG_PHONE),y)
+SUB_DIRS += telephony
+MOD_SUB_DIRS += telephony
+else
+  ifeq ($(CONFIG_PHONE),m)
+  MOD_SUB_DIRS += telephony
+  endif
+endif 
+
 ifdef CONFIG_SGI
 SUB_DIRS += sgi
 MOD_SUB_DIRS += sgi
index 085cf0523f24a7172412aa9c4bb97277ac54c12c..7d2d0c8e7cf06a971bbf330bd47651abb77fa3cd 100644 (file)
@@ -129,7 +129,7 @@ comment 'Video For Linux'
 tristate 'Video For Linux' CONFIG_VIDEO_DEV
 if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
    dep_tristate '  I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT
-   comment 'Radio/Video Adapters'
+   comment 'Radio Adapters'
    dep_tristate '  ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
    dep_tristate '  AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
@@ -143,37 +143,15 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
    if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
       hex '    Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
    fi
-   if [ "$CONFIG_PCI" != "n" ]; then
-      dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
-   fi
    dep_tristate '  GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
       hex '    GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
    fi
-   dep_tristate '  Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
    dep_tristate '  Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
-   if [ "$CONFIG_PMAC" = "y" ]; then
-      dep_tristate '  PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
-   fi
-   if [ "$CONFIG_PARPORT" != "n" ]; then
-      dep_tristate '  Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        dep_tristate '  QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
-      fi
-   fi
-   dep_tristate '  SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
    dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
       hex '    SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
    fi
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      if [ "$CONFIG_SGI" = "y" ]; then
-        dep_tristate '  SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV
-      fi
-   fi
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      dep_tristate '  Stradis 4:2:2 MPEG-2 video driver  (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV
-   fi
    dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
       hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
@@ -196,9 +174,25 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
    if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
       hex '    ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
    fi
-   dep_tristate '  Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI
+   comment 'Video Adapters'
+   dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI
+   dep_tristate '  Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_PARPORT" != "n" ]; then
+      dep_tristate '  Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+        dep_tristate '  QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
+      fi
+   fi
+   dep_tristate '  SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_SGI" = "y" ]; then
+         dep_tristate '  SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI
+      fi
+      dep_tristate '  Stradis 4:2:2 MPEG-2 video driver  (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI
+   fi
+   dep_tristate '  Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI
    dep_tristate '    Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
-   dep_tristate '  Zoran ZR36120/36125 support' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI
+   dep_tristate '  Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI
 fi
 
 endmenu
index 9bd359d829a099a9534acc162694bbfbb3f485f7..623ac990835b45ef2d2c1d6aeb1682893ad4c68b 100644 (file)
@@ -74,6 +74,7 @@ MODULE_PARM(card,"1-4i");
 MODULE_PARM(pll,"1-4i");
 MODULE_PARM(bigendian,"i");
 MODULE_PARM(fieldnr,"i");
+MODULE_PARM(autoload,"i");
 
 #if defined(__sparc__) || defined(__powerpc__)
 static unsigned int bigendian=1;
@@ -86,6 +87,7 @@ static unsigned int radio[BTTV_MAX];
 static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 };
 static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0};
 static unsigned int fieldnr = 0;
+static unsigned int autoload = 1;
 
 
 #define I2C_TIMING (0x7<<4)
@@ -389,16 +391,24 @@ static int init_bttv_i2c(struct bttv *btv)
 }
 
 /* read I2C */
-static int I2CRead(struct bttv *btv, unsigned char addr) 
+static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for
 {
         unsigned char buffer = 0;
 
+       if (NULL != probe_for)
+               printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
+                      btv->nr,probe_for,addr);
         btv->i2c_client.addr = addr >> 1;
         if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
-               printk("bttv%d: i2c read 0x%x: error\n",btv->nr,addr);
+               if (NULL != probe_for)
+                       printk("not found\n");
+               else
+                       printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
+                              btv->nr,addr);
                 return -1;
        }
-       printk("bttv%d: i2c read 0x%x: %d\n",btv->nr,addr,buffer);
+       if (NULL != probe_for)
+               printk("found\n");
         return buffer;
 }
 
@@ -529,31 +539,31 @@ static void init_PXC200(struct bttv *btv)
        printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
        
        tmp=I2CWrite(btv,0x1E,0x08,0,1);
-       printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x09,0,1);
-       printk(KERN_INFO "I2C Write(0x09) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x09) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x0a,0,1);
-       printk(KERN_INFO "I2C Write(0x0a) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x0a) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x0b,0,1);
-       printk(KERN_INFO "I2C Write(0x0b) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x0b) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x0c,0,1);
-       printk(KERN_INFO "I2C Write(0x0c) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x0c) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x0d,0,1);
-       printk(KERN_INFO "I2C Write(0x0d) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x0d) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x01,0,1);
-       printk(KERN_INFO "I2C Write(0x01) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x01) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x02,0,1);
-       printk(KERN_INFO "I2C Write(0x02) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x02) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x03,0,1);
-       printk(KERN_INFO "I2C Write(0x03) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x03) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x04,0,1);
-       printk(KERN_INFO "I2C Write(0x04) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x04) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x05,0,1);
-       printk(KERN_INFO "I2C Write(0x05) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x05) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x06,0,1);
-       printk(KERN_INFO "I2C Write(0x06) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x06) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        tmp=I2CWrite(btv,0x1E,0x00,0,1);
-       printk(KERN_INFO "I2C Write(0x00) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+       printk(KERN_INFO "I2C Write(0x00) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
        
        printk(KERN_INFO "PXC200 Initialised.\n");
 }
@@ -628,7 +638,7 @@ static struct tvcard tvcards[] =
          3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
          1,1,1,1,0 },
         { "AVerMedia TVCapture 98",
-         3, 1, 4, 0, 15, { 2, 3, 1, 0, 0}, { 13, 14, 11, 7, 0, 0},0,
+         3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
          1,1,1,1,0 },
         { "Aimslab VHX",
           3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
@@ -702,12 +712,15 @@ static struct tvcard tvcards[] =
         { "Askey/Typhoon/Anubis Magic TView",
          3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
          1,1,1,1,0 },
+       { "Terratec TerraTValue",
+          3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
+         1,1,1,1,0 },
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
 
 /* ----------------------------------------------------------------------- */
 
-static void audio(struct bttv *btv, int mode)
+static void audio(struct bttv *btv, int mode, int no_irq_context)
 {
        btaor(tvcards[btv->type].gpiomask, ~tvcards[btv->type].gpiomask,
               BT848_GPIO_OUT_EN);
@@ -739,7 +752,8 @@ static void audio(struct bttv *btv, int mode)
                mode = AUDIO_RADIO;
        btaor(tvcards[btv->type].audiomux[mode],
               ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
-       call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));
+       if (no_irq_context)
+               call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));
 }
 
 
@@ -882,7 +896,7 @@ static void bt848_muxsel(struct bttv *btv, unsigned int input)
        }
        btaor((tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM);
        audio(btv, (input!=tvcards[btv->type].tuner) ? 
-              AUDIO_EXTERN : AUDIO_TUNER);
+              AUDIO_EXTERN : AUDIO_TUNER, 1);
        btaor(tvcards[btv->type].muxsel[input]>>4,
                ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
 }
@@ -1418,7 +1432,7 @@ static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc,
 
 
 static void bt848_set_geo(struct bttv *btv, u16 width, u16 height,
-                         u16 fmt, int pllset)
+                         u16 fmt, int no_irq_context)
 {
         u16 vscale, hscale;
        u32 xsf, sr;
@@ -1447,7 +1461,7 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height,
        btwrite(1, BT848_VBI_PACK_DEL);
 
         btv->pll.pll_ofreq = tvn->Fsc;
-       if (pllset)
+       if (no_irq_context)
                set_pll(btv);
 
        btwrite(fmt, BT848_COLOR_FMT);
@@ -1834,7 +1848,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
        struct bttv *btv=(struct bttv *)dev;
        int i;
-       
+
        switch (cmd) {
        case VIDIOCGCAP:
        {
@@ -2230,7 +2244,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        return -EFAULT;
                down(&btv->lock);
                if(v.flags&VIDEO_AUDIO_MUTE)
-                       audio(btv, AUDIO_MUTE);
+                       audio(btv, AUDIO_MUTE, 1);
                /* One audio source per tuner -- huh? <GA> */
                if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) {
                        up(&btv->lock);
@@ -2238,9 +2252,11 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                }
                /* bt848_muxsel(btv,v.audio); */
                if(!(v.flags&VIDEO_AUDIO_MUTE))
-                       audio(btv, AUDIO_UNMUTE);
+                       audio(btv, AUDIO_UNMUTE, 1);
 
+               up(&btv->lock);
                call_i2c_clients(btv,cmd,&v);
+               down(&btv->lock);
                
                if (btv->type == BTTV_TERRATV) {
                        unsigned int con = 0;
@@ -2844,14 +2860,14 @@ static void idcard(int i)
           */
        if (btv->type == BTTV_UNKNOWN) 
        {
-               if (I2CRead(btv, I2C_HAUPEE)>=0)
+               if (I2CRead(btv, I2C_HAUPEE, "eeprom")>=0)
                {
                        if(btv->id>849)
                                btv->type=BTTV_HAUPPAUGE878;
                        else
                                btv->type=BTTV_HAUPPAUGE;
 
-               } else if (I2CRead(btv, I2C_STBEE)>=0) {
+               } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) {
                        btv->type=BTTV_STB;
 
 #if 0  /* bad idea: 0xc0 is used for the tuner on _many_ boards */
@@ -2860,7 +2876,7 @@ static void idcard(int i)
 #endif
 
                } else {
-                       if (I2CRead(btv, 0x80)>=0) /* check for msp34xx */
+                       if (I2CRead(btv, 0x80, "msp3400")>=0) /* check for msp34xx */
                                btv->type = BTTV_MIROPRO;
                        else
                                btv->type = BTTV_MIRO;
@@ -2911,43 +2927,43 @@ static void idcard(int i)
 
        /* try to detect audio/fader chips */
        if (tvcards[btv->type].msp34xx &&
-           I2CRead(btv, I2C_MSP3400) >=0) {
-                printk(KERN_INFO "bttv%d: audio chip: MSP34xx\n",i);
-               request_module("msp3400");
+           I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
+               if (autoload)
+                       request_module("msp3400");
        }
 
        if (tvcards[btv->type].tda8425 &&
-           I2CRead(btv, I2C_TDA8425) >=0) {
-                printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",i);
-               request_module("tda8425");
+           I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) {
+               if (autoload)
+                       request_module("tda8425");
         }
 
        if (tvcards[btv->type].tda9840 &&
-           I2CRead(btv, I2C_TDA9840) >=0) {
+           I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) {
                init_tda9840(btv);
-               printk(KERN_INFO "bttv%d: audio chip: TDA9840\n", i);
                 btv->audio_chip = TDA9840;
                /* move this to a module too? */
                init_tda9840(btv);
        }
 
        if (tvcards[btv->type].tda985x &&
-           I2CRead(btv, I2C_TDA9850) >=0) {
-                printk(KERN_INFO "bttv%d: audio chip: TDA985x\n",i);
-               request_module("tda9855");
+           I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) {
+               if (autoload)
+                       request_module("tda9855");
        }
 
        if (tvcards[btv->type].tea63xx &&
-           I2CRead(btv, I2C_TEA6300)) {
-               printk(KERN_INFO "bttv%d: fader chip: TEA63xx\n",i);
-               request_module("tea6300");
+           I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0) {
+               if (autoload)
+                       request_module("tea6300");
        }
 
        if (tvcards[btv->type].tuner != -1) {
-               request_module("tuner");
+               if (autoload)
+                       request_module("tuner");
        }
 
-       audio(btv, AUDIO_MUTE);
+       audio(btv, AUDIO_MUTE, 1);
 }
 
 
@@ -3303,13 +3319,14 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                if (astat&BT848_INT_HLOCK) 
                {
                        if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
-                               audio(btv, AUDIO_ON);
+                               audio(btv, AUDIO_ON,0);
                        else
-                               audio(btv, AUDIO_OFF);
+                               audio(btv, AUDIO_OFF,0);
                }
     
                if (astat&BT848_INT_I2CDONE) 
                {
+                       IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr));
                }
     
                count++;
index 36f0ba24fe152ae5f4ac749db71c350ce0a76a0d..b4b0caaa0b3748542545d8765471cef73fbdb07d 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef _BTTV_H_
 #define _BTTV_H_
 
-#define BTTV_VERSION_CODE 0x00070a
+#define BTTV_VERSION_CODE 0x00070b
 
 #include <linux/types.h>
 #include <linux/wait.h>
index 18db5942da27d249615f9d1ee6e891149bc6ec5f..4c4e44621722ee60f0bd865c24ee4630d7547245 100644 (file)
@@ -3166,8 +3166,6 @@ static int zr36057_init(int i)
                        mdelay(10);
                        zr36060_reset(zr);
                        mdelay(10);
-                       zr36060_sleep(zr, 1);
-                       mdelay(10);
        
                        /* display codec revision */
                        if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
@@ -3204,8 +3202,6 @@ static int zr36057_init(int i)
                        udelay(3000);
                        zr36060_reset(zr);
                        udelay(3000);
-                       zr36060_sleep(zr, 1);
-                       udelay(3000);
 
                        /* display codec revision */
                        if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
@@ -3213,8 +3209,8 @@ static int zr36057_init(int i)
                               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;
+                               kfree((void *) zr->stat_com);
+                               return -1;
                        }
                        break;
        }
index b05ba9ff56426a3312884c9419f8e250fe620afe..b2dd14b0fb2b85b81232aea9b4422b26fbe227d7 100644 (file)
@@ -61,6 +61,9 @@ extern void adbdev_init(void);
 #ifdef CONFIG_USB
 extern void usb_init(void);
 #endif
+#ifdef CONFIG_PHONE
+extern void telephony_init(void);
+#endif
      
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
                            const char * buf, size_t count, loff_t *ppos)
@@ -624,6 +627,9 @@ int __init chr_dev_init(void)
 #ifdef CONFIG_USB
        usb_init();
 #endif
+#ifdef CONFIG_I2C
+        i2c_init_all();
+#endif
 #if defined (CONFIG_FB)
        fbmem_init();
 #endif
@@ -669,10 +675,6 @@ int __init chr_dev_init(void)
 #ifdef CONFIG_FTAPE
        ftape_init();
 #endif
-#ifdef CONFIG_I2C
-       i2c_init_all();
-#endif
-
 #ifdef CONFIG_VIDEO_BT848
        i2c_init();
 #endif
@@ -682,5 +684,8 @@ int __init chr_dev_init(void)
 #ifdef CONFIG_VIDEO_DEV
        videodev_init();
 #endif
+#ifdef CONFIG_PHONE
+       telephony_init();
+#endif 
        return 0;
 }
index f5e9c9d8d32bc62e23eb9922b7c043108b65e0ce..6146b84b9af56998141ab52b81e9d70800697334 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/videodev.h>
 #include "linux/video_decoder.h"
 
-#define DEBUG(x...)    x               /* remove when no long debugging */
+#define DEBUG(x...)                    /* remove when no long debugging */
 
 #define SAA7110_MAX_INPUT      9       /* 6 CVBS, 3 SVHS */
 #define SAA7110_MAX_OUTPUT     0       /* its a decoder only */
@@ -224,7 +224,7 @@ static      const unsigned char initseq[] = {
        else {
                saa7110_write(decoder,0x21,0x16);
                saa7110_write(decoder,0x0D,0x04);
-               printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder));
+               DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder)));
                saa7110_write(decoder,0x0D,0x06);
        }
 
index 8e37ed304ca76adc0e237d89c26971c599f6d4a4..1eeeca3524195be5e612b857a8faed7baf0464b7 100644 (file)
@@ -70,7 +70,6 @@ struct saa7111 {
 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);
@@ -85,9 +84,8 @@ static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned ch
 
 static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len)
 {
-       int ack;
+       int ack = 0;
        unsigned subaddr;
-       unsigned long flags;
 
        while (len > 1) {
                LOCK_I2C_BUS(dev->bus);
@@ -110,7 +108,6 @@ static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, u
 static int saa7111_read(struct saa7111 *dev, unsigned char subaddr)
 {
        int data;
-       unsigned long flags;
 
        LOCK_I2C_BUS(dev->bus);
        i2c_start(dev->bus);
index ecedb213efc2f77aad87265b6ff2ae6aefcbfba6..c30e6353b6c2cf4acf154415430de17cafb01e94 100644 (file)
@@ -69,7 +69,6 @@ struct saa7185 {
 static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data)
 {
        int ack;
-       unsigned long flags;
 
        LOCK_I2C_BUS(dev->bus);
 
@@ -85,9 +84,8 @@ static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned ch
 
 static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len)
 {
-       int ack;
+       int ack = 0;
        unsigned subaddr;
-       unsigned long flags;
 
        while (len > 1) {
                LOCK_I2C_BUS(dev->bus);
index 85bd6e8de0ac0fb4b6aacbe968dbd619a745d948..ed676087f485b613392d9cdb52e9529c6300bdaf 100644 (file)
@@ -415,7 +415,7 @@ static int tda9855_command(struct i2c_client *client,
 
 static struct i2c_driver driver = {
         "i2c tda9855 driver",
-        I2C_DRIVERID_TDA9855, /* FIXME */
+        I2C_DRIVERID_TDA9855,
         I2C_DF_NOTIFY,
        tda9855_probe,
         tda9855_detach,
index 58669583bf6be563f9c2f0d3828b0c3da1ac8ba3..5449ae0a52fea49580d22be47e4593117a5b9763 100644 (file)
@@ -88,7 +88,7 @@ static struct i2c_client client_template;
 static int tea6300_write(struct i2c_client *client, int addr, int val)
 {
        unsigned char buffer[2];
-       
+
        buffer[0] = addr;
        buffer[1] = val;
        if (2 != i2c_master_send(client,buffer,2)) {
@@ -303,7 +303,7 @@ tea6300_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static struct i2c_driver driver = {
         "i2c tea6300 driver",
-        I2C_DRIVERID_TEA6300,  /* FIXME */
+        I2C_DRIVERID_TEA6300,
         I2C_DF_NOTIFY,
        tea6300_probe,
         tea6300_detach,
index fa097ea9788d0e03a46e663bf5e6a51c3b867fec..99dc750ee629aa5de7fc937594de9a4c07006e31 100644 (file)
@@ -29,12 +29,16 @@ static struct i2c_client_address_data addr_data = {
 };
 
 static int debug =  0; /* insmod parameter */
-static int type = -1;  /* insmod parameter */
+static int type  = -1; /* insmod parameter */
+
+static int addr  =  0;
+static int this_adap;
 
 #define dprintk     if (debug) printk
 
 MODULE_PARM(debug,"i");
 MODULE_PARM(type,"i");
+MODULE_PARM(addr,"i");
 
 struct tuner
 {
@@ -164,9 +168,9 @@ static void set_tv_freq(struct i2c_client *c, int freq)
        else
                config = tun->UHF;
 
-#if 0   // Fix colorstandard mode change
+#if 1   // Fix colorstandard mode change
        if (t->type == TUNER_PHILIPS_SECAM 
-               && t->std == V4L2_STANDARD_DDD )
+           /*&& t->std == V4L2_STANDARD_DDD*/ )
                config |= tun->mode;
        else
                config &= ~tun->mode;
@@ -255,6 +259,10 @@ static int tuner_attach(struct i2c_adapter *adap, int addr,
        struct tuner *t;
        struct i2c_client *client;
 
+       if (this_adap > 0)
+               return -1;
+       this_adap++;
+       
         client_template.adapter = adap;
         client_template.addr = addr;
 
@@ -283,6 +291,11 @@ static int tuner_attach(struct i2c_adapter *adap, int addr,
 
 static int tuner_probe(struct i2c_adapter *adap)
 {
+       if (0 != addr) {
+               normal_i2c_range[0] = addr;
+               normal_i2c_range[1] = addr;
+       }
+       this_adap = 0;
        if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
                return i2c_probe(adap, &addr_data, tuner_attach);
        return 0;
index ab41407bf7605793dcbe4fe3461dfb65787d5fc5..05f2eeeeaeadc5ff3988cfcb81d0b7b6f27a009d 100644 (file)
@@ -54,9 +54,6 @@ extern int init_planbs(struct video_init *);
 #ifdef CONFIG_VIDEO_ZORAN
 extern int init_zoran_cards(struct video_init *);
 #endif
-#ifdef CONFIG_VIDEO_ZR36120
-extern int init_zr36120_cards(struct video_init *);
-#endif
 
 static struct video_init video_init_list[]={
 #ifdef CONFIG_VIDEO_BT848
@@ -74,9 +71,6 @@ static struct video_init video_init_list[]={
 #endif
 #ifdef CONFIG_VIDEO_ZORAN
        {"zoran", init_zoran_cards},
-#endif 
-#ifdef CONFIG_VIDEO_ZR36120
-       {"zr36120", init_zr36120_cards},
 #endif 
        {"end", NULL}
 };
index aea50c955eb6efac1c29b310f18f03c9786f5717..692824133cb4e6c5d7bba13a1fcbd5bfebc89a69 100644 (file)
@@ -18,9 +18,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
+#include <linux/video_decoder.h>
 #include <asm/segment.h>
 
 #include <linux/version.h>
 #include <asm/uaccess.h>
 
-#include "linux/video_decoder.h"
 #include "tuner.h"
 #include "zr36120.h"
 #include "zr36120_mem.h"
 
+/* mark an required function argument unused - lintism */
+#define        UNUSED(x)       (void)(x)
+
 /* sensible default */
 #ifndef CARDTYPE
 #define CARDTYPE 0
@@ -52,9 +55,7 @@
 /* Anybody who uses more than four? */
 #define ZORAN_MAX 4
 
-static ulong irq1 = 0;
-
-       unsigned int triton1=0;                 /* triton1 chipset? */
+static unsigned int triton1=0;                 /* triton1 chipset? */
 static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE };
 
 MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>");
@@ -99,15 +100,21 @@ static struct tvcard tvcards[] = {
 #undef F
 #define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0]))
 
-static struct { const char name[8]; int mode; int bpp; } palette2fmt[] = {
+#ifdef __sparc__
+#define        ENDIANESS       0
+#else
+#define        ENDIANESS       ZORAN_VFEC_LE
+#endif
+
+static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = {
 /* n/a     */  { "n/a",     0, 0 },
 /* GREY    */  { "GRAY",    0, 0 },
 /* HI240   */  { "HI240",   0, 0 },
-/* RGB565  */  { "RGB565",  ZORAN_VFEC_RGB_RGB565|ZORAN_VFEC_LE, 2 },
-/* RGB24   */  { "RGB24",   ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24, 3 },
-/* RGB32   */  { "RGB32",   ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE, 4 },
-/* RGB555  */  { "RGB555",  ZORAN_VFEC_RGB_RGB555|ZORAN_VFEC_LE, 2 },
-/* YUV422  */  { "YUV422",  ZORAN_VFEC_RGB_YUV422|ZORAN_VFEC_LE, 3 },
+/* RGB565  */  { "RGB565",  ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 },
+/* RGB24   */  { "RGB24",   ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 },
+/* RGB32   */  { "RGB32",   ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 },
+/* RGB555  */  { "RGB555",  ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 },
+/* YUV422  */  { "YUV422",  ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 },
 /* YUYV    */  { "YUYV",    0, 0 },
 /* UYVY    */  { "UYVY",    0, 0 },
 /* YUV420  */  { "YUV420",  0, 0 },
@@ -116,23 +123,24 @@ static struct { const char name[8]; int mode; int bpp; } palette2fmt[] = {
 /* YUV422P */  { "YUV422P", 0, 0 },
 /* YUV411P */  { "YUV411P", 0, 0 }};
 #define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0]))
+#undef ENDIANESS
 
 /* ----------------------------------------------------------------------- */
-/* ZORAN chipset detector                                                 */
-/* shamelessly stolen from bttv.c                                         */
+/* ZORAN chipset detector                                                 */
+/* shamelessly stolen from bttv.c                                         */
 /* Reason for beeing here: we need to detect if we are running on a        */
 /* Triton based chipset, and if so, enable a certain bit                   */
 /* ----------------------------------------------------------------------- */
-
-void handle_chipset(void)
+static
+void __init handle_chipset(void)
 {
        struct pci_dev *dev = NULL;
-  
+
        /* Just in case some nut set this to something dangerous */
        if (triton1)
                triton1 = ZORAN_VDC_TRICOM;
-       
-       while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) 
+
+       while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev)))
        {
                printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n");
                triton1 = ZORAN_VDC_TRICOM;
@@ -148,15 +156,15 @@ static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i);
 static
 void zoran_dump(struct zoran *ztv)
 {
-       char    str[1024];
+       char    str[256];
        char    *p=str; /* shut up, gcc! */
        int     i;
 
        for (i=0; i<0x60; i+=4) {
                if ((i % 16) == 0) {
-                       if (i) printk(/*KERN_DEBUG*/ "%s\n",str);
+                       if (i) printk("%s\n",str);
                        p = str;
-                       p+= sprintf(str, "       %04x: ",i);
+                       p+= sprintf(str, KERN_DEBUG "       %04x: ",i);
                }
                p += sprintf(p, "%08x ",zrread(i));
        }
@@ -165,114 +173,110 @@ void zoran_dump(struct zoran *ztv)
 static
 void reap_states(struct zoran* ztv)
 {
-       irq1++;         /* debugging... */
+       /* count frames */
+       ztv->fieldnr++;
 
        /*
-        * GRABBING?
+        * Are we busy at all?
+        * This depends on if there is a workqueue AND the
+        * videotransfer is enabled on the chip...
         */
-       if ( test_bit(STATE_GRAB, &ztv->state) ) {
-               int i;
+       if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN))
+       {
+               struct vidinfo* newitem;
+
+               /* did we get a complete frame? */
+               if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
+                       return;
 
-               /* are we already grabbing? */
-               if (test_bit(STATE_GRAB, &ztv->prevstate)) {
+DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue));
 
-                       /* did we get a complete grab? */
-                       if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
-                               goto out;
+               /* we are done with this buffer, tell everyone */
+               ztv->workqueue->status = FBUFFER_DONE;
+               ztv->workqueue->fieldnr = ztv->fieldnr;
+               /* not good, here for BTTV_FIELDNR reasons */
+               ztv->lastfieldnr = ztv->fieldnr;
 
-                       /* we are done with this buffer, tell everyone */
-                       ztv->grabinfo[ztv->lastframe].status = FBUFFER_DONE;
+               switch (ztv->workqueue->kindof) {
+                case FBUFFER_GRAB:
                        wake_up_interruptible(&ztv->grabq);
+                       break;
+                case FBUFFER_VBI:
+                       wake_up_interruptible(&ztv->vbiq);
+                       break;
+                default:
+                       printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof);
                }
 
-               /* locate a new frame to grab */
-               for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
-                       if (ztv->grabinfo[i].status == FBUFFER_GRABBING) {
-
-                               /* there is a buffer more to be grabbed... */
-                               ztv->lastframe = i;
-
-DEBUG(printk(KERN_DEBUG "irq(%ld): starting grab(%d)\n",irq1,i));
-
-                               /* loadup the frame settings */
-                               read_lock(&ztv->lock);
-                               zoran_set_geo(ztv,&ztv->grabinfo[i]);
-                               read_unlock(&ztv->lock);
-
-                               zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
-                               zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
-                               zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
-                               zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
-
-                               /* start single-shot grab */
-                               zror(ZORAN_VSTR_GRAB, ZORAN_VSTR);
-                               goto out;
-                       }
-
-DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to grab\n",irq1));
-
-               /* turn grabbing off the next time around */
-               clear_bit(STATE_GRAB, &ztv->state);
-
-               /* force re-init of Read or Overlay settings */
-               clear_bit(STATE_READ, &ztv->prevstate);
-               clear_bit(STATE_OVERLAY, &ztv->prevstate);
+               /* item completed, skip to next item in queue */
+               write_lock(&ztv->lock);
+               newitem = ztv->workqueue->next;
+               ztv->workqueue->next = 0;       /* mark completed */
+               ztv->workqueue = newitem;
+               write_unlock(&ztv->lock);
        }
 
        /*
-        * READING?
+        * ok, so it seems we have nothing in progress right now.
+        * Lets see if we can find some work.
         */
-       if ( test_bit(STATE_READ, &ztv->state) ) {
-               /* are we already reading? */
-               if (!test_bit(STATE_READ, &ztv->prevstate)) {
+       if (ztv->workqueue)
+       {
+               struct vidinfo* newitem;
+again:
 
-DEBUG(printk(KERN_DEBUG "irq(%ld): starting read\n",irq1));
+DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue));
 
-                       read_lock(&ztv->lock);
-                       zoran_set_geo(ztv,&ztv->readinfo);
-                       read_unlock(&ztv->lock);
+               /* loadup the frame settings */
+               read_lock(&ztv->lock);
+               zoran_set_geo(ztv,ztv->workqueue);
+               read_unlock(&ztv->lock);
 
-                       zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
+               switch (ztv->workqueue->kindof) {
+                case FBUFFER_GRAB:
+                case FBUFFER_VBI:
                        zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
                        zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
                        zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
 
                        /* start single-shot grab */
                        zror(ZORAN_VSTR_GRAB, ZORAN_VSTR);
-                       goto out;
+                       break;
+                default:
+                       printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof);
+                       write_lock(&ztv->lock);
+                       newitem = ztv->workqueue->next;
+                       ztv->workqueue->next = 0;
+                       ztv->workqueue = newitem;
+                       write_unlock(&ztv->lock);
+                       if (newitem)
+                               goto again;     /* yeah, sure.. */
                }
-
-               /* did we get a complete grab? */
-               if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
-                       goto out;
-
-DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to read\n",irq1));
-
-               /* turn reading off the next time around */
-               clear_bit(STATE_READ, &ztv->state);
-               /* force re-init of Overlay settings */
-               clear_bit(STATE_OVERLAY, &ztv->prevstate);
-
-               /* we are done, tell everyone */
-               wake_up_interruptible(&ztv->readq);
+               /* bye for now */
+               return;
        }
+DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD));
 
        /*
-        * OVERLAYING?
+        * What? Even the workqueue is empty? Am i really here
+        * for nothing? Did i come all that way to... do nothing?
         */
-       if ( test_bit(STATE_OVERLAY, &ztv->state) ) {
-               /* are we already overlaying? */
-               if (!test_bit(STATE_OVERLAY, &ztv->prevstate)) {
 
-DEBUG(printk(KERN_DEBUG "irq(%ld): starting overlay\n",irq1));
+       /* do we need to overlay? */
+       if (test_bit(STATE_OVERLAY, &ztv->state))
+       {
+               /* are we already overlaying? */
+               if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) ||
+                   !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN))
+               {
+DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD));
 
                        read_lock(&ztv->lock);
                        zoran_set_geo(ztv,&ztv->overinfo);
                        read_unlock(&ztv->lock);
 
-                       zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
-                       zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
                        zror(ZORAN_OCR_OVLEN, ZORAN_OCR);
+                       zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
                        zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
                }
 
@@ -280,18 +284,43 @@ DEBUG(printk(KERN_DEBUG "irq(%ld): starting overlay\n",irq1));
                 * leave overlaying on, but turn interrupts off.
                 */
                zrand(~ZORAN_ICR_EN,ZORAN_ICR);
-               goto out;
+               return;
+       }
+
+       /* do we have any VBI idle time processing? */
+       if (test_bit(STATE_VBI, &ztv->state))
+       {
+               struct vidinfo* item;
+               struct vidinfo* lastitem;
+
+               /* protect the workqueue */
+               write_lock(&ztv->lock);
+               lastitem = ztv->workqueue;
+               if (lastitem)
+                       while (lastitem->next) lastitem = lastitem->next;
+               for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
+                       if (item->next == 0 && item->status == FBUFFER_FREE)
+                       {
+DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item));
+                               item->status = FBUFFER_BUSY;
+                               if (!lastitem)
+                                       ztv->workqueue = item;
+                               else 
+                                       lastitem->next = item;
+                               lastitem = item;
+                       }
+               write_unlock(&ztv->lock);
+               if (ztv->workqueue)
+                       goto again;     /* hey, _i_ graduated :) */
        }
 
        /*
-        * THEN WE MUST BE IDLING
+        * Then we must be realy IDLE
         */
-DEBUG(printk(KERN_DEBUG "irq(%ld): turning off\n",irq1));
+DEBUG(printk(CARD_DEBUG "turning off\n",CARD));
        /* nothing further to do, disable DMA and further IRQs */
        zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
        zrand(~ZORAN_ICR_EN,ZORAN_ICR);
-out:
-       ztv->prevstate = ztv->state;
 }
 
 static
@@ -301,6 +330,7 @@ void zoran_irq(int irq, void *dev_id, struct pt_regs * regs)
        int count = 0;
        struct zoran *ztv = (struct zoran *)dev_id;
 
+       UNUSED(irq); UNUSED(regs);
        for (;;) {
                /* get/clear interrupt status bits */
                stat=zrread(ZORAN_ISR);
@@ -308,117 +338,35 @@ void zoran_irq(int irq, void *dev_id, struct pt_regs * regs)
                if (!estat)
                        return;
                zrwrite(estat,ZORAN_ISR);
-               IDEBUG(printk(KERN_DEBUG "%s: estat %08x\n",CARD,estat));
-               IDEBUG(printk(KERN_DEBUG "%s:  stat %08x\n",CARD,stat));
+               IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat));
+               IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat));
 
                if (estat & ZORAN_ISR_CODE)
                {
-                       IDEBUG(printk(KERN_DEBUG "%s: CodReplIRQ\n",CARD));
+                       IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD));
                }
                if (estat & ZORAN_ISR_GIRQ0)
                {
-                       IDEBUG(printk(KERN_DEBUG "%s: GIRQ0\n",CARD));
+                       IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD));
                        if (!ztv->card->usegirq1)
                                reap_states(ztv);
                }
                if (estat & ZORAN_ISR_GIRQ1)
                {
-                       IDEBUG(printk(KERN_DEBUG "%s: GIRQ1\n",CARD));
+                       IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD));
                        if (ztv->card->usegirq1)
                                reap_states(ztv);
                }
 
                count++;
                if (count > 10)
-                       printk(KERN_ERR "%s: irq loop %d (%x)\n",CARD,count,estat);
+                       printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat);
                if (count > 20)
                {
                        zrwrite(0, ZORAN_ICR);
-                       printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n",CARD);
-               }
-       }
-}
-
-/*
- *      Scan for a Zoran chip, request the irq and map the io memory
- */
-static int find_zoran(void)
-{
-       unsigned char command, latency;
-       int result;
-       struct zoran *ztv;
-       struct pci_dev *dev;
-       int zoran_num=0;
-
-       if (!pcibios_present())
-       {
-               DEBUG(printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n"));
-               return 0;
-       }
-
-       for (dev = pci_devices; dev != NULL; dev = dev->next)
-       {
-               if (dev->vendor != PCI_VENDOR_ID_ZORAN)
-                       continue;
-               if (dev->device != PCI_DEVICE_ID_ZORAN_36120)
-                       continue;
-
-               /* Ok, ZR36120 found! */
-               ztv=&zorans[zoran_num];
-               ztv->dev=dev;
-               ztv->id=dev->device;
-               ztv->zoran_mem=NULL;
-
-               ztv->zoran_adr = ztv->dev->resource[0].start;
-               pci_read_config_byte(ztv->dev, PCI_CLASS_REVISION,
-                            &ztv->revision);
-               printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
-                       ztv->id, ztv->revision);
-               printk("bus: %d, devfn: %d, ",
-                       ztv->dev->bus->number, ztv->dev->devfn);
-               printk("irq: %d, ",ztv->dev->irq);
-               printk("memory: 0x%08x.\n", ztv->zoran_adr);
-
-               ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000);
-               DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem));
-
-               result = request_irq(ztv->dev->irq, zoran_irq,
-                       SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv);
-               if (result==-EINVAL)
-               {
-                       printk(KERN_ERR "zoran: Bad irq number or handler\n");
-                       return -EINVAL;
-               }
-               if (result==-EBUSY)
-               {
-                       printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",ztv->dev->irq);
-                       return result;
+                       printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD);
                }
-               if (result < 0)
-                       return result;
-
-               /* Enable bus-mastering */
-               pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
-               command|=PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY;
-               pci_write_config_byte(ztv->dev, PCI_COMMAND, command);
-               pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
-               if (!(command&PCI_COMMAND_MASTER))
-               {
-                       printk(KERN_ERR "zoran: PCI bus-mastering could not be enabled\n");
-                       return -1;
-               }
-               pci_read_config_byte(ztv->dev, PCI_LATENCY_TIMER, &latency);
-               if (!latency)
-               {
-                       latency=32;
-                       pci_write_config_byte(ztv->dev, PCI_LATENCY_TIMER, latency);
-                       DEBUG(printk(KERN_INFO "zoran: latency set to %d\n",latency));
-               }
-               zoran_num++;
        }
-       if(zoran_num)
-               printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num);
-       return zoran_num;
 }
 
 static
@@ -444,31 +392,25 @@ int zoran_muxsel(struct zoran* ztv, int channel, int norm)
 static
 void zoran_cap(struct zoran* ztv, int on)
 {
-       DEBUG(printk(KERN_DEBUG "       zoran_cap(%d) at %ld, state=%x\n",on,irq1,ztv->state));
+DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state));
 
        if (on) {
                ztv->running = 1;
-               /* 
-                * Clear the previous state flag. This way the irq
-                * handler will be forced to re-examine its current
-                * state from scratch, setting up the registers along
-                * the way.
-                */
-               clear_bit(STATE_OVERLAY, &ztv->prevstate);
+
                /*
-                * turn interrupts back on. The DMA will be enabled
+                * turn interrupts (back) on. The DMA will be enabled
                 * inside the irq handler when it detects a restart.
                 */
-               zror(ZORAN_ICR_CODE|ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1,ZORAN_ICR);
                zror(ZORAN_ICR_EN,ZORAN_ICR);
        }
        else {
-               ztv->running = 0;
                /*
-                * turn interrupts and DMA both off
+                * turn both interrupts and DMA off
                 */
                zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
                zrand(~ZORAN_ICR_EN,ZORAN_ICR);
+
+               ztv->running = 0;
        }
 }
 
@@ -488,23 +430,15 @@ void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp)
 {
        ulong*  mtop;
        int     ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */
-       int     mult = ztv->interlace;          /* double height? */
        int     i;
 
-       DEBUG(printk(KERN_DEBUG "       overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count));
-       if (ztv->overinfo.overlay == 0) {
-               zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
-               return;
-       }
-
-for (i=0; i<count; i++) {
-       struct video_clip *vp = vcp+i;
-       DEBUG(printk(KERN_DEBUG "       %d: clip(%d,%d,%d,%d)\n",
-               i,vp->x,vp->y,vp->width,vp->height));
-}
+DEBUG(printk(KERN_DEBUG "       overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count));
 
-       /* clear entire blob */
-/*     memset(ztv->overinfo.overlay, 0, 1024*1024/8); */
+       for (i=0; i<count; i++) {
+               struct video_clip *vp = vcp+i;
+               UNUSED(vp);
+DEBUG(printk(KERN_DEBUG "       %d: clip(%d,%d,%d,%d)\n", i,vp->x,vp->y,vp->width,vp->height));
+       }
 
        /*
         * activate the visible portion of the screen
@@ -535,18 +469,18 @@ for (i=0; i<count; i++) {
        /* process clipping regions */
        for (i=0; i<count; i++) {
                int h;
-               if (vcp->x < 0 || vcp->x > ztv->overinfo.w ||
+               if (vcp->x < 0 || (uint)vcp->x > ztv->overinfo.w ||
                    vcp->y < 0 || vcp->y > ztv->overinfo.h ||
-                   vcp->width < 0 || (vcp->x+vcp->width) > ztv->overinfo.w ||
+                   vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w ||
                    vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h)
                {
-                       DEBUG(printk(KERN_DEBUG "%s: illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h));
+                       DEBUG(printk(CARD_DEBUG "illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h));
                        if (vcp->x < 0) vcp->x = 0;
-                       if (vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w;
+                       if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w;
                        if (vcp->y < 0) vcp->y = 0;
                        if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h;
                        if (vcp->width < 0) vcp->width = 0;
-                       if (vcp->x+vcp->width > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x;
+                       if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x;
                        if (vcp->height < 0) vcp->height = 0;
                        if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y;
 //                     continue;
@@ -568,7 +502,7 @@ for (i=0; i<count; i++) {
        mtop = ztv->overinfo.overlay;
        zrwrite(virt_to_bus(mtop), ZORAN_MTOP);
        zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT);
-       zraor((mult*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR);
+       zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR);
 }
 
 struct tvnorm 
@@ -591,6 +525,17 @@ static struct tvnorm tvnorms[] = {
 };
 #define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
 
+/*
+ * Program the chip for a setup as described in the vidinfo struct.
+ *
+ * Side-effects: calculates vidXshift, vidInterlace,
+ * vidHeight, vidWidth which are used in a later stage
+ * to calculate the overlay mask
+ *
+ * This is an internal function, as such it does not check the
+ * validity of the struct members... Spectaculair crashes will
+ * follow /very/ quick when you're wrong and the chip right :)
+ */
 static
 void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
 {
@@ -598,9 +543,9 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
        int     stride;
        int     winWidth, winHeight;
        int     maxWidth, maxHeight, maxXOffset, maxYOffset;
-       int     filter;
+       long    vfec;
 
-       DEBUG(printk(KERN_DEBUG "       set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, vidadr=%lx, overlay=%p)\n", i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->vidadr,i->overlay));
+DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay));
 
        /*
         * make sure the DMA transfers are inhibited during our
@@ -609,10 +554,14 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
        zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
 
        maxWidth = tvnorms[ztv->norm].Wa;
-       maxHeight = tvnorms[ztv->norm].Ha;
+       maxHeight = tvnorms[ztv->norm].Ha/2;
        maxXOffset = tvnorms[ztv->norm].HStart;
        maxYOffset = tvnorms[ztv->norm].VStart;
 
+       /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */
+       vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) |
+              (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24));
+
        /*
         * Set top, bottom ptrs. Since these must be DWORD aligned,
         * possible adjust the x and the width of the window.
@@ -621,7 +570,9 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
         */
        ztv->vidXshift = 0;
        winWidth = i->w;
-       top = i->vidadr + i->x*i->bpp + i->y*i->bpl;
+       if (winWidth < 0)
+               winWidth = -winWidth;
+       top = i->busadr + i->x*i->bpp + i->y*i->bpl;
        if (top & 3) {
                ztv->vidXshift = (top & 3) / i->bpp;
                winWidth += ztv->vidXshift;
@@ -644,30 +595,30 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
         * next line is DWORD aligned too (as required by spec).
         */
        if ((winWidth*i->bpp) & 3) {
-               DEBUG(printk(KERN_DEBUG "       window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3));
+DEBUG(printk(KERN_DEBUG "       window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3));
                winWidth += (winWidth*i->bpp) & 3;
        }
 
        /* determine the DispMode and stride */
-       if (i->h <= maxHeight/2) {
-               /* single frame suffices for this height */
-               zror(ZORAN_VFEC_DISPMOD, ZORAN_VFEC);
-               ztv->interlace = 0;
-               winHeight = i->h;
-               if (winHeight < 0)      /* can happen for read's! */
-                       winHeight = -winHeight;
+       if (i->h >= 0 && i->h <= maxHeight) {
+               /* single frame grab suffices for this height. */
+               vfec |= ZORAN_VFEC_DISPMOD;
+               ztv->vidInterlace = 0;
                stride = i->bpl - (winWidth*i->bpp);
+               winHeight = i->h;
        }
        else {
                /* interleaving needed for this height */
-               zrand(~ZORAN_VFEC_DISPMOD, ZORAN_VFEC);
-               ztv->interlace = 1;
-               winHeight = i->h/2;
+               ztv->vidInterlace = 1;
                stride = i->bpl*2 - (winWidth*i->bpp);
+               winHeight = i->h/2;
        }
+       if (winHeight < 0)      /* can happen for VBI! */
+               winHeight = -winHeight;
+
        /* safety net, sometimes bpl is too short??? */
        if (stride<0) {
-               DEBUG(printk(KERN_DEBUG "%s: WARNING stride = %d\n",CARD,stride));
+DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride));
                stride = 0;
        }
 
@@ -677,86 +628,117 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
        /* remember vidWidth, vidHeight for overlay calculations */
        ztv->vidWidth = winWidth;
        ztv->vidHeight = winHeight;
-DEBUG(printk(KERN_DEBUG "       top=%08lx, bottom=%08lx, winWidth=%d, winHeight=%d, maxWidth=%d, maxHeight=%d, stride=%d\n",top,bot,winWidth,winHeight,maxWidth,maxHeight,stride));
-
-       /* determine scales and crops */
-       if (1) {
-               int Wa, X, We, HorDcm, hcrop1, hcrop2, Hstart, Hend;
-
-A:             Wa = maxWidth;
-               X = (winWidth*64+Wa-1)/Wa;
-               We = winWidth*64/X;
-               HorDcm = 64-X;
-               hcrop1 = 2*(Wa-We)/4;
-               hcrop2 = Wa-We-hcrop1;
-               Hstart = maxXOffset + hcrop1;
-               Hend = maxXOffset + Wa-1-hcrop2;
+DEBUG(printk(KERN_DEBUG "       top=%08lx, bottom=%08lx\n",top,bot));
+DEBUG(printk(KERN_DEBUG "       winWidth=%d, winHeight=%d\n",winWidth,winHeight));
+DEBUG(printk(KERN_DEBUG "       maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight));
+DEBUG(printk(KERN_DEBUG "       stride=%d\n",stride));
 
+       /*
+        * determine horizontal scales and crops
+        */
+       if (i->w < 0) {
+               int Hstart = 1;
+               int Hend = Hstart + winWidth;
+DEBUG(printk(KERN_DEBUG "       Y: scale=0, start=%d, end=%d\n", Hstart, Hend));
+               zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
+       }
+       else {
+               int Wa = maxWidth;
+               int X = (winWidth*64+Wa-1)/Wa;
+               int We = winWidth*64/X;
+               int HorDcm = 64-X;
+               int hcrop1 = 2*(Wa-We)/4;
                /*
                 * BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi> 
                 * found the solution to the color phase shift.
                 * See ChangeLog for the full explanation)
                 */
-               if (!(Hstart & 1)) {
-DEBUG(printk(KERN_DEBUG "       correcting horizontal start/end by one\n"));
-                       winWidth--;
-                       goto A;
-               }
+               int Hstart = (maxXOffset + hcrop1) | 1;
+               int Hend = Hstart + We - 1;
 
 DEBUG(printk(KERN_DEBUG "       X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend));
 
                zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
-               zraor((HorDcm<<14),~ZORAN_VFEC_HORDCM, ZORAN_VFEC);
-
-               filter = ZORAN_VFEC_HFILTER_1;
-               if (HorDcm >= 48)
-                       filter = ZORAN_VFEC_HFILTER_5; /* 5 tap filter */
-               else if (HorDcm >= 32)
-                       filter = ZORAN_VFEC_HFILTER_4; /* 4 tap filter */
-               else if (HorDcm >= 16)
-                       filter = ZORAN_VFEC_HFILTER_3; /* 3 tap filter */
-               zraor(filter, ~ZORAN_VFEC_HFILTER, ZORAN_VFEC);
+               vfec |= HorDcm<<14;
+
+               if (HorDcm<16)
+                       vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */
+               else if (HorDcm<32)
+                       vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */
+               else if (HorDcm<48)
+                       vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */
+               else    vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */
        }
-       /* when height is negative, we want to read from line 0 */
+
+       /*
+        * Determine vertical scales and crops
+        *
+        * when height is negative, we want to read starting at line 0
+        * One day someone might need access to these lines...
+        */
        if (i->h < 0) {
                int Vstart = 0;
                int Vend = Vstart + winHeight;
-               int VerDcm = 0;
-DEBUG(printk(KERN_DEBUG "       Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend));
+DEBUG(printk(KERN_DEBUG "       Y: scale=0, start=%d, end=%d\n", Vstart, Vend));
                zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
-               zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC);
        }
        else {
-               int Ha = maxHeight/2;
+               int Ha = maxHeight;
                int Y = (winHeight*64+Ha-1)/Ha;
                int He = winHeight*64/Y;
                int VerDcm = 64-Y;
                int vcrop1 = 2*(Ha-He)/4;
-               int vcrop2 = Ha-He-vcrop1;
                int Vstart = maxYOffset + vcrop1;
-               int Vend = maxYOffset + Ha-1-vcrop2;
+               int Vend = Vstart + He - 1;
 
 DEBUG(printk(KERN_DEBUG "       Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend));
                zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
-               zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC);
+               vfec |= VerDcm<<8;
        }
 
 DEBUG(printk(KERN_DEBUG "       F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name));
+
        /* setup the requested format */
-       zraor(palette2fmt[i->format].mode, ~(ZORAN_VFEC_RGB|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24), ZORAN_VFEC);
+       zrwrite(vfec, ZORAN_VFEC);
 }
 
-#if LINUX_VERSION_CODE >= 0x020100
 static
-unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait)
+void zoran_common_open(struct zoran* ztv, int flags)
 {
-       struct zoran *ztv = (struct zoran *)dev;
+       UNUSED(flags);
+
+       /* already opened? */
+       if (ztv->users++ != 0)
+               return;
 
-       poll_wait(file, &ztv->readq, wait);
+       /* unmute audio */
+       /* /what/ audio? */
 
-       return (POLLIN | POLLRDNORM);
+       ztv->state = 0;
+
+       /* setup the encoder to the initial values */
+       ztv->picture.colour=254<<7;
+       ztv->picture.brightness=128<<8;
+       ztv->picture.hue=128<<8;
+       ztv->picture.contrast=216<<7;
+       i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture);
+
+       /* default to the composite input since my camera is there */
+       zoran_muxsel(ztv, 0, VIDEO_MODE_PAL);
+}
+
+static
+void zoran_common_close(struct zoran* ztv)
+{
+       if (--ztv->users != 0)
+               return;
+
+       /* mute audio */
+       /* /what/ audio? */
+
+       /* stop the chip */
+       zoran_cap(ztv, 0);
 }
-#endif
 
 /*
  * Open a zoran card. Right now the flags are just a hack
@@ -764,60 +746,46 @@ unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table
 static int zoran_open(struct video_device *dev, int flags)
 {
        struct zoran *ztv = (struct zoran*)dev;
-       int     i;
-
-       DEBUG(printk(KERN_DEBUG "%s: open(dev,%d)\n",CARD,flags));
-
-       switch (flags) {
-        case 0:
-               /* already active? */
-               if (ztv->user)
-                       return -EBUSY;
-               ztv->user++;
-
-               /* unmute audio */
-               /* /what/ audio? */
-
-/******************************************
- We really should be doing lazy allocing...
- ******************************************/
-               /* allocate a frame buffer */
-               if (!ztv->fbuffer)
-                       ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE);
-               if (!ztv->fbuffer) {
-                       /* could not get a buffer, bail out */
-                       ztv->user--;
-                       return -ENOBUFS;
-               }
-               /* at this time we _always_ have a framebuffer */
-               memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE);
-
-               if (!ztv->overinfo.overlay)
-                       ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL);
-               if (!ztv->overinfo.overlay) {
-                       /* could not get an overlay buffer, bail out */
-                       ztv->user--;
-                       bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
-                       return -ENOBUFS;
-               }
-               /* at this time we _always_ have a overlay */
+       struct vidinfo* item;
+       char* pos;
+
+       DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags));
+
+       /*********************************************
+        * We really should be doing lazy allocing...
+        *********************************************/
+       /* allocate a frame buffer */
+       if (!ztv->fbuffer)
+               ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE);
+       if (!ztv->fbuffer) {
+               /* could not get a buffer, bail out */
+               return -ENOBUFS;
+       }
+       /* at this time we _always_ have a framebuffer */
+       memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE);
+
+       if (!ztv->overinfo.overlay)
+               ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL);
+       if (!ztv->overinfo.overlay) {
+               /* could not get an overlay buffer, bail out */
+               bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
+               return -ENOBUFS;
+       }
+       /* at this time we _always_ have a overlay */
 
-               /* clear buffer status */
-               for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
-                       ztv->grabinfo[i].status = FBUFFER_UNUSED;
-               ztv->state = 0;
-               ztv->prevstate = 0;
-               ztv->lastframe = -1;
+       /* clear buffer status, and give them a DMAable address */
+       pos = ztv->fbuffer;
+       for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
+       {
+               item->status = FBUFFER_FREE;
+               item->memadr = pos;
+               item->busadr = virt_to_bus(pos);
+               pos += ZORAN_MAX_FBUFFER;
+       }
 
-               /* setup the encoder to the initial values */
-               i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture);
+       /* do the common part of all open's */
+       zoran_common_open(ztv, flags);
 
-               /* default to the compisite input since my camera is there */
-               zoran_muxsel(ztv, 0, VIDEO_MODE_PAL);
-               break;
-        case 1:
-               break;
-       }
        MOD_INC_USE_COUNT;
        return 0;
 }
@@ -827,14 +795,20 @@ void zoran_close(struct video_device* dev)
 {
        struct zoran *ztv = (struct zoran*)dev;
 
-       DEBUG(printk(KERN_DEBUG "%s: close(dev)\n",CARD));
+       DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD));
 
-       /* we are no longer active, goodbye */
-       ztv->user--;
+       /* driver specific closure */
+       clear_bit(STATE_OVERLAY, &ztv->state);
 
-       /* mute audio */
-       /* stop the chip */
-       zoran_cap(ztv, 0);
+       zoran_common_close(ztv);
+
+        /*
+         *      This is sucky but right now I can't find a good way to
+         *      be sure its safe to free the buffer. We wait 5-6 fields
+         *      which is more than sufficient to be sure.
+         */
+        current->state = TASK_UNINTERRUPTIBLE;
+        schedule_timeout(HZ/10);        /* Wait 1/10th of a second */
 
        /* free the allocated framebuffer */
        if (ztv->fbuffer)
@@ -847,46 +821,139 @@ void zoran_close(struct video_device* dev)
        MOD_DEC_USE_COUNT;
 }
 
-static
-long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock)
-{
-       DEBUG(printk(KERN_DEBUG "zoran_write\n"));
-       return -EINVAL;
-}
-
+/*
+ * This read function could be used reentrant in a SMP situation.
+ *
+ * This is made possible by the spinlock which is kept till we
+ * found and marked a buffer for our own use. The lock must
+ * be released as soon as possible to prevent lock contention.
+ */
 static
 long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
 {
        struct zoran *ztv = (struct zoran*)dev;
-       int     max;
+       unsigned long max;
+       struct vidinfo* unused = 0;
+       struct vidinfo* done = 0;
 
-       DEBUG(printk(KERN_DEBUG "zoran_read(%p,%ld,%d)\n",buf,count,nonblock));
+       DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock));
 
-       /* tell the state machine we want in too */
-       write_lock_irq(&ztv->lock);
-       ztv->readinfo.vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer));
-       set_bit(STATE_READ, &ztv->state);
-       write_unlock_irq(&ztv->lock);
-       zoran_cap(ztv, 1);
+       /* find ourself a free or completed buffer */
+       for (;;) {
+               struct vidinfo* item;
+
+               write_lock_irq(&ztv->lock);
+               for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
+               {
+                       if (!unused && item->status == FBUFFER_FREE)
+                               unused = item;
+                       if (!done && item->status == FBUFFER_DONE)
+                               done = item;
+               }
+               if (done || unused)
+                       break;
+
+               /* no more free buffers, wait for them. */
+               write_unlock_irq(&ztv->lock);
+               if (nonblock)
+                       return -EWOULDBLOCK;
+               interruptible_sleep_on(&ztv->grabq);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
 
-       /* wait for data to arrive */
-       interruptible_sleep_on(&ztv->readq);
+       /* Do we have 'ready' data? */
+       if (!done) {
+               /* no? than this will take a while... */
+               if (nonblock) {
+                       write_unlock_irq(&ztv->lock);
+                       return -EWOULDBLOCK;
+               }
+
+               /* mark the unused buffer as wanted */
+               unused->status = FBUFFER_BUSY;
+               unused->w = 320;
+               unused->h = 240;
+               unused->format = VIDEO_PALETTE_RGB24;
+               unused->bpp = palette2fmt[unused->format].bpp;
+               unused->bpl = unused->w * unused->bpp;
+               unused->next = 0;
+               { /* add to tail of queue */
+                 struct vidinfo* oldframe = ztv->workqueue;
+                 if (!oldframe) ztv->workqueue = unused;
+                 else {
+                   while (oldframe->next) oldframe = oldframe->next;
+                   oldframe->next = unused;
+                 }
+               }
+               write_unlock_irq(&ztv->lock);
 
-       /* see if a signal did it */
-       if (signal_pending(current))
-               return -ERESTARTSYS;
+               /* tell the state machine we want it filled /NOW/ */
+               zoran_cap(ztv, 1);
+
+               /* wait till this buffer gets grabbed */
+               while (unused->status == FBUFFER_BUSY) {
+                       interruptible_sleep_on(&ztv->grabq);
+                       /* see if a signal did it */
+                       if (signal_pending(current))
+                               return -EINTR;
+               }
+               done = unused;
+       }
+       else
+               write_unlock_irq(&ztv->lock);
 
-       /* give the user what he requested */
-       max = ztv->readinfo.w*ztv->readinfo.bpp - ztv->readinfo.h*ztv->readinfo.bpl;
+       /* Yes! we got data! */
+       max = done->bpl * done->h;
        if (count > max)
                count = max;
-       if (copy_to_user((void*)buf, (void*)ztv->fbuffer, count))
-               return -EFAULT;
+       if (copy_to_user((void*)buf, done->memadr, count))
+               count = -EFAULT;
+
+       /* keep the engine running */
+       done->status = FBUFFER_FREE;
+//     zoran_cap(ztv,1);
+
+       /* tell listeners this buffer became free */
+       wake_up_interruptible(&ztv->grabq);
 
        /* goodbye */
+       DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count));
        return count;
 }
 
+static
+long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock)
+{
+       struct zoran *ztv = (struct zoran *)dev;
+       UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock);
+       DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD));
+       return -EINVAL;
+}
+
+#if LINUX_VERSION_CODE >= 0x020100
+static
+unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait)
+{
+       struct zoran *ztv = (struct zoran *)dev;
+       struct vidinfo* item;
+       unsigned int mask = 0;
+
+       poll_wait(file, &ztv->grabq, wait);
+
+       for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
+               if (item->status == FBUFFER_DONE)
+               {
+                       mask |= (POLLIN | POLLRDNORM);
+                       break;
+               }
+
+       DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask));
+
+       return mask;
+}
+#endif
+
 /* append a new clipregion to the vector of video_clips */
 static
 void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h)
@@ -905,20 +972,9 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
 
        switch (cmd) {
         case VIDIOCGCAP:
-        {      /* get video capabilities */
+        {
                struct video_capability c;
-               struct video_decoder_capability dc;
-               int rv;
-               DEBUG(printk(KERN_DEBUG "%s: GetCapabilities\n",CARD));
-
-               /* fetch the capabilites of the decoder */
-               dc.flags = 0;
-               dc.inputs = -1;
-               dc.outputs = -1;
-               rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc);
-               if (rv)
-                       return rv;
-               DEBUG(printk(KERN_DEBUG "%s: capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs));
+               DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD));
 
                strcpy(c.name,ztv->video_dev.name);
                c.type = VID_TYPE_CAPTURE|
@@ -926,25 +982,30 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                         VID_TYPE_CLIPPING|
                         VID_TYPE_FRAMERAM|
                         VID_TYPE_SCALES;
-               c.channels = ztv->card->video_inputs;
-               c.audios = ztv->card->audio_inputs;
+               if (ztv->have_tuner)
+                       c.type |= VID_TYPE_TUNER;
+               if (ztv->have_decoder) {
+                       c.channels = ztv->card->video_inputs;
+                       c.audios = ztv->card->audio_inputs;
+               } else
+                       /* no decoder -> no channels */
+                       c.channels = c.audios = 0;
                c.maxwidth = 768;
                c.maxheight = 576;
                c.minwidth = 32;
                c.minheight = 32;
                if (copy_to_user(arg,&c,sizeof(c)))
                        return -EFAULT;
-               return 0;
+               break;
         }
 
         case VIDIOCGCHAN:
         {
                struct video_channel v;
                int mux;
-
                if (copy_from_user(&v, arg,sizeof(v)))
                        return -EFAULT;
-               DEBUG(printk(KERN_DEBUG "%s: GetChannel(%d)\n",CARD,v.channel));
+               DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel));
                v.flags=VIDEO_VC_AUDIO
 #ifdef VIDEO_VC_NORM
                        |VIDEO_VC_NORM
@@ -959,8 +1020,8 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
 #else
                v.norm=VIDEO_MODE_PAL;
 #endif
-               /* too many inputs? */
-               if (v.channel >= ztv->card->video_inputs)
+               /* too many inputs? no decoder -> no channels */
+               if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
                        return -EINVAL;
 
                /* now determine the name of the channel */
@@ -981,15 +1042,17 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
 
                if (copy_to_user(arg,&v,sizeof(v)))
                        return -EFAULT;
-               return 0;
+               break;
         }
         case VIDIOCSCHAN:
         {      /* set video channel */
                struct video_channel v;
                if (copy_from_user(&v, arg,sizeof(v)))
                        return -EFAULT;
-               DEBUG(printk(KERN_DEBUG "%s: SetChannel(%d,%d)\n",CARD,v.channel,v.norm));
-               if (v.channel >= ztv->card->video_inputs)
+               DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm));
+
+               /* too many inputs? no decoder -> no channels */
+               if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
                        return -EINVAL;
 
                if (v.norm != VIDEO_MODE_PAL &&
@@ -1007,9 +1070,10 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                struct video_tuner v;
                if (copy_from_user(&v, arg,sizeof(v)))
                        return -EFAULT;
+               DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner));
 
-               /* Only one tuner for now */
-               if (!ztv->have_tuner && v.tuner)
+               /* Only no or one tuner for now */
+               if (!ztv->have_tuner || v.tuner)
                        return -EINVAL;
 
                strcpy(v.name,"Television");
@@ -1021,17 +1085,17 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
 
                if (copy_to_user(arg,&v,sizeof(v)))
                        return -EFAULT;
-               return 0;
+               break;
         }
-
         case VIDIOCSTUNER:
         {
                struct video_tuner v;
                if (copy_from_user(&v, arg, sizeof(v)))
                        return -EFAULT;
+               DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode));
 
-               /* Only one tuner for now */
-               if (!ztv->have_tuner && v.tuner)
+               /* Only no or one tuner for now */
+               if (!ztv->have_tuner || v.tuner)
                        return -EINVAL;
 
                /* and it only has certain valid modes */
@@ -1047,7 +1111,7 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
         case VIDIOCGPICT:
         {
                struct video_picture p = ztv->picture;
-               DEBUG(printk(KERN_DEBUG "%s: GetPicture\n",CARD));
+               DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD));
                p.depth = ztv->depth;
                switch (p.depth) {
                 case  8: p.palette=VIDEO_PALETTE_YUV422;
@@ -1063,21 +1127,21 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                }
                if (copy_to_user(arg, &p, sizeof(p)))
                        return -EFAULT;
-               return 0;
+               break;
         }
         case VIDIOCSPICT:
         {
                struct video_picture p;
-               DEBUG(printk(KERN_DEBUG "%s: SetPicture\n",CARD));
                if (copy_from_user(&p, arg,sizeof(p)))
                        return -EFAULT;
+               DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette));
 
                /* depth must match with framebuffer */
                if (p.depth != ztv->depth)
                        return -EINVAL;
 
                /* check if palette matches this bpp */
-               if (p.palette<1 || p.palette>NRPALETTES ||
+               if (p.palette>NRPALETTES ||
                    palette2fmt[p.palette].bpp != ztv->overinfo.bpp)
                        return -EINVAL;
 
@@ -1088,13 +1152,13 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
 
                /* tell the decoder */
                i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
-               return 0;
+               break;
         }
 
         case VIDIOCGWIN:
         {
                struct video_window vw;
-               DEBUG(printk(KERN_DEBUG "%s: GetWindow\n",CARD));
+               DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD));
                read_lock(&ztv->lock);
                vw.x      = ztv->overinfo.x;
                vw.y      = ztv->overinfo.y;
@@ -1102,23 +1166,21 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                vw.height = ztv->overinfo.h;
                vw.chromakey= 0;
                vw.flags  = 0;
-               if (ztv->interlace)
+               if (ztv->vidInterlace)
                        vw.flags|=VIDEO_WINDOW_INTERLACE;
                read_unlock(&ztv->lock);
                if (copy_to_user(arg,&vw,sizeof(vw)))
                        return -EFAULT;
-               return 0;
+               break;
         }
         case VIDIOCSWIN:
         {
                struct video_window vw;
                struct video_clip *vcp;
                int on;
-
                if (copy_from_user(&vw,arg,sizeof(vw)))
                        return -EFAULT;
-
-               DEBUG(printk(KERN_DEBUG "%s: SetWindow(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount));
+               DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount));
 
                if (vw.flags)
                        return -EINVAL;
@@ -1139,6 +1201,15 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                if (on)
                        zoran_cap(ztv, 0);
 
+               /*
+                * strange, it seems xawtv sometimes calls us with 0
+                * width and/or height. Ignore these values
+                */
+               if (vw.x == 0)
+                       vw.x = ztv->overinfo.x;
+               if (vw.y == 0)
+                       vw.y = ztv->overinfo.y;
+
                /* by now we are committed to the new data... */
                write_lock_irq(&ztv->lock);
                ztv->overinfo.x = vw.x;
@@ -1150,10 +1221,6 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                /*
                 *      Impose display clips
                 */
-               if (vw.x<0)
-                       new_clip(&vw, vcp, 0, 0, -vw.x, vw.height-1);
-               if (vw.y<0)
-                       new_clip(&vw, vcp, 0, 0, vw.width-1,-vw.y);
                if (vw.x+vw.width > ztv->swidth)
                        new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1);
                if (vw.y+vw.height > ztv->sheight)
@@ -1165,36 +1232,38 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                vfree(vcp);
 
                /* if we were on, restart the video engine */
-               if (on) zoran_cap(ztv, on);
-               return 0;
+               if (on)
+                       zoran_cap(ztv, 1);
+               break;
         }
+
         case VIDIOCCAPTURE:
         {
                int v;
                get_user_ret(v,(int*)arg, -EFAULT);
-               DEBUG(printk(KERN_DEBUG "%s: Capture(%d)\n",CARD,v));
+               DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v));
 
                if (v==0) {
-                       zoran_cap(ztv, 0);
                        clear_bit(STATE_OVERLAY, &ztv->state);
+                       zoran_cap(ztv, 1);
                }
                else {
                        /* is VIDIOCSFBUF, VIDIOCSWIN done? */
-                       if (ztv->overinfo.vidadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0)
+                       if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0)
                                return -EINVAL;
 
                        set_bit(STATE_OVERLAY, &ztv->state);
                        zoran_cap(ztv, 1);
                }
-               return 0;
+               break;
         }
 
         case VIDIOCGFBUF:
         {
                struct video_buffer v;
-               DEBUG(printk(KERN_DEBUG "%s: GetFramebuffer\n",CARD));
+               DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD));
                read_lock(&ztv->lock);
-               v.base   = (void *)ztv->overinfo.vidadr;
+               v.base   = (void *)ztv->overinfo.busadr;
                v.height = ztv->sheight;
                v.width  = ztv->swidth;
                v.depth  = ztv->depth;
@@ -1202,19 +1271,21 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                read_unlock(&ztv->lock);
                if(copy_to_user(arg, &v,sizeof(v)))
                        return -EFAULT;
-               return 0;
+               break;
         }
         case VIDIOCSFBUF:
         {
                struct video_buffer v;
 #if LINUX_VERSION_CODE >= 0x020100
-                       if(!capable(CAP_SYS_ADMIN))
+                       if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN))
 #else
                        if(!suser())
 #endif
                        return -EPERM;
                if (copy_from_user(&v, arg,sizeof(v)))
                        return -EFAULT;
+               DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline));
+
                if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32)
                        return -EINVAL;
                if (v.bytesperline<1)
@@ -1222,48 +1293,50 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                if (ztv->running)
                        return -EBUSY;
                write_lock_irq(&ztv->lock);
-               ztv->overinfo.vidadr  = (unsigned long)v.base;
+               ztv->overinfo.busadr  = (ulong)v.base;
                ztv->sheight      = v.height;
                ztv->swidth       = v.width;
-               ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */
                ztv->depth        = v.depth;            /* bits per pixel */
-               ztv->overinfo.bpl = v.bytesperline;
+               ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */
+               ztv->overinfo.bpl = v.bytesperline;     /* bytes per line */
                write_unlock_irq(&ztv->lock);
+               break;
+        }
 
-               DEBUG(printk(KERN_DEBUG "%s: SetFrameBuffer(%p,%dx%d, bpp %d, bpl %d)\n",CARD,v.base, v.width,v.height, ztv->overinfo.bpp, ztv->overinfo.bpl));
-               return 0;
+        case VIDIOCKEY:
+        {
+               /* Will be handled higher up .. */
+               break;
         }
 
         case VIDIOCSYNC:
         {
                int i;
                get_user_ret(i,(int*)arg, -EFAULT);
-               DEBUG(printk(KERN_DEBUG "%s: VIDEOCSYNC(%d)\n",CARD,i));
+               DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i));
                if (i<0 || i>ZORAN_MAX_FBUFFERS)
                        return -EINVAL;
                switch (ztv->grabinfo[i].status) {
-                case FBUFFER_UNUSED:
+                case FBUFFER_FREE:
                        return -EINVAL;
-                case FBUFFER_GRABBING:
+                case FBUFFER_BUSY:
                        /* wait till this buffer gets grabbed */
-                       while (ztv->grabinfo[i].status == FBUFFER_GRABBING) {
+                       while (ztv->grabinfo[i].status == FBUFFER_BUSY) {
                                interruptible_sleep_on(&ztv->grabq);
                                /* see if a signal did it */
                                if (signal_pending(current))
-                                       return -ERESTARTSYS;
+                                       return -EINTR;
                        }
-                       /* fall through */
+                       /* don't fall through; a DONE buffer is not UNUSED */
+                       break;
                 case FBUFFER_DONE:
-                       ztv->grabinfo[i].status = FBUFFER_UNUSED;
+                       ztv->grabinfo[i].status = FBUFFER_FREE;
+                       /* tell ppl we have a spare buffer */
+                       wake_up_interruptible(&ztv->grabq);
                        break;
                }
-               return 0;
-        }
-
-        case VIDIOCKEY:
-        {
-               /* Will be handled higher up .. */
-               return 0;
+               DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i));
+               break;
         }
 
         case VIDIOCMCAPTURE:
@@ -1272,63 +1345,67 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                struct vidinfo* frame;
                if (copy_from_user(&vm,arg,sizeof(vm)))
                        return -EFAULT;
+               DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format));
                if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS ||
                    vm.width<32 || vm.width>768 ||
                    vm.height<32 || vm.height>576 ||
-                   vm.format<0 || vm.format>NRPALETTES ||
+                   vm.format>NRPALETTES ||
                    palette2fmt[vm.format].mode == 0)
                        return -EINVAL;
 
-               DEBUG(printk(KERN_DEBUG "%s: Mcapture(%d,(%d,%d),%d=%s)\n",CARD,vm.frame,vm.width,vm.height,vm.format,palette2fmt[vm.format].name));
+               /* we are allowed to take over UNUSED and DONE buffers */
                frame = &ztv->grabinfo[vm.frame];
-               if (frame->status == FBUFFER_GRABBING)
+               if (frame->status == FBUFFER_BUSY)
                        return -EBUSY;
 
                /* setup the other parameters if they are given */
                write_lock_irq(&ztv->lock);
-               if (vm.width)
-                       frame->w = vm.width;
-               if (vm.height)
-                       frame->h = vm.height;
-               if (vm.format)
-                       frame->format = vm.format;
+               frame->w = vm.width;
+               frame->h = vm.height;
+               frame->format = vm.format;
                frame->bpp = palette2fmt[frame->format].bpp;
                frame->bpl = frame->w*frame->bpp;
-               frame->vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer+vm.frame*ZORAN_MAX_FBUFFER));
-               frame->status = FBUFFER_GRABBING;
-               set_bit(STATE_GRAB, &ztv->state);
+               frame->status = FBUFFER_BUSY;
+               frame->next = 0;
+               { /* add to tail of queue */
+                 struct vidinfo* oldframe = ztv->workqueue;
+                 if (!oldframe) ztv->workqueue = frame;
+                 else {
+                   while (oldframe->next) oldframe = oldframe->next;
+                   oldframe->next = frame;
+                 }
+               }
                write_unlock_irq(&ztv->lock);
-
                zoran_cap(ztv, 1);
-               return 0;
+               break;
         }
 
         case VIDIOCGMBUF:
         {
                struct video_mbuf mb;
                int i;
-               DEBUG(printk(KERN_DEBUG "%s: GetMemoryBuffer\n",CARD));
+               DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD));
                mb.size = ZORAN_MAX_FBUFSIZE;
                mb.frames = ZORAN_MAX_FBUFFERS;
                for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
                        mb.offsets[i] = i*ZORAN_MAX_FBUFFER;
                if(copy_to_user(arg, &mb,sizeof(mb)))
                        return -EFAULT;
-               return 0;
+               break;
         }
 
         case VIDIOCGUNIT:
         {
                struct video_unit vu;
-               DEBUG(printk(KERN_DEBUG "%s: GetUnit\n",CARD));
+               DEBUG(printk(CARD_DEBUG "VIDIOCGUNIT\n",CARD));
                vu.video = ztv->video_dev.minor;
-               vu.vbi = VIDEO_NO_UNIT;
+               vu.vbi = ztv->vbi_dev.minor;
                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;
+               break;
         }
 
         case VIDIOCGFREQ:
@@ -1336,14 +1413,15 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                unsigned long v = ztv->tuner_freq;
                if (copy_to_user(arg,&v,sizeof(v)))
                        return -EFAULT;
-               return 0;
+               DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD));
+               break;
         }
-
         case VIDIOCSFREQ:
         {
                unsigned long v;
                if (copy_from_user(&v, arg, sizeof(v)))
                        return -EFAULT;
+               DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD));
 
                if (ztv->have_tuner) {
                        int fixme = v;
@@ -1351,20 +1429,25 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                                return -EAGAIN;
                }
                ztv->tuner_freq = v;
-               return 0;
+               break;
         }
 
-        case VIDIOCGAUDIO:
-        case VIDIOCSAUDIO:
-        case VIDIOCGCAPTURE:
-        case VIDIOCSCAPTURE:
-               DEBUG(printk(KERN_DEBUG "%s: unhandled video ioctl(%x)\n",CARD,cmd));
-               return -EINVAL;
+        /* Why isn't this in the API?
+         * And why doesn't it take a buffer number?
+        case BTTV_FIELDNR: 
+        {
+               unsigned long v = ztv->lastfieldnr;
+               if (copy_to_user(arg,&v,sizeof(v)))
+                       return -EFAULT;
+               DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD));
+               break;
+        }
+        */
 
         default:
-               DEBUG(printk(KERN_DEBUG "%s: bad ioctl(%x)\n",CARD,cmd));
+               return -ENOIOCTLCMD;
        }
-       return -EPERM;
+       return 0;
 }
 
 static
@@ -1374,7 +1457,7 @@ int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size)
        unsigned long start = (unsigned long)adr;
        unsigned long pos;
 
-       DEBUG(printk(KERN_DEBUG "zoran_mmap(0x%p,%ld)\n",adr,size));
+       DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size));
 
        /* sanity checks */
        if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer)
@@ -1383,11 +1466,7 @@ int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size)
        /* start mapping the whole shabang to user memory */
        pos = (unsigned long)ztv->fbuffer;
        while (size>0) {
-#ifdef CONFIG_BIGPHYS_AREA
                unsigned long page = virt_to_phys((void*)pos);
-#else
-               unsigned long page = kvirt_to_phys(pos);
-#endif
                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
                        return -EAGAIN;
                start += PAGE_SIZE;
@@ -1397,7 +1476,7 @@ int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size)
        return 0;
 }
 
-static struct video_device zoran_template=
+static struct video_device zr36120_template=
 {
        "UNSET",
        VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
@@ -1419,13 +1498,412 @@ static struct video_device zoran_template=
 };
 
 static
-int init_zoran(int card)
+int vbi_open(struct video_device *dev, int flags)
+{
+       struct zoran *ztv = (struct zoran*)dev->priv;
+       struct vidinfo* item;
+
+       DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags));
+
+       /*
+        * During VBI device open, we continiously grab VBI-like
+        * data in the vbi buffer when we have nothing to do.
+        * Only when there is an explicit request for VBI data
+        * (read call) we /force/ a read.
+        */
+
+       /* allocate buffers */
+       for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
+       {
+               item->status = FBUFFER_FREE;
+
+               /* alloc */
+               if (!item->memadr) {
+                       item->memadr = bmalloc(ZORAN_VBI_BUFSIZE);
+                       if (!item->memadr) {
+                               /* could not get a buffer, bail out */
+                               while (item != ztv->readinfo) {
+                                       item--;
+                                       bfree(item->memadr, ZORAN_VBI_BUFSIZE);
+                                       item->memadr = 0;
+                                       item->busadr = 0;
+                               }
+                               return -ENOBUFS;
+                       }
+               }
+
+               /* determine the DMAable address */
+               item->busadr = virt_to_bus(item->memadr);
+       }
+
+       /* do the common part of all open's */
+       zoran_common_open(ztv, flags);
+
+       set_bit(STATE_VBI, &ztv->state);
+       /* start read-ahead */
+       zoran_cap(ztv, 1);
+
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static
+void vbi_close(struct video_device *dev)
+{
+       struct zoran *ztv = (struct zoran*)dev->priv;
+       struct vidinfo* item;
+
+       DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD));
+
+       /* driver specific closure */
+       clear_bit(STATE_VBI, &ztv->state);
+
+       zoran_common_close(ztv);
+
+        /*
+         *      This is sucky but right now I can't find a good way to
+         *      be sure its safe to free the buffer. We wait 5-6 fields
+         *      which is more than sufficient to be sure.
+         */
+        current->state = TASK_UNINTERRUPTIBLE;
+        schedule_timeout(HZ/10);        /* Wait 1/10th of a second */
+
+       for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
+       {
+               if (item->memadr)
+                       bfree(item->memadr, ZORAN_VBI_BUFSIZE);
+               item->memadr = 0;
+       }
+
+       MOD_DEC_USE_COUNT;
+}
+
+/*
+ * This read function could be used reentrant in a SMP situation.
+ *
+ * This is made possible by the spinlock which is kept till we
+ * found and marked a buffer for our own use. The lock must
+ * be released as soon as possible to prevent lock contention.
+ */
+static
+long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
+{
+       struct zoran *ztv = (struct zoran*)dev->priv;
+       unsigned long max;
+       struct vidinfo* unused = 0;
+       struct vidinfo* done = 0;
+
+       DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock));
+
+       /* find ourself a free or completed buffer */
+       for (;;) {
+               struct vidinfo* item;
+
+               write_lock_irq(&ztv->lock);
+               for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) {
+                       if (!unused && item->status == FBUFFER_FREE)
+                               unused = item;
+                       if (!done && item->status == FBUFFER_DONE)
+                               done = item;
+               }
+               if (done || unused)
+                       break;
+
+               /* no more free buffers, wait for them. */
+               write_unlock_irq(&ztv->lock);
+               if (nonblock)
+                       return -EWOULDBLOCK;
+               interruptible_sleep_on(&ztv->vbiq);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       /* Do we have 'ready' data? */
+       if (!done) {
+               /* no? than this will take a while... */
+               if (nonblock) {
+                       write_unlock_irq(&ztv->lock);
+                       return -EWOULDBLOCK;
+               }
+               
+               /* mark the unused buffer as wanted */
+               unused->status = FBUFFER_BUSY;
+               unused->next = 0;
+               { /* add to tail of queue */
+                 struct vidinfo* oldframe = ztv->workqueue;
+                 if (!oldframe) ztv->workqueue = unused;
+                 else {
+                   while (oldframe->next) oldframe = oldframe->next;
+                   oldframe->next = unused;
+                 }
+               }
+               write_unlock_irq(&ztv->lock);
+
+               /* tell the state machine we want it filled /NOW/ */
+               zoran_cap(ztv, 1);
+
+               /* wait till this buffer gets grabbed */
+               while (unused->status == FBUFFER_BUSY) {
+                       interruptible_sleep_on(&ztv->vbiq);
+                       /* see if a signal did it */
+                       if (signal_pending(current))
+                               return -EINTR;
+               }
+               done = unused;
+       }
+       else
+               write_unlock_irq(&ztv->lock);
+
+       /* Yes! we got data! */
+       max = done->bpl * -done->h;
+       if (count > max)
+               count = max;
+
+       /* check if the user gave us enough room to write the data */
+       if (!access_ok(VERIFY_WRITE, buf, count)) {
+               count = -EFAULT;
+               goto out;
+       }
+
+       /*
+        * Now transform/strip the data from YUV to Y-only
+        * NB. Assume the Y is in the LSB of the YUV data.
+        */
+       {
+       unsigned char* optr = buf;
+       unsigned char* eptr = buf+count;
+
+       /* are we beeing accessed from an old driver? */
+       if (count == 2*19*2048) {
+               /*
+                * Extreme HACK, old VBI programs expect 2048 points
+                * of data, and we only got 864 orso. Double each 
+                * datapoint and clear the rest of the line.
+                * This way we have appear to have a
+                * sample_frequency of 29.5 Mc.
+                */
+               int x,y;
+               unsigned char* iptr = done->memadr+1;
+               for (y=done->h; optr<eptr && y<0; y++)
+               {
+                       /* copy to doubled data to userland */
+                       for (x=0; optr+1<eptr && x<-done->w; x++)
+                       {
+                               unsigned char a = iptr[x*2];
+                               *optr++ = a;
+                               *optr++ = a;
+                       }
+                       /* and clear the rest of the line */
+                       for (x*=2; optr<eptr && x<done->bpl; x++)
+                               *optr++ = 0;
+                       /* next line */
+                       iptr += done->bpl;
+               }
+       }
+       else {
+               /*
+                * Other (probably newer) programs asked
+                * us what geometry we are using, and are
+                * reading the correct size.
+                */
+               int x,y;
+               unsigned char* iptr = done->memadr+1;
+               for (y=done->h; optr<eptr && y<0; y++)
+               {
+                       /* copy to doubled data to userland */
+                       for (x=0; optr<eptr && x<-done->w; x++)
+                               *optr++ = iptr[x*2];
+                       /* and clear the rest of the line */
+                       for (;optr<eptr && x<done->bpl; x++)
+                               *optr++ = 0;
+                       /* next line */
+                       iptr += done->bpl;
+               }
+       }
+
+       /* API compliance:
+        * place the framenumber (half fieldnr) in the last long
+        */
+       ((ulong*)eptr)[-1] = done->fieldnr/2;
+       }
+
+       /* keep the engine running */
+       done->status = FBUFFER_FREE;
+       zoran_cap(ztv, 1);
+
+       /* tell listeners this buffer just became free */
+       wake_up_interruptible(&ztv->vbiq);
+
+       /* goodbye */
+out:
+       DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count));
+       return count;
+}
+
+#if LINUX_VERSION_CODE >= 0x020100
+static
+unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait)
+{
+       struct zoran *ztv = (struct zoran*)dev->priv;
+       struct vidinfo* item;
+       unsigned int mask = 0;
+
+       poll_wait(file, &ztv->vbiq, wait);
+
+       for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
+               if (item->status == FBUFFER_DONE)
+               {
+                       mask |= (POLLIN | POLLRDNORM);
+                       break;
+               }
+
+       DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask));
+
+       return mask;
+}
+#endif
+
+static
+int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+       struct zoran* ztv = (struct zoran*)dev->priv;
+
+       switch (cmd) {
+        case VIDIOCGVBIFMT:
+        {
+               struct vbi_format f;
+               DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD));
+               f.sampling_rate = 14750000UL;
+               f.samples_per_line = -ztv->readinfo[0].w;
+               f.sample_format = VIDEO_PALETTE_RAW;
+               f.start[0] = f.start[1] = ztv->readinfo[0].y;
+               f.start[1] += 312;
+               f.count[0] = f.count[1] = -ztv->readinfo[0].h;
+               f.flags = VBI_INTERLACED;
+               if (copy_to_user(arg,&f,sizeof(f)))
+                       return -EFAULT;
+               break;
+        }
+        case VIDIOCSVBIFMT:
+        {
+               struct vbi_format f;
+               int i;
+               if (copy_from_user(&f, arg,sizeof(f)))
+                       return -EFAULT;
+               DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags));
+
+               /* lots of parameters are fixed... (PAL) */
+               if (f.sampling_rate != 14750000UL ||
+                   f.samples_per_line > 864 ||
+                   f.sample_format != VIDEO_PALETTE_RAW ||
+                   f.start[0] < 0 ||
+                   f.start[0] != f.start[1]-312 ||
+                   f.count[0] != f.count[1] ||
+                   f.start[0]+f.count[0] >= 288 ||
+                   f.flags != VBI_INTERLACED)
+                       return -EINVAL;
+
+               write_lock_irq(&ztv->lock);
+               ztv->readinfo[0].y = f.start[0];
+               ztv->readinfo[0].w = -f.samples_per_line;
+               ztv->readinfo[0].h = -f.count[0];
+               ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp;
+               for (i=1; i<ZORAN_VBI_BUFFERS; i++)
+                       ztv->readinfo[i] = ztv->readinfo[i];
+               write_unlock_irq(&ztv->lock);
+               break;
+        }
+        default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static struct video_device vbi_template=
+{
+       "UNSET",
+       VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+       VID_HARDWARE_ZR36120,
+
+       vbi_open,
+       vbi_close,
+       vbi_read,
+       zoran_write,
+#if LINUX_VERSION_CODE >= 0x020100
+       vbi_poll,               /* poll */
+#endif
+       vbi_ioctl,
+       NULL,                   /* no mmap */
+       NULL,                   /* no initialize */
+       NULL,                   /* priv */
+       0,                      /* busy */
+       -1                      /* minor */
+};
+
+/*
+ *      Scan for a Zoran chip, request the irq and map the io memory
+ */
+static
+int __init find_zoran(void)
+{
+       int result;
+       struct zoran *ztv;
+       struct pci_dev *dev = NULL;
+       unsigned char revision;
+       int zoran_num=0;
+
+       if (!pcibios_present())
+       {
+               printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n");
+               return 0;
+       }
+
+       while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
+       {
+               /* Ok, a ZR36120/ZR36125 found! */
+               ztv = &zorans[zoran_num];
+               ztv->dev = dev;
+
+               pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision);
+               printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
+                       dev->device, revision);
+               printk("bus: %d, devfn: %d, irq: %d, ",
+                       dev->bus->number, dev->devfn, dev->irq);
+               printk("memory: 0x%08lx.\n", ztv->zoran_adr);
+
+               ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000);
+               DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem));
+
+               result = request_irq(dev->irq, zoran_irq,
+                       SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv);
+               if (result==-EINVAL)
+               {
+                       printk(KERN_ERR "zoran: Bad irq number or handler\n");
+                       return -EINVAL;
+               }
+               if (result==-EBUSY)
+                       printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq);
+               if (result < 0)
+                       return result;
+
+               /* Enable bus-mastering */
+               pci_set_master(dev);
+
+               zoran_num++;
+       }
+       if(zoran_num)
+               printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num);
+       return zoran_num;
+}
+
+static
+int __init init_zoran(int card)
 {
        struct zoran *ztv = &zorans[card];
        int     i;
 
        /* if the given cardtype valid? */
-       if (cardtype[card]<0 || cardtype[card]>=NRTVCARDS) {
+       if (cardtype[card]>=NRTVCARDS) {
                printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]);
                return -1;
        }
@@ -1436,19 +1914,20 @@ int init_zoran(int card)
        zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
        udelay(10);
 
-       /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
-
-       /* framegrabber details */
-       ztv->swidth=800;
-       ztv->sheight=600;
-       ztv->depth=16;
-
-       /* channel details */
-       ztv->norm=0;                            /* PAL */
-       ztv->card=tvcards+cardtype[card];       /* point to the selected card */
+       /* zoran chip specific details */
+       ztv->card = tvcards+cardtype[card];     /* point to the selected card */
+       ztv->norm = 0;                          /* PAL */
        ztv->tuner_freq = 0;
 
-       ztv->overinfo.status = FBUFFER_UNUSED;
+       /* videocard details */
+       ztv->swidth = 800;
+       ztv->sheight = 600;
+       ztv->depth = 16;
+
+       /* State details */
+       ztv->fbuffer = 0;
+       ztv->overinfo.kindof = FBUFFER_OVERLAY;
+       ztv->overinfo.status = FBUFFER_FREE;
        ztv->overinfo.x = 0;
        ztv->overinfo.y = 0;
        ztv->overinfo.w = 768; /* 640 */
@@ -1456,40 +1935,37 @@ int init_zoran(int card)
        ztv->overinfo.format = VIDEO_PALETTE_RGB565;
        ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp;
        ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth;
-       ztv->overinfo.vidadr = 0;
+       ztv->overinfo.busadr = 0;
+       ztv->overinfo.memadr = 0;
        ztv->overinfo.overlay = 0;
-
-       ztv->readinfo = ztv->overinfo;
-       ztv->readinfo.w = 768;
-       ztv->readinfo.h = -22;
-       ztv->readinfo.format = VIDEO_PALETTE_YUV422;
-       ztv->readinfo.bpp = palette2fmt[ztv->readinfo.format].bpp;
-       ztv->readinfo.bpl = ztv->readinfo.w*ztv->readinfo.bpp;
-
-       /* grabbing details */
        for (i=0; i<ZORAN_MAX_FBUFFERS; i++) {
                ztv->grabinfo[i] = ztv->overinfo;
-               ztv->grabinfo[i].format = VIDEO_PALETTE_RGB24;
+               ztv->grabinfo[i].kindof = FBUFFER_GRAB;
        }
+       init_waitqueue_head(&ztv->grabq);
+
+       /* VBI details */
+       ztv->readinfo[0] = ztv->overinfo;
+       ztv->readinfo[0].kindof = FBUFFER_VBI;
+       ztv->readinfo[0].w = -864;
+       ztv->readinfo[0].h = -38;
+       ztv->readinfo[0].format = VIDEO_PALETTE_YUV422;
+       ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp;
+       ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp;
+       for (i=1; i<ZORAN_VBI_BUFFERS; i++)
+               ztv->readinfo[i] = ztv->readinfo[0];
+       init_waitqueue_head(&ztv->vbiq);
 
        /* maintenance data */
-       ztv->fbuffer = NULL;
-       ztv->user = 0;
        ztv->have_decoder = 0;
        ztv->have_tuner = 0;
+       ztv->tuner_type = 0;
        ztv->running = 0;
-       init_waitqueue_head(&ztv->grabq);
-       init_waitqueue_head(&ztv->readq);
+       ztv->users = 0;
        ztv->lock = RW_LOCK_UNLOCKED;
-       ztv->state = 0;
-       ztv->prevstate = 0;
-       ztv->lastframe = -1;
-
-       /* picture details */
-       ztv->picture.colour=254<<7;
-       ztv->picture.brightness=128<<8;
-       ztv->picture.hue=128<<8;
-       ztv->picture.contrast=216<<7;
+       ztv->workqueue = 0;
+       ztv->fieldnr = 0;
+       ztv->lastfieldnr = 0;
 
        if (triton1)
                zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC);
@@ -1509,7 +1985,7 @@ int init_zoran(int card)
        zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI);
        /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */
        zrwrite(ztv->card->gpval<<24,ZORAN_GUEST);
-       
+
        /* clear interrupt status */
        zrwrite(~0, ZORAN_ISR);
 
@@ -1523,29 +1999,37 @@ int init_zoran(int card)
        /*
         * Now add the template and register the device unit
         */
-       ztv->video_dev = zoran_template;
+       ztv->video_dev = zr36120_template;
        strcpy(ztv->video_dev.name, ztv->i2c.name);
+       ztv->video_dev.priv = ztv;
        if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0)
                return -1;
+
+       ztv->vbi_dev = vbi_template;
+       strcpy(ztv->vbi_dev.name, ztv->i2c.name);
+       ztv->vbi_dev.priv = ztv;
+       if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI) < 0) {
+               video_unregister_device(&ztv->video_dev);
+               return -1;
+       }
        i2c_register_bus(&ztv->i2c);
 
        /* set interrupt mask - the PIN enable will be set later */
        zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR);
 
-       printk(KERN_INFO "%s: installed %s\n",CARD,ztv->card->name);
+       printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name);
        return 0;
 }
 
 static
-void release_zoran(int max)
+void __exit release_zoran(int max)
 {
-       u8 command;
        struct zoran *ztv;
        int i;
 
        for (i=0;i<max; i++) 
        {
-               ztv=&zorans[i];
+               ztv = &zorans[i];
 
                /* turn off all capturing, DMA and IRQs */
                /* reset the zoran */
@@ -1564,31 +2048,22 @@ void release_zoran(int max)
                /* unregister i2c_bus */
                i2c_unregister_bus((&ztv->i2c));
 
-               /* disable PCI bus-mastering */
-               pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
-               command&=PCI_COMMAND_MASTER;
-               pci_write_config_byte(ztv->dev, PCI_COMMAND, command);
-    
                /* unmap and free memory */
                if (ztv->zoran_mem)
                        iounmap(ztv->zoran_mem);
 
                video_unregister_device(&ztv->video_dev);
+               video_unregister_device(&ztv->vbi_dev);
        }
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+void __exit zr36120_exit(void)
 {
        release_zoran(zoran_cards);
 }
 
-int init_module(void)
+int __init zr36120_init(void)
 {
-#else
-int init_zr36120_cards(struct video_init *unused)
-{
-#endif
        int     card;
  
        handle_chipset();
@@ -1607,3 +2082,6 @@ int init_zr36120_cards(struct video_init *unused)
        }
        return 0;
 }
+
+module_init(zr36120_init);
+module_exit(zr36120_exit);
index 237c7a5f6af5361db921fa32b9cc21bbcbf070b6..e500de10dca1d0ba0776e94ff52b52a224e5aea1 100644 (file)
 extern struct i2c_bus zoran_i2c_bus_template;
 
 #define        ZORAN_MAX_FBUFFERS      2
-#define ZORAN_MAX_FBUFFER      0x0A2000
-#define ZORAN_MAX_FBUFSIZE     (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER)
+#define        ZORAN_MAX_FBUFFER       (768*576*2)
+#define        ZORAN_MAX_FBUFSIZE      (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER)
 
-/* external declarations */
-extern unsigned long zoran_alloc_memory(void);
-extern void zoran_free_memory(void);
+#define        ZORAN_VBI_BUFFERS       2
+#define        ZORAN_VBI_BUFSIZE       (22*1024*2)
 
 struct tvcard {
        char*   name;           /* name of the cardtype */
@@ -70,76 +69,84 @@ struct tvcard {
 #define        SVHS(x)         ((x)|IS_SVHS)
 
 struct vidinfo {
-       int     status;
-#define FBUFFER_UNUSED       0
-#define FBUFFER_GRABBING     1
-#define FBUFFER_DONE         2
-       int     x,y;
-       int     w,h;
-       int     bpl;
-       int     bpp;            /* should be calculated */
-       int     format;
-       ulong   vidadr;         /* physical video address */
-       ulong*  overlay;
+       struct  vidinfo* next;  /* next active buffer                   */
+       uint    kindof;
+#define        FBUFFER_OVERLAY         0
+#define        FBUFFER_GRAB            1
+#define        FBUFFER_VBI             2
+       uint    status;
+#define FBUFFER_FREE           0
+#define FBUFFER_BUSY           1
+#define FBUFFER_DONE           2
+       ulong   fieldnr;        /* # of field, not framer!              */
+       uint    x,y;
+       int     w,h;            /* w,h can be negative!                 */
+       uint    format;         /* index in palette2fmt[]               */
+       uint    bpp;            /* lookup from palette2fmt[]            */
+       uint    bpl;            /* calc: width * bpp                    */
+       ulong   busadr;         /* bus addr for DMA engine              */
+       char*   memadr;         /* kernel addr for making copies        */
+       ulong*  overlay;        /* kernel addr of overlay mask          */
 };
 
 struct zoran 
 {
        struct video_device video_dev;
-#define CARD   ztv->video_dev.name
-       struct i2c_bus  i2c;
-       struct video_picture picture;   /* Current picture params */
-       struct video_audio audio_dev;   /* Current audio params */
+#define CARD_DEBUG     KERN_DEBUG "%s(%lu): "
+#define CARD_INFO      KERN_INFO "%s(%lu): "
+#define CARD_ERR       KERN_ERR "%s(%lu): "
+#define CARD           ztv->video_dev.name,ztv->fieldnr
 
        /* zoran chip specific details */
-       struct pci_dev* dev;            /* ptr to PCI device */
-       ushort          id;             /* chip id */
-       unsigned char   revision;       /* chip revision */
-       int             zoran_adr;      /* bus address of IO memory */
-       char*           zoran_mem;      /* pointer to mapped IO memory */
+       struct i2c_bus  i2c;            /* i2c registration data        */
+       struct pci_dev* dev;            /* ptr to PCI device            */
+       ulong           zoran_adr;      /* bus address of IO memory     */
+       char*           zoran_mem;      /* kernel address of IO memory  */
+       struct tvcard*  card;           /* the cardtype                 */
+       uint            norm;           /* 0=PAL, 1=NTSC, 2=SECAM       */
+       uint            tuner_freq;     /* Current freq in kHz          */
+       struct video_picture picture;   /* Current picture params       */
   
        /* videocard details */
-       int             swidth;         /* screen width */
-       int             sheight;        /* screen height */
-       int             depth;          /* depth in bits */
-
-       /* channel details */
-       int             norm;           /* 0=PAL, 1=NTSC, 2=SECAM */
-       struct tvcard*  card;           /* the cardtype */
-       int             tuner_freq;     /* in Hz */
+       uint            swidth;         /* screen width                 */
+       uint            sheight;        /* screen height                */
+       uint            depth;          /* depth in bits                */
 
        /* State details */
-       struct vidinfo  overinfo;       /* overlay data */
-       struct vidinfo  grabinfo[ZORAN_MAX_FBUFFERS];   /* grabbing data */
-       struct vidinfo  readinfo;       /* reading data */
+       char*           fbuffer;        /* framebuffers for mmap        */
+       struct vidinfo  overinfo;       /* overlay data                 */
+       struct vidinfo  grabinfo[ZORAN_MAX_FBUFFERS];   /* grabbing data*/
+       wait_queue_head_t grabq;        /* grabbers queue               */
+
+       /* VBI details */
+       struct video_device vbi_dev;
+       struct vidinfo  readinfo[2];    /* VBI data - flip buffers      */
+       wait_queue_head_t vbiq;         /* vbi queue                    */
 
        /* maintenance data */
-       char*           fbuffer;        /* framebuffers for mmap */
-       int             user;           /* # users */
-       int             have_decoder;   /* did we detect a mux? */
-       int             have_tuner;     /* did we detect a tuner? */
-       int             tuner_type;     /* tuner type, when found */
-       int             running;
-       wait_queue_head_t grabq;        /* waiting capturers */
-       wait_queue_head_t readq;        /* waiting readers */
+       int             have_decoder;   /* did we detect a mux?         */
+       int             have_tuner;     /* did we detect a tuner?       */
+       int             users;          /* howmany video/vbi open?      */
+       int             tuner_type;     /* tuner type, when found       */
+       int             running;        /* are we rolling?              */
        rwlock_t        lock;
-       int             state;          /* what is requested of us? */
-#define STATE_READ     0
-#define STATE_GRAB     1
-#define STATE_OVERLAY  2
-       int             prevstate;
-       int             lastframe;
-
-       int             interlace;      /* calculated */
+       int             state;          /* what is requested of us?     */
+#define STATE_OVERLAY  0
+#define STATE_VBI      1
+       struct vidinfo* workqueue;      /* buffers to grab, head is active */
+       ulong           fieldnr;        /* #field, ticked every VSYNC   */
+       ulong           lastfieldnr;    /* #field, ticked every GRAB    */
+
+       int             vidInterlace;   /* calculated */
        int             vidXshift;      /* calculated */
-       int             vidWidth;       /* calculated */
-       int             vidHeight;      /* calculated */
+       uint            vidWidth;       /* calculated */
+       uint            vidHeight;      /* calculated */
 };
 
 #define zrwrite(dat,adr)    writel((dat),(char *) (ztv->zoran_mem+(adr)))
 #define zrread(adr)         readl(ztv->zoran_mem+(adr))
 
-#if !defined(PDEBUG) || (PDEBUG == 0)
+#if PDEBUG == 0
 #define zrand(dat,adr)      zrwrite((dat) & zrread(adr), adr)
 #define zror(dat,adr)       zrwrite((dat) | zrread(adr), adr)
 #define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr)
index 8eb618b14f54cf8e292809dd92e3999c56ac48f1..0de59b9f15e6e035cf0b6a1237582d027201fbba 100644 (file)
@@ -23,9 +23,9 @@
 #include <asm/io.h>
 
 #include <linux/version.h>
+#include <linux/video_decoder.h>
 #include <asm/uaccess.h>
 
-#include "linux/video_decoder.h"
 #include "tuner.h"
 #include "zr36120.h"
 
@@ -59,23 +59,38 @@ static
 void attach_inform(struct i2c_bus *bus, int id)
 {
        struct zoran *ztv = (struct zoran*)bus->data;
+       struct video_decoder_capability dc;
+       int rv;
 
        switch (id) {
         case I2C_DRIVERID_VIDEODECODER:
-               ztv->have_decoder = 1;
-               DEBUG(printk(KERN_INFO "%s: decoder attached\n",CARD));
+               DEBUG(printk(CARD_INFO "decoder attached\n",CARD));
+
+               /* fetch the capabilites of the decoder */
+               rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc);
+               if (rv) {
+                       DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD));
+                       break;
+               }
+               DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs));
+
+               /* Test if the decoder can de VBI transfers */
+               if (dc.flags & 16 /*VIDEO_DECODER_VBI*/)
+                       ztv->have_decoder = 2;
+               else
+                       ztv->have_decoder = 1;
                break;
         case I2C_DRIVERID_TUNER:
                ztv->have_tuner = 1;
-               DEBUG(printk(KERN_INFO "%s: tuner attached\n",CARD));
+               DEBUG(printk(CARD_INFO "tuner attached\n",CARD));
                if (ztv->tuner_type >= 0)
                {
                        if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0)
-                       DEBUG(printk(KERN_INFO "%s: attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type));
+                       DEBUG(printk(CARD_INFO "attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type));
                }
                break;
         default:
-               DEBUG(printk(KERN_INFO "%s: attach_inform; unknown device id=%d\n",CARD,id));
+               DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id));
                break;
        }
 }
@@ -88,14 +103,14 @@ void detach_inform(struct i2c_bus *bus, int id)
        switch (id) {
         case I2C_DRIVERID_VIDEODECODER:
                ztv->have_decoder = 0;
-               DEBUG(printk(KERN_INFO "%s: decoder detached\n",CARD));
+               DEBUG(printk(CARD_INFO "decoder detached\n",CARD));
                break;
         case I2C_DRIVERID_TUNER:
                ztv->have_tuner = 0;
-               DEBUG(printk(KERN_INFO "%s: tuner detached\n",CARD));
+               DEBUG(printk(CARD_INFO "tuner detached\n",CARD));
                break;
         default:
-               DEBUG(printk(KERN_INFO "%s: detach_inform; unknown device id=%d\n",CARD,id));
+               DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id));
                break;
        }
 }
index 0a93ab722dd09e09c0c33eb527e92fa15e6e0f35..5e81049eb064f32485c1ed6ebac9ce58150b8c2c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/wrapper.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 #ifdef CONFIG_BIGPHYS_AREA
 #include <linux/bigphysarea.h>
 #include "zr36120.h"
 #include "zr36120_mem.h"
 
-/* ----------------------------------------------------------------------- */
-/* Memory functions                                                       */
-/* shamelessly stolen and adapted from bttv.c                             */
-/* ----------------------------------------------------------------------- */
+/*******************************/
+/* Memory management functions */
+/*******************************/
 
-/*
- * convert virtual user memory address to physical address
- * (virt_to_phys only works for kmalloced kernel memory)
- */
-inline unsigned long uvirt_to_phys(unsigned long adr)
-{
-       pgd_t *pgd;
-       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;
-       /* Note; page_address will panic for us if the page is high */
-        if(pte_present(pte))
-               return page_address(pte_page(pte))|(adr&(PAGE_SIZE-1));
-       return 0;
-}
-
-/*
- * vmalloced address to physical address
- */
-inline unsigned long kvirt_to_phys(unsigned long adr)
-{
-       return uvirt_to_phys(VMALLOC_VMADDR(adr));
-}
-
-/*
- * vmalloced address to bus address
- */
-inline unsigned long kvirt_to_bus(unsigned long adr)
+inline int __get_order(unsigned long size)
 {
-       return virt_to_bus(phys_to_virt(kvirt_to_phys(adr)));
-}
-
-inline int order(unsigned long size)
-{
-       int ordr = 0;
+        int order = 0;
        size = (size+PAGE_SIZE-1)/PAGE_SIZE;
        while (size) {
                size /= 2;
-               ordr++;
+               order++;
        }
-       return ordr;
+       return order;
 }
-
+                       
 void* bmalloc(unsigned long size)
 {
        void* mem;
@@ -96,7 +56,7 @@ void* bmalloc(unsigned long size)
         * The following function got a lot of memory at boottime,
         * so we know its always there...
         */
-       mem = (void*)__get_free_pages(GFP_USER,order(size));
+       mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,__get_order(size));
 #endif
        if (mem) {
                unsigned long adr = (unsigned long)mem;
@@ -122,7 +82,7 @@ void bfree(void* mem, unsigned long size)
 #ifdef CONFIG_BIGPHYS_AREA
                bigphysarea_free_pages(mem);
 #else
-               free_pages((unsigned long)mem,order(size));
+               free_pages((unsigned long)mem,__get_order(size));
 #endif
        }
 }
index 609f0a1a9a4f95bd6acc424f887c1fdfd019609e..aad117acc91d558b5d5e1ce72ab31cadc8c7e410 100644 (file)
@@ -1,17 +1,3 @@
-extern inline unsigned long uvirt_to_phys(unsigned long adr);
-
-/* vmalloced address to physical address */
-extern inline unsigned long kvirt_to_phys(unsigned long adr)
-{ return uvirt_to_phys(VMALLOC_VMADDR(adr)); }
-
-/* vmalloced address to bus address */
-extern inline unsigned long kvirt_to_bus(unsigned long adr)
-{ return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); }
-
-/* always vmalloced memory - not always continuous! */
-void*  rvmalloc(unsigned long size);
-void   rvfree(void* mem, unsigned long size);
-
 /* either kmalloc() or bigphysarea() alloced memory - continuous */
 void*  bmalloc(unsigned long size);
 void   bfree(void* mem, unsigned long size);
index 9c8cc29c2c5eb7dce5f15be4e300cb62d825323c..32a8514ee2a06552a70ff9bc862ba35dc17bb76c 100644 (file)
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-
-/*
-static char alg_rcsid[] = "$Id: i2c-algo-bit.c,v 1.20 1999/11/12 11:26:20 frodo Exp $";
-*/
+/* $Id: i2c-algo-bit.c,v 1.21 1999/12/21 23:45:58 frodo Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
index 184295e003900e6dda253b0b8530e94989cdc426..2edf21f375479db47d41a42e684fcce93ab15377 100644 (file)
@@ -23,6 +23,8 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-algo-pcf.c,v 1.15 1999/12/21 23:45:58 frodo Exp $ */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
index c24f0d146058463a5efab20715e93634cece4b95..3d88b6c390122f76b2e78f817de088aa1af604d4 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
 /* ------------------------------------------------------------------------- */
-#define RCSID "$Id: i2c-core.c,v 1.42 1999/11/30 20:06:42 frodo Exp $"
-/* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
    All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-core.c,v 1.44 1999/12/21 23:45:58 frodo Exp $ */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -451,12 +451,23 @@ int i2c_del_driver(struct i2c_driver *driver)
        return 0;
 }
 
+int i2c_check_addr (struct i2c_adapter *adapter, int addr)
+{
+  int i;
+  for (i = 0; i < I2C_CLIENT_MAX ; i++) 
+    if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
+      return -EBUSY;
+  return 0;
+}
 
 int i2c_attach_client(struct i2c_client *client)
 {
        struct i2c_adapter *adapter = client->adapter;
        int i;
 
+        if (i2c_check_addr(client->adapter,client->addr))
+          return -EBUSY;
+
        for (i = 0; i < I2C_CLIENT_MAX; i++)
                if (NULL == adapter->clients[i])
                        break;
@@ -855,6 +866,10 @@ int i2c_probe(struct i2c_adapter *adapter,
        addr <= 0x7f;
        addr++) {
 
+    /* Skip if already in use */
+    if (i2c_check_addr(adapter,addr))
+      continue;
+
     /* If it is in one of the force entries, we don't do any detection
        at all */
     found = 0;
@@ -1311,6 +1326,7 @@ EXPORT_SYMBOL(i2c_attach_client);
 EXPORT_SYMBOL(i2c_detach_client);
 EXPORT_SYMBOL(i2c_inc_use_client);
 EXPORT_SYMBOL(i2c_dec_use_client);
+EXPORT_SYMBOL(i2c_check_addr);
 
 
 EXPORT_SYMBOL(i2c_master_send);
index d2c94dc65687db394b3674f9ca0b6c5171fa0966..088d730fce2239503ed3fed455fbb9bc7c866fbf 100644 (file)
@@ -23,6 +23,8 @@
    But I have used so much of his original code and ideas that it seems
    only fair to recognize him as co-author -- Frodo */
 
+/* $Id: i2c-dev.c,v 1.18 1999/12/21 23:45:58 frodo Exp $ */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -277,8 +279,11 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
 
   switch ( cmd ) {
     case I2C_SLAVE:
+    case I2C_SLAVE_FORCE:
       if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
         return -EINVAL;
+      if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
+        return -EBUSY;
       client->addr = arg;
       return 0;
     case I2C_TENBIT:
index 9d860c137db00516977c55aa26205d76ccc94244..fb965df0f7130fa0bf46bfa81f1de2dbd9f9a280 100644 (file)
@@ -22,6 +22,8 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-elektor.c,v 1.13 1999/12/21 23:45:58 frodo Exp $ */
+
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
index fab01ed8d8d2de51e5a436e0521baf91d92b08e3..1eb17cacf0afed0bcd9d34c4555eaad33b8b35ed 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
 /* ------------------------------------------------------------------------- 
-static char rcsid[] = "$Id: i2c-elv.c,v 1.11 1999/10/08 14:25:11 frodo Exp $";
-   ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-elv.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
index e407151e1c8f38a46857cd5a6a0da276c6eb80e8..7dabbd9a91cb923dcdb9391e5a4fe86c17eca5a0 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.          */
 /* --------------------------------------------------------------------        */
-/* $Id: i2c-pcf8584.h,v 1.1 1999/07/18 14:01:33 frodo Exp $ */
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-pcf8584.h,v 1.2 1999/12/21 23:45:58 frodo Exp $ */
+
 #ifndef I2C_PCF8584_H
 #define I2C_PCF8584_H 1
 
index 5b7a43c61ff4924c64bd4ff433fad632655b6efa..52079eb8856be94d9ce0a3a8981c0f5ba7801e60 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
 /* ------------------------------------------------------------------------- 
-static char rcsid[] = "$Id: i2c-philips-par.c,v 1.11 1999/10/08 14:25:11 frodo Exp $";
-   ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-philips-par.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */
+
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
index eb58c9eb4a56035911981433585c9765f0fab036..7a3bc3522a7e3cbf84b3a1223111905fd2ba228e 100644 (file)
@@ -17,8 +17,8 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
 /* ------------------------------------------------------------------------- 
-static char rcsid[] = "$Id: i2c-velleman.c,v 1.13 1999/10/08 14:25:11 frodo Exp $";
-  ------------------------------------------------------------------------- */
+
+/* $Id: i2c-velleman.c,v 1.14 1999/12/21 23:45:58 frodo Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/ioport.h>
index 8bd701ad798798409a4ecd3a7c8c21ef7c651894..ff3e2405f336b50e0cb789103c572eb445dd9954 100644 (file)
@@ -45,6 +45,8 @@
 // #define DRIVERDEBUG
 // #define DEBUG_IRQ
 
+#define dprintk(x)
+
 /*
  *     Size of the I2O module table
  */
@@ -53,7 +55,6 @@ 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 int i2o_init_outbound_q(struct i2o_controller *c);
@@ -61,9 +62,9 @@ static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
                           struct i2o_message *);
 static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *);
 static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *);
-static int i2o_quiesce_system(void);
-static int i2o_enable_system(void);
-static void i2o_dump_message(u32 *);
+static void i2o_dump_message(u32 *msg);
+
+static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32);
 
 static int i2o_lct_get(struct i2o_controller *);
 static int i2o_hrt_get(struct i2o_controller *);
@@ -149,8 +150,8 @@ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
                    struct i2o_message *m)
 {
        u32 *msg=(u32 *)m;
-       u32 status;
-       u32 context = msg[3];
+       int status;
+       u32 context = msg[2];
 
 #if 0
        i2o_report_status(KERN_INFO, "i2o_core", msg);
@@ -158,7 +159,7 @@ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
        
        if (msg[0] & (1<<13)) // Fail bit is set
         {
-                printk(KERN_ERR "IOP failed to process the msg:\n");
+                printk(KERN_ERR "%s: Failed to process the msg:\n",c->name);
                 printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n",
                       (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] &
                       0xFFF);
@@ -176,7 +177,7 @@ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
                if (msg[4] >> 24)
                {
                        /* 0x40000000 is used as an error report supress bit */
-                       if((msg[2]&0x40000000)==0)
+                       if(msg[2]&0x40000000)
                                i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
                        status = -(msg[4] & 0xFFFF);
                }
@@ -356,8 +357,7 @@ int i2o_delete_controller(struct i2o_controller *c)
                if(*p==c)
                {
                        /* Ask the IOP to switch to HOLD state */
-                       if (i2o_clear_controller(c) < 0)
-                               printk("Unable to clear iop%d\n", c->unit);
+                       i2o_clear_controller(c);
 
                        /* Release IRQ */
                        c->destructor(c);
@@ -427,7 +427,7 @@ int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
                        return -EBUSY;
        }
 
-       if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, &reply_flag, type))
+       if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, type))
        {
                return -EBUSY;
        }
@@ -443,7 +443,10 @@ int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
        if(type == I2O_CLAIM_PRIMARY)
                d->owner=h;
        else
-               i2o_add_management_user(d, h);
+               if (i2o_add_management_user(d, h))
+                       printk(KERN_WARNING "i2o: Too many managers for TID %d\n",
+                               d->lct_data->tid);
+                                                                              
 
        spin_unlock(&i2o_configuration_lock);
        return 0;
@@ -463,7 +466,7 @@ int i2o_release_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
                else
                {
                        if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0,
-                                          &reply_flag, type))
+                                          type))
                        {
                                err = -ENXIO;
                        }
@@ -486,7 +489,7 @@ int i2o_release_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
                atomic_dec(&d->controller->users);
 
                if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0, 
-                                  &reply_flag, type))
+                                  type))
                        err = -ENXIO;
        }
 
@@ -647,10 +650,8 @@ u32 i2o_wait_message(struct i2o_controller *c, char *why)
        {
                if((jiffies-time)>=5*HZ)
                {
-#ifdef DRIVERDEBUG
-                       printk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", 
-                               c->name, why);
-#endif
+                       dprintk((KERN_ERR "%s: Timeout waiting for message frame (%s).\n", 
+                               c->name, why));
                        return 0xFFFFFFFF;
                }
                schedule();
@@ -673,10 +674,8 @@ u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout)
        {
                if(jiffies-time >= timeout*HZ )
                {
-#ifdef DRIVERDEBUG
-                       printk(KERN_ERR "%s: timeout waiting for %s reply.\n",
-                               c->name, why);
-#endif
+                       dprintk((KERN_ERR "%s: timeout waiting for %s reply.\n",
+                               c->name, why));
                        return 0xFFFFFFFF;
                }
                schedule();
@@ -685,106 +684,6 @@ u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout)
 }
        
 
-static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf, int buflen, 
-       int group, int field)
-{
-       u32 m;
-       u32 *msg;
-       u16 op[8];
-       u32 *p;
-       int i;
-       u32 *rbuf;
-
-       op[0]=1;                        /* One Operation */
-       op[1]=0;                        /* PAD */
-       op[2]=1;                        /* FIELD_GET */
-       op[3]=group;                    /* group number */
-       op[4]=1;                        /* 1 field */
-       op[5]=field;                    /* Field number */
-
-       m=i2o_wait_message(c, "ParamsGet");
-       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 scalar read.\n");
-               return -ENOMEM;
-       }
-
-       __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_5, &msg[0]);
-       __raw_writel(I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid, &msg[1]);
-       __raw_writel(0, &msg[2]);                       /* Context */
-       __raw_writel(0, &msg[3]);
-       __raw_writel(0, &msg[4]);
-       __raw_writel(0x54000000|12, &msg[5]);
-       __raw_writel(virt_to_bus(op), &msg[6]);
-       __raw_writel(0xD0000000|(32+buflen), &msg[7]);
-       __raw_writel(virt_to_bus(rbuf), &msg[8]);
-
-       i2o_post_message(c,m);
-       barrier();
-       
-       /*
-        *      Now wait for a reply
-        */
-        
-       m=i2o_wait_reply(c, "ParamsGet", 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);
-       }
-       
-       p=rbuf;
-
-       /* Ok 'p' is the reply block - lets see what happened */
-       /* p0->p2 are the header */
-       
-       /* FIXME: endians - turn p3 to little endian */
-       
-       if((p[0]&0xFFFF)!=1)    
-               printk(KERN_WARNING "Suspicious field read return 0x%08X\n", p[0]);
-               
-       i=(p[1]&0xFFFF)<<2;             /* Message size */
-       if(i<buflen)
-               buflen=i;
-       
-       /* Do we have an error block ? */
-       if(p[1]&0xFF000000)
-       {
-#ifdef DRIVERDEBUG
-               printk(KERN_ERR "%s: error in field read.\n",
-                       c->name);
-#endif
-               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;
-}
-
 /*
  *      Dump the information block associated with a given unit (TID)
  */
@@ -832,25 +731,25 @@ void i2o_report_controller_unit(struct i2o_controller *c, int unit)
 static int i2o_parse_hrt(struct i2o_controller *c)
 {
 #ifdef DRIVERDEBUG
-       u32 *rows=(u32*)c->hrt;
+       u32 *rows=(u32 *)c->hrt;
        u8 *p=(u8 *)c->hrt;
        u8 *d;
        int count;
        int length;
        int i;
        int state;
-       
-       if(p[3]!=0)
-       {
-               printk(KERN_ERR "i2o: HRT table for controller is too new a version.\n");
-               return -1;
+
+       if(p[3]!=0) {
+               printk(KERN_ERR "%s: HRT table for controller is too new a version.\n",
+                       c->name);
+               return -1;      
        }
-               
+       
        count=p[0]|(p[1]<<8);
        length = p[2];
        
-       printk(KERN_INFO "iop%d: HRT has %d entries of %d bytes each.\n",
-               c->unit, count, length<<2);
+       printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
+               c->name, count, length<<2);
 
        rows+=2;
        
@@ -912,6 +811,7 @@ static int i2o_parse_hrt(struct i2o_controller *c)
                printk("\n");
                rows+=length;
        }
+
 #endif
        return 0;
 }
@@ -938,27 +838,27 @@ static int i2o_parse_lct(struct i2o_controller *c)
 
        if(max==0)
        {
-               printk(KERN_ERR "LCT is empty????\n");
+               printk(KERN_ERR "%s: LCT is empty????\n",c->name);
                return -1;
        }
-       
-       printk(KERN_INFO "LCT has %d entries.\n", max);
+
+       printk(KERN_INFO "%s: LCT has %d entries.\n", c->name,max);
        
        if(max > 128)
        {
-               printk(KERN_INFO "LCT was truncated.\n");
+               printk(KERN_INFO "%s: LCT was truncated.\n",c->name);
                max=128;
        }
        
        if(lct->iop_flags&(1<<0))
-               printk(KERN_WARNING "I2O: Configuration dialog desired by iop%d.\n", c->unit);
+               printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name);
                
        for(i=0;i<max;i++)
        {
                d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
                if(d==NULL)
                {
-                       printk("i2o_core: Out of memory for I2O device data.\n");
+                       printk(KERN_CRIT "i2o_core: Out of memory for I2O device data.\n");
                        return -ENOMEM;
                }
                
@@ -1003,128 +903,65 @@ static int i2o_parse_lct(struct i2o_controller *c)
 int i2o_quiesce_controller(struct i2o_controller *c)
 {
        u32 msg[4];
+       int ret;
 
-       if(c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)
+       if ((c->status_block->iop_state != ADAPTER_STATE_READY) &
+           (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)) 
+       {
+               dprintk((KERN_INFO "%s: Not in READY or OPERATIONAL state\n", 
+                       c->name));
+               dprintk((KERN_INFO "%s: state = %d\n", 
+                       c->name, c->status_block->iop_state));
                return -EINVAL;
+       }
 
        msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2]=(u32)core_context;
-       msg[3]=(u32)&reply_flag;
+       /* msg[2] and msg[3] filled in i2o_post_wait */
 
        /* Long timeout needed for quiesce if lots of devices */
-#ifdef DRIVERDEBUG
-       printk(KERN_INFO "Posting quiesce message to iop%d\n", c->unit);
-#endif
-       if(i2o_post_wait(c, msg, sizeof(msg), 120))
-               return -1;
+
+       if ((ret = i2o_post_wait(c, msg, sizeof(msg), 120)))
+               printk(KERN_INFO "%s: Unable to quiesce.\n", c->name);
        else
-               return 0;
+               dprintk((KERN_INFO "%s: Quiesced.\n", c->name));
+
+       return ret;
 }
 
 /* Enable IOP */
 int i2o_enable_controller(struct i2o_controller *c)
 {
        u32 msg[4];
-
+       int ret;
+       
        msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2]=core_context;
-       msg[3]=(u32)&reply_flag;
+       /* msg[2] and msg[3] filled in i2o_post_wait */
 
        /* How long of a timeout do we need? */
-       return i2o_post_wait(c, msg, sizeof(msg), 240);
-}
-
-/*
- * Quiesce _all_ IOPs in OP state.  
- * Used during init/shutdown time.
- */
-int i2o_quiesce_system(void)
-{
-       struct i2o_controller *iop;
-       int ret = 0;
-
-       for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
-       {
-               /* 
-                * Quiesce only needed on operational IOPs
-                */
-               i2o_status_get(iop);
-
-               if(iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
-               {
-#ifdef DRIVERDEBUG
-                       printk(KERN_INFO "Attempting to quiesce iop%d\n", iop->unit);
-#endif
-                       if(i2o_quiesce_controller(iop))
-                       {
-                               printk(KERN_INFO "Unable to quiesce iop%d\n", iop->unit);
-                               ret = -ENXIO;
-                       }
-#ifdef DRIVERDEBUG
-                       else
-                               printk(KERN_INFO "%s quiesced\n", iop->name);
-#endif
-
-                       i2o_status_get(iop);    // Update IOP state information
-               }
-       }
-       
-       return ret;
-}
-
-/*
- * (re)Enable _all_ IOPs in READY state.
- */
-int i2o_enable_system(void)
-{
-       struct i2o_controller *iop;
-       int ret = 0;
-               
-       for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
-       {
-               /*
-                * Enable only valid for IOPs in READY state
-                */
-               i2o_status_get(iop);
 
-               if(iop->status_block->iop_state == ADAPTER_STATE_READY)
-               {
-                       if(i2o_enable_controller(iop)<0)
-                               printk(KERN_INFO "Unable to (re)enable iop%d\n",
-                                      iop->unit);
-                       
-                       i2o_status_get(iop);    // Update IOP state information
-               }
-       }
+       if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
+               printk(KERN_ERR "%s: Could not enable, %d\n", c->name, ret);
 
        return ret;
 }
 
-
 /* Reset an IOP, but keep message queues alive */
 int i2o_clear_controller(struct i2o_controller *c)
 {
        u32 msg[4];
        int ret;
 
-#ifdef DRIVERDEBUG
-       printk(KERN_INFO "Clearing iop%d\n", c->unit);
-#endif
-
-       /* 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;
+       /* msg[2] and msg[3] filled in i2o_post_wait */
 
-       if((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
-               printk(KERN_INFO "ExecIopClear failed: %#10x\n", ret);
-#ifdef DRIVERDEBUG
-       else
-               printk(KERN_INFO "ExecIopClear success!\n");
-#endif
+       if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
+               printk(KERN_INFO "%s: Unable to clear, %#10x\n", 
+                       c->name, ret);
+
+       i2o_status_get(c); // Reread the Status Block
 
        return ret;
 }
@@ -1134,97 +971,82 @@ int i2o_clear_controller(struct i2o_controller *c)
 static int i2o_reset_controller(struct i2o_controller *c)
 {
        u32 m;
-       u8 *work8;
+       u8 *status;
        u32 *msg;
        long time;
 
-#ifdef DRIVERDEBUG
-       printk(KERN_INFO "Reseting iop%d\n", c->unit);
-#endif
-
-       /* Get a message */
        m=i2o_wait_message(c, "AdapterReset");
        if(m==0xFFFFFFFF)       
                return -ETIMEDOUT;
        msg=(u32 *)(c->mem_offset+m);
-       
-       work8=(void *)kmalloc(4, GFP_KERNEL);
-       if(work8==NULL) {
-               printk(KERN_ERR "IOP reset failed - no free memory.\n");
+
+       status = kmalloc(4,GFP_KERNEL);
+       if (status==NULL) {
+               printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
+                       c->name);
                return -ENOMEM;
        }
-       
-       memset(work8, 0, 4);
-       
+       memset(status,0,4);
+
        msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
        msg[2]=core_context;
-       msg[3]=(u32)&reply_flag;
+       msg[3]=0;
        msg[4]=0;
        msg[5]=0;
-       msg[6]=virt_to_phys(work8);
+       msg[6]=virt_to_phys(status);
        msg[7]=0;       /* 64bit host FIXME */
 
-       /* Then reset the IOP */        
        i2o_post_message(c,m);
 
        /* Wait for a reply */
        time=jiffies;
-       
-       /* DPT driver claims they need this */
-       mdelay(5);
-
-#ifdef DRIVERDEBUG
-       printk(KERN_INFO "Reset posted, waiting...\n");
-#endif
-       while(work8[0]==0)
+       while (status[0]==0)
        {
                if((jiffies-time)>=5*HZ)
                {
-                       printk(KERN_ERR "IOP reset timeout.\n");
-                       kfree(work8);
+                       printk(KERN_ERR "%s: IOP reset timeout.\n", c->name);
+                       kfree(status);
                        return -ETIMEDOUT;
                }
                schedule();
                barrier();
        }
 
-       if (work8[0]==0x02) 
-       { 
-               printk(KERN_WARNING "IOP Reset rejected\n"); 
-       } 
+       if (status[0]==0x02) 
+               printk(KERN_WARNING "%s: Reset rejected.\n",c->name); 
        else 
        {
                /* 
                 * Once the reset is sent, the IOP goes into the INIT state 
-                * which is indeterminate.  We need to wait until the IOP 
+                * which is inditerminate.  We need to wait until the IOP 
                 * has rebooted before we can let the system talk to 
                 * it. We read the inbound Free_List until a message is 
                 * available.  If we can't read one in the given ammount of 
                 * time, we assume the IOP could not reboot properly.  
                 */ 
-#ifdef DRIVERDEBUG 
-               printk(KERN_INFO "Reset succeeded...waiting for reboot\n"); 
-#endif 
+
                time = jiffies; 
                m = I2O_POST_READ32(c); 
                while(m == 0XFFFFFFFF) 
                { 
                        if((jiffies-time) >= 30*HZ)
                        {
-                               printk(KERN_ERR "i2o/iop%d: Timeout waiting for IOP reset.\n", 
-                                                       c->unit); 
+                               printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n",
+                                               c->name); 
+                               kfree(status);
                                return -ETIMEDOUT; 
                        } 
                        schedule(); 
                        barrier(); 
                        m = I2O_POST_READ32(c); 
                } 
-#ifdef DRIVERDEBUG 
-               printk(KERN_INFO "Reboot completed\n"); 
-#endif 
+
+               i2o_flush_reply(c,m);
+               printk(KERN_INFO "%s: Reset completed.\n", c->name);
        }
 
+       kfree(status);
        return 0;
 }
 
@@ -1235,127 +1057,172 @@ int i2o_status_get(struct i2o_controller *c)
        u32 m;
        u32 *msg;
        u8 *status_block;
-       int i;
-
-#ifdef DRIVERDEBUG
-       printk(KERN_INFO "Getting status block for iop%d\n", c->unit);
-#endif
-       if(c->status_block)
-               kfree(c->status_block);
 
-       c->status_block = 
-               (i2o_status_block *)kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
-       if(c->status_block == NULL)
-       {
-#ifdef DRIVERDEBUG
-               printk(KERN_ERR "No memory in status get!\n");
-#endif
-               return -ENOMEM;
+       if (c->status_block == NULL) {
+               c->status_block = (i2o_status_block *)
+                                       kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
+               if (c->status_block == NULL)
+               {
+                       printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", c->name);
+                       return -ENOMEM;
+               }
        }
 
        status_block = (u8*)c->status_block;
-       
+       memset(c->status_block,0,sizeof(i2o_status_block));
+
        m=i2o_wait_message(c, "StatusGet");
        if(m==0xFFFFFFFF)
                return -ETIMEDOUT;
-       
-       memset(status_block, 0, sizeof(i2o_status_block));
 
        msg=(u32 *)(c->mem_offset+m);
-               __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
-       __raw_writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]);
-       __raw_writel(0, &msg[2]);
-       __raw_writel(0, &msg[3]);
-       __raw_writel(0, &msg[4]);
-       __raw_writel(0, &msg[5]);
-       __raw_writel(virt_to_bus(c->status_block), &msg[6]);
-       __raw_writel(0, &msg[7]);       /* 64bit host FIXME */
-       __raw_writel(sizeof(i2o_status_block), &msg[8]);
-       
+
+       msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
+       msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
+       msg[2]=core_context;
+       msg[3]=0;
+       msg[4]=0;
+       msg[5]=0;
+       msg[6]=virt_to_phys(c->status_block);
+       msg[7]=0;       /* 64bit host FIXME */
+       msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
+
        i2o_post_message(c,m);
-       
-       /* DPT work around */
-       mdelay(5);
 
        /* Wait for a reply */
-       time=jiffies;
        
-       while((jiffies-time)<=HZ)
+       time=jiffies;
+       while(status_block[87]!=0xFF)
        {
-               if(status_block[87]!=0)
+               if((jiffies-time)>=5*HZ)
                {
-                       /* Ok the reply has arrived. Fill in the important stuff */
-                       c->inbound_size = (status_block[12]|(status_block[13]<<8))*4;
-                       return 0;
+                       printk(KERN_ERR "%s: Get status timeout.\n",c->name);
+                       return -ETIMEDOUT;
                }
                schedule();
                barrier();
        }
+       
+       /* Ok the reply has arrived. Fill in the important stuff */
+       c->inbound_size = c->status_block->inbound_frame_size *4;
+
 #ifdef DRIVERDEBUG
-       printk(KERN_ERR "IOP get status timeout.\n");
+       printk(KERN_INFO "%s: State = ", c->name);
+       switch (c->status_block->iop_state) {
+               case 0x01:      
+                       printk("INIT\n"); 
+                       break;
+               case 0x02:      
+                       printk("RESET\n"); 
+                       break;
+               case 0x04:      
+                       printk("HOLD\n"); 
+                       break;
+               case 0x05:      
+                       printk("READY\n"); 
+                       break;
+               case 0x08:      
+                       printk("OPERATIONAL\n"); 
+                       break;
+               case 0x10:      
+                       printk("FAILED\n"); 
+                       break;
+               case 0x11:      
+                       printk("FAULTED\n"); 
+                       break;
+               default:        
+                       printk("%x (unknown !!)\n",c->status_block->iop_state);
+       }
 #endif
-       return -ETIMEDOUT;
+
+       return 0;
 }
 
 
 int i2o_hrt_get(struct i2o_controller *c)
 {
        u32 msg[6];
+       int ret, size = sizeof(i2o_hrt);
 
-       if(c->hrt)
-               kfree(c->hrt);
+       /* Read first just the header to figure out the real size */
 
-       c->hrt=kmalloc(2048, GFP_KERNEL);
-       if(c->hrt==NULL)
-       {
-               printk(KERN_ERR "IOP init failed; no memory.\n");
-               return -ENOMEM;
-       }
+       do  {
+               if (c->hrt == NULL) {
+                       c->hrt=kmalloc(size, GFP_KERNEL);
+                       if (c->hrt == NULL) {
+                               printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name);
+                               return -ENOMEM;
+                       }
+               }
 
-       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 */
+               msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
+               msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
+               /* msg[2] and msg[3] filled in i2o_post_wait */
+               msg[4]= (0xD0000000 | size);    /* Simple transaction */
+               msg[5]= virt_to_phys(c->hrt);   /* Dump it here */
+
+               if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) {
+                       printk(KERN_ERR "%s: Unable to get HRT,"
+                               " Status = %d.\n",c->name, ret);        
+                       return ret;
+               }
+
+               if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) {
+                       size = c->hrt->num_entries * c->hrt->entry_len << 2;
+                       kfree(c->hrt);
+                       c->hrt = NULL;
+               }
+       } while (c->hrt == NULL);
+
+       i2o_parse_hrt(c); // just for debugging
 
-       return i2o_post_wait(c, msg, sizeof(msg), 20);
+       return 0;
 }
 
-static int i2o_systab_send(struct i2o_controlleriop)
+static int i2o_systab_send(struct i2o_controller *iop)
 {
-       u32 msg[10];
-       u32 privmem[2];
-       u32 privio[2];
-       int ret;
+        u32 msg[12];
+        u32 privmem[2];
+        u32 privio[2];
+        int ret;
 
-       privmem[0]=iop->priv_mem;       /* Private memory space base address */
-       privmem[1]=iop->priv_mem_size;
-       privio[0]=iop->priv_io;         /* Private I/O address */
-       privio[1]=iop->priv_io_size;
-
-       msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_6;
-       msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
-       msg[2] = 0;     /* Context not needed */
-       msg[3] = 0;
-       msg[4] = (0<<16)|((iop->unit+2)<<12);   /* Host 0 IOP ID (unit + 2) */
-       msg[5] = 0;                             /* Segment 0 */
-       
-       /*
-        *      Scatter Gather List
+       /* See i2o_status_block */
+#if 0
+        iop->status->current_mem_base;
+        iop->status->current_mem_size;
+        iop->status->current_io_base;
+        iop->status->current_io_size;
+#endif
+        privmem[0]=iop->priv_mem;       /* Private memory space base address */
+        privmem[1]=iop->priv_mem_size;
+        privio[0]=iop->priv_io;         /* Private I/O address */
+        privio[1]=iop->priv_io_size;
+
+       msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
+        msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
+       /* [2] and [3] filled in i2o_post_wait */
+        msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+        msg[5] = 0;                               /* Segment 0 */
+
+        /* 
+         * Provide three SGL-elements:
+         * System table (SysTab), Private memory space declaration and 
+         * Private i/o space declaration  
         */
-       msg[6] = 0x54000000|sys_tbl_len;
-       msg[7] = virt_to_phys(sys_tbl);
-       msg[8] = 0xD4000000|48; /* One table for now */
-       msg[9] = virt_to_phys(privmem);
-/*     msg[10] = virt_to_phys(privio); */
-
-       ret=i2o_post_wait(iop, msg, sizeof(msg), 120);
-       if(ret)
-               return ret;
+        msg[6] = 0x54000000 | sys_tbl_len;
+        msg[7] = virt_to_phys(sys_tbl);
+        msg[8] = 0x54000000 | 0;
+        msg[9] = virt_to_phys(privmem);
+        msg[10] = 0xD4000000 | 0;
+        msg[11] = virt_to_phys(privio);
 
-       return 0;
-}
+       if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120)))
+               printk(KERN_INFO "%s: Unable to set SysTab, %d\n", 
+                               iop->name, ret);
+
+       return ret;     
+
+ }
 
 /*
  * Initialize I2O subsystem.
@@ -1550,17 +1417,20 @@ static void __init i2o_sys_init()
  *
  * 1. Quiesce all controllers
  * 2. Delete all controllers
- *
  */
 static void i2o_sys_shutdown(void)
 {
-       struct i2o_controller *iop = NULL;
+       struct i2o_controller *iop, *niop;
 
-       i2o_quiesce_system();
-       for(iop = i2o_controller_chain; iop; iop = iop->next)
-       {
-               if(i2o_delete_controller(iop))
-                       iop->bus_disable(iop);
+       for (iop = i2o_controller_chain; iop ; iop=iop->next) {
+               i2o_quiesce_controller(iop);                    
+               i2o_status_get(iop);    // Update IOP status block
+       }
+
+       for (iop = i2o_controller_chain; iop; iop = niop) {
+               niop = iop->next;
+               if (i2o_delete_controller(iop))
+                       iop->bus_disable(iop); 
        }
 }
 
@@ -1589,8 +1459,8 @@ int i2o_activate_controller(struct i2o_controller *c)
        int i;
        int ret;
 
-       printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n",
-              (u32)c->mem_phys);
+       printk(KERN_INFO "%s: Configuring I2O controller at 0x%08X.\n",
+              c->name, (u32)c->mem_phys);
 
        if((ret=i2o_status_get(c)))
                return ret;
@@ -1627,43 +1497,20 @@ int i2o_activate_controller(struct i2o_controller *c)
                        return ret;
        }
 
-       if((ret=i2o_init_outbound_q(c)))
-       {
-               printk(KERN_ERR 
-                       "IOP%d initialization failed: Could not initialize outbound queue\n",
-                       c->unit);
+       if ((ret=i2o_init_outbound_q(c))){
                return ret;
        }
 
        /* 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)
-       {
-               printk(KERN_ERR "IOP init failed: no memory for message page.\n");
-               return -ENOMEM;
-       }
-       
-       m=virt_to_phys(c->page_frame);
-       
-       for(i=0; i< NMBR_MSG_FRAMES; i++)
-       {
-               I2O_REPLY_WRITE32(c,m);
-               mb();
-               m+=MSG_FRAME_SIZE;
-               mb();
-       }
-       
        /* 
         *      The outbound queue is initialised and loaded, 
         * 
         *      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)
+        
+       if ((ret=i2o_hrt_get(c)))
                return ret;
 
        return i2o_online_controller(c);
@@ -1675,23 +1522,26 @@ int i2o_activate_controller(struct i2o_controller *c)
  */
 int i2o_init_outbound_q(struct i2o_controller *c)
 {
-       u8 workspace[88];
+       u8 *status;
        u32 m;
        u32 *msg;
        u32 time;
+       int i;
 
-       memset(workspace, 0, 88);
-
-//     printk(KERN_INFO "i2o/iop%d: Initializing Outbound Queue\n", c->unit);
        m=i2o_wait_message(c, "OutboundInit");
        if(m==0xFFFFFFFF)
-       {       
-               kfree(workspace);
                return -ETIMEDOUT;
-       }
-
        msg=(u32 *)(c->mem_offset+m);
 
+
+       status = kmalloc(4,GFP_KERNEL);
+       if (status==NULL) {
+               printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
+                       c->name);
+               return -ENOMEM;
+       }
+       memset(status, 0, 4);
+       
        msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
        msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
        msg[2]= core_context;
@@ -1699,30 +1549,41 @@ int i2o_init_outbound_q(struct i2o_controller *c)
        msg[4]= 4096;                   /* Host page frame size */
        msg[5]= MSG_FRAME_SIZE<<16|0x80;        /* Outbound msg frame size and Initcode */
        msg[6]= 0xD0000004;             /* Simple SG LE, EOB */
-       msg[7]= virt_to_bus(workspace);
-       *((u32 *)workspace)=0;
+       msg[7]= virt_to_phys(status);
 
-       /*
-        *      Post it
-        */
        i2o_post_message(c,m);
        
-       barrier();
-       
+       barrier();      
        time=jiffies;
-       
-       while(workspace[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE)
+       while(status[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE)
        {
                if((jiffies-time)>=5*HZ)
                {
-                       printk(KERN_ERR "i2o/iop%d: IOP outbound initialise failed.\n",
-                                               c->unit);
+                       printk(KERN_ERR "%s: Outbound Q initialize timeout.\n",
+                                       c->name);
+                       kfree(status);
                        return -ETIMEDOUT;
                }
                schedule();
                barrier();
        }
 
+       c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
+       if(c->page_frame==NULL) {
+               printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
+                       c->name);
+               kfree(status);
+               return -ENOMEM;
+       }       
+       m=virt_to_phys(c->page_frame);
+       
+       for(i=0; i< NMBR_MSG_FRAMES; i++) {
+               I2O_REPLY_WRITE32(c,m);
+                mb();
+               m += MSG_FRAME_SIZE;
+       }
+
+       kfree(status);
        return 0;
 }
 
@@ -1732,34 +1593,41 @@ int i2o_init_outbound_q(struct i2o_controller *c)
 int i2o_lct_get(struct i2o_controller *c)
 {
        u32 msg[8];
+       int ret, size = c->status_block->expected_lct_size;
+
+       do {
+               if (c->lct == NULL) {
+                       c->lct = kmalloc(size, GFP_KERNEL);
+                       if(c->lct == NULL) {
+                               printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
+                                       c->name);
+                               return -ENOMEM;
+                       }
+               }
+               memset(c->lct, 0, size);
+
+               msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+               msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+               /* msg[2] and msg[3] filled in i2o_post_wait */
+               msg[4] = 0xFFFFFFFF;    /* All devices */
+               msg[5] = 0x00000000;    /* Report now */
+               msg[6] = 0xD0000000|size;
+               msg[7] = virt_to_bus(c->lct);
+
+               if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) {
+                       printk(KERN_ERR "%s: Unable to get LCT,"
+                               " Status = %d.\n", c->name,ret);        
+                       return ret;
+               }
 
-#ifdef DRIVERDEBUG
-       printk(KERN_INFO "Getting lct for iop%d\n", c->unit);
-#endif
-
-       if(c->lct)
-               kfree(c->lct);
+               if (c->lct->table_size << 2 > size) {
+                       size = c->lct->table_size << 2;
+                       kfree(c->lct);
+                       c->lct = NULL;
+               }
+       } while (c->lct == NULL);
 
-       c->lct = kmalloc(8192, GFP_KERNEL);
-       if(c->lct==NULL)
-       {
-               printk(KERN_ERR "i2o/iop%d: No free memory for i2o controller buffer.\n",
-                               c->unit);
-               return -ENOMEM;
-       }
-       
-       memset(c->lct, 0, 8192);
-       
-       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);
-       
-       return(i2o_post_wait(c, msg, sizeof(msg), 120));
+       return 0;
 }
 
 
@@ -1774,69 +1642,67 @@ int i2o_online_controller(struct i2o_controller *c)
        u32 msg[10];
        u32 privmem[2];
        u32 privio[2];
-       u32 systab[32];
        int ret;
 
-       systab[0]=1;
-       systab[1]=0;
-       systab[2]=0;
-       systab[3]=0;
-       systab[4]=0;                    /* Organisation ID */
-       systab[5]=2;                    /* Ident 2 for now */
-       systab[6]=0<<24|0<<16|I2OVERSION<<12|1; /* Memory mapped, IOPState, v1.5, segment 1 */
-       systab[7]=MSG_FRAME_SIZE>>2;    /* Message size */
-       systab[8]=0;                    /* LastChanged */
-       systab[9]=0;                    /* Should be IOP capabilities */
-       systab[10]=virt_to_phys(c->post_port);
-       systab[11]=0;
-       
-       i2o_build_sys_table();
+       /*
+        * Build and send the system table
+        *
+        * If build_sys_table fails, we kill everything and bail
+        * as we can't init the IOPs w/o a system table
+        */
+        
+       if (i2o_build_sys_table()) {
+               i2o_sys_shutdown();
+               return;
+        }
        
        privmem[0]=c->priv_mem;         /* Private memory space base address */
        privmem[1]=c->priv_mem_size;
        privio[0]=c->priv_io;           /* Private I/O address */
        privio[1]=c->priv_io_size;
 
-       __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_6, &msg[0]);
-       __raw_writel(I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
-       __raw_writel(0, &msg[2]);               /* Context not needed */
-       __raw_writel(0, &msg[3]);
-       __raw_writel((0<<16)|(2<<12), &msg[4]); /* Host 1 I2O 2 */
-       __raw_writel(0, &msg[5]);               /* Segment 1 */
-       
-       /*
-        *      Scatter Gather List
-        */
-       
-       __raw_writel(0x54000000|sys_tbl_len, &msg[6]);  /* One table for now */
-       __raw_writel(virt_to_phys(sys_tbl), &msg[[7]);
-       __raw_writel(0xD4000000|48, &msg[8]);   /* One table for now */
-       __raw_writel(virt_to_phys(privmem), &msg[9]);
-
-       return(i2o_post_wait(c, msg, sizeof(msg), 120));
-       
-       /*
-        *      Finally we go online
-        */
-       ret = i2o_enable_controller(c);
-       if(ret)
-               return ret;
-       
-       /*
-        *      Grab the LCT, see what is attached
-        */
-       ret=i2o_lct_get(c);
-       if(ret)
-       {
-               /* Maybe we should do also do something else */
-               return ret;
-       }
+        __raw_writel(TEN_WORD_MSG_SIZE|SGL_OFFSET_6, &msg[0]);
+        __raw_writel(I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID, &msg$
+        __raw_writel(0, &msg[2]);               /* Context not needed */
+        __raw_writel(0, &msg[3]);
+        __raw_writel((0<<16)|(2<<12), &msg[4]); /* Host 1 I2O 2 */
+        __raw_writel(0, &msg[5]);               /* Segment 1 */
+
+        /*
+         *      Scatter Gather List
+         */
+
+        __raw_writel(0x54000000|sys_tbl_len, &msg[6]);  /* One table for now */
+        __raw_writel(virt_to_phys(sys_tbl), &msg[[7]);
+        __raw_writel(0xD4000000|48, &msg[8]);   /* One table for now */
+        __raw_writel(virt_to_phys(privmem), &msg[9]);
+
+        ret = (i2o_post_wait(c, msg, sizeof(msg), 120);
+        if (ret)
+               return ret; 
+
+        /*
+         *      Finally we go online
+         */
+        ret = i2o_enable_controller(c);
+        if(ret)
+                return ret;
+
+        /*
+         *      Grab the LCT, see what is attached
+         */
+        ret=i2o_lct_get(c);
+        if(ret)
+        {
+                /* Maybe we should do also do something else */
+                return ret;
+        }
 
-       ret=i2o_parse_lct(c);
-       if(ret)
-               return ret;
+        ret=i2o_parse_lct(c);
+        if(ret)
+                return ret;
 
-       return 0;
+        return 0; 
 #endif
 }
 
@@ -1844,23 +1710,19 @@ static int i2o_build_sys_table(void)
 {
        struct i2o_controller *iop = NULL;
        int count = 0;
-#ifdef DRIVERDEBUG
-       u32 *table;
-#endif
 
        sys_tbl_len = sizeof(struct i2o_sys_tbl) +      // Header + IOPs
                                (i2o_num_controllers) *
                                        sizeof(struct i2o_sys_tbl_entry);
 
-#ifdef DRIVERDEBUG
-       printk(KERN_INFO "Building system table len = %d\n", sys_tbl_len);
-#endif
        if(sys_tbl)
                kfree(sys_tbl);
 
        sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL);
-       if(!sys_tbl)
+       if(!sys_tbl) {
+               printk(KERN_CRIT "SysTab Set failed. Out of memory.\n");        
                return -ENOMEM;
+       }
        memset((void*)sys_tbl, 0, sys_tbl_len);
 
        sys_tbl->num_entries = i2o_num_controllers;
@@ -1869,8 +1731,11 @@ static int i2o_build_sys_table(void)
 
        for(iop = i2o_controller_chain; iop; iop = iop->next)
        {
-               // Get updated IOP state so we have the latest information
-               i2o_status_get(iop);    
+               // Get updated Status Block so we have the latest information
+               if (i2o_status_get(iop)) {
+                       sys_tbl->num_entries--;
+                       continue; // try next one       
+               }
 
                sys_tbl->iops[count].org_id = iop->status_block->org_id;
                sys_tbl->iops[count].iop_id = iop->unit + 2;
@@ -1894,9 +1759,12 @@ static int i2o_build_sys_table(void)
        }
 
 #ifdef DRIVERDEBUG
-       table = (u32*)sys_tbl;
+{
+       u32 *table = (u32*)sys_tbl;
        for(count = 0; count < (sys_tbl_len >>2); count++)
-               printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);
+               printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", 
+                       count, table[count]);
+}
 #endif
 
        return 0;
@@ -1929,12 +1797,13 @@ int i2o_post_this(struct i2o_controller *c, u32 *data, int len)
        
        if(m==0xFFFFFFFF)
        {
-               printk(KERN_ERR "i2o/iop%d: Timeout waiting for message frame!\n",
-                                       c->unit);
+               printk(KERN_ERR "%s: Timeout waiting for message frame!\n",
+                               c->name);
                return -ETIMEDOUT;
        }
+
        msg = (u32 *)(c->mem_offset + m);
-       memcpy_toio(msg, data, len);
+       memcpy_toio(msg, data, len);
        i2o_post_message(c,m);
        return 0;
 }
@@ -1947,16 +1816,13 @@ int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
        DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post);
        int status = 0;
        int flags = 0;
-       int ret = 0;
        struct i2o_post_wait_data *p1, *p2;
        struct i2o_post_wait_data *wait_data =
                kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);
 
        if(!wait_data)
-               return -ETIMEDOUT;
+               return -ENOMEM;
 
-       p1 = p2 = NULL;
-       
        /* 
         * The spin locking is needed to keep anyone from playing 
         * with the queue pointers and id while we do the same
@@ -1964,48 +1830,29 @@ int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
        spin_lock_irqsave(&post_wait_lock, flags);
        wait_data->next = post_wait_queue;
        post_wait_queue = wait_data;
-       wait_data->id = ++post_wait_id;
+       wait_data->id = (++post_wait_id) & 0x7fff;
        spin_unlock_irqrestore(&post_wait_lock, flags);
 
        wait_data->wq = &wq_i2o_post;
-       wait_data->status = -ETIMEDOUT;
+       wait_data->status = -EAGAIN;
 
-       msg[3] = (u32)wait_data->id;    
-       msg[2] = 0x80000000|(u32)core_context;
+       msg[2]=0x80000000|(u32)core_context|((u32)wait_data->id<<16);
 
-       if((ret=i2o_post_this(c, msg, len)))
-               return ret;
-       /*
-        * Go to sleep and wait for timeout or wake_up call
-        */
-       interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout);
-
-       /*
-        * Grab transaction status
-        */
-       status = wait_data->status;
+       if ((status = i2o_post_this(c, msg, len))==0) {
+               interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout);
+               status = wait_data->status;
+       }
 
-       /* 
-        * Remove the entry from the queue.
-        * Since i2o_post_wait() may have been called again by
-        * a different thread while we were waiting for this 
-        * instance to complete, we're not guaranteed that 
-        * this entry is at the head of the queue anymore, so 
-        * we need to search for it, find it, and delete it.
-        */
+       p2 = NULL;
        spin_lock_irqsave(&post_wait_lock, flags);
-       for(p1 = post_wait_queue; p1;  )
-       {
-               if(p1 == wait_data)
-               {
+       for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) {
+               if(p1 == wait_data) {
                        if(p2)
                                p2->next = p1->next;
                        else
                                post_wait_queue = p1->next;
-
                        break;
                }
-               p1 = p1->next;
        }
        spin_unlock_irqrestore(&post_wait_lock, flags);
        
@@ -2020,7 +1867,7 @@ int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
  */
 static void i2o_post_wait_complete(u32 context, int status)
 {
-       struct i2o_post_wait_data *p1 = NULL;
+       struct i2o_post_wait_data *p1;
 
        /* 
         * We need to search through the post_wait 
@@ -2035,42 +1882,75 @@ static void i2o_post_wait_complete(u32 context, int status)
         * around while we're looking through them.
         */
        spin_lock(&post_wait_lock);
-       for(p1 = post_wait_queue; p1; p1 = p1->next)
-       {
-               if(p1->id == context)
-               {
+       for(p1 = post_wait_queue; p1; p1 = p1->next) {
+               if(p1->id == ((context >> 16) & 0x7fff)) {
                        p1->status = status;
-                       wake_up_interruptible(p1->wq);
                        spin_unlock(&post_wait_lock);
+                       wake_up_interruptible(p1->wq);
                        return;
                }
        }
        spin_unlock(&post_wait_lock);
 
-       printk(KERN_DEBUG "i2o_post_wait reply after timeout!");
+       printk(KERN_DEBUG "i2o: i2o_post_wait reply after timeout!");
 }
 
 /*
- *     Issue UTIL_CLAIM messages
+ *      Send UTIL_EVENT messages
+ */
+
+int i2o_event_register(struct i2o_controller *c, int tid, int context,
+                        u32 evt_mask)
+{
+        u32 msg[5];
+
+        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+        msg[1] = I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | tid;
+        msg[2] = context;
+        msg[3] = 0;
+        msg[4] = evt_mask;
+
+        if (i2o_post_this(c, msg, sizeof(msg)) < 0)
+                return -ETIMEDOUT;
+
+        return 0;
+}
+
+int i2o_event_ack(struct i2o_controller *c, int tid, int context,
+                u32 evt_indicator, void *evt_data, int evt_data_len)
+{
+        u32 msg[c->inbound_size];
+
+        msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5;
+        msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid;
+       /* msg[2] and msg[3] filled in i2o_post_wait */
+        msg[4] = evt_indicator;
+        memcpy(msg+5, evt_data, evt_data_len);
+
+        if (i2o_post_this(c, msg, sizeof(msg)) < 0)
+                return -ETIMEDOUT;
+
+        return 0;
+}
+
+/*
+ *     Issue UTIL_CLAIM or UTIL_RELEASE messages
  */
  
-int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag, u32 type)
+static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, u32 type)
 {
-       u32 msg[6];
+       u32 msg[5];
 
        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
        if(onoff)
                msg[1] = I2O_CMD_UTIL_CLAIM << 24 | HOST_TID<<12 | tid;
        else    
                msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid;
-       
-       /* The 0x80000000 convention for flagging is assumed by this helper */
-       
-       msg[2] = 0x80000000|context;
-       msg[3] = (u32)flag;
+
+       /* msg[2] and msg[3] filled in i2o_post_wait */ 
        msg[4] = type;
        
-       return i2o_post_wait(c, msg, 20, 2);
+       return i2o_post_wait(c, msg, sizeof(msg), 2);
 }
 
 /*     Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
@@ -2085,10 +1965,7 @@ int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid,
                 void *opblk, int oplen, void *resblk, int reslen)
 {
        u32 msg[9]; 
-       u8 *res = (u8 *)resblk;
-       int res_count;
-       int blk_size;
-       int bytes;
+       u32 *res = (u32 *)resblk;
        int wait_status;
 
        msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
@@ -2099,31 +1976,21 @@ int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid,
        msg[7] = 0xD0000000 | reslen;   /* ResultBlock */
        msg[8] = virt_to_bus(resblk);
 
-       wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10);
-       if (wait_status)       
-       return wait_status;     /* -DetailedStatus */
+       if ((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 20)))
+               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);
+               printk(KERN_WARNING "%s: %s - Error:\n  ErrorInfoSize = 0x%02x, "
+                       "BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+                       iop->name,
+                       (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--)
-       {
-               blk_size = (res[0] & 0xFFFF) << 2;
-               bytes   += blk_size;
-               res     += blk_size;
-       }
-  
-       return bytes; /* total sizeof Result List in bytes */
+        return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ 
 }
 
 /*
@@ -2138,10 +2005,10 @@ int i2o_query_scalar(struct i2o_controller *iop, int tid,
 
        if (field == -1)                /* whole group */
                        opblk[4] = -1;
-              
+
        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, 
                opblk, sizeof(opblk), resblk, sizeof(resblk));
-               
+                       
        if (size < 0)
                return size;    
 
@@ -2673,6 +2540,10 @@ EXPORT_SYMBOL(i2o_delete_controller);
 EXPORT_SYMBOL(i2o_unlock_controller);
 EXPORT_SYMBOL(i2o_find_controller);
 EXPORT_SYMBOL(i2o_num_controllers);
+
+EXPORT_SYMBOL(i2o_event_register);
+EXPORT_SYMBOL(i2o_event_ack);
+
 EXPORT_SYMBOL(i2o_claim_device);
 EXPORT_SYMBOL(i2o_release_device);
 EXPORT_SYMBOL(i2o_run_queue);
@@ -2691,7 +2562,6 @@ EXPORT_SYMBOL(i2o_row_delete_table);
 
 EXPORT_SYMBOL(i2o_post_this);
 EXPORT_SYMBOL(i2o_post_wait);
-EXPORT_SYMBOL(i2o_issue_claim);
 EXPORT_SYMBOL(i2o_issue_params);
 
 EXPORT_SYMBOL(i2o_report_status);
@@ -2699,25 +2569,23 @@ EXPORT_SYMBOL(i2o_report_status);
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Core");
 
-
 int init_module(void)
 {
-       printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n");
+       printk(KERN_INFO "I2O Core - (c) Copyright 1999 Red Hat Software.\n");
        if (i2o_install_handler(&i2o_core_handler) < 0)
        {
                printk(KERN_ERR 
-                       "i2o_core: Unable to install core handler.\nI2O stack not loaded!");
+                       "i2o: Unable to install core handler.\nI2O stack not loaded!");
                return 0;
        }
 
        core_context = i2o_core_handler.context;
-
        /*
         * Attach core to I2O PCI transport (and others as they are developed)
         */
 #ifdef CONFIG_I2O_PCI_MODULE
        if(i2o_pci_core_attach(&i2o_core_functions) < 0)
-               printk(KERN_INFO "No PCI I2O controllers found\n");
+               printk(KERN_INFO "i2o: No PCI I2O controllers found\n");
 #endif
 
        if(i2o_num_controllers)
index c9516286333d367c01eacb321b889703350d3e09..08fcc2c2c9acc6462b7666a48acb6ce5307f7c8b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     linux/drivers/i2o/i2o_lan.c
  *
- *     I2O LAN CLASS OSM       Prototyping, November 8th 1999
+ *     I2O LAN CLASS OSM       December 2nd 1999
  *
  *     (C) Copyright 1999      University of Helsinki,
  *                             Department of Computer Science
@@ -20,8 +20,7 @@
  *     Tested:         in FDDI environment (using SysKonnect's DDM)
  *                     in Ethernet environment (using Intel 82558 DDM proto)
  *
- *     TODO:           batch mode sends
- *                     error checking / timeouts
+ *     TODO:           check error checking / timeouts
  *                     code / test for other LAN classes
  */
 
@@ -45,7 +44,7 @@
 #include <linux/i2o.h>
 #include "i2o_lan.h"
 
-#define DRIVERDEBUG
+//#define DRIVERDEBUG
 #ifdef DRIVERDEBUG
 #define dprintk(s, args...) printk(s, ## args)
 #else
@@ -68,16 +67,22 @@ struct i2o_lan_local {
        struct fddi_statistics stats;   /* see also struct net_device_stats */
        unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
        u32 bucket_count;               /* nbr of buckets sent to DDM */
-       u32 tx_count;                   /* nbr of outstanding TXes */
-       u32 max_tx;                     /* DDM's Tx queue len */
+       u32 tx_count;                   /* packets in one TX message frame */
+       u32 tx_max;                     /* DDM's Tx queue len */
+       u32 tx_out;                     /* outstanding TXes */
+       u32 sgl_max;                    /* max SGLs in one message frame */
+       u32 m;                          /* IOP address of msg frame */
+
+       struct sk_buff **i2o_fbl;       /* Free bucket list (to reuse skbs) */
+       int i2o_fbl_tail;
 
        spinlock_t lock;
 };
 
 static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
-                          struct i2o_message *m); 
-static void i2o_lan_event_reply(struct net_device *dev, u32 *msg); 
-static int i2o_lan_receive_post(struct net_device *dev, u32 count);
+                          struct i2o_message *m);
+static void i2o_lan_event_reply(struct net_device *dev, u32 *msg);
+static int i2o_lan_receive_post(struct net_device *dev);
 static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg);
 static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg);
 
@@ -87,8 +92,11 @@ static struct i2o_handler i2o_lan_handler = {
        0,              // context
        I2O_CLASS_LAN
 };
-static int lan_context;  
+static int lan_context;
 
+static struct tq_struct i2o_post_buckets_task = {
+       0, 0, (void (*)(void *))i2o_lan_receive_post, (void *) 0
+};
 
 static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                          struct i2o_message *m)
@@ -116,10 +124,10 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                i2o_report_status(KERN_INFO, dev->name, msg);
        
        switch (msg[1] >> 24) {
-       case LAN_RECEIVE_POST: 
+       case LAN_RECEIVE_POST:
        {
                if (dev->start) {
-                       if(!(msg[4]>>24)) {
+                       if (!(msg[4]>>24)) {
                                i2o_lan_receive_post_reply(dev,msg);
                                break;
                        }
@@ -128,27 +136,27 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                        printk( KERN_WARNING "i2olan: Device %s rejected bucket post.\n", dev->name);
                }
 
-               // Getting unused buckets back
+               // Shutting down, we are getting unused buckets back
                i2o_lan_release_buckets(dev,msg);       
        
                break;
        }
 
        case LAN_PACKET_SEND:
-       case LAN_SDU_SEND: 
+       case LAN_SDU_SEND:
        {
-               struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
-               u8 trl_count  = msg[3] & 0x000000FF;    
-               
-               while (trl_count) {     
-                       // The HDM has handled the outgoing packet
+               struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+               u8 trl_count  = msg[3] & 0x000000FF;
+
+               while (trl_count) {
+                       // The HDM has handled the outgoing packet
                        dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]);
-                       printk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
+                       dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
                                dev->name,trl_count);
-                       priv->tx_count--;
+                       priv->tx_out--;
                        trl_count--;
                }
-               
+
                if (dev->tbusy) {
                        clear_bit(0,(void*)&dev->tbusy);
                        mark_bh(NET_BH); /* inform upper layers */
@@ -217,7 +225,7 @@ static void i2o_lan_event_reply(struct net_device *dev, u32 *msg)
                                 break;
                         case I2O_EVT_IND_DEVICE_RESET:
                                 printk("Device reset.\n");
-                                break;                            
+                                break;
                         case I2O_EVT_IND_EVT_MASK_MODIFIED:
                                 printk("Event mask modified, 0x%08X.\n",
                                         evt->evt_data[0]);
@@ -267,22 +275,20 @@ static void i2o_lan_event_reply(struct net_device *dev, u32 *msg)
 
         /* else evt->function == I2O_CMD_UTIL_EVT_ACK) */
         /* Do we need to do something here too? */
-}   
-
+}
 
-void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
+static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
 {
-       struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
-       u8 trl_count  = (u8)(msg[3] & 0x000000FF);      
+        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+       u8 trl_count  = (u8)(msg[3] & 0x000000FF);
        u32 *pskb = &msg[6];
 
-       while (trl_count) {     
+       while (trl_count--) {
                dprintk("%s: Releasing unused sk_buff %p.\n",dev->name,
                        (struct sk_buff*)(*pskb));
                dev_kfree_skb((struct sk_buff*)(*pskb));
                pskb++;
                priv->bucket_count--;
-               trl_count--;
        }
 }
 
@@ -291,50 +297,35 @@ static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg)
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
        struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6];
        struct i2o_packet_info *packet;
-       
-       u8 trl_count  = msg[3] & 0x000000FF;    
-       struct sk_buff *skb, *newskb;
+       u8 trl_count = msg[3] & 0x000000FF;
+       struct sk_buff *skb, *old_skb;
 
-#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
        while (trl_count--) {
-               skb = (struct sk_buff *)(bucket->context);              
+               skb = (struct sk_buff *)bucket->context;                
                packet = (struct i2o_packet_info *)bucket->packet_info; 
                priv->bucket_count--;
 
-#if 0
-               dprintk(KERN_INFO "Buckets_remaining = %d, bucket_count = %d, trl_count = %d\n",
-                       msg[5], priv->bucket_count, trl_count);
-
-               dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n",
-                       packet->flags, packet->offset, packet->status, packet->len);
-#endif
                if (packet->len < rx_copybreak) {
-                       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 {
+                       old_skb = skb;
+                       skb = (struct sk_buff *)dev_alloc_skb(packet->len+2);   
+                       if (skb == NULL) {
                                printk("%s: Can't allocate skb.\n", dev->name);
                                return -ENOMEM;
-                       }
-               } else {
-                       skb_put(skb,packet->len);               
-                       skb->dev = dev;         
-                       skb->protocol = priv->type_trans(skb, dev);
+                       }                               
+                       skb_reserve(skb,2);
+                       memcpy(skb_put(skb,packet->len), old_skb->data, packet->len);
+
+                       if (priv->i2o_fbl_tail < I2O_BUCKET_COUNT)
+                               priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb;  
+                       else
+                               dev_kfree_skb(old_skb);
+               } else
+                       skb_put(skb,packet->len);       
+       
+               skb->dev = dev;
+               skb->protocol = priv->type_trans(skb, dev);
+               netif_rx(skb);
 
-                       netif_rx(skb);
-               }
                dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered "
                        "to upper level.\n",dev->name,packet->len);
 
@@ -344,67 +335,74 @@ static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg)
        if ((msg[4] & 0x000000FF) == I2O_LAN_DSC_BUCKET_OVERRUN)
                printk(KERN_INFO "%s: DDM out of buckets (count = %d)!\n",
                         dev->name, msg[5]);
-       
-       if (priv->bucket_count <= bucketpost - bucketthresh)
-               i2o_lan_receive_post(dev, bucketpost - priv->bucket_count);
 
+        if (priv->bucket_count <= bucketpost - bucketthresh) {
+//             i2o_lan_receive_post(dev);
+               i2o_post_buckets_task.data = (void *)dev;
+               queue_task(&i2o_post_buckets_task, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+       }
+                               
        return 0;
 }
 
+
 /*
  * i2o_lan_receive_post(): Post buckets to receive packets.
  */
-static int i2o_lan_receive_post(struct net_device *dev, u32 count)
-{      
-       struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
+static int i2o_lan_receive_post(struct net_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;
        struct sk_buff *skb;
-       u32 m; u32 *msg;
-       
-       u32 bucket_len = (dev->mtu + dev->hard_header_len);
-       u32 bucket_count;
-       int n_elems = (iop->inbound_size - 16 ) / 12; /* msg header + SGLs */
-       u32 total = 0;
-       int i;
-       
-       while (total < count) {
-               m = I2O_POST_READ32(iop);
-               if (m == 0xFFFFFFFF)
-                       return -ETIMEDOUT;              
-               msg = (u32 *)(iop->mem_offset + m);
-               bucket_count = (total + n_elems < count)
-                            ? n_elems
-                            : count - total;
-
-               msg[0] = I2O_MESSAGE_SIZE(4 + 3 *  bucket_count) | SGL_OFFSET_4;
-               msg[1] = LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
-               msg[2] = priv->unit << 16 | lan_context; // InitiatorContext    
-               msg[3] = bucket_count;                   // BucketCount
-
-               for (i = 0; i < bucket_count; i++) {
-                       skb = dev_alloc_skb(bucket_len + 2);
-                       if (skb == NULL)
-                               return -ENOMEM;
-                       skb_reserve(skb, 2);
-
-                       priv->bucket_count++;
-
-                       msg[4 + 3*i] = 0x51000000 | bucket_len;
-                       msg[5 + 3*i] = (u32)skb;
-                       msg[6 + 3*i] = virt_to_bus(skb->data);
-               }
-               msg[4 + 3*i - 3] |= 0x80000000; // set LE flag
-               i2o_post_message(iop,m);
-
-               dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n",
-                       dev->name, bucket_count, bucket_len);
+        u32 m; u32 *msg;
+        u32 bucket_len = (dev->mtu + dev->hard_header_len);
+        u32 total = bucketpost - priv->bucket_count;
+        u32 bucket_count;
+        u32 *sgl_elem;
+
+        while (total) {
+                m = I2O_POST_READ32(iop);
+                if (m == 0xFFFFFFFF)
+                        return -ETIMEDOUT;
+                msg = (u32 *)(iop->mem_offset + m);
+
+                bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total;
+                total -= bucket_count;
+                priv->bucket_count += bucket_count;
+
+                dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n",
+                        dev->name, bucket_count, bucket_len);
+
+               __raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg);
+               __raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1);
+               __raw_writel(priv->unit << 16 | lan_context, msg+2);
+               __raw_writel(bucket_count, msg+3);
+                sgl_elem = &msg[4];
+
+                while (bucket_count--) {
+                        if (priv->i2o_fbl_tail >= 0)
+                                skb = priv->i2o_fbl[priv->i2o_fbl_tail--];
+                        else {
+                                skb = dev_alloc_skb(bucket_len + 2);
+                                if (skb == NULL)
+                                        return -ENOMEM;
+                                skb_reserve(skb, 2);
+                        }
+                        __raw_writel(0x51000000 | bucket_len, sgl_elem);
+                        __raw_writel((u32)skb,               sgl_elem+1);
+                        __raw_writel(virt_to_bus(skb->data),  sgl_elem+2);
+                        sgl_elem += 3;
+                }
 
-               total += bucket_count;
-       }
+               /* set LE flag and post buckets */
+               __raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3));
+                i2o_post_message(iop,m);
+        }
 
-       return 0;       
-}      
+        return 0;
+}
 
 /*
  * i2o_lan_reset(): Reset the LAN adapter into the operational state and
@@ -441,7 +439,7 @@ static int i2o_lan_suspend(struct net_device *dev)
        struct i2o_controller *iop = i2o_dev->controller;       
        u32 msg[5];
 
-       dprintk( "%s: LAN SUSPEND MESSAGE.\n", dev->name );
+       dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name);
        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
        msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
        msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
@@ -459,12 +457,6 @@ static int i2o_lan_suspend(struct net_device *dev)
  */
 static void i2o_set_batch_mode(struct net_device *dev)
 {
-
-/*
- * NOTE: we have not been able to test batch mode
- *      since HDMs we have, don't implement it
- */
-
        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;       
@@ -474,13 +466,11 @@ static void i2o_set_batch_mode(struct net_device *dev)
 
        // enable batch mode, toggle automatically
        val = 0x00000000;
-//     val = 0x00000001; // turn off batch mode
        if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0003, 0, &val, sizeof(val)) <0)
                printk(KERN_WARNING "%s: Unable to enter I2O LAN batch mode.\n",
                        dev->name);
-       else 
+       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,
@@ -508,28 +498,32 @@ static int i2o_lan_open(struct net_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; 
+       struct i2o_controller *iop = i2o_dev->controller;
        u32 evt_mask =  0xFFC00007; // All generic events, all lan evenst
 
        if (i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) {
                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", 
+       dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n",
                dev->name, i2o_dev->lct_data->tid);
 #if 0
        if (i2o_event_register(iop, i2o_dev->lct_data->tid,
                                priv->unit << 16 | lan_context, evt_mask) < 0)
-               printk(KERN_WARNING "%s: Unable to set the event mask.\n", 
-                       dev->name);
+               printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name);
 #endif
        i2o_lan_reset(dev);
        
+       priv->i2o_fbl = kmalloc(bucketpost * sizeof(struct sk_buff *),GFP_KERNEL);
+       if (priv->i2o_fbl == NULL)
+               return -ENOMEM;
+       priv->i2o_fbl_tail = -1;
+
        dev->tbusy = 0;
        dev->start = 1;
 
        i2o_set_batch_mode(dev);
-       i2o_lan_receive_post(dev, bucketpost);
+       i2o_lan_receive_post(dev);
 
        MOD_INC_USE_COUNT;
 
@@ -543,14 +537,14 @@ static int i2o_lan_close(struct net_device *dev)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
        struct i2o_device *i2o_dev = priv->i2o_dev;     
-//#if 0
-       struct i2o_controller *iop = i2o_dev->controller; 
+#if 0
+       struct i2o_controller *iop = i2o_dev->controller;
 
        if (i2o_event_register(iop, i2o_dev->lct_data->tid,
                                priv->unit << 16 | lan_context, 0) < 0)
-               printk(KERN_WARNING "%s: Unable to clear the event mask.\n", 
+               printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
                                dev->name);
-//#endif
+#endif
        dev->tbusy = 1;
        dev->start = 0;
        i2o_lan_suspend(dev);
@@ -559,6 +553,10 @@ static int i2o_lan_close(struct net_device *dev)
                printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
                       "(tid=%d).\n", dev->name, i2o_dev->lct_data->tid);
 
+       while (priv->i2o_fbl_tail >= 0)
+               dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
+       kfree(priv->i2o_fbl);
+
        MOD_DEC_USE_COUNT;
 
        return 0;
@@ -576,6 +574,22 @@ static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev)
 }
 #endif
 
+static void i2o_lan_batch_send(struct net_device *dev)
+{      
+       struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+       struct i2o_controller *iop = priv->i2o_dev->controller;
+
+       if (priv->tx_count != 0) {
+               i2o_post_message(iop, priv->m);
+               dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);   
+               priv->tx_count = 0;
+       }
+}
+
+struct tq_struct i2o_post_send_task = {
+       0, 0, (void (*)(void *))i2o_lan_batch_send, (void *) 0
+};
+
 /*
  * i2o_lan_packet_send(): Send a packet as is, including the MAC header.
  *
@@ -588,63 +602,75 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
        struct i2o_device *i2o_dev = priv->i2o_dev;     
        struct i2o_controller *iop = i2o_dev->controller;
        u32 m, *msg;
-       u32 flags = 0;
+       u32 *sgl_elem;
 
        /*
         * Keep interrupt from changing dev->tbusy from underneath us
         * (Do we really need to do this?)
         */
-       spin_lock_irqsave(&priv->lock, flags);
 
-       if(test_and_set_bit(0,(void*)&dev->tbusy) != 0) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return 1;
-       }
+       if (test_and_set_bit(0,(void*)&dev->tbusy) != 0) {
+               return 1;
+        }
 
-       m = I2O_POST_READ32(iop);
-       if (m == 0xFFFFFFFF) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               dev_kfree_skb(skb);
-               return -ETIMEDOUT;
-       }
-       msg = (u32 *)(iop->mem_offset + m);
+       priv->tx_count++;
+       priv->tx_out++;
 
-#if 0
-       __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4,&msg[0]);
-       __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, &msg[1]);
-       __raw_writel(priv->unit << 16 | lan_context, &msg[2]); // InitiatorContext
-       __raw_writel(1 << 4, &msg[3]);                  // TransmitControlWord
-       __raw_writel(0xD5000000 | skb->len, &msg[4]);   // MAC hdr included
-       __raw_writel((u32)skb, &msg[5]);                // TransactionContext
-       __raw_writel(virt_to_bus(skb->data),&msg[6]);
-#endif
+       if (priv->tx_count == 1) {              
+               dprintk("%s: New message frame\n", dev->name);
 
-       msg[0] = SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4;
-       msg[1] = LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;   
-       msg[2] = priv->unit << 16 | lan_context; // IntiatorContext
-       msg[3] = 1 << 4;                         // TransmitControlWord
+               m = I2O_POST_READ32(iop);
+               if (m == 0xFFFFFFFF) {
+                       dev_kfree_skb(skb);
+                       return -ETIMEDOUT;
+               }
+               msg = (u32 *)(iop->mem_offset + m);
+               priv->m = m;
+
+               __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg);
+               __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1);
+               __raw_writel(priv->unit << 16 | lan_context, msg+2); // InitiatorContext
+               __raw_writel(1 << 4, msg+3);                         // TransmitControlWord
+               __raw_writel(0xD5000000 | skb->len, msg+4);          // MAC hdr included
+               __raw_writel((u32)skb, msg+5);                       // TransactionContext
+               __raw_writel(virt_to_bus(skb->data), msg+6);
+
+               i2o_post_send_task.data = (void *)dev;
+               queue_task(&i2o_post_send_task, &tq_scheduler);
        
-       // create a simple SGL, see fig. 3-26
-       // D5 = 1101 0101 = LE eob 0 1 LA dir bc1 bc0
+               if (priv->tx_out < priv->tx_max)
+                       clear_bit(0, (void *)&dev->tbusy);
 
-       msg[4] = 0xD5000000 | skb->len;         // MAC hdr included
-       msg[5] = (u32)skb;                      // TransactionContext
-       msg[6] = virt_to_bus(skb->data);
+               return 0;
+       }
+       
+       /* Else add new SGL element to the previous message frame */
+       
+       dprintk("%s: Adding packet %d to msg frame\n", dev->name, priv->tx_count);
 
-       i2o_post_message(iop,m);
+       msg = (u32 *)(iop->mem_offset + priv->m);
+       sgl_elem = &msg[priv->tx_count * 3 + 1];
+       
+       __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg);
+       __raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */
+       __raw_writel(0xD5000000 | skb->len, sgl_elem);
+       __raw_writel((u32)skb, sgl_elem+1);
+       __raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+
+       if (priv->tx_count == priv->sgl_max) {  /* frame full, send now */
+//             i2o_lan_batch_send(dev);
+               i2o_post_message(iop, priv->m);
+               dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);   
+               priv->tx_count = 0;
+       }
 
-       // Check to see if HDM queue is full..if so...stay busy
-       if(++priv->tx_count < priv->max_tx)
+       if (priv->tx_out < priv->tx_max)
                clear_bit(0, (void *)&dev->tbusy);
 
-       spin_unlock_irqrestore(&priv->lock, flags);
-               
-       dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n",
-               dev->name, skb->len);
-
        return 0;
 }
 
+
 static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
@@ -653,7 +679,7 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
        u64 val64[16];
        u64 supported_group[4] = { 0, 0, 0, 0 };
 
-        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64, 
+        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64,
                             sizeof(val64)) < 0)
                printk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name);
        else {
@@ -703,8 +729,7 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
                if (supported_stats != 0) {
                        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0281, -1,
                                         val64, sizeof(val64)) < 0)
-;
-//                             printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name);
+                               printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name);
                        else {
                                dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name);
                                if (supported_stats & 0x1)
@@ -713,7 +738,6 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
                                        priv->stats.tx_heartbeat_errors = val64[2];
                        }
                }
-
        }
 
 #ifdef CONFIG_TR
@@ -724,7 +748,7 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
                else {
                        struct tr_statistics *stats =
                                        (struct tr_statistics *)&priv->stats;
-//                     dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
+                       dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
 
                        stats->line_errors              = val64[0];
                        stats->internal_errors          = val64[7];
@@ -747,7 +771,7 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
                                 val64, sizeof(val64)) < 0)
                        printk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name);
                else {
-//                     dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name);
+                       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);                 
@@ -782,7 +806,7 @@ static void i2o_lan_set_mc_list(struct net_device *dev)
 
         if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0001, -1,
                              &mc_addr_group, sizeof(mc_addr_group)) < 0 ) {
-                printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name);
+               printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name);
                 return;
         }
 
@@ -863,7 +887,7 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        struct net_device *dev = NULL;
        struct i2o_lan_local *priv = NULL;
        u8 hw_addr[8];
-       u32 max_tx = 0;
+       u32 tx_max = 0;
        unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
        void (*unregister_dev)(struct net_device *dev);
 
@@ -934,6 +958,7 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        priv->i2o_dev = i2o_dev;
        priv->type_trans = type_trans;
        priv->bucket_count = 0;
+       priv->sgl_max = (i2o_dev->controller->inbound_size - 16) / 12;
 
        unit++;
        i2o_landevs[unit] = dev;
@@ -956,7 +981,7 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        memcpy(dev->dev_addr, hw_addr, 6);
 
        if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
-               0x0007, 2, &max_tx, sizeof(max_tx)) < 0) 
+               0x0007, 2, &tx_max, sizeof(tx_max)) < 0)
        {
                printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
                unit--;
@@ -964,11 +989,11 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
                kfree(dev);
                return NULL;
        }
-       dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, max_tx);
-       priv->max_tx = max_tx;
-       priv->tx_count = 0;
-
-       priv->lock = SPIN_LOCK_UNLOCKED;
+       dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max);
+       priv->tx_max    = tx_max;
+       priv->tx_out    = 0;
+       priv->tx_count  = 0;
+       priv->lock      = SPIN_LOCK_UNLOCKED;
 
        dev->open               = i2o_lan_open;
        dev->stop               = i2o_lan_close;
@@ -989,7 +1014,12 @@ int __init i2o_lan_init(void)
        int i;
 
        printk(KERN_INFO "Linux I2O LAN OSM (c) 1999 University of Helsinki.\n");
+
+       if (bucketpost > I2O_BUCKET_COUNT)
+               bucketpost = I2O_BUCKET_COUNT;
+       if (bucketthresh > bucketpost)
+               bucketthresh = bucketpost;
+
        if (i2o_install_handler(&i2o_lan_handler) < 0) {
                printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
                return -EINVAL;
@@ -1085,7 +1115,7 @@ 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(bucketpost, "i");   // Total number of buckets to post
 MODULE_PARM(bucketthresh, "i"); // Bucket post threshold
 MODULE_PARM(rx_copybreak, "i");
 
index f436802eb65a58261fe46af0d2a329fa5462f9db..7b988f297d76e3ec11284c620c90338831e30d1a 100644 (file)
@@ -747,7 +747,7 @@ static char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
 static char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
 static int     eepro_grab_irq(struct net_device *dev)
 {
-       int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12 };
+       int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
        int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr;
        
        outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
index 7ca5801b2f76992e382c5650e84eb9323b1eb9d2..b1af7e5dc1e313a8cab93a9922e7b84b6d7f5983 100644 (file)
@@ -1,8 +1,8 @@
 /* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
    
-   Written 1994-1998 by Mika Kuoppala
+   Written 1994-1999 by Mika Kuoppala
    
-   Copyright (C) 1994-1998 by Mika Kuoppala
+   Copyright (C) 1994-1999 by Mika Kuoppala
    Based on skeleton.c and heavily on at1700.c by Donald Becker
 
    This software may be used and distributed according to the terms
@@ -16,7 +16,7 @@
          (Uses true 32 bit transfers rather than 16i compability mode)
 
    Example Module usage:
-        insmod eth16i.o ioaddr=0x2a0 mediatype=bnc
+        insmod eth16i.o io=0x2a0 mediatype=bnc
 
        mediatype can be one of the following: bnc,tp,dix,auto,eprom
 
                                Now more shallow reset is made on
                                close.
 
+   0.34         29.06-99       Fixed one bad #ifdef.
+                               Changed ioaddr -> io for consistency
+
+   0.35         01.07-99        transmit,-receive bytes were never
+                                updated in stats. 
+
    Bugs:
        In some cases the media interface autoprobing code doesn't find 
        the correct interface type. In this case you can 
 */
 
 static char *version = 
-    "eth16i.c: v0.33 10-09-98 Mika Kuoppala (miku@iki.fi)\n";
+    "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n";
 
 #include <linux/module.h>
 
@@ -400,7 +406,8 @@ struct eth16i_local {
        unsigned short    tx_queue_len;         
        unsigned int      tx_buf_size;
        unsigned long     open_time;
-       unsigned long     tx_buffered_packets;  
+       unsigned long     tx_buffered_packets;
+       unsigned long     tx_buffered_bytes;
        unsigned long     col_16;
 };
 
@@ -1147,9 +1154,9 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
                        }
 
                        lp->tx_buffered_packets++;
+                       lp->tx_buffered_bytes = length;
                        lp->tx_queue++;
                        lp->tx_queue_len += length + 2;
-                       
                }
                
                lp->tx_buf_busy = 0;
@@ -1260,6 +1267,7 @@ static void eth16i_rx(struct net_device *dev)
                        skb->protocol=eth_type_trans(skb, dev);
                        netif_rx(skb);
                        lp->stats.rx_packets++;
+                       lp->stats.rx_bytes += pkt_len;
 
                        if( eth16i_debug > 5 ) {
                                int i;
@@ -1368,6 +1376,7 @@ static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
                if(status & TX_DONE) {         /* The transmit has been done */
                        lp->stats.tx_packets = lp->tx_buffered_packets;
+                       lp->stats.tx_bytes += lp->tx_buffered_bytes;
                        lp->col_16 = 0;            
 
                        if(lp->tx_queue) {           /* Is there still packets ? */
@@ -1500,7 +1509,7 @@ static struct net_device dev_eth16i[MAX_ETH16I_CARDS] = {
        },
 };
 
-static int ioaddr[MAX_ETH16I_CARDS] = { 0, };
+static int io[MAX_ETH16I_CARDS] = { 0, };
 #if 0
 static int irq[MAX_ETH16I_CARDS] = { 0, };
 #endif
@@ -1511,8 +1520,8 @@ static int debug = -1;
 MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");
 MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
 
-MODULE_PARM(ioaddr, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
-MODULE_PARM_DESC(ioaddr, "eth16i io base address");
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
+MODULE_PARM_DESC(io, "eth16i io base address");
 
 #if 0
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
@@ -1536,7 +1545,7 @@ int init_module(void)
        
                dev->name = namelist + (NAMELEN*this_dev);
                dev->irq = 0; /* irq[this_dev]; */
-               dev->base_addr = ioaddr[this_dev];
+               dev->base_addr = io[this_dev];
                dev->init = eth16i_probe;
 
                if(debug != -1)
@@ -1547,7 +1556,7 @@ int init_module(void)
 
                dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
 
-               if(ioaddr[this_dev] == 0)
+               if(io[this_dev] == 0)
                {
                        if(this_dev != 0) break; /* Only autoprobe 1st one */
 
@@ -1557,7 +1566,7 @@ int init_module(void)
                if(register_netdev(dev) != 0)
                {
                        printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
-                              ioaddr[this_dev]);
+                              io[this_dev]);
            
                        if(found != 0) return 0;
                        return -ENXIO;
index 4b723cf1e864b5b01026524504a4f598110768b3..2948b9d32943d4361fa87b567a2bf563e271658a 100644 (file)
@@ -6,7 +6,7 @@
  * Status:       Experimental.
  * Author:       Dag Brattli <dagb@cs.uit.no>
  * Created at:   Sun Aug  3 13:49:59 1997
- * Modified at:   Thu Dec 16 00:47:08 1999
+ * Modified at:   Tue Dec 21 21:51:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:      serial.c by Linus Torvalds 
  * 
@@ -218,9 +218,6 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
                ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
                return NULL;
        }
-       /* dev_alloc doesn't clear the struct */
-       memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
-
        self->netdev = dev;
 
        /* May be overridden by piggyback drivers */
@@ -266,8 +263,6 @@ int irport_close(struct irport_cb *self)
                rtnl_lock();
                unregister_netdevice(self->netdev);
                rtnl_unlock();
-               /* Must free the old-style 2.2.x device */
-               kfree(self->netdev);
        }
 
        /* Release the IO-port that this driver is using */
index d342eb98dda81ed431f5892a04da96090a858966..0205f0e266891b5f1bffc7ac7bde2d4c60083b6d 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:18:38 1997
- * Modified at:   Thu Dec 16 09:37:47 1999
+ * Modified at:   Tue Dec 21 21:50:59 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -233,8 +233,6 @@ static int irtty_open(struct tty_struct *tty)
                ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
                return -ENOMEM;
        }
-       /* dev_alloc doesn't clear the struct */
-       memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
 
        dev->priv = (void *) self;
        self->netdev = dev;
@@ -286,8 +284,6 @@ static void irtty_close(struct tty_struct *tty)
                rtnl_lock();
                unregister_netdevice(self->netdev);
                rtnl_unlock();
-               /* Must free the old-style 2.2.x device */
-               kfree(self->netdev);
        }
        
        /* We are not using any dongle anymore! */
index 375f3c0dd7937f17def862cc362837bf04d1b0cb..47da35ddf161bea7a66a444139bcd874c62ac32b 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Thu Dec 16 00:54:27 1999
+ * Modified at:   Tue Dec 21 21:51:54 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
@@ -113,7 +113,6 @@ static int  pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
 static void pc87108_dma_write(struct pc87108 *self, int iobase);
 static void pc87108_change_speed(struct pc87108 *self, __u32 baud);
 static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void pc87108_wait_until_sent(struct pc87108 *self);
 static int  pc87108_is_receiving(struct pc87108 *self);
 static int  pc87108_read_dongle_id (int iobase);
 static void pc87108_init_dongle_interface (int iobase, int dongle_id);
@@ -257,9 +256,6 @@ static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr,
                ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
                return -ENOMEM;
        }
-       /* dev_alloc doesn't clear the struct, so lets do a little hack */
-       memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
-
        dev->priv = (void *) self;
        self->netdev = dev;
 
@@ -308,8 +304,6 @@ static int pc87108_close(struct pc87108 *self)
                rtnl_lock();
                unregister_netdevice(self->netdev);
                rtnl_unlock();
-               /* Must free the old-style 2.2.x device */
-               kfree(self->netdev);
        }
 
        /* Release the PORT that this driver is using */
@@ -666,7 +660,7 @@ static void pc87108_change_speed(struct pc87108 *self, __u32 speed)
        __u8 bank;
        int iobase; 
 
-       IRDA_DEBUG(4, __FUNCTION__ "()\n");
+       IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed);
 
        ASSERT(self != NULL, return;);
 
@@ -819,11 +813,11 @@ static int pc87108_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                        pc87108_dma_write(self, iobase);
                }
         } else {
+               self->tx_buff.data = self->tx_buff.head;
+
                self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
                                                   self->tx_buff.truesize);
-               
-               self->tx_buff.data = self->tx_buff.head;
-               
+                               
                /* Add interrupt on tx low level (will fire immediately) */
                switch_bank(iobase, BANK0);
                outb(IER_TXLDL_IE, iobase+IER);
@@ -992,12 +986,13 @@ static int pc87108_dma_receive(struct pc87108 *self)
        switch_bank(iobase, BANK0);
        outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
 
+       self->rx_buff.data = self->rx_buff.head;
+
        setup_dma(self->io.dma, self->rx_buff.data, 
                  self->rx_buff.truesize, DMA_MODE_READ);
        
        /* driver->media_busy = FALSE; */
        self->io.direction = IO_RECV;
-       self->rx_buff.data = self->rx_buff.head;
 
        /* Reset Rx FIFO. This will also flush the ST_FIFO */
        outb(FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
@@ -1163,9 +1158,7 @@ static void pc87108_pio_receive(struct pc87108 *self)
        /*  Receive all characters in Rx FIFO */
        do {
                byte = inb(iobase+RXD);
-               async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
-                                 byte);
-
+               async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, byte);
        } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */      
 }
 
@@ -1215,7 +1208,14 @@ static __u8 pc87108_sir_interrupt(struct pc87108 *self, int eir)
        }
        /* Check if transmission has completed */
        if (eir & EIR_TXEMP_EV) {
-               
+               /* Check if we need to change the speed? */
+               if (self->new_speed) {
+                       IRDA_DEBUG(2, __FUNCTION__ 
+                                  "(), Changing speed!\n");
+                       pc87108_change_speed(self, self->new_speed);
+                       self->new_speed = 0;
+               }
+
                /* Turn around and get ready to receive some data */
                self->io.direction = IO_RECV;
                new_ier |= IER_RXHDL_IE;
@@ -1352,19 +1352,6 @@ static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        dev->interrupt = 0;
 }
 
-/*
- * Function pc87108_wait_until_sent (self)
- *
- *    This function should put the current thread to sleep until all data 
- *    have been sent, so it is safe to f.eks. change the speed.
- */
-static void pc87108_wait_until_sent(struct pc87108 *self)
-{
-       /* Just delay 60 ms */
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(MSECS_TO_JIFFIES(60));
-}
-
 /*
  * Function pc87108_is_receiving (self)
  *
index 98a0d4a30147b9be6e32c612b14721e2276a3476..6715d07b8717955d0329b5a1a3a44e58e3ea148b 100644 (file)
@@ -702,8 +702,6 @@ toshoboe_close (struct toshoboe_cb *self)
          rtnl_lock();
          unregister_netdevice(self->netdev);
          rtnl_unlock();
-         /* Must free the old-style 2.2.x device */
-         kfree(self->netdev);
   }
 
   kfree (self->taskfilebuf);
@@ -872,8 +870,6 @@ toshoboe_open (struct pci_dev *pci_dev)
          ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
          return -ENOMEM;
   }
-  /* dev_alloc doesn't clear the struct, so lets do a little hack */
-  memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
 
   dev->priv = (void *) self;
   self->netdev = dev;
index 052b79f0ea827ca91fc1bc8c11314681f241f471..82f308cd67494b2082469665aa38d7bf1fe86a83 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Thu Dec 16 00:52:53 1999
+ * Modified at:   Tue Dec 21 21:53:09 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
@@ -244,9 +244,6 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq,
                ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
                return -ENOMEM;
        }
-       /* dev_alloc doesn't clear the struct, so lets do a little hack */
-       memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
-
        dev->priv = (void *) self;
        self->netdev = dev;
 
@@ -301,8 +298,6 @@ static int w83977af_close(struct w83977af_ir *self)
                rtnl_lock();
                unregister_netdevice(self->netdev);
                rtnl_unlock();
-               /* Must free the old-style 2.2.x device */
-               kfree(self->netdev);
        }
 
        /* Release the PORT that this driver is using */
@@ -1013,8 +1008,15 @@ static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr)
                }
        }
        /* Check if transmission has completed */
-       if (isr & ISR_TXEMP_I) {
-               
+       if (isr & ISR_TXEMP_I) {                
+               /* Check if we need to change the speed? */
+               if (self->new_speed) {
+                       IRDA_DEBUG(2, __FUNCTION__ 
+                                  "(), Changing speed!\n");
+                       w83977af_change_speed(self, self->new_speed);
+                       self->new_speed = 0;
+               }
+
                /* Turn around and get ready to receive some data */
                self->io.direction = IO_RECV;
                new_icr |= ICR_ERBRI;
index 571b40dc17ad3cc68c663b4e07b30758ec998d17..228803fb07680efb1e84cee4f885e36e545d690e 100644 (file)
@@ -1221,7 +1221,7 @@ static void set_rx_mode(struct net_device *net_dev)
 
        /* update Multicast Hash Table in Receive Filter */
        for (i = 0; i < 8; i++) {
-+               /* why plus 0x04 ??, That makes the correct value for hash table. */
+                /* why plus 0x04 ??, That makes the correct value for hash table. */
                outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
                outl(mc_filter[i], ioaddr + rfdr);
        }
index 28f73d6b862de14b81c5b7ed38b0b1fbde0f8580..236815963fa1a912ef141908bf844288d69b3445 100644 (file)
@@ -34,7 +34,6 @@ static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap)
 static int yenta_get_status(pci_socket_t *socket, unsigned int *value)
 {
        u32 state = cb_readl(socket, CB_SOCKET_STATE);
-       u8 status;
        unsigned int val;
 
        /* Convert from Yenta status to old-style status */
@@ -46,10 +45,12 @@ static int yenta_get_status(pci_socket_t *socket, unsigned int *value)
        val |= (state & CB_XVCARD) ? SS_XVCARD : 0;
 
        /* Get the old compatibility status too.. */
-       status = exca_readb(socket, I365_STATUS);
-       val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
-       val |= (status & I365_CS_READY) ? SS_READY : 0;
-       val |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+       if (!(state & CB_CBCARD)) {
+               u8 status = exca_readb(socket, I365_STATUS);
+               val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+               val |= (status & I365_CS_READY) ? SS_READY : 0;
+               val |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+       }
 
 printk("yenta_get_status(%p)= %x\n", socket, val);
 
@@ -121,6 +122,9 @@ printk("yenta_set_socket(%p, %d, %d, %x)\n", socket, state->Vcc, state->Vpp, sta
        bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
        config_writew(socket, CB_BRIDGE_CONTROL, bridge);
 
+       exca_writeb(socket, I365_GBLCTL, 0x00);
+       exca_writeb(socket, I365_GENCTL, 0x00);
+
        /* Set the IO interrupt and socket state */
        reg = state->io_irq;
        reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
@@ -451,7 +455,11 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket)
 
 static void yenta_get_socket_capabilities(pci_socket_t *socket)
 {
-       socket->cap.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
+       /* MAGIC NUMBERS! Fixme */
+       config_writeb(socket, PCI_LATENCY_TIMER, 168);
+       config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176);
+
+       socket->cap.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
        socket->cap.irq_mask = yenta_probe_irq(socket);
        if (socket->cb_irq && socket->cb_irq < 16)
                socket->cap.irq_mask |= 1 << socket->cb_irq;
index 7cf7803f3191af077bdc33d1bb322be740b36678..92a2ddfaf80b897ed0ea1278501628f40fadd8a4 100644 (file)
@@ -13,7 +13,7 @@ MIX_OBJS :=
 MOD_LIST_NAME := SCSI_MODULES
 SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
 
-CFLAGS_aha152x.o =   -DDEBUG_AHA152X -DAUTOCONF
+CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
 CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
 CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
 
diff --git a/drivers/scsi/README.aha152x b/drivers/scsi/README.aha152x
new file mode 100644 (file)
index 0000000..2ce022c
--- /dev/null
@@ -0,0 +1,183 @@
+$Id: README.aha152x,v 1.2 1999/12/25 15:32:30 fischer Exp fischer $
+Adaptec AHA-1520/1522 SCSI driver for Linux (aha152x)
+
+Copyright 1993-1999 Jürgen Fischer <fischer@norbit.de>
+TC1550 patches by Luuk van Dijk (ldz@xs4all.nl)
+
+
+In Revision 2 the driver was modified a lot (especially the
+bottom-half handler complete()).
+
+The driver is much cleaner now, has support for the new
+error handling code in 2.3, produced less cpu load (much
+less polling loops), has slightly higher throughput (at
+least on my ancient test box; a i486/33Mhz/20MB).
+
+
+CONFIGURATION ARGUMENTS:
+
+IOPORT        base io address                           (0x340/0x140)
+IRQ           interrupt level                           (9-12; default 11)
+SCSI_ID       scsi id of controller                     (0-7; default 7)
+RECONNECT     allow targets to disconnect from the bus  (0/1; default 1 [on])
+PARITY        enable parity checking                    (0/1; default 1 [on])
+SYNCHRONOUS   enable synchronous transfers              (0/1; default 1 [on])
+DELAY:        bus reset delay                           (default 100)
+EXT_TRANS:    enable extended translation               (0/1: default 0 [off])
+              (see NOTES)
+
+COMPILE TIME CONFIGURATION (go into AHA152X in drivers/scsi/Makefile):
+
+-DAUTOCONF
+ use configuration the controller reports (AHA-152x only)
+
+-DSKIP_BIOSTEST
+ Don't test for BIOS signature (AHA-1510 or disabled BIOS)
+
+-DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
+ override for the first controller 
+
+-DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
+ override for the second controller
+
+-DAHA152X_DEBUG
+ enable debugging output
+
+-DAHA152X_STAT
+ enable some statistics
+
+
+LILO COMMAND LINE OPTIONS:
+
+aha152x=<IOPORT>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY> [,<EXT_TRANS]]]]]]]
+
+ The normal configuration can be overridden by specifying a command line.
+ When you do this, the BIOS test is skipped. Entered values have to be
+ valid (known).  Don't use values that aren't supported under normal
+ operation.  If you think that you need other values: contact me.
+ For two controllers use the aha152x statement twice.
+
+
+SYMBOLS FOR MODULE CONFIGURATION:
+
+Choose from 2 alternatives:
+
+1. specify everything (old)
+
+aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
+  configuration override for first controller
+
+
+aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
+  configuration override for second controller
+
+2. specify only what you need to (irq or io is required; new)
+
+io=IOPORT0[,IOPORT1]
+  IOPORT for first and second controller
+
+irq=IRQ0[,IRQ1]
+  IRQ for first and second controller
+
+scsiid=SCSIID0[,SCSIID1]
+  SCSIID for first and second controller
+
+reconnect=RECONNECT0[,RECONNECT1]
+  allow targets to disconnect for first and second controller
+
+parity=PAR0[PAR1]
+  use parity for first and second controller
+
+sync=SYNCHRONOUS0[,SYNCHRONOUS1]
+  enable synchronous transfers for first and second controller
+
+delay=DELAY0[,DELAY1]
+  reset DELAY for first and second controller
+
+exttrans=EXTTRANS0[,EXTTRANS1]
+  enable extended translation for first and second controller
+
+
+If you use both alternatives the first will be taken.
+
+
+NOTES ON EXT_TRANS: 
+
+SCSI uses block numbers to address blocks/sectors on a device.
+The BIOS uses a cylinder/head/sector addressing scheme (C/H/S)
+scheme instead.  DOS expects a BIOS or driver that understands this
+C/H/S addressing.
+
+The number of cylinders/heads/sectors is called geometry and is required
+as base for requests in C/H/S addressing.  SCSI only knows about the
+total capacity of disks in blocks (sectors).
+
+Therefore the SCSI BIOS/DOS driver has to calculate a logical/virtual
+geometry just to be able to support that addressing scheme.  The geometry
+returned by the SCSI BIOS is a pure calculation and has nothing to
+do with the real/physical geometry of the disk (which is usually
+irrelevant anyway).
+
+Basically this has no impact at all on Linux, because it also uses block
+instead of C/H/S addressing.  Unfortunately C/H/S addressing is also used
+in the partition table and therefore every operating system has to know
+the right geometry to be able to interpret it.
+
+Moreover there are certain limitations to the C/H/S addressing scheme,
+namely the address space is limited to upto 255 heads, upto 63 sectors
+and a maximum of 1023 cylinders.
+
+The AHA-1522 BIOS calculates the geometry by fixing the number of heads
+to 64, the number of sectors to 32 and by calculating the number of
+cylinders by dividing the capacity reported by the disk by 64*32 (1 MB).
+This is considered to be the default translation.
+
+With respect to the limit of 1023 cylinders using C/H/S you can only
+address the first GB of your disk in the partition table.  Therefore
+BIOSes of some newer controllers based on the AIC-6260/6360 support
+extended translation.  This means that the BIOS uses 255 for heads,
+63 for sectors and then divides the capacity of the disk by 255*63
+(about 8 MB), as soon it sees a disk greater than 1 GB.  That results
+in a maximum of about 8 GB addressable diskspace in the partition table
+(but there are already bigger disks out there today).
+
+To make it even more complicated the translation mode might/might
+not be configurable in certain BIOS setups.
+
+This driver does some more or less failsafe guessing to get the
+geometry right in most cases:
+
+- for disks<1GB: use default translation (C/32/64)
+
+- for disks>1GB:
+  - take current geometry from the partition table
+    (using scsicam_bios_param and accept only `valid' geometries,
+    ie. either (C/32/64) or (C/63/255)).  This can be extended translation
+    even if it's not enabled in the driver.
+
+  - if that fails, take extended translation if enabled by override,
+    kernel or module parameter, otherwise take default translation and
+    ask the user for verification.  This might on not yet partitioned
+    disks.
+
+
+REFERENCES USED:
+
+ "AIC-6260 SCSI Chip Specification", Adaptec Corporation.
+
+ "SCSI COMPUTER SYSTEM INTERFACE - 2 (SCSI-2)", X3T9.2/86-109 rev. 10h
+
+ "Writing a SCSI device driver for Linux", Rik Faith (faith@cs.unc.edu)
+
+ "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu)
+
+ "Adaptec 1520/1522 User's Guide", Adaptec Corporation.
+
+ Michael K. Johnson (johnsonm@sunsite.unc.edu)
+
+ Drew Eckhardt (drew@cs.colorado.edu)
+
+ Eric Youngdale (eric@andante.org) 
+
+ special thanks to Eric Youngdale for the free(!) supplying the
+ documentation on the chip.
index afcc4d1a5a4cf6f0ed9358c014371bd1850ad041..93387842f5c3217d1cee356210350125b920d17d 100644 (file)
@@ -1,5 +1,5 @@
-/* $Id: advansys.c,v 1.68 1999/11/19 01:57:47 bobf Exp bobf $ */
-#define ASC_VERSION "3.2L"    /* AdvanSys Driver Version */
+/* $Id: advansys.c,v 1.69 1999/11/29 18:37:53 bobf Exp bobf $ */
+#define ASC_VERSION "3.2M"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
             at line 7475. The reqp->sgblkp pointer must be initialized
             to NULL in adv_get_sglist().
 
+     3.2M (11/29/99):
+         1. Really fix bug in adv_get_sglist().
+         2. Incorporate v2.3.29 changes into driver.
+
   J. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -5389,9 +5393,14 @@ advansys_detect(Scsi_Host_Template *tpnt)
 
             /* BIOS start address. */
             if (ASC_NARROW_BOARD(boardp)) {
-                shp->base = ((ulong) AscGetChipBiosAddress(
-                                                asc_dvc_varp->iop_base,
-                                                asc_dvc_varp->bus_type));
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29)
+                shp->base =
+#else /* version >= v2.3.29 */
+                shp->base = (char *)
+#endif /* version < v2.3.29 */
+                        ((ulong) AscGetChipBiosAddress(
+                            asc_dvc_varp->iop_base,
+                            asc_dvc_varp->bus_type));
             } else {
                 /*
                  * Fill-in BIOS board variables. The Wide BIOS saves
@@ -5423,7 +5432,12 @@ advansys_detect(Scsi_Host_Template *tpnt)
                      * Convert x86 realmode code segment to a linear
                      * address by shifting left 4.
                      */
-                    shp->base = (boardp->bios_codeseg << 4);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29)
+                    shp->base =
+#else /* version >= v2.3.29 */
+                    shp->base = (char *)
+#endif /* version < v2.3.29 */
+                        ((ulong) boardp->bios_codeseg << 4);
                 } else {
                     shp->base = 0;
                 }
@@ -7476,7 +7490,7 @@ adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp)
     slp = (struct scatterlist *) scp->request_buffer;
     sg_elem_cnt = scp->use_sg;
     prev_sg_block = NULL;
-    reqp->sgblkp == NULL;
+    reqp->sgblkp = NULL;
 
     do
     {
index 7db30e068bd377b123c40efe3dc2d72d8ba0e049..4ae0bb33d99902ea9d1bfdd5e050a1c856238249 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: advansys.h,v 1.17 1998/01/08 21:23:49 bobf Exp bobf $ */
+/* $Id: advansys.h,v 1.18 1999/11/29 21:47:16 bobf Exp bobf $ */
 
 /*
  * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
@@ -40,9 +40,20 @@ const char *advansys_info(struct Scsi_Host *);
 int advansys_command(Scsi_Cmnd *);
 int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 int advansys_abort(Scsi_Cmnd *);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
+int advansys_reset(Scsi_Cmnd *);
+#else /* version >= v1.3.89 */
 int advansys_reset(Scsi_Cmnd *, unsigned int);
+#endif /* version >= v1.3.89 */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+int advansys_biosparam(Disk *, int, int[]);
+#else /* version >= v1.3.0 */
 int advansys_biosparam(Disk *, kdev_t, int[]);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
+extern struct proc_dir_entry proc_scsi_advansys;
+#endif /* version < v2.3.28 */
 int advansys_proc_info(char *, char **, off_t, int, int, int);
+#endif /* version >= v1.3.0 */
 
 /* init/main.c setup function */
 void advansys_setup(char *, int *);
@@ -50,6 +61,118 @@ void advansys_setup(char *, int *);
 /*
  * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h.
  */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+#define ADVANSYS { \
+    NULL,                     /* struct SHT *next */ \
+    NULL,                     /* int *usage_count */ \
+    "advansys",               /* char *name */ \
+    advansys_detect,          /* int (*detect)(struct SHT *) */ \
+    advansys_release,         /* int (*release)(struct Scsi_Host *) */ \
+    advansys_info,            /* const char *(*info)(struct Scsi_Host *) */ \
+    advansys_command,         /* int (*command)(Scsi_Cmnd *) */ \
+    advansys_queuecommand, \
+            /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
+    advansys_abort,           /* int (*abort)(Scsi_Cmnd *) */ \
+    advansys_reset,           /* int (*reset)(Scsi_Cmnd *) */ \
+    NULL,                     /* int (*slave_attach)(int, int) */ \
+    advansys_biosparam,       /* int (* bios_param)(Disk *, int, int []) */ \
+    /* \
+     * The following fields are set per adapter in advansys_detect(). \
+     */ \
+    0,                        /* int can_queue */ \
+    0,                        /* int this_id */ \
+    0,                        /* short unsigned int sg_tablesize */ \
+    0,                        /* short cmd_per_lun */ \
+    0,                        /* unsigned char present */    \
+    /* \
+     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+     * must be set. The flag will be cleared in advansys_detect for non-ISA \
+     * adapters. Refer to the comment in scsi_module.c for more information. \
+     */ \
+    1,                        /* unsigned unchecked_isa_dma:1 */ \
+    /* \
+     * All adapters controlled by this driver are capable of large \
+     * scatter-gather lists. According to the mid-level SCSI documentation \
+     * this obviates any performance gain provided by setting \
+     * 'use_clustering'. But empirically while CPU utilization is increased \
+     * by enabling clustering, I/O throughput increases as well. \
+     */ \
+    ENABLE_CLUSTERING,        /* unsigned use_clustering:1 */ \
+}
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75)
+#define ADVANSYS { \
+    NULL,                    /* struct SHT *next */ \
+    NULL, \
+        /* version < v2.1.23 long *usage_count */ \
+        /* version >= v2.1.23 struct module * */ \
+    &proc_scsi_advansys,     /* struct proc_dir_entry *proc_dir */ \
+    advansys_proc_info,    \
+        /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \
+    "advansys",              /* const char *name */ \
+    advansys_detect,         /* int (*detect)(struct SHT *) */ \
+    advansys_release,        /* int (*release)(struct Scsi_Host *) */ \
+    advansys_info,           /* const char *(*info)(struct Scsi_Host *) */ \
+    advansys_command,        /* int (*command)(Scsi_Cmnd *) */ \
+    advansys_queuecommand, \
+        /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
+    advansys_abort,          /* int (*abort)(Scsi_Cmnd *) */ \
+    advansys_reset, \
+        /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \
+        /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \
+    NULL,                    /* int (*slave_attach)(int, int) */ \
+    advansys_biosparam,      /* int (* bios_param)(Disk *, kdev_t, int []) */ \
+    /* \
+     * The following fields are set per adapter in advansys_detect(). \
+     */ \
+    0,                        /* int can_queue */ \
+    0,                        /* int this_id */ \
+    0,                        /* short unsigned int sg_tablesize */ \
+    0,                        /* short cmd_per_lun */ \
+    0,                        /* unsigned char present */    \
+    /* \
+     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+     * must be set. The flag will be cleared in advansys_detect for non-ISA \
+     * adapters. Refer to the comment in scsi_module.c for more information. \
+     */ \
+    1,                        /* unsigned unchecked_isa_dma:1 */ \
+    /* \
+     * All adapters controlled by this driver are capable of large \
+     * scatter-gather lists. According to the mid-level SCSI documentation \
+     * this obviates any performance gain provided by setting \
+     * 'use_clustering'. But empirically while CPU utilization is increased \
+     * by enabling clustering, I/O throughput increases as well. \
+     */ \
+    ENABLE_CLUSTERING,        /* unsigned use_clustering:1 */ \
+}
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
+#define ADVANSYS { \
+    proc_dir:     &proc_scsi_advansys, \
+    proc_info:    advansys_proc_info, \
+    name:         "advansys", \
+    detect:       advansys_detect, \
+    release:      advansys_release, \
+    info:         advansys_info, \
+    command:      advansys_command, \
+    queuecommand: advansys_queuecommand, \
+    abort:        advansys_abort, \
+    reset:        advansys_reset, \
+    bios_param:   advansys_biosparam, \
+    /* \
+     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+     * must be set. The flag will be cleared in advansys_detect for non-ISA \
+     * adapters. Refer to the comment in scsi_module.c for more information. \
+     */ \
+    unchecked_isa_dma: 1, \
+    /* \
+     * All adapters controlled by this driver are capable of large \
+     * scatter-gather lists. According to the mid-level SCSI documentation \
+     * this obviates any performance gain provided by setting \
+     * 'use_clustering'. But empirically while CPU utilization is increased \
+     * by enabling clustering, I/O throughput increases as well. \
+     */ \
+    use_clustering: ENABLE_CLUSTERING, \
+}
+#else /* version >= v2.3.28 */
 #define ADVANSYS { \
     proc_name:    "advansys", \
     proc_info:    advansys_proc_info, \
@@ -61,7 +184,7 @@ void advansys_setup(char *, int *);
     queuecommand: advansys_queuecommand, \
     abort:        advansys_abort, \
     reset:        advansys_reset, \
-    bios_param:    advansys_biosparam, \
+    bios_param:   advansys_biosparam, \
     /* \
      * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
      * must be set. The flag will be cleared in advansys_detect for non-ISA \
@@ -77,4 +200,5 @@ void advansys_setup(char *, int *);
      */ \
     use_clustering: ENABLE_CLUSTERING, \
 }
+#endif /* version >= v2.3.28 */
 #endif /* _ADVANSYS_H */
index 67c026bc29ed3294e27aded139dffd45f9033d74..38550e1d30545fa0a11ccbe17cb3685289d31956 100644 (file)
@@ -1,13 +1,6 @@
 /* aha152x.c -- Adaptec AHA-152x driver
- * Author: Jürgen E. Fischer, fischer@et-inf.fho-emden.de
- * Copyright 1993, 1994, 1995, 1996 Jürgen E. Fischer
- *
- *
- * This driver is based on
- *   fdomain.c -- Future Domain TMC-16x0 driver
- * which is
- *   Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
- *
+ * Author: Jürgen E. Fischer, fischer@norbit.de
+ * Copyright 1993-1999 Jürgen E. Fischer
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * General Public License for more details.
  *
  *
- * $Id: aha152x.c,v 1.18 1996/09/07 20:10:40 fischer Exp $
+ * $Id: aha152x.c,v 2.0 1999/12/25 15:07:32 fischer Exp fischer $
  *
  * $Log: aha152x.c,v $
+ * Revision 2.0  1999/12/25 15:07:32  fischer
+ * - interrupt routine completly reworked
+ * - basic support for new eh code
+ *
+ * Revision 1.21  1999/11/10 23:46:36  fischer
+ * - default to synchronous operation
+ * - synchronous negotiation fixed
+ * - added timeout to loops
+ * - debugging output can be controlled through procfs
+ *
+ * Revision 1.20  1999/11/07 18:37:31  fischer
+ * - synchronous operation works
+ * - resid support for sg driver
+ *
+ * Revision 1.19  1999/11/02 22:39:59  fischer
+ * - moved leading comments to README.aha152x
+ * - new additional module parameters
+ * - updates for 2.3
+ * - support for the Tripace TC1550 controller
+ * - interrupt handling changed
+ *
  * Revision 1.18  1996/09/07 20:10:40  fischer
  * - fixed can_queue handling (multiple outstanding commands working again)
  *
  *
  *
  **************************************************************************
-
-
-
- DESCRIPTION:
-
- This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI
- host adapters.
-
-
- CONFIGURATION ARGUMENTS:
-
- IOPORT        base io address                           (0x340/0x140)
- IRQ           interrupt level                           (9-12; default 11)
- SCSI_ID       scsi id of controller                     (0-7; default 7)
- RECONNECT     allow targets to disconnect from the bus  (0/1; default 1 [on])
- PARITY        enable parity checking                    (0/1; default 1 [on])
- SYNCHRONOUS   enable synchronous transfers              (0/1; default 0 [off])
- (NOT WORKING YET)
- DELAY:        bus reset delay                           (default 100)
- EXT_TRANS:    enable extended translation               (0/1: default 0 [off])
- (see NOTES below)
-
- COMPILE TIME CONFIGURATION (put into AHA152X in drivers/scsi/Makefile):
-
- -DAUTOCONF
- use configuration the controller reports (AHA-152x only)
-
- -DSKIP_BIOSTEST
- Don't test for BIOS signature (AHA-1510 or disabled BIOS)
-
- -DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
- override for the first controller 
-
- -DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
- override for the second controller
-
-
- LILO COMMAND LINE OPTIONS:
-
- aha152x=<IOPORT>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY> [,<EXT_TRANS]]]]]]]
-
- The normal configuration can be overridden by specifying a command line.
- When you do this, the BIOS test is skipped. Entered values have to be
- valid (known).  Don't use values that aren't supported under normal
- operation.  If you think that you need other values: contact me.
- For two controllers use the aha152x statement twice.
-
-
- SYMBOLS FOR MODULE CONFIGURATION:
-
- aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
- configuration override of first controller
-
-
- aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
- configuration override of second controller
-
-
- NOTES ON EXT_TRANS: 
-
- SCSI uses block numbers to address blocks/sectors on a device.
- The BIOS uses a cylinder/head/sector addressing scheme (C/H/S)
- scheme instead.  DOS expects a BIOS or driver that understands this
- C/H/S addressing.
-
- The number of cylinders/heads/sectors is called geometry and is required
- as base for requests in C/H/S addressing.  SCSI only knows about the
- total capacity of disks in blocks (sectors).
-
- Therefore the SCSI BIOS/DOS driver has to calculate a logical/virtual
- geometry just to be able to support that addressing scheme.  The geometry
- returned by the SCSI BIOS is a pure calculation and has nothing to
- do with the real/physical geometry of the disk (which is usually
- irrelevant anyway).
-
- Basically this has no impact at all on Linux, because it also uses block
- instead of C/H/S addressing.  Unfortunately C/H/S addressing is also used
- in the partition table and therefore every operating system has to know
- the right geometry to be able to interpret it.
-
- Moreover there are certain limitations to the C/H/S addressing scheme,
- namely the address space is limited to upto 255 heads, upto 63 sectors
- and a maximum of 1023 cylinders.
-
- The AHA-1522 BIOS calculates the geometry by fixing the number of heads
- to 64, the number of sectors to 32 and by calculating the number of
- cylinders by dividing the capacity reported by the disk by 64*32 (1 MB).
- This is considered to be the default translation.
-
- With respect to the limit of 1023 cylinders using C/H/S you can only
- address the first GB of your disk in the partition table.  Therefore
- BIOSes of some newer controllers based on the AIC-6260/6360 support
- extended translation.  This means that the BIOS uses 255 for heads,
- 63 for sectors and then divides the capacity of the disk by 255*63
- (about 8 MB), as soon it sees a disk greater than 1 GB.  That results
- in a maximum of about 8 GB addressable diskspace in the partition table
- (but there are already bigger disks out there today).
-
- To make it even more complicated the translation mode might/might
- not be configurable in certain BIOS setups.
-
- This driver does some more or less failsafe guessing to get the
- geometry right in most cases:
-
- - for disks<1GB: use default translation (C/32/64)
- - for disks>1GB:
- - take current geometry from the partition table
- (using scsicam_bios_param and accept only `valid' geometries,
- ie. either (C/32/64) or (C/63/255)).  This can be extended
- translation even if it's not enabled in the driver.
- - if that fails, take extended translation if enabled by override,
- kernel or module parameter, otherwise take default translation and
- ask the user for verification.  This might on not yet partitioned
- disks or
-
-
- REFERENCES USED:
-
- "AIC-6260 SCSI Chip Specification", Adaptec Corporation.
-
- "SCSI COMPUTER SYSTEM INTERFACE - 2 (SCSI-2)", X3T9.2/86-109 rev. 10h
-
- "Writing a SCSI device driver for Linux", Rik Faith (faith@cs.unc.edu)
-
- "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu)
-
- "Adaptec 1520/1522 User's Guide", Adaptec Corporation.
-
- Michael K. Johnson (johnsonm@sunsite.unc.edu)
-
- Drew Eckhardt (drew@cs.colorado.edu)
-
- Eric Youngdale (ericy@cais.com) 
-
- special thanks to Eric Youngdale for the free(!) supplying the
- documentation on the chip.
+ see README.aha152x for configuration details
 
  **************************************************************************/
 
-#ifdef PCMCIA
+#if defined(PCMCIA)
 #define MODULE
 #endif
 
 #include <linux/module.h>
 
-#ifdef PCMCIA
+#if defined(PCMCIA)
 #undef MODULE
 #endif
 
 #include <linux/string.h>
 #include <linux/wait.h>
 #include <linux/ioport.h>
+#include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <asm/semaphore.h>
+#include <linux/spinlock.h>
 
 #include "aha152x.h"
 #include <linux/stat.h>
 #error define AUTOCONF or SETUP0
 #endif
 
-#if defined(DEBUG_AHA152X)
-
-#undef  SKIP_PORTS             /* don't display ports */
-
-#undef  DEBUG_QUEUE            /* debug queue() */
-#undef  DEBUG_RESET            /* debug reset() */
-#undef  DEBUG_INTR             /* debug intr() */
-#undef  DEBUG_SELECTION                /* debug selection part in intr() */
-#undef  DEBUG_MSGO             /* debug message out phase in intr() */
-#undef  DEBUG_MSGI             /* debug message in phase in intr() */
-#undef  DEBUG_STATUS           /* debug status phase in intr() */
-#undef  DEBUG_CMD              /* debug command phase in intr() */
-#undef  DEBUG_DATAI            /* debug data in phase in intr() */
-#undef  DEBUG_DATAO            /* debug data out phase in intr() */
-#undef  DEBUG_ABORT            /* debug abort() */
-#undef  DEBUG_DONE             /* debug done() */
-#undef  DEBUG_BIOSPARAM                /* debug biosparam() */
-
-#undef  DEBUG_RACE             /* debug race conditions */
-#undef  DEBUG_PHASES           /* debug phases (useful to trace) */
-#undef  DEBUG_QUEUES           /* debug reselection */
-
-/* recently used for debugging */
-#if 0
-#endif
-
-#define DEBUG_SELECTION
-#define DEBUG_PHASES
-#define DEBUG_RESET
-#define DEBUG_ABORT
-
-#define DEBUG_DEFAULT (debug_reset|debug_abort)
-
-#endif
-
-/* END OF DEFINES */
+#if defined(AHA152X_DEBUG)
+#define DEBUG_DEFAULT debug_eh
+
+#define DPRINTK(when,msgs...) \
+       do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0)
+
+#define DO_LOCK(flags) \
+       do { \
+               if(QLOCK.lock) { \
+                       DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+               } \
+               DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+               spin_lock_irqsave(&QLOCK,flags); \
+               DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+               QLOCKER=__FUNCTION__; \
+               QLOCKERL=__LINE__; \
+       } while(0)
+
+#define DO_UNLOCK(flags)       \
+       do { \
+               DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+               spin_unlock_irqrestore(&QLOCK,flags); \
+               DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+               QLOCKER="(not locked)"; \
+               QLOCKERL=0; \
+       } while(0)
 
-extern long loops_per_sec;
+#else
+#define DPRINTK(when,msgs...)
+#define        DO_LOCK(flags)          spin_lock_irqsave(&QLOCK,flags)
+#define        DO_UNLOCK(flags)        spin_unlock_irqrestore(&QLOCK,flags)
+#define DEBUG_DEFAULT  0
+#endif
+
+#define LEAD           "(scsi%d:%d:%d) "
+#define WARN_LEAD      KERN_WARNING    LEAD
+#define INFO_LEAD      KERN_INFO       LEAD
+#define NOTE_LEAD      KERN_NOTICE     LEAD
+#define ERR_LEAD       KERN_ERR        LEAD
+#define DEBUG_LEAD     KERN_DEBUG      LEAD
+#define CMDINFO(cmd) \
+                       (cmd) ? ((cmd)->host->host_no) : -1, \
+                        (cmd) ? ((cmd)->target & 0x0f) : -1, \
+                       (cmd) ? ((cmd)->lun & 0x07) : -1
 
 #define DELAY_DEFAULT 100
 
-/* some additional "phases" for getphase() */
-#define P_BUSFREE  1
-#define P_PARITY   2
-
 /* possible irq range */
-#ifdef PCMCIA
+#if defined(PCMCIA)
 #define IRQ_MIN 0
 #define IRQ_MAX 16
 #else
@@ -421,33 +306,76 @@ extern long loops_per_sec;
 #define IRQS    IRQ_MAX-IRQ_MIN+1
 
 enum {
-       not_issued = 0x0001,
-       in_selection = 0x0002,
-       disconnected = 0x0004,
-       aborted = 0x0008,
-       sent_ident = 0x0010,
-       in_other = 0x0020,
-       in_sync = 0x0040,
-       sync_ok = 0x0080,
+       not_issued      = 0x0001,       /* command not yet issued */
+       selecting       = 0x0002,       /* target is beeing selected */
+       identified      = 0x0004,       /* IDENTIFY was sent */
+       disconnected    = 0x0008,       /* target disconnected */
+       completed       = 0x0010,       /* target sent COMMAND COMPLETE */ 
+       aborted         = 0x0020,       /* ABORT was sent */
+       resetted        = 0x0040,       /* BUS DEVICE RESET was sent */
+       spiordy         = 0x0080,       /* waiting for SPIORDY to raise */
+       syncneg         = 0x0100,       /* synchronous negotiation in progress */
+       aborting        = 0x0200,       /* ABORT is pending */
+       resetting       = 0x0400,       /* BUS DEVICE RESET is pending */
 };
 
 #if defined(MODULE)
-#if defined(DEBUG_AHA152X)
-int aha152x[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
-int aha152x1[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
-MODULE_PARM(aha152x, "1-9i");
-MODULE_PARM(aha152x1, "1-9i");
-#else
-int aha152x[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
-int aha152x1[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+MODULE_AUTHOR("Jürgen Fischer");
+MODULE_DESCRIPTION(AHA152X_REVID);
+MODULE_PARM(io, "1-2i");
+MODULE_PARM_DESC(io,"base io address of controller");
+static int io[] = {0, 0};
+
+MODULE_PARM(irq, "1-2i");
+MODULE_PARM_DESC(irq,"interrupt for controller");
+static int irq[] = {0, 0};
+
+MODULE_PARM(scsiid, "1-2i");
+MODULE_PARM_DESC(scsiid,"scsi id of controller");
+static int scsiid[] = {7, 7};
+
+MODULE_PARM(reconnect, "1-2i");
+MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
+static int reconnect[] = {1, 1};
+
+MODULE_PARM(parity, "1-2i");
+MODULE_PARM_DESC(parity,"use scsi parity");
+static int parity[] = {1, 1};
+
+MODULE_PARM(sync, "1-2i");
+MODULE_PARM_DESC(sync,"use synchronous transfers");
+static int sync[] = {1, 1};
+
+MODULE_PARM(delay, "1-2i");
+MODULE_PARM_DESC(delay,"scsi reset delay");
+static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
+
+MODULE_PARM(exttrans, "1-2i");
+MODULE_PARM_DESC(exttrans,"use extended translation");
+static int exttrans[] = {0, 0};
+
+#if !defined(AHA152X_DEBUG)
 MODULE_PARM(aha152x, "1-8i");
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+static int aha152x[]   = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+
 MODULE_PARM(aha152x1, "1-8i");
-#endif
-#endif
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+static int aha152x1[]  = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+#else
+MODULE_PARM(debug, "1-2i");
+MODULE_PARM_DESC(debug, "flags for driver debugging");
+static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT};
+
+MODULE_PARM(aha152x, "1-9i");
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+
+MODULE_PARM(aha152x1, "1-9i");
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+#endif /* !defined(AHA152X_DEBUG) */
+#endif /* MODULE */
 
 /* set by aha152x_setup according to the command line */
 static int setup_count = 0;
@@ -461,7 +389,8 @@ static struct aha152x_setup {
        int synchronous;
        int delay;
        int ext_trans;
-#ifdef DEBUG_AHA152X
+       int tc1550;
+#if defined(AHA152X_DEBUG)
        int debug;
 #endif
        char *conf;
@@ -469,73 +398,259 @@ static struct aha152x_setup {
 
 static struct Scsi_Host *aha152x_host[IRQS];
 
-#define HOSTDATA(shpnt)   ((struct aha152x_hostdata *) &shpnt->hostdata)
-#define CURRENT_SC        (HOSTDATA(shpnt)->current_SC)
-#define ISSUE_SC          (HOSTDATA(shpnt)->issue_SC)
-#define DISCONNECTED_SC   (HOSTDATA(shpnt)->disconnected_SC)
-#define DELAY             (HOSTDATA(shpnt)->delay)
-#define EXT_TRANS         (HOSTDATA(shpnt)->ext_trans)
-#define SYNCRATE          (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target])
-#define MSG(i)            (HOSTDATA(shpnt)->message[i])
-#define MSGLEN            (HOSTDATA(shpnt)->message_len)
-#define ADDMSG(x)         (MSG(MSGLEN++)=x)
+/*
+ * internal states of the host
+ *
+ */ 
+enum aha152x_state {
+       idle=0,
+       unknown,
+       seldo,
+       seldi,
+       selto,
+       busfree,
+       msgo,
+       cmd,
+       msgi,
+       status,
+       datai,
+       datao,
+       parerr,
+       rsti,
+       maxstate
+};
 
+/*
+ * current state information of the host
+ *
+ */
 struct aha152x_hostdata {
        Scsi_Cmnd *issue_SC;
+               /* pending commands to issue */
+
        Scsi_Cmnd *current_SC;
+               /* current command on the bus */
+
        Scsi_Cmnd *disconnected_SC;
-       int aborting;
-       int abortion_complete;
-       int abort_result;
-       int commands;
+               /* commands that disconnected */
 
-       int reconnect;
-       int parity;
-       int synchronous;
-       int delay;
-       int ext_trans;
+       Scsi_Cmnd *done_SC;
+               /* command that was completed */
 
-       int swint;
-       int service;
+       spinlock_t lock;
+               /* host lock */
 
-       unsigned char syncrate[8];
+#if defined(AHA152X_DEBUG)
+       char *locker;   /* which function has the lock */
+       int lockerl;    /* where did it get it */
 
-       unsigned char message[256];
-       int message_len;
+       int debug;      /* current debugging setting */
+#endif
 
-#ifdef DEBUG_AHA152X
-       int debug;
+#if defined(AHA152X_STAT)
+       int           total_commands;
+       int           disconnections;
+       int           busfree_without_any_action;
+       int           busfree_without_old_command;
+       int           busfree_without_new_command;
+       int           busfree_without_done_command;
+       int           busfree_with_check_condition;
+       int           count[maxstate];
+       int           count_trans[maxstate];
+       unsigned long time[maxstate];
 #endif
+
+       int commands;           /* current number of commands */
+
+       int reconnect;          /* disconnection allowed */
+       int parity;             /* parity checking enabled */
+       int synchronous;        /* synchronous transferes enabled */
+       int delay;              /* reset out delay */
+       int ext_trans;          /* extended translation enabled */
+
+       int swint;              /* software-interrupt was fired during detect() */
+       int service;            /* bh needs to be run */
+       int in_intr;            /* bh is running */
+
+       /* current state,
+          previous state,
+          last state different from current state */
+       enum aha152x_state state, prevstate, laststate;
+
+       int target;
+               /* reconnecting target */
+
+       unsigned char syncrate[8];
+               /* current synchronous transfer agreements */
+
+       unsigned char syncneg[8];
+               /* 0: no negotiation;
+                * 1: negotiation in progress;
+                * 2: negotiation completed
+                */
+
+       int cmd_i;
+               /* number of sent bytes of current command */
+
+       int msgi_len;
+               /* number of received message bytes */
+       unsigned char msgi[256];
+               /* received message bytes */
+
+       int msgo_i, msgo_len;   
+               /* number of sent bytes and length of current messages */
+       unsigned char msgo[256];
+               /* pending messages */
+
+       int data_len;
+               /* number of sent/received bytes in dataphase */
+
+       unsigned long io_port0;
+       unsigned long io_port1;
+};
+
+
+/*
+ * host specific command extension
+ *
+ */
+struct aha152x_scdata {
+       Scsi_Cmnd *next;        /* next sc in queue */
+       Scsi_Cmnd *done;        /* done command */
+       struct semaphore *sem;  /* semaphore to block on */
 };
 
-static void aha152x_intr(int irq, void *dev_id, struct pt_regs *);
-void aha152x_done(struct Scsi_Host *shpnt, int error);
-void aha152x_setup(char *str, int *ints);
-int aha152x_checksetup(struct aha152x_setup *setup);
 
-static void aha152x_reset_ports(struct Scsi_Host *shpnt);
-static void aha152x_panic(struct Scsi_Host *shpnt, char *msg);
+/* access macros for hostdata */
+
+#define HOSTDATA(shpnt)                ((struct aha152x_hostdata *) &shpnt->hostdata)
+
+#define HOSTNO                 ((shpnt)->host_no)
+
+#define CURRENT_SC             (HOSTDATA(shpnt)->current_SC)
+#define DONE_SC                        (HOSTDATA(shpnt)->done_SC)
+#define ISSUE_SC               (HOSTDATA(shpnt)->issue_SC)
+#define DISCONNECTED_SC                (HOSTDATA(shpnt)->disconnected_SC)
+#define QLOCK                  (HOSTDATA(shpnt)->lock)
+#define QLOCKER                        (HOSTDATA(shpnt)->locker)
+#define QLOCKERL               (HOSTDATA(shpnt)->lockerl)
+
+#define STATE                  (HOSTDATA(shpnt)->state)
+#define PREVSTATE              (HOSTDATA(shpnt)->prevstate)
+#define LASTSTATE              (HOSTDATA(shpnt)->laststate)
+
+#define RECONN_TARGET          (HOSTDATA(shpnt)->target)
+
+#define CMD_I                  (HOSTDATA(shpnt)->cmd_i)
+
+#define MSGO(i)                        (HOSTDATA(shpnt)->msgo[i])
+#define MSGO_I                 (HOSTDATA(shpnt)->msgo_i)
+#define MSGOLEN                        (HOSTDATA(shpnt)->msgo_len)
+#define ADDMSGO(x)             (MSGOLEN<256 ? MSGO(MSGOLEN++)=x : aha152x_error(shpnt,"MSGO overflow"))
+
+#define MSGI(i)                        (HOSTDATA(shpnt)->msgi[i])
+#define MSGILEN                        (HOSTDATA(shpnt)->msgi_len)
+#define ADDMSGI(x)             (MSGILEN<256 ? MSGI(MSGILEN++)=x : aha152x_error(shpnt,"MSGI overflow"))
+
+#define DATA_LEN               (HOSTDATA(shpnt)->data_len)
+
+#define SYNCRATE               (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target])
+#define SYNCNEG                        (HOSTDATA(shpnt)->syncneg[CURRENT_SC->target])
+
+#define DELAY                  (HOSTDATA(shpnt)->delay)
+#define EXT_TRANS              (HOSTDATA(shpnt)->ext_trans)
+#define TC1550                 (HOSTDATA(shpnt)->tc1550)
+#define RECONNECT              (HOSTDATA(shpnt)->reconnect)
+#define PARITY                 (HOSTDATA(shpnt)->parity)
+#define SYNCHRONOUS            (HOSTDATA(shpnt)->synchronous)
+
+#define HOSTIOPORT0            (HOSTDATA(shpnt)->io_port0)
+#define HOSTIOPORT1            (HOSTDATA(shpnt)->io_port1)
 
+#define SCDATA(SCpnt)          ((struct aha152x_scdata *) (SCpnt)->host_scribble)
+#define SCNEXT(SCpnt)          SCDATA(SCpnt)->next
+#define SCDONE(SCpnt)          SCDATA(SCpnt)->done
+#define SCSEM(SCpnt)           SCDATA(SCpnt)->sem
+
+
+/* state handling */
+static void seldi_run(struct Scsi_Host *shpnt);
+static void seldo_run(struct Scsi_Host *shpnt);
+static void selto_run(struct Scsi_Host *shpnt);
+static void busfree_run(struct Scsi_Host *shpnt);
+
+static void msgo_init(struct Scsi_Host *shpnt);
+static void msgo_run(struct Scsi_Host *shpnt);
+static void msgo_end(struct Scsi_Host *shpnt);
+
+static void cmd_init(struct Scsi_Host *shpnt);
+static void cmd_run(struct Scsi_Host *shpnt);
+static void cmd_end(struct Scsi_Host *shpnt);
+
+static void datai_init(struct Scsi_Host *shpnt);
+static void datai_run(struct Scsi_Host *shpnt);
+static void datai_end(struct Scsi_Host *shpnt);
+
+static void datao_init(struct Scsi_Host *shpnt);
+static void datao_run(struct Scsi_Host *shpnt);
+static void datao_end(struct Scsi_Host *shpnt);
+
+static void status_run(struct Scsi_Host *shpnt);
+
+static void msgi_run(struct Scsi_Host *shpnt);
+static void msgi_end(struct Scsi_Host *shpnt);
+
+static void parerr_run(struct Scsi_Host *shpnt);
+static void rsti_run(struct Scsi_Host *shpnt);
+
+static void complete(struct Scsi_Host *shpnt);
+
+/*
+ * driver states
+ *
+ */
+static struct {
+       char            *name;
+       void            (*init)(struct Scsi_Host *);
+       void            (*run)(struct Scsi_Host *);
+       void            (*end)(struct Scsi_Host *);
+       int             spio;
+} states[] = {
+       { "idle",       0,              0,              0,              0},
+       { "unknown",    0,              0,              0,              0},
+       { "seldo",      0,              seldo_run,      0,              0},
+       { "seldi",      0,              seldi_run,      0,              0},
+       { "selto",      0,              selto_run,      0,              0},
+       { "busfree",    0,              busfree_run,    0,              0},
+       { "msgo",       msgo_init,      msgo_run,       msgo_end,       1},
+       { "cmd",        cmd_init,       cmd_run,        cmd_end,        1},
+       { "msgi",       0,              msgi_run,       msgi_end,       1},
+       { "status",     0,              status_run,     0,              1},
+       { "datai",      datai_init,     datai_run,      datai_end,      0},
+       { "datao",      datao_init,     datao_run,      datao_end,      0},
+       { "parerr",     0,              parerr_run,     0,              0},
+       { "rsti",       0,              rsti_run,       0,              0},
+};
+
+/* setup & interrupt */
+static void intr(int irq, void *dev_id, struct pt_regs *);
+static void reset_ports(struct Scsi_Host *shpnt);
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
+static void done(struct Scsi_Host *shpnt, int error);
+static int checksetup(struct aha152x_setup *setup);
+
+/* diagnostics */
 static void disp_ports(struct Scsi_Host *shpnt);
 static void show_command(Scsi_Cmnd * ptr);
 static void show_queues(struct Scsi_Host *shpnt);
 static void disp_enintr(struct Scsi_Host *shpnt);
 
-#if defined(DEBUG_RACE)
-static void enter_driver(const char *);
-static void leave_driver(const char *);
-#endif
-
-/* possible i/o addresses for the AIC-6260 */
-static unsigned short ports[] =
-{
-       0x340,                  /* default first */
-       0x140
-};
+/* possible i/o addresses for the AIC-6260; default first */
+static unsigned short ports[] = { 0x340, 0x140 };
 #define PORT_COUNT (sizeof(ports) / sizeof(unsigned short))
 
 #if !defined(SKIP_BIOSTEST)
-/* possible locations for the Adaptec BIOS */
+/* possible locations for the Adaptec BIOS; defaults first */
 static unsigned int addresses[] =
 {
        0xdc000,                /* default first */
@@ -562,71 +677,52 @@ static struct signature {
        int sig_offset;
        int sig_length;
 } signatures[] =
-
 {
-       {
-               "Adaptec AHA-1520 BIOS", 0x102e, 21
-       },                      /* Adaptec 152x */
-       {
-               "Adaptec AHA-1520B", 0x0b, 19
-       },                      /* Adaptec 152x rev B */
-       {
-               "Adaptec ASW-B626 BIOS", 0x1029, 21
-       },                      /* on-board controller */
-       {
-               "Adaptec BIOS: ASW-B626", 0x0f, 22
-       },                      /* on-board controller */
-       {
-               "Adaptec ASW-B626 S2", 0x2e6c, 19
-       },                      /* on-board controller */
-       {
-               "Adaptec BIOS:AIC-6360", 0xc, 21
-       },                      /* on-board controller */
-       {
-               "ScsiPro SP-360 BIOS", 0x2873, 19
-       },                      /* ScsiPro-Controller  */
-       {
-               "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26
-       },                      /* Gigabyte Local-Bus-SCSI */
-       {
-               "Adaptec BIOS:AVA-282X", 0xc, 21
-       },                      /* Adaptec 282x */
-       {
-               "Adaptec IBM Dock II SCSI", 0x2edd, 24
-       },                      /* IBM Thinkpad Dock II */
-       {
-               "Adaptec BIOS:AHA-1532P", 0x1c, 22
-       },                      /* IBM Thinkpad Dock II SCSI */
-       {
-               "DTC3520A Host Adapter BIOS", 0x318a, 26
-       },                      /* DTC 3520A ISA SCSI */
+       { "Adaptec AHA-1520 BIOS",      0x102e, 21 },
+               /* Adaptec 152x */
+       { "Adaptec AHA-1520B",          0x000b, 19 },
+               /* Adaptec 152x rev B */
+       { "Adaptec ASW-B626 BIOS",      0x1029, 21 },
+               /* on-board controller */
+       { "Adaptec BIOS: ASW-B626",     0x000f, 22 },
+               /* on-board controller */
+       { "Adaptec ASW-B626 S2",        0x2e6c, 19 },
+               /* on-board controller */
+       { "Adaptec BIOS:AIC-6360",      0x000c, 21 },
+               /* on-board controller */
+       { "ScsiPro SP-360 BIOS",        0x2873, 19 },
+               /* ScsiPro-Controller  */
+       { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
+               /* Gigabyte Local-Bus-SCSI */
+       { "Adaptec BIOS:AVA-282X",      0x000c, 21 },
+               /* Adaptec 282x */
+       { "Adaptec IBM Dock II SCSI",   0x2edd, 24 },
+               /* IBM Thinkpad Dock II */
+       { "Adaptec BIOS:AHA-1532P",     0x001c, 22 },
+               /* IBM Thinkpad Dock II SCSI */
+       { "DTC3520A Host Adapter BIOS", 0x318a, 26 },
+               /* DTC 3520A ISA SCSI */
 };
 
 #define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature))
 #endif
 
 
-static void do_pause(unsigned amount)
-{                              /* Pause for amount*10 milliseconds */
-       unsigned long the_time = jiffies + amount;      /* 0.01 seconds per jiffy */
-
-       while (time_before(jiffies, the_time))
-               barrier();
-}
-
 /*
  *  queue services:
+ *
  */
-static inline void append_SC(Scsi_Cmnd ** SC, Scsi_Cmnd * new_SC)
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
 {
        Scsi_Cmnd *end;
 
-       new_SC->host_scribble = (unsigned char *) NULL;
+       SCNEXT(new_SC) = NULL;
        if (!*SC)
                *SC = new_SC;
        else {
-               for (end = *SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble);
-               end->host_scribble = (unsigned char *) new_SC;
+               for (end = *SC; SCNEXT(end); end = SCNEXT(end))
+                       ;
+               SCNEXT(end) = new_SC;
        }
 }
 
@@ -635,135 +731,113 @@ static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC)
        Scsi_Cmnd *ptr;
 
        ptr = *SC;
-       if (ptr)
-               *SC = (Scsi_Cmnd *) (*SC)->host_scribble;
+       if (ptr) {
+               *SC = SCNEXT(*SC);
+               SCNEXT(ptr)=NULL;
+       }
        return ptr;
 }
 
-static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd ** SC, int target, int lun)
+static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun)
 {
        Scsi_Cmnd *ptr, *prev;
 
        for (ptr = *SC, prev = NULL;
             ptr && ((ptr->target != target) || (ptr->lun != lun));
-            prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+            prev = ptr, ptr = SCNEXT(ptr))
+            ;
 
        if (ptr) {
                if (prev)
-                       prev->host_scribble = ptr->host_scribble;
+                       SCNEXT(prev) = SCNEXT(ptr);
                else
-                       *SC = (Scsi_Cmnd *) ptr->host_scribble;
-       }
-       return ptr;
-}
+                       *SC = SCNEXT(ptr);
 
-/*
- * read inbound byte and wait for ACK to get low
- */
-static void make_acklow(struct Scsi_Host *shpnt)
-{
-       SETPORT(SXFRCTL0, CH1 | SPIOEN);
-       GETPORT(SCSIDAT);
-       SETPORT(SXFRCTL0, CH1);
+               SCNEXT(ptr)=NULL;
+       }
 
-       while (TESTHI(SCSISIG, ACKI))
-               barrier();
+       return ptr;
 }
 
-/*
- * detect current phase more reliable:
- * phase is valid, when the target asserts REQ after we've deasserted ACK.
- *
- * return value is a valid phase or an error code.
- *
- * errorcodes:
- *   P_BUSFREE   BUS FREE phase detected
- *   P_PARITY    parity error in DATA phase
- */
-static int getphase(struct Scsi_Host *shpnt)
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
 {
-       int phase, sstat1;
-
-       while (1) {
-               do {
-                       while (!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE | SCSIRSTI | REQINIT)))
-                               barrier();
-                       if (sstat1 & BUSFREE)
-                               return P_BUSFREE;
-                       if (sstat1 & SCSIRSTI) {
-                               printk("aha152x: RESET IN\n");
-                               SETPORT(SSTAT1, SCSIRSTI);
-                       }
-               } while (TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT));
-
-               SETPORT(SSTAT1, CLRSCSIPERR);
+       Scsi_Cmnd *ptr, *prev;
 
-               phase = GETPORT(SCSISIG) & P_MASK;
+       for (ptr = *SC, prev = NULL;
+            ptr && SCp!=ptr;
+            prev = ptr, ptr = SCNEXT(ptr))
+            ;
 
-               if (TESTHI(SSTAT1, SCSIPERR)) {
-                       if ((phase & (CDO | MSGO)) == 0)        /* DATA phase */
-                               return P_PARITY;
+       if (ptr) {
+               if (prev)
+                       SCNEXT(prev) = SCNEXT(ptr);
+               else
+                       *SC = SCNEXT(ptr);
 
-                       make_acklow(shpnt);
-               } else
-                       return phase;
+               SCNEXT(ptr)=NULL;
        }
+
+       return ptr;
 }
 
-#ifdef PCMCIA
+#if defined(PCMCIA) || !defined(MODULE)
 void aha152x_setup(char *str, int *ints)
 {
-       if (setup_count > 2)
-               panic("aha152x: you can only configure up to two controllers\n");
-
-       setup[setup_count].conf = str;
-       setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340;
-       setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11;
-       setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7;
-       setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1;
-       setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1;
-       setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */ ;
-       setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
-       setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0;
-#ifdef DEBUG_AHA152X
-       setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
+       if(setup_count>2) {
+               printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
+               return;
+       }
+
+       setup[setup_count].conf        = str;
+       setup[setup_count].io_port     = ints[0] >= 1 ? ints[1] : 0x340;
+       setup[setup_count].irq         = ints[0] >= 2 ? ints[2] : 11;
+       setup[setup_count].scsiid      = ints[0] >= 3 ? ints[3] : 7;
+       setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
+       setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
+       setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
+       setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
+       setup[setup_count].ext_trans   = ints[0] >= 8 ? ints[8] : 0;
+#if defined(AHA152X_DEBUG)
+       setup[setup_count].debug       = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
        if (ints[0] > 9) {
-               printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+               printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
                       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n");
 #else
-       if (ints[0] > 8) {
-               printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+       if (ints[0] > 8) {                                                /*}*/
+               printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
                       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
 #endif
-       } else
+               return;
+       } else {
                setup_count++;
+               return;
+       }
 }
-#endif /* PCMCIA */
+#endif
 
-#ifndef MODULE
-static int __init do_aha152x_setup (char * str)
+#if !defined(MODULE)
+static int __init do_setup(char *str)
 {
-       if (setup_count > 2) {
-               printk(KERN_ERR"aha152x: you can only configure up to two
-controllers\n");
-       return 0;
-       }
 
-       setup[setup_count].conf = str;
-       get_option(&str,&setup[setup_count].io_port);
-       get_option(&str,&setup[setup_count].irq);
-       get_option(&str,&setup[setup_count].scsiid);
-       get_option(&str,&setup[setup_count].reconnect);
-       
-       setup_count++;
-       return 1;
+#if defined(AHA152X_DEBUG)
+       int ints[11];
+#else
+       int ints[10];
+#endif
+       int count=setup_count;
+
+       get_options(str, sizeof(ints)/sizeof(int), ints);
+       aha152x_setup(str,ints);
+
+       return count<setup_count;
 }
 
-__setup("aha152x=",do_aha152x_setup);
+__setup("aha152x=", do_setup);
 #endif
+
 /*
  * Test, if port_base is valid.
+ *
  */
 static int aha152x_porttest(int io_port)
 {
@@ -777,24 +851,48 @@ static int aha152x_porttest(int io_port)
                SETPORT(io_port + O_STACK, i);
 
        SETPORT(io_port + O_DMACNTRL1, 0);      /* reset stack pointer */
-       for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++);
+       for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
+               ;
+
+       return (i == 16);
+}
+
+static int tc1550_porttest(int io_port)
+{
+       int i;
+
+       if (check_region(io_port, IO_RANGE))
+               return 0;
+
+       SETPORT(io_port + O_TC_DMACNTRL1, 0);   /* reset stack pointer */
+       for (i = 0; i < 16; i++)
+               SETPORT(io_port + O_STACK, i);
+
+       SETPORT(io_port + O_TC_DMACNTRL1, 0);   /* reset stack pointer */
+       for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
+               ;
 
        return (i == 16);
 }
 
-int aha152x_checksetup(struct aha152x_setup *setup)
+static int checksetup(struct aha152x_setup *setup)
 {
        int i;
 
-#ifndef PCMCIA
-       for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++);
+#if !defined(PCMCIA)
+       for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++)
+               ;
 
        if (i == PORT_COUNT)
                return 0;
 #endif
 
-       if (!aha152x_porttest(setup->io_port))
-               return 0;
+       if(aha152x_porttest(setup->io_port)) {
+          setup->tc1550=0;
+        } else if(tc1550_porttest(setup->io_port)) {
+          setup->tc1550=1;
+        } else
+          return 0;
 
        if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
                return 0;
@@ -818,12 +916,12 @@ int aha152x_checksetup(struct aha152x_setup *setup)
        return 1;
 }
 
-void aha152x_swintr(int irqno, void *dev_id, struct pt_regs *regs)
+static void swintr(int irqno, void *dev_id, struct pt_regs *regs)
 {
        struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
 
        if (!shpnt)
-               panic("aha152x: catched software interrupt for unknown controller.\n");
+               printk(KERN_ERR "aha152x%d: catched software interrupt for unknown controller.\n", HOSTNO);
 
        HOSTDATA(shpnt)->swint++;
 }
@@ -835,29 +933,28 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 #if defined(AUTOCONF)
        aha152x_config conf;
 #endif
-
-       tpnt->proc_name = "aha152x";
+       tpnt->proc_name = "aha152x"; 
 
        for (i = 0; i < IRQS; i++)
                aha152x_host[i] = (struct Scsi_Host *) NULL;
 
        if (setup_count) {
-               printk("aha152x: processing commandline: ");
+               printk(KERN_INFO "aha152x: processing commandline: ");
 
                for (i = 0; i < setup_count; i++)
-                       if (!aha152x_checksetup(&setup[i])) {
-                               printk("\naha152x: %s\n", setup[i].conf);
-                               printk("aha152x: invalid line (controller=%d)\n", i + 1);
+                       if (!checksetup(&setup[i])) {
+                               printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
+                               printk(KERN_ERR "aha152x: invalid line\n");
                        }
                printk("ok\n");
        }
-#ifdef SETUP0
+#if defined(SETUP0)
        if (setup_count < 2) {
                struct aha152x_setup override = SETUP0;
 
                if (setup_count == 0 || (override.io_port != setup[0].io_port))
-                       if (!aha152x_checksetup(&override)) {
-                               printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+                       if (!checksetup(&override)) {
+                               printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
                                       override.io_port,
                                       override.irq,
                                       override.scsiid,
@@ -871,13 +968,13 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
        }
 #endif
 
-#ifdef SETUP1
+#if defined(SETUP1)
        if (setup_count < 2) {
                struct aha152x_setup override = SETUP1;
 
                if (setup_count == 0 || (override.io_port != setup[0].io_port))
-                       if (!aha152x_checksetup(&override)) {
-                               printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+                       if (!checksetup(&override)) {
+                               printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
                                       override.io_port,
                                       override.irq,
                                       override.scsiid,
@@ -892,23 +989,39 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 #endif
 
 #if defined(MODULE)
-       if (setup_count < 2 && aha152x[0] != 0) {
-               setup[setup_count].conf = "";
-               setup[setup_count].io_port = aha152x[0];
-               setup[setup_count].irq = aha152x[1];
-               setup[setup_count].scsiid = aha152x[2];
-               setup[setup_count].reconnect = aha152x[3];
-               setup[setup_count].parity = aha152x[4];
-               setup[setup_count].synchronous = aha152x[5];
-               setup[setup_count].delay = aha152x[6];
-               setup[setup_count].ext_trans = aha152x[7];
-#ifdef DEBUG_AHA152X
-               setup[setup_count].debug = aha152x[8];
+       if (setup_count<2 && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
+               if(aha152x[0]!=0) {
+                       setup[setup_count].conf        = "";
+                       setup[setup_count].io_port     = aha152x[0];
+                       setup[setup_count].irq         = aha152x[1];
+                       setup[setup_count].scsiid      = aha152x[2];
+                       setup[setup_count].reconnect   = aha152x[3];
+                       setup[setup_count].parity      = aha152x[4];
+                       setup[setup_count].synchronous = aha152x[5];
+                       setup[setup_count].delay       = aha152x[6];
+                       setup[setup_count].ext_trans   = aha152x[7];
+#if defined(AHA152X_DEBUG)
+                       setup[setup_count].debug       = aha152x[8];
+#endif
+               } else if(io[0]!=0 || irq[0]!=0) {
+                       if(io[0]!=0)  setup[setup_count].io_port = io[0];
+                       if(irq[0]!=0) setup[setup_count].irq     = irq[0];
+
+                       setup[setup_count].scsiid      = scsiid[0];
+                       setup[setup_count].reconnect   = reconnect[0];
+                       setup[setup_count].parity      = parity[0];
+                       setup[setup_count].synchronous = sync[0];
+                       setup[setup_count].delay       = delay[0];
+                       setup[setup_count].ext_trans   = exttrans[0];
+#if defined(AHA152X_DEBUG)
+                       setup[setup_count].debug       = debug[0];
 #endif
-               if (aha152x_checksetup(&setup[setup_count]))
+               }
+
+               if (checksetup(&setup[setup_count]))
                        setup_count++;
                else
-                       printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
+                       printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
                               setup[setup_count].io_port,
                               setup[setup_count].irq,
                               setup[setup_count].scsiid,
@@ -918,23 +1031,39 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
                               setup[setup_count].delay,
                               setup[setup_count].ext_trans);
        }
-       if (setup_count < 2 && aha152x1[0] != 0) {
-               setup[setup_count].conf = "";
-               setup[setup_count].io_port = aha152x1[0];
-               setup[setup_count].irq = aha152x1[1];
-               setup[setup_count].scsiid = aha152x1[2];
-               setup[setup_count].reconnect = aha152x1[3];
-               setup[setup_count].parity = aha152x1[4];
-               setup[setup_count].synchronous = aha152x1[5];
-               setup[setup_count].delay = aha152x1[6];
-               setup[setup_count].ext_trans = aha152x1[7];
-#ifdef DEBUG_AHA152X
-               setup[setup_count].debug = aha152x1[8];
+
+       if (setup_count < 2 && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
+               if(aha152x1[0]!=0) {
+                       setup[setup_count].conf        = "";
+                       setup[setup_count].io_port     = aha152x1[0];
+                       setup[setup_count].irq         = aha152x1[1];
+                       setup[setup_count].scsiid      = aha152x1[2];
+                       setup[setup_count].reconnect   = aha152x1[3];
+                       setup[setup_count].parity      = aha152x1[4];
+                       setup[setup_count].synchronous = aha152x1[5];
+                       setup[setup_count].delay       = aha152x1[6];
+                       setup[setup_count].ext_trans   = aha152x1[7];
+#if defined(AHA152X_DEBUG)
+                       setup[setup_count].debug       = aha152x1[8];
+#endif
+               } else if(io[1]!=0 || irq[1]!=0) {
+                       if(io[1]!=0)  setup[setup_count].io_port = io[1];
+                       if(irq[1]!=0) setup[setup_count].irq     = irq[1];
+
+                       setup[setup_count].scsiid      = scsiid[1];
+                       setup[setup_count].reconnect   = reconnect[1];
+                       setup[setup_count].parity      = parity[1];
+                       setup[setup_count].synchronous = sync[1];
+                       setup[setup_count].delay       = delay[1];
+                       setup[setup_count].ext_trans   = exttrans[1];
+#if defined(AHA152X_DEBUG)
+                       setup[setup_count].debug       = debug[1];
 #endif
-               if (aha152x_checksetup(&setup[setup_count]))
+               }
+               if (checksetup(&setup[setup_count]))
                        setup_count++;
                else
-                       printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
+                       printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
                               setup[setup_count].io_port,
                               setup[setup_count].irq,
                               setup[setup_count].scsiid,
@@ -953,14 +1082,14 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
                for (i = 0; i < ADDRESS_COUNT && !ok; i++)
                        for (j = 0; (j < SIGNATURE_COUNT) && !ok; j++)
                                ok = isa_check_signature(addresses[i] + signatures[j].sig_offset,
-                                                    signatures[j].signature, signatures[j].sig_length);
+                                                               signatures[j].signature, signatures[j].sig_length);
 
                if (!ok && setup_count == 0)
                        return 0;
 
-               printk("aha152x: BIOS test: passed, ");
+               printk(KERN_INFO "aha152x: BIOS test: passed, ");
 #else
-               printk("aha152x: ");
+               printk(KERN_INFO "aha152x: ");
 #endif                         /* !SKIP_BIOSTEST */
 
                ok = 0;
@@ -971,6 +1100,26 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
                        if (aha152x_porttest(ports[i])) {
                                ok++;
                                setup[setup_count].io_port = ports[i];
+                               setup[setup_count].tc1550  = 0;
+
+                               conf.cf_port =
+                                   (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
+
+                               setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
+                               setup[setup_count].scsiid = conf.cf_id;
+                               setup[setup_count].reconnect = conf.cf_tardisc;
+                               setup[setup_count].parity = !conf.cf_parity;
+                               setup[setup_count].synchronous = conf.cf_syncneg;
+                               setup[setup_count].delay = DELAY_DEFAULT;
+                               setup[setup_count].ext_trans = 0;
+#if defined(AHA152X_DEBUG)
+                               setup[setup_count].debug = DEBUG_DEFAULT;
+#endif
+                               setup_count++;
+                       } else if (tc1550_porttest(ports[i])) {
+                               ok++;
+                               setup[setup_count].io_port = ports[i];
+                               setup[setup_count].tc1550  = 1;
 
                                conf.cf_port =
                                    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
@@ -979,10 +1128,10 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
                                setup[setup_count].scsiid = conf.cf_id;
                                setup[setup_count].reconnect = conf.cf_tardisc;
                                setup[setup_count].parity = !conf.cf_parity;
-                               setup[setup_count].synchronous = 0 /* FIXME: conf.cf_syncneg */ ;
+                               setup[setup_count].synchronous = conf.cf_syncneg;
                                setup[setup_count].delay = DELAY_DEFAULT;
                                setup[setup_count].ext_trans = 0;
-#ifdef DEBUG_AHA152X
+#if defined(AHA152X_DEBUG)
                                setup[setup_count].debug = DEBUG_DEFAULT;
 #endif
                                setup_count++;
@@ -996,40 +1145,75 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 
        printk("detected %d controller(s)\n", setup_count);
 
-       for (i = 0; i < setup_count; i++) {
+       for (i=0; i<setup_count; i++) {
                struct Scsi_Host *shpnt;
-               unsigned long int the_time;
 
-               shpnt = aha152x_host[setup[i].irq - IRQ_MIN] =
+               aha152x_host[setup[i].irq - IRQ_MIN] = shpnt =
                    scsi_register(tpnt, sizeof(struct aha152x_hostdata));
+
+               if(!shpnt) {
+                       printk(KERN_ERR "aha152x: scsi_register failed\n");
+                       continue;
+               }
+
                registered_count++;
 
-               shpnt->io_port = setup[i].io_port;
+               shpnt->io_port   = setup[i].io_port;
                shpnt->n_io_port = IO_RANGE;
-               shpnt->irq = setup[i].irq;
-
-               ISSUE_SC = (Scsi_Cmnd *) NULL;
-               CURRENT_SC = (Scsi_Cmnd *) NULL;
-               DISCONNECTED_SC = (Scsi_Cmnd *) NULL;
-
-               HOSTDATA(shpnt)->reconnect = setup[i].reconnect;
-               HOSTDATA(shpnt)->parity = setup[i].parity;
-               HOSTDATA(shpnt)->synchronous = setup[i].synchronous;
-               HOSTDATA(shpnt)->delay = setup[i].delay;
-               HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans;
-#ifdef DEBUG_AHA152X
-               HOSTDATA(shpnt)->debug = setup[i].debug;
-#endif
+               shpnt->irq       = setup[i].irq;
 
-               HOSTDATA(shpnt)->aborting = 0;
-               HOSTDATA(shpnt)->abortion_complete = 0;
-               HOSTDATA(shpnt)->abort_result = 0;
-               HOSTDATA(shpnt)->commands = 0;
+               if(!setup[i].tc1550) {
+                       HOSTIOPORT0 = setup[i].io_port;
+                       HOSTIOPORT1 = setup[i].io_port;
+               } else {
+                       HOSTIOPORT0 = setup[i].io_port+0x10;
+                       HOSTIOPORT1 = setup[i].io_port-0x10;
+               }
 
-               HOSTDATA(shpnt)->message_len = 0;
+               ISSUE_SC        = 0;
+               CURRENT_SC      = 0;
+               DONE_SC         = 0;
+               DISCONNECTED_SC = 0;
 
-               for (j = 0; j < 8; j++)
-                       HOSTDATA(shpnt)->syncrate[j] = 0;
+               QLOCK           = SPIN_LOCK_UNLOCKED;
+
+               STATE           = 0;
+               PREVSTATE       = 0;
+               LASTSTATE       = 0;
+
+               MSGILEN         = 0;
+               MSGOLEN         = 0;
+
+               RECONNECT       = setup[i].reconnect;
+               SYNCHRONOUS     = setup[i].synchronous;
+               PARITY          = setup[i].parity;
+               DELAY           = setup[i].delay;
+               EXT_TRANS       = setup[i].ext_trans;
+#if defined(AHA152X_DEBUG)
+               HOSTDATA(shpnt)->debug = setup[i].debug;
+#endif
+               HOSTDATA(shpnt)->in_intr = 0;
+               HOSTDATA(shpnt)->commands = 0;
+
+#if defined(AHA152X_STAT)
+               HOSTDATA(shpnt)->total_commands=0;
+               HOSTDATA(shpnt)->disconnections=0;
+               HOSTDATA(shpnt)->busfree_without_any_action=0;
+               HOSTDATA(shpnt)->busfree_without_old_command=0;
+               HOSTDATA(shpnt)->busfree_without_new_command=0;
+               HOSTDATA(shpnt)->busfree_without_done_command=0;
+               HOSTDATA(shpnt)->busfree_with_check_condition=0;
+               for (j = idle; j<maxstate; j++) {
+                       HOSTDATA(shpnt)->count[j]=0;
+                       HOSTDATA(shpnt)->count_trans[j]=0;
+                       HOSTDATA(shpnt)->time[j]=0;
+               }
+#endif
+
+               for (j = 0; j < 8; j++) {
+                       HOSTDATA(shpnt)->syncrate[j] = 0;
+                       HOSTDATA(shpnt)->syncneg[j] = 0;
+               }
 
                SETPORT(SCSIID, setup[i].scsiid << 4);
                shpnt->this_id = setup[i].scsiid;
@@ -1037,59 +1221,73 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
                if (setup[i].reconnect)
                        shpnt->can_queue = AHA152X_MAXQUEUE;
 
-               /* RESET OUT */
-               SETBITS(SCSISEQ, SCSIRSTO);
-               do_pause(30);
-               CLRBITS(SCSISEQ, SCSIRSTO);
-               do_pause(setup[i].delay);
-
-               aha152x_reset_ports(shpnt);
+#if 0
+               if(!shpnt->hostt->use_new_eh_code) {
+#endif
+                       /* RESET OUT */
+                       printk("aha152x: resetting bus...\n");
+                       SETPORT(SCSISEQ, SCSIRSTO);
+                       mdelay(256);
+                       SETPORT(SCSISEQ, 0);
+                       mdelay(DELAY);
+#if 0
+               }
+#endif
 
-               printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d,"
-                      " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n",
-                      i,
-                      shpnt->io_port,
+               reset_ports(shpnt);
+
+               printk(KERN_INFO
+                      "aha152x%d%s: "
+                      "vital data: rev=%x, "
+                      "io=0x%03lx (0x%03lx/0x%03lx), "
+                      "irq=%d, "
+                      "scsiid=%d, "
+                      "reconnect=%s, "
+                      "parity=%s, "
+                      "synchronous=%s, "
+                      "delay=%d, "
+                      "extended translation=%s\n",
+                      HOSTNO, setup[i].tc1550 ? " (tc1550 mode)" : "",
+                      GETPORT(REV) & 0x7,
+                      shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
                       shpnt->irq,
                       shpnt->this_id,
-                    HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled",
-                      HOSTDATA(shpnt)->parity ? "enabled" : "disabled",
-                  HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled",
-                      HOSTDATA(shpnt)->delay,
-                   HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled");
+                      RECONNECT ? "enabled" : "disabled",
+                      PARITY ? "enabled" : "disabled",
+                      SYNCHRONOUS ? "enabled" : "disabled",
+                      DELAY,
+                      EXT_TRANS ? "enabled" : "disabled");
 
-               request_region(shpnt->io_port, IO_RANGE, "aha152x");    /* Register */
+               request_region(shpnt->io_port, IO_RANGE, "aha152x");
 
                /* not expecting any interrupts */
                SETPORT(SIMODE0, 0);
                SETPORT(SIMODE1, 0);
 
-               SETBITS(DMACNTRL0, INTEN);
-
-               ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt);
+               ok = request_irq(shpnt->irq, swintr, SA_INTERRUPT, "aha152x", shpnt);
                if (ok < 0) {
-                       if (ok == -EINVAL)
-                               printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq);
-                       else if (ok == -EBUSY)
-                               printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq);
+                       if (ok==-EINVAL)
+                               printk(KERN_ERR "aha152x%d: bad IRQ %d.\n", HOSTNO, shpnt->irq);
+                       else if(ok==-EBUSY)
+                               printk(KERN_ERR "aha152x%d: IRQ %d already in use.\n", HOSTNO, shpnt->irq);
                        else
-                               printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq);
-                       printk("aha152x: driver needs an IRQ.\n");
+                               printk(KERN_ERR "aha152x%d: Unexpected error code %d on requesting IRQ %d.\n", HOSTNO, ok, shpnt->irq);
+
+                       printk(KERN_ERR "aha152x%d: driver needs an IRQ.\n", HOSTNO);
 
                        scsi_unregister(shpnt);
                        registered_count--;
                        release_region(shpnt->io_port, IO_RANGE);
-                       shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+                       aha152x_host[shpnt->irq - IRQ_MIN] = shpnt = 0;
                        continue;
                }
                HOSTDATA(shpnt)->swint = 0;
 
-               printk("aha152x: trying software interrupt, ");
-               SETBITS(DMACNTRL0, SWINT);
-
-               the_time = jiffies + 100;
-               while (!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time))
-                       barrier();
-
+               printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO);
+               SETPORT(DMACNTRL0, SWINT|INTEN);
+               spin_unlock_irq(&io_request_lock);
+               mdelay(1000);
+               spin_lock_irq(&io_request_lock);
                free_irq(shpnt->irq, shpnt);
 
                if (!HOSTDATA(shpnt)->swint) {
@@ -1099,7 +1297,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
                                printk("failed.\n");
                        }
 
-                       printk("aha152x: IRQ %d possibly wrong.  Please verify.\n", shpnt->irq);
+                       printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong.  Please verify.\n", HOSTNO, shpnt->irq);
 
                        scsi_unregister(shpnt);
                        registered_count--;
@@ -1109,18 +1307,24 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
                }
                printk("ok.\n");
 
-               CLRBITS(DMACNTRL0, SWINT);
+               SETPORT(DMACNTRL0, INTEN);
 
                /* clear interrupts */
                SETPORT(SSTAT0, 0x7f);
                SETPORT(SSTAT1, 0xef);
 
-               if (request_irq(shpnt->irq, aha152x_intr, SA_INTERRUPT, "aha152x", shpnt) < 0) {
-                       printk("aha152x: failed to reassign interrupt.\n");
+               if (request_irq(shpnt->irq, intr, SA_INTERRUPT, "aha152x", shpnt) < 0) {
+                       printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", HOSTNO);
+
+                       scsi_unregister(shpnt);
+                       registered_count--;
+                       release_region(shpnt->io_port, IO_RANGE);
+                       shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+                       continue;
                }
        }
 
-       return (registered_count > 0);
+       return registered_count>0;
 }
 
 
@@ -1128,41 +1332,89 @@ int aha152x_release(struct Scsi_Host *shpnt)
 {
        if (shpnt->irq)
                free_irq(shpnt->irq, shpnt);
+
        if (shpnt->io_port)
                release_region(shpnt->io_port, IO_RANGE);
 
+       scsi_unregister(shpnt);
+
        return 0;
 }
 
+/*
+ * setup controller to generate interrupts depending
+ * on current state (lock has to be aquired)
+ *
+ */ 
+static int setup_expected_interrupts(struct Scsi_Host *shpnt)
+{
+       ASSERT_LOCK(&QLOCK,1);
+
+       if(CURRENT_SC) {
+               CURRENT_SC->SCp.phase |= 1 << 16;
+       
+               if(CURRENT_SC->SCp.phase & selecting) {
+                       DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC));
+                       SETPORT(SSTAT1, SELTO);
+                       SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
+                       SETPORT(SIMODE1, ENSELTIMO);
+               } else {
+                       DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : "");
+                       SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
+                       SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 
+               }
+       } else if(STATE==seldi) {
+               DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC));
+               SETPORT(SIMODE0, 0);
+               SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 
+       } else {
+               DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n",
+                       CMDINFO(CURRENT_SC),
+                       DISCONNECTED_SC ? "(reselection)" : "",
+                       ISSUE_SC ? "(busfree)" : "");
+               SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+               SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
+       }
+
+       if(!HOSTDATA(shpnt)->in_intr)
+               SETBITS(DMACNTRL0, INTEN);
+
+       return TESTHI(DMASTAT, INTSTAT);
+}
+
+
 /* 
  *  Queue a command and setup interrupts for a free bus.
  */
-int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, Scsi_Cmnd *done_SC, void (*done)(Scsi_Cmnd *))
 {
        struct Scsi_Host *shpnt = SCpnt->host;
        unsigned long flags;
 
-#if defined(DEBUG_RACE)
-       enter_driver("queue");
-#else
-#if defined(DEBUG_QUEUE)
-       if (HOSTDATA(shpnt)->debug & debug_queue)
-               printk("aha152x: queue(), ");
-#endif
-#endif
-
-#if defined(DEBUG_QUEUE)
+#if defined(AHA152X_DEBUG)
        if (HOSTDATA(shpnt)->debug & debug_queue) {
-               printk("SCpnt (target = %d lun = %d cmnd = ",
-                      SCpnt->target, SCpnt->lun);
+               printk(INFO_LEAD "queue: cmd_len=%d pieces=%d size=%u cmnd=",
+                      CMDINFO(SCpnt), SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
                print_command(SCpnt->cmnd);
-               printk(", cmd_len=%d, pieces = %d size = %u), ",
-                 SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
-               disp_ports(shpnt);
        }
 #endif
 
-       SCpnt->scsi_done = done;
+       SCpnt->scsi_done        = done;
+       SCpnt->resid            = SCpnt->request_bufflen;
+       SCpnt->SCp.phase        = not_issued | phase;
+       SCpnt->SCp.Status       = CHECK_CONDITION;
+       SCpnt->SCp.Message      = 0;
+       SCpnt->SCp.have_data_in = 0;
+       SCpnt->SCp.sent_command = 0;
+       SCpnt->host_scribble    = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
+       if(!SCpnt->host_scribble) {
+               printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
+               return FAILED;
+       }
+
+       SCNEXT(SCpnt)           = 0;
+       SCDONE(SCpnt)           = done_SC;
+       SCSEM(SCpnt)            = sem;
 
        /* setup scratch area
           SCp.ptr              : buffer pointer
@@ -1170,193 +1422,265 @@ int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
           SCp.buffer           : next buffer
           SCp.buffers_residual : left buffers in list
           SCp.phase            : current state of the command */
-       SCpnt->SCp.phase = not_issued;
        if (SCpnt->use_sg) {
-               SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
-               SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
-               SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+               SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->request_buffer;
+               SCpnt->SCp.ptr              = SCpnt->SCp.buffer->address;
+               SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
                SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
        } else {
-               SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
-               SCpnt->SCp.this_residual = SCpnt->request_bufflen;
-               SCpnt->SCp.buffer = NULL;
+               SCpnt->SCp.ptr              = (char *) SCpnt->request_buffer;
+               SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+               SCpnt->SCp.buffer           = NULL;
                SCpnt->SCp.buffers_residual = 0;
        }
 
-       SCpnt->SCp.Status = CHECK_CONDITION;
-       SCpnt->SCp.Message = 0;
-       SCpnt->SCp.have_data_in = 0;
-       SCpnt->SCp.sent_command = 0;
+       DO_LOCK(flags);
+
+#if defined(AHA152X_STAT)
+       HOSTDATA(shpnt)->total_commands++;
+#endif
 
        /* Turn led on, when this is the first command. */
-       save_flags(flags);
-       cli();
        HOSTDATA(shpnt)->commands++;
-       if (HOSTDATA(shpnt)->commands == 1)
+       if (HOSTDATA(shpnt)->commands==1)
                SETPORT(PORTA, 1);
 
-#if defined(DEBUG_QUEUES)
-       if (HOSTDATA(shpnt)->debug & debug_queues)
-               printk("i+ (%d), ", HOSTDATA(shpnt)->commands);
-#endif
        append_SC(&ISSUE_SC, SCpnt);
 
-       /* Enable bus free interrupt, when we aren't currently on the bus */
-       if (!CURRENT_SC) {
-               SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-               SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-       }
-       restore_flags(flags);
+       if(!HOSTDATA(shpnt)->in_intr)
+               setup_expected_interrupts(shpnt);
 
-#if defined(DEBUG_RACE)
-       leave_driver("queue");
-#endif
+       DO_UNLOCK(flags);
 
        return 0;
 }
 
+int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+       if(*SCpnt->cmnd == REQUEST_SENSE) {
+               SCpnt->result = 0;
+               done(SCpnt);
+
+               return SUCCESS;
+       }
+
+       return aha152x_internal_queue(SCpnt, 0, 0, 0, done);
+}
+
+
 /*
- *  We only support commands in interrupt-driven fashion
+ *  run a command
+ *
  */
+void internal_done(Scsi_Cmnd *SCpnt)
+{
+#if 0
+       struct Scsi_Host *shpnt = SCpnt->host;
+
+       DPRINTK(debug_eh, INFO_LEAD "internal_done called\n", CMDINFO(SCpnt));
+#endif
+       if(SCSEM(SCpnt))
+               up(SCSEM(SCpnt));
+}
+
 int aha152x_command(Scsi_Cmnd * SCpnt)
 {
-       printk("aha152x: interrupt driven driver; use aha152x_queue()\n");
-       return -1;
+       DECLARE_MUTEX_LOCKED(sem);
+
+       aha152x_internal_queue(SCpnt, &sem, 0, 0, internal_done);
+       down(&sem);
+
+       return SUCCESS;
 }
 
 /*
- *  Abort a queued command
- *  (commands that are on the bus can't be aborted easily)
+ *  Abort a command
+ *
  */
-int aha152x_abort(Scsi_Cmnd * SCpnt)
+int aha152x_abort(Scsi_Cmnd *SCpnt)
 {
        struct Scsi_Host *shpnt = SCpnt->host;
+       Scsi_Cmnd *ptr;
        unsigned long flags;
-       Scsi_Cmnd *ptr, *prev;
 
-       save_flags(flags);
-       cli();
+       if(!shpnt) {
+               printk(ERR_LEAD "abort(%p): no host structure\n", CMDINFO(SCpnt), SCpnt);
+               return FAILED;
+       }
 
-#if defined(DEBUG_ABORT)
-       if (HOSTDATA(shpnt)->debug & debug_abort) {
-               printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt);
+#if defined(AHA152X_DEBUG)
+       if(HOSTDATA(shpnt)->debug & debug_eh) {
+               printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt);
                show_queues(shpnt);
+               mdelay(1000);
        }
 #endif
 
-       /* look for command in issue queue */
-       for (ptr = ISSUE_SC, prev = NULL;
-            ptr && ptr != SCpnt;
-            prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+       DO_LOCK(flags);
 
-       if (ptr) {
-               /* dequeue */
-               if (prev)
-                       prev->host_scribble = ptr->host_scribble;
-               else
-                       ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble;
+       ptr=remove_SC(&ISSUE_SC, SCpnt);
+
+       if(ptr) {
+               DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt));
 
                HOSTDATA(shpnt)->commands--;
+               if (!HOSTDATA(shpnt)->commands)
+                       SETPORT(PORTA, 0);
+               DO_UNLOCK(flags);
 
-               restore_flags(flags);
+               kfree(SCpnt->host_scribble);
+               SCpnt->host_scribble=0;
 
-               ptr->host_scribble = NULL;
-               ptr->result = DID_ABORT << 16;
-               spin_lock_irqsave(&io_request_lock, flags);
-               ptr->scsi_done(ptr);
-               spin_unlock_irqrestore(&io_request_lock, flags);
+               return SUCCESS;
+       } 
 
-               return SCSI_ABORT_SUCCESS;
-       }
-       /* if the bus is busy or a command is currently processed,
-          we can't do anything more */
-       if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC != SCpnt)) {
-               /* fail abortion, if bus is busy */
+       DO_UNLOCK(flags);
 
-               if (!CURRENT_SC)
-                       printk("bus busy w/o current command, ");
+       /*
+        * FIXME:
+        * for current command: queue ABORT for message out and raise ATN
+        * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
+        *
+        */
 
-               restore_flags(flags);
+       printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt));
 
-               return SCSI_ABORT_BUSY;
-       }
-       /* bus is free */
+       return FAILED;
+}
 
-       if (CURRENT_SC) {
-               HOSTDATA(shpnt)->commands--;
+static void timer_expired(unsigned long p)
+{
+       struct semaphore *sem = (void *)p;
 
-               /* target entered bus free before COMMAND COMPLETE, nothing to abort */
-               restore_flags(flags);
-               spin_lock_irqsave(&io_request_lock, flags);
-               CURRENT_SC->result = DID_ERROR << 16;
-               CURRENT_SC->scsi_done(CURRENT_SC);
-               CURRENT_SC = (Scsi_Cmnd *) NULL;
-               spin_unlock_irqrestore(&io_request_lock, flags);
+       printk(KERN_INFO "aha152x: timer expired\n");
+       up(sem);
+}
 
-               return SCSI_ABORT_SUCCESS;
-       }
-       /* look for command in disconnected queue */
-       for (ptr = DISCONNECTED_SC, prev = NULL;
-            ptr && ptr != SCpnt;
-            prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+/*
+ * Reset a device
+ *
+ * FIXME: never seen this live. might lockup...
+ *
+ */
+int aha152x_device_reset(Scsi_Cmnd * SCpnt)
+{
+       struct Scsi_Host *shpnt = SCpnt->host;
+       DECLARE_MUTEX_LOCKED(sem);
+       struct timer_list timer;
+       Scsi_Cmnd cmnd;
 
-       if (!ptr) {
-               /* command wasn't found */
-               printk("command not found\n");
-               restore_flags(flags);
+#if defined(AHA152X_DEBUG)
+       if(HOSTDATA(shpnt)->debug & debug_eh) {
+               printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt);
+               show_queues(shpnt);
+               mdelay(1000);
+       }
+#endif
 
-               return SCSI_ABORT_NOT_RUNNING;
+       if(CURRENT_SC==SCpnt) {
+               printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt));
+               return FAILED;
        }
-       if (!HOSTDATA(shpnt)->aborting) {
-               /* dequeue */
-               if (prev)
-                       prev->host_scribble = ptr->host_scribble;
-               else
-                       DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
 
-               HOSTDATA(shpnt)->commands--;
+       cmnd.cmd_len         = 0;
+       cmnd.host            = SCpnt->host;
+       cmnd.target          = SCpnt->target;
+       cmnd.lun             = SCpnt->lun;
+       cmnd.use_sg          = 0;
+       cmnd.request_buffer  = 0;
+       cmnd.request_bufflen = 0;
 
-               /* set command current and initiate selection,
-                  let the interrupt routine take care of the abortion */
-               CURRENT_SC = ptr;
-               ptr->SCp.phase = in_selection | aborted;
-               SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+       init_timer(&timer);
+       timer.data     = (unsigned long) &sem;
+       timer.expires  = jiffies + 10000;   /* 10s */
+       timer.function = (void (*)(unsigned long)) timer_expired;
+       add_timer(&timer);
 
-               ADDMSG(ABORT);
+       aha152x_internal_queue(&cmnd, &sem, resetting, 0, internal_done);
 
-               /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-               SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
-               SETPORT(SIMODE1, ENSELTIMO);
+       down(&sem);
 
-               /* Enable SELECTION OUT sequence */
-               SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+       del_timer(&timer);
 
-               SETBITS(DMACNTRL0, INTEN);
-               HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
-               HOSTDATA(shpnt)->aborting++;
-               HOSTDATA(shpnt)->abortion_complete = 0;
+       if(cmnd.SCp.phase & resetted) {
+               return SUCCESS;
+       } else {
+               return FAILED;
+       }
+}
 
-               restore_flags(flags);
+void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs)
+{
+       Scsi_Cmnd *ptr;
+       unsigned long flags;
 
-               /* sleep until the abortion is complete */
-               while (!HOSTDATA(shpnt)->abortion_complete)
-                       barrier();
-               HOSTDATA(shpnt)->aborting = 0;
+       DO_LOCK(flags);
 
-               return HOSTDATA(shpnt)->abort_result;
-       } else {
-               /* we're already aborting a command */
-               restore_flags(flags);
+       ptr=*SCs;
+       while(ptr) {
+               Scsi_Cmnd *next = SCNEXT(ptr);
+
+               if (!ptr->device->soft_reset) {
+                       DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr);
+                       remove_SC(SCs, ptr);
+                       HOSTDATA(shpnt)->commands--;
+                       kfree(ptr->host_scribble);
+                       ptr->host_scribble=0;
+               }
 
-               return SCSI_ABORT_BUSY;
+               ptr = next;
        }
+
+       DO_UNLOCK(flags);
 }
 
+/*
+ * Reset the bus
+ *
+ */
+int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+{
+       struct Scsi_Host *shpnt = SCpnt->host;
+       unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+       if(HOSTDATA(shpnt)->debug & debug_eh) {
+               printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt);
+               show_queues(shpnt);
+               mdelay(1000);
+       }
+#endif
+
+       free_hard_reset_SCs(shpnt, &ISSUE_SC);
+       free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
+
+       DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt));
+
+       SETPORT(SCSISEQ, SCSIRSTO);
+       mdelay(256);
+       SETPORT(SCSISEQ, 0);
+       mdelay(DELAY);
+
+       DPRINTK(debug_eh, DEBUG_LEAD "bus reset returns\n", CMDINFO(SCpnt));
+
+       DO_LOCK(flags);
+       setup_expected_interrupts(shpnt);
+       if(HOSTDATA(shpnt)->commands==0)
+               SETPORT(PORTA, 0);
+       DO_UNLOCK(flags);
+
+       return SUCCESS;
+}
+
+
 /*
  *  Restore default values to the AIC-6260 registers and reset the fifos
+ *
  */
-static void aha152x_reset_ports(struct Scsi_Host *shpnt)
+static void reset_ports(struct Scsi_Host *shpnt)
 {
+       unsigned long flags;
+
        /* disable interrupts */
        SETPORT(DMACNTRL0, RSTFIFO);
 
@@ -1364,7 +1688,7 @@ static void aha152x_reset_ports(struct Scsi_Host *shpnt)
 
        SETPORT(SXFRCTL1, 0);
        SETPORT(SCSISIG, 0);
-       SETPORT(SCSIRATE, 0);
+       SETRATE(0);
 
        /* clear all interrupt conditions */
        SETPORT(SSTAT0, 0x7f);
@@ -1377,106 +1701,41 @@ static void aha152x_reset_ports(struct Scsi_Host *shpnt)
 
        SETPORT(BRSTCNTRL, 0xf1);
 
-       /* clear SCSI fifo and transfer count */
-       SETPORT(SXFRCTL0, CH1 | CLRCH1 | CLRSTCNT);
+       /* clear SCSI fifos and transfer count */
+       SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
        SETPORT(SXFRCTL0, CH1);
 
-       /* enable interrupts */
-       SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-       SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+       DO_LOCK(flags);
+       setup_expected_interrupts(shpnt);
+       DO_UNLOCK(flags);
 }
 
 /*
- *  Reset registers, reset a hanging bus and
- *  kill active and disconnected commands for target w/o soft reset
+ * Reset the host (bus and controller)
+ *
  */
-int aha152x_reset(Scsi_Cmnd * SCpnt, unsigned int unused)
+int aha152x_host_reset(Scsi_Cmnd * SCpnt)
 {
        struct Scsi_Host *shpnt = SCpnt->host;
-       unsigned long flags;
-       Scsi_Cmnd *ptr, *prev, *next;
 
-       aha152x_reset_ports(shpnt);
+       DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt);
 
-       /* Reset, if bus hangs */
-       if (TESTLO(SSTAT1, BUSFREE)) {
-               CLRBITS(DMACNTRL0, INTEN);
+       aha152x_bus_reset(SCpnt);
 
-#if defined(DEBUG_RESET)
-               if (HOSTDATA(shpnt)->debug & debug_reset) {
-                       printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
-                       show_queues(shpnt);
-               }
-#endif
+       DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt));
+       reset_ports(SCpnt->host);
 
-               ptr = CURRENT_SC;
-               if (ptr && !ptr->device->soft_reset) {
-                       ptr->host_scribble = NULL;
-                       ptr->result = DID_RESET << 16;
-                       ptr->scsi_done(CURRENT_SC);
-                       CURRENT_SC = NULL;
-               }
-               save_flags(flags);
-               cli();
-               prev = NULL;
-               ptr = DISCONNECTED_SC;
-               while (ptr) {
-                       if (!ptr->device->soft_reset) {
-                               if (prev)
-                                       prev->host_scribble = ptr->host_scribble;
-                               else
-                                       DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
-
-                               next = (Scsi_Cmnd *) ptr->host_scribble;
-
-                               ptr->host_scribble = NULL;
-                               ptr->result = DID_RESET << 16;
-                               spin_lock_irqsave(&io_request_lock, flags);
-                               ptr->scsi_done(ptr);
-                               spin_unlock_irqrestore(&io_request_lock, flags);
-
-                               ptr = next;
-                       } else {
-                               prev = ptr;
-                               ptr = (Scsi_Cmnd *) ptr->host_scribble;
-                       }
-               }
-               restore_flags(flags);
-
-#if defined(DEBUG_RESET)
-               if (HOSTDATA(shpnt)->debug & debug_reset) {
-                       printk("commands on targets w/ soft-resets:\n");
-                       show_queues(shpnt);
-               }
-#endif
-
-               /* RESET OUT */
-               SETPORT(SCSISEQ, SCSIRSTO);
-               do_pause(30);
-               SETPORT(SCSISEQ, 0);
-               do_pause(DELAY);
-
-               SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-               SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-
-               SETPORT(DMACNTRL0, INTEN);
-       }
-       return SCSI_RESET_SUCCESS;
+       return SUCCESS;
 }
 
 /*
  * Return the "logical geometry"
+ *
  */
 int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
 {
        struct Scsi_Host *shpnt = disk->device->host;
 
-#if defined(DEBUG_BIOSPARAM)
-       if (HOSTDATA(shpnt)->debug & debug_biosparam)
-               printk("aha152x_biosparam: dev=%s, size=%d, ",
-                      kdevname(dev), disk->capacity);
-#endif
-
        /* try default translation */
        info_array[0] = 64;
        info_array[1] = 32;
@@ -1490,16 +1749,18 @@ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
                if (scsicam_bios_param(disk, dev, info) < 0 ||
                    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
                        if (EXT_TRANS) {
-                               printk("aha152x: unable to verify geometry for disk with >1GB.\n"
-                               "         using extended translation.\n");
+                               printk(KERN_NOTICE
+                                      "aha152x: unable to verify geometry for disk with >1GB.\n"
+                                      "         using extended translation.\n");
                                info_array[0] = 255;
                                info_array[1] = 63;
                                info_array[2] = disk->capacity / (255 * 63);
                        } else {
-                               printk("aha152x: unable to verify geometry for disk with >1GB.\n"
+                               printk(KERN_NOTICE
+                                      "aha152x: unable to verify geometry for disk with >1GB.\n"
                                       "         Using default translation. Please verify yourself.\n"
                                       "         Perhaps you need to enable extended translation in the driver.\n"
-                                      "         See /usr/src/linux/drivers/scsi/aha152x.c for details.\n");
+                                      "         See /usr/src/linux/drivers/scsi/README.aha152x for details.\n");
                        }
                } else {
                        info_array[0] = info[0];
@@ -1507,1158 +1768,1211 @@ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
                        info_array[2] = info[2];
 
                        if (info[0] == 255 && !EXT_TRANS) {
-                               printk("aha152x: current partition table is using extended translation.\n"
-                                      "         using it also, although it's not explicty enabled.\n");
+                               printk(KERN_NOTICE
+                                      "aha152x: current partition table is using extended translation.\n"
+                                      "         using it also, although it's not explictly enabled.\n");
                        }
                }
        }
-#if defined(DEBUG_BIOSPARAM)
-       if (HOSTDATA(shpnt)->debug & debug_biosparam) {
-               printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
-                      info_array[0], info_array[1], info_array[2]);
-               printk("WARNING: check, if the bios geometry is correct.\n");
-       }
-#endif
 
        return 0;
 }
 
 /*
  *  Internal done function
+ *
  */
-void aha152x_done(struct Scsi_Host *shpnt, int error)
+static void done(struct Scsi_Host *shpnt, int error)
 {
-       unsigned long flags;
-       Scsi_Cmnd *done_SC;
-
-#if defined(DEBUG_DONE)
-       if (HOSTDATA(shpnt)->debug & debug_done) {
-               printk("\naha152x: done(), ");
-               disp_ports(shpnt);
-       }
-#endif
-
        if (CURRENT_SC) {
-#if defined(DEBUG_DONE)
-               if (HOSTDATA(shpnt)->debug & debug_done)
-                       printk("done(%x), ", error);
-#endif
+               if(DONE_SC)
+                       printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC);
 
-               save_flags(flags);
-               cli();
-
-               done_SC = CURRENT_SC;
-               CURRENT_SC = NULL;
-
-               /* turn led off, when no commands are in the driver */
-               HOSTDATA(shpnt)->commands--;
-               if (!HOSTDATA(shpnt)->commands)
-                       SETPORT(PORTA, 0);      /* turn led off */
-
-#if defined(DEBUG_QUEUES)
-               if (HOSTDATA(shpnt)->debug & debug_queues)
-                       printk("ok (%d), ", HOSTDATA(shpnt)->commands);
-#endif
-               restore_flags(flags);
-
-               SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-               SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-
-#if 0
-/* Why poll for the BUS FREE phase, when we have setup the interrupt!? */
-#if defined(DEBUG_PHASES)
-               if (HOSTDATA(shpnt)->debug & debug_phases)
-                       printk("BUS FREE loop, ");
-#endif
-               while (TESTLO(SSTAT1, BUSFREE))
-                       barrier();
-#if defined(DEBUG_PHASES)
-               if (HOSTDATA(shpnt)->debug & debug_phases)
-                       printk("BUS FREE\n");
-#endif
-#endif
-
-               done_SC->result = error;
-               if (done_SC->scsi_done) {
-#if defined(DEBUG_DONE)
-                       if (HOSTDATA(shpnt)->debug & debug_done)
-                               printk("calling scsi_done, ");
-#endif
-                       spin_lock_irqsave(&io_request_lock, flags);
-                       done_SC->scsi_done(done_SC);
-                       spin_unlock_irqrestore(&io_request_lock, flags);
-#if defined(DEBUG_DONE)
-                       if (HOSTDATA(shpnt)->debug & debug_done)
-                               printk("done returned, ");
-#endif
-               } else
-                       panic("aha152x: current_SC->scsi_done() == NULL");
+               DONE_SC = CURRENT_SC;
+               CURRENT_SC = 0;
+               DONE_SC->result = error;
        } else
-               aha152x_panic(shpnt, "done() called outside of command");
+               printk(KERN_ERR "aha152x: done() called outside of command\n");
 }
 
-
-static void aha152x_complete(struct Scsi_Host *);
-
 static struct tq_struct aha152x_tq;
 
 /*
- *    Run service completions on the card with interrupts enabled.
+ * Run service completions on the card with interrupts enabled.
+ *
  */
-
-static void aha152x_run(void)
+static void run(void)
 {
        int i;
        for (i = 0; i < IRQS; i++) {
                struct Scsi_Host *shpnt = aha152x_host[i];
                if (shpnt && HOSTDATA(shpnt)->service) {
-                       HOSTDATA(shpnt)->service = 0;
-                       aha152x_complete(shpnt);
+                       HOSTDATA(shpnt)->service=0;
+                       complete(shpnt);
                }
        }
 }
 
 /*
- *    Interrupts handler (main routine of the driver)
+ *    Interrupts handler
+ *
  */
 
-static void aha152x_intr(int irqno, void *dev_id, struct pt_regs *regs)
+static void intr(int irqno, void *dev_id, struct pt_regs *regs)
 {
        struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
 
-#if defined(DEBUG_RACE)
-       enter_driver("intr");
-#else
-#if defined(DEBUG_INTR)
-       if (HOSTDATA(shpnt)->debug & debug_intr)
-               printk("\naha152x: intr(), ");
-#endif
-#endif
-
-       if (!shpnt)
-               panic("aha152x: catched interrupt for unknown controller.\n");
+       if (!shpnt) {
+               printk(KERN_ERR "aha152x: catched interrupt for unknown controller.\n");
+               return;
+       }
 
        /* no more interrupts from the controller, while we're busy.
           INTEN is restored by the BH handler */
-
        CLRBITS(DMACNTRL0, INTEN);
 
+#if 0
+       /* check if there is already something to be
+           serviced; should not happen */
+       if(HOSTDATA(shpnt)->service) {
+               printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service);
+               show_queues(shpnt);
+       }
+#endif
+       
        /* Poke the BH handler */
-
-       HOSTDATA(shpnt)->service = 1;
-       aha152x_tq.routine = (void *) aha152x_run;
+       HOSTDATA(shpnt)->service++;
+       aha152x_tq.routine = (void *) run;
        queue_task(&aha152x_tq, &tq_immediate);
        mark_bh(IMMEDIATE_BH);
 }
 
-static void aha152x_complete(struct Scsi_Host *shpnt)
+/*
+ * busfree phase
+ * - handle completition/disconnection/error of current command
+ * - start selection for next command (if any)
+ */
+static void busfree_run(struct Scsi_Host *shpnt)
 {
-       unsigned int flags;
-       int done = 0, phase;
+       unsigned long flags;
+#if defined(AHA152X_STAT)
+       int action=0;
+#endif
 
-       /* disconnected target is trying to reconnect.
-          Only possible, if we have disconnected nexuses and
-          nothing is occupying the bus.
-        */
+       SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+       SETPORT(SXFRCTL0, CH1);
 
-       if (TESTHI(SSTAT0, SELDI) &&
-           DISCONNECTED_SC &&
-           (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))) {
-               int identify_msg, target, i;
-
-               /* Avoid conflicts when a target reconnects
-                  while we are trying to connect to another. */
-               if (CURRENT_SC) {
-#if defined(DEBUG_QUEUES)
-                       if (HOSTDATA(shpnt)->debug & debug_queues)
-                               printk("i+, ");
+       SETPORT(SSTAT1, CLRBUSFREE);
+       
+       if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+               action++;
 #endif
-                       save_flags(flags);
-                       cli();
-                       append_SC(&ISSUE_SC, CURRENT_SC);
-                       CURRENT_SC = NULL;
-                       restore_flags(flags);
-               }
-               /* disable sequences */
-               SETPORT(SCSISEQ, 0);
-               SETPORT(SSTAT0, CLRSELDI);
-               SETPORT(SSTAT1, CLRBUSFREE);
-
-#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
-               if (HOSTDATA(shpnt)->debug & (debug_queues | debug_phases))
-                       printk("reselected, ");
+               CURRENT_SC->SCp.phase &= ~syncneg;
+
+               if(CURRENT_SC->SCp.phase & completed) {
+                       /* target sent COMMAND COMPLETE */
+                       done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
+
+               } else if(CURRENT_SC->SCp.phase & aborted) {
+                       DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC));
+                       done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
+
+               } else if(CURRENT_SC->SCp.phase & resetted) {
+                       DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC));
+                       done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
+
+               } else if(CURRENT_SC->SCp.phase & disconnected) {
+                       /* target sent DISCONNECT */
+                       DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n",
+                               CMDINFO(CURRENT_SC),
+                               CURRENT_SC->resid,
+                               CURRENT_SC->request_bufflen);
+#if defined(AHA152X_STAT)
+                       HOSTDATA(shpnt)->disconnections++;
 #endif
+                       append_SC(&DISCONNECTED_SC, CURRENT_SC);
+                       CURRENT_SC->SCp.phase |= 1 << 16;
+                       CURRENT_SC = 0;
 
-               i = GETPORT(SELID) & ~(1 << shpnt->this_id);
-               target = 0;
+               } else {
+                       done(shpnt, DID_ERROR << 16);
+               }
+#if defined(AHA152X_STAT)
+       } else {
+               HOSTDATA(shpnt)->busfree_without_old_command++;
+#endif
+       }
 
-               if (i == 0)
-                       aha152x_panic(shpnt, "reconnecting target unknown");
+       DO_LOCK(flags);
 
-               for (; (i & 1) == 0; target++, i >>= 1);
+       if(DONE_SC) {
+#if defined(AHA152X_STAT)
+               action++;
+#endif
+               if(SCDONE(DONE_SC)) {
+                       Scsi_Cmnd *ptr=DONE_SC;
+                       DONE_SC=SCDONE(DONE_SC);
 
-#if defined(DEBUG_QUEUES)
-               if (HOSTDATA(shpnt)->debug & debug_queues)
-                       printk("SELID=%02x, target=%d, ", GETPORT(SELID), target);
+#if 0
+                       if(HOSTDATA(shpnt)->debug & debug_eh) {
+                               printk(ERR_LEAD "received sense: ", CMDINFO(ptr));
+                               print_sense("bh", DONE_SC);
+                       }
 #endif
-               SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
-               SETPORT(SCSISEQ, ENRESELI);
 
-               if (TESTLO(SSTAT0, SELDI))
-                       aha152x_panic(shpnt, "RESELI failed");
+                       HOSTDATA(shpnt)->commands--;
+                       if (!HOSTDATA(shpnt)->commands)
+                               SETPORT(PORTA, 0);      /* turn led off */
 
-               SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f);
+                       kfree(ptr->host_scribble);
+                       kfree(ptr);
+               } else if(DONE_SC->SCp.Status==0x02) {
+#if defined(AHA152X_STAT)
+                       HOSTDATA(shpnt)->busfree_with_check_condition++;
+#endif
+#if 0
+                       DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
+#endif
+
+                       if(!(DONE_SC->SCp.Status & not_issued)) {
+                               Scsi_Cmnd *cmnd = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
 
-               SETPORT(SCSISIG, P_MSGI);
+                               if(cmnd) {
+                                       Scsi_Cmnd *ptr=DONE_SC;
+                                       DONE_SC=0;
 
-               /* Get identify message */
-               if ((i = getphase(shpnt)) != P_MSGI) {
-                       printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
-                       aha152x_panic(shpnt, "unknown lun");
+#if 0
+                                       DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
+#endif
+
+                                       cmnd->cmnd[0]         = REQUEST_SENSE;
+                                       cmnd->cmnd[1]         = 0;
+                                       cmnd->cmnd[2]         = 0;
+                                       cmnd->cmnd[3]         = 0;
+                                       cmnd->cmnd[4]         = sizeof(ptr->sense_buffer);
+                                       cmnd->cmnd[5]         = 0;
+                                       cmnd->cmd_len         = 6;
+                                       cmnd->host            = ptr->host;
+                                       cmnd->target          = ptr->target;
+                                       cmnd->lun             = ptr->lun;
+                                       cmnd->use_sg          = 0; 
+                                       cmnd->request_buffer  = ptr->sense_buffer;
+                                       cmnd->request_bufflen = sizeof(ptr->sense_buffer);
+                       
+                                       DO_UNLOCK(flags);
+                                       aha152x_internal_queue(cmnd, 0, 0, ptr, internal_done);
+                                       DO_LOCK(flags);
+                               } else {
+                                       printk(ERR_LEAD "allocation failed\n", CMDINFO(CURRENT_SC));
+                                       if(cmnd)
+                                               kfree(cmnd);
+                               }
+                       } else {
+#if 0
+                               DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC));
+#endif                         
+                       }
                }
-               SETPORT(SCSISEQ, 0);
 
-               SETPORT(SXFRCTL0, CH1);
+               if(DONE_SC && DONE_SC->scsi_done) {
+                       /* turn led off, when no commands are in the driver */
+                       HOSTDATA(shpnt)->commands--;
+                       if (!HOSTDATA(shpnt)->commands)
+                               SETPORT(PORTA, 0);      /* turn led off */
 
-               identify_msg = GETPORT(SCSIBUS);
+                       kfree(DONE_SC->host_scribble);
+                       DONE_SC->host_scribble=0;
 
-               if (!(identify_msg & IDENTIFY_BASE)) {
-                       printk("target=%d, inbound message (%02x) != IDENTIFY\n",
-                              target, identify_msg);
-                       aha152x_panic(shpnt, "unknown lun");
+                       DO_UNLOCK(flags);
+                       DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC);
+                       DONE_SC->scsi_done(DONE_SC);
+                       DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC);
+                       DO_LOCK(flags);
                }
-#if defined(DEBUG_QUEUES)
-               if (HOSTDATA(shpnt)->debug & debug_queues)
-                       printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f);
+
+               DONE_SC=0;
+#if defined(AHA152X_STAT)
+       } else {
+               HOSTDATA(shpnt)->busfree_without_done_command++;
 #endif
+       }
+
+       if(ISSUE_SC)
+               CURRENT_SC = remove_first_SC(&ISSUE_SC);
 
-               save_flags(flags);
-               cli();
+       DO_UNLOCK(flags);
 
-#if defined(DEBUG_QUEUES)
-               if (HOSTDATA(shpnt)->debug & debug_queues)
-                       printk("d-, ");
+       if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+               action++;
 #endif
-               CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f);
+               CURRENT_SC->SCp.phase |= selecting;
 
-               if (!CURRENT_SC) {
-                       printk("lun=%d, ", identify_msg & 0x3f);
-                       aha152x_panic(shpnt, "no disconnected command for that lun");
-               }
-               CURRENT_SC->SCp.phase &= ~disconnected;
-               restore_flags(flags);
-
-               make_acklow(shpnt);
-               if (getphase(shpnt) != P_MSGI) {
-                       SETPORT(SIMODE0, 0);
-                       SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-#if defined(DEBUG_RACE)
-                       leave_driver("(reselected) intr");
+               DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC));
+
+               /* clear selection timeout */
+               SETPORT(SSTAT1, SELTO);
+
+               SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+               SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
+               SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
+       } else {
+#if defined(AHA152X_STAT)
+               HOSTDATA(shpnt)->busfree_without_new_command++;
 #endif
-                       SETBITS(DMACNTRL0, INTEN);
-                       return;
-               }
+               SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
        }
-       /* Check, if we aren't busy with a command */
-       if (!CURRENT_SC) {
-               /* bus is free to issue a queued command */
-               if (TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) {
-                       save_flags(flags);
-                       cli();
-#if defined(DEBUG_QUEUES)
-                       if (HOSTDATA(shpnt)->debug & debug_queues)
-                               printk("i-, ");
-#endif
-                       CURRENT_SC = remove_first_SC(&ISSUE_SC);
-                       restore_flags(flags);
 
-#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-                       if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases))
-                               printk("issuing command, ");
+#if defined(AHA152X_STAT)
+       if(!action)
+               HOSTDATA(shpnt)->busfree_without_any_action++;
 #endif
-                       CURRENT_SC->SCp.phase = in_selection;
+}
 
-#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-                       if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases))
-                               printk("selecting %d, ", CURRENT_SC->target);
-#endif
-                       SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+/*
+ * Selection done (OUT)
+ * - queue IDENTIFY message and SDTR to selected target for message out
+ *   (ATN asserted automagically via ENAUTOATNO in busfree())
+ */
+static void seldo_run(struct Scsi_Host *shpnt)
+{
+       SETPORT(SCSISIG, 0);
+       SETPORT(SSTAT1, CLRBUSFREE);
+       SETPORT(SSTAT1, CLRPHASECHG);
 
-                       /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
-                       SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER);
+       CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
 
-                       /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-                       SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
-                       SETPORT(SIMODE1, ENSELTIMO);
+       SETPORT(SCSISEQ, 0);
 
-                       /* Enable SELECTION OUT sequence */
-                       SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+       if (TESTLO(SSTAT0, SELDO)) {
+               printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC));
+               done(shpnt, DID_NO_CONNECT << 16);
+               return;
+       }
 
-               } else {
-                       /* No command we are busy with and no new to issue */
-                       printk("aha152x: ignoring spurious interrupt, nothing to do\n");
-                       if (TESTHI(DMACNTRL0, SWINT)) {
-                               printk("aha152x: SWINT is set!  Why?\n");
-                               CLRBITS(DMACNTRL0, SWINT);
-                       }
-                       show_queues(shpnt);
-               }
+       SETPORT(SSTAT0, CLRSELDO);
+       
+       ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->lun));
+
+       if (CURRENT_SC->SCp.phase & aborting) {
+               ADDMSGO(ABORT);
+       } else if (CURRENT_SC->SCp.phase & resetting) {
+               ADDMSGO(BUS_DEVICE_RESET);
+       } else if (SYNCNEG==0 && SYNCHRONOUS) {
+               CURRENT_SC->SCp.phase |= syncneg;
+               ADDMSGO(EXTENDED_MESSAGE);
+               ADDMSGO(3);
+               ADDMSGO(EXTENDED_SDTR);
+               ADDMSGO(50);            /* 200ns */
+               ADDMSGO(8);             /* 8 byte req/ack offset */
+
+               SYNCNEG=1;              /* negotiation in progress */
+       }
 
-#if defined(DEBUG_RACE)
-               leave_driver("(selecting) intr");
-#endif
-               SETBITS(DMACNTRL0, INTEN);
+       SETRATE(SYNCRATE);
+}
+
+/*
+ * Selection timeout
+ * - return command to mid-level with failure cause
+ *
+ */
+static void selto_run(struct Scsi_Host *shpnt)
+{
+       SETPORT(SCSISEQ, 0);            
+       SETPORT(SSTAT1, CLRSELTIMO);
+
+       DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC));
+
+       if(!CURRENT_SC) {
+               DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC));
                return;
        }
-       /* the bus is busy with something */
 
-#if defined(DEBUG_INTR)
-       if (HOSTDATA(shpnt)->debug & debug_intr)
-               disp_ports(shpnt);
-#endif
+       CURRENT_SC->SCp.phase &= ~selecting;
 
-       /* we are waiting for the result of a selection attempt */
-       if (CURRENT_SC->SCp.phase & in_selection) {
-               if (TESTLO(SSTAT1, SELTO)) {
-                       /* no timeout */
-                       if (TESTHI(SSTAT0, SELDO)) {
-                               /* clear BUS FREE interrupt */
-                               SETPORT(SSTAT1, CLRBUSFREE);
-
-                               /* Disable SELECTION OUT sequence */
-                               CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+       if (CURRENT_SC->SCp.phase & aborted) {
+               DPRINTK(debug_selection, DEBUG_LEAD "aborted\n", CMDINFO(CURRENT_SC));
+               done(shpnt, DID_ABORT << 16);
+       } else if (TESTLO(SSTAT0, SELINGO)) {
+               DPRINTK(debug_selection, DEBUG_LEAD "arbitration not won\n", CMDINFO(CURRENT_SC));
+               done(shpnt, DID_BUS_BUSY << 16);
+       } else {
+               /* ARBITRATION won, but SELECTION failed */
+               DPRINTK(debug_selection, DEBUG_LEAD "selection failed\n", CMDINFO(CURRENT_SC));
+               done(shpnt, DID_NO_CONNECT << 16);
+       }
+}
 
-                               /* Disable SELECTION OUT DONE interrupt */
-                               CLRBITS(SIMODE0, ENSELDO);
-                               CLRBITS(SIMODE1, ENSELTIMO);
+/*
+ * Selection in done
+ * - put current command back to issue queue
+ *   (reconnection of a disconnected nexus instead
+ *    of successful selection out)
+ *
+ */
+static void seldi_run(struct Scsi_Host *shpnt)
+{
+       int selid;
+       int target;
+       unsigned long flags;
 
-                               if (TESTLO(SSTAT0, SELDO)) {
-                                       printk("aha152x: passing bus free condition\n");
+       SETPORT(SCSISIG, 0);
+       SETPORT(SSTAT0, CLRSELDI);
+       SETPORT(SSTAT1, CLRBUSFREE);
+       SETPORT(SSTAT1, CLRPHASECHG);
 
-#if defined(DEBUG_RACE)
-                                       leave_driver("(passing bus free) intr");
-#endif
-                                       SETBITS(DMACNTRL0, INTEN);
+       if(CURRENT_SC) {
+               if(!(CURRENT_SC->SCp.phase & not_issued))
+                       printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC));
 
-                                       if (CURRENT_SC->SCp.phase & aborted) {
-                                               HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR;
-                                               HOSTDATA(shpnt)->abortion_complete++;
-                                       }
-                                       aha152x_done(shpnt, DID_NO_CONNECT << 16);
+               DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC));
 
-                                       return;
-                               }
-#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-                               if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
-                                       printk("SELDO (SELID=%x), ", GETPORT(SELID));
-#endif
+               DO_LOCK(flags);
+               append_SC(&ISSUE_SC, CURRENT_SC);
+               DO_UNLOCK(flags);
 
-                               /* selection was done */
-                               SETPORT(SSTAT0, CLRSELDO);
+               CURRENT_SC = 0;
+       }
 
-#if defined(DEBUG_ABORT)
-                               if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted))
-                                       printk("(ABORT) target selected, ");
-#endif
+       if(!DISCONNECTED_SC) {
+               DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC));
+               return;
+       }
 
-                               CURRENT_SC->SCp.phase &= ~in_selection;
-                               CURRENT_SC->SCp.phase |= in_other;
+       RECONN_TARGET=-1;
 
-                               ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun));
+       selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
 
-                               if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) {
-                                       ADDMSG(EXTENDED_MESSAGE);
-                                       ADDMSG(3);
-                                       ADDMSG(EXTENDED_SDTR);
-                                       ADDMSG(50);
-                                       ADDMSG(8);
+       if (selid==0) {
+               printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid);
+               return;
+       }
 
-                                       printk("outbound SDTR: ");
-                                       print_msg(&MSG(MSGLEN - 5));
+       for(target=7; !(selid & (1 << target)); target--)
+               ;
 
-                                       SYNCRATE = 0x80;
-                                       CURRENT_SC->SCp.phase |= in_sync;
-                               }
-#if defined(DEBUG_RACE)
-                               leave_driver("(SELDO) intr");
-#endif
-                               SETPORT(SCSIRATE, SYNCRATE & 0x7f);
+       if(selid & ~(1 << target)) {
+               printk("aha152x%d: multiple targets reconnected (%02x)\n",
+                      HOSTNO, selid);
+       }
 
-                               SETPORT(SCSISIG, P_MSGO);
 
-                               SETPORT(SIMODE0, 0);
-                               SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
-                               SETBITS(DMACNTRL0, INTEN);
+       SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
+       SETPORT(SCSISEQ, 0);
 
-                               return;
-                       } else
-                               aha152x_panic(shpnt, "neither timeout nor selection\007");
-               } else {
-#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-                       if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
-                               printk("SELTO, ");
-#endif
-                       /* end selection attempt */
-                       CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+       SETRATE(HOSTDATA(shpnt)->syncrate[target]);
 
-                       /* timeout */
-                       SETPORT(SSTAT1, CLRSELTIMO);
+       RECONN_TARGET=target;
+       DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid);
+}
 
-                       SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-                       SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-                       SETBITS(DMACNTRL0, INTEN);
-#if defined(DEBUG_RACE)
-                       leave_driver("(SELTO) intr");
-#endif
+/*
+ * message in phase
+ * - handle initial message after reconnection to identify
+ *   reconnecting nexus
+ * - queue command on DISCONNECTED_SC on DISCONNECT message
+ * - set completed flag on COMMAND COMPLETE
+ *   (other completition code moved to busfree_run)
+ * - handle response to SDTR
+ * - clear synchronous transfer agreements on BUS RESET
+ *
+ * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
+ *
+ */
+static void msgi_run(struct Scsi_Host *shpnt)
+{
+       for(;;) {
+               int sstat1 = GETPORT(SSTAT1);
 
-                       if (CURRENT_SC->SCp.phase & aborted) {
-#if defined(DEBUG_ABORT)
-                               if (HOSTDATA(shpnt)->debug & debug_abort)
-                                       printk("(ABORT) selection timeout, ");
-#endif
-                               HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR;
-                               HOSTDATA(shpnt)->abortion_complete++;
-                       }
-                       if (TESTLO(SSTAT0, SELINGO))
-                               /* ARBITRATION not won */
-                               aha152x_done(shpnt, DID_BUS_BUSY << 16);
-                       else
-                               /* ARBITRATION won, but SELECTION failed */
-                               aha152x_done(shpnt, DID_NO_CONNECT << 16);
+               if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
+                       return;
 
+               if(TESTLO(SSTAT0,SPIORDY)) {
+                       DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
                        return;
+               }       
+
+               ADDMSGI(GETPORT(SCSIDAT));
+
+#if defined(AHA152X_DEBUG)
+               if (HOSTDATA(shpnt)->debug & debug_msgi) {
+                       printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0));
+                       print_msg(&MSGI(0));
+                       printk("\n");
                }
-       }
-       /* enable interrupt, when target leaves current phase */
-       phase = getphase(shpnt);
-       if (!(phase & ~P_MASK)) /* "real" phase */
-               SETPORT(SCSISIG, phase);
-       SETPORT(SSTAT1, CLRPHASECHG);
-       CURRENT_SC->SCp.phase =
-           (CURRENT_SC->SCp.phase & ~((P_MASK | 1) << 16)) | (phase << 16);
-
-       /* information transfer phase */
-       switch (phase) {
-       case P_MSGO:            /* MESSAGE OUT */
-               {
-                       int i, identify = 0, abort = 0;
-
-#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
-                       if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgo | debug_phases))
-                               printk("MESSAGE OUT, ");
 #endif
-                       if (MSGLEN == 0) {
-                               ADDMSG(MESSAGE_REJECT);
-#if defined(DEBUG_MSGO)
-                               if (HOSTDATA(shpnt)->debug & debug_msgo)
-                                       printk("unexpected MESSAGE OUT phase; rejecting, ");
-#endif
-                       }
-                       CLRBITS(SXFRCTL0, ENDMA);
 
-                       SETPORT(SIMODE0, 0);
-                       SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+               if(!CURRENT_SC) {
+                       if(LASTSTATE!=seldi) {
+                               printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO);
+                       }
 
-                       /* wait for data latch to become ready or a phase change */
-                       while (TESTLO(DMASTAT, INTSTAT))
-                               barrier();
+                       /*
+                        * Handle reselection
+                        */
+                       if(!(MSGI(0) & IDENTIFY_BASE)) {
+                               printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO);
+                               continue;
+                       }
 
-#if defined(DEBUG_MSGO)
-                       if (HOSTDATA(shpnt)->debug & debug_msgo) {
-                               int i;
+                       CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
 
-                               printk("messages (");
-                               for (i = 0; i < MSGLEN; i += print_msg(&MSG(i)), printk(" "));
-                               printk("), ");
+                       if (!CURRENT_SC) {
+                               show_queues(shpnt);
+                               printk(KERN_ERR "aha152x%d: no disconnected command for target %d/%d\n", HOSTNO, RECONN_TARGET, MSGI(0) & 0x3f);
+                               continue;
                        }
-#endif
 
-                       for (i = 0; i < MSGLEN && TESTLO(SSTAT1, PHASEMIS); i++) {
-#if defined(DEBUG_MSGO)
-                               if (HOSTDATA(shpnt)->debug & debug_msgo)
-                                       printk("%x ", MSG(i));
-#endif
-                               if (i == MSGLEN - 1) {
-                                       /* Leave MESSAGE OUT after transfer */
-                                       SETPORT(SSTAT1, CLRATNO);
-                               }
-                               SETPORT(SCSIDAT, MSG(i));
+                       DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC));
 
-                               make_acklow(shpnt);
-                               getphase(shpnt);
+                       CURRENT_SC->SCp.Message = MSGI(0);
+                       CURRENT_SC->SCp.phase &= ~disconnected;
 
-                               if (MSG(i) == IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun))
-                                       identify++;
+                       MSGILEN=0;
 
-                               if (MSG(i) == ABORT)
-                                       abort++;
+                       /* next message if any */
+                       continue;
+               } 
 
-                       }
+               CURRENT_SC->SCp.Message = MSGI(0);
 
-                       MSGLEN = 0;
+               switch (MSGI(0)) {
+               case DISCONNECT:
+                       if (!RECONNECT)
+                               printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC));
 
-                       if (identify)
-                               CURRENT_SC->SCp.phase |= sent_ident;
+                       CURRENT_SC->SCp.phase |= disconnected;
+                       break;
 
-                       if (abort) {
-                               /* revive abort(); abort() enables interrupts */
-                               HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
-                               HOSTDATA(shpnt)->abortion_complete++;
+               case COMMAND_COMPLETE:
+                       if(CURRENT_SC->SCp.phase & completed)
+                               DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC));
 
-                               CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
+                       CURRENT_SC->SCp.phase |= completed;
+                       break;
 
-                               /* exit */
-                               SETBITS(DMACNTRL0, INTEN);
-#if defined(DEBUG_RACE)
-                               leave_driver("(ABORT) intr");
-#endif
-                               aha152x_done(shpnt, DID_ABORT << 16);
+               case MESSAGE_REJECT:
+                       if (SYNCNEG==1) {
+                               printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+                               SYNCNEG=2;      /* negotiation completed */
+                       } else
+                               printk(INFO_LEAD "inbound message (MESSAGE REJECT)\n", CMDINFO(CURRENT_SC));
+                       break;
 
-                               return;
-                       }
-               }
-               break;
+               case SAVE_POINTERS:
+                       break;
 
-       case P_CMD:             /* COMMAND phase */
-#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
-               if (HOSTDATA(shpnt)->debug & (debug_intr | debug_cmd | debug_phases))
-                       printk("COMMAND, ");
-#endif
-               if (!(CURRENT_SC->SCp.sent_command)) {
-                       int i;
+               case RESTORE_POINTERS:
+                       break;
 
-                       CLRBITS(SXFRCTL0, ENDMA);
+               case EXTENDED_MESSAGE:
+                       if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
+                               /* not yet completed */
+                               continue;
+                       }
 
-                       SETPORT(SIMODE0, 0);
-                       SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+                       switch (MSGI(2)) {
+                       case EXTENDED_SDTR:
+                               {
+                                       long ticks;
 
-                       /* wait for data latch to become ready or a phase change */
-                       while (TESTLO(DMASTAT, INTSTAT))
-                               barrier();
+                                       if (MSGI(1) != 3) {
+                                               printk(ERR_LEAD "SDTR message length!=3\n", CMDINFO(CURRENT_SC));
+                                               break;
+                                       }
 
-                       for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) {
-                               SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]);
+                                       if (!HOSTDATA(shpnt)->synchronous)
+                                               break;
 
-                               make_acklow(shpnt);
-                               getphase(shpnt);
-                       }
+                                       printk(INFO_LEAD, CMDINFO(CURRENT_SC));
+                                       print_msg(&MSGI(0));
+                                       printk("\n");
 
-                       if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS))
-                               aha152x_panic(shpnt, "target left COMMAND");
+                                       ticks = (MSGI(3) * 4 + 49) / 50;
 
-                       CURRENT_SC->SCp.sent_command++;
-               } else
-                       aha152x_panic(shpnt, "Nothing to send while in COMMAND");
-               break;
+                                       if (syncneg) {
+                                               /* negotiation in progress */
+                                               if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
+                                                       ADDMSGO(MESSAGE_REJECT);
+                                                       printk(INFO_LEAD "received Synchronous Data Transfer Request invalid - rejected\n", CMDINFO(CURRENT_SC));
+                                                       break;
+                                               }
+                                               
+                                               SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
+                                       } else if (ticks <= 9 && MSGI(4) >= 1) {
+                                               ADDMSGO(EXTENDED_MESSAGE);
+                                               ADDMSGO(3);
+                                               ADDMSGO(EXTENDED_SDTR);
+                                               if (ticks < 4) {
+                                                       ticks = 4;
+                                                       ADDMSGO(50);
+                                               } else
+                                                       ADDMSGO(MSGI(3));
+
+                                               if (MSGI(4) > 8)
+                                                       MSGI(4) = 8;
+
+                                               ADDMSGO(MSGI(4));
+
+                                               SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
+                                       } else {
+                                               /* requested SDTR is too slow, do it asynchronously */
+                                               printk(INFO_LEAD "Synchronous Data Transfer Request too slow - Rejecting\n", CMDINFO(CURRENT_SC));
+                                               ADDMSGO(MESSAGE_REJECT);
+                                       }
 
-       case P_MSGI:            /* MESSAGE IN phase */
-               {
-                       int start_sync = 0;
+                                       SYNCNEG=2;              /* negotiation completed */
+                                       SETRATE(SYNCRATE);
+                               }
+                               break;
 
-#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-                       if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgi | debug_phases))
-                               printk("MESSAGE IN, ");
-#endif
-                       SETPORT(SXFRCTL0, CH1);
+                       case BUS_DEVICE_RESET:
+                               {
+                                       int i;
 
-                       SETPORT(SIMODE0, 0);
-                       SETPORT(SIMODE1, ENBUSFREE);
+                                       for(i=0; i<8; i++) {
+                                               HOSTDATA(shpnt)->syncrate[i]=0;
+                                               HOSTDATA(shpnt)->syncneg[i]=0;
+                                       }
 
-                       while (phase == P_MSGI) {
-                               CURRENT_SC->SCp.Message = GETPORT(SCSIDAT);
-                               switch (CURRENT_SC->SCp.Message) {
-                               case DISCONNECT:
-#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-                                       if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases))
-                                               printk("target disconnected, ");
-#endif
-                                       CURRENT_SC->SCp.Message = 0;
-                                       CURRENT_SC->SCp.phase |= disconnected;
-                                       if (!HOSTDATA(shpnt)->reconnect)
-                                               aha152x_panic(shpnt, "target was not allowed to disconnect");
+                               }
+                               break;
+
+                       case EXTENDED_MODIFY_DATA_POINTER:
+                       case EXTENDED_EXTENDED_IDENTIFY:
+                       case EXTENDED_WDTR:
+                       default:
+                               ADDMSGO(MESSAGE_REJECT);
+                               break;
+                       }
+                       break;
+               }
 
-                                       break;
+               MSGILEN=0;
+       }
+}
 
-                               case COMMAND_COMPLETE:
-#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-                                       if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases))
-                                               printk("inbound message (COMMAND COMPLETE), ");
-#endif
-                                       done++;
-                                       break;
-
-                               case MESSAGE_REJECT:
-                                       if (CURRENT_SC->SCp.phase & in_sync) {
-                                               CURRENT_SC->SCp.phase &= ~in_sync;
-                                               SYNCRATE = 0x80;
-                                               printk("synchronous rejected, ");
-                                       } else
-                                               printk("inbound message (MESSAGE REJECT), ");
-#if defined(DEBUG_MSGI)
-                                       if (HOSTDATA(shpnt)->debug & debug_msgi)
-                                               printk("inbound message (MESSAGE REJECT), ");
-#endif
-                                       break;
+static void msgi_end(struct Scsi_Host *shpnt)
+{
+       if(MSGILEN>0)
+               printk(WARN_LEAD "target left before message completed (%d)\n", CMDINFO(CURRENT_SC), MSGILEN);
 
-                               case SAVE_POINTERS:
-#if defined(DEBUG_MSGI)
-                                       if (HOSTDATA(shpnt)->debug & debug_msgi)
-                                               printk("inbound message (SAVE DATA POINTERS), ");
-#endif
-                                       break;
+       if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) {
+               DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC));
+               SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
+       } 
+}
 
-                               case RESTORE_POINTERS:
-#if defined(DEBUG_MSGI)
-                                       if (HOSTDATA(shpnt)->debug & debug_msgi)
-                                               printk("inbound message (RESTORE DATA POINTERS), ");
-#endif
-                                       break;
+/*
+ * message out phase
+ *
+ */
+static void msgo_init(struct Scsi_Host *shpnt)
+{
+       if(MSGOLEN==0) {
+               if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) {
+                       ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->lun));
+               } else {
+                       printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC));
+                       ADDMSGO(MESSAGE_REJECT);
+               }
+       }
 
-                               case EXTENDED_MESSAGE:
-                                       {
-                                               char buffer[16];
-                                               int i;
+#if defined(AHA152X_DEBUG)
+       if(HOSTDATA(shpnt)->debug & debug_msgo) {
+               int i;
 
-#if defined(DEBUG_MSGI)
-                                               if (HOSTDATA(shpnt)->debug & debug_msgi)
-                                                       printk("inbound message (EXTENDED MESSAGE), ");
+               printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
+               for (i=0; i<MSGOLEN; i+=print_msg(&MSGO(i)), printk(" "))
+                       ;
+               printk(")\n");
+       }
 #endif
-                                               make_acklow(shpnt);
-                                               if (getphase(shpnt) != P_MSGI)
-                                                       break;
-
-                                               buffer[0] = EXTENDED_MESSAGE;
-                                               buffer[1] = GETPORT(SCSIDAT);
+}
 
-                                               for (i = 0; i < buffer[1] &&
-                                                    (make_acklow(shpnt), getphase(shpnt) == P_MSGI); i++)
-                                                       buffer[2 + i] = GETPORT(SCSIDAT);
+/*
+ * message out phase
+ *
+ */
+static void msgo_run(struct Scsi_Host *shpnt)
+{
+       if(MSGO_I==MSGOLEN)
+               DPRINTK(debug_msgo, DEBUG_LEAD "messages all sent (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
 
-#if defined(DEBUG_MSGI)
-                                               if (HOSTDATA(shpnt)->debug & debug_msgi)
-                                                       print_msg(buffer);
-#endif
+       while(MSGO_I<MSGOLEN) {
+               DPRINTK(debug_msgo, DEBUG_LEAD "message byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO(MSGO_I), MSGO_I, MSGOLEN);
 
-                                               switch (buffer[2]) {
-                                               case EXTENDED_SDTR:
-                                                       {
-                                                               long ticks;
+               if(TESTLO(SSTAT0, SPIORDY)) {
+                       DPRINTK(debug_msgo, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+                       return;
+               }
 
-                                                               if (buffer[1] != 3)
-                                                                       aha152x_panic(shpnt, "SDTR message length != 3");
+               if (MSGO_I==MSGOLEN-1) {
+                       /* Leave MESSAGE OUT after transfer */
+                       SETPORT(SSTAT1, CLRATNO);
+               }
 
-                                                               if (!HOSTDATA(shpnt)->synchronous)
-                                                                       break;
 
-                                                               printk("inbound SDTR: ");
-                                                               print_msg(buffer);
+               if (MSGO(MSGO_I) & IDENTIFY_BASE)
+                       CURRENT_SC->SCp.phase |= identified;
 
-                                                               ticks = (buffer[3] * 4 + 49) / 50;
+               if (MSGO(MSGO_I)==ABORT)
+                       CURRENT_SC->SCp.phase |= aborted;
 
-                                                               if (CURRENT_SC->SCp.phase & in_sync) {
-                                                                       /* we initiated SDTR */
-                                                                       if (ticks > 9 || buffer[4] < 1 || buffer[4] > 8)
-                                                                               aha152x_panic(shpnt, "received SDTR invalid");
+               if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
+                       CURRENT_SC->SCp.phase |= resetted;
 
-                                                                       SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
-                                                               } else if (ticks <= 9 && buffer[4] >= 1) {
-                                                                       if (buffer[4] > 8)
-                                                                               buffer[4] = 8;
+               SETPORT(SCSIDAT, MSGO(MSGO_I++));
+       }
+}
 
-                                                                       ADDMSG(EXTENDED_MESSAGE);
-                                                                       ADDMSG(3);
-                                                                       ADDMSG(EXTENDED_SDTR);
-                                                                       if (ticks < 4) {
-                                                                               ticks = 4;
-                                                                               ADDMSG(50);
-                                                                       } else
-                                                                               ADDMSG(buffer[3]);
+static void msgo_end(struct Scsi_Host *shpnt)
+{
+       if(MSGO_I<MSGOLEN)
+               printk(ERR_LEAD "message sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
+               
+       MSGO_I  = 0;
+       MSGOLEN = 0;
+}
 
-                                                                       ADDMSG(buffer[4]);
+/* 
+ * command phase
+ *
+ */
+static void cmd_init(struct Scsi_Host *shpnt)
+{
+       if (CURRENT_SC->SCp.sent_command) {
+               printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC));
+               done(shpnt, DID_ERROR << 16);
+               return;
+       }
 
-                                                                       printk("outbound SDTR: ");
-                                                                       print_msg(&MSG(MSGLEN - 5));
+#if defined(AHA152X_DEBUG)
+       if (HOSTDATA(shpnt)->debug & debug_cmd) {
+               printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC));
+               print_command(CURRENT_SC->cmnd);
+       }
+#endif
 
-                                                                       CURRENT_SC->SCp.phase |= in_sync;
+       CMD_I=0;
+}
 
-                                                                       SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
+/*
+ * command phase
+ *
+ */
+static void cmd_run(struct Scsi_Host *shpnt)
+{
+       if(CMD_I==CURRENT_SC->cmd_len) {
+               DPRINTK(debug_cmd, DEBUG_LEAD "command already completely sent (%d/%d)", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+               disp_ports(shpnt);
+       }
 
-                                                                       start_sync++;
-                                                               } else {
-                                                                       /* requested SDTR is too slow, do it asynchronously */
-                                                                       ADDMSG(MESSAGE_REJECT);
-                                                                       SYNCRATE = 0;
-                                                               }
+       while(CMD_I<CURRENT_SC->cmd_len) {
+               DPRINTK(debug_cmd, DEBUG_LEAD "command byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), CURRENT_SC->cmnd[CMD_I], CMD_I, CURRENT_SC->cmd_len);
 
-                                                               SETPORT(SCSIRATE, SYNCRATE & 0x7f);
-                                                       }
-                                                       break;
+               if(TESTLO(SSTAT0, SPIORDY)) {
+                       DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+                       return;
+               }
 
-                                               case EXTENDED_MODIFY_DATA_POINTER:
-                                               case EXTENDED_EXTENDED_IDENTIFY:
-                                               case EXTENDED_WDTR:
-                                               default:
-                                                       ADDMSG(MESSAGE_REJECT);
-                                                       break;
-                                               }
-                                       }
-                                       break;
+               SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
+       }
+}
 
-                               default:
-                                       printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message);
-                                       break;
+static void cmd_end(struct Scsi_Host *shpnt)
+{
+       if(CMD_I<CURRENT_SC->cmd_len)
+               printk(ERR_LEAD "command sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+       else
+               CURRENT_SC->SCp.sent_command++;
+}
 
-                               }
+/*
+ * status phase
+ *
+ */
+static void status_run(struct Scsi_Host *shpnt)
+{
+       if(TESTLO(SSTAT0,SPIORDY)) {
+               DPRINTK(debug_status, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+               return;
+       }
 
-                               make_acklow(shpnt);
-                               phase = getphase(shpnt);
-                       }
+       CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
 
-                       if (start_sync)
-                               CURRENT_SC->SCp.phase |= in_sync;
-                       else
-                               CURRENT_SC->SCp.phase &= ~in_sync;
+#if defined(AHA152X_DEBUG)
+       if (HOSTDATA(shpnt)->debug & debug_status) {
+               printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status);
+               print_status(CURRENT_SC->SCp.Status);
+               printk("\n");
+       }
+#endif
+}
 
-                       if (MSGLEN > 0)
-                               SETPORT(SCSISIG, P_MSGI | ATNO);
+/*
+ * data in phase
+ *
+ */
+static void datai_init(struct Scsi_Host *shpnt)
+{
+       SETPORT(DMACNTRL0, RSTFIFO);
+       SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
 
-                       /* clear SCSI fifo on BUSFREE */
-                       if (phase == P_BUSFREE)
-                               SETPORT(SXFRCTL0, CH1 | CLRCH1);
+       SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+       SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
 
-                       if (CURRENT_SC->SCp.phase & disconnected) {
-                               save_flags(flags);
-                               cli();
-#if defined(DEBUG_QUEUES)
-                               if (HOSTDATA(shpnt)->debug & debug_queues)
-                                       printk("d+, ");
-#endif
-                               append_SC(&DISCONNECTED_SC, CURRENT_SC);
-                               CURRENT_SC->SCp.phase |= 1 << 16;
-                               CURRENT_SC = NULL;
-                               restore_flags(flags);
+       SETPORT(SIMODE0, 0);
+       SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
 
-                               SETBITS(SCSISEQ, ENRESELI);
+       DATA_LEN=0;
+       DPRINTK(debug_datai,
+               DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
+               CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
 
-                               SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-                               SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+static void datai_run(struct Scsi_Host *shpnt)
+{
+       unsigned int the_time;
+       int fifodata, data_count;
 
-                               SETBITS(DMACNTRL0, INTEN);
+       /*
+        * loop while the phase persists or the fifos are not empty
+        *
+        */
+       while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
+               /* FIXME: maybe this should be done by setting up
+                * STCNT to trigger ENSWRAP interrupt, instead of
+                * polling for DFIFOFULL
+                */
+               the_time=jiffies + 100;
+               while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
+                       barrier();
 
-                               return;
-                       }
+               if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
+                       printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC));
+                       disp_ports(shpnt);
+                       break;
                }
-               break;
-
-       case P_STATUS:          /* STATUS IN phase */
-#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-               if (HOSTDATA(shpnt)->debug & (debug_status | debug_intr | debug_phases))
-                       printk("STATUS, ");
-#endif
-               SETPORT(SXFRCTL0, CH1);
-
-               SETPORT(SIMODE0, 0);
-               SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
 
-               if (TESTHI(SSTAT1, PHASEMIS))
-                       printk("aha152x: passing STATUS phase");
+               if(TESTHI(DMASTAT, DFIFOFULL)) {
+                       fifodata = 128;
+               } else {
+                       the_time=jiffies + 100;
+                       while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
+                               barrier();
 
-               CURRENT_SC->SCp.Status = GETPORT(SCSIBUS);
-               make_acklow(shpnt);
-               getphase(shpnt);
+                       if(TESTLO(SSTAT2, SEMPTY)) {
+                               printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC));
+                               disp_ports(shpnt);
+                               break;
+                       }
 
-#if defined(DEBUG_STATUS)
-               if (HOSTDATA(shpnt)->debug & debug_status) {
-                       printk("inbound status ");
-                       print_status(CURRENT_SC->SCp.Status);
-                       printk(", ");
+                       fifodata = GETPORT(FIFOSTAT);
                }
-#endif
-               break;
 
-       case P_DATAI:           /* DATA IN phase */
-               {
-                       int fifodata, data_count, done;
+                while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
+                        data_count = fifodata>CURRENT_SC->SCp.this_residual ?
+                                       CURRENT_SC->SCp.this_residual :
+                                       fifodata;
+                       fifodata -= data_count;
+
+                        if(data_count & 1) {
+                               DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC));
+                                SETPORT(DMACNTRL0, ENDMA|_8BIT);
+                                *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+                                CURRENT_SC->SCp.this_residual--;
+                                DATA_LEN++;
+                                SETPORT(DMACNTRL0, ENDMA);
+                        }
+
+                        if(data_count > 1) {
+                               DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
+                                data_count >>= 1;
+                                insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+                                CURRENT_SC->SCp.ptr           += 2 * data_count;
+                                CURRENT_SC->SCp.this_residual -= 2 * data_count;
+                                DATA_LEN                      += 2 * data_count;
+                        }
+
+                        if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+                                       /* advance to next buffer */
+                                       CURRENT_SC->SCp.buffers_residual--;
+                                       CURRENT_SC->SCp.buffer++;
+                                       CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address;
+                                       CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+                       } 
+                }
+
+               if(fifodata>0 && CURRENT_SC->SCp.this_residual==0) {
+                       printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT));
+                       break;
+               }
+       }
 
-#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-                       if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr | debug_phases))
-                               printk("DATA IN, ");
-#endif
+       if(TESTLO(DMASTAT, INTSTAT) ||
+          TESTLO(DMASTAT, DFIFOEMP) ||
+          TESTLO(SSTAT2, SEMPTY) ||
+          GETPORT(FIFOSTAT)>0) {
+               /*
+                * something went wrong, if there's something left in the fifos
+                * or the phase didn't change
+                */
+               printk(ERR_LEAD "fifos should be empty and phase should have changed\n", CMDINFO(CURRENT_SC));
+               disp_ports(shpnt);
+       }
 
-#if 0
-                       if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT))
-                               printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
-                                      GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT));
-#endif
+       if(DATA_LEN!=GETSTCNT()) {
+               printk(ERR_LEAD
+                      "manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d)",
+                      CMDINFO(CURRENT_SC), DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, GETPORT(FIFOSTAT));
+               disp_ports(shpnt);
+               mdelay(10000);
+       }
+}
 
-                       /* reset host fifo */
-                       SETPORT(DMACNTRL0, RSTFIFO);
-                       SETPORT(DMACNTRL0, RSTFIFO | ENDMA);
+static void datai_end(struct Scsi_Host *shpnt)
+{
+       CURRENT_SC->resid -= GETSTCNT();
 
-                       SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN);
+       DPRINTK(debug_datai,
+               DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n",
+               CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT());
 
-                       SETPORT(SIMODE0, 0);
-                       SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
+       SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+       SETPORT(DMACNTRL0, 0);
+}
 
-                       /* done is set when the FIFO is empty after the target left DATA IN */
-                       done = 0;
+/*
+ * data out phase
+ *
+ */
+static void datao_init(struct Scsi_Host *shpnt)
+{
+       SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
+       SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
 
-                       /* while the target stays in DATA to transfer data */
-                       while (!done) {
-#if defined(DEBUG_DATAI)
-                               if (HOSTDATA(shpnt)->debug & debug_datai)
-                                       printk("expecting data, ");
-#endif
-                               /* wait for PHASEMIS or full FIFO */
-                               while (TESTLO(DMASTAT, DFIFOFULL | INTSTAT))
-                                       barrier();
+       SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+       SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
 
-#if defined(DEBUG_DATAI)
-                               if (HOSTDATA(shpnt)->debug & debug_datai)
-                                       printk("ok, ");
-#endif
+       SETPORT(SIMODE0, 0);
+       SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
 
-                               if (TESTHI(DMASTAT, DFIFOFULL))
-                                       fifodata = GETPORT(FIFOSTAT);
-                               else {
-                                       /* wait for SCSI fifo to get empty */
-                                       while (TESTLO(SSTAT2, SEMPTY))
-                                               barrier();
-
-                                       /* rest of data in FIFO */
-                                       fifodata = GETPORT(FIFOSTAT);
-#if defined(DEBUG_DATAI)
-                                       if (HOSTDATA(shpnt)->debug & debug_datai)
-                                               printk("last transfer, ");
-#endif
-                                       done = 1;
-                               }
+       DATA_LEN = CURRENT_SC->resid;
 
-#if defined(DEBUG_DATAI)
-                               if (HOSTDATA(shpnt)->debug & debug_datai)
-                                       printk("fifodata=%d, ", fifodata);
-#endif
+       DPRINTK(debug_datao,
+               DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
+               CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
 
-                               while (fifodata && CURRENT_SC->SCp.this_residual) {
-                                       data_count = fifodata;
+static void datao_run(struct Scsi_Host *shpnt)
+{
+       unsigned int the_time;
+       int data_count;
+
+       /* until phase changes or all data sent */
+       while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) {
+               data_count = 128;
+               if(data_count > CURRENT_SC->SCp.this_residual)
+                       data_count=CURRENT_SC->SCp.this_residual;
+
+               if(TESTLO(DMASTAT, DFIFOEMP)) {
+                       printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT));
+                       disp_ports(shpnt);
+                       break;
+               }
 
-                                       /* limit data transfer to size of first sg buffer */
-                                       if (data_count > CURRENT_SC->SCp.this_residual)
-                                               data_count = CURRENT_SC->SCp.this_residual;
+               if(data_count & 1) {
+                       SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
+                       SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
+                       CURRENT_SC->SCp.this_residual--;
+                       CURRENT_SC->resid--;
+                       SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
+               }
 
-                                       fifodata -= data_count;
+               if(data_count > 1) {
+                       data_count >>= 1;
+                       outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+                       CURRENT_SC->SCp.ptr           += 2 * data_count;
+                       CURRENT_SC->SCp.this_residual -= 2 * data_count;
+                       CURRENT_SC->resid             -= 2 * data_count;
+               }
+
+               if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+                       /* advance to next buffer */
+                       CURRENT_SC->SCp.buffers_residual--;
+                       CURRENT_SC->SCp.buffer++;
+                       CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address;
+                       CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+               }
 
-#if defined(DEBUG_DATAI)
-                                       if (HOSTDATA(shpnt)->debug & debug_datai)
-                                               printk("data_count=%d, ", data_count);
-#endif
+               the_time=jiffies+100;
+               while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
+                       barrier();
 
-                                       if (data_count & 1) {
-                                               /* get a single byte in byte mode */
-                                               SETBITS(DMACNTRL0, _8BIT);
-                                               *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
-                                               CURRENT_SC->SCp.this_residual--;
-                                       }
-                                       if (data_count > 1) {
-                                               CLRBITS(DMACNTRL0, _8BIT);
-                                               data_count >>= 1;       /* Number of words */
-                                               insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
-#if defined(DEBUG_DATAI)
-                                               if (HOSTDATA(shpnt)->debug & debug_datai)
-                                                       /* show what comes with the last transfer */
-                                                       if (done) {
-#if 0
-                                                               int i;
-                                                               unsigned char *data;
-#endif
+               if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
+                       printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC));
+                       disp_ports(shpnt);
+                       break;
+               }
+       }
+}
 
-                                                               printk("data on last transfer (%d bytes) ",
-                                                                      2 * data_count);
-#if 0
-                                                               printk("data on last transfer (%d bytes: ",
-                                                                      2 * data_count);
-                                                               data = (unsigned char *) CURRENT_SC->SCp.ptr;
-                                                               for (i = 0; i < 2 * data_count; i++)
-                                                                       printk("%2x ", *data++);
-                                                               printk("), ");
-#endif
-                                                       }
-#endif
-                                               CURRENT_SC->SCp.ptr += 2 * data_count;
-                                               CURRENT_SC->SCp.this_residual -= 2 * data_count;
-                                       }
-                                       /* if this buffer is full and there are more buffers left */
-                                       if (!CURRENT_SC->SCp.this_residual &&
-                                           CURRENT_SC->SCp.buffers_residual) {
-                                               /* advance to next buffer */
-                                               CURRENT_SC->SCp.buffers_residual--;
-                                               CURRENT_SC->SCp.buffer++;
-                                               CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
-                                               CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
-                                       }
-                               }
+static void datao_end(struct Scsi_Host *shpnt)
+{
+       if(TESTLO(DMASTAT, DFIFOEMP)) {
+               int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
+
+               DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transfered)\n",
+                       CMDINFO(CURRENT_SC),
+                       data_count,
+                       DATA_LEN-CURRENT_SC->resid,
+                       GETSTCNT());
+
+               CURRENT_SC->resid += data_count;
+
+               data_count -= CURRENT_SC->SCp.ptr - CURRENT_SC->SCp.buffer->address;
+               while(data_count>0) {
+                       CURRENT_SC->SCp.buffer--;
+                       CURRENT_SC->SCp.buffers_residual++;
+                       data_count -= CURRENT_SC->SCp.buffer->length;
+               }
+               CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address - data_count;
+               CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
+       }
 
-                               /*
-                                * FIFO should be empty
-                                */
-                               if (fifodata > 0) {
-                                       printk("aha152x: more data than expected (%d bytes)\n",
-                                              GETPORT(FIFOSTAT));
-                                       SETBITS(DMACNTRL0, _8BIT);
-                                       printk("aha152x: data (");
-                                       while (fifodata--)
-                                               printk("%2x ", GETPORT(DATAPORT));
-                                       printk(")\n");
-                               }
-#if defined(DEBUG_DATAI)
-                               if (HOSTDATA(shpnt)->debug & debug_datai)
-                                       if (!fifodata)
-                                               printk("fifo empty, ");
-                                       else
-                                               printk("something left in fifo, ");
-#endif
-                       }
+       DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n",
+               CMDINFO(CURRENT_SC),
+               CURRENT_SC->request_bufflen,
+               CURRENT_SC->resid,
+               GETSTCNT());
 
-#if defined(DEBUG_DATAI)
-                       if ((HOSTDATA(shpnt)->debug & debug_datai) &&
-                           (CURRENT_SC->SCp.buffers_residual ||
-                            CURRENT_SC->SCp.this_residual))
-                               printk("left buffers (buffers=%d, bytes=%d), ",
-                                      CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual);
-#endif
-                       /* transfer can be considered ended, when SCSIEN reads back zero */
-                       CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
-                       while (TESTHI(SXFRCTL0, SCSIEN))
-                               barrier();
-                       CLRBITS(DMACNTRL0, ENDMA);
+       SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+       SETPORT(SXFRCTL0, CH1);
 
-#if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
-                       if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr))
-                               printk("got %d bytes, ", GETSTCNT());
-#endif
+       SETPORT(DMACNTRL0, 0);
+}
 
-                       CURRENT_SC->SCp.have_data_in++;
+/*
+ * figure out what state we're in
+ *
+ */
+static int update_state(struct Scsi_Host *shpnt)
+{
+       int dataphase=0;
+       unsigned int stat0 = GETPORT(SSTAT0);
+       unsigned int stat1 = GETPORT(SSTAT1);
+
+       PREVSTATE = STATE;
+       STATE=unknown;
+
+       if(stat1 & SCSIRSTI) {
+               STATE=rsti;
+               SETPORT(SCSISEQ,0);
+               SETPORT(SSTAT1,SCSIRSTI);
+       } else if(stat0 & SELDI && PREVSTATE==busfree) {
+               STATE=seldi;
+       } else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) {
+               STATE=seldo;
+       } else if(stat1 & SELTO) {
+               STATE=selto;
+       } else if(stat1 & BUSFREE) {
+               STATE=busfree;
+               SETPORT(SSTAT1,BUSFREE);
+       } else if(stat1 & SCSIPERR) {
+               STATE=parerr;
+               SETPORT(SSTAT1,SCSIPERR);
+       } else if(stat1 & REQINIT) {
+               switch(GETPORT(SCSISIG) & P_MASK) {
+               case P_MSGI:    STATE=msgi;     break;
+               case P_MSGO:    STATE=msgo;     break;
+               case P_DATAO:   STATE=datao;    break;
+               case P_DATAI:   STATE=datai;    break;
+               case P_STATUS:  STATE=status;   break;
+               case P_CMD:     STATE=cmd;      break;
                }
-               break;
+               dataphase=1;
+       }
 
-       case P_DATAO:           /* DATA OUT phase */
-               {
-                       int data_count;
+       if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
+               printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC));
+               disp_ports(shpnt);
+       }
 
-#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-                       if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr | debug_phases))
-                               printk("DATA OUT, ");
-#endif
-#if defined(DEBUG_DATAO)
-                       if (HOSTDATA(shpnt)->debug & debug_datao)
-                               printk("got data to send (bytes=%d, buffers=%d), ",
-                                      CURRENT_SC->SCp.this_residual,
-                                      CURRENT_SC->SCp.buffers_residual);
-#endif
+       if(STATE!=PREVSTATE) {
+               LASTSTATE=PREVSTATE;
+       }
 
-                       if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) {
-                               printk("%d(%d) left in FIFO, ",
-                                      GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT));
-                               aha152x_panic(shpnt, "FIFO should be empty");
-                       }
-                       SETPORT(SXFRCTL0, CH1 | CLRSTCNT | CLRCH1);
-                       SETPORT(SXFRCTL0, SCSIEN | DMAEN | CH1);
-
-                       SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
-                       SETPORT(DMACNTRL0, ENDMA | WRITE_READ);
-
-                       SETPORT(SIMODE0, 0);
-                       SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-
-                       /* while current buffer is not empty or
-                          there are more buffers to transfer */
-                       while (TESTLO(SSTAT1, PHASEMIS) &&
-                              (CURRENT_SC->SCp.this_residual ||
-                               CURRENT_SC->SCp.buffers_residual)) {
-#if defined(DEBUG_DATAO)
-                               if (HOSTDATA(shpnt)->debug & debug_datao)
-                                       printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
-                                          CURRENT_SC->SCp.this_residual,
-                                       CURRENT_SC->SCp.buffers_residual);
-#endif
-                               /* transfer rest of buffer, but max. 128 byte */
-                               data_count =
-                                   CURRENT_SC->SCp.this_residual > 128 ?
-                                   128 : CURRENT_SC->SCp.this_residual;
-
-#if defined(DEBUG_DATAO)
-                               if (HOSTDATA(shpnt)->debug & debug_datao)
-                                       printk("data_count=%d, ", data_count);
-#endif
+       return dataphase;
+}
 
-                               if (data_count & 1) {
-                                       /* put a single byte in byte mode */
-                                       SETBITS(DMACNTRL0, _8BIT);
-                                       SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
-                                       CURRENT_SC->SCp.this_residual--;
-                               }
-                               if (data_count > 1) {
-                                       CLRBITS(DMACNTRL0, _8BIT);
-                                       data_count >>= 1;       /* number of words */
-                                       outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
-                                       CURRENT_SC->SCp.ptr += 2 * data_count;
-                                       CURRENT_SC->SCp.this_residual -= 2 * data_count;
-                               }
-                               /* wait for FIFO to get empty */
-                               while (TESTLO(DMASTAT, DFIFOEMP | INTSTAT))
-                                       barrier();
-
-#if defined(DEBUG_DATAO)
-                               if (HOSTDATA(shpnt)->debug & debug_datao)
-                                       printk("fifo (%d bytes), transfered (%d bytes), ",
-                                         GETPORT(FIFOSTAT), GETSTCNT());
-#endif
+/*
+ * handle parity error
+ *
+ * FIXME: in which phase?
+ *
+ */
+static void parerr_run(struct Scsi_Host *shpnt)
+{
+       printk(ERR_LEAD "parity error\n", CMDINFO(CURRENT_SC));
+       done(shpnt, DID_PARITY << 16);
+}
 
-                               /* if this buffer is empty and there are more buffers left */
-                               if (TESTLO(SSTAT1, PHASEMIS) &&
-                                   !CURRENT_SC->SCp.this_residual &&
-                                   CURRENT_SC->SCp.buffers_residual) {
-                                       /* advance to next buffer */
-                                       CURRENT_SC->SCp.buffers_residual--;
-                                       CURRENT_SC->SCp.buffer++;
-                                       CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
-                                       CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
-                               }
-                       }
+/*
+ * handle reset in
+ *
+ */
+static void rsti_run(struct Scsi_Host *shpnt)
+{
+       Scsi_Cmnd *ptr;
 
-                       if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) {
-                               /* target leaves DATA OUT for an other phase (perhaps disconnect) */
-
-                               /* data in fifos has to be resend */
-                               data_count = GETPORT(SSTAT2) & (SFULL | SFCNT);
-
-                               data_count += GETPORT(FIFOSTAT);
-                               CURRENT_SC->SCp.ptr -= data_count;
-                               CURRENT_SC->SCp.this_residual += data_count;
-#if defined(DEBUG_DATAO)
-                               if (HOSTDATA(shpnt)->debug & debug_datao)
-                                       printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), "
-                                              "transfer incomplete, resetting fifo, ",
-                                          CURRENT_SC->SCp.this_residual,
-                                       CURRENT_SC->SCp.buffers_residual,
-                                              data_count);
-#endif
-                               SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
-                               CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
-                               CLRBITS(DMACNTRL0, ENDMA);
-                       } else {
-#if defined(DEBUG_DATAO)
-                               if (HOSTDATA(shpnt)->debug & debug_datao)
-                                       printk("waiting for SCSI fifo to get empty, ");
-#endif
-                               /* wait for SCSI fifo to get empty */
-                               while (TESTLO(SSTAT2, SEMPTY))
-                                       barrier();
-#if defined(DEBUG_DATAO)
-                               if (HOSTDATA(shpnt)->debug & debug_datao)
-                                       printk("ok, left data (bytes=%d, buffers=%d) ",
-                                          CURRENT_SC->SCp.this_residual,
-                                       CURRENT_SC->SCp.buffers_residual);
-#endif
-                               CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
+       printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO);
+       
+       ptr=DISCONNECTED_SC;
+       while(ptr) {
+               Scsi_Cmnd *next = SCNEXT(ptr);
 
-                               /* transfer can be considered ended, when SCSIEN reads back zero */
-                               while (TESTHI(SXFRCTL0, SCSIEN))
-                                       barrier();
+               if (!ptr->device->soft_reset) {
+                       remove_SC(&DISCONNECTED_SC, ptr);
 
-                               CLRBITS(DMACNTRL0, ENDMA);
-                       }
+                       kfree(ptr->host_scribble);
+                       ptr->host_scribble=0;
 
-#if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
-                       if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr))
-                               printk("sent %d data bytes, ", GETSTCNT());
-#endif
+                       ptr->result =  DID_RESET << 16;
+                       ptr->scsi_done(ptr);
                }
-               break;
-
-       case P_BUSFREE: /* BUSFREE */
-#if defined(DEBUG_RACE)
-               leave_driver("(BUSFREE) intr");
-#endif
-#if defined(DEBUG_PHASES)
-               if (HOSTDATA(shpnt)->debug & debug_phases)
-                       printk("unexpected BUS FREE, ");
-#endif
-               CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
-
-               aha152x_done(shpnt, DID_ERROR << 16);   /* Don't know any better */
-               return;
-               break;
-
-       case P_PARITY:          /* parity error in DATA phase */
-#if defined(DEBUG_RACE)
-               leave_driver("(DID_PARITY) intr");
-#endif
-               printk("PARITY error in DATA phase, ");
-
-               CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
-
-               SETBITS(DMACNTRL0, INTEN);
-               aha152x_done(shpnt, DID_PARITY << 16);
-               return;
-               break;
 
-       default:
-               printk("aha152x: unexpected phase\n");
-               break;
+               ptr = next;
        }
 
-       if (done) {
-#if defined(DEBUG_INTR)
-               if (HOSTDATA(shpnt)->debug & debug_intr)
-                       printk("command done.\n");
-#endif
-#if defined(DEBUG_RACE)
-               leave_driver("(done) intr");
-#endif
-
-               SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-               SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-               SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
+       if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
+               done(shpnt, DID_RESET << 16 );
+}
 
-               SETBITS(DMACNTRL0, INTEN);
 
-               aha152x_done(shpnt,
-                            (CURRENT_SC->SCp.Status & 0xff)
-                            | ((CURRENT_SC->SCp.Message & 0xff) << 8)
-                            | (DID_OK << 16));
+/*
+ * bottom-half handler
+ *
+ */
+static void complete(struct Scsi_Host *shpnt)
+{
+       int dataphase;
+       unsigned long flags;
+       int pending;
 
-#if defined(DEBUG_RACE)
-               printk("done returned (DID_OK: Status=%x; Message=%x).\n",
-                      CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message);
-#endif
-               return;
-       }
-       if (CURRENT_SC)
-               CURRENT_SC->SCp.phase |= 1 << 16;
+       DO_LOCK(flags);
+       if(HOSTDATA(shpnt)->in_intr!=0)
+               aha152x_error(shpnt, "bottom-half already running!?");
+       HOSTDATA(shpnt)->in_intr++;
+       DO_UNLOCK(flags);
 
-       SETPORT(SIMODE0, 0);
-       SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-#if defined(DEBUG_INTR)
-       if (HOSTDATA(shpnt)->debug & debug_intr)
-               disp_enintr(shpnt);
-#endif
-#if defined(DEBUG_RACE)
-       leave_driver("(PHASEEND) intr");
-#endif
+       /*
+        * loop while there are interrupt conditions pending
+        *
+        */
+       do {
+               unsigned long start = jiffies;
+               dataphase=update_state(shpnt);
+
+               DPRINTK(debug_phases, LEAD "start %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
+
+               /*
+                * end previous state
+                *
+                */
+               if(PREVSTATE!=STATE && states[PREVSTATE].end)
+                       states[PREVSTATE].end(shpnt);
+
+               /*
+                * disable SPIO mode if previous phase used it
+                * and this one doesn't
+                *
+                */
+               if(states[PREVSTATE].spio && !states[STATE].spio) {
+                       SETPORT(SXFRCTL0, CH1);
+                       SETPORT(DMACNTRL0, 0);
+                       if(CURRENT_SC)
+                               CURRENT_SC->SCp.phase &= ~spiordy;
+               }
 
+               /*
+                * accept current dataphase phase
+                *
+                */
+               if(dataphase) {
+                       SETPORT(SSTAT0, REQINIT);
+                       SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
+                       SETPORT(SSTAT1, PHASECHG);  
+               }
+               
+               /*
+                * enable SPIO mode if previous didn't use it
+                * and this one does
+                *
+                */
+               if(!states[PREVSTATE].spio && states[STATE].spio) {
+                       SETPORT(DMACNTRL0, 0);
+                       SETPORT(SXFRCTL0, CH1|SPIOEN);
+                       if(CURRENT_SC)
+                               CURRENT_SC->SCp.phase |= spiordy;
+               }
+               
+               /*
+                * initialize for new state
+                *
+                */
+               if(PREVSTATE!=STATE && states[STATE].init)
+                       states[STATE].init(shpnt);
+               
+               /*
+                * handle current state
+                *
+                */
+               if(states[STATE].run)
+                       states[STATE].run(shpnt);
+               else
+                       printk(ERR_LEAD "unexpected state (%x)\n", CMDINFO(CURRENT_SC), STATE);
+               
+               /*
+                * setup controller to interrupt on
+                * the next expected condition and
+                * loop if it's already there
+                *
+                */
+               DO_LOCK(flags);
+               pending=setup_expected_interrupts(shpnt);
+#if defined(AHA152X_STAT)
+               HOSTDATA(shpnt)->count[STATE]++;
+               if(PREVSTATE!=STATE)
+                       HOSTDATA(shpnt)->count_trans[STATE]++;
+               HOSTDATA(shpnt)->time[STATE] += jiffies-start;
+#endif
+               DO_UNLOCK(flags);
+
+               DPRINTK(debug_phases, LEAD "end %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
+       } while(pending);
+
+       /*
+        * enable interrupts and leave bottom-half
+        *
+        */
+       DO_LOCK(flags);
+       HOSTDATA(shpnt)->in_intr--;
        SETBITS(DMACNTRL0, INTEN);
-       return;
+       DO_UNLOCK(flags);
 }
 
+
 /* 
- * Dump the current driver status and panic...
+ * Dump the current driver status and panic
  */
-static void aha152x_panic(struct Scsi_Host *shpnt, char *msg)
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
 {
-       printk("\naha152x: %s\n", msg);
+       printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg);
        show_queues(shpnt);
-       panic("aha152x panic");
+       panic("aha152x panic\n");
 }
 
 /*
@@ -2666,18 +2980,16 @@ static void aha152x_panic(struct Scsi_Host *shpnt, char *msg)
  */
 static void disp_ports(struct Scsi_Host *shpnt)
 {
-#ifdef DEBUG_AHA152X
+#if defined(AHA152X_DEBUG)
        int s;
 
-#ifdef SKIP_PORTS
-       if (HOSTDATA(shpnt)->debug & debug_skipports)
-               return;
-#endif
-
-       printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+       printk("\n%s: %s(%s) ",
+               CURRENT_SC ? "busy" : "waiting",
+               states[STATE].name,
+               states[PREVSTATE].name);
 
        s = GETPORT(SCSISEQ);
-       printk("SCSISEQ (");
+       printk("SCSISEQ");
        if (s & TEMODEO)
                printk("TARGET MODE ");
        if (s & ENSELO)
@@ -2696,7 +3008,7 @@ static void disp_ports(struct Scsi_Host *shpnt)
                printk("SCSIRSTO ");
        printk(");");
 
-       printk(" SCSISIG (");
+       printk(" SCSISIG(");
        s = GETPORT(SCSISIG);
        switch (s & P_MASK) {
        case P_DATAO:
@@ -2726,7 +3038,7 @@ static void disp_ports(struct Scsi_Host *shpnt)
 
        printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
 
-       printk("SSTAT (");
+       printk("SSTAT");
        s = GETPORT(SSTAT0);
        if (s & TARGET)
                printk("TARGET ");
@@ -2765,7 +3077,7 @@ static void disp_ports(struct Scsi_Host *shpnt)
        printk("); ");
 
 
-       printk("SSTAT (");
+       printk("SSTAT");
 
        s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
 
@@ -2806,7 +3118,7 @@ static void disp_ports(struct Scsi_Host *shpnt)
                printk("REQINIT ");
        printk("); ");
 
-       printk("SXFRCTL0 (");
+       printk("SXFRCTL0");
 
        s = GETPORT(SXFRCTL0);
        if (s & SCSIEN)
@@ -2823,24 +3135,26 @@ static void disp_ports(struct Scsi_Host *shpnt)
                printk("CLRCH1 ");
        printk("); ");
 
-       printk("SIGNAL (");
+       printk("SIGNAL");
 
        s = GETPORT(SCSISIG);
-       if (s & ATNI)
+       if (s & SIG_ATNI)
                printk("ATNI ");
-       if (s & SELI)
+       if (s & SIG_SELI)
                printk("SELI ");
-       if (s & BSYI)
+       if (s & SIG_BSYI)
                printk("BSYI ");
-       if (s & REQI)
+       if (s & SIG_REQI)
                printk("REQI ");
-       if (s & ACKI)
+       if (s & SIG_ACKI)
                printk("ACKI ");
        printk("); ");
 
        printk("SELID (%02x), ", GETPORT(SELID));
 
-       printk("SSTAT2 (");
+       printk("STCNT (%d), ", GETSTCNT());
+       
+       printk("SSTAT2( ");
 
        s = GETPORT(SSTAT2);
        if (s & SOFFSET)
@@ -2854,7 +3168,7 @@ static void disp_ports(struct Scsi_Host *shpnt)
        s = GETPORT(SSTAT3);
        printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
 
-       printk("SSTAT4 (");
+       printk("SSTAT4");
        s = GETPORT(SSTAT4);
        if (s & SYNCERR)
                printk("SYNCERR ");
@@ -2864,7 +3178,7 @@ static void disp_ports(struct Scsi_Host *shpnt)
                printk("FRERR ");
        printk("); ");
 
-       printk("DMACNTRL0 (");
+       printk("DMACNTRL0");
        s = GETPORT(DMACNTRL0);
        printk("%s ", s & _8BIT ? "8BIT" : "16BIT");
        printk("%s ", s & DMA ? "DMA" : "PIO");
@@ -2879,7 +3193,7 @@ static void disp_ports(struct Scsi_Host *shpnt)
                printk("SWINT ");
        printk("); ");
 
-       printk("DMASTAT (");
+       printk("DMASTAT");
        s = GETPORT(DMASTAT);
        if (s & ATDONE)
                printk("ATDONE ");
@@ -2889,9 +3203,7 @@ static void disp_ports(struct Scsi_Host *shpnt)
                printk("DFIFOFULL ");
        if (s & DFIFOEMP)
                printk("DFIFOEMP ");
-       printk(")");
-
-       printk("\n");
+       printk(")\n");
 #endif
 }
 
@@ -2902,7 +3214,7 @@ static void disp_enintr(struct Scsi_Host *shpnt)
 {
        int s;
 
-       printk("enabled interrupts (");
+       printk(KERN_DEBUG "enabled interrupts ( ");
 
        s = GETPORT(SIMODE0);
        if (s & ENSELDO)
@@ -2938,100 +3250,38 @@ static void disp_enintr(struct Scsi_Host *shpnt)
        printk(")\n");
 }
 
-#if defined(DEBUG_RACE)
-
-static const char *should_leave;
-static int in_driver = 0;
-
-/*
- * Only one routine can be in the driver at once.
- */
-static void enter_driver(const char *func)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       printk("aha152x: entering %s() (%x)\n", func, jiffies);
-       if (in_driver) {
-               printk("%s should leave first.\n", should_leave);
-               panic("aha152x: already in driver\n");
-       }
-       in_driver++;
-       should_leave = func;
-       restore_flags(flags);
-}
-
-static void leave_driver(const char *func)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       printk("\naha152x: leaving %s() (%x)\n", func, jiffies);
-       if (!in_driver) {
-               printk("aha152x: %s already left.\n", should_leave);
-               panic("aha152x: %s already left driver.\n");
-       }
-       in_driver--;
-       should_leave = func;
-       restore_flags(flags);
-}
-#endif
-
 /*
  * Show the command data of a command
  */
-static void show_command(Scsi_Cmnd * ptr)
+static void show_command(Scsi_Cmnd *ptr)
 {
-       printk("0x%08x: target=%d; lun=%d; cmnd=(",
+       printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(",
               (unsigned int) ptr, ptr->target, ptr->lun);
 
        print_command(ptr->cmnd);
 
-       printk("); residual=%d; buffers=%d; phase |",
-              ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+       printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
+              ptr->request_bufflen, ptr->resid);
 
        if (ptr->SCp.phase & not_issued)
                printk("not issued|");
-       if (ptr->SCp.phase & in_selection)
-               printk("in selection|");
+       if (ptr->SCp.phase & selecting)
+               printk("selecting|");
+       if (ptr->SCp.phase & identified)
+               printk("identified|");
        if (ptr->SCp.phase & disconnected)
                printk("disconnected|");
+       if (ptr->SCp.phase & completed)
+               printk("completed|");
+       if (ptr->SCp.phase & spiordy)
+               printk("spiordy|");
+       if (ptr->SCp.phase & syncneg)
+               printk("syncneg|");
        if (ptr->SCp.phase & aborted)
                printk("aborted|");
-       if (ptr->SCp.phase & sent_ident)
-               printk("send_ident|");
-       if (ptr->SCp.phase & in_other) {
-               printk("; in other(");
-               switch ((ptr->SCp.phase >> 16) & P_MASK) {
-               case P_DATAO:
-                       printk("DATA OUT");
-                       break;
-               case P_DATAI:
-                       printk("DATA IN");
-                       break;
-               case P_CMD:
-                       printk("COMMAND");
-                       break;
-               case P_STATUS:
-                       printk("STATUS");
-                       break;
-               case P_MSGO:
-                       printk("MESSAGE OUT");
-                       break;
-               case P_MSGI:
-                       printk("MESSAGE IN");
-                       break;
-               default:
-                       printk("*illegal*");
-                       break;
-               }
-               printk(")");
-               if (ptr->SCp.phase & (1 << 16))
-                       printk("; phaseend");
-       }
-       printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+       if (ptr->SCp.phase & resetted)
+               printk("resetted|");
+       printk("; next=0x%p\n", SCNEXT(ptr));
 }
 
 /*
@@ -3039,33 +3289,27 @@ static void show_command(Scsi_Cmnd * ptr)
  */
 static void show_queues(struct Scsi_Host *shpnt)
 {
-       unsigned long flags;
        Scsi_Cmnd *ptr;
+       unsigned long flags;
 
-       save_flags(flags);
-       cli();
-       printk("QUEUE STATUS:\nissue_SC:\n");
-       for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+       DO_LOCK(flags);
+       printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
+       for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
                show_command(ptr);
+       DO_UNLOCK(flags);
 
-       printk("current_SC:\n");
+       printk(KERN_DEBUG "current_SC:\n");
        if (CURRENT_SC)
                show_command(CURRENT_SC);
        else
-               printk("none\n");
+               printk(KERN_DEBUG "none\n");
 
-       printk("disconnected_SC:\n");
-       for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+       printk(KERN_DEBUG "disconnected_SC:\n");
+       for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
                show_command(ptr);
 
        disp_ports(shpnt);
        disp_enintr(shpnt);
-       restore_flags(flags);
-}
-
-int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
-{
-       return (-ENOSYS);       /* Currently this is a no-op */
 }
 
 #undef SPRINTF
@@ -3082,49 +3326,26 @@ static int get_command(char *pos, Scsi_Cmnd * ptr)
        for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
                SPRINTF("0x%02x ", ptr->cmnd[i]);
 
-       SPRINTF("); residual=%d; buffers=%d; phase |",
-               ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+       SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |",
+               ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual);
 
        if (ptr->SCp.phase & not_issued)
                SPRINTF("not issued|");
-       if (ptr->SCp.phase & in_selection)
-               SPRINTF("in selection|");
+       if (ptr->SCp.phase & selecting)
+               SPRINTF("selecting|");
        if (ptr->SCp.phase & disconnected)
                SPRINTF("disconnected|");
        if (ptr->SCp.phase & aborted)
                SPRINTF("aborted|");
-       if (ptr->SCp.phase & sent_ident)
-               SPRINTF("send_ident|");
-       if (ptr->SCp.phase & in_other) {
-               SPRINTF("; in other(");
-               switch ((ptr->SCp.phase >> 16) & P_MASK) {
-               case P_DATAO:
-                       SPRINTF("DATA OUT");
-                       break;
-               case P_DATAI:
-                       SPRINTF("DATA IN");
-                       break;
-               case P_CMD:
-                       SPRINTF("COMMAND");
-                       break;
-               case P_STATUS:
-                       SPRINTF("STATUS");
-                       break;
-               case P_MSGO:
-                       SPRINTF("MESSAGE OUT");
-                       break;
-               case P_MSGI:
-                       SPRINTF("MESSAGE IN");
-                       break;
-               default:
-                       SPRINTF("*illegal*");
-                       break;
-               }
-               SPRINTF(")");
-               if (ptr->SCp.phase & (1 << 16))
-                       SPRINTF("; phaseend");
-       }
-       SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+       if (ptr->SCp.phase & identified)
+               SPRINTF("identified|");
+       if (ptr->SCp.phase & completed)
+               SPRINTF("completed|");
+       if (ptr->SCp.phase & spiordy)
+               SPRINTF("spiordy|");
+       if (ptr->SCp.phase & syncneg)
+               SPRINTF("syncneg|");
+       SPRINTF("; next=0x%p\n", SCNEXT(ptr));
 
        return (pos - start);
 }
@@ -3134,15 +3355,10 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
        char *start = pos;
        int s;
 
-#ifdef SKIP_PORTS
-       if (HOSTDATA(shpnt)->debug & debug_skipports)
-               return;
-#endif
-
-       SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+       SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
 
        s = GETPORT(SCSISEQ);
-       SPRINTF("SCSISEQ (");
+       SPRINTF("SCSISEQ");
        if (s & TEMODEO)
                SPRINTF("TARGET MODE ");
        if (s & ENSELO)
@@ -3161,7 +3377,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
                SPRINTF("SCSIRSTO ");
        SPRINTF(");");
 
-       SPRINTF(" SCSISIG (");
+       SPRINTF(" SCSISIG(");
        s = GETPORT(SCSISIG);
        switch (s & P_MASK) {
        case P_DATAO:
@@ -3191,7 +3407,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
 
        SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
 
-       SPRINTF("SSTAT (");
+       SPRINTF("SSTAT");
        s = GETPORT(SSTAT0);
        if (s & TARGET)
                SPRINTF("TARGET ");
@@ -3230,7 +3446,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
        SPRINTF("); ");
 
 
-       SPRINTF("SSTAT (");
+       SPRINTF("SSTAT");
 
        s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
 
@@ -3271,7 +3487,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
                SPRINTF("REQINIT ");
        SPRINTF("); ");
 
-       SPRINTF("SXFRCTL0 (");
+       SPRINTF("SXFRCTL0");
 
        s = GETPORT(SXFRCTL0);
        if (s & SCSIEN)
@@ -3288,24 +3504,26 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
                SPRINTF("CLRCH1 ");
        SPRINTF("); ");
 
-       SPRINTF("SIGNAL (");
+       SPRINTF("SIGNAL");
 
        s = GETPORT(SCSISIG);
-       if (s & ATNI)
+       if (s & SIG_ATNI)
                SPRINTF("ATNI ");
-       if (s & SELI)
+       if (s & SIG_SELI)
                SPRINTF("SELI ");
-       if (s & BSYI)
+       if (s & SIG_BSYI)
                SPRINTF("BSYI ");
-       if (s & REQI)
+       if (s & SIG_REQI)
                SPRINTF("REQI ");
-       if (s & ACKI)
+       if (s & SIG_ACKI)
                SPRINTF("ACKI ");
        SPRINTF("); ");
 
-       SPRINTF("SELID (%02x), ", GETPORT(SELID));
+       SPRINTF("SELID(%02x), ", GETPORT(SELID));
+
+       SPRINTF("STCNT(%d), ", GETSTCNT());
 
-       SPRINTF("SSTAT2 (");
+       SPRINTF("SSTAT2");
 
        s = GETPORT(SSTAT2);
        if (s & SOFFSET)
@@ -3319,7 +3537,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
        s = GETPORT(SSTAT3);
        SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
 
-       SPRINTF("SSTAT4 (");
+       SPRINTF("SSTAT4");
        s = GETPORT(SSTAT4);
        if (s & SYNCERR)
                SPRINTF("SYNCERR ");
@@ -3329,7 +3547,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
                SPRINTF("FRERR ");
        SPRINTF("); ");
 
-       SPRINTF("DMACNTRL0 (");
+       SPRINTF("DMACNTRL0");
        s = GETPORT(DMACNTRL0);
        SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT");
        SPRINTF("%s ", s & DMA ? "DMA" : "PIO");
@@ -3344,7 +3562,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
                SPRINTF("SWINT ");
        SPRINTF("); ");
 
-       SPRINTF("DMASTAT (");
+       SPRINTF("DMASTAT");
        s = GETPORT(DMASTAT);
        if (s & ATDONE)
                SPRINTF("ATDONE ");
@@ -3354,9 +3572,9 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
                SPRINTF("DFIFOFULL ");
        if (s & DFIFOEMP)
                SPRINTF("DFIFOEMP ");
-       SPRINTF(")\n\n");
+       SPRINTF(")\n");
 
-       SPRINTF("enabled interrupts (");
+       SPRINTF("enabled interrupts");
 
        s = GETPORT(SIMODE0);
        if (s & ENSELDO)
@@ -3394,8 +3612,52 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
        return (pos - start);
 }
 
+int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+       if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
+               return -EINVAL;
+
+#if defined(AHA152X_DEBUG)
+       if(length>14 && strncmp("debug ", buffer+8, 6)==0) {
+               int debug = HOSTDATA(shpnt)->debug;
+
+               HOSTDATA(shpnt)->debug = simple_strtoul(buffer+14, NULL, 0);
+
+               printk(KERN_INFO "aha152x%d: debugging options set to 0x%04x (were 0x%04x)\n", HOSTNO, HOSTDATA(shpnt)->debug, debug);
+       } else
+#endif
+#if defined(AHA152X_STAT)
+       if(length>13 && strncmp("reset", buffer+8, 5)==0) {
+               int i;
+
+               HOSTDATA(shpnt)->total_commands=0;
+               HOSTDATA(shpnt)->disconnections=0;
+               HOSTDATA(shpnt)->busfree_without_any_action=0;
+               HOSTDATA(shpnt)->busfree_without_old_command=0;
+               HOSTDATA(shpnt)->busfree_without_new_command=0;
+               HOSTDATA(shpnt)->busfree_without_done_command=0;
+               HOSTDATA(shpnt)->busfree_with_check_condition=0;
+               for (i = idle; i<maxstate; i++) {
+                       HOSTDATA(shpnt)->count[i]=0;
+                       HOSTDATA(shpnt)->count_trans[i]=0;
+                       HOSTDATA(shpnt)->time[i]=0;
+               }
+
+               printk(KERN_INFO "aha152x%d: stats reseted.\n", HOSTNO);
+
+       } else
+#endif
+       {
+               return -EINVAL;
+       }
+
+
+       return length;
+}
+
 #undef SPRINTF
-#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+#define SPRINTF(args...) \
+       do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
 
 int aha152x_proc_info(char *buffer, char **start,
                      off_t offset, int length, int hostno, int inout)
@@ -3403,48 +3665,39 @@ int aha152x_proc_info(char *buffer, char **start,
        int i;
        char *pos = buffer;
        struct Scsi_Host *shpnt;
-       unsigned long flags;
        Scsi_Cmnd *ptr;
+       unsigned long flags;
+       int thislength;
 
        for (i = 0, shpnt = (struct Scsi_Host *) NULL; i < IRQS; i++)
                if (aha152x_host[i] && aha152x_host[i]->host_no == hostno)
                        shpnt = aha152x_host[i];
 
        if (!shpnt)
-               return (-ESRCH);
+               return -ESRCH;
 
-       if (inout)              /* Has data been written to the file ? */
-               return (aha152x_set_info(buffer, length, shpnt));
+       DPRINTK(debug_procinfo, 
+              KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n",
+              buffer, offset, length, hostno, inout);
 
-       SPRINTF(AHA152X_REVID "\n");
 
-       save_flags(flags);
-       cli();
+       if (inout)
+               return aha152x_set_info(buffer, length, shpnt);
+
+       SPRINTF(AHA152X_REVID "\n");
 
        SPRINTF("ioports 0x%04lx to 0x%04lx\n",
                shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
        SPRINTF("interrupt 0x%02x\n", shpnt->irq);
        SPRINTF("disconnection/reconnection %s\n",
-               HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled");
+               RECONNECT ? "enabled" : "disabled");
        SPRINTF("parity checking %s\n",
-               HOSTDATA(shpnt)->parity ? "enabled" : "disabled");
+               PARITY ? "enabled" : "disabled");
        SPRINTF("synchronous transfers %s\n",
-               HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled");
+               SYNCHRONOUS ? "enabled" : "disabled");
        SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands);
 
-       if (HOSTDATA(shpnt)->synchronous) {
-#if 0
-               SPRINTF("synchronously operating targets (tick=%ld ns):\n",
-                       250000000 / loops_per_sec);
-               for (i = 0; i < 8; i++)
-                       if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
-                               SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n",
-                                       i,
-                                       (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
-                                       (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) *
-                                       250000000 / loops_per_sec,
-                                   HOSTDATA(shpnt)->syncrate[i] & 0x0f);
-#else
+       if(SYNCHRONOUS) {
                SPRINTF("synchronously operating targets (tick=50 ns):\n");
                for (i = 0; i < 8; i++)
                        if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
@@ -3453,14 +3706,14 @@ int aha152x_proc_info(char *buffer, char **start,
                                        (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
                                        (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
                                    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
-#endif
        }
-#ifdef DEBUG_AHA152X
-#define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
+#if defined(AHA152X_DEBUG)
+#define PDEBUG(flags,txt) \
+       if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
 
        SPRINTF("enabled debugging options: ");
 
-       PDEBUG(debug_skipports, "skip ports");
+       PDEBUG(debug_procinfo, "procinfo");
        PDEBUG(debug_queue, "queue");
        PDEBUG(debug_intr, "interrupt");
        PDEBUG(debug_selection, "selection");
@@ -3470,23 +3723,22 @@ int aha152x_proc_info(char *buffer, char **start,
        PDEBUG(debug_cmd, "command");
        PDEBUG(debug_datai, "data in");
        PDEBUG(debug_datao, "data out");
-       PDEBUG(debug_abort, "abort");
-       PDEBUG(debug_done, "done");
-       PDEBUG(debug_biosparam, "bios parameters");
+       PDEBUG(debug_eh, "eh");
+       PDEBUG(debug_locks, "locks");
        PDEBUG(debug_phases, "phases");
-       PDEBUG(debug_queues, "queues");
-       PDEBUG(debug_reset, "reset");
 
        SPRINTF("\n");
 #endif
 
        SPRINTF("\nqueue status:\n");
+       DO_LOCK(flags);
        if (ISSUE_SC) {
                SPRINTF("not yet issued commands:\n");
-               for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+               for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
                        pos += get_command(pos, ptr);
        } else
                SPRINTF("no not yet issued commands\n");
+       DO_UNLOCK(flags);
 
        if (CURRENT_SC) {
                SPRINTF("current command:\n");
@@ -3496,25 +3748,62 @@ int aha152x_proc_info(char *buffer, char **start,
 
        if (DISCONNECTED_SC) {
                SPRINTF("disconnected commands:\n");
-               for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+               for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
                        pos += get_command(pos, ptr);
        } else
                SPRINTF("no disconnected commands\n");
 
-       restore_flags(flags);
-
        pos += get_ports(shpnt, pos);
 
-       *start = buffer + offset;
-       if (pos - buffer < offset)
+#if defined(AHA152X_STAT)
+       SPRINTF("statistics:\n"
+               "total commands:               %d\n"
+               "disconnections:               %d\n"
+               "busfree with check condition: %d\n"
+               "busfree without old command:  %d\n"
+               "busfree without new command:  %d\n"
+               "busfree without done command: %d\n"
+               "busfree without any action:   %d\n"
+               "state      "
+               "transitions  "
+               "count        "
+               "time\n",
+               HOSTDATA(shpnt)->total_commands,
+               HOSTDATA(shpnt)->disconnections,
+               HOSTDATA(shpnt)->busfree_with_check_condition,
+               HOSTDATA(shpnt)->busfree_without_old_command,
+               HOSTDATA(shpnt)->busfree_without_new_command,
+               HOSTDATA(shpnt)->busfree_without_done_command,
+               HOSTDATA(shpnt)->busfree_without_any_action);
+       for(i=0; i<maxstate; i++) {
+               SPRINTF("%-10s %-12d %-12d %-12ld\n",
+                       states[i].name,
+                       HOSTDATA(shpnt)->count_trans[i],
+                       HOSTDATA(shpnt)->count[i],
+                       HOSTDATA(shpnt)->time[i]);
+       }
+#endif
+
+       DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: pos=%p\n", pos);
+
+       thislength = pos - (buffer + offset);
+       DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: length=%d thislength=%d\n", length, thislength);
+
+       if(thislength<0) {
+               DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: output too short\n");
+               *start = 0;
                return 0;
-       else if (pos - buffer - offset < length)
-               return pos - buffer - offset;
-       else
-               return length;
+       }
+
+       thislength = thislength<length ? thislength : length;
+
+       DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: return %d\n", thislength);
+
+       *start = buffer + offset;
+       return thislength < length ? thislength : length;
 }
 
-#ifdef MODULE
+#if defined(MODULE)
 /* Eventually this will go into an include file, but this will be later */
 Scsi_Host_Template driver_template = AHA152X;
 
index 8bac1ddf9cc2d7108b15cdf6c2b8f28d32f4f182..910f1668bf63d5c3bce249c6e01cd7e931245cfe 100644 (file)
@@ -2,7 +2,7 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 1.7 1997/01/19 23:07:11 davem Exp $
+ * $Id: aha152x.h,v 2.0 1999/12/25 15:08:35 fischer Exp fischer $
  */
 
 #if defined(__KERNEL__)
 #include <linux/blk.h>
 #include "scsi.h"
 #include <asm/io.h>
+#include <linux/version.h>
 
 int aha152x_detect(Scsi_Host_Template *);
 int aha152x_command(Scsi_Cmnd *);
 int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int aha152x_abort(Scsi_Cmnd *);
 int aha152x_release(struct Scsi_Host *shpnt);
-int aha152x_reset(Scsi_Cmnd *, unsigned int);
+int aha152x_device_reset(Scsi_Cmnd *);
+int aha152x_bus_reset(Scsi_Cmnd *);
+int aha152x_host_reset(Scsi_Cmnd *);
 int aha152x_biosparam(Disk *, kdev_t, int*);
 int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
 
@@ -24,69 +27,79 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE 7
 
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.7 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.0 $"
 
 /* Initial value of Scsi_Host entry */
-#define AHA152X { proc_name:          "a152x",           \
-                  proc_info:          aha152x_proc_info,  \
-                  name:               AHA152X_REVID,     \
-                  detect:             aha152x_detect,    \
-                  command:           aha152x_command,    \
-                  queuecommand:       aha152x_queue,     \
-                  abort:              aha152x_abort,     \
-                  reset:              aha152x_reset,     \
-                  release:            aha152x_release,   \
-                  slave_attach:       0,                 \
-                  bios_param:         aha152x_biosparam,  \
-                  can_queue:          1,                 \
-                  this_id:            7,                 \
-                  sg_tablesize:       SG_ALL,            \
-                  cmd_per_lun:        1,                 \
-                  present:            0,                 \
-                  unchecked_isa_dma:  0,                 \
-                  use_clustering:     DISABLE_CLUSTERING }
+#define AHA152X { proc_name:                   "aha152x",              \
+                  proc_info:                   aha152x_proc_info,      \
+                  name:                                AHA152X_REVID,          \
+                  detect:                      aha152x_detect,         \
+                  command:                     aha152x_command,        \
+                  queuecommand:                        aha152x_queue,          \
+                 eh_abort_handler:             aha152x_abort,          \
+                 eh_device_reset_handler:      aha152x_device_reset,   \
+                 eh_bus_reset_handler:         aha152x_bus_reset,      \
+                 eh_host_reset_handler:        aha152x_host_reset,     \
+                  release:                     aha152x_release,        \
+                  slave_attach:                        0,                      \
+                  bios_param:                  aha152x_biosparam,      \
+                  can_queue:                   1,                      \
+                  this_id:                     7,                      \
+                  sg_tablesize:                        SG_ALL,                 \
+                  cmd_per_lun:                 1,                      \
+                  present:                     0,                      \
+                  unchecked_isa_dma:           0,                      \
+                  use_clustering:              DISABLE_CLUSTERING,     \
+                 use_new_eh_code:              1 }
 #endif
 
 
 /* port addresses */
-#define SCSISEQ      (shpnt->io_port+0x00)    /* SCSI sequence control */
-#define SXFRCTL0     (shpnt->io_port+0x01)    /* SCSI transfer control 0 */
-#define SXFRCTL1     (shpnt->io_port+0x02)    /* SCSI transfer control 1 */
-#define SCSISIG      (shpnt->io_port+0x03)    /* SCSI signal in/out */
-#define SCSIRATE     (shpnt->io_port+0x04)    /* SCSI rate control */
-#define SELID        (shpnt->io_port+0x05)    /* selection/reselection ID */
-#define SCSIID       SELID                    /* SCSI ID */
-#define SCSIDAT      (shpnt->io_port+0x06)    /* SCSI latched data */
-#define SCSIBUS      (shpnt->io_port+0x07)    /* SCSI data bus */
-#define STCNT0       (shpnt->io_port+0x08)    /* SCSI transfer count 0 */
-#define STCNT1       (shpnt->io_port+0x09)    /* SCSI transfer count 1 */
-#define STCNT2       (shpnt->io_port+0x0a)    /* SCSI transfer count 2 */
-#define SSTAT0       (shpnt->io_port+0x0b)    /* SCSI interrupt status 0 */
-#define SSTAT1       (shpnt->io_port+0x0c)    /* SCSI interrupt status 1 */
-#define SSTAT2       (shpnt->io_port+0x0d)    /* SCSI interrupt status 2 */
-#define SCSITEST     (shpnt->io_port+0x0e)    /* SCSI test control */
-#define SSTAT3       SCSITEST                 /* SCSI interrupt status 3 */
-#define SSTAT4       (shpnt->io_port+0x0f)    /* SCSI status 4 */
-#define SIMODE0      (shpnt->io_port+0x10)    /* SCSI interrupt mode 0 */
-#define SIMODE1      (shpnt->io_port+0x11)    /* SCSI interrupt mode 1 */
-#define DMACNTRL0    (shpnt->io_port+0x12)    /* DMA control 0 */
-#define DMACNTRL1    (shpnt->io_port+0x13)    /* DMA control 1 */
-#define DMASTAT      (shpnt->io_port+0x14)    /* DMA status */
-#define FIFOSTAT     (shpnt->io_port+0x15)    /* FIFO status */
-#define DATAPORT     (shpnt->io_port+0x16)    /* DATA port */
-#define BRSTCNTRL    (shpnt->io_port+0x18)    /* burst control */
-#define PORTA        (shpnt->io_port+0x1a)    /* PORT A */
-#define PORTB        (shpnt->io_port+0x1b)    /* PORT B */
-#define REV          (shpnt->io_port+0x1c)    /* revision */
-#define STACK        (shpnt->io_port+0x1d)    /* stack */
-#define TEST         (shpnt->io_port+0x1e)    /* test register */
+#define SCSISEQ      (HOSTIOPORT0+0x00)    /* SCSI sequence control */
+#define SXFRCTL0     (HOSTIOPORT0+0x01)    /* SCSI transfer control 0 */
+#define SXFRCTL1     (HOSTIOPORT0+0x02)    /* SCSI transfer control 1 */
+#define SCSISIG      (HOSTIOPORT0+0x03)    /* SCSI signal in/out */
+#define SCSIRATE     (HOSTIOPORT0+0x04)    /* SCSI rate control */
+#define SELID        (HOSTIOPORT0+0x05)    /* selection/reselection ID */
+#define SCSIID       SELID                 /* SCSI ID */
+#define SCSIDAT      (HOSTIOPORT0+0x06)    /* SCSI latched data */
+#define SCSIBUS      (HOSTIOPORT0+0x07)    /* SCSI data bus */
+#define STCNT0       (HOSTIOPORT0+0x08)    /* SCSI transfer count 0 */
+#define STCNT1       (HOSTIOPORT0+0x09)    /* SCSI transfer count 1 */
+#define STCNT2       (HOSTIOPORT0+0x0a)    /* SCSI transfer count 2 */
+#define SSTAT0       (HOSTIOPORT0+0x0b)    /* SCSI interrupt status 0 */
+#define SSTAT1       (HOSTIOPORT0+0x0c)    /* SCSI interrupt status 1 */
+#define SSTAT2       (HOSTIOPORT0+0x0d)    /* SCSI interrupt status 2 */
+#define SCSITEST     (HOSTIOPORT0+0x0e)    /* SCSI test control */
+#define SSTAT3       SCSITEST              /* SCSI interrupt status 3 */
+#define SSTAT4       (HOSTIOPORT0+0x0f)    /* SCSI status 4 */
+#define SIMODE0      (HOSTIOPORT1+0x10)    /* SCSI interrupt mode 0 */
+#define SIMODE1      (HOSTIOPORT1+0x11)    /* SCSI interrupt mode 1 */
+#define DMACNTRL0    (HOSTIOPORT1+0x12)    /* DMA control 0 */
+#define DMACNTRL1    (HOSTIOPORT1+0x13)    /* DMA control 1 */
+#define DMASTAT      (HOSTIOPORT1+0x14)    /* DMA status */
+#define FIFOSTAT     (HOSTIOPORT1+0x15)    /* FIFO status */
+#define DATAPORT     (HOSTIOPORT1+0x16)    /* DATA port */
+#define BRSTCNTRL    (HOSTIOPORT1+0x18)    /* burst control */
+#define PORTA        (HOSTIOPORT1+0x1a)    /* PORT A */
+#define PORTB        (HOSTIOPORT1+0x1b)    /* PORT B */
+#define REV          (HOSTIOPORT1+0x1c)    /* revision */
+#define STACK        (HOSTIOPORT1+0x1d)    /* stack */
+#define TEST         (HOSTIOPORT1+0x1e)    /* test register */
+
+#define IO_RANGE        0x20
 
 /* used in aha152x_porttest */
-#define O_PORTA      0x1a                    /* PORT A */
-#define O_PORTB      0x1b                    /* PORT B */
-#define O_DMACNTRL1  0x13                    /* DMA control 1 */
-#define O_STACK      0x1d                    /* stack */
-#define IO_RANGE     0x20
+#define O_PORTA         0x1a               /* PORT A */
+#define O_PORTB         0x1b               /* PORT B */
+#define O_DMACNTRL1     0x13               /* DMA control 1 */
+#define O_STACK         0x1d               /* stack */
+
+/* used in tc1550_porttest */
+#define O_TC_PORTA      0x0a               /* PORT A */
+#define O_TC_PORTB      0x0b               /* PORT B */
+#define O_TC_DMACNTRL1  0x03               /* DMA control 1 */
+#define O_TC_STACK      0x0d               /* stack */
 
 /* bits and bitmasks to ports */
 
@@ -118,33 +131,33 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int
 #define BYTEALIGN    0x02
 
 /* SCSI signal IN */
-#define CDI          0x80
-#define IOI          0x40
-#define MSGI         0x20
-#define ATNI         0x10
-#define SELI         0x08
-#define BSYI         0x04
-#define REQI         0x02
-#define ACKI         0x01
+#define SIG_CDI          0x80
+#define SIG_IOI          0x40
+#define SIG_MSGI         0x20
+#define SIG_ATNI         0x10
+#define SIG_SELI         0x08
+#define SIG_BSYI         0x04
+#define SIG_REQI         0x02
+#define SIG_ACKI         0x01
 
 /* SCSI Phases */
-#define P_MASK       (MSGI|CDI|IOI)
+#define P_MASK       (SIG_MSGI|SIG_CDI|SIG_IOI)
 #define P_DATAO      (0)
-#define P_DATAI      (IOI)
-#define P_CMD        (CDI)
-#define P_STATUS     (CDI|IOI)
-#define P_MSGO       (MSGI|CDI)
-#define P_MSGI       (MSGI|CDI|IOI)
+#define P_DATAI      (SIG_IOI)
+#define P_CMD        (SIG_CDI)
+#define P_STATUS     (SIG_CDI|SIG_IOI)
+#define P_MSGO       (SIG_MSGI|SIG_CDI)
+#define P_MSGI       (SIG_MSGI|SIG_CDI|SIG_IOI)
 
 /* SCSI signal OUT */
-#define CDO          0x80
-#define IOO          0x40
-#define MSGO         0x20
-#define ATNO         0x10
-#define SELO         0x08
-#define BSYO         0x04
-#define REQO         0x02
-#define ACKO         0x01
+#define SIG_CDO          0x80
+#define SIG_IOO          0x40
+#define SIG_MSGO         0x20
+#define SIG_ATNO         0x10
+#define SIG_SELO         0x08
+#define SIG_BSYO         0x04
+#define SIG_REQO         0x02
+#define SIG_ACKO         0x01
 
 /* SCSI rate control */
 #define SXFR         0x70    /* mask */
@@ -315,38 +328,31 @@ typedef union {
 
 /* Some macros to manipulate ports and their bits */
 
-#define SETPORT(PORT, VAL)         outb( (VAL), (PORT) )
-#define SETPORTP(PORT, VAL)        outb_p( (VAL), (PORT) )
-#define SETPORTW(PORT, VAL)        outw( (VAL), (PORT) )
-
-#define GETPORT(PORT)              inb( PORT )
-#define GETPORTW(PORT)             inw( PORT )
-
-#define SETBITS(PORT, BITS)        outb( (inb(PORT) | (BITS)), (PORT) )
-#define CLRBITS(PORT, BITS)        outb( (inb(PORT) & ~(BITS)), (PORT) )
-#define CLRSETBITS(PORT, CLR, SET) outb( (inb(PORT) & ~(CLR)) | (SET) , (PORT) )
+#define SETPORT(PORT, VAL)     outb( (VAL), (PORT) )
+#define GETPORT(PORT)          inb( PORT )
+#define SETBITS(PORT, BITS)    outb( (inb(PORT) | (BITS)), (PORT) )
+#define CLRBITS(PORT, BITS)    outb( (inb(PORT) & ~(BITS)), (PORT) )
+#define TESTHI(PORT, BITS)     ((inb(PORT) & (BITS)) == (BITS))
+#define TESTLO(PORT, BITS)     ((inb(PORT) & (BITS)) == 0)
 
-#define TESTHI(PORT, BITS)         ((inb(PORT) & (BITS)) == BITS)
-#define TESTLO(PORT, BITS)         ((inb(PORT) & (BITS)) == 0)
+#define SETRATE(RATE)          SETPORT(SCSIRATE,(RATE) & 0x7f)
 
-#ifdef DEBUG_AHA152X
+#if defined(AHA152X_DEBUG)
 enum {
-  debug_skipports = 0x0001,
+  debug_procinfo  = 0x0001,
   debug_queue     = 0x0002,
-  debug_intr      = 0x0004,
-  debug_selection = 0x0008,
-  debug_msgo      = 0x0010,
-  debug_msgi      = 0x0020,
-  debug_status    = 0x0040,
-  debug_cmd       = 0x0080,
-  debug_datai     = 0x0100,
-  debug_datao     = 0x0200,
-  debug_abort     = 0x0400,
-  debug_done      = 0x0800,
-  debug_biosparam = 0x1000,
+  debug_locks     = 0x0004,
+  debug_intr      = 0x0008,
+  debug_selection = 0x0010,
+  debug_msgo      = 0x0020,
+  debug_msgi      = 0x0040,
+  debug_status    = 0x0080,
+  debug_cmd       = 0x0100,
+  debug_datai     = 0x0200,
+  debug_datao     = 0x0400,
+  debug_eh       = 0x0800,
+  debug_done      = 0x1000,
   debug_phases    = 0x2000,
-  debug_queues    = 0x4000,
-  debug_reset     = 0x8000,
 };
 #endif
 
index 8131fdfc9a1711585999e2b090f69f8283231aa3..e2f4397b2b874da26d291c4ae1dea6f59242b457 100644 (file)
@@ -9,7 +9,7 @@
  *        Set up on-board DMA controller, such that we do not have to
  *        have the bios enabled to use the aha1542.
  *  Modified by David Gentzel
- *       Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus
+ *        Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus
  *        controller).
  *  Modified by Matti Aarnio
  *        Accept parameters from LILO cmd-line. -- 1-Oct-94
@@ -18,7 +18,7 @@
  *        1-Jan-97
  *  Modified by Bjorn L. Thordarson and Einar Thor Einarsson
  *        Recognize that DMA0 is valid DMA channel -- 13-Jul-98
- *  Modified by Chris Faulhaber        <jedgar@fxp.org>
+ *  Modified by Chris Faulhaber <jedgar@fxp.org>
  *        Added module command-line options
  *        19-Jul-99
  */
@@ -34,6 +34,8 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/isapnp.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
 #define SCSI_PA(address) virt_to_bus(address)
 
-static void BAD_DMA(void * address, unsigned int length)
+static void BAD_DMA(void *address, unsigned int length)
 {
-  printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n", 
-        address, 
-        SCSI_PA(address),
-        length);
-  panic("Buffer at physical address > 16Mb used for aha1542");
+       printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
+              address,
+              SCSI_PA(address),
+              length);
+       panic("Buffer at physical address > 16Mb used for aha1542");
 }
 
-static void BAD_SG_DMA(Scsi_Cmnd * SCpnt, 
-                      struct scatterlist * sgpnt, 
-                      int nseg, 
+static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
+                      struct scatterlist *sgpnt,
+                      int nseg,
                       int badseg)
 {
-  printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx alt %p/0x%lx length %d\n", 
-        badseg, nseg,
-        sgpnt[badseg].address, 
-        SCSI_PA(sgpnt[badseg].address),
-        sgpnt[badseg].alt_address, 
-        sgpnt[badseg].alt_address ? SCSI_PA(sgpnt[badseg].alt_address) : 0,
-        sgpnt[badseg].length);
-
-  /*
-   * Not safe to continue.
-   */
-  panic("Buffer at physical address > 16Mb used for aha1542");
+       printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx alt %p/0x%lx length %d\n",
+              badseg, nseg,
+              sgpnt[badseg].address,
+              SCSI_PA(sgpnt[badseg].address),
+              sgpnt[badseg].alt_address,
+              sgpnt[badseg].alt_address ? SCSI_PA(sgpnt[badseg].alt_address) : 0,
+              sgpnt[badseg].length);
+
+       /*
+        * Not safe to continue.
+        */
+       panic("Buffer at physical address > 16Mb used for aha1542");
 }
 
 #include<linux/stat.h>
@@ -81,75 +83,83 @@ static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
 #else
 #define DEB(x)
 #endif
+
 /*
-static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
-*/
+   static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
+ */
 
 /* The adaptec can be configured for quite a number of addresses, but
-I generally do not want the card poking around at random.  We allow
-two addresses - this allows people to use the Adaptec with a Midi
-card, which also used 0x330 -- can be overridden with LILO! */
+   I generally do not want the card poking around at random.  We allow
+   two addresses - this allows people to use the Adaptec with a Midi
+   card, which also used 0x330 -- can be overridden with LILO! */
 
-#define MAXBOARDS 2    /* Increase this and the sizes of the
-                          arrays below, if you need more.. */
+#define MAXBOARDS 4            /* Increase this and the sizes of the
+                                  arrays below, if you need more.. */
 
-static unsigned int bases[MAXBOARDS]={0x330, 0x334};
+/* Boards 3,4 slots are reserved for ISAPnP scans */
+
+static unsigned int bases[MAXBOARDS] = {0x330, 0x334, 0, 0};
 
 /* set by aha1542_setup according to the command line */
-static int setup_called[MAXBOARDS]   = {0,0};
-static int setup_buson[MAXBOARDS]    = {0,0};
-static int setup_busoff[MAXBOARDS]   = {0,0};
-static int setup_dmaspeed[MAXBOARDS] = {-1,-1};
 
-static char *setup_str[MAXBOARDS] = {(char *)NULL,(char *)NULL};
+static int setup_called[MAXBOARDS];
+static int setup_buson[MAXBOARDS];
+static int setup_busoff[MAXBOARDS];
+static int setup_dmaspeed[MAXBOARDS] = { -1, -1, -1, -1 };
+
+static char *setup_str[MAXBOARDS];
 
 /*
  * LILO/Module params:  aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]
  *
  * Where:  <PORTBASE> is any of the valid AHA addresses:
- *                     0x130, 0x134, 0x230, 0x234, 0x330, 0x334
- *        <BUSON>  is the time (in microsecs) that AHA spends on the AT-bus
- *                 when transferring data.  1542A power-on default is 11us,
- *                 valid values are in range: 2..15 (decimal)
- *        <BUSOFF> is the time that AHA spends OFF THE BUS after while
- *                 it is transferring data (not to monopolize the bus).
- *                 Power-on default is 4us, valid range: 1..64 microseconds.
- *        <DMASPEED> Default is jumper selected (1542A: on the J1),
- *                 but experimenter can alter it with this.
- *                 Valid values: 5, 6, 7, 8, 10 (MB/s)
- *                 Factory default is 5 MB/s.
+ *                      0x130, 0x134, 0x230, 0x234, 0x330, 0x334
+ *         <BUSON>  is the time (in microsecs) that AHA spends on the AT-bus
+ *                  when transferring data.  1542A power-on default is 11us,
+ *                  valid values are in range: 2..15 (decimal)
+ *         <BUSOFF> is the time that AHA spends OFF THE BUS after while
+ *                  it is transferring data (not to monopolize the bus).
+ *                  Power-on default is 4us, valid range: 1..64 microseconds.
+ *         <DMASPEED> Default is jumper selected (1542A: on the J1),
+ *                  but experimenter can alter it with this.
+ *                  Valid values: 5, 6, 7, 8, 10 (MB/s)
+ *                  Factory default is 5 MB/s.
  */
 
 #if defined(MODULE)
-int aha1542[] = { 0x330, 11, 4, -1 };
+int isapnp=0;
+int aha1542[] = {0x330, 11, 4, -1};
 MODULE_PARM(aha1542, "1-4i");
+MODULE_PARM(isapnp, "i");
+#else
+int isapnp=1;
 #endif
 
-#define BIOS_TRANSLATION_1632 0  /* Used by some old 1542A boards */
-#define BIOS_TRANSLATION_6432 1 /* Default case these days */
-#define BIOS_TRANSLATION_25563 2 /* Big disk case */
+#define BIOS_TRANSLATION_1632 0        /* Used by some old 1542A boards */
+#define BIOS_TRANSLATION_6432 1        /* Default case these days */
+#define BIOS_TRANSLATION_25563 2       /* Big disk case */
 
-struct aha1542_hostdata{
+struct aha1542_hostdata {
        /* This will effectively start both of them at the first mailbox */
-       int bios_translation;   /* Mapping bios uses - for compatibility */
+       int bios_translation;   /* Mapping bios uses - for compatibility */
        int aha1542_last_mbi_used;
        int aha1542_last_mbo_used;
-       Scsi_Cmnd * SCint[AHA1542_MAILBOXES];
-       struct mailbox mb[2*AHA1542_MAILBOXES];
+       Scsi_Cmnd *SCint[AHA1542_MAILBOXES];
+       struct mailbox mb[2 * AHA1542_MAILBOXES];
        struct ccb ccb[AHA1542_MAILBOXES];
 };
 
 #define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata)
 
-static struct Scsi_Host * aha_host[7] = {NULL,};  /* One for each IRQ level (9-15) */
+static struct Scsi_Host *aha_host[7];  /* One for each IRQ level (9-15) */
 
 
 
 
 #define WAITnexttimeout 3000000
 
-static void setup_mailboxes(int base_io, struct Scsi_Host * shpnt);
-static int aha1542_restart(struct Scsi_Host * shost);
+static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
+static int aha1542_restart(struct Scsi_Host *shost);
 static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
 static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
 
@@ -182,543 +192,567 @@ static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
 
 static void aha1542_stat(void)
 {
-/*    int s = inb(STATUS), i = inb(INTRFLAGS);
-  printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
+/*     int s = inb(STATUS), i = inb(INTRFLAGS);
+       printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
 }
 
 /* This is a bit complicated, but we need to make sure that an interrupt
    routine does not send something out while we are in the middle of this.
    Fortunately, it is only at boot time that multi-byte messages
    are ever sent. */
-static int aha1542_out(unsigned int base, unchar *cmdp, int len)
+static int aha1542_out(unsigned int base, unchar * cmdp, int len)
 {
-  unsigned long flags = 0;
-  
-  save_flags(flags);
-  if(len == 1) {
-    while(1==1){
-       WAIT(STATUS(base), CDF, 0, CDF);
-       cli();
-       if(inb(STATUS(base)) & CDF) {restore_flags(flags); continue;}
-       outb(*cmdp, DATA(base));
-       restore_flags(flags);
+       unsigned long flags = 0;
+
+       save_flags(flags);
+       if (len == 1) {
+               while (1 == 1) {
+                       WAIT(STATUS(base), CDF, 0, CDF);
+                       cli();
+                       if (inb(STATUS(base)) & CDF) {
+                               restore_flags(flags);
+                               continue;
+                       }
+                       outb(*cmdp, DATA(base));
+                       restore_flags(flags);
+                       return 0;
+               }
+       } else {
+               cli();
+               while (len--) {
+                       WAIT(STATUS(base), CDF, 0, CDF);
+                       outb(*cmdp++, DATA(base));
+               }
+               restore_flags(flags);
+       }
        return 0;
-      }
-  } else {
-    cli();
-    while (len--)
-      {
-       WAIT(STATUS(base), CDF, 0, CDF);
-       outb(*cmdp++, DATA(base));
-      }
-    restore_flags(flags);
-  }
-    return 0;
-  fail:
-    restore_flags(flags);
-    printk("aha1542_out failed(%d): ", len+1); aha1542_stat();
-    return 1;
+fail:
+       restore_flags(flags);
+       printk(KERN_ERR "aha1542_out failed(%d): ", len + 1);
+       aha1542_stat();
+       return 1;
 }
 
 /* Only used at boot time, so we do not need to worry about latency as much
    here */
-static int aha1542_in(unsigned int base, unchar *cmdp, int len)
+
+static int aha1542_in(unsigned int base, unchar * cmdp, int len)
 {
-    unsigned long flags;
-
-    save_flags(flags);
-    cli();
-    while (len--)
-      {
-         WAIT(STATUS(base), DF, DF, 0);
-         *cmdp++ = inb(DATA(base));
-      }
-    restore_flags(flags);
-    return 0;
-  fail:
-    restore_flags(flags);
-    printk("aha1542_in failed(%d): ", len+1); aha1542_stat();
-    return 1;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       while (len--) {
+               WAIT(STATUS(base), DF, DF, 0);
+               *cmdp++ = inb(DATA(base));
+       }
+       restore_flags(flags);
+       return 0;
+fail:
+       restore_flags(flags);
+       printk(KERN_ERR "aha1542_in failed(%d): ", len + 1);
+       aha1542_stat();
+       return 1;
 }
 
 /* Similar to aha1542_in, except that we wait a very short period of time.
    We use this if we know the board is alive and awake, but we are not sure
    if the board will respond to the command we are about to send or not */
-static int aha1542_in1(unsigned int base, unchar *cmdp, int len)
+static int aha1542_in1(unsigned int base, unchar * cmdp, int len)
 {
-    unsigned long flags;
-    
-    save_flags(flags);
-    cli();
-    while (len--)
-      {
-         WAITd(STATUS(base), DF, DF, 0, 100);
-         *cmdp++ = inb(DATA(base));
-      }
-    restore_flags(flags);
-    return 0;
-  fail:
-    restore_flags(flags);
-    return 1;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       while (len--) {
+               WAITd(STATUS(base), DF, DF, 0, 100);
+               *cmdp++ = inb(DATA(base));
+       }
+       restore_flags(flags);
+       return 0;
+fail:
+       restore_flags(flags);
+       return 1;
 }
 
 static int makecode(unsigned hosterr, unsigned scsierr)
 {
-    switch (hosterr) {
-      case 0x0:
-      case 0xa: /* Linked command complete without error and linked normally */
-      case 0xb: /* Linked command complete without error, interrupt generated */
-       hosterr = 0;
-       break;
-
-      case 0x11: /* Selection time out-The initiator selection or target
-                   reselection was not complete within the SCSI Time out period */
-       hosterr = DID_TIME_OUT;
-       break;
-
-      case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
-                   than was allocated by the Data Length field or the sum of the
-                   Scatter / Gather Data Length fields. */
-
-      case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
-
-      case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
-                   invalid. This usually indicates a software failure. */
-
-      case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
-                   This usually indicates a software failure. */
-
-      case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
-                   of linked CCB's does not specify the same logical unit number as
-                   the first. */
-      case 0x18: /* Invalid Target Direction received from Host-The direction of a
-                   Target Mode CCB was invalid. */
-
-      case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
-                   received to service data transfer between the same target LUN
-                   and initiator SCSI ID in the same direction. */
-
-      case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
-                   length segment or invalid segment list boundaries was received.
-                   A CCB parameter was invalid. */
-       DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
-       hosterr = DID_ERROR; /* Couldn't find any better */
-       break;
-
-      case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
-                   phase sequence was requested by the target. The host adapter
-                   will generate a SCSI Reset Condition, notifying the host with
-                   a SCRD interrupt */
-       hosterr = DID_RESET;
-       break;
-      default:
-       printk("makecode: unknown hoststatus %x\n", hosterr);
-       break;
-    }
-    return scsierr|(hosterr << 16);
+       switch (hosterr) {
+       case 0x0:
+       case 0xa:               /* Linked command complete without error and linked normally */
+       case 0xb:               /* Linked command complete without error, interrupt generated */
+               hosterr = 0;
+               break;
+
+       case 0x11:              /* Selection time out-The initiator selection or target
+                                  reselection was not complete within the SCSI Time out period */
+               hosterr = DID_TIME_OUT;
+               break;
+
+       case 0x12:              /* Data overrun/underrun-The target attempted to transfer more data
+                                  than was allocated by the Data Length field or the sum of the
+                                  Scatter / Gather Data Length fields. */
+
+       case 0x13:              /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+
+       case 0x15:              /* MBO command was not 00, 01 or 02-The first byte of the CB was
+                                  invalid. This usually indicates a software failure. */
+
+       case 0x16:              /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
+                                  This usually indicates a software failure. */
+
+       case 0x17:              /* Linked CCB does not have the same LUN-A subsequent CCB of a set
+                                  of linked CCB's does not specify the same logical unit number as
+                                  the first. */
+       case 0x18:              /* Invalid Target Direction received from Host-The direction of a
+                                  Target Mode CCB was invalid. */
+
+       case 0x19:              /* Duplicate CCB Received in Target Mode-More than once CCB was
+                                  received to service data transfer between the same target LUN
+                                  and initiator SCSI ID in the same direction. */
+
+       case 0x1a:              /* Invalid CCB or Segment List Parameter-A segment list with a zero
+                                  length segment or invalid segment list boundaries was received.
+                                  A CCB parameter was invalid. */
+               DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
+               hosterr = DID_ERROR;    /* Couldn't find any better */
+               break;
+
+       case 0x14:              /* Target bus phase sequence failure-An invalid bus phase or bus
+                                  phase sequence was requested by the target. The host adapter
+                                  will generate a SCSI Reset Condition, notifying the host with
+                                  a SCRD interrupt */
+               hosterr = DID_RESET;
+               break;
+       default:
+               printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
+               break;
+       }
+       return scsierr | (hosterr << 16);
 }
 
-static int aha1542_test_port(int bse, struct Scsi_Host * shpnt)
+static int aha1542_test_port(int bse, struct Scsi_Host *shpnt)
 {
-    unchar inquiry_cmd[] = {CMD_INQUIRY };
-    unchar inquiry_result[4];
-    unchar *cmdp;
-    int len;
-    volatile int debug = 0;
-    
-    /* Quick and dirty test for presence of the card. */
-    if(inb(STATUS(bse)) == 0xff) return 0;
-
-    /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
-    
-    /*  DEB(printk("aha1542_test_port called \n")); */
-
-    /* In case some other card was probing here, reset interrupts */
-    aha1542_intr_reset(bse);     /* reset interrupts, so they don't block */   
-
-    outb(SRST|IRST/*|SCRST*/, CONTROL(bse));
-
-    mdelay(20);        /* Wait a little bit for things to settle down. */
-    
-    debug = 1;
-    /* Expect INIT and IDLE, any of the others are bad */
-    WAIT(STATUS(bse), STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
-    
-    debug = 2;
-    /* Shouldn't have generated any interrupts during reset */
-    if (inb(INTRFLAGS(bse))&INTRMASK) goto fail;
-
-
-    /* Perform a host adapter inquiry instead so we do not need to set
-       up the mailboxes ahead of time */
-
-    aha1542_out(bse, inquiry_cmd, 1);
-
-    debug = 3;
-    len = 4;
-    cmdp = &inquiry_result[0];
-
-    while (len--)
-      {
-         WAIT(STATUS(bse), DF, DF, 0);
-         *cmdp++ = inb(DATA(bse));
-      }
-    
-    debug = 8;
-    /* Reading port should reset DF */
-    if (inb(STATUS(bse)) & DF) goto fail;
-    
-    debug = 9;
-    /* When HACC, command is completed, and we're though testing */
-    WAIT(INTRFLAGS(bse), HACC, HACC, 0);
-    /* now initialize adapter */
-    
-    debug = 10;
-    /* Clear interrupts */
-    outb(IRST, CONTROL(bse));
-    
-    debug = 11;
-
-    return debug;                              /* 1 = ok */
-  fail:
-    return 0;                                  /* 0 = not ok */
+       unchar inquiry_cmd[] = {CMD_INQUIRY};
+       unchar inquiry_result[4];
+       unchar *cmdp;
+       int len;
+       volatile int debug = 0;
+
+       /* Quick and dirty test for presence of the card. */
+       if (inb(STATUS(bse)) == 0xff)
+               return 0;
+
+       /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
+
+       /*  DEB(printk("aha1542_test_port called \n")); */
+
+       /* In case some other card was probing here, reset interrupts */
+       aha1542_intr_reset(bse);        /* reset interrupts, so they don't block */
+
+       outb(SRST | IRST /*|SCRST */ , CONTROL(bse));
+
+       mdelay(20);             /* Wait a little bit for things to settle down. */
+
+       debug = 1;
+       /* Expect INIT and IDLE, any of the others are bad */
+       WAIT(STATUS(bse), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+       debug = 2;
+       /* Shouldn't have generated any interrupts during reset */
+       if (inb(INTRFLAGS(bse)) & INTRMASK)
+               goto fail;
+
+
+       /* Perform a host adapter inquiry instead so we do not need to set
+          up the mailboxes ahead of time */
+
+       aha1542_out(bse, inquiry_cmd, 1);
+
+       debug = 3;
+       len = 4;
+       cmdp = &inquiry_result[0];
+
+       while (len--) {
+               WAIT(STATUS(bse), DF, DF, 0);
+               *cmdp++ = inb(DATA(bse));
+       }
+
+       debug = 8;
+       /* Reading port should reset DF */
+       if (inb(STATUS(bse)) & DF)
+               goto fail;
+
+       debug = 9;
+       /* When HACC, command is completed, and we're though testing */
+       WAIT(INTRFLAGS(bse), HACC, HACC, 0);
+       /* now initialize adapter */
+
+       debug = 10;
+       /* Clear interrupts */
+       outb(IRST, CONTROL(bse));
+
+       debug = 11;
+
+       return debug;           /* 1 = ok */
+fail:
+       return 0;               /* 0 = not ok */
 }
 
 /* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
 static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
-    unsigned long flags;
+       unsigned long flags;
 
-    spin_lock_irqsave(&io_request_lock, flags);
-    aha1542_intr_handle(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+       spin_lock_irqsave(&io_request_lock, flags);
+       aha1542_intr_handle(irq, dev_id, regs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /* A "high" level interrupt handler */
 static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
-    void (*my_done)(Scsi_Cmnd *) = NULL;
-    int errstatus, mbi, mbo, mbistatus;
-    int number_serviced;
-    unsigned int flags;
-    struct Scsi_Host * shost;
-    Scsi_Cmnd * SCtmp;
-    int flag;
-    int needs_restart;
-    struct mailbox * mb;
-    struct ccb  *ccb;
-
-    shost = aha_host[irq - 9];
-    if(!shost) panic("Splunge!");
-
-    mb = HOSTDATA(shost)->mb;
-    ccb = HOSTDATA(shost)->ccb;
+       void (*my_done) (Scsi_Cmnd *) = NULL;
+       int errstatus, mbi, mbo, mbistatus;
+       int number_serviced;
+       unsigned int flags;
+       struct Scsi_Host *shost;
+       Scsi_Cmnd *SCtmp;
+       int flag;
+       int needs_restart;
+       struct mailbox *mb;
+       struct ccb *ccb;
+
+       shost = aha_host[irq - 9];
+       if (!shost)
+               panic("Splunge!");
+
+       mb = HOSTDATA(shost)->mb;
+       ccb = HOSTDATA(shost)->ccb;
 
 #ifdef DEBUG
-    {
-    flag = inb(INTRFLAGS(shost->io_port));
-    printk("aha1542_intr_handle: ");
-    if (!(flag&ANYINTR)) printk("no interrupt?");
-    if (flag&MBIF) printk("MBIF ");
-    if (flag&MBOA) printk("MBOF ");
-    if (flag&HACC) printk("HACC ");
-    if (flag&SCRD) printk("SCRD ");
-    printk("status %02x\n", inb(STATUS(shost->io_port)));
-  };
+       {
+               flag = inb(INTRFLAGS(shost->io_port));
+               printk(KERN_DEBUG "aha1542_intr_handle: ");
+               if (!(flag & ANYINTR))
+                       printk("no interrupt?");
+               if (flag & MBIF)
+                       printk("MBIF ");
+               if (flag & MBOA)
+                       printk("MBOF ");
+               if (flag & HACC)
+                       printk("HACC ");
+               if (flag & SCRD)
+                       printk("SCRD ");
+               printk("status %02x\n", inb(STATUS(shost->io_port)));
+       };
 #endif
-    number_serviced = 0;
-    needs_restart = 0;
-
-    while(1==1){
-      flag = inb(INTRFLAGS(shost->io_port));
-
-      /* Check for unusual interrupts.  If any of these happen, we should
-        probably do something special, but for now just printing a message
-        is sufficient.  A SCSI reset detected is something that we really
-        need to deal with in some way. */
-      if (flag & ~MBIF) {
-       if (flag&MBOA) printk("MBOF ");
-       if (flag&HACC) printk("HACC ");
-       if (flag&SCRD) {
-         needs_restart = 1;
-         printk("SCRD ");
-       }
-      }
-
-      aha1542_intr_reset(shost->io_port);
-
-      save_flags(flags);
-      cli();
-      mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1;
-      if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
-      
-      do{
-       if(mb[mbi].status != 0) break;
-       mbi++;
-       if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
-      } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used);
-      
-      if(mb[mbi].status == 0){
-       restore_flags(flags);
-       /* Hmm, no mail.  Must have read it the last time around */
-       if (!number_serviced && !needs_restart)
-         printk("aha1542.c: interrupt received, but no mail.\n");
-       /* We detected a reset.  Restart all pending commands for
-          devices that use the hard reset option */
-       if(needs_restart) aha1542_restart(shost);
-       return;
-      };
-
-      mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_PA(&ccb[0]))) / sizeof(struct ccb);
-      mbistatus = mb[mbi].status;
-      mb[mbi].status = 0;
-      HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
-      restore_flags(flags);
-      
+       number_serviced = 0;
+       needs_restart = 0;
+
+       while (1 == 1) {
+               flag = inb(INTRFLAGS(shost->io_port));
+
+               /* Check for unusual interrupts.  If any of these happen, we should
+                  probably do something special, but for now just printing a message
+                  is sufficient.  A SCSI reset detected is something that we really
+                  need to deal with in some way. */
+               if (flag & ~MBIF) {
+                       if (flag & MBOA)
+                               printk("MBOF ");
+                       if (flag & HACC)
+                               printk("HACC ");
+                       if (flag & SCRD) {
+                               needs_restart = 1;
+                               printk("SCRD ");
+                       }
+               }
+               aha1542_intr_reset(shost->io_port);
+
+               save_flags(flags);
+               cli();
+               mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1;
+               if (mbi >= 2 * AHA1542_MAILBOXES)
+                       mbi = AHA1542_MAILBOXES;
+
+               do {
+                       if (mb[mbi].status != 0)
+                               break;
+                       mbi++;
+                       if (mbi >= 2 * AHA1542_MAILBOXES)
+                               mbi = AHA1542_MAILBOXES;
+               } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used);
+
+               if (mb[mbi].status == 0) {
+                       restore_flags(flags);
+                       /* Hmm, no mail.  Must have read it the last time around */
+                       if (!number_serviced && !needs_restart)
+                               printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n");
+                       /* We detected a reset.  Restart all pending commands for
+                          devices that use the hard reset option */
+                       if (needs_restart)
+                               aha1542_restart(shost);
+                       return;
+               };
+
+               mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_PA(&ccb[0]))) / sizeof(struct ccb);
+               mbistatus = mb[mbi].status;
+               mb[mbi].status = 0;
+               HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
+               restore_flags(flags);
+
 #ifdef DEBUG
-      {
-       if (ccb[mbo].tarstat|ccb[mbo].hastat)
-         printk("aha1542_command: returning %x (status %d)\n", 
-                ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
-      };
+               {
+                       if (ccb[mbo].tarstat | ccb[mbo].hastat)
+                               printk(KERN_DEBUG "aha1542_command: returning %x (status %d)\n",
+                                      ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
+               };
 #endif
 
-      if(mbistatus == 3) continue; /* Aborted command not found */
+               if (mbistatus == 3)
+                       continue;       /* Aborted command not found */
 
 #ifdef DEBUG
-      printk("...done %d %d\n",mbo, mbi);
+               printk(KERN_DEBUG "...done %d %d\n", mbo, mbi);
 #endif
-      
-      SCtmp = HOSTDATA(shost)->SCint[mbo];
-
-      if (!SCtmp || !SCtmp->scsi_done) {
-       printk("aha1542_intr_handle: Unexpected interrupt\n");
-       printk("tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat, 
-              ccb[mbo].hastat, ccb[mbo].idlun, mbo);
-       return;
-      }
-      
-      my_done = SCtmp->scsi_done;
-      if (SCtmp->host_scribble) {
-         scsi_free(SCtmp->host_scribble, 512);
-         SCtmp->host_scribble = 0;
-      }
-      
-      /* Fetch the sense data, and tuck it away, in the required slot.  The
-        Adaptec automatically fetches it, and there is no guarantee that
-        we will still have it in the cdb when we come back */
-      if (ccb[mbo].tarstat == 2)
-       memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], 
-              sizeof(SCtmp->sense_buffer));
-      
-      
-      /* is there mail :-) */
-      
-      /* more error checking left out here */
-      if (mbistatus != 1)
-       /* This is surely wrong, but I don't know what's right */
-       errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
-      else
-       errstatus = 0;
-      
+
+               SCtmp = HOSTDATA(shost)->SCint[mbo];
+
+               if (!SCtmp || !SCtmp->scsi_done) {
+                       printk(KERN_WARNING "aha1542_intr_handle: Unexpected interrupt\n");
+                       printk(KERN_WARNING "tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat,
+                              ccb[mbo].hastat, ccb[mbo].idlun, mbo);
+                       return;
+               }
+               my_done = SCtmp->scsi_done;
+               if (SCtmp->host_scribble) {
+                       scsi_free(SCtmp->host_scribble, 512);
+                       SCtmp->host_scribble = 0;
+               }
+               /* Fetch the sense data, and tuck it away, in the required slot.  The
+                  Adaptec automatically fetches it, and there is no guarantee that
+                  we will still have it in the cdb when we come back */
+               if (ccb[mbo].tarstat == 2)
+                       memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
+                              sizeof(SCtmp->sense_buffer));
+
+
+               /* is there mail :-) */
+
+               /* more error checking left out here */
+               if (mbistatus != 1)
+                       /* This is surely wrong, but I don't know what's right */
+                       errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
+               else
+                       errstatus = 0;
+
 #ifdef DEBUG
-      if(errstatus) printk("(aha1542 error:%x %x %x) ",errstatus, 
-                          ccb[mbo].hastat, ccb[mbo].tarstat);
+               if (errstatus)
+                       printk(KERN_DEBUG "(aha1542 error:%x %x %x) ", errstatus,
+                              ccb[mbo].hastat, ccb[mbo].tarstat);
 #endif
 
-      if (ccb[mbo].tarstat == 2) {
+               if (ccb[mbo].tarstat == 2) {
 #ifdef DEBUG
-       int i;
+                       int i;
 #endif
-       DEB(printk("aha1542_intr_handle: sense:"));
+                       DEB(printk("aha1542_intr_handle: sense:"));
 #ifdef DEBUG
-       for (i = 0; i < 12; i++)
-         printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen+i]);
-       printk("\n");
+                       for (i = 0; i < 12; i++)
+                               printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]);
+                       printk("\n");
 #endif
-       /*
-         DEB(printk("aha1542_intr_handle: buf:"));
-         for (i = 0; i < bufflen; i++)
-         printk("%02x ", ((unchar *)buff)[i]);
-         printk("\n");
-         */
-      }
-      DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
-      SCtmp->result = errstatus;
-      HOSTDATA(shost)->SCint[mbo] = NULL;  /* This effectively frees up the mailbox slot, as
-                            far as queuecommand is concerned */
-      my_done(SCtmp);
-      number_serviced++;
-    };
+                       /*
+                          DEB(printk("aha1542_intr_handle: buf:"));
+                          for (i = 0; i < bufflen; i++)
+                          printk("%02x ", ((unchar *)buff)[i]);
+                          printk("\n");
+                        */
+               }
+               DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
+               SCtmp->result = errstatus;
+               HOSTDATA(shost)->SCint[mbo] = NULL;     /* This effectively frees up the mailbox slot, as
+                                                          far as queuecommand is concerned */
+               my_done(SCtmp);
+               number_serviced++;
+       };
 }
 
-int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
-    unchar ahacmd = CMD_START_SCSI;
-    unchar direction;
-    unchar *cmd = (unchar *) SCpnt->cmnd;
-    unchar target = SCpnt->target;
-    unchar lun = SCpnt->lun;
-    unsigned long flags;
-    void *buff = SCpnt->request_buffer;
-    int bufflen = SCpnt->request_bufflen;
-    int mbo;
-    struct mailbox * mb;
-    struct ccb  *ccb;
-
-    DEB(int i);
-
-    mb = HOSTDATA(SCpnt->host)->mb;
-    ccb = HOSTDATA(SCpnt->host)->ccb;
-
-    DEB(if (target > 1) {
-      SCpnt->result = DID_TIME_OUT << 16;
-      done(SCpnt); return 0;});
-    
-    if(*cmd == REQUEST_SENSE){
-      /* Don't do the command - we have the sense data already */
+       unchar ahacmd = CMD_START_SCSI;
+       unchar direction;
+       unchar *cmd = (unchar *) SCpnt->cmnd;
+       unchar target = SCpnt->target;
+       unchar lun = SCpnt->lun;
+       unsigned long flags;
+       void *buff = SCpnt->request_buffer;
+       int bufflen = SCpnt->request_bufflen;
+       int mbo;
+       struct mailbox *mb;
+       struct ccb *ccb;
+
+       DEB(int i);
+
+       mb = HOSTDATA(SCpnt->host)->mb;
+       ccb = HOSTDATA(SCpnt->host)->ccb;
+
+       DEB(if (target > 1) {
+           SCpnt->result = DID_TIME_OUT << 16;
+           done(SCpnt); return 0;
+           }
+       );
+
+       if (*cmd == REQUEST_SENSE) {
+               /* Don't do the command - we have the sense data already */
 #if 0
-      /* scsi_request_sense() provides a buffer of size 256,
-        so there is no reason to expect equality */
-      if (bufflen != sizeof(SCpnt->sense_buffer))
-       printk("aha1542: Wrong buffer length supplied "
-              "for request sense (%d)\n", bufflen);
+               /* scsi_request_sense() provides a buffer of size 256,
+                  so there is no reason to expect equality */
+               if (bufflen != sizeof(SCpnt->sense_buffer))
+                       printk(KERN_CRIT "aha1542: Wrong buffer length supplied "
+                              "for request sense (%d)\n", bufflen);
 #endif
-      SCpnt->result = 0;
-      done(SCpnt); 
-      return 0;
-    }
-
+               SCpnt->result = 0;
+               done(SCpnt);
+               return 0;
+       }
 #ifdef DEBUG
-    if (*cmd == READ_10 || *cmd == WRITE_10)
-      i = xscsi2int(cmd+2);
-    else if (*cmd == READ_6 || *cmd == WRITE_6)
-      i = scsi2int(cmd+2);
-    else
-      i = -1;
-    if (done)
-      printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
-    else
-      printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
-    aha1542_stat();
-    printk("aha1542_queuecommand: dumping scsi cmd:");
-    for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
-    printk("\n");
-    if (*cmd == WRITE_10 || *cmd == WRITE_6)
-      return 0; /* we are still testing, so *don't* write */
+       if (*cmd == READ_10 || *cmd == WRITE_10)
+               i = xscsi2int(cmd + 2);
+       else if (*cmd == READ_6 || *cmd == WRITE_6)
+               i = scsi2int(cmd + 2);
+       else
+               i = -1;
+       if (done)
+               printk(KERN_DEBUG "aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+       else
+               printk(KERN_DEBUG "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+       aha1542_stat();
+       printk(KERN_DEBUG "aha1542_queuecommand: dumping scsi cmd:");
+       for (i = 0; i < SCpnt->cmd_len; i++)
+               printk("%02x ", cmd[i]);
+       printk("\n");
+       if (*cmd == WRITE_10 || *cmd == WRITE_6)
+               return 0;       /* we are still testing, so *don't* write */
 #endif
-/* Use the outgoing mailboxes in a round-robin fashion, because this
-   is how the host adapter will scan for them */
+       /* Use the outgoing mailboxes in a round-robin fashion, because this
+          is how the host adapter will scan for them */
 
-    save_flags(flags);
-    cli();
-    mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
-    if (mbo >= AHA1542_MAILBOXES) mbo = 0;
+       save_flags(flags);
+       cli();
+       mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
+       if (mbo >= AHA1542_MAILBOXES)
+               mbo = 0;
 
-    do{
-      if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
-       break;
-      mbo++;
-      if (mbo >= AHA1542_MAILBOXES) mbo = 0;
-    } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
+       do {
+               if (mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
+                       break;
+               mbo++;
+               if (mbo >= AHA1542_MAILBOXES)
+                       mbo = 0;
+       } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
 
-    if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
-      panic("Unable to find empty mailbox for aha1542.\n");
+       if (mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
+               panic("Unable to find empty mailbox for aha1542.\n");
 
-    HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt;  /* This will effectively prevent someone else from
-                           screwing with this cdb. */
+       HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt;      /* This will effectively prevent someone else from
+                                                          screwing with this cdb. */
 
-    HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;    
-    restore_flags(flags);
+       HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
+       restore_flags(flags);
 
 #ifdef DEBUG
-    printk("Sending command (%d %x)...",mbo, done);
+       printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done);
 #endif
 
-    any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/
+       any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo]));   /* This gets trashed for some reason */
 
-    memset(&ccb[mbo], 0, sizeof(struct ccb));
+       memset(&ccb[mbo], 0, sizeof(struct ccb));
 
-    ccb[mbo].cdblen = SCpnt->cmd_len;
+       ccb[mbo].cdblen = SCpnt->cmd_len;
 
-    direction = 0;
-    if (*cmd == READ_10 || *cmd == READ_6)
-       direction = 8;
-    else if (*cmd == WRITE_10 || *cmd == WRITE_6)
-       direction = 16;
+       direction = 0;
+       if (*cmd == READ_10 || *cmd == READ_6)
+               direction = 8;
+       else if (*cmd == WRITE_10 || *cmd == WRITE_6)
+               direction = 16;
 
-    memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
+       memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
 
-    if (SCpnt->use_sg) {
-      struct scatterlist * sgpnt;
-      struct chain * cptr;
+       if (SCpnt->use_sg) {
+               struct scatterlist *sgpnt;
+               struct chain *cptr;
 #ifdef DEBUG
-      unsigned char * ptr;
+               unsigned char *ptr;
 #endif
-      int i;
-      ccb[mbo].op = 2;       /* SCSI Initiator Command  w/scatter-gather*/
-      SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
-      sgpnt = (struct scatterlist *) SCpnt->request_buffer;
-      cptr = (struct chain *) SCpnt->host_scribble; 
-      if (cptr == NULL) panic("aha1542.c: unable to allocate DMA memory\n");
-      for(i=0; i<SCpnt->use_sg; i++) {
-       if(sgpnt[i].length == 0 || SCpnt->use_sg > 16 || 
-          (((int)sgpnt[i].address) & 1) || (sgpnt[i].length & 1)){
-         unsigned char * ptr;
-         printk("Bad segment list supplied to aha1542.c (%d, %d)\n",SCpnt->use_sg,i);
-         for(i=0;i<SCpnt->use_sg;i++){
-           printk("%d: %x %x %d\n",i,(unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
-                  sgpnt[i].length);
-         };
-         printk("cptr %x: ",(unsigned int) cptr);
-         ptr = (unsigned char *) &cptr[i];
-         for(i=0;i<18;i++) printk("%02x ", ptr[i]);
-         panic("Foooooooood fight!");
-       };
-       any2scsi(cptr[i].dataptr, SCSI_PA(sgpnt[i].address));
-       if(SCSI_PA(sgpnt[i].address+sgpnt[i].length-1) > ISA_DMA_THRESHOLD)
-         BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i);
-       any2scsi(cptr[i].datalen, sgpnt[i].length);
-      };
-      any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
-      any2scsi(ccb[mbo].dataptr, SCSI_PA(cptr));
+               int i;
+               ccb[mbo].op = 2;        /* SCSI Initiator Command  w/scatter-gather */
+               SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
+               sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+               cptr = (struct chain *) SCpnt->host_scribble;
+               if (cptr == NULL)
+                       panic("aha1542.c: unable to allocate DMA memory\n");
+               for (i = 0; i < SCpnt->use_sg; i++) {
+                       if (sgpnt[i].length == 0 || SCpnt->use_sg > 16 ||
+                           (((int) sgpnt[i].address) & 1) || (sgpnt[i].length & 1)) {
+                               unsigned char *ptr;
+                               printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
+                               for (i = 0; i < SCpnt->use_sg; i++) {
+                                       printk(KERN_CRIT "%d: %x %x %d\n", i, (unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
+                                              sgpnt[i].length);
+                               };
+                               printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
+                               ptr = (unsigned char *) &cptr[i];
+                               for (i = 0; i < 18; i++)
+                                       printk("%02x ", ptr[i]);
+                               panic("Foooooooood fight!");
+                       };
+                       any2scsi(cptr[i].dataptr, SCSI_PA(sgpnt[i].address));
+                       if (SCSI_PA(sgpnt[i].address + sgpnt[i].length - 1) > ISA_DMA_THRESHOLD)
+                               BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i);
+                       any2scsi(cptr[i].datalen, sgpnt[i].length);
+               };
+               any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
+               any2scsi(ccb[mbo].dataptr, SCSI_PA(cptr));
 #ifdef DEBUG
-      printk("cptr %x: ",cptr);
-      ptr = (unsigned char *) cptr;
-      for(i=0;i<18;i++) printk("%02x ", ptr[i]);
+               printk("cptr %x: ", cptr);
+               ptr = (unsigned char *) cptr;
+               for (i = 0; i < 18; i++)
+                       printk("%02x ", ptr[i]);
 #endif
-    } else {
-      ccb[mbo].op = 0;       /* SCSI Initiator Command */
-      SCpnt->host_scribble = NULL;
-      any2scsi(ccb[mbo].datalen, bufflen);
-      if(buff && SCSI_PA(buff+bufflen-1) > ISA_DMA_THRESHOLD)
-       BAD_DMA(buff, bufflen);
-      any2scsi(ccb[mbo].dataptr, SCSI_PA(buff));
-    };
-    ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/
-    ccb[mbo].rsalen = 16;
-    ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
-    ccb[mbo].commlinkid = 0;
+       } else {
+               ccb[mbo].op = 0;        /* SCSI Initiator Command */
+               SCpnt->host_scribble = NULL;
+               any2scsi(ccb[mbo].datalen, bufflen);
+               if (buff && SCSI_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD)
+                       BAD_DMA(buff, bufflen);
+               any2scsi(ccb[mbo].dataptr, SCSI_PA(buff));
+       };
+       ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);     /*SCSI Target Id */
+       ccb[mbo].rsalen = 16;
+       ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+       ccb[mbo].commlinkid = 0;
 
 #ifdef DEBUG
-    { int i;
-    printk("aha1542_command: sending.. ");
-    for (i = 0; i < sizeof(ccb[mbo])-10; i++)
-      printk("%02x ", ((unchar *)&ccb[mbo])[i]);
-    };
+       {
+               int i;
+               printk(KERN_DEBUG "aha1542_command: sending.. ");
+               for (i = 0; i < sizeof(ccb[mbo]) - 10; i++)
+                       printk("%02x ", ((unchar *) & ccb[mbo])[i]);
+       };
 #endif
-    
-    if (done) {
-       DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
-       SCpnt->scsi_done = done;
-       mb[mbo].status = 1;
-       aha1542_out(SCpnt->host->io_port, &ahacmd, 1);          /* start scsi command */
-       DEB(aha1542_stat());
-    }
-    else
-      printk("aha1542_queuecommand: done can't be NULL\n");
-    
-    return 0;
+
+       if (done) {
+               DEB(printk("aha1542_queuecommand: now waiting for interrupt ");
+                   aha1542_stat());
+               SCpnt->scsi_done = done;
+               mb[mbo].status = 1;
+               aha1542_out(SCpnt->host->io_port, &ahacmd, 1);  /* start scsi command */
+               DEB(aha1542_stat());
+       } else
+               printk("aha1542_queuecommand: done can't be NULL\n");
+
+       return 0;
 }
 
 static void internal_done(Scsi_Cmnd * SCpnt)
@@ -728,107 +762,107 @@ static void internal_done(Scsi_Cmnd * SCpnt)
 
 int aha1542_command(Scsi_Cmnd * SCpnt)
 {
-    DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
+       DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
 
-    aha1542_queuecommand(SCpnt, internal_done);
+       aha1542_queuecommand(SCpnt, internal_done);
 
-    SCpnt->SCp.Status = 0;
-    while (!SCpnt->SCp.Status)
-       barrier();
-    return SCpnt->result;
+       SCpnt->SCp.Status = 0;
+       while (!SCpnt->SCp.Status)
+               barrier();
+       return SCpnt->result;
 }
 
 /* Initialize mailboxes */
-static void setup_mailboxes(int bse, struct Scsi_Host * shpnt)
+static void setup_mailboxes(int bse, struct Scsi_Host *shpnt)
 {
-    int i;
-    struct mailbox * mb;
-    struct ccb  *ccb;
-
-    unchar cmd[5] = {CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
-
-    mb = HOSTDATA(shpnt)->mb;
-    ccb = HOSTDATA(shpnt)->ccb;
-
-    for(i=0; i<AHA1542_MAILBOXES; i++){
-      mb[i].status = mb[AHA1542_MAILBOXES+i].status = 0;
-      any2scsi(mb[i].ccbptr, SCSI_PA(&ccb[i]));
-    };
-    aha1542_intr_reset(bse);     /* reset interrupts, so they don't block */   
-    any2scsi((cmd+2), SCSI_PA(mb));
-    aha1542_out(bse, cmd, 5);
-    WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
-    while (0) {
-      fail:
-       printk("aha1542_detect: failed setting up mailboxes\n");
-    }
-    aha1542_intr_reset(bse);
+       int i;
+       struct mailbox *mb;
+       struct ccb *ccb;
+
+       unchar cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
+
+       mb = HOSTDATA(shpnt)->mb;
+       ccb = HOSTDATA(shpnt)->ccb;
+
+       for (i = 0; i < AHA1542_MAILBOXES; i++) {
+               mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
+               any2scsi(mb[i].ccbptr, SCSI_PA(&ccb[i]));
+       };
+       aha1542_intr_reset(bse);        /* reset interrupts, so they don't block */
+       any2scsi((cmd + 2), SCSI_PA(mb));
+       aha1542_out(bse, cmd, 5);
+       WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
+       while (0) {
+fail:
+               printk(KERN_ERR "aha1542_detect: failed setting up mailboxes\n");
+       }
+       aha1542_intr_reset(bse);
 }
 
-static int aha1542_getconfig(int base_io, unsigned char * irq_level, unsigned char * dma_chan, unsigned char * scsi_id)
+static int aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id)
 {
-  unchar inquiry_cmd[] = {CMD_RETCONF };
-  unchar inquiry_result[3];
-  int i;
-  i = inb(STATUS(base_io));
-  if (i & DF) {
-    i = inb(DATA(base_io));
-  };
-  aha1542_out(base_io, inquiry_cmd, 1);
-  aha1542_in(base_io, inquiry_result, 3);
-  WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
-  while (0) {
-  fail:
-    printk("aha1542_detect: query board settings\n");
-  }
-  aha1542_intr_reset(base_io);
-  switch(inquiry_result[0]){
-  case 0x80:
-    *dma_chan = 7;
-    break;
-  case 0x40:
-    *dma_chan = 6;
-    break;
-  case 0x20:
-    *dma_chan = 5;
-    break;
-  case 0x01:
-    *dma_chan = 0;
-    break;
-  case 0:
-    /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
-       Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
-    *dma_chan = 0xFF;
-    break;
-  default:
-    printk("Unable to determine Adaptec DMA priority.  Disabling board\n");
-    return -1;
-  };
-  switch(inquiry_result[1]){
-  case 0x40:
-    *irq_level = 15;
-    break;
-  case 0x20:
-    *irq_level = 14;
-    break;
-  case 0x8:
-    *irq_level = 12;
-    break;
-  case 0x4:
-    *irq_level = 11;
-    break;
-  case 0x2:
-    *irq_level = 10;
-    break;
-  case 0x1:
-    *irq_level = 9;
-    break;
-  default:
-    printk("Unable to determine Adaptec IRQ level.  Disabling board\n");
-    return -1;
-  };
-  *scsi_id=inquiry_result[2] & 7;
-  return 0;
+       unchar inquiry_cmd[] = {CMD_RETCONF};
+       unchar inquiry_result[3];
+       int i;
+       i = inb(STATUS(base_io));
+       if (i & DF) {
+               i = inb(DATA(base_io));
+       };
+       aha1542_out(base_io, inquiry_cmd, 1);
+       aha1542_in(base_io, inquiry_result, 3);
+       WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+       while (0) {
+fail:
+               printk(KERN_ERR "aha1542_detect: query board settings\n");
+       }
+       aha1542_intr_reset(base_io);
+       switch (inquiry_result[0]) {
+       case 0x80:
+               *dma_chan = 7;
+               break;
+       case 0x40:
+               *dma_chan = 6;
+               break;
+       case 0x20:
+               *dma_chan = 5;
+               break;
+       case 0x01:
+               *dma_chan = 0;
+               break;
+       case 0:
+               /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
+                  Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
+               *dma_chan = 0xFF;
+               break;
+       default:
+               printk(KERN_ERR "Unable to determine Adaptec DMA priority.  Disabling board\n");
+               return -1;
+       };
+       switch (inquiry_result[1]) {
+       case 0x40:
+               *irq_level = 15;
+               break;
+       case 0x20:
+               *irq_level = 14;
+               break;
+       case 0x8:
+               *irq_level = 12;
+               break;
+       case 0x4:
+               *irq_level = 11;
+               break;
+       case 0x2:
+               *irq_level = 10;
+               break;
+       case 0x1:
+               *irq_level = 9;
+               break;
+       default:
+               printk(KERN_ERR "Unable to determine Adaptec IRQ level.  Disabling board\n");
+               return -1;
+       };
+       *scsi_id = inquiry_result[2] & 7;
+       return 0;
 }
 
 /* This function should only be called for 1542C boards - we can detect
@@ -836,364 +870,394 @@ static int aha1542_getconfig(int base_io, unsigned char * irq_level, unsigned ch
 
 static int aha1542_mbenable(int base)
 {
-  static unchar mbenable_cmd[3];
-  static unchar mbenable_result[2];
-  int retval;
-  
-  retval = BIOS_TRANSLATION_6432;
-
-  mbenable_cmd[0]=CMD_EXTBIOS;
-  aha1542_out(base,mbenable_cmd,1);
-  if(aha1542_in1(base,mbenable_result,2))
-    return retval;
-  WAITd(INTRFLAGS(base),INTRMASK,HACC,0,100);
-  aha1542_intr_reset(base);
-  
-  if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
-     mbenable_cmd[0]=CMD_MBENABLE;
-     mbenable_cmd[1]=0;
-     mbenable_cmd[2]=mbenable_result[1];
-
-     if((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
-       retval = BIOS_TRANSLATION_25563;
-
-     aha1542_out(base,mbenable_cmd,3);
-     WAIT(INTRFLAGS(base),INTRMASK,HACC,0);
-  };
-  while(0) {
+       static unchar mbenable_cmd[3];
+       static unchar mbenable_result[2];
+       int retval;
+
+       retval = BIOS_TRANSLATION_6432;
+
+       mbenable_cmd[0] = CMD_EXTBIOS;
+       aha1542_out(base, mbenable_cmd, 1);
+       if (aha1542_in1(base, mbenable_result, 2))
+               return retval;
+       WAITd(INTRFLAGS(base), INTRMASK, HACC, 0, 100);
+       aha1542_intr_reset(base);
+
+       if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
+               mbenable_cmd[0] = CMD_MBENABLE;
+               mbenable_cmd[1] = 0;
+               mbenable_cmd[2] = mbenable_result[1];
+
+               if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
+                       retval = BIOS_TRANSLATION_25563;
+
+               aha1542_out(base, mbenable_cmd, 3);
+               WAIT(INTRFLAGS(base), INTRMASK, HACC, 0);
+       };
+       while (0) {
 fail:
-    printk("aha1542_mbenable: Mailbox init failed\n");
-  }
-aha1542_intr_reset(base);
-return retval;
+               printk(KERN_ERR "aha1542_mbenable: Mailbox init failed\n");
+       }
+       aha1542_intr_reset(base);
+       return retval;
 }
 
 /* Query the board to find out if it is a 1542 or a 1740, or whatever. */
-static int aha1542_query(int base_io, int * transl)
+static int aha1542_query(int base_io, int *transl)
 {
-  unchar inquiry_cmd[] = {CMD_INQUIRY };
-  unchar inquiry_result[4];
-  int i;
-  i = inb(STATUS(base_io));
-  if (i & DF) {
-    i = inb(DATA(base_io));
-  };
-  aha1542_out(base_io, inquiry_cmd, 1);
-  aha1542_in(base_io, inquiry_result, 4);
-  WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
-  while (0) {
-  fail:
-    printk("aha1542_detect: query card type\n");
-  }
-  aha1542_intr_reset(base_io);
-
-  *transl = BIOS_TRANSLATION_6432; /* Default case */
-
-/* For an AHA1740 series board, we ignore the board since there is a
-   hardware bug which can lead to wrong blocks being returned if the board
-   is operating in the 1542 emulation mode.  Since there is an extended mode
-   driver, we simply ignore the board and let the 1740 driver pick it up.
-*/
-
-  if (inquiry_result[0] == 0x43) {
-    printk("aha1542.c: Emulation mode not supported for AHA 174N hardware.\n");
-    return 1;
-  };
-
-  /* Always call this - boards that do not support extended bios translation
-     will ignore the command, and we will set the proper default */
-
-  *transl = aha1542_mbenable(base_io);
-
-  return 0;
+       unchar inquiry_cmd[] = {CMD_INQUIRY};
+       unchar inquiry_result[4];
+       int i;
+       i = inb(STATUS(base_io));
+       if (i & DF) {
+               i = inb(DATA(base_io));
+       };
+       aha1542_out(base_io, inquiry_cmd, 1);
+       aha1542_in(base_io, inquiry_result, 4);
+       WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+       while (0) {
+fail:
+               printk(KERN_ERR "aha1542_detect: query card type\n");
+       }
+       aha1542_intr_reset(base_io);
+
+       *transl = BIOS_TRANSLATION_6432;        /* Default case */
+
+       /* For an AHA1740 series board, we ignore the board since there is a
+          hardware bug which can lead to wrong blocks being returned if the board
+          is operating in the 1542 emulation mode.  Since there is an extended mode
+          driver, we simply ignore the board and let the 1740 driver pick it up.
+        */
+
+       if (inquiry_result[0] == 0x43) {
+               printk(KERN_INFO "aha1542.c: Emulation mode not supported for AHA 174N hardware.\n");
+               return 1;
+       };
+
+       /* Always call this - boards that do not support extended bios translation
+          will ignore the command, and we will set the proper default */
+
+       *transl = aha1542_mbenable(base_io);
+
+       return 0;
 }
 
 /* called from init/main.c */
-void __init aha1542_setup( char *str, int *ints)
+void __init aha1542_setup(char *str, int *ints)
 {
-    const char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n";
-    static int setup_idx = 0;
-    int setup_portbase;
-
-    if(setup_idx >= MAXBOARDS)
-      {
-       printk("aha1542: aha1542_setup called too many times! Bad LILO params ?\n");
-       printk("   Entryline 1: %s\n",setup_str[0]);
-       printk("   Entryline 2: %s\n",setup_str[1]);
-       printk("   This line:   %s\n",str);
-       return;
-      }
-    if (ints[0] < 1 || ints[0] > 4)
-      {
-       printk("aha1542: %s\n", str );
-       printk(ahausage);
-       printk("aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n");
-      }
-
-    setup_called[setup_idx]=ints[0];
-    setup_str[setup_idx]=str;
-
-    setup_portbase             = ints[0] >= 1 ? ints[1] : 0; /* Preserve the default value.. */
-    setup_buson   [setup_idx]  = ints[0] >= 2 ? ints[2] : 7;
-    setup_busoff  [setup_idx]  = ints[0] >= 3 ? ints[3] : 5;
-    if (ints[0] >= 4) {
-      int atbt = -1;
-      switch (ints[4]) {
-       case 5:
-           atbt = 0x00;
-           break;
-       case 6:
-           atbt = 0x04;
-           break;
-       case 7:
-           atbt = 0x01;
-           break;
-       case 8:
-           atbt = 0x02;
-           break;
-       case 10:
-           atbt = 0x03;
-           break;
-       default:
-           printk("aha1542: %s\n", str );
-           printk(ahausage);
-           printk("aha1542: Valid values for DMASPEED are 5-8, 10 MB/s.  Using jumper defaults.\n");
-           break;
-      }
-      setup_dmaspeed[setup_idx]  = atbt;
-    }
-
-    if (setup_portbase != 0)
-      bases[setup_idx] = setup_portbase;
-
-    ++setup_idx;
+       const char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n";
+       static int setup_idx = 0;
+       int setup_portbase;
+
+       if (setup_idx >= MAXBOARDS) {
+               printk(KERN_ERR "aha1542: aha1542_setup called too many times! Bad LILO params ?\n");
+               printk(KERN_ERR "   Entryline 1: %s\n", setup_str[0]);
+               printk(KERN_ERR "   Entryline 2: %s\n", setup_str[1]);
+               printk(KERN_ERR "   This line:   %s\n", str);
+               return;
+       }
+       if (ints[0] < 1 || ints[0] > 4) {
+               printk(KERN_ERR "aha1542: %s\n", str);
+               printk(ahausage);
+               printk(KERN_ERR "aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n");
+       }
+       setup_called[setup_idx] = ints[0];
+       setup_str[setup_idx] = str;
+
+       setup_portbase = ints[0] >= 1 ? ints[1] : 0;    /* Preserve the default value.. */
+       setup_buson[setup_idx] = ints[0] >= 2 ? ints[2] : 7;
+       setup_busoff[setup_idx] = ints[0] >= 3 ? ints[3] : 5;
+       if (ints[0] >= 4) 
+       {
+               int atbt = -1;
+               switch (ints[4]) {
+               case 5:
+                       atbt = 0x00;
+                       break;
+               case 6:
+                       atbt = 0x04;
+                       break;
+               case 7:
+                       atbt = 0x01;
+                       break;
+               case 8:
+                       atbt = 0x02;
+                       break;
+               case 10:
+                       atbt = 0x03;
+                       break;
+               default:
+                       printk(KERN_ERR "aha1542: %s\n", str);
+                       printk(ahausage);
+                       printk(KERN_ERR "aha1542: Valid values for DMASPEED are 5-8, 10 MB/s.  Using jumper defaults.\n");
+                       break;
+               }
+               setup_dmaspeed[setup_idx] = atbt;
+       }
+       if (setup_portbase != 0)
+               bases[setup_idx] = setup_portbase;
+
+       ++setup_idx;
 }
 
 /* return non-zero on detection */
 int aha1542_detect(Scsi_Host_Template * tpnt)
 {
-    unsigned char dma_chan;
-    unsigned char irq_level;
-    unsigned char scsi_id;
-    unsigned long flags;
-    unsigned int base_io;
-    int trans;
-    struct Scsi_Host * shpnt = NULL;
-    int count = 0;
-    int indx;
+       unsigned char dma_chan;
+       unsigned char irq_level;
+       unsigned char scsi_id;
+       unsigned long flags;
+       unsigned int base_io;
+       int trans;
+       struct Scsi_Host *shpnt = NULL;
+       int count = 0;
+       int indx;
 
-    DEB(printk("aha1542_detect: \n"));
+       DEB(printk("aha1542_detect: \n"));
 
-    tpnt->proc_name = "aha1542";
+       tpnt->proc_name = "aha1542";
 
 #ifdef MODULE
-    bases[0]        = aha1542[0];              
-    setup_buson[0]  = aha1542[1];              
-    setup_busoff[0] = aha1542[2];              
-    {                                          
-      int atbt = -1;                           
-      switch (aha1542[3]) {                    
-        case 5:                                
-            atbt = 0x00;                       
-            break;                             
-        case 6:                                
-            atbt = 0x04;                       
-            break;                             
-        case 7:                                
-            atbt = 0x01;                       
-            break;                             
-        case 8:                                
-            atbt = 0x02;                       
-            break;                             
-        case 10:                               
-            atbt = 0x03;                       
-            break;                             
-      };                                       
-    setup_dmaspeed[0] = atbt;                  
-    }
+       bases[0] = aha1542[0];
+       setup_buson[0]=aha1542[1];
+       setup_busoff[0] = aha1542[2];
+       {
+               int atbt = -1;
+               switch (aha1542[3]) {
+               case 5:
+                       atbt = 0x00;
+                       break;
+               case 6:
+                       atbt = 0x04;
+                       break;
+               case 7:
+                       atbt = 0x01;
+                       break;
+               case 8:
+                       atbt = 0x02;
+                       break;
+               case 10:
+                       atbt = 0x03;
+                       break;
+               };
+               setup_dmaspeed[0] = atbt;
+       }
 #endif
-
-    for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++)
-           if(bases[indx] != 0 && !check_region(bases[indx], 4)) { 
-                   shpnt = scsi_register(tpnt,
-                                         sizeof(struct aha1542_hostdata));
-
-                   /* For now we do this - until kmalloc is more intelligent
-                      we are resigned to stupid hacks like this */
-                   if (SCSI_PA(shpnt) >= ISA_DMA_THRESHOLD) {
-                     printk("Invalid address for shpnt with 1542.\n");
-                     goto unregister;
-                   }
-
-                   if(!aha1542_test_port(bases[indx], shpnt)) goto unregister;
-
-
-                   base_io = bases[indx];
-                   
-                   /* Set the Bus on/off-times as not to ruin floppy performance */
-           {
-                   unchar oncmd[] = {CMD_BUSON_TIME, 7};
-                   unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
-
-                   if(setup_called[indx])
-                     {
-                       oncmd[1]  = setup_buson[indx];
-                       offcmd[1] = setup_busoff[indx];
-                     }
-                   
-                   aha1542_intr_reset(base_io);
-                   aha1542_out(base_io, oncmd, 2);
-                   WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
-                   aha1542_intr_reset(base_io);
-                   aha1542_out(base_io, offcmd, 2);
-                   WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
-                   if (setup_dmaspeed[indx] >= 0)
-                     {
-                       unchar dmacmd[] = {CMD_DMASPEED, 0};
-                       dmacmd[1] = setup_dmaspeed[indx];
-                       aha1542_intr_reset(base_io);
-                       aha1542_out(base_io, dmacmd, 2);
-                       WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
-                     }
-                   while (0) {
-                   fail:
-                           printk("aha1542_detect: setting bus on/off-time failed\n");
-                   }
-                   aha1542_intr_reset(base_io);
-           }
-                   if(aha1542_query(base_io, &trans))  goto unregister;
-                   
-                   if (aha1542_getconfig(base_io, &irq_level, &dma_chan, &scsi_id) == -1)  goto unregister;
-                   
-                   printk("Configuring Adaptec (SCSI-ID %d) at IO:%x, IRQ %d", scsi_id, base_io, irq_level);
-                   if (dma_chan != 0xFF)
-                           printk(", DMA priority %d", dma_chan);
-                   printk("\n");
-                   
-                   DEB(aha1542_stat());
-                   setup_mailboxes(base_io, shpnt);
-                   
-                   DEB(aha1542_stat());
-                   
-                   DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
-                   save_flags(flags);
-                   cli();
-                   if (request_irq(irq_level,do_aha1542_intr_handle, 0, "aha1542", NULL)) {
-                           printk("Unable to allocate IRQ for adaptec controller.\n");
-                           restore_flags(flags);
-                           goto unregister;
-                   }
-                   
-                   if (dma_chan != 0xFF) {
-                           if (request_dma(dma_chan,"aha1542")) {
-                                   printk("Unable to allocate DMA channel for Adaptec.\n");
-                                   free_irq(irq_level, NULL);
-                                   restore_flags(flags);
-                                   goto unregister;
-                           }
-                           
-                           if (dma_chan == 0 || dma_chan >= 5) {
-                                   set_dma_mode(dma_chan, DMA_MODE_CASCADE);
-                                   enable_dma(dma_chan);
-                           }
-                   }
-                   aha_host[irq_level - 9] = shpnt;
-                   shpnt->this_id = scsi_id;
-                   shpnt->unique_id = base_io;
-                   shpnt->io_port = base_io;
-                   shpnt->n_io_port = 4;  /* Number of bytes of I/O space used */
-                   shpnt->dma_channel = dma_chan;
-                   shpnt->irq = irq_level;
-                   HOSTDATA(shpnt)->bios_translation  = trans;
-                   if(trans == BIOS_TRANSLATION_25563) 
-                     printk("aha1542.c: Using extended bios translation\n");
-                   HOSTDATA(shpnt)->aha1542_last_mbi_used  = (2*AHA1542_MAILBOXES - 1);
-                   HOSTDATA(shpnt)->aha1542_last_mbo_used  = (AHA1542_MAILBOXES - 1);
-                   memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
-                   restore_flags(flags);
+       /*
+        *      Hunt for ISA Plug'n'Pray Adaptecs (AHA1535)
+        */
+        
+       if(isapnp)
+       {
+               struct pci_dev *pdev = NULL;
+               for(indx = 0; indx <sizeof(bases)/sizeof(bases[0]);indx++)
+               {
+                       if(bases[indx])
+                               continue;
+                       pdev = isapnp_find_dev(NULL, ISAPNP_VENDOR('A', 'D', 'P'), 
+                               ISAPNP_FUNCTION(0x1542), pdev);
+                       if(pdev==NULL)
+                               break;
+                       /*
+                        *      Activate the PnP card
+                        */
+                        
+                       if(pdev->prepare(pdev)<0)
+                               continue;
+                               
+                       if(!(pdev->resource[0].flags&IORESOURCE_IO))
+                               continue;
+                               
+                       pdev->resource[0].flags|=IORESOURCE_AUTO;
+
+                       if(pdev->activate(pdev)<0)
+                               continue;
+                               
+                       bases[indx] = pdev->resource[0].start;
+                       
+                       /* The card can be queried for its DMA, we have 
+                          the DMA set up that is enough */
+                          
+                       printk(KERN_INFO "ISAPnP found an AHA1535 at I/O 0x%03X\n", bases[indx]);
+               }
+       }
+       for (indx = 0; indx < sizeof(bases) / sizeof(bases[0]); indx++)
+               if (bases[indx] != 0 && !check_region(bases[indx], 4)) {
+                       shpnt = scsi_register(tpnt,
+                                       sizeof(struct aha1542_hostdata));
+
+                       /* For now we do this - until kmalloc is more intelligent
+                          we are resigned to stupid hacks like this */
+                       if (SCSI_PA(shpnt) >= ISA_DMA_THRESHOLD) {
+                               printk(KERN_ERR "Invalid address for shpnt with 1542.\n");
+                               goto unregister;
+                       }
+                       if (!aha1542_test_port(bases[indx], shpnt))
+                               goto unregister;
+
+
+                       base_io = bases[indx];
+
+                       /* Set the Bus on/off-times as not to ruin floppy performance */
+                       {
+                               unchar oncmd[] = {CMD_BUSON_TIME, 7};
+                               unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
+
+                               if (setup_called[indx]) {
+                                       oncmd[1] = setup_buson[indx];
+                                       offcmd[1] = setup_busoff[indx];
+                               }
+                               aha1542_intr_reset(base_io);
+                               aha1542_out(base_io, oncmd, 2);
+                               WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+                               aha1542_intr_reset(base_io);
+                               aha1542_out(base_io, offcmd, 2);
+                               WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+                               if (setup_dmaspeed[indx] >= 0) {
+                                       unchar dmacmd[] = {CMD_DMASPEED, 0};
+                                       dmacmd[1] = setup_dmaspeed[indx];
+                                       aha1542_intr_reset(base_io);
+                                       aha1542_out(base_io, dmacmd, 2);
+                                       WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+                               }
+                               while (0) {
+fail:
+                                       printk(KERN_ERR "aha1542_detect: setting bus on/off-time failed\n");
+                               }
+                               aha1542_intr_reset(base_io);
+                       }
+                       if (aha1542_query(base_io, &trans))
+                               goto unregister;
+
+                       if (aha1542_getconfig(base_io, &irq_level, &dma_chan, &scsi_id) == -1)
+                               goto unregister;
+
+                       printk(KERN_INFO "Configuring Adaptec (SCSI-ID %d) at IO:%x, IRQ %d", scsi_id, base_io, irq_level);
+                       if (dma_chan != 0xFF)
+                               printk(", DMA priority %d", dma_chan);
+                       printk("\n");
+
+                       DEB(aha1542_stat());
+                       setup_mailboxes(base_io, shpnt);
+
+                       DEB(aha1542_stat());
+
+                       DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
+                       save_flags(flags);
+                       cli();
+                       if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) {
+                               printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n");
+                               restore_flags(flags);
+                               goto unregister;
+                       }
+                       if (dma_chan != 0xFF) {
+                               if (request_dma(dma_chan, "aha1542")) {
+                                       printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n");
+                                       free_irq(irq_level, NULL);
+                                       restore_flags(flags);
+                                       goto unregister;
+                               }
+                               if (dma_chan == 0 || dma_chan >= 5) {
+                                       set_dma_mode(dma_chan, DMA_MODE_CASCADE);
+                                       enable_dma(dma_chan);
+                               }
+                       }
+                       aha_host[irq_level - 9] = shpnt;
+                       shpnt->this_id = scsi_id;
+                       shpnt->unique_id = base_io;
+                       shpnt->io_port = base_io;
+                       shpnt->n_io_port = 4;   /* Number of bytes of I/O space used */
+                       shpnt->dma_channel = dma_chan;
+                       shpnt->irq = irq_level;
+                       HOSTDATA(shpnt)->bios_translation = trans;
+                       if (trans == BIOS_TRANSLATION_25563)
+                               printk(KERN_INFO "aha1542.c: Using extended bios translation\n");
+                       HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1);
+                       HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
+                       memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
+                       restore_flags(flags);
 #if 0
-                   DEB(printk(" *** READ CAPACITY ***\n"));
-                   
-           {
-                   unchar buf[8];
-                   static unchar cmd[] = {     READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-                   int i;
-                   
-                   for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
-                   for (i = 0; i < 2; ++i)
-                           if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
-                                   printk("aha_detect: LU %d sector_size %d device_size %d\n",
-                                          i, xscsi2int(buf+4), xscsi2int(buf));
-                           }
-           }
-                   
-                   DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
-                   
-                   for (i = 0; i < 4; ++i)
-                   {
-                           unsigned char cmd[10];
-                           static buffer[512];
-                           
-                           cmd[0] = READ_10;
-                           cmd[1] = 0;
-                           xany2scsi(cmd+2, i);
-                           cmd[6] = 0;
-                           cmd[7] = 0;
-                           cmd[8] = 1;
-                           cmd[9] = 0;
-                           aha1542_command(0, cmd, buffer, 512);
-                   }
-#endif    
-                   request_region(bases[indx], 4,"aha1542");  /* Register the IO ports that we use */
-                   count++;
-                   continue;
-           unregister:
-                   scsi_unregister(shpnt);
-                   continue;
-                   
-           };
-       
-    return count;
+                       DEB(printk(" *** READ CAPACITY ***\n"));
+
+                       {
+                               unchar buf[8];
+                               static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+                               int i;
+
+                               for (i = 0; i < sizeof(buf); ++i)
+                                       buf[i] = 0x87;
+                               for (i = 0; i < 2; ++i)
+                                       if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
+                                               printk(KERN_DEBUG "aha_detect: LU %d sector_size %d device_size %d\n",
+                                                      i, xscsi2int(buf + 4), xscsi2int(buf));
+                                       }
+                       }
+
+                       DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
+
+                       for (i = 0; i < 4; ++i) {
+                               unsigned char cmd[10];
+                               static buffer[512];
+
+                               cmd[0] = READ_10;
+                               cmd[1] = 0;
+                               xany2scsi(cmd + 2, i);
+                               cmd[6] = 0;
+                               cmd[7] = 0;
+                               cmd[8] = 1;
+                               cmd[9] = 0;
+                               aha1542_command(0, cmd, buffer, 512);
+                       }
+#endif
+                       request_region(bases[indx], 4, "aha1542");      /* Register the IO ports that we use */
+                       count++;
+                       continue;
+unregister:
+                       scsi_unregister(shpnt);
+                       continue;
+
+               };
+
+       return count;
 }
 
-static int aha1542_restart(struct Scsi_Host * shost)
+static int aha1542_restart(struct Scsi_Host *shost)
 {
-  int i;
-  int count = 0;
+       int i;
+       int count = 0;
 #if 0
-  unchar ahacmd = CMD_START_SCSI;
+       unchar ahacmd = CMD_START_SCSI;
 #endif
 
-  for(i=0; i< AHA1542_MAILBOXES; i++)
-   if(HOSTDATA(shost)->SCint[i] && 
-      !(HOSTDATA(shost)->SCint[i]->device->soft_reset))
-     {
+       for (i = 0; i < AHA1542_MAILBOXES; i++)
+               if (HOSTDATA(shost)->SCint[i] &&
+                   !(HOSTDATA(shost)->SCint[i]->device->soft_reset)) {
 #if 0
-       HOSTDATA(shost)->mb[i].status = 1; /* Indicate ready to restart... */
+                       HOSTDATA(shost)->mb[i].status = 1;      /* Indicate ready to restart... */
 #endif
-       count++;
-     }     
-
-  printk("Potential to restart %d stalled commands...\n", count);
+                       count++;
+               }
+       printk(KERN_DEBUG "Potential to restart %d stalled commands...\n", count);
 #if 0
-  /* start scsi command */
-  if (count) aha1542_out(shost->io_port, &ahacmd, 1);
+       /* start scsi command */
+       if (count)
+               aha1542_out(shost->io_port, &ahacmd, 1);
 #endif
-  return 0;
+       return 0;
 }
 
 int aha1542_abort(Scsi_Cmnd * SCpnt)
 {
-    
-    /*
-     * The abort command does not leave the device in a clean state where
-     *  it is available to be used again.  Until this gets worked out, we
-     * will leave it commented out.  
-     */
-
-    printk("aha1542.c: Unable to abort command for target %d\n", 
-          SCpnt->target);
-    return FAILED;
+
+       /*
+        * The abort command does not leave the device in a clean state where
+        *  it is available to be used again.  Until this gets worked out, we
+        * will leave it commented out.  
+        */
+
+       printk(KERN_ERR "aha1542.c: Unable to abort command for target %d\n",
+              SCpnt->target);
+       return FAILED;
 }
 
 /*
@@ -1202,240 +1266,226 @@ int aha1542_abort(Scsi_Cmnd * SCpnt)
  */
 int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
 {
-    unsigned long flags;
-    struct mailbox * mb;
-    unchar target = SCpnt->target;
-    unchar lun = SCpnt->lun;
-    int mbo;
-    struct ccb  *ccb;
-    unchar ahacmd = CMD_START_SCSI;
-
-    ccb = HOSTDATA(SCpnt->host)->ccb;
-    mb = HOSTDATA(SCpnt->host)->mb;
-
-    save_flags(flags);
-    cli();
-    mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
-    if (mbo >= AHA1542_MAILBOXES) mbo = 0;
-    
-    do{
-       if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
-           break;
-       mbo++;
-       if (mbo >= AHA1542_MAILBOXES) mbo = 0;
-    } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
-    
-    if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
-       panic("Unable to find empty mailbox for aha1542.\n");
-    
-    HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt;  /* This will effectively
-                                                  prevent someone else from
-                                                  screwing with this cdb. */
-           
-    HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;    
-    restore_flags(flags);
-    
-    any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/
-
-    memset(&ccb[mbo], 0, sizeof(struct ccb));
-    
-    ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
-
-    ccb[mbo].idlun = (target&7)<<5 | (lun & 7); /*SCSI Target Id*/
-
-    ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
-    ccb[mbo].commlinkid = 0;
-    
-    /* 
-     * Now tell the 1542 to flush all pending commands for this 
-     * target 
-     */
-    aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
-
-    printk("aha1542.c: Trying device reset for target %d\n", SCpnt->target);
-
-    return SUCCESS;
-           
+       unsigned long flags;
+       struct mailbox *mb;
+       unchar target = SCpnt->target;
+       unchar lun = SCpnt->lun;
+       int mbo;
+       struct ccb *ccb;
+       unchar ahacmd = CMD_START_SCSI;
+
+       ccb = HOSTDATA(SCpnt->host)->ccb;
+       mb = HOSTDATA(SCpnt->host)->mb;
+
+       save_flags(flags);
+       cli();
+       mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
+       if (mbo >= AHA1542_MAILBOXES)
+               mbo = 0;
+
+       do {
+               if (mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
+                       break;
+               mbo++;
+               if (mbo >= AHA1542_MAILBOXES)
+                       mbo = 0;
+       } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
+
+       if (mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
+               panic("Unable to find empty mailbox for aha1542.\n");
+
+       HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt;      /* This will effectively
+                                                          prevent someone else from
+                                                          screwing with this cdb. */
+
+       HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
+       restore_flags(flags);
+
+       any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo]));   /* This gets trashed for some reason */
+
+       memset(&ccb[mbo], 0, sizeof(struct ccb));
+
+       ccb[mbo].op = 0x81;     /* BUS DEVICE RESET */
+
+       ccb[mbo].idlun = (target & 7) << 5 | (lun & 7);         /*SCSI Target Id */
+
+       ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+       ccb[mbo].commlinkid = 0;
+
+       /* 
+        * Now tell the 1542 to flush all pending commands for this 
+        * target 
+        */
+       aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+       printk(KERN_WARNING "aha1542.c: Trying device reset for target %d\n", SCpnt->target);
+
+       return SUCCESS;
+
 
 #ifdef ERIC_neverdef
-    /* 
-     * With the 1542 we apparently never get an interrupt to
-     * acknowledge a device reset being sent.  Then again, Leonard
-     * says we are doing this wrong in the first place...
-     *
-     * Take a wait and see attitude.  If we get spurious interrupts,
-     * then the device reset is doing something sane and useful, and
-     * we will wait for the interrupt to post completion.
-     */
-    printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
-    
-    /*
-     * Free the command block for all commands running on this 
-     * target... 
-     */
-    for(i=0; i< AHA1542_MAILBOXES; i++)
-    {
-       if(HOSTDATA(SCpnt->host)->SCint[i] &&
-          HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
-       {
-           Scsi_Cmnd * SCtmp;
-           SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
-           if (SCtmp->host_scribble) 
-           {
-               scsi_free(SCtmp->host_scribble, 512);
-           }
-           
-           HOSTDATA(SCpnt->host)->SCint[i] = NULL;
-           HOSTDATA(SCpnt->host)->mb[i].status = 0;
+       /* 
+        * With the 1542 we apparently never get an interrupt to
+        * acknowledge a device reset being sent.  Then again, Leonard
+        * says we are doing this wrong in the first place...
+        *
+        * Take a wait and see attitude.  If we get spurious interrupts,
+        * then the device reset is doing something sane and useful, and
+        * we will wait for the interrupt to post completion.
+        */
+       printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+       /*
+        * Free the command block for all commands running on this 
+        * target... 
+        */
+       for (i = 0; i < AHA1542_MAILBOXES; i++) {
+               if (HOSTDATA(SCpnt->host)->SCint[i] &&
+                   HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) {
+                       Scsi_Cmnd *SCtmp;
+                       SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+                       if (SCtmp->host_scribble) {
+                               scsi_free(SCtmp->host_scribble, 512);
+                       }
+                       HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+                       HOSTDATA(SCpnt->host)->mb[i].status = 0;
+               }
        }
-    }
-    return SUCCESS;
+       return SUCCESS;
 
-    return FAILED;
-#endif /* ERIC_neverdef */
+       return FAILED;
+#endif                         /* ERIC_neverdef */
 }
 
 int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
 {
-    int i;
-
-    /* 
-     * This does a scsi reset for all devices on the bus.
-     * In principle, we could also reset the 1542 - should
-     * we do this?  Try this first, and we can add that later
-     * if it turns out to be useful.
-     */
-    outb(SCRST, CONTROL(SCpnt->host->io_port));
-
-    /*
-     * Wait for the thing to settle down a bit.  Unfortunately
-     * this is going to basically lock up the machine while we
-     * wait for this to complete.  To be 100% correct, we need to
-     * check for timeout, and if we are doing something like this
-     * we are pretty desperate anyways.
-     */
-    spin_unlock_irq(&io_request_lock);
-    scsi_sleep(4*HZ);
-    spin_lock_irq(&io_request_lock);
-
-    WAIT(STATUS(SCpnt->host->io_port), 
-        STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
-    
-    /*
-     * Now try to pick up the pieces.  For all pending commands,
-     * free any internal data structures, and basically clear things
-     * out.  We do not try and restart any commands or anything - 
-     * the strategy handler takes care of that crap.
-     */
-    printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
-
-    for(i=0; i< AHA1542_MAILBOXES; i++)
-    {
-       if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
-       {
-           Scsi_Cmnd * SCtmp;
-           SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+       int i;
 
-    
-           if( SCtmp->device->soft_reset )
-           {
-               /*
-                * If this device implements the soft reset option,
-                * then it is still holding onto the command, and
-                * may yet complete it.  In this case, we don't
-                * flush the data.
-                */
-               continue;
-           }
+       /* 
+        * This does a scsi reset for all devices on the bus.
+        * In principle, we could also reset the 1542 - should
+        * we do this?  Try this first, and we can add that later
+        * if it turns out to be useful.
+        */
+       outb(SCRST, CONTROL(SCpnt->host->io_port));
 
-           if (SCtmp->host_scribble) 
-           {
-               scsi_free(SCtmp->host_scribble, 512);
-           }
-           
-           HOSTDATA(SCpnt->host)->SCint[i] = NULL;
-           HOSTDATA(SCpnt->host)->mb[i].status = 0;
+       /*
+        * Wait for the thing to settle down a bit.  Unfortunately
+        * this is going to basically lock up the machine while we
+        * wait for this to complete.  To be 100% correct, we need to
+        * check for timeout, and if we are doing something like this
+        * we are pretty desperate anyways.
+        */
+       spin_unlock_irq(&io_request_lock);
+       scsi_sleep(4 * HZ);
+       spin_lock_irq(&io_request_lock);
+
+       WAIT(STATUS(SCpnt->host->io_port),
+            STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+       /*
+        * Now try to pick up the pieces.  For all pending commands,
+        * free any internal data structures, and basically clear things
+        * out.  We do not try and restart any commands or anything - 
+        * the strategy handler takes care of that crap.
+        */
+       printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+       for (i = 0; i < AHA1542_MAILBOXES; i++) {
+               if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) {
+                       Scsi_Cmnd *SCtmp;
+                       SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+
+
+                       if (SCtmp->device->soft_reset) {
+                               /*
+                                * If this device implements the soft reset option,
+                                * then it is still holding onto the command, and
+                                * may yet complete it.  In this case, we don't
+                                * flush the data.
+                                */
+                               continue;
+                       }
+                       if (SCtmp->host_scribble) {
+                               scsi_free(SCtmp->host_scribble, 512);
+                       }
+                       HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+                       HOSTDATA(SCpnt->host)->mb[i].status = 0;
+               }
        }
-    }
 
-    return SUCCESS;
+       return SUCCESS;
 
 fail:
-    return FAILED;
+       return FAILED;
 }
 
 int aha1542_host_reset(Scsi_Cmnd * SCpnt)
 {
-    int i;
-
-    /* 
-     * This does a scsi reset for all devices on the bus.
-     * In principle, we could also reset the 1542 - should
-     * we do this?  Try this first, and we can add that later
-     * if it turns out to be useful.
-     */
-    outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
-
-    /*
-     * Wait for the thing to settle down a bit.  Unfortunately
-     * this is going to basically lock up the machine while we
-     * wait for this to complete.  To be 100% correct, we need to
-     * check for timeout, and if we are doing something like this
-     * we are pretty desperate anyways.
-     */
-    spin_unlock_irq(&io_request_lock);
-    scsi_sleep(4*HZ);
-    spin_lock_irq(&io_request_lock);
-
-    WAIT(STATUS(SCpnt->host->io_port), 
-        STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
-    
-    /*
-     * We need to do this too before the 1542 can interact with
-     * us again.
-     */
-    setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
-    
-    /*
-     * Now try to pick up the pieces.  For all pending commands,
-     * free any internal data structures, and basically clear things
-     * out.  We do not try and restart any commands or anything - 
-     * the strategy handler takes care of that crap.
-     */
-    printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
-    
-    for(i=0; i< AHA1542_MAILBOXES; i++)
-    {
-       if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
-       {
-           Scsi_Cmnd * SCtmp;
-           SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+       int i;
 
-           if( SCtmp->device->soft_reset )
-           {
-               /*
-                * If this device implements the soft reset option,
-                * then it is still holding onto the command, and
-                * may yet complete it.  In this case, we don't
-                * flush the data.
-                */
-               continue;
-           }
+       /* 
+        * This does a scsi reset for all devices on the bus.
+        * In principle, we could also reset the 1542 - should
+        * we do this?  Try this first, and we can add that later
+        * if it turns out to be useful.
+        */
+       outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
 
-           if (SCtmp->host_scribble) 
-           {
-               scsi_free(SCtmp->host_scribble, 512);
-           }
-           
-           HOSTDATA(SCpnt->host)->SCint[i] = NULL;
-           HOSTDATA(SCpnt->host)->mb[i].status = 0;
+       /*
+        * Wait for the thing to settle down a bit.  Unfortunately
+        * this is going to basically lock up the machine while we
+        * wait for this to complete.  To be 100% correct, we need to
+        * check for timeout, and if we are doing something like this
+        * we are pretty desperate anyways.
+        */
+       spin_unlock_irq(&io_request_lock);
+       scsi_sleep(4 * HZ);
+       spin_lock_irq(&io_request_lock);
+
+       WAIT(STATUS(SCpnt->host->io_port),
+            STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+       /*
+        * We need to do this too before the 1542 can interact with
+        * us again.
+        */
+       setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+
+       /*
+        * Now try to pick up the pieces.  For all pending commands,
+        * free any internal data structures, and basically clear things
+        * out.  We do not try and restart any commands or anything - 
+        * the strategy handler takes care of that crap.
+        */
+       printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+       for (i = 0; i < AHA1542_MAILBOXES; i++) {
+               if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) {
+                       Scsi_Cmnd *SCtmp;
+                       SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+
+                       if (SCtmp->device->soft_reset) {
+                               /*
+                                * If this device implements the soft reset option,
+                                * then it is still holding onto the command, and
+                                * may yet complete it.  In this case, we don't
+                                * flush the data.
+                                */
+                               continue;
+                       }
+                       if (SCtmp->host_scribble) {
+                               scsi_free(SCtmp->host_scribble, 512);
+                       }
+                       HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+                       HOSTDATA(SCpnt->host)->mb[i].status = 0;
+               }
        }
-    }
 
-    return SUCCESS;
+       return SUCCESS;
 
 fail:
-    return FAILED;
+       return FAILED;
 }
 
 /*
@@ -1445,68 +1495,68 @@ fail:
 int aha1542_old_abort(Scsi_Cmnd * SCpnt)
 {
 #if 0
-  unchar ahacmd = CMD_START_SCSI;
-  unsigned long flags;
-  struct mailbox * mb;
-  int mbi, mbo, i;
-
-  printk("In aha1542_abort: %x %x\n",
-        inb(STATUS(SCpnt->host->io_port)),
-        inb(INTRFLAGS(SCpnt->host->io_port)));
-
-  save_flags(flags);
-  cli();
-  mb = HOSTDATA(SCpnt->host)->mb;
-  mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1;
-  if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
-  
-  do{
-    if(mb[mbi].status != 0) break;
-    mbi++;
-    if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
-  } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used);
-  restore_flags(flags);
-
-  if(mb[mbi].status) {
-    printk("Lost interrupt discovered on irq %d - attempting to recover\n", 
-          SCpnt->host->irq);
-    aha1542_intr_handle(SCpnt->host->irq, NULL);
-    return 0;
-  }
-
-  /* OK, no lost interrupt.  Try looking to see how many pending commands
-     we think we have. */
-
-  for(i=0; i< AHA1542_MAILBOXES; i++)
-   if(HOSTDATA(SCpnt->host)->SCint[i])
-     {
-       if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
-        printk("Timed out command pending for %s\n",
-               kdevname(SCpnt->request.rq_dev));
-        if (HOSTDATA(SCpnt->host)->mb[i].status) {
-          printk("OGMB still full - restarting\n");
-          aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
-        };
-       } else
-        printk("Other pending command %s\n",
-               kdevname(SCpnt->request.rq_dev));
-     }
+       unchar ahacmd = CMD_START_SCSI;
+       unsigned long flags;
+       struct mailbox *mb;
+       int mbi, mbo, i;
+
+       printk(KERN_DEBUG "In aha1542_abort: %x %x\n",
+              inb(STATUS(SCpnt->host->io_port)),
+              inb(INTRFLAGS(SCpnt->host->io_port)));
+
+       save_flags(flags);
+       cli();
+       mb = HOSTDATA(SCpnt->host)->mb;
+       mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1;
+       if (mbi >= 2 * AHA1542_MAILBOXES)
+               mbi = AHA1542_MAILBOXES;
+
+       do {
+               if (mb[mbi].status != 0)
+                       break;
+               mbi++;
+               if (mbi >= 2 * AHA1542_MAILBOXES)
+                       mbi = AHA1542_MAILBOXES;
+       } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used);
+       restore_flags(flags);
 
+       if (mb[mbi].status) {
+               printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n",
+                      SCpnt->host->irq);
+               aha1542_intr_handle(SCpnt->host->irq, NULL);
+               return 0;
+       }
+       /* OK, no lost interrupt.  Try looking to see how many pending commands
+          we think we have. */
+
+       for (i = 0; i < AHA1542_MAILBOXES; i++)
+               if (HOSTDATA(SCpnt->host)->SCint[i]) {
+                       if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+                               printk(KERN_ERR "Timed out command pending for %s\n",
+                                      kdevname(SCpnt->request.rq_dev));
+                               if (HOSTDATA(SCpnt->host)->mb[i].status) {
+                                       printk(KERN_ERR "OGMB still full - restarting\n");
+                                       aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+                               };
+                       } else
+                               printk(KERN_ERR "Other pending command %s\n",
+                                      kdevname(SCpnt->request.rq_dev));
+               }
 #endif
 
-    DEB(printk("aha1542_abort\n"));
+       DEB(printk("aha1542_abort\n"));
 #if 0
-    save_flags(flags);
-    cli();
-    for(mbo = 0; mbo < AHA1542_MAILBOXES; mbo++)
-      if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]){
-       mb[mbo].status = 2;  /* Abort command */
-       aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */
-       restore_flags(flags);
-       break;
-      };
+       save_flags(flags);
+       cli();
+       for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++)
+               if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) {
+                       mb[mbo].status = 2;     /* Abort command */
+                       aha1542_out(SCpnt->host->io_port, &ahacmd, 1);  /* start scsi command */
+                       restore_flags(flags);
+                       break;
+               };
 #endif
-    return SCSI_ABORT_SNOOZE;
+       return SCSI_ABORT_SNOOZE;
 }
 
 /* We do not implement a reset function here, but the upper level code
@@ -1517,136 +1567,132 @@ int aha1542_old_abort(Scsi_Cmnd * SCpnt)
 
 int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
-    unchar ahacmd = CMD_START_SCSI;
-    int i;
-
-    /*
-     * See if a bus reset was suggested.
-     */
-    if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET )
-      {
-       /* 
-        * This does a scsi reset for all devices on the bus.
-        * In principle, we could also reset the 1542 - should
-        * we do this?  Try this first, and we can add that later
-        * if it turns out to be useful.
-        */
-       outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
+       unchar ahacmd = CMD_START_SCSI;
+       int i;
 
        /*
-        * Wait for the thing to settle down a bit.  Unfortunately
-        * this is going to basically lock up the machine while we
-        * wait for this to complete.  To be 100% correct, we need to
-        * check for timeout, and if we are doing something like this
-        * we are pretty desperate anyways.
+        * See if a bus reset was suggested.
         */
-       WAIT(STATUS(SCpnt->host->io_port), 
-            STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+       if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) {
+               /* 
+                * This does a scsi reset for all devices on the bus.
+                * In principle, we could also reset the 1542 - should
+                * we do this?  Try this first, and we can add that later
+                * if it turns out to be useful.
+                */
+               outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
 
-       /*
-        * We need to do this too before the 1542 can interact with
-        * us again.
-        */
-       setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+               /*
+                * Wait for the thing to settle down a bit.  Unfortunately
+                * this is going to basically lock up the machine while we
+                * wait for this to complete.  To be 100% correct, we need to
+                * check for timeout, and if we are doing something like this
+                * we are pretty desperate anyways.
+                */
+               WAIT(STATUS(SCpnt->host->io_port),
+               STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
 
-       /*
-        * Now try to pick up the pieces.  Restart all commands
-        * that are currently active on the bus, and reset all of
-        * the datastructures.  We have some time to kill while
-        * things settle down, so print a nice message.
-        */
-       printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
-
-       for(i=0; i< AHA1542_MAILBOXES; i++)
-         if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
-           {
-             Scsi_Cmnd * SCtmp;
-             SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
-             SCtmp->result = DID_RESET << 16;
-             if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512);
-             printk("Sending DID_RESET for target %d\n", SCpnt->target);
-             SCtmp->scsi_done(SCpnt);
-             
-             HOSTDATA(SCpnt->host)->SCint[i] = NULL;
-             HOSTDATA(SCpnt->host)->mb[i].status = 0;
-           }
-       /*
-        * Now tell the mid-level code what we did here.  Since
-        * we have restarted all of the outstanding commands,
-        * then report SUCCESS.
-        */
-       return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
+               /*
+                * We need to do this too before the 1542 can interact with
+                * us again.
+                */
+               setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+
+               /*
+                * Now try to pick up the pieces.  Restart all commands
+                * that are currently active on the bus, and reset all of
+                * the datastructures.  We have some time to kill while
+                * things settle down, so print a nice message.
+                */
+               printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+               for (i = 0; i < AHA1542_MAILBOXES; i++)
+                       if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) {
+                               Scsi_Cmnd *SCtmp;
+                               SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+                               SCtmp->result = DID_RESET << 16;
+                               if (SCtmp->host_scribble)
+                                       scsi_free(SCtmp->host_scribble, 512);
+                               printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
+                               SCtmp->scsi_done(SCpnt);
+
+                               HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+                               HOSTDATA(SCpnt->host)->mb[i].status = 0;
+                       }
+               /*
+                * Now tell the mid-level code what we did here.  Since
+                * we have restarted all of the outstanding commands,
+                * then report SUCCESS.
+                */
+               return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
 fail:
-       printk("aha1542.c: Unable to perform hard reset.\n");
-       printk("Power cycle machine to reset\n");
-       return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET);
-
-
-      }
-    else
-      {
-       /* This does a selective reset of just the one device */
-       /* First locate the ccb for this command */
-       for(i=0; i< AHA1542_MAILBOXES; i++)
-         if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt)
-           {
-             HOSTDATA(SCpnt->host)->ccb[i].op = 0x81;  /* BUS DEVICE RESET */
-             /* Now tell the 1542 to flush all pending commands for this target */
-             aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
-             
-             /* Here is the tricky part.  What to do next.  Do we get an interrupt
-                for the commands that we aborted with the specified target, or
-                do we generate this on our own?  Try it without first and see
-                what happens */
-             printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
-             
-             /* If the first does not work, then try the second.  I think the
-                first option is more likely to be correct. Free the command
-                block for all commands running on this target... */
-             for(i=0; i< AHA1542_MAILBOXES; i++)
-               if(HOSTDATA(SCpnt->host)->SCint[i] &&
-                  HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
-                 {
-                   Scsi_Cmnd * SCtmp;
-                   SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
-                   SCtmp->result = DID_RESET << 16;
-                   if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512);
-                   printk("Sending DID_RESET for target %d\n", SCpnt->target);
-                   SCtmp->scsi_done(SCpnt);
-                   
-                   HOSTDATA(SCpnt->host)->SCint[i] = NULL;
-                   HOSTDATA(SCpnt->host)->mb[i].status = 0;
-                 }
-             return SCSI_RESET_SUCCESS;
-           }
-      }
-    /* No active command at this time, so this means that each time we got
-       some kind of response the last time through.  Tell the mid-level code
-       to request sense information in order to decide what to do next. */
-    return SCSI_RESET_PUNT;
+               printk(KERN_CRIT "aha1542.c: Unable to perform hard reset.\n");
+               printk(KERN_CRIT "Power cycle machine to reset\n");
+               return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET);
+
+
+       } else {
+               /* This does a selective reset of just the one device */
+               /* First locate the ccb for this command */
+               for (i = 0; i < AHA1542_MAILBOXES; i++)
+                       if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+                               HOSTDATA(SCpnt->host)->ccb[i].op = 0x81;        /* BUS DEVICE RESET */
+                               /* Now tell the 1542 to flush all pending commands for this target */
+                               aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+                               /* Here is the tricky part.  What to do next.  Do we get an interrupt
+                                  for the commands that we aborted with the specified target, or
+                                  do we generate this on our own?  Try it without first and see
+                                  what happens */
+                               printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+                               /* If the first does not work, then try the second.  I think the
+                                  first option is more likely to be correct. Free the command
+                                  block for all commands running on this target... */
+                               for (i = 0; i < AHA1542_MAILBOXES; i++)
+                                       if (HOSTDATA(SCpnt->host)->SCint[i] &&
+                                           HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) {
+                                               Scsi_Cmnd *SCtmp;
+                                               SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+                                               SCtmp->result = DID_RESET << 16;
+                                               if (SCtmp->host_scribble)
+                                                       scsi_free(SCtmp->host_scribble, 512);
+                                               printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
+                                               SCtmp->scsi_done(SCpnt);
+
+                                               HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+                                               HOSTDATA(SCpnt->host)->mb[i].status = 0;
+                                       }
+                               return SCSI_RESET_SUCCESS;
+                       }
+       }
+       /* No active command at this time, so this means that each time we got
+          some kind of response the last time through.  Tell the mid-level code
+          to request sense information in order to decide what to do next. */
+       return SCSI_RESET_PUNT;
 }
 
 #include "sd.h"
 
-int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int * ip)
+int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
 {
-  int translation_algorithm;
-  int size = disk->capacity;
-
-  translation_algorithm = HOSTDATA(disk->device->host)->bios_translation;
-
-  if((size>>11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) {
-    /* Please verify that this is the same as what DOS returns */
-    ip[0] = 255;
-    ip[1] = 63;
-    ip[2] = size /255/63;
-  } else {
-    ip[0] = 64;
-    ip[1] = 32;
-    ip[2] = size >> 11;
-  }
-
-  return 0;
+       int translation_algorithm;
+       int size = disk->capacity;
+
+       translation_algorithm = HOSTDATA(disk->device->host)->bios_translation;
+
+       if ((size >> 11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) {
+               /* Please verify that this is the same as what DOS returns */
+               ip[0] = 255;
+               ip[1] = 63;
+               ip[2] = size / 255 / 63;
+       } else {
+               ip[0] = 64;
+               ip[1] = 32;
+               ip[2] = size >> 11;
+       }
+
+       return 0;
 }
 
 
@@ -1656,4 +1702,3 @@ Scsi_Host_Template driver_template = AHA1542;
 
 #include "scsi_module.c"
 #endif
-
index 209d88091715ad3aec87953990af76ab930196f9..95141ebd248f4f8be031e042886c84e1a6368238 100644 (file)
@@ -139,6 +139,7 @@ MODULE_AUTHOR ("American Megatrends Inc.");
 MODULE_DESCRIPTION ("AMI MegaRAID driver");
 #endif
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -232,6 +233,8 @@ void WROUTDOOR (mega_host_config * megaCfg, u32 value)
  *
  *================================================================
  */
+static int __init megaraid_setup(char *);
+
 static int megaIssueCmd (mega_host_config * megaCfg,
                         u_char * mboxData,
                         mega_scb * scb,
@@ -268,8 +271,8 @@ static int ser_printk (const char *fmt,...);
 /*  Use "megaraid=skipXX" as LILO option to prohibit driver from scanning
     XX scsi id on each channel.  Used for Madrona motherboard, where SAF_TE
     processor id cannot be scanned */
-static char *megaraid;
 #ifdef MODULE
+static char *megaraid = NULL;
 MODULE_PARM(megaraid, "s");
 #endif
 static int skip_id;
@@ -1509,18 +1512,12 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl)
 {
   int count = 0;
 
-  pHostTmpl->proc_name = "megaraid";
+#ifdef MODULE
+  if (megaraid)
+      megaraid_setup(megaraid);
+#endif
 
-  skip_id = -1;
-  if (megaraid && !strncmp(megaraid,"skip",strlen("skip"))) {
-      if (megaraid[4] != '\0') {
-          skip_id = megaraid[4] - '0';
-          if (megaraid[5] != '\0') {
-              skip_id = (skip_id * 10) + (megaraid[5] - '0');
-          }
-      }
-      skip_id = (skip_id > 15) ? -1 : skip_id;
-  }
+  pHostTmpl->proc_name = "megaraid";
 
   printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
 
@@ -1877,6 +1874,23 @@ int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
   return 0;
 }
 
+static int __init megaraid_setup(char *str)
+{
+  skip_id = -1;
+  if (str && !strncmp(str, "skip", strlen("skip"))) {
+      if (str[4] != '\0') {
+          skip_id = str[4] - '0';
+          if (str[5] != '\0') {
+              skip_id = (skip_id * 10) + (str[5] - '0');
+          }
+      }
+      skip_id = (skip_id > 15) ? -1 : skip_id;
+  }
+  return 1;
+}
+
+__setup("megaraid=", megaraid_setup);
+
 #ifdef MODULE
 Scsi_Host_Template driver_template = MEGARAID;
 
index cc671c0d396847de5220e246d6af7514db9a02a2..fb986e2317fa98a1d3c8b5a77d4ecd34960f6383 100644 (file)
@@ -265,6 +265,7 @@ static struct dev_info device_list[] =
        {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},              /* Locks up if polled for lun != 0  
                                                                 * extra reset */
        {"RELISYS", "Scorpio", "*", BLIST_NOLUN},               /* responds to all LUN */
+       {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},      /* responds to all LUN */
 
 /*
  * Other types of devices that have special flags.
index 1379563f24b3608f64c0246e6fda278522fd1a27..54bf5fd01c87015f2616b35f8b967019ffef70f6 100644 (file)
@@ -189,7 +189,7 @@ typedef u8                  BYTE;
 typedef u16                    USHORT;
 typedef u16                    WORD;
 typedef u32                    DWORD;
-typedef volatile BYTE *                LPDAQD;
+typedef unsigned long          LPDAQD;
 
 /* Generic FIFO */
 typedef struct {
@@ -208,12 +208,12 @@ typedef struct multisound_dev {
        int memid, irqid;
        int irq, irq_ref;
        unsigned char info;
-       volatile BYTE *base;
+       unsigned long base;
 
        /* Motorola 56k DSP SMA */
-       volatile BYTE *SMA;
-       volatile BYTE *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ;
-       volatile WORD *pwDSPQData, *pwMIDQData, *pwMODQData;
+       unsigned long SMA;
+       unsigned long DAPQ, DARQ, MODQ, MIDQ, DSPQ;
+       unsigned long pwDSPQData, pwMIDQData, pwMODQData;
 
        /* State variables */
        enum { msndClassic, msndPinnacle } type;
index 0528acbc506a37822a55e91ff55c69069b684700..c30660b4674c6f0c600a055a223e1d919fa5a5fc 100644 (file)
@@ -104,18 +104,18 @@ static void reset_play_queue(void)
        LPDAQD lpDAQ;
 
        dev.last_playbank = -1;
-       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead);
-       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail);
+       isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead);
+       isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail);
 
        for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
-               writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
-               writew(0, lpDAQ + DAQDS_wSize);
-               writew(1, lpDAQ + DAQDS_wFormat);
-               writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize);
-               writew(dev.play_channels, lpDAQ + DAQDS_wChannels);
-               writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate);
-               writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
-               writew(n, lpDAQ + DAQDS_wFlags);
+               isa_writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
+               isa_writew(0, lpDAQ + DAQDS_wSize);
+               isa_writew(1, lpDAQ + DAQDS_wFormat);
+               isa_writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize);
+               isa_writew(dev.play_channels, lpDAQ + DAQDS_wChannels);
+               isa_writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate);
+               isa_writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
+               isa_writew(n, lpDAQ + DAQDS_wFlags);
        }
 }
 
@@ -126,25 +126,25 @@ static void reset_record_queue(void)
        unsigned long flags;
 
        dev.last_recbank = 2;
-       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead);
-       writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail);
+       isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead);
+       isa_writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail);
 
        /* Critical section: bank 1 access */
        spin_lock_irqsave(&dev.lock, flags);
        outb(HPBLKSEL_1, dev.io + HP_BLKS);
-       memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+       isa_memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
        outb(HPBLKSEL_0, dev.io + HP_BLKS);
        spin_unlock_irqrestore(&dev.lock, flags);
 
        for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
-               writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
-               writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
-               writew(1, lpDAQ + DAQDS_wFormat);
-               writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize);
-               writew(dev.rec_channels, lpDAQ + DAQDS_wChannels);
-               writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate);
-               writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
-               writew(n, lpDAQ + DAQDS_wFlags);
+               isa_writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
+               isa_writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
+               isa_writew(1, lpDAQ + DAQDS_wFormat);
+               isa_writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize);
+               isa_writew(dev.rec_channels, lpDAQ + DAQDS_wChannels);
+               isa_writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate);
+               isa_writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
+               isa_writew(n, lpDAQ + DAQDS_wFlags);
        }
 }
 
@@ -180,9 +180,9 @@ static int dsp_set_format(struct file *file, int val)
 
        for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
                if (file->f_mode & FMODE_WRITE)
-                       writew(data, lpDAQ + DAQDS_wSampleSize);
+                       isa_writew(data, lpDAQ + DAQDS_wSampleSize);
                if (file->f_mode & FMODE_READ)
-                       writew(data, lpDARQ + DAQDS_wSampleSize);
+                       isa_writew(data, lpDARQ + DAQDS_wSampleSize);
        }
        if (file->f_mode & FMODE_WRITE)
                dev.play_sample_size = data;
@@ -312,9 +312,9 @@ static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
                        if (file->f_mode & FMODE_WRITE)
-                               writew(data, lpDAQ + DAQDS_wSampleRate);
+                               isa_writew(data, lpDAQ + DAQDS_wSampleRate);
                        if (file->f_mode & FMODE_READ)
-                               writew(data, lpDARQ + DAQDS_wSampleRate);
+                               isa_writew(data, lpDARQ + DAQDS_wSampleRate);
                }
                if (file->f_mode & FMODE_WRITE)
                        dev.play_sample_rate = data;
@@ -355,9 +355,9 @@ static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                                                        
                for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
                        if (file->f_mode & FMODE_WRITE)
-                               writew(data, lpDAQ + DAQDS_wChannels);
+                               isa_writew(data, lpDAQ + DAQDS_wChannels);
                        if (file->f_mode & FMODE_READ)
-                               writew(data, lpDARQ + DAQDS_wChannels);
+                               isa_writew(data, lpDARQ + DAQDS_wChannels);
                }
                if (file->f_mode & FMODE_WRITE)
                        dev.play_channels = data;
@@ -394,28 +394,28 @@ static int mixer_get(int d)
        }
 }
 
-#define update_volm(a,b)                                       \
-       writew((dev.left_levels[a] >> 1) *                      \
-              readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff,  \
-              dev.SMA + SMA_##b##Left);                        \
-       writew((dev.right_levels[a] >> 1)  *                    \
-              readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \
+#define update_volm(a,b)                                               \
+       isa_writew((dev.left_levels[a] >> 1) *                          \
+              isa_readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff,      \
+              dev.SMA + SMA_##b##Left);                                \
+       isa_writew((dev.right_levels[a] >> 1)  *                        \
+              isa_readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff,     \
               dev.SMA + SMA_##b##Right);
 
-#define update_potm(d,s,ar)                                    \
-       writeb((dev.left_levels[d] >> 8) *                      \
-              readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff,  \
-              dev.SMA + SMA_##s##Left);                        \
-       writeb((dev.right_levels[d] >> 8) *                     \
-              readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \
-              dev.SMA + SMA_##s##Right);                       \
-       if (msnd_send_word(&dev, 0, 0, ar) == 0)                \
+#define update_potm(d,s,ar)                                            \
+       isa_writeb((dev.left_levels[d] >> 8) *                          \
+              isa_readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff,      \
+              dev.SMA + SMA_##s##Left);                                \
+       isa_writeb((dev.right_levels[d] >> 8) *                         \
+              isa_readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff,     \
+              dev.SMA + SMA_##s##Right);                               \
+       if (msnd_send_word(&dev, 0, 0, ar) == 0)                        \
                chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
 
 #define update_pot(d,s,ar)                             \
-       writeb(dev.left_levels[d] >> 8,                 \
+       isa_writeb(dev.left_levels[d] >> 8,             \
               dev.SMA + SMA_##s##Left);                \
-       writeb(dev.right_levels[d] >> 8,                \
+       isa_writeb(dev.right_levels[d] >> 8,            \
               dev.SMA + SMA_##s##Right);               \
        if (msnd_send_word(&dev, 0, 0, ar) == 0)        \
                chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
@@ -444,23 +444,23 @@ static int mixer_set(int d, int value)
                /* master volume unscaled controls */
        case SOUND_MIXER_LINE:                  /* line pot control */
                /* scaled by IMIX in digital mix */
-               writeb(bLeft, dev.SMA + SMA_bInPotPosLeft);
-               writeb(bRight, dev.SMA + SMA_bInPotPosRight);
+               isa_writeb(bLeft, dev.SMA + SMA_bInPotPosLeft);
+               isa_writeb(bRight, dev.SMA + SMA_bInPotPosRight);
                if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
                        chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
                break;
 #ifndef MSND_CLASSIC
        case SOUND_MIXER_MIC:                   /* mic pot control */
                /* scaled by IMIX in digital mix */
-               writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft);
-               writeb(bRight, dev.SMA + SMA_bMicPotPosRight);
+               isa_writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft);
+               isa_writeb(bRight, dev.SMA + SMA_bMicPotPosRight);
                if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
                        chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
                break;
 #endif
        case SOUND_MIXER_VOLUME:                /* master volume */
-               writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft);
-               writew(wRight, dev.SMA + SMA_wCurrMastVolRight);
+               isa_writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft);
+               isa_writew(wRight, dev.SMA + SMA_wCurrMastVolRight);
                /* fall through */
 
        case SOUND_MIXER_LINE1:                 /* aux pot control */
@@ -834,18 +834,18 @@ static __inline__ int pack_DARQ_to_DARF(register int bank)
        LPDAQD DAQD;
 
        /* Increment the tail and check for queue wrap */
-       wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
-       if (wTmp > readw(dev.DARQ + JQS_wSize))
+       wTmp = isa_readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+       if (wTmp > isa_readw(dev.DARQ + JQS_wSize))
                wTmp = 0;
-       while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--)
+       while (wTmp == isa_readw(dev.DARQ + JQS_wHead) && timeout--)
                udelay(1);
-       writew(wTmp, dev.DARQ + JQS_wTail);
+       isa_writew(wTmp, dev.DARQ + JQS_wTail);
 
        /* Get our digital audio queue struct */
        DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF;
 
        /* Get length of data */
-       size = readw(DAQD + DAQDS_wSize);
+       size = isa_readw(DAQD + DAQDS_wSize);
 
        /* Read data from the head (unprotected bank 1 access okay
            since this is only called inside an interrupt) */
@@ -868,8 +868,8 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
        register int protect = start, nbanks = 0;
        LPDAQD DAQD;
 
-       DAPQ_tail = readw(dev.DAPQ + JQS_wTail);
-       while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || start) {
+       DAPQ_tail = isa_readw(dev.DAPQ + JQS_wTail);
+       while (DAPQ_tail != isa_readw(dev.DAPQ + JQS_wHead) || start) {
                register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
                register int n;
                unsigned long flags;
@@ -904,12 +904,12 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
                DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF;
 
                /* Write size of this bank */
-               writew(n, DAQD + DAQDS_wSize);
+               isa_writew(n, DAQD + DAQDS_wSize);
                ++nbanks;
 
                /* Then advance the tail */
                DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
-               writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
+               isa_writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
                
                /* Tell the DSP to play the bank */
                msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
@@ -1110,15 +1110,15 @@ static void intr(int irq, void *dev_id, struct pt_regs *regs)
        inb(dev.io + HP_RXL);
 
        /* Evaluate queued DSP messages */
-       while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) {
+       while (isa_readw(dev.DSPQ + JQS_wTail) != isa_readw(dev.DSPQ + JQS_wHead)) {
                register WORD wTmp;
 
-               eval_dsp_msg(readw(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead)));
+               eval_dsp_msg(isa_readw(dev.pwDSPQData + 2*isa_readw(dev.DSPQ + JQS_wHead)));
 
-               if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize))
-                       writew(0, dev.DSPQ + JQS_wHead);
+               if ((wTmp = isa_readw(dev.DSPQ + JQS_wHead) + 1) > isa_readw(dev.DSPQ + JQS_wSize))
+                       isa_writew(0, dev.DSPQ + JQS_wHead);
                else
-                       writew(wTmp, dev.DSPQ + JQS_wHead);
+                       isa_writew(wTmp, dev.DSPQ + JQS_wHead);
        }
 }
 
@@ -1211,7 +1211,7 @@ static int __init probe_multisound(void)
        }
        printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
 #endif /* MSND_CLASSIC */
-              "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n",
+              "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
               dev.name,
 #ifndef MSND_CLASSIC
               rev, xv,
@@ -1225,12 +1225,12 @@ static int __init probe_multisound(void)
        return 0;
 }
 
-static void msnd_init_queue(volatile BYTE *base, int start, int size)
+static void msnd_init_queue(unsigned long base, int start, int size)
 {
-       writew(PCTODSP_BASED(start), base + JQS_wStart);
-       writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
-       writew(0, base + JQS_wHead);
-       writew(0, base + JQS_wTail);
+       isa_writew(PCTODSP_BASED(start), base + JQS_wStart);
+       isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+       isa_writew(0, base + JQS_wHead);
+       isa_writew(0, base + JQS_wTail);
 }
 
 static int init_sma(void)
@@ -1244,22 +1244,22 @@ static int init_sma(void)
 #endif
        outb(HPBLKSEL_0, dev.io + HP_BLKS);
        if (initted) {
-               mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft);
-               mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight);
+               mastVolLeft = isa_readw(dev.SMA + SMA_wCurrMastVolLeft);
+               mastVolRight = isa_readw(dev.SMA + SMA_wCurrMastVolRight);
        } else
                mastVolLeft = mastVolRight = 0;
-       memset_io(dev.base, 0, 0x8000);
+       isa_memset_io(dev.base, 0, 0x8000);
 
        /* Critical section: bank 1 access */
        spin_lock_irqsave(&dev.lock, flags);
        outb(HPBLKSEL_1, dev.io + HP_BLKS);
-       memset_io(dev.base, 0, 0x8000);
+       isa_memset_io(dev.base, 0, 0x8000);
        outb(HPBLKSEL_0, dev.io + HP_BLKS);
        spin_unlock_irqrestore(&dev.lock, flags);
 
-       dev.pwDSPQData = (volatile WORD *)(dev.base + DSPQ_DATA_BUFF);
-       dev.pwMODQData = (volatile WORD *)(dev.base + MODQ_DATA_BUFF);
-       dev.pwMIDQData = (volatile WORD *)(dev.base + MIDQ_DATA_BUFF);
+       dev.pwDSPQData = (dev.base + DSPQ_DATA_BUFF);
+       dev.pwMODQData = (dev.base + MODQ_DATA_BUFF);
+       dev.pwMIDQData = (dev.base + MIDQ_DATA_BUFF);
 
        /* Motorola 56k shared memory base */
        dev.SMA = dev.base + SMA_STRUCT_START;
@@ -1286,19 +1286,19 @@ static int init_sma(void)
 
        /* Setup some DSP values */
 #ifndef MSND_CLASSIC
-       writew(1, dev.SMA + SMA_wCurrPlayFormat);
-       writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
-       writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels);
-       writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
+       isa_writew(1, dev.SMA + SMA_wCurrPlayFormat);
+       isa_writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
+       isa_writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels);
+       isa_writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
 #endif
-       writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD);
-       writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft);
-       writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);
+       isa_writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD);
+       isa_writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft);
+       isa_writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);
 #ifndef MSND_CLASSIC
-       writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch);
-       writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);
+       isa_writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch);
+       isa_writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);
 #endif
-       writew(0x303, dev.SMA + SMA_wCurrInputTagBits);
+       isa_writew(0x303, dev.SMA + SMA_wCurrInputTagBits);
 
        initted = 1;
 
@@ -1307,12 +1307,12 @@ static int init_sma(void)
 
 static int __init calibrate_adc(WORD srate)
 {
-       writew(srate, dev.SMA + SMA_wCalFreqAtoD);
+       isa_writew(srate, dev.SMA + SMA_wCalFreqAtoD);
        if (dev.calibrate_signal == 0)
-               writew(readw(dev.SMA + SMA_wCurrHostStatusFlags)
+               isa_writew(isa_readw(dev.SMA + SMA_wCurrHostStatusFlags)
                       | 0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
        else
-               writew(readw(dev.SMA + SMA_wCurrHostStatusFlags)
+               isa_writew(isa_readw(dev.SMA + SMA_wCurrHostStatusFlags)
                       & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
        if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
            chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
@@ -1342,7 +1342,7 @@ static int upload_dsp_code(void)
                return -EBUSY;
        }
 #endif
-       memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+       isa_memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
        if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
                printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
                return -ENODEV;
@@ -1395,7 +1395,7 @@ static int initialize(void)
        }
 
        timeout = 200;
-       while (readw(dev.base)) {
+       while (isa_readw(dev.base)) {
                mdelay(1);
                if (!timeout--) {
                        printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n");
@@ -1897,7 +1897,7 @@ int __init msnd_pinnacle_init(void)
        dev.io = io;
        dev.numio = DSP_NUMIO;
        dev.irq = irq;
-       dev.base = phys_to_virt(mem);
+       dev.base = mem;
        dev.fifosize = fifosize * 1024;
        dev.calibrate_signal = calibrate_signal ? 1 : 0;
        dev.recsrc = 0;
index 08c4acfa13a3ed6351130637b57a2ca02973b313..af0c1c9dff16cf4d5a951d8927929717bf17fd9a 100644 (file)
@@ -1,36 +1,41 @@
-/*****************************************************************************
+/*
  *
- *      Trident 4D-Wave OSS driver for Linux 2.2.x
+ *     Trident 4D-Wave/SiS 7018 OSS driver for Linux 2.2.x
  *
  *     Driver: Alan Cox <alan@redhat.com>
  *
  *  Built from:
- *     Low level code: <audio@tridentmicro.com> from ALSA
- *     Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- *     Extended by: Zach Brown <zab@redhat.com>  
+ *     Low level code: <audio@tridentmicro.com> from ALSA
+ *     Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *     Extended by: Zach Brown <zab@redhat.com>  
  *
- *     Hacked up by:
- *       Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *  Hacked up by:
+ *     Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *     Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
  *
  *
- *      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 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.
+ *     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.
+ *     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.
  *
+ *  History
+ *  v0.03 Dec 24 1999 Ollie Lho
+ *     mem leak in prog_dmabuf and dealloc_dmabuf removed
+ *  v0.02 Dec 15 1999 Ollie Lho
+ *     SiS 7018 support added, playback O.K.
+ *  v0.01 Alan Cox et. al.
+ *     Initial Release in kernel 2.3.30, does not work
  */
-
-/*****************************************************************************/
-
       
 #include <linux/config.h>
 #include <linux/module.h>
 
 /* --------------------------------------------------------------------- */
 
-#define M_DEBUG 1
-
-#ifdef M_DEBUG
-static int debug=0;
-#define M_printk(args...) {if (debug) printk(args);}
-#else
-#define M_printk(x)
-#endif
+#undef DEBUG
 
 /* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.01"
+#define DRIVER_VERSION "0.03"
 
 #define TRIDENT_FMT_STEREO     0x01
 #define TRIDENT_FMT_16BIT      0x02
@@ -79,33 +77,53 @@ static int debug=0;
 #define TRIDENT_DAC_SHIFT      0   
 #define TRIDENT_ADC_SHIFT      4
 
-#define TRIDENT_ENABLE_PE      1
-#define TRIDENT_ENABLE_RE      2
+#define TRIDENT_ENABLE_PE              1
+#define TRIDENT_ENABLE_RE              2
+#define DAC_RUNNING            1
+#define ADC_RUNNING            2
 
 
-#define TRIDENT_CARD_MAGIC     0x5072696E
-#define TRIDENT_STATE_MAGIC    0x63657373
+#define TRIDENT_CARD_MAGIC     0x5072696E /* "Prin" */
+#define TRIDENT_STATE_MAGIC    0x63657373 /* "cess" */
 
-#define DAC_RUNNING            1
-#define ADC_RUNNING            2
 
 #define NR_DSPS                8
 
-#define SND_DEV_DSP16   
+#define SND_DEV_DSP16  5 
 
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
 
-enum card_types_t {
-       TYPE_4DWAVE_DX,
-       TYPE_4DWAVE_NX
+struct pci_audio_info {
+       u16 vendor;
+       u16 device;
+       char *name;
 };
 
-static const char *card_names[]={
-       [TYPE_4DWAVE_DX] = "Trident 4DWave DX",
-       [TYPE_4DWAVE_NX] = "Trident 4DWave NX",
+static struct pci_audio_info pci_audio_devices[] = {
+       {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, "Trident 4DWave DX"},
+       {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, "Trident 4DWave NX"},
+       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"}
 };
 
+static struct {
+       unsigned int id;
+       char *name;
+} snd_ac97_codec_ids[] = {
+       {0x414B4D00, "Asahi Kasei AK4540"    },
+       {0x41445340, "Analog Devices AD1881" },
+       {0x43525900, "Cirrus Logic CS4297"   },
+       {0x43525913, "Cirrus Logic CS4297A"  },
+       {0x43525931, "Cirrus Logic CS4299"   },
+       {0x4e534331, "National Semiconductor LM4549"},
+       {0x83847600, "SigmaTel STAC????"     },
+       {0x83847604, "SigmaTel STAC9701/3/4/5"},
+       {0x83847605, "SigmaTel STAC9704"      },
+       {0x83847608, "SigmaTel STAC9708"      },
+       {0x83847609, "SigmaTel STAC9721/23"   },
+       {0x00000000, NULL}
+};
 
 typedef struct tChannelControl
 {
@@ -149,7 +167,7 @@ struct trident_state {
                unsigned fragshift;
                int chan[2];    /* Hardware channel */
                /* XXX zab - swptr only in here so that it can be referenced by
-                       clear_advance, as far as I can tell :( */
+                  clear_advance, as far as I can tell :( */
                unsigned hwptr, swptr;
                unsigned total_bytes;
                int count;
@@ -172,7 +190,31 @@ struct trident_state {
        u8 bDMAStart;
 
 };
-       
+
+struct trident_pcm_bank {
+       /* registers to control bank operations */
+       u32 start;
+       u32 stop;
+       u32 aint;
+       u32 aint_en;
+       /* each bank has 32 channels */
+       u32 bitmap; /* channel allocation bitmap */
+       //struct trident_channel channels[32];
+};
+
+struct trident_mixer {
+       int modcnt;
+       int supported_mixers;
+       int stereo_mixers;
+       int record_sources;
+       /* the caller must guarantee arg sanity before calling these */
+       /* int (*read_mixer)(struct trident_card *card, int index);*/
+       void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left,
+                           unsigned int right);
+       int (*recmask_io)(struct trident_card *card,int rw,int mask);
+       unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
 struct trident_card {
        unsigned int magic;
 
@@ -180,23 +222,23 @@ struct trident_card {
        struct trident_card *next;
 
        /* The trident has a certain amount of cross channel interaction
-          so we use a single per card lock */
-          
+          so we use a single per card lock */     
        spinlock_t lock;
 
-       int dev_mixer;
-
-       int card_type;
+       struct pci_audio_info *pci_info;
+       struct pci_dev * pci_dev;
+       u16 pci_id;
 
        /* as most of this is static,
-               perhaps it should be a pointer to a global struct */
+          perhaps it should be a pointer to a global struct */
+       int dev_mixer;
        struct mixer_goo {
                int modcnt;
                int supported_mixers;
                int stereo_mixers;
                int record_sources;
                /* the caller must guarantee arg sanity before calling these */
-/*             int (*read_mixer)(struct trident_card *card, int index);*/
+               /* int (*read_mixer)(struct trident_card *card, int index);*/
                void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left,unsigned int right);
                int (*recmask_io)(struct trident_card *card,int rw,int mask);
                unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
@@ -208,41 +250,12 @@ struct trident_card {
        unsigned long iobase;
        u32 irq;
 
-       u32 ChanMap[2];
-       int ChanPCMcnt;
-       int ChanPCM;
+       u32 bitmap[2];
        CHANNELCONTROL ChRegs;
        int ChanDwordCount;
 };
 
-static struct timer_list debug_timer;
-
-#define IWriteAinten( x ) \
-        {int i; \
-         for( i= 0; i < ChanDwordCount; i++) \
-               outl((x)->lpChAinten[i], TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define IReadAinten( x ) \
-        {int i; \
-         for( i= 0; i < ChanDwordCount; i++) \
-         (x)->lpChAinten[i] = inl(TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define ReadAint( x ) \
-        IReadAint( x ) 
-
-#define WriteAint( x ) \
-        IWriteAint( x ) 
-
-#define IWriteAint( x ) \
-        {int i; \
-         for( i= 0; i < ChanDwordCount; i++) \
-         outl((x)->lpChAint[i], TRID_REG(trident, (x)->lpAChAint[i]));}
-
-#define IReadAint( x ) \
-        {int i; \
-         for( i= 0; i < ChanDwordCount; i++) \
-         (x)->lpChAint[i] = inl(TRID_REG(trident, (x)->lpAChAint[i]));}
-
+static struct trident_card *devs = NULL;
 
 /*
  *     Trident support library routines
@@ -252,12 +265,12 @@ static struct timer_list debug_timer;
    void ResetAinten( struct trident_state *trident, int ChannelNum)
   
    Description: This routine will disable interrupts and ack any 
-                existing interrupts for specified channel.
+               existing interrupts for specified channel.
   
-   Parameters:  trident - pointer to target device class for 4DWave.
-                ChannelNum - channel number 
+   Parameters: trident - pointer to target device class for 4DWave.
+               ChannelNum - channel number 
   
-   returns:     TRUE if everything went ok, else FALSE.
+   returns:    TRUE if everything went ok, else FALSE.
   
   ---------------------------------------------------------------------------*/
 
@@ -279,105 +292,171 @@ static void ResetAinten(struct trident_card * trident, int ChannelNum)
    void EnableEndInterrupts( struct trident_card *trident)
   
    Description: This routine will enable end of loop interrupts.
-                End of loop interrupts will occur when a running
-                channel reaches ESO.
+               End of loop interrupts will occur when a running
+               channel reaches ESO.
   
-   Parameters:  trident - pointer to target device class for 4DWave.
+   Parameters: trident - pointer to target device class for 4DWave.
   
-   returns:     TRUE if everything went ok, else FALSE.
+   returns:    TRUE if everything went ok, else FALSE.
   
   ---------------------------------------------------------------------------*/
 
-static int EnableEndInterrupts(struct trident_card * trident)
+static int trident_enable_end_interrupts(struct trident_card * trident)
 {
-       unsigned int GlobalControl;
+       u32 GlobalControl;
+
+       GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+
+       switch (trident->pci_id)
+       {
+       case PCI_DEVICE_ID_SI_7018:
+               GlobalControl |= (ENDLP_IE | BANK_B_EN);
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+               GlobalControl |= ENDLP_IE;
+               break;
+       default:
+               return FALSE;
+       }
 
-       GlobalControl = inb(TRID_REG(trident, T4D_LFO_GC_CIR + 1));
-       GlobalControl |= 0x10;
-       outb(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR + 1));
+       outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
 
-       M_printk("(trident) globctl=%02X\n", GlobalControl);
-       M_printk("(trident) enabled end interrupts\n");
+#ifdef DEBUG
+       printk("trident: Enable End Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
        return (TRUE);
 }
 
+static int trident_enable_middle_interrupts(struct trident_card * trident)
+{
+       u32 GlobalControl;
+
+       GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+
+       switch (trident->pci_id)
+       {
+       case PCI_DEVICE_ID_SI_7018:
+               GlobalControl |= (MIDLP_IE | BANK_B_EN);
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+       default:
+               GlobalControl |= MIDLP_IE;
+               break;
+       }
+
+       outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+       printk("trident: Enable Middle Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
+       return (TRUE);
+}
 /*---------------------------------------------------------------------------
-e   void DisableEndInterrupts( struct trident_card *trident)
+   void DisableEndInterrupts( struct trident_card *trident)
   
    Description: This routine will disable end of loop interrupts.
-                End of loop interrupts will occur when a running
-                channel reaches ESO.
+               End of loop interrupts will occur when a running
+               channel reaches ESO.
   
-   Parameters:  
-                trident - pointer to target device class for 4DWave.
+   Parameters: 
+               trident - pointer to target device class for 4DWave.
   
-   returns:     TRUE if everything went ok, else FALSE.
+   returns:    TRUE if everything went ok, else FALSE.
   
   ---------------------------------------------------------------------------*/
 
-static int DisableEndInterrupts(struct trident_card * trident)
+static int trident_disable_end_interrupts(struct trident_card * trident)
 {
-       unsigned int GlobalControl;
+       u32 GlobalControl;
 
-       GlobalControl = inb(TRID_REG(trident, T4D_LFO_GC_CIR + 1));
-       GlobalControl &= ~0x10;
-       outb(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR + 1));
+       GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+       GlobalControl &= ~ENDLP_IE;
+       outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
 
-       M_printk("(trident) disabled end interrupts\n");
-       M_printk("(trident) globctl=%02X\n", GlobalControl);
+#ifdef DEBUG
+       printk("trident: Disabled End Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
        return (TRUE);
 }
 
+static int trident_disable_middle_interrupts(struct trident_card * trident)
+{
+       u32 GlobalControl;
+
+       GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+       GlobalControl &= ~MIDLP_IE;
+       outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+       printk("trident: Disabled Middle Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
+       return (TRUE);
+}
 /*---------------------------------------------------------------------------
    void trident_enable_voice_irq( unsigned int HwChannel )
   
     Description: Enable an interrupt channel, any channel 0 thru n.
-                 This routine automatically handles the fact that there are
-                 more than 32 channels available.
+                This routine automatically handles the fact that there are
+                more than 32 channels available.
   
     Parameters : HwChannel - Channel number 0 thru n.
-                 trident - pointer to target device class for 4DWave.
+                trident - pointer to target device class for 4DWave.
   
     Return Value: None.
   
   ---------------------------------------------------------------------------*/
-void trident_enable_voice_irq(struct trident_card * trident, unsigned int HwChannel)
+void trident_enable_voice_irq(struct trident_card * trident, unsigned int channel)
 {
-       unsigned int x, Data, ChanDwordCount;
+       unsigned int bank, mask, ChanDwordCount;
+       u32 reg;
+
+       bank = channel >> 5;
+       mask = 1 << (channel & 0x1f);
 
-       x = HwChannel >> 5;
-       Data = 1 << (HwChannel & 0x1f);
        ChanDwordCount = trident->ChanDwordCount;
+
        IReadAinten(&trident->ChRegs);
-       trident->ChRegs.lpChAinten[x] |= Data;
+       trident->ChRegs.lpChAinten[bank] |= mask;
        IWriteAinten(&trident->ChRegs);
-       M_printk("(trident) enabled voice IRQ %d\n", HwChannel);
+
+#ifdef DEBUG
+       reg = inl(TRID_REG(trident, T4D_AINTEN_B));
+       printk("trident: enabled IRQ on channel %d\n", channel);
+#endif
 }
 
 /*---------------------------------------------------------------------------
    void trident_disable_voice_irq( unsigned int HwChannel )
   
     Description: Disable an interrupt channel, any channel 0 thru n.
-                 This routine automatically handles the fact that there are
-                 more than 32 channels available.
+                This routine automatically handles the fact that there are
+                more than 32 channels available.
   
     Parameters : HwChannel - Channel number 0 thru n.
-                 trident - pointer to target device class for 4DWave.
+                trident - pointer to target device class for 4DWave.
   
     Return Value: None.
   
   ---------------------------------------------------------------------------*/
-void trident_disable_voice_irq(struct trident_card * trident, unsigned int HwChannel)
+void trident_disable_voice_irq(struct trident_card * trident, unsigned int channel)
 {
-       unsigned int x, Data, ChanDwordCount;
+       unsigned int bank, mask, ChanDwordCount;
+       u32 reg;
+
+       bank = channel >> 5;
+       mask = 1 << (channel & 0x1f);
 
-       x = HwChannel >> 5;
-       Data = 1 << (HwChannel & 0x1f);
        ChanDwordCount = trident->ChanDwordCount;
        IReadAinten(&trident->ChRegs);
-       trident->ChRegs.lpChAinten[x] &= ~Data;
+       trident->ChRegs.lpChAinten[bank] &= ~mask;
        IWriteAinten(&trident->ChRegs);
-       M_printk("(trident) disabled voice IRQ %d\n", HwChannel);
+
+#ifdef DEBUG
+       reg = inl(TRID_REG(trident, T4D_AINTEN_B));
+       printk("trident: disabled IRQ on channel %d\n", channel);
+#endif
 }
 
 /*---------------------------------------------------------------------------
@@ -391,29 +470,38 @@ void trident_disable_voice_irq(struct trident_card * trident, unsigned int HwCha
   
   ---------------------------------------------------------------------------*/
 
-static int AllocateChannelPCM(struct trident_card *trident)
+static int trident_alloc_pcm_channel(struct trident_card *trident)
 {
        int idx;
 
-       if (trident->ChanPCMcnt >= trident->ChanPCM)
-       {
-               M_printk(KERN_DEBUG "(trident) no channels available.\n");
+       if (trident->bitmap[BANK_B] == ~0UL) {
+               /* not more free channels avaliable */
+               printk(KERN_ERR "trident: no more channels available on Bank B.\n");
                return -1;
        }
        for (idx = 31; idx >= 0; idx--) {
-               if (!(trident->ChanMap[1] & (1 << idx))) {
-                       trident->ChanMap[1] |= 1 << idx;
-                       trident->ChanPCMcnt++;
+               if (!(trident->bitmap[BANK_B] & (1 << idx))) {
+                       trident->bitmap[BANK_B] |= 1 << idx;
                        return idx + 32;
                }
        }
+
+#ifdef ABUSE_BANK_A
+       /* channels in Bank A should be reserved for synthesizer 
+          not for normal use (channels in Bank A can't record) */
+       if (trident->bitmap[BANK_A] == ~0UL) {
+               /* not more free channels avaliable */
+               printk(KERN_ERR "trident: no channels available on Bank A.\n");
+               return -1;
+       }
        for (idx = 31; idx >= 0; idx--) {
-               if (!(trident->ChanMap[0] & (1 << idx))) {
-                       trident->ChanMap[0] |= 1 << idx;
-                       trident->ChanPCMcnt++;
+               if (!(trident->bitmap[BANK_A] & (1 << idx))) {
+                       trident->bitmap[BANK_A] |= 1 << idx;
                        return idx;
                }
        }
+#endif
+
        return -1;
 }
 
@@ -423,19 +511,29 @@ static int AllocateChannelPCM(struct trident_card *trident)
     Description: Free hardware channel.
   
     Parameters :  trident - pointer to target device class for 4DWave.
-                 channel - hardware channel number 0-63
+                  channel - hardware channel number 0-63
   
     Return Value: none
   
   ---------------------------------------------------------------------------*/
 
-static void FreeChannelPCM(struct trident_card *trident, int channel)
+static void trident_free_pcm_channel(struct trident_card *trident, int channel)
 {
+       int bank;
+
+#ifdef ABUSE_BANK_A
        if (channel < 0 || channel > 63)
                return;
-       if (trident->ChanMap[channel>>5] & (1 << (channel & 0x1f))) {
-               trident->ChanMap[channel>>5] &= ~(1 << (channel & 0x1f));
-               trident->ChanPCMcnt--;
+#else
+       if (channel < 31 || channel > 63)
+               return;
+#endif
+
+       bank = channel >> 5;
+       channel = channel & 0x1f;
+
+       if (trident->bitmap[bank] & (1 << (channel))) {
+               trident->bitmap[bank] &= ~(1 << (channel));
        }
 }
 
@@ -443,113 +541,127 @@ static void FreeChannelPCM(struct trident_card *trident, int channel)
    void trident_start_voice( ULONG HwChannel )
   
     Description: Start a channel, any channel 0 thru n.
-                 This routine automatically handles the fact that there are
-                 more than 32 channels available.
+                This routine automatically handles the fact that there are
+                more than 32 channels available.
   
     Parameters : HwChannel - Channel number 0 thru n.
-                 trident - pointer to target device class for 4DWave.
+                trident - pointer to target device class for 4DWave.
   
     Return Value: None.
   
   ---------------------------------------------------------------------------*/
-void trident_start_voice(struct trident_card * trident, unsigned int HwChannel)
+void trident_start_voice(struct trident_card * trident, unsigned int channel)
 {
-       unsigned int x = HwChannel >> 5;
-       unsigned int Data = 1 << (HwChannel & 0x1f);
+       unsigned int bank = channel >> 5;
+       unsigned int mask = 1 << (channel & 0x1f);
 
-       outl(Data, TRID_REG(trident, trident->ChRegs.lpAChStart[x]));
-       M_printk("(trident) start voice %d\n", HwChannel);
+       outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStart[bank]));
+#ifdef DEBUG
+       printk("trident: start voice on channel %d\n", channel);
+#endif
 }
 
 /*---------------------------------------------------------------------------
    void trident_stop_voice( ULONG HwChannel )
   
     Description: Stop a channel, any channel 0 thru n.
-                 This routine automatically handles the fact that there are
-                 more than 32 channels available.
+                This routine automatically handles the fact that there are
+                more than 32 channels available.
   
     Parameters : HwChannel - Channel number 0 thru n.
-                 trident - pointer to target device class for 4DWave.
+                trident - pointer to target device class for 4DWave.
   
     Return Value: None.
   
   ---------------------------------------------------------------------------*/
-void trident_stop_voice(struct trident_card * trident, unsigned int HwChannel)
+void trident_stop_voice(struct trident_card * trident, unsigned int channel)
 {
-       unsigned int x = HwChannel >> 5;
-       unsigned int Data = 1 << (HwChannel & 0x1f);
+       unsigned int bank = channel >> 5;
+       unsigned int mask = 1 << (channel & 0x1f);
 
-       outl(Data, TRID_REG(trident, trident->ChRegs.lpAChStop[x]));
-  M_printk("(trident) stop voice %d\n", HwChannel);
+       outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStop[bank]));
+#ifdef DEBUG
+       printk("trident: stop voice on channel %d\n", channel);
+#endif
 }
 
 /*---------------------------------------------------------------------------
    int DidChannelInterrupt( )
   
-   Description:  Check if interrupt channel occurred.
+   Description:         Check if interrupt channel occurred.
   
-   Parameters :  trident - pointer to target device class for 4DWave.
+   Parameters :         trident - pointer to target device class for 4DWave.
   
    Return Value: TRUE if interrupt occurred, else FALSE.
   
   ---------------------------------------------------------------------------*/
-static int DidChannelInterrupt(struct trident_card * trident, int channel)
+static int trident_check_channel_interrupt(struct trident_card * trident, int channel)
 {
-       unsigned int ChanDwordCount = trident->ChanDwordCount;
-       unsigned int x = channel >> 5;
-       unsigned int dwMask = 1 << (channel & 0x1f);
+       unsigned int ChanDwordCount = NUM_BANKS;
+       unsigned int bank = channel >> 5;
+       unsigned int mask = 1 << (channel & 0x1f);
 
        ReadAint(&trident->ChRegs);
-       return (trident->ChRegs.lpChAint[x] & dwMask) ? TRUE : FALSE;
+
+#ifdef DEBUG
+       if (trident->ChRegs.lpChAint[bank] & mask)
+               printk("trident: channel %d has interrupt\n", channel);
+#endif 
+       return (trident->ChRegs.lpChAint[bank] & mask) ? TRUE : FALSE;
 }
 
 /*---------------------------------------------------------------------------
    void AckChannelInterrupt( )
   
-   Description:  Acknowledge the interrupt bit for channel intrs.
+   Description:         Acknowledge the interrupt bit for channel intrs.
   
-   Parameters :  trident - pointer to target device class for 4DWave.
+   Parameters :         trident - pointer to target device class for 4DWave.
   
    Return Value: None
   
   ---------------------------------------------------------------------------*/
-static void AckChannelInterrupt(struct trident_card * trident, int channel)
+static void trident_ack_channel_interrupt(struct trident_card * trident, int channel)
 {
-       unsigned int ChanDwordCount = trident->ChanDwordCount;
-       unsigned int x = channel >> 5;
-       unsigned int dwMask = 1 << (channel & 0x1f);
+       unsigned int ChanDwordCount = NUM_BANKS;
+       unsigned int bank = channel >> 5;
+       unsigned int mask = 1 << (channel & 0x1f);
 
        ReadAint(&trident->ChRegs);
-       trident->ChRegs.lpChAint[x] &= dwMask;
+       trident->ChRegs.lpChAint[bank] &= mask;
        IWriteAint(&trident->ChRegs);
 }
 
 /*---------------------------------------------------------------------------
-   int LoadDeltaHw( unsigned int HwChannel, unsigned int Delta )
+   int trident_load_hw_delta( unsigned int HwChannel, unsigned int Delta )
   
    Description: This routine writes Delta to the hardware.
   
-   Parameters:  Delta - data to write (2 Bytes only)
-                HwChannel - Hardware channel to write to.
-               trident - pointer to target device class for 4DWave.
+   Parameters: Delta - data to write (2 Bytes only)
+               HwChannel - Hardware channel to write to.
+               trident - pointer to target device class for 4DWave.
   
-   Returns:     TRUE if all goes well, else FALSE. 
+   Returns:    TRUE if all goes well, else FALSE. 
   
   ---------------------------------------------------------------------------*/
-static int LoadDeltaHw(struct trident_card * trident, unsigned int HwChannel, unsigned int Delta)
+static int trident_load_hw_delta (struct trident_card * trident, unsigned int channel,
+                                 unsigned short delta)
 {
+       /* select a channel for output */
+       outb(channel, TRID_REG(trident, T4D_LFO_GC_CIR));
 
-       outb(HwChannel, TRID_REG(trident, T4D_LFO_GC_CIR));
-
-       if (trident->card_type != TYPE_4DWAVE_NX) {
-               outw((unsigned short) Delta, TRID_REG(trident, CH_DX_ESO_DELTA));
-       } 
-       else                    // ID_4DWAVE_NX
+       switch (trident->pci_id)
        {
-               outb((unsigned char) Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
-               outb((unsigned char) (Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3));
+       case PCI_DEVICE_ID_SI_7018:
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+               outw((u16) delta, TRID_REG(trident, CH_DX_ESO_DELTA));
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+               outb(delta       & 0xff, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
+               outb((delta >> 8)& 0xff, TRID_REG(trident, CH_NX_DELTA_ESO + 3));
+               break;
+       default:
+               return FALSE;
        }
-
        return TRUE;
 }
 
@@ -558,11 +670,11 @@ static int LoadDeltaHw(struct trident_card * trident, unsigned int HwChannel, un
   
    Description: This routine writes all required channel registers to hardware.
   
-   Parameters:  *Data - a pointer to the data to write (5 ULONGS always).
-                HwChannel - Hardware channel to write to.
-               trident - pointer to target device class for 4DWave.
+   Parameters: *Data - a pointer to the data to write (5 ULONGS always).
+               HwChannel - Hardware channel to write to.
+               trident - pointer to target device class for 4DWave.
   
-   Returns:     TRUE if all goes well, else FALSE. 
+   Returns:    TRUE if all goes well, else FALSE. 
   
   ---------------------------------------------------------------------------*/
 static int LoadVirtualChannel(struct trident_card * trident, unsigned int *Data, unsigned int HwChannel)
@@ -579,8 +691,9 @@ static int LoadVirtualChannel(struct trident_card * trident, unsigned int *Data,
 
        for (i = 0; i < ULONGSToDo; i++, Address += 4)
                outl(ChanData[i], TRID_REG(trident, Address));
-
-       M_printk("(trident) load virtual channel %d\n", HwChannel);
+#ifdef DEBUG
+       printk("(trident) load virtual channel %d\n", HwChannel);
+#endif
        return TRUE;
 }
 
@@ -588,13 +701,13 @@ static int LoadVirtualChannel(struct trident_card * trident, unsigned int *Data,
    trident_write_voice_regs
   
    Description: This routine will write the 5 hardware channel registers
-                to hardware.
+               to hardware.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
-                Channel - Real or Virtual channel number.
-                Each register field.
+   Paramters:  trident - pointer to target device class for 4DWave.
+               Channel - Real or Virtual channel number.
+               Each register field.
   
-   Returns:     TRUE if all goes well, else FALSE. 
+   Returns:    TRUE if all goes well, else FALSE. 
   
   ---------------------------------------------------------------------------*/
 int trident_write_voice_regs(struct trident_card * trident,
@@ -622,17 +735,19 @@ int trident_write_voice_regs(struct trident_card * trident,
 
        FmcRvolCvol = FMC_RVOL_CVOL & 0x0000ffff;
 
-       if (trident->card_type != TYPE_4DWAVE_NX) 
+       switch (trident->pci_id)
        {
+       case PCI_DEVICE_ID_SI_7018:
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
                ChanData[0] = (CSO << 16) | (ALPHA_FMS & 0x0000ffff);
-               ChanData[2] = (ESO << 16) | (DELTA & 0x0ffff);
+               ChanData[2] = (ESO << 16) | (DELTA & 0x0000ffff);
                ChanData[3] = FmcRvolCvol;
-       }
-       else                    // ID_4DWAVE_NX
-       {
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
                ChanData[0] = (DELTA << 24) | (CSO & 0x00ffffff);
                ChanData[2] = ((DELTA << 16) & 0xff000000) | (ESO & 0x00ffffff);
                ChanData[3] = (ALPHA_FMS << 16) | FmcRvolCvol;
+               break;
        }
 
        LoadVirtualChannel(trident, ChanData, Channel);
@@ -663,19 +778,18 @@ static int compute_rate(u32 rate)
   
    Description: This routine will set the sample rate for playback.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
-                rate    - desired sample rate
-                set     - actually write hardware if set is true.
+   Paramters:  trident - pointer to target device class for 4DWave.
+               rate    - desired sample rate
+               set     - actually write hardware if set is true.
   
-   Returns:     The rate allowed by device.
+   Returns:    The rate allowed by device.
   
   ---------------------------------------------------------------------------*/
 
 static unsigned int trident_set_dac_rate(struct trident_state * trident,
-                                            unsigned int rate, int set)
+                                        unsigned int rate, int set)
 {
-       unsigned int delta;
-
+       u16 delta;
 
        if (rate > 48000)
                rate = 48000;
@@ -683,25 +797,16 @@ static unsigned int trident_set_dac_rate(struct trident_state * trident,
                rate = 4000;
 
        delta = compute_rate(rate);
+       trident->ratedac = rate;
 
-       if(set)
-       {
-               //Select channel window
-               outb(trident->dma_dac.chan[1], TRID_REG(trident->card, T4D_LFO_GC_CIR));
-
-               if (trident->card->card_type != TYPE_4DWAVE_NX) 
-                       outw(delta,TRID_REG(trident->card,CH_DX_ESO_DELTA+2));
-               else                    // ID_4DWAVE_NX
-               {
-                       outb( delta     & 0xff,TRID_REG(trident->card,CH_NX_DELTA_CSO));
-                       outb((delta>>8) & 0xff,TRID_REG(trident->card,CH_NX_DELTA_ESO));
-               }
-       }
-        
-       M_printk("(trident) called trident_set_dac_rate : rate = %d, set = %d delta = %4x\n", 
-                       rate, set,delta);
+       if (set)
+               trident_load_hw_delta(trident->card, trident->dma_dac.chan[1],
+                                     delta);
+#ifdef DEBUG    
+       printk("trident: called trident_set_dac_rate : rate = %d, "
+              "set = %d, delta = 0x%04x\n", rate, set, delta);
+#endif
 
-       trident->ratedac = rate;
        return rate;
 }
 
@@ -710,29 +815,36 @@ static unsigned int trident_set_dac_rate(struct trident_state * trident,
   
    Description: This routine will set the sample rate for capture.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
-                rate    - desired sample rate
-                set     - actually write hardware if set is true.
+   Paramters:  trident - pointer to target device class for 4DWave.
+               rate    - desired sample rate
+               set     - actually write hardware if set is true.
   
-   Returns:     The rate allowed by device.
+   Returns:    The rate allowed by device.
   
   ---------------------------------------------------------------------------*/
 
 static unsigned int trident_set_adc_rate(struct trident_state * trident,
-                                            unsigned int rate,
-                                            int set)
+                                        unsigned int rate, int set)
 {
-       //snd_printk("trid: called trident_set_adc_rate\n");
+       u16 delta;
+
        if (rate > 48000)
                rate = 48000;
        if (rate < 4000)
                rate = 4000;
 
-       trident->rateadc = rate;
-       /*
-        *      FIXME: hit the hardware
-        */
+       delta = compute_rate(rate);
+       trident->ratedac = rate;
 
+#if 0 /* It seems that 4D-Wave can not use wave tables channels for recording */
+       if (set)
+               trident_load_hw_delta(trident->card, trident->dma_dac.chan[0],
+                                     delta);
+#endif
+#ifdef DEBUG    
+       printk("trident: called trident_set_adc_rate : rate = %d, "
+              "set = %d, delta = 0x%04x\n", rate, set, delta);
+#endif
        return rate;
 }
  
@@ -761,94 +873,87 @@ extern __inline__ unsigned ld2(unsigned int x)
        return r;
 }
 
-
-/* --------------------------------------------------------------------- */
-
-static struct trident_card *devs = NULL;
-
-/* --------------------------------------------------------------------- */
-
-
-/*
- *     Trident AC97 codec programming interface.
- */
-        
+/* Write AC97 mixer registers */
 static void trident_ac97_set(struct trident_card *trident, u8 cmd, u16 val)
 {
-       unsigned int    address, data;
-       unsigned short  count  = 0xffff;
+       unsigned int    address, mask, busy;
+       unsigned short  count  = 0xffff;
+       u32 data;
 
-       data = ((unsigned long)val) << 16;
+       data = ((u32) val) << 16;
 
-       if (trident->card_type != TYPE_4DWAVE_NX)
+       switch (trident->pci_id)
        {
+       default:
+       case PCI_DEVICE_ID_SI_7018:
+               address = SI_AC97_WRITE;
+               mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
+               busy = SI_AC97_BUSY_WRITE;
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
                address = DX_ACR0_AC97_W;
-               /* read AC-97 write register status */
-               do
-               {
-                       if ((inw(TRID_REG(trident,address))&0x8000) == 0)
-                       break;
-               }
-               while(count--);
-
-               data |= (0x8000 | (cmd & 0x000000ff));
-       }
-       else  // ID_4DWAVE_NX
-       {
+               mask = busy = DX_AC97_BUSY_WRITE;
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
                address = NX_ACR1_AC97_W;
-               /* read AC-97 write register status */
-               do
-               {
-                       if ((inw(TRID_REG(trident, address )) & 0x0800) == 0)
-                               break;
-               }
-               while (count--);
-               data |= (0x0800 | (cmd & 0x000000ff));
+               mask = busy = NX_AC97_BUSY_WRITE;
+               break;
        }
-       if (count == 0) 
-       {
+
+       do {
+               if ((inw(TRID_REG(trident, address)) & busy) == 0)
+                       break;
+       } while (count--);
+       
+       data |= (mask | (cmd & AC97_REG_ADDR));
+
+       if (count == 0) {
                printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
                return;
        }
-
        outl(data, TRID_REG(trident, address));
 }
 
+/* Read AC97 codec registers */
 static u16 trident_ac97_get(struct trident_card *trident, u8 cmd)
 {
-       unsigned int data = 0;
+       unsigned int address, mask, busy;
        unsigned short count = 0xffff;
+       u32 data;
 
-       if (trident->card_type != TYPE_4DWAVE_NX)
-       {
-               data = (0x00008000L | (cmd & 0x000000ff));
-               outl(data, TRID_REG(trident, DX_ACR1_AC97_R));
-               do
-               {
-                       data = inl(TRID_REG(trident, DX_ACR1_AC97_R));
-                       if ( ( data & 0x0008000 ) == 0 )
-                               break;
-               }
-               while(count--);
-       }
-       else  // ID_4DWAVE_NX
-       {
-               data = (0x00000800L | (cmd & 0x000000ff));
-               outl(data, TRID_REG(trident, NX_ACR2_AC97_R_PRIMARY));
-               do
-               {
-                       data = inl(TRID_REG(trident, NX_ACR2_AC97_R_PRIMARY));
-                       if ( ( data & 0x00000C00 ) == 0 )
-                               break;
-               }
-               while(count--);
-       }
-       if ( count == 0 ) 
+       switch (trident->pci_id)
        {
-               printk("trident: AC97 CODEC read timed out.\n");
+       default:
+       case PCI_DEVICE_ID_SI_7018:
+               address = SI_AC97_READ;
+               mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
+               busy = SI_AC97_BUSY_READ;
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+               address = DX_ACR1_AC97_R;
+               mask = busy = DX_AC97_BUSY_READ;
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+               address = NX_ACR2_AC97_R_PRIMARY;
+               mask = NX_AC97_BUSY_READ;
+               busy = 0x0c00;
+               break;
+       }
+
+       data = (mask | (cmd & AC97_REG_ADDR));
+       outl(data, TRID_REG(trident, address));
+
+       do {
+               data = inl(TRID_REG(trident, address));
+               if ((data & busy) == 0)
+                       break;
+       } while (count--);
+
+       if (count == 0) {
+               printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
                data = 0;
        }
-       return ((unsigned short)(data >> 16));
+       return ((u16) (data >> 16));
 }
 
 /* OSS interface to the ac97s.. */
@@ -876,7 +981,7 @@ static struct mixer_defaults {
        int mixer;
        unsigned int value;
 } mixer_defaults[SOUND_MIXER_NRDEVICES] = {
-               /* all values 0 -> 100 in bytes */
+       /* all values 0 -> 100 in bytes */
        {SOUND_MIXER_VOLUME,    0x3232},
        {SOUND_MIXER_BASS,      0x3232},
        {SOUND_MIXER_TREBLE,    0x3232},
@@ -895,35 +1000,35 @@ static struct ac97_mixer_hw {
        unsigned char offset;
        int scale;
 } ac97_hw[SOUND_MIXER_NRDEVICES]= {
-       [SOUND_MIXER_VOLUME]    =       {0x02,63},
-       [SOUND_MIXER_BASS]      =       {0x08,15},
-       [SOUND_MIXER_TREBLE]    =       {0x08,15},
-       [SOUND_MIXER_SPEAKER]   =       {0x0a,15},
-       [SOUND_MIXER_MIC]       =       {0x0e,31},
-       [SOUND_MIXER_LINE]      =       {0x10,31},
-       [SOUND_MIXER_CD]        =       {0x12,31},
-       [SOUND_MIXER_VIDEO]     =       {0x14,31},
-       [SOUND_MIXER_LINE1]     =       {0x16,31},
-       [SOUND_MIXER_PCM]       =       {0x18,31},
-       [SOUND_MIXER_IGAIN]     =       {0x1c,31}
+       [SOUND_MIXER_VOLUME]    =       {AC97_MASTER_VOL_STEREO,63},
+       [SOUND_MIXER_BASS]      =       {AC97_MASTER_TONE,      15},
+       [SOUND_MIXER_TREBLE]    =       {AC97_MASTER_TONE,      15},
+       [SOUND_MIXER_SPEAKER]   =       {AC97_PCBEEP_VOL,       15},
+       [SOUND_MIXER_MIC]       =       {AC97_MIC_VOL,          31},
+       [SOUND_MIXER_LINE]      =       {AC97_LINEIN_VOL,       31},
+       [SOUND_MIXER_CD]        =       {AC97_CD_VOL,           31},
+       [SOUND_MIXER_VIDEO]     =       {AC97_VIDEO_VOL,        31},
+       [SOUND_MIXER_LINE1]     =       {AC97_AUX_VOL,          31},
+       [SOUND_MIXER_PCM]       =       {AC97_PCMOUT_VOL,       31},
+       [SOUND_MIXER_IGAIN]     =       {AC97_RECORD_GAIN,      31}
 };
 
 #if 0 /* *shrug* removed simply because we never used it.
-               feel free to implement again if needed */
+        feel free to implement again if needed */
 
 /* reads the given OSS mixer from the ac97
-       the caller must have insured that the ac97 knows
-       about that given mixer, and should be holding a
-       spinlock for the card */
+   the caller must have insured that the ac97 knows
+   about that given mixer, and should be holding a
+   spinlock for the card */
 static int ac97_read_mixer(struct trident_card *card, int mixer) 
 {
        u16 val;
-       int ret=0;
+       int ret = 0;
        struct ac97_mixer_hw *mh = &ac97_hw[mixer];
 
        val = trident_ac97_get(card , mh->offset);
 
-       if(AC97_STEREO_MASK & (1<<mixer)) {
+       if (AC97_STEREO_MASK & (1<<mixer)) {
                /* nice stereo mixers .. */
                int left,right;
 
@@ -944,33 +1049,39 @@ static int ac97_read_mixer(struct trident_card *card, int mixer)
        } else if (mixer == SOUND_MIXER_MIC) {
                ret = 100 - (((val & 0x1f) * 100) / mh->scale);
        /*  the low bit is optional in the tone sliders and masking
-               it lets is avoid the 0xf 'bypass'.. */
+           it lets us avoid the 0xf 'bypass'.. */
        } else if (mixer == SOUND_MIXER_BASS) {
                ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
        } else if (mixer == SOUND_MIXER_TREBLE) {
                ret = 100 - (((val & 0xe) * 100) / mh->scale);
        }
 
-       printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret);
+#ifdef DEBUG
+       printk("trident: read OSS mixer %2d (ac97 register 0x%02x), "
+              "0x%04x -> 0x%04x\n", mixer, mh->offset, val, ret);
+#endif
 
        return ret;
 }
 #endif
 
 /* write the OSS encoded volume to the given OSS encoded mixer,
-       again caller's job to make sure all is well in arg land,
-       call with spinlock held */
-static void ac97_write_mixer(struct trident_card *card, int mixer, unsigned int left, unsigned int right)
+   again caller's job to make sure all is well in arg land,
+   call with spinlock held */
+static void ac97_write_mixer(struct trident_card *card, int mixer, 
+                            unsigned int left, unsigned int right)
 {
-       u16 val=0;
+       u16 val = 0;
        struct ac97_mixer_hw *mh = &ac97_hw[mixer];
 
-       printk("(trident) wrote ac97 mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right);
+#ifdef DEBUG
+       printk("trident: wrote OSS mixer %2d (ac97 register 0x%02x), "
+              "left vol:%2d, right vol:%2d:",
+              mixer, mh->offset, left, right);
+#endif
 
-       if(AC97_STEREO_MASK & (1<<mixer)) {
+       if (AC97_STEREO_MASK & (1 << mixer)) {
                /* stereo mixers */
-
-
                if (mixer == SOUND_MIXER_IGAIN) {
                        right = (right * mh->scale) / 100;
                        left = (left * mh->scale) / 100;
@@ -980,25 +1091,31 @@ static void ac97_write_mixer(struct trident_card *card, int mixer, unsigned int
                }
 
                val = (left << 8) | right;
-
        } else if (mixer == SOUND_MIXER_SPEAKER) {
                val = (((100 - left) * mh->scale) / 100) << 1;
        } else if (mixer == SOUND_MIXER_MIC) {
                val = trident_ac97_get(card , mh->offset) & ~0x801f;
                val |= (((100 - left) * mh->scale) / 100);
-       /*  the low bit is optional in the tone sliders and masking
-               it lets us avoid the 0xf 'bypass'.. */
+               /*  the low bit is optional in the tone sliders and masking
+                   it lets us avoid the 0xf 'bypass'.. */
        } else if (mixer == SOUND_MIXER_BASS) {
                val = trident_ac97_get(card , mh->offset) & ~0x0f00;
                val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
-       } else if (mixer == SOUND_MIXER_TREBLE)  {
+       } else if (mixer == SOUND_MIXER_TREBLE)  {
                val = trident_ac97_get(card , mh->offset) & ~0x000f;
                val |= (((100 - left) * mh->scale) / 100) & 0x000e;
        }
 
+#ifdef DEBUG
+       printk(" 0x%04x", val);
+#endif
+
        trident_ac97_set(card, mh->offset, val);
-       
-       printk(" -> %x\n",val);
+
+#ifdef DEBUG
+       val = trident_ac97_get(card, mh->offset);
+       printk(" -> 0x%04x\n", val);
+#endif
 }
 
 /* the following tables allow us to go from 
@@ -1011,8 +1128,8 @@ enum ac97_recsettings {
        AC97_REC_AUX,
        AC97_REC_LINE,
        AC97_REC_STEREO, /* combination of all enabled outputs..  */
-       AC97_REC_MONO,        /*.. or the mono equivalent */
-       AC97_REC_PHONE        
+       AC97_REC_MONO,        /*.. or the mono equivalent */
+       AC97_REC_PHONE        
 };
 
 static unsigned int ac97_rm2oss[] = {
@@ -1035,12 +1152,11 @@ static unsigned int ac97_oss_rm[] = {
 };
        
 /* read or write the recmask 
-       the ac97 can really have left and right recording
-       inputs independantly set, but OSS doesn't seem to 
-       want us to express that to the user. 
-       the caller guarantees that we have a supported bit set,
-       and they must be holding the card's spinlock */
-       
+   the ac97 can really have left and right recording
+   inputs independantly set, but OSS doesn't seem to 
+   want us to express that to the user. 
+   the caller guarantees that we have a supported bit set,
+   and they must be holding the card's spinlock */
 static int ac97_recmask_io(struct trident_card *card, int rw, int mask) 
 {
        unsigned int val;
@@ -1052,125 +1168,91 @@ static int ac97_recmask_io(struct trident_card *card, int rw, int mask)
        }
 
        /* else, write the first set in the mask as the
-               output */       
+          output */    
 
        val = ffs(mask); 
        val = ac97_oss_rm[val-1];
        val |= val << 8;  /* set both channels */
-
-       printk("trident: setting ac97 recmask to 0x%x\n",val);
-
-       trident_ac97_set(card,0x1a,val);
+#ifdef DEBUG
+       printk("trident: setting ac97 recmask to 0x%x\n", val);
+#endif
+       trident_ac97_set(card, 0x1a, val);
 
        return 0;
 };
 
-/*
- *     Generic AC97 codec initialisation. Need to check there are no
- *     quirks for the Trident cards.
- */
+/* AC97 codec initialisation. */
 static u16 trident_ac97_init(struct trident_card *trident)
 {
-       trident->mix.supported_mixers = AC97_SUPPORTED_MASK;
-       trident->mix.stereo_mixers = AC97_STEREO_MASK;
-       trident->mix.record_sources = AC97_RECORD_MASK;
-/*     trident->mix.read_mixer = ac97_read_mixer;*/
-       trident->mix.write_mixer = ac97_write_mixer;
-       trident->mix.recmask_io = ac97_recmask_io;
+       u16 id1, id2;
+       char *ac97_name = NULL;
+       int i;
 
-       if(trident->card_type == TYPE_4DWAVE_NX)
+       /* initialize controller side of AC link */
+       switch (trident->pci_id)
        {
-               unsigned short VendorID1, VendorID2;
-
+       case PCI_DEVICE_ID_SI_7018:
+               /* disable AC97 GPIO interrupt */
+               outl(0x00, TRID_REG(trident, SI_AC97_GPIO));
+               /* stop AC97 cold reset process */
+               outl(0x00014000, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+               /* playback on */
+               outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+               /* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
                outl(0x02, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
+               break;
+       }
 
-               // 4 Speaker Codec initialization
-               VendorID1 = trident_ac97_get(trident, AC97_VENDOR_ID1);
-               VendorID2 = trident_ac97_get(trident, AC97_VENDOR_ID2);
-
-               if( (VendorID1 == 0x8384) && (VendorID2 == 0x7608) )
-               {
-                       // Sigmatel 9708.
-            
-                       unsigned short TestReg;
-                       unsigned int DTemp;
-
-                       trident_ac97_set(trident, AC97_SIGMATEL_CIC1, 0xABBAL);  
-                       trident_ac97_set(trident, AC97_SIGMATEL_CIC2, 0x1000L);
-
-                       TestReg = trident_ac97_get(trident, AC97_SIGMATEL_BIAS2);
-
-                       if( TestReg != 0x8000 ) // Errata Notice.
-                       {
-                               trident_ac97_set(trident, AC97_SIGMATEL_BIAS1, 0xABBAL );
-                               trident_ac97_set(trident, AC97_SIGMATEL_BIAS2, 0x0007L );
-                       }
-                       else // Newer version
-                       {
-                               trident_ac97_set(trident, AC97_SIGMATEL_CIC2, 0x1001L );  // recommended
-                               trident_ac97_set(trident, AC97_SIGMATEL_DAC2INVERT, 0x0008L );
-                       }
-
-                       trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
-                       trident_ac97_set( trident, AC97_HEADPHONE_VOL,   0x8000L );
-
-                       DTemp = (unsigned int)trident_ac97_get( trident, AC97_GENERAL_PURPOSE );
-                       trident_ac97_set( trident, AC97_GENERAL_PURPOSE, DTemp & 0x0000FDFFL );  // bit9 = 0.
-
-                       DTemp = (unsigned int)trident_ac97_get( trident, AC97_MIC_VOL );
-                       trident_ac97_set( trident, AC97_MIC_VOL, DTemp | 0x00008000L );  // bit15 = 1.
+       /* get some information about our AC97 codec */
+       id1 = trident_ac97_get(trident, AC97_VENDOR_ID1);
+       id2 = trident_ac97_get(trident, AC97_VENDOR_ID2);
+       for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
+               if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+                       ac97_name = snd_ac97_codec_ids[i].name;
+                       break;
+               }
+       }
+       if (ac97_name == NULL)
+               ac97_name = "Unknown";
+       printk(KERN_INFO "trident: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
+              id1, id2, ac97_name);
 
-                       DTemp = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
-                       outl(DTemp | 0x0010, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
+       /* initialize volume level */
+       trident_ac97_set(trident, AC97_RESET, 0L);
+       trident_ac97_set(trident, AC97_MASTER_VOL_STEREO, 0L);
+       trident_ac97_set(trident, AC97_PCMOUT_VOL, 0L);
 
-               }
-               else if((VendorID1 == 0x5452) && (VendorID2 == 0x4108) )
-               {   // TriTech TR28028
-                       trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
-                       trident_ac97_set( trident, AC97_EXTENDED_STATUS, 0x0000L );
-               }
-               else if((VendorID1 == 0x574D) && 
-                       (VendorID2 >= 0x4C00) && (VendorID2 <= 0x4C0f))
-               {   // Wolfson WM9704
-                       trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
-               }
-               else
-               {
-#if 0
-                       printk("trident: No four Speaker Support with on board CODEC\n") ;
-#endif
-               }
+       /* set appropriate masks and function pointers */
+       trident->mix.supported_mixers = AC97_SUPPORTED_MASK;
+       trident->mix.stereo_mixers = AC97_STEREO_MASK;
+       trident->mix.record_sources = AC97_RECORD_MASK;
+       /* FIXME: trident->mix.read_mixer = ac97_read_mixer; */
+       trident->mix.write_mixer = ac97_write_mixer;
+       trident->mix.recmask_io = ac97_recmask_io;
 
-               // S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled
-               outl(0x200004, TRID_REG(trident, NX_SPCSTATUS));
-               // Enable S/PDIF out, 48khz only from ac97 fifo
-               outb(0x28, TRID_REG(trident, NX_SPCTRL_SPCSO+3));
-       }
-        else
-        {
-               outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));
-        }
        return 0;
 }
 
-
 /* this only fixes the output apu mode to be later set by start_dac and
-       company.  output apu modes are set in trident_rec_setup */
+   company.  output apu modes are set in trident_rec_setup */
 static void set_fmt(struct trident_state *s, unsigned char mask, unsigned char data)
 {
        s->fmt = (s->fmt & mask) | data;
        /* Set the chip ? */
 }
 
-
-/*
- *     Native play back driver 
- */
-
 /* the mode passed should be already shifted and masked */
+/* trident_play_setup: initialize channel for play back, mode specify the format of samples to
+   be played. 
+   default values: 
+*/
 
-static void trident_play_setup(struct trident_state *trident, int mode, u32 rate, void *buffer, int size)
+static void trident_play_setup(struct trident_state *trident, int mode, u32 rate,
+                              void *buffer, int size)
 {
        unsigned int LBA;
        unsigned int Delta;
@@ -1182,38 +1264,28 @@ static void trident_play_setup(struct trident_state *trident, int mode, u32 rate
        unsigned int VOL;
        unsigned int EC;
 
-
-
-       /* set Loop Back Address */
+       /* set Loop Begin Address */
        LBA = virt_to_bus(buffer);
-
        Delta = compute_rate(rate);
 
-       M_printk("(trident) rate, delta = %d %d\n", rate, Delta);
-
        /* set ESO */
        ESO = size;
        if (mode & TRIDENT_FMT_16BIT)
                ESO /= 2;
        if (mode & TRIDENT_FMT_STEREO)
                ESO /= 2;
-
        ESO = ESO - 1;
-       //snd_printk("trid: ESO = %d\n", ESO);
 
-       /* set ctrl mode
-          CTRL default: 8-bit (unsigned) mono, loop mode enabled
-        */
        CTRL = 0x00000001;
-       if (mode & TRIDENT_FMT_16BIT)
-       {
+       if (mode & TRIDENT_FMT_16BIT) {
                CTRL |= 0x00000008;     // 16-bit data
                CTRL |= 0x00000002;     // signed data
        }
-       if (mode&TRIDENT_FMT_STEREO)
+       if (mode & TRIDENT_FMT_STEREO)
                CTRL |= 0x00000004;     // stereo data
-
-       //FMC_RVOL_CVOL = 0x0000c000;
+       
+       /* FIXME: some difference between 4D and 7018 in FMC_RVOL_CVOL */
+       /* right vol: mute, ledt vol: mute */
        FMC_RVOL_CVOL = 0x0000ffff;
        GVSEL = 1;
        PAN = 0;
@@ -1221,25 +1293,25 @@ static void trident_play_setup(struct trident_state *trident, int mode, u32 rate
        EC = 0;
 
        trident_write_voice_regs(trident->card,
-                            trident->dma_dac.chan[1],
-                            LBA,
-                            0, /* cso */
-                            ESO,
-                            Delta,
-                            0, /* alpha */
-                            FMC_RVOL_CVOL,
-                            GVSEL,
-                            PAN,
-                            VOL,
-                            CTRL,
-                            EC);
+                                trident->dma_dac.chan[1],
+                                LBA,
+                                0,     /* cso */
+                                ESO,
+                                Delta,
+                                0,     /* alpha */
+                                FMC_RVOL_CVOL,
+                                GVSEL,
+                                PAN,
+                                VOL,
+                                CTRL,
+                                EC);
 
 }
 
 /*
  *     Native record driver 
  */
-
+/* FIXME: Not exammed yet */
 /* again, passed mode is alrady shifted/masked */
 
 static void trident_rec_setup(struct trident_state *trident, int mode, u32 rate, void *buffer, int size)
@@ -1260,16 +1332,24 @@ static void trident_rec_setup(struct trident_state *trident, int mode, u32 rate,
        unsigned int dwChanFlags;
        struct trident_card *card = trident->card;
 
+#ifdef DEBUG
+       printk("trident: trident_rec_setup called\n");
+#endif
+
        // Enable AC-97 ADC (capture), disable capture interrupt
-       if (trident->card->card_type != TYPE_4DWAVE_NX
+       switch (card->pci_id
        {
+       case PCI_DEVICE_ID_SI_7018:
+               /* for 7018, the ac97 is always in playback/record (duplex) mode */
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
                bValue = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
                outb(bValue | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
-       }
-       else 
-       {
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
                wValue = inw(TRID_REG(card, T4D_MISCINT));
                outw(wValue | 0x1000, TRID_REG(card, T4D_MISCINT));
+               break;
        }
 
        // Initilize the channel and set channel Mode
@@ -1367,35 +1447,42 @@ static void trident_rec_setup(struct trident_state *trident, int mode, u32 rate,
 
 }
 
-/* Playback pointer */
+/* get current playback pointer */
 __inline__ unsigned int get_dmaa(struct trident_state *trident)
 {
-       unsigned int cso;
-       unsigned int eso;
-
+       u32 cso;
+       u32 eso;
 #if 0
+       /* FIXME: does this mean that FULL duplex is not supported ? */
        if (!(trident->enable & ADC_RUNNING))
                return 0;
 #endif
-
        outb(trident->dma_dac.chan[1], TRID_REG(trident->card, T4D_LFO_GC_CIR));
 
-       if (trident->card->card_type != TYPE_4DWAVE_NX
+       switch (trident->card->pci_id
        {
+       case PCI_DEVICE_ID_SI_7018:
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+               /* 16 bits ESO, CSO for 7018 and DX */
                cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
                eso = inw(TRID_REG(trident->card, CH_DX_ESO_DELTA + 2));
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+               /* 24 bits ESO, CSO for NX */
+               cso =  inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+               eso =  inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff;
+               break;
+       default:
+               return 0;
        }
-       else                    // ID_4DWAVE_NX
-       {
-               cso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
-               eso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff;
-       }
-       M_printk("(trident) get_dmaa: chip reported %d.%d\n", cso, eso);
-       cso++;
 
+#ifdef DEBUG
+       printk("trident: get_dmaa: chip reported esc = %d, cso = %d\n", cso, eso);
+#endif
+       cso++;
+       /* ESO and CSO are in units of Samples, convert to byte offset */
        if (cso > eso)
                cso = eso;
-
        if (trident->fmt & TRIDENT_FMT_16BIT)
                cso *= 2;
        if (trident->fmt & TRIDENT_FMT_STEREO)
@@ -1403,26 +1490,36 @@ __inline__ unsigned int get_dmaa(struct trident_state *trident)
        return cso;
 }
 
-/* Record pointer */
+/* get current recording pointer */
 extern __inline__ unsigned get_dmac(struct trident_state *trident)
 {
-       unsigned int cso;
-
+       u32 cso;
+#if 0
+       /* FIXME: does this mean that FULL duplex is not supported ? */
        if (!(trident->enable&DAC_RUNNING))
                return 0;
-
+#endif
        outb(trident->dma_adc.chan[0], TRID_REG(trident->card, T4D_LFO_GC_CIR));
 
-       if (trident->card->card_type != TYPE_4DWAVE_NX) {
+       switch (trident->card->pci_id) 
+       {
+       default:
+       case PCI_DEVICE_ID_SI_7018:
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+               /* 16 bits ESO, CSO for 7018 and DX */
                cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
-       } else {                // ID_4DWAVE_NX 
-               cso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+               break;
+       case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+               /* 24 bits ESO, CSO for NX */
+               cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+               break;
        }
 
-       printk("(trident) get_dmac: chip reported %d\n", cso);
-       
+#ifdef DEBUG
+       printk("(trident) get_dmac: chip reported cso = %d\n", cso);
+#endif
        cso++;
-
+       /* ESO and CSO are in units of Samples, convert to byte offset */
        if (trident->fmt & TRIDENT_FMT_16BIT)
                cso *= 2;
        if (trident->fmt & TRIDENT_FMT_STEREO)
@@ -1430,24 +1527,13 @@ extern __inline__ unsigned get_dmac(struct trident_state *trident)
        return cso;
 }
 
-static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-static void trident_kick(unsigned long plop)
-{
-       trident_interrupt(5, (void *)plop, NULL);
-       debug_timer.expires=jiffies+1;
-       add_timer(&debug_timer);
-}
-
 /* Stop recording (lock held) */
-
 extern inline void __stop_adc(struct trident_state *s)
 {
        struct trident_card *trident = s->card;
-
-       M_printk("(trident) stopping ADC\n");
-       
-
+#ifdef DEBUG
+       printk("(trident) stopping ADC\n");
+#endif
        s->enable &= ~ADC_RUNNING;
        trident_disable_voice_irq(trident, s->dma_adc.chan[0]);
        outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));
@@ -1471,9 +1557,9 @@ extern inline void stop_adc(struct trident_state *s)
 extern inline void __stop_dac(struct trident_state *s)
 {
        struct trident_card *trident = s->card;
-
-       M_printk("(trident) stopping DAC\n");
-       
+#ifdef DEBUG
+       printk("(trident) stopping DAC\n");
+#endif 
        //trident_stop_voice(trident, s->dma_dac.chan[0]);
        //trident_disable_voice_irq(trident, s->dma_dac.chan[0]);
        trident_stop_voice(trident, s->dma_dac.chan[1]);
@@ -1503,8 +1589,9 @@ static void start_dac(struct trident_state *s)
                trident_enable_voice_irq(trident, s->dma_dac.chan[1]);
                trident_start_voice(trident, s->dma_dac.chan[1]);
                //trident_start_voice(trident, s->dma_dac.chan[0]);
-               M_printk("(trident) starting DAC\n");
-       
+#ifdef DEBUG
+               printk("(trident) starting DAC\n");
+#endif
        }
        spin_unlock_irqrestore(&s->card->lock, flags);
 }      
@@ -1520,25 +1607,65 @@ static void start_adc(struct trident_state *s)
                trident_enable_voice_irq(s->card, s->dma_adc.chan[0]);
                outb(s->bDMAStart, TRID_REG(s->card, T4D_SBCTRL_SBE2R_SBDD));
                trident_start_voice(s->card, s->dma_adc.chan[0]);
-               M_printk("(trident) starting ADC\n");
-       
+#ifdef DEBUG
+               printk("(trident) starting ADC\n");
+#endif 
        }
        spin_unlock_irqrestore(&s->card->lock, flags);
 }      
 
-/* --------------------------------------------------------------------- */
-
-/* we allocate both buffers at once */
 #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
 #define DMABUF_MINORDER 2
 
+/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
+static int alloc_dmabuf(struct trident_state *state, unsigned rec)
+{
+       void *rawbuf;
+       int order;
+       unsigned long map, mapend;
+
+       /* alloc as big a chunk as we can, FIXME: is this necessary ?? */
+       for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+               if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+                       break;
+       if (!rawbuf)
+               return -ENOMEM;
+
+       /* for 4DWave and 7018, there are only 30 (31) siginifcan bits for Loop Begin Address
+          (LBA) which limits the address space to 1 (2) GB, bad T^2 design */
+       if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~0x3fffffff) {
+               printk(KERN_ERR "trident: DMA buffer beyond 1 GB; "
+                      "bus address = 0x%lx, size = %ld\n",
+                      virt_to_bus(rawbuf), PAGE_SIZE << order);
+               free_pages((unsigned long)rawbuf, order);
+               return -ENOMEM;
+       }
+
+       if (rec) {
+               state->dma_adc.ready = state->dma_adc.mapped = 0;
+               state->dma_adc.rawbuf = rawbuf;
+               state->dma_adc.buforder = order;
+       }
+       else {
+               state->dma_dac.ready = state->dma_dac.mapped = 0;
+               state->dma_dac.rawbuf = rawbuf;
+               state->dma_dac.buforder = order;
+       }
+
+       /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+       mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
+       for (map = MAP_NR(rawbuf); map <= mapend; map++)
+               set_bit(PG_reserved, &mem_map[map].flags);
+
+       return 0;
+}
+
+/* free DMA buffer */
 static void dealloc_dmabuf(struct dmabuf *db)
 {
        unsigned long map, mapend;
 
-       if (db->rawbuf) 
-       {
-               M_printk("(trident) freeing %p\n",db->rawbuf);
+       if (db->rawbuf) {
                /* undo marking the pages as reserved */
                mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
                for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
@@ -1549,72 +1676,37 @@ static void dealloc_dmabuf(struct dmabuf *db)
        db->mapped = db->ready = 0;
 }
 
-static int prog_dmabuf(struct trident_state *s, unsigned rec)
+static int prog_dmabuf(struct trident_state *state, unsigned rec)
 {
-       struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
-       unsigned rate = rec ? s->rateadc : s->ratedac;
-       int order;
+       struct dmabuf *db = rec ? &state->dma_adc : &state->dma_dac;
+       unsigned rate = rec ? state->rateadc : state->ratedac;
        unsigned bytepersec;
        unsigned bufs;
-       unsigned long map, mapend;
        unsigned char fmt;
        unsigned long flags;
+       int ret;
 
-       spin_lock_irqsave(&s->card->lock, flags);
-       fmt = s->fmt;
+       spin_lock_irqsave(&state->card->lock, flags);
+       fmt = state->fmt;
        if (rec) {
-               s->enable &= ~TRIDENT_ENABLE_RE;
+               state->enable &= ~TRIDENT_ENABLE_RE;
                fmt >>= TRIDENT_ADC_SHIFT;
        } else {
-               s->enable &= ~TRIDENT_ENABLE_PE;
+               state->enable &= ~TRIDENT_ENABLE_PE;
                fmt >>= TRIDENT_DAC_SHIFT;
        }
-       spin_unlock_irqrestore(&s->card->lock, flags);
-       fmt &= TRIDENT_FMT_MASK;
+       spin_unlock_irqrestore(&state->card->lock, flags);
 
-       db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
-       if (!db->rawbuf) {
-               void *rawbuf;
-               /* haha, this thing is hacked to hell and back.
-                       this is so ugly. */
-               s->dma_dac.ready = s->dma_dac.mapped = 0;
-               s->dma_adc.ready = s->dma_adc.mapped = 0;
-
-               /* alloc as big a chunk as we can */
-               for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-                       if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
-
-                               break;
-
-               if (!rawbuf)
-                       return -ENOMEM;
-
-
-               /* we allocated both buffers */
-               s->dma_adc.rawbuf = rawbuf;
-               s->dma_dac.rawbuf = rawbuf + ( PAGE_SIZE << (order - 1) );
-
-               M_printk("(trident) allocated %ld bytes at %p\n",PAGE_SIZE<<order, db->rawbuf);
-
-               s->dma_adc.buforder = s->dma_dac.buforder = order - 1;
+       fmt &= TRIDENT_FMT_MASK;
 
-               /* XXX these checks are silly now */
-#if 0
-               if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << order) - 1)) & ~0xffff)
-                       printk(KERN_DEBUG "trident: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 
-                              virt_to_bus(db->rawbuf), PAGE_SIZE << order);
+       db->hwptr = db->swptr = db->total_bytes = 0;
+       db->count = db->error = db->endcleared  = 0;
 
-#endif
-               if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << order) - 1) & ~0xffffff)
-                       M_printk(KERN_DEBUG "(trident) DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
-                              virt_to_bus(db->rawbuf), PAGE_SIZE << order);
+       /* allocate DMA buffer if not allocated yet */
+       if (!db->rawbuf)
+               if ((ret = alloc_dmabuf(state, rec)))
+                       return ret;
 
-               /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
-               mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << order) - 1);
-               for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
-                       set_bit(PG_reserved, &mem_map[map].flags);
-       }
        bytepersec = rate << sample_shift[fmt];
        bufs = PAGE_SIZE << db->buforder;
        if (db->ossfragshift) {
@@ -1623,13 +1715,8 @@ static int prog_dmabuf(struct trident_state *s, unsigned rec)
                else
                        db->fragshift = db->ossfragshift;
        } else {
-       /*      lets hand out reasonable big ass buffers by default */
+               /* lets hand out reasonable big ass buffers by default */
                db->fragshift = (db->buforder + PAGE_SHIFT -2);
-#if 0
-               db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-               if (db->fragshift < 3)
-                       db->fragshift = 3; 
-#endif
        }
        db->numfrag = bufs >> db->fragshift;
        while (db->numfrag < 4 && db->fragshift > 3) {
@@ -1644,22 +1731,23 @@ static int prog_dmabuf(struct trident_state *s, unsigned rec)
 
        memset(db->rawbuf, (fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, db->dmasize);
 
-       spin_lock_irqsave(&s->card->lock, flags);
+       spin_lock_irqsave(&state->card->lock, flags);
        if (rec) {
-               trident_rec_setup(s, fmt, s->rateadc, 
-                       db->rawbuf, db->numfrag << db->fragshift);
+               trident_rec_setup(state, fmt, state->rateadc, 
+                                 db->rawbuf, db->numfrag << db->fragshift);
        } else {
-               trident_play_setup(s, fmt, s->ratedac, 
-                       db->rawbuf, db->numfrag << db->fragshift);
+               trident_play_setup(state, fmt, state->ratedac, 
+                                  db->rawbuf, db->numfrag << db->fragshift);
        }
-       spin_unlock_irqrestore(&s->card->lock, flags);
+       spin_unlock_irqrestore(&state->card->lock, flags);
+
+       /* set the ready flag for the dma buffer */
        db->ready = 1;
 
        return 0;
 }
 
 /* only called by trident_write */
-
 extern __inline__ void clear_advance(struct trident_state *s)
 {
        unsigned char c = ((s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_16BIT) ? 0 : 0x80;
@@ -1701,13 +1789,16 @@ static void trident_update_ptr(struct trident_state *s)
                        }
                }
        }
+
        /* update DAC pointer */
        if (s->dma_dac.ready) 
        {
                /* this is so gross.  */
                hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize; 
                diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-               M_printk("(trident) updating dac: hwptr: %d diff: %d\n",hwptr,diff);
+#ifdef DEBUG
+               printk("(trident) updating dac: hwptr: %d diff: %d\n",hwptr,diff);
+#endif
                s->dma_dac.hwptr = hwptr;
                s->dma_dac.total_bytes += diff;
                if (s->dma_dac.mapped) 
@@ -1719,7 +1810,9 @@ static void trident_update_ptr(struct trident_state *s)
                else 
                {
                        s->dma_dac.count -= diff;
-                       M_printk("(trident) trident_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); 
+#ifdef DEBUG
+                       printk("(trident) trident_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); 
+#endif
                        if (s->dma_dac.count <= 0) 
                        {
                                s->enable &= ~TRIDENT_ENABLE_PE;
@@ -1747,94 +1840,76 @@ static void trident_update_ptr(struct trident_state *s)
 /*
  *     Trident interrupt handlers.
  */
 static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-        struct trident_state *s;
-        struct trident_card *c = (struct trident_card *)dev_id;
+       struct trident_state *state;
+       struct trident_card *card = (struct trident_card *)dev_id;
        int i;
        u32 event;
 
-       spin_lock(&c->lock);
-       
-       event = inl(TRID_REG(c, T4D_MISCINT));
-       
-//     if(event & 0x28)
-//             printk("IRQ %04X (%08lX, %08lX)\n", event, c->iobase, TRID_REG(c, T4D_MISCINT));
-       
-       if(event & 8)
-       {
-               /* Midi - TODO */
-       }       
-       
-       if(event & 0x20)
-       {
-               /*
-                *      Update the pointers for all channels we are running.
-                */
-        
-               for(i=0;i<NR_DSPS;i++)
-               {
-                       s=&c->channels[i];
-                       if(DidChannelInterrupt(c, i))
-                       {
-                               AckChannelInterrupt(c,i);
-                               if(s->dev_audio != -1)
-                                       trident_update_ptr(s);
-                               else
-                               {
+       spin_lock(&card->lock);
+       event = inl(TRID_REG(card, T4D_MISCINT));
+
+#ifdef DEBUG
+       printk("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);
+#endif
+
+       if (event & ADDRESS_IRQ) {
+               /* Update the pointers for all channels we are running. */
+               /* the index variable i is the main bug make the original driver crash,
+                  the code mix "software" channel with "hardware" channel */
+               for (i = 0; i < NR_DSPS; i++) {
+                       state = &card->channels[i];
+                       if (trident_check_channel_interrupt(card, 63 - i)) {
+                               trident_ack_channel_interrupt(card, 63 - i);
+                               if (state->dev_audio != -1)
+                                       trident_update_ptr(state);
+                               else {
                                        /* Spurious ? */
-                                       M_printk("(trident) spurious channel irq %d.\n", i);
-                                       trident_stop_voice(c, i);
-                                       trident_disable_voice_irq(c,i);
+                                       printk("trident: spurious channel irq %d.\n", 
+                                              63 - i);
+                                       trident_stop_voice(card, i);
+                                       trident_disable_voice_irq(card, i);
                                }
                        }
                }
-               
-       }       
-       spin_unlock(&c->lock);
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
+       }
 
-#define VALIDATE_MAGIC(FOO,MAG)                         \
-({                                                \
-       if (!(FOO) || (FOO)->magic != MAG) { \
-               printk(invalid_magic,__FUNCTION__);            \
-               return -ENXIO;                    \
-       }                                         \
-})
+       if (event & SB_IRQ){
+               /* Midi - TODO */
+       }
 
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
+       /* manually clear interrupt status, bad hardware design, balme T^2 */
+       outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
+            TRID_REG(card, T4D_MISCINT));
+       spin_unlock(&card->lock);
+}
 
 static void set_mixer(struct trident_card *card,unsigned int mixer, unsigned int val ) 
 {
        unsigned int left,right;
+
        /* cleanse input a little */
        right = ((val >> 8)  & 0xff) ;
        left = (val  & 0xff) ;
 
-       if(right > 100) right = 100;
-       if(left > 100) left = 100;
+       if (right > 100) right = 100;
+       if (left > 100) left = 100;
 
-       card->mix.mixer_state[mixer]=(right << 8) | left;
-       card->mix.write_mixer(card,mixer,left,right);
+       card->mix.mixer_state[mixer] = (right << 8) | left;
+       card->mix.write_mixer(card, mixer, left, right);
 }
 
 static int mixer_ioctl(struct trident_card *card, unsigned int cmd, unsigned long arg)
 {
        unsigned long flags;
-       int i, val=0;
+       int i, val = 0;
 
        VALIDATE_CARD(card);
-        if (cmd == SOUND_MIXER_INFO) {
+       if (cmd == SOUND_MIXER_INFO) {
                mixer_info info;
-               strncpy(info.id, card_names[card->card_type], sizeof(info.id));
-               strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+               strncpy(info.id, card->pci_info->name, sizeof(info.id));
+               strncpy(info.name, card->pci_info->name, sizeof(info.name));
                info.modify_counter = card->mix.modcnt;
                if (copy_to_user((void *)arg, &info, sizeof(info)))
                        return -EFAULT;
@@ -1842,23 +1917,23 @@ static int mixer_ioctl(struct trident_card *card, unsigned int cmd, unsigned lon
        }
        if (cmd == SOUND_OLD_MIXER_INFO) {
                _old_mixer_info info;
-               strncpy(info.id, card_names[card->card_type], sizeof(info.id));
-               strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+               strncpy(info.id, card->pci_info->name, sizeof(info.id));
+               strncpy(info.name, card->pci_info->name, sizeof(info.name));
                if (copy_to_user((void *)arg, &info, sizeof(info)))
                        return -EFAULT;
                return 0;
        }
-       if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, (int *)arg);
 
        if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
-                return -EINVAL;
+               return -EINVAL;
 
-        if (_IOC_DIR(cmd) == _IOC_READ) {
-                switch (_IOC_NR(cmd)) {
-                case SOUND_MIXER_RECSRC: /* give them the current record source */
+       if (cmd == OSS_GETVERSION)
+               return put_user(SOUND_VERSION, (int *)arg);
 
-                       if(!card->mix.recmask_io) {
+       if (_IOC_DIR(cmd) == _IOC_READ) {
+               switch (_IOC_NR(cmd)) {
+               case SOUND_MIXER_RECSRC: /* give them the current record source */
+                       if (!card->mix.recmask_io) {
                                val = 0;
                        } else {
                                spin_lock_irqsave(&card->lock, flags);
@@ -1866,83 +1941,71 @@ static int mixer_ioctl(struct trident_card *card, unsigned int cmd, unsigned lon
                                spin_unlock_irqrestore(&card->lock, flags);
                        }
                        break;
-                       
-                case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
+
+               case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
                        val = card->mix.supported_mixers;
                        break;
 
-                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+               case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
                        val = card->mix.record_sources;
                        break;
-                       
-                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+
+               case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
                        val = card->mix.stereo_mixers;
                        break;
-                       
-                case SOUND_MIXER_CAPS:
+
+               case SOUND_MIXER_CAPS:
                        val = SOUND_CAP_EXCL_INPUT;
                        break;
 
                default: /* read a specific mixer */
                        i = _IOC_NR(cmd);
 
-                       if ( ! supported_mixer(card,i)) 
+                       if (!supported_mixer(card,i)) 
                                return -EINVAL;
 
                        /* do we ever want to touch the hardware? */
-/*                     spin_lock_irqsave(&s->lock, flags);
+                       /* spin_lock_irqsave(&s->lock, flags);
                        val = card->mix.read_mixer(card,i);
                        spin_unlock_irqrestore(&s->lock, flags);*/
 
                        val = card->mix.mixer_state[i];
-/*                     printk("returned 0x%x for mixer %d\n",val,i);*/
-
+                       /* printk("returned 0x%x for mixer %d\n",val,i);*/
                        break;
                }
                return put_user(val,(int *)arg);
        }
-       
-        if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
-               return -EINVAL;
-       
-       card->mix.modcnt++;
 
-       get_user_ret(val, (int *)arg, -EFAULT);
+       if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
+               card->mix.modcnt++;
+               get_user_ret(val, (int *)arg, -EFAULT);
 
-       switch (_IOC_NR(cmd)) {
-       case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+               switch (_IOC_NR(cmd)) {
+               case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+                       if (!card->mix.recmask_io) return -EINVAL;
+                       if (!(val &= card->mix.record_sources)) return -EINVAL;
 
-               if (!card->mix.recmask_io) return -EINVAL;
-               if(! (val &= card->mix.record_sources)) return -EINVAL;
+                       spin_lock_irqsave(&card->lock, flags);
+                       card->mix.recmask_io(card, 0, val);
+                       spin_unlock_irqrestore(&card->lock, flags);
 
-               spin_lock_irqsave(&card->lock, flags);
-               card->mix.recmask_io(card,0,val);
-               spin_unlock_irqrestore(&card->lock, flags);
-               return 0;
-
-       default:
-               i = _IOC_NR(cmd);
+                       return 0;
+               default: /* write a specific mixer */
+                       i = _IOC_NR(cmd);
 
-               if ( ! supported_mixer(card,i)) 
-                       return -EINVAL;
+                       if (!supported_mixer(card, i)) 
+                               return -EINVAL;
 
-               spin_lock_irqsave(&card->lock, flags);
-               set_mixer(card,i,val);
-               spin_unlock_irqrestore(&card->lock, flags);
+                       spin_lock_irqsave(&card->lock, flags);
+                       set_mixer(card, i, val);
+                       spin_unlock_irqrestore(&card->lock, flags);
 
-               return 0;
+                       return 0;
+               }
        }
+       return -EINVAL;
 }
 
-/* --------------------------------------------------------------------- */
-
-static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
-{
-       return -ESPIPE;
-}
-
-/* --------------------------------------------------------------------- */
-
 static int trident_open_mixdev(struct inode *inode, struct file *file)
 {
        int minor = MINOR(inode->i_rdev);
@@ -1954,6 +2017,7 @@ static int trident_open_mixdev(struct inode *inode, struct file *file)
                return -ENODEV;
 
        file->private_data = card;
+
        //FIXME put back in
        //MOD_INC_USE_COUNT;
        return 0;
@@ -1970,7 +2034,8 @@ static int trident_release_mixdev(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, 
+                               unsigned long arg)
 {
        struct trident_card *card = (struct trident_card *)file->private_data;
 
@@ -1979,6 +2044,11 @@ static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned
        return mixer_ioctl(card, cmd, arg);
 }
 
+static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
+{
+       return -ESPIPE;
+}
+
 static /*const*/ struct file_operations trident_mixer_fops = {
        &trident_llseek,
        NULL,  /* read */
@@ -1997,11 +2067,13 @@ static /*const*/ struct file_operations trident_mixer_fops = {
        NULL,  /* lock */
 };
 
-/* --------------------------------------------------------------------- */
-
+/* drain the DAC buffer
+   FIXME: This function will block (forever ??) when using
+   XMMS Qsound plugin and direct cat sample.wav > /dev/dsp
+   This behavior is when drain_dac is called by trident_release. */
 static int drain_dac(struct trident_state *s, int nonblock)
 {
-        DECLARE_WAITQUEUE(wait, current);
+       DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        int count;
        signed long tmo;
@@ -2011,8 +2083,7 @@ static int drain_dac(struct trident_state *s, int nonblock)
        current->state = TASK_INTERRUPTIBLE;
        add_wait_queue(&s->dma_dac.wait, &wait);
 
-       for (;;) 
-       {
+       for (;;) {
                spin_lock_irqsave(&s->card->lock, flags);
                count = s->dma_dac.count;
                spin_unlock_irqrestore(&s->card->lock, flags);
@@ -2023,20 +2094,20 @@ static int drain_dac(struct trident_state *s, int nonblock)
                if (signal_pending(current))
                        break;
 
-               if (nonblock) 
-               {
+               if (nonblock) {
                        remove_wait_queue(&s->dma_dac.wait, &wait);
                        current->state = TASK_RUNNING;
                        return -EBUSY;
                }
-
+               
                tmo = (count * HZ) / s->ratedac;
                tmo >>= sample_shift[(s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK];
 
-               /* XXX this is just broken.  someone is waking us up alot, or schedule_timeout is broken.
-               or something.  who cares. - zach */
+               /* XXX this is just broken.  someone is waking us up alot, 
+                  or schedule_timeout is broken.
+                  or something.  who cares. - zach */
                if (!schedule_timeout(tmo ? tmo : 1) && tmo)
-                       printk(KERN_DEBUG "trident: dma timed out?? %ld\n",jiffies);
+                       printk(KERN_ERR "trident: dma timed out?? %ld\n", jiffies);
        }
        remove_wait_queue(&s->dma_dac.wait, &wait);
        current->state = TASK_RUNNING;
@@ -2045,82 +2116,86 @@ static int drain_dac(struct trident_state *s, int nonblock)
        return 0;
 }
 
-/* --------------------------------------------------------------------- */
-
 /* in this loop, dma_adc.count signifies the amount of data thats waiting
-       to be copied to the user's buffer.  it is filled by the interrupt
-       handler and drained by this loop. */
+   to be copied to the user's buffer.  it is filled by the interrupt
+   handler and drained by this loop. */
 static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
-       struct trident_state *s = (struct trident_state *)file->private_data;
+       struct trident_state *state = (struct trident_state *)file->private_data;
        ssize_t ret;
        unsigned long flags;
        unsigned swptr;
        int cnt;
        
-       VALIDATE_STATE(s);
+       VALIDATE_STATE(state);
        if (ppos != &file->f_pos)
                return -ESPIPE;
-       if (s->dma_adc.mapped)
+       if (state->dma_adc.mapped)
                return -ENXIO;
-       if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+       if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
                return ret;
        if (!access_ok(VERIFY_WRITE, buffer, count))
                return -EFAULT;
        ret = 0;
 
        while (count > 0) {
-               spin_lock_irqsave(&s->card->lock, flags);
+               spin_lock_irqsave(&state->card->lock, flags);
                /* remember, all these things are expressed in bytes to be
-                       sent to the user.. hence the evil / 2 down below */
-               swptr = s->dma_adc.swptr;
-               cnt = s->dma_adc.dmasize-swptr;
-               if (s->dma_adc.count < cnt)
-                       cnt = s->dma_adc.count;
-               spin_unlock_irqrestore(&s->card->lock, flags);
+                  sent to the user.. hence the evil / 2 down below */
+               swptr = state->dma_adc.swptr;
+               cnt = state->dma_adc.dmasize - swptr;
+               if (state->dma_adc.count < cnt)
+                       cnt = state->dma_adc.count;
+               spin_unlock_irqrestore(&state->card->lock, flags);
 
                if (cnt > count)
                        cnt = count;
 
                if (cnt <= 0) {
-                       start_adc(s);
-                       if (file->f_flags & O_NONBLOCK) 
-                       {
+                       start_adc(state);
+                       if (file->f_flags & O_NONBLOCK) {
                                ret = ret ? ret : -EAGAIN;
                                return ret;
                        }
-                       if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
-                               M_printk(KERN_DEBUG "(trident) read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-                                      s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, 
-                                      s->dma_adc.hwptr, s->dma_adc.swptr);
-                               stop_adc(s);
-                               spin_lock_irqsave(&s->card->lock, flags);
-//                             set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
-                               s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
-                               spin_unlock_irqrestore(&s->card->lock, flags);
+                       if (!interruptible_sleep_on_timeout(&state->dma_adc.wait, HZ)) {
+                               printk(KERN_DEBUG "(trident) read: chip lockup? "
+                                      "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+                                      state->dma_adc.dmasize,
+                                      state->dma_adc.fragsize,
+                                      state->dma_adc.count,
+                                      state->dma_adc.hwptr,
+                                      state->dma_adc.swptr);
+                               stop_adc(state);
+
+                               spin_lock_irqsave(&state->card->lock, flags);
+                               /*set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), 
+                                 s->dma_adc.numfrag << s->dma_adc.fragshift); */
+                               state->dma_adc.count = 0;
+                               state->dma_adc.hwptr = 0;
+                               state->dma_adc.swptr = 0;
+                               spin_unlock_irqrestore(&state->card->lock, flags);
                        }
-                       if (signal_pending(current)) 
-                       {
+                       if (signal_pending(current)) {
                                ret = ret ? ret : -ERESTARTSYS;
                                return ret;
                        }
                        continue;
                }
        
-               if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+               if (copy_to_user(buffer, state->dma_adc.rawbuf + swptr, cnt)) {
                        ret = ret ? ret : -EFAULT;
                        return ret;
                }
 
-               swptr = (swptr + cnt) % s->dma_adc.dmasize;
-               spin_lock_irqsave(&s->card->lock, flags);
-               s->dma_adc.swptr = swptr;
-               s->dma_adc.count -= cnt;
-               spin_unlock_irqrestore(&s->card->lock, flags);
+               swptr = (swptr + cnt) % state->dma_adc.dmasize;
+               spin_lock_irqsave(&state->card->lock, flags);
+               state->dma_adc.swptr = swptr;
+               state->dma_adc.count -= cnt;
+               spin_unlock_irqrestore(&state->card->lock, flags);
                count -= cnt;
                buffer += cnt;
                ret += cnt;
-               start_adc(s);
+               start_adc(state);
        }
 
        return ret;
@@ -2128,92 +2203,92 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
 
 static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
-       struct trident_state *s = (struct trident_state *)file->private_data;
+       struct trident_state *state = (struct trident_state *)file->private_data;
        ssize_t ret;
        unsigned long flags;
        unsigned swptr;
        int cnt;
-       int mode = (s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK;
+       int mode = (state->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK;
 
-       M_printk("(trident) trident_write: count %d\n", count);
-       
-       VALIDATE_STATE(s);
+#ifdef DEBUG
+       printk("(trident) trident_write: count %d\n", count);
+#endif 
+
+       VALIDATE_STATE(state);
        if (ppos != &file->f_pos)
                return -ESPIPE;
-       if (s->dma_dac.mapped)
+       if (state->dma_dac.mapped)
                return -ENXIO;
-       if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+       if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
                return ret;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
        ret = 0;
 
        while (count > 0) {
-               spin_lock_irqsave(&s->card->lock, flags);
-
-               if (s->dma_dac.count < 0) 
-               {
-                       s->dma_dac.count = 0;
-                       s->dma_dac.swptr = s->dma_dac.hwptr;
+               spin_lock_irqsave(&state->card->lock, flags);
+               if (state->dma_dac.count < 0) {
+                       state->dma_dac.count = 0;
+                       state->dma_dac.swptr = state->dma_dac.hwptr;
                }
-               swptr = s->dma_dac.swptr;
-
-               cnt = s->dma_dac.dmasize-swptr;
-
-               if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-                       cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
-               spin_unlock_irqrestore(&s->card->lock, flags);
+               swptr = state->dma_dac.swptr;
+               cnt = state->dma_dac.dmasize - swptr;
+               if (state->dma_dac.count + cnt > state->dma_dac.dmasize)
+                       cnt = state->dma_dac.dmasize - state->dma_dac.count;
+               spin_unlock_irqrestore(&state->card->lock, flags);
 
                if (cnt > count)
                        cnt = count;
-
-               if (cnt <= 0) 
-               {
+               if (cnt <= 0) {
                        /* buffer is full, wait for it to be played */
-                       start_dac(s);
-                       if (file->f_flags & O_NONBLOCK) 
-                       {
-                               if(!ret) ret = -EAGAIN;
+                       start_dac(state);
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret) ret = -EAGAIN;
                                return ret;
                        }
-                       if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) 
-                       {
-                               M_printk(KERN_DEBUG 
-                                               "trident: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", 
-                                               s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr, 
-                                               s->dma_dac.swptr);
-                               stop_dac(s);
-                               spin_lock_irqsave(&s->card->lock, flags);
-//                     set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
-                               s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
-                               spin_unlock_irqrestore(&s->card->lock, flags);
+                       if (!interruptible_sleep_on_timeout(&state->dma_dac.wait, HZ)) {
+                               printk(KERN_DEBUG 
+                                      "trident: write: chip lockup? "
+                                      "dmasz %u fragsz %u count %i "
+                                      "hwptr %u swptr %u\n", 
+                                      state->dma_dac.dmasize, 
+                                      state->dma_dac.fragsize, 
+                                      state->dma_dac.count, 
+                                      state->dma_dac.hwptr, 
+                                      state->dma_dac.swptr);
+                               stop_dac(state);
+                               spin_lock_irqsave(&state->card->lock, flags);
+                               /* set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), 
+                                  s->dma_dac.numfrag << s->dma_dac.fragshift); */
+                               state->dma_dac.count = 0;
+                               state->dma_dac.hwptr = 0;
+                               state->dma_dac.swptr = 0;
+                               spin_unlock_irqrestore(&state->card->lock, flags);
                        }
-                       if (signal_pending(current)) 
-                       {
+                       if (signal_pending(current)) {
                                if (!ret) ret = -ERESTARTSYS;
                                return ret;
                        }
                        continue;
                }
-               if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) 
-               {
+               if (copy_from_user(state->dma_dac.rawbuf + swptr, buffer, cnt)) {
                        if (!ret)
                                ret = -EFAULT;
                        return ret;
                }
 
-               swptr = (swptr + cnt) % s->dma_dac.dmasize;
+               swptr = (swptr + cnt) % state->dma_dac.dmasize;
+
+               spin_lock_irqsave(&state->card->lock, flags);
+               state->dma_dac.swptr = swptr;
+               state->dma_dac.count += cnt;
+               state->dma_dac.endcleared = 0;
+               spin_unlock_irqrestore(&state->card->lock, flags);
 
-               spin_lock_irqsave(&s->card->lock, flags);
-               s->dma_dac.swptr = swptr;
-               s->dma_dac.count += cnt;
-               s->dma_dac.endcleared = 0;
-               spin_unlock_irqrestore(&s->card->lock, flags);
                count -= cnt;
                buffer += cnt;
                ret += cnt;
-               start_dac(s);
+               start_dac(state);
        }
        return ret;
 }
@@ -2259,11 +2334,11 @@ static int trident_mmap(struct file *file, struct vm_area_struct *vma)
 
        VALIDATE_STATE(s);
        if (vma->vm_flags & VM_WRITE) {
-               if ((ret = prog_dmabuf(s, 1)) != 0)
+               if ((ret = prog_dmabuf(s, 0)) != 0)
                        return ret;
                db = &s->dma_dac;
        } else if (vma->vm_flags & VM_READ) {
-               if ((ret = prog_dmabuf(s, 0)) != 0)
+               if ((ret = prog_dmabuf(s, 1)) != 0)
                        return ret;
                db = &s->dma_adc;
        } else 
@@ -2284,336 +2359,315 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
 {
        struct trident_state *s = (struct trident_state *)file->private_data;
        unsigned long flags;
-        audio_buf_info abinfo;
-        count_info cinfo;
+       audio_buf_info abinfo;
+       count_info cinfo;
        int val, mapped, ret;
        unsigned char fmtm, fmtd;
 
-/*     printk("trident: trident_ioctl: cmd %d\n", cmd);*/
-       
        VALIDATE_STATE(s);
-  mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+       mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
                ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
 
        switch (cmd) 
        {
-               case OSS_GETVERSION:
+       case OSS_GETVERSION:
                return put_user(SOUND_VERSION, (int *)arg);
 
-               case SNDCTL_DSP_SYNC:
-                       if (file->f_mode & FMODE_WRITE)
-                               return drain_dac(s, file->f_flags & O_NONBLOCK);
+       case SNDCTL_DSP_RESET:
+               if (file->f_mode & FMODE_WRITE) {
+                       stop_dac(s);
+                       synchronize_irq();
+                       s->dma_dac.swptr = s->dma_dac.hwptr = 0;
+                       s->dma_dac.count = s->dma_dac.total_bytes = 0;
+               }
+               if (file->f_mode & FMODE_READ) {
+                       stop_adc(s);
+                       synchronize_irq();
+                       s->dma_adc.swptr = s->dma_adc.hwptr = 0;
+                       s->dma_adc.count = s->dma_adc.total_bytes = 0;
+               }
                return 0;
 
-               case SNDCTL_DSP_SETDUPLEX:
-               /* XXX fix */
+       case SNDCTL_DSP_SYNC:
+               if (file->f_mode & FMODE_WRITE)
+                       return drain_dac(s, file->f_flags & O_NONBLOCK);
                return 0;
 
-               case SNDCTL_DSP_GETCAPS:
-                       return put_user(0/*DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP*/, (int *)arg);
-
-               case SNDCTL_DSP_RESET:
-                       if (file->f_mode & FMODE_WRITE) 
-                       {
-                               stop_dac(s);
-                               synchronize_irq();
-                               s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
-                       }
-                       if (file->f_mode & FMODE_READ) 
-                       {
+       case SNDCTL_DSP_SPEED:
+               get_user_ret(val, (int *)arg, -EFAULT);
+               if (val >= 0) {
+                       if (file->f_mode & FMODE_READ) {
                                stop_adc(s);
-                               synchronize_irq();
-                               s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+                               s->dma_adc.ready = 0;
+                               trident_set_adc_rate(s, val, 1);
+                       }
+                       if (file->f_mode & FMODE_WRITE) {
+                               stop_dac(s);
+                               s->dma_dac.ready = 0;
+                               trident_set_dac_rate(s, val, 1);
                        }
+               }
+               return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac,
+                               (int *)arg);
+
+       case SNDCTL_DSP_STEREO:
+               get_user_ret(val, (int *)arg, -EFAULT);
+               fmtd = 0;
+               fmtm = ~0;
+               if (file->f_mode & FMODE_READ) {
+                       stop_adc(s);
+                       s->dma_adc.ready = 0;
+                       if (val)
+                               fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+                       else
+                               fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       stop_dac(s);
+                       s->dma_dac.ready = 0;
+                       if (val)
+                               fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+                       else
+                               fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+               }
+               set_fmt(s, fmtm, fmtd);
                return 0;
 
-               case SNDCTL_DSP_SPEED:
-                       get_user_ret(val, (int *)arg, -EFAULT);
-                       if (val >= 0) 
-                       {
-                               if (file->f_mode & FMODE_READ) 
-                               {
-                                       stop_adc(s);
-                                       s->dma_adc.ready = 0;
-                                       trident_set_adc_rate(s, val, 1);
-                               }
-                               if (file->f_mode & FMODE_WRITE) 
-                               {
-                                       stop_dac(s);
-                                       s->dma_dac.ready = 0;
-                                       trident_set_dac_rate(s, val, 1);
-                               }
-                       }
-               return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+       case SNDCTL_DSP_GETBLKSIZE:
+               if (file->f_mode & FMODE_WRITE) {
+                       if ((val = prog_dmabuf(s, 0)))
+                               return val;
+                       return put_user(s->dma_dac.fragsize, (int *)arg);
+               }
+               if ((val = prog_dmabuf(s, 1)))
+                       return val;
+               return put_user(s->dma_adc.fragsize, (int *)arg);
 
-               case SNDCTL_DSP_STEREO:
-                       get_user_ret(val, (int *)arg, -EFAULT);
+       case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+               return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+       case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+               get_user_ret(val, (int *)arg, -EFAULT);
+               if (val != AFMT_QUERY) {
                        fmtd = 0;
                        fmtm = ~0;
-                       if (file->f_mode & FMODE_READ) 
-                       {
+                       if (file->f_mode & FMODE_READ) {
                                stop_adc(s);
                                s->dma_adc.ready = 0;
-                               if (val)
-                                       fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+                               /* fixed at 16bit for now */
+                               fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
+#if 0
+                               if (val == AFMT_S16_LE)
+                                       fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
                                else
-                                       fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+                                       fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT);
+#endif
                        }
-                       if (file->f_mode & FMODE_WRITE) 
-                       {
+                       if (file->f_mode & FMODE_WRITE) {
                                stop_dac(s);
                                s->dma_dac.ready = 0;
-                               if (val)
-                                       fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+                               if (val == AFMT_S16_LE)
+                                       fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
                                else
-                                       fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+                                       fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT);
                        }
                        set_fmt(s, fmtm, fmtd);
+               }
+               return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
+                                          (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) : 
+                                          (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 
+                               AFMT_S16_LE : AFMT_S8, (int *)arg);
 
-               return 0;
-
-               case SNDCTL_DSP_CHANNELS:
-                       get_user_ret(val, (int *)arg, -EFAULT);
-                       if (val != 0) 
-                       {
-                               fmtd = 0;
-                               fmtm = ~0;
+       case SNDCTL_DSP_CHANNELS:
+               get_user_ret(val, (int *)arg, -EFAULT);
+               if (val != 0) {
+                       fmtd = 0;
+                       fmtm = ~0;
 
-                               if (file->f_mode & FMODE_READ) 
-                               {
+                       if (file->f_mode & FMODE_READ) {
                                stop_adc(s);
                                s->dma_adc.ready = 0;
                                if (val >= 2)
                                        fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
                                else
                                        fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
-                               }
+                       }
 
-                               if (file->f_mode & FMODE_WRITE) 
-                               {
-                                       stop_dac(s);
-                                       s->dma_dac.ready = 0;
-                                       if (val >= 2)
-                                               fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
-                                       else
-                                               fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
-                               }
-                               set_fmt(s, fmtm, fmtd);
+                       if (file->f_mode & FMODE_WRITE) {
+                               stop_dac(s);
+                               s->dma_dac.ready = 0;
+                               if (val >= 2)
+                                       fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+                               else
+                                       fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
                        }
+                       set_fmt(s, fmtm, fmtd);
+               }
                return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-                                                       (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) : 
-                                                       (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+                                          (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) : 
+                                          (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+       case SNDCTL_DSP_POST:
+               return 0;
 
-               case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-               return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+       case SNDCTL_DSP_SUBDIVIDE:
+               if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || 
+                   (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+                       return -EINVAL;
+               get_user_ret(val, (int *)arg, -EFAULT);
+               if (val != 1 && val != 2 && val != 4)
+                       return -EINVAL;
+               if (file->f_mode & FMODE_READ)
+                       s->dma_adc.subdivision = val;
+               if (file->f_mode & FMODE_WRITE)
+                       s->dma_dac.subdivision = val;
+               return 0;
 
-               case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-                       get_user_ret(val, (int *)arg, -EFAULT);
-                       if (val != AFMT_QUERY) 
-                       {
-                               fmtd = 0;
-                               fmtm = ~0;
-                               if (file->f_mode & FMODE_READ) 
-                               {
-                                       stop_adc(s);
-                                       s->dma_adc.ready = 0;
-                                       /* fixed at 16bit for now */
-                                       fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
-#if 0
-                                       if (val == AFMT_S16_LE)
-                                       fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
-                                       else
-                                       fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT);
-#endif
-                               }
-                               if (file->f_mode & FMODE_WRITE) 
-                               {
-                                       stop_dac(s);
-                                       s->dma_dac.ready = 0;
-                                       if (val == AFMT_S16_LE)
-                                               fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
-                                       else
-                                               fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT);
-                               }
-                               set_fmt(s, fmtm, fmtd);
-                       }
-               return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-                       (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) : 
-                       (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 
-                       AFMT_S16_LE : AFMT_S8, (int *)arg);
+       case SNDCTL_DSP_SETFRAGMENT:
+               get_user_ret(val, (int *)arg, -EFAULT);
+               if (file->f_mode & FMODE_READ) {
+                       s->dma_adc.ossfragshift = val & 0xffff;
+                       s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+                       if (s->dma_adc.ossfragshift < 4)
+                               s->dma_adc.ossfragshift = 4;
+                       if (s->dma_adc.ossfragshift > 15)
+                               s->dma_adc.ossfragshift = 15;
+                       if (s->dma_adc.ossmaxfrags < 4)
+                               s->dma_adc.ossmaxfrags = 4;
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       s->dma_dac.ossfragshift = val & 0xffff;
+                       s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+                       if (s->dma_dac.ossfragshift < 4)
+                               s->dma_dac.ossfragshift = 4;
+                       if (s->dma_dac.ossfragshift > 15)
+                               s->dma_dac.ossfragshift = 15;
+                       if (s->dma_dac.ossmaxfrags < 4)
+                               s->dma_dac.ossmaxfrags = 4;
+               }
+               return 0;
 
-               case SNDCTL_DSP_POST:
+       case SNDCTL_DSP_GETCAPS:
+               return put_user(0/* DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP */,
+                               (int *)arg);
+               
+       case SNDCTL_DSP_SETDUPLEX:
+               /* XXX fix */
                return 0;
 
-               case SNDCTL_DSP_GETTRIGGER:
-                       val = 0;
-                       if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE) 
-                               val |= PCM_ENABLE_INPUT;
-                       if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE) 
-                               val |= PCM_ENABLE_OUTPUT;
+       case SNDCTL_DSP_GETTRIGGER:
+               val = 0;
+               if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE) 
+                       val |= PCM_ENABLE_INPUT;
+               if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE) 
+                       val |= PCM_ENABLE_OUTPUT;
                return put_user(val, (int *)arg);
 
-               case SNDCTL_DSP_SETTRIGGER:
-                       get_user_ret(val, (int *)arg, -EFAULT);
-                       if (file->f_mode & FMODE_READ) 
-                       {
-                               if (val & PCM_ENABLE_INPUT) 
-                               {
-                                       if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-                                               return ret;
-                                       start_adc(s);
-                               } 
-                               else
-                                       stop_adc(s);
-                       }
-                       if (file->f_mode & FMODE_WRITE) 
-                       {
-                               if (val & PCM_ENABLE_OUTPUT) 
-                               {
-                                       if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-                                               return ret;
-                                       start_dac(s);
-                               } 
-                               else
-                                       stop_dac(s);
-                       }
+       case SNDCTL_DSP_SETTRIGGER:
+               get_user_ret(val, (int *)arg, -EFAULT);
+               if (file->f_mode & FMODE_READ) {
+                       if (val & PCM_ENABLE_INPUT) {
+                               if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
+                                       return ret;
+                               start_adc(s);
+                       } 
+                       else
+                               stop_adc(s);
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       if (val & PCM_ENABLE_OUTPUT) {
+                               if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+                                       return ret;
+                               start_dac(s);
+                       } 
+                       else
+                               stop_dac(s);
+               }
                return 0;
 
-               case SNDCTL_DSP_GETOSPACE:
-                       if (!(file->f_mode & FMODE_WRITE))
-                               return -EINVAL;
-                       if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
-                               return val;
-                       spin_lock_irqsave(&s->card->lock, flags);
-                       trident_update_ptr(s);
-                       abinfo.fragsize = s->dma_dac.fragsize;
-                       abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
-                       abinfo.fragstotal = s->dma_dac.numfrag;
-                       abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
-                       spin_unlock_irqrestore(&s->card->lock, flags);
+       case SNDCTL_DSP_GETOSPACE:
+               if (!(file->f_mode & FMODE_WRITE))
+                       return -EINVAL;
+               if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
+                       return val;
+               spin_lock_irqsave(&s->card->lock, flags);
+               trident_update_ptr(s);
+               abinfo.fragsize = s->dma_dac.fragsize;
+               abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+               abinfo.fragstotal = s->dma_dac.numfrag;
+               abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
+               spin_unlock_irqrestore(&s->card->lock, flags);
                return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
-               case SNDCTL_DSP_GETISPACE:
-                       if (!(file->f_mode & FMODE_READ))
+       case SNDCTL_DSP_GETISPACE:
+               if (!(file->f_mode & FMODE_READ))
                        return -EINVAL;
-                       if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
+               if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
                        return val;
-                       spin_lock_irqsave(&s->card->lock, flags);
-                       trident_update_ptr(s);
-                       abinfo.fragsize = s->dma_adc.fragsize;
-                       abinfo.bytes = s->dma_adc.count;
-                       abinfo.fragstotal = s->dma_adc.numfrag;
-                       abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
-                       spin_unlock_irqrestore(&s->card->lock, flags);
+               spin_lock_irqsave(&s->card->lock, flags);
+               trident_update_ptr(s);
+               abinfo.fragsize = s->dma_adc.fragsize;
+               abinfo.bytes = s->dma_adc.count;
+               abinfo.fragstotal = s->dma_adc.numfrag;
+               abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
+               spin_unlock_irqrestore(&s->card->lock, flags);
                return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
-               case SNDCTL_DSP_NONBLOCK:
-                       file->f_flags |= O_NONBLOCK;
+       case SNDCTL_DSP_NONBLOCK:
+               file->f_flags |= O_NONBLOCK;
                return 0;
 
-               case SNDCTL_DSP_GETODELAY:
-                       if (!(file->f_mode & FMODE_WRITE))
-                               return -EINVAL;
-                       spin_lock_irqsave(&s->card->lock, flags);
-                       trident_update_ptr(s);
-                       val = s->dma_dac.count;
-                       spin_unlock_irqrestore(&s->card->lock, flags);
+       case SNDCTL_DSP_GETODELAY:
+               if (!(file->f_mode & FMODE_WRITE))
+                       return -EINVAL;
+               spin_lock_irqsave(&s->card->lock, flags);
+               trident_update_ptr(s);
+               val = s->dma_dac.count;
+               spin_unlock_irqrestore(&s->card->lock, flags);
                return put_user(val, (int *)arg);
 
-               case SNDCTL_DSP_GETIPTR:
-                       if (!(file->f_mode & FMODE_READ))
-                               return -EINVAL;
-                       spin_lock_irqsave(&s->card->lock, flags);
-                       trident_update_ptr(s);
-                       cinfo.bytes = s->dma_adc.total_bytes;
-                       cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
-                       cinfo.ptr = s->dma_adc.hwptr;
-                       if (s->dma_adc.mapped)
-                               s->dma_adc.count &= s->dma_adc.fragsize-1;
-                       spin_unlock_irqrestore(&s->card->lock, flags);
+       case SNDCTL_DSP_GETIPTR:
+               if (!(file->f_mode & FMODE_READ))
+                       return -EINVAL;
+               spin_lock_irqsave(&s->card->lock, flags);
+               trident_update_ptr(s);
+               cinfo.bytes = s->dma_adc.total_bytes;
+               cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+               cinfo.ptr = s->dma_adc.hwptr;
+               if (s->dma_adc.mapped)
+                       s->dma_adc.count &= s->dma_adc.fragsize-1;
+               spin_unlock_irqrestore(&s->card->lock, flags);
                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
-
-               case SNDCTL_DSP_GETOPTR:
-                       if (!(file->f_mode & FMODE_WRITE))
-                               return -EINVAL;
-                       spin_lock_irqsave(&s->card->lock, flags);
-                       trident_update_ptr(s);
-                       cinfo.bytes = s->dma_dac.total_bytes;
-                       cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
-                       cinfo.ptr = s->dma_dac.hwptr;
-                       if (s->dma_dac.mapped)
-                               s->dma_dac.count &= s->dma_dac.fragsize-1;
-                       spin_unlock_irqrestore(&s->card->lock, flags);
+               
+       case SNDCTL_DSP_GETOPTR:
+               if (!(file->f_mode & FMODE_WRITE))
+                       return -EINVAL;
+               spin_lock_irqsave(&s->card->lock, flags);
+               trident_update_ptr(s);
+               cinfo.bytes = s->dma_dac.total_bytes;
+               cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+               cinfo.ptr = s->dma_dac.hwptr;
+               if (s->dma_dac.mapped)
+                       s->dma_dac.count &= s->dma_dac.fragsize-1;
+               spin_unlock_irqrestore(&s->card->lock, flags);
                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
-               case SNDCTL_DSP_GETBLKSIZE:
-                       if (file->f_mode & FMODE_WRITE) 
-                       {
-                               if ((val = prog_dmabuf(s, 0)))
-                                       return val;
-                               return put_user(s->dma_dac.fragsize, (int *)arg);
-                       }
-                       if ((val = prog_dmabuf(s, 1)))
-                               return val;
-               return put_user(s->dma_adc.fragsize, (int *)arg);
-
-               case SNDCTL_DSP_SETFRAGMENT:
-                       get_user_ret(val, (int *)arg, -EFAULT);
-                       if (file->f_mode & FMODE_READ) 
-                       {
-                               s->dma_adc.ossfragshift = val & 0xffff;
-                               s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-                               if (s->dma_adc.ossfragshift < 4)
-                                       s->dma_adc.ossfragshift = 4;
-                               if (s->dma_adc.ossfragshift > 15)
-                                       s->dma_adc.ossfragshift = 15;
-                               if (s->dma_adc.ossmaxfrags < 4)
-                                       s->dma_adc.ossmaxfrags = 4;
-                       }
-                       if (file->f_mode & FMODE_WRITE) 
-                       {
-                               s->dma_dac.ossfragshift = val & 0xffff;
-                               s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-                               if (s->dma_dac.ossfragshift < 4)
-                                       s->dma_dac.ossfragshift = 4;
-                               if (s->dma_dac.ossfragshift > 15)
-                                       s->dma_dac.ossfragshift = 15;
-                               if (s->dma_dac.ossmaxfrags < 4)
-                                       s->dma_dac.ossmaxfrags = 4;
-                       }
-               return 0;
-
-               case SNDCTL_DSP_SUBDIVIDE:
-                       if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || 
-                                       (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-                               return -EINVAL;
-                       get_user_ret(val, (int *)arg, -EFAULT);
-                       if (val != 1 && val != 2 && val != 4)
-                               return -EINVAL;
-                       if (file->f_mode & FMODE_READ)
-                               s->dma_adc.subdivision = val;
-                       if (file->f_mode & FMODE_WRITE)
-                               s->dma_dac.subdivision = val;
-               return 0;
-
-               case SOUND_PCM_READ_RATE:
+       case SOUND_PCM_READ_RATE:
                return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
 
-               case SOUND_PCM_READ_CHANNELS:
+       case SOUND_PCM_READ_CHANNELS:
                return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-                                               (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) : 
-                                               (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
-
-               case SOUND_PCM_READ_BITS:
+                                          (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) : 
+                                          (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+               
+       case SOUND_PCM_READ_BITS:
                return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-                                               (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) : 
-                                               (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg);
-
-               case SOUND_PCM_WRITE_FILTER:
-               case SNDCTL_DSP_SETSYNCRO:
-               case SOUND_PCM_READ_FILTER:
+                                          (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) : 
+                                          (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg);
+               
+       case SOUND_PCM_WRITE_FILTER:
+       case SNDCTL_DSP_SETSYNCRO:
+       case SOUND_PCM_READ_FILTER:
                return -EINVAL;
-
+               
        }
        return -EINVAL;
 }
@@ -2621,74 +2675,74 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
 static int trident_open(struct inode *inode, struct file *file)
 {
        int minor = MINOR(inode->i_rdev);
-       struct trident_card *c = devs;
-       struct trident_state *s = NULL, *sp;
+       struct trident_card *card = devs;
+       struct trident_state *state = NULL, *sp;
        int i;
        unsigned char fmtm = ~0, fmts = 0;
 
-       /*
-        *      Scan the cards and find the channel. We only
-        *      do this at open time so it is ok
-        */
-        
-       while (c!=NULL)
-       {
-               for(i=0;i<NR_DSPS;i++)
-               {
-                       sp=&c->channels[i];
-                       if(sp->dev_audio < 0)
+       /* Scan the cards and find the channel. 
+          We only do this at open time so it is ok */
+       while (card != NULL) {
+               for (i = 0; i < NR_DSPS; i++) {
+                       sp = &card->channels[i];
+                       if (sp->dev_audio < 0)
                                continue;
-                       if((sp->dev_audio ^ minor) & ~0xf)
+                       if ((sp->dev_audio ^ minor) & ~0xf)
                                continue;
-                       s=sp;
+                       state = sp;
                }
-               c=c->next;
+               card = card->next;
        }
-               
-       if (!s)
+
+       if (!state)
                return -ENODEV;
-               
-       VALIDATE_STATE(s);
-       file->private_data = s;
-       /* wait for device to become free */
-       down(&s->open_sem);
-       while (s->open_mode & file->f_mode) 
-       {
-               if (file->f_flags & O_NONBLOCK) 
-               {
-                       up(&s->open_sem);
+
+       VALIDATE_STATE(state);
+       file->private_data = state;
+
+       down(&state->open_sem);
+
+       while (state->open_mode & file->f_mode) {
+               /* the channel has been open for the same mode before */
+               if (file->f_flags & O_NONBLOCK) {
+                       /* Non-blocking mode, return immediately */
+                       up(&state->open_sem);
                        return -EWOULDBLOCK;
                }
-               up(&s->open_sem);
-               interruptible_sleep_on(&s->open_wait);
+               up(&state->open_sem);
+               /* blocking, wait for device to become free */
+               interruptible_sleep_on(&state->open_wait);
                if (signal_pending(current))
                        return -ERESTARTSYS;
-               down(&s->open_sem);
+               down(&state->open_sem);
        }
-       if (file->f_mode & FMODE_READ) 
-       {
-/*
-               fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT);
+
+       if (file->f_mode & FMODE_READ) {
+               /* fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT);
                if ((minor & 0xf) == SND_DEV_DSP16)
                        fmts |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT; */
 
                fmtm = (TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT;
 
-               s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
-               trident_set_adc_rate(s, 8000, 0);
+               state->dma_adc.ossfragshift = 0;
+               state->dma_adc.ossmaxfrags  = 0;
+               state->dma_adc.subdivision  = 0;
+               trident_set_adc_rate(state, 8000, 0);
        }
-       if (file->f_mode & FMODE_WRITE) 
-       {
+       if (file->f_mode & FMODE_WRITE) {
                fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_DAC_SHIFT);
                if ((minor & 0xf) == SND_DEV_DSP16)
                        fmts |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
-               s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
-               trident_set_dac_rate(s, 8000, 1);
+               state->dma_dac.ossfragshift = 0;
+               state->dma_dac.ossmaxfrags  = 0;
+               state->dma_dac.subdivision  = 0;
+               trident_set_dac_rate(state, 8000, 1);
        }
-       set_fmt(s, fmtm, fmts);
-       s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+       set_fmt(state, fmtm, fmts);
+       state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+
+       up(&state->open_sem);
 
-       up(&s->open_sem);
        //FIXME put back in
        //MOD_INC_USE_COUNT;
        return 0;
@@ -2696,27 +2750,28 @@ static int trident_open(struct inode *inode, struct file *file)
 
 static int trident_release(struct inode *inode, struct file *file)
 {
-       struct trident_state *s = (struct trident_state *)file->private_data;
+       struct trident_state *state = (struct trident_state *)file->private_data;
 
-       VALIDATE_STATE(s);
+       VALIDATE_STATE(state);
        if (file->f_mode & FMODE_WRITE)
-               drain_dac(s, file->f_flags & O_NONBLOCK);
-       down(&s->open_sem);
+               drain_dac(state, file->f_flags & O_NONBLOCK);
+
+       /* stop DMA state machine and free DMA buffers */
+       down(&state->open_sem);
        if (file->f_mode & FMODE_WRITE) {
-               stop_dac(s);
+               stop_dac(state);
+               dealloc_dmabuf(&state->dma_dac);
        }
        if (file->f_mode & FMODE_READ) {
-               stop_adc(s);
+               stop_adc(state);
+               dealloc_dmabuf(&state->dma_adc);
        }
-
-       /* free our shared dma buffers */
-       dealloc_dmabuf(&s->dma_adc);
-       dealloc_dmabuf(&s->dma_dac);
-               
-       s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+       state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
        /* we're covered by the open_sem */
-       up(&s->open_sem);
-       wake_up(&s->open_wait);
+       up(&state->open_sem);
+
+       wake_up(&state->open_wait);
+
        //FIXME put back in
        //MOD_DEC_USE_COUNT;
        return 0;
@@ -2726,31 +2781,31 @@ static /*const*/ struct file_operations trident_audio_fops = {
        &trident_llseek,
        &trident_read,
        &trident_write,
-       NULL,  /* readdir */
+       NULL,   /* readdir */
        &trident_poll,
        &trident_ioctl,
        NULL,   /* XXX &trident_mmap, */
        &trident_open,
        NULL,   /* flush */
        &trident_release,
-       NULL,  /* fsync */
-       NULL,  /* fasync */
-       NULL,  /* check_media_change */
-       NULL,  /* revalidate */
-       NULL,  /* lock */
+       NULL,   /* fsync */
+       NULL,   /* fasync */
+       NULL,   /* check_media_change */
+       NULL,   /* revalidate */
+       NULL,   /* lock */
 };
 
 #ifdef CONFIG_APM
 int trident_apm_callback(apm_event_t ae) {
+       return 0;
 }
 #endif
 
 /* --------------------------------------------------------------------- */
 
-static int trident_install(struct pci_dev *pcidev, int card_type)
+static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
 {
        u16 w;
-       u32 l;
        unsigned long iobase;
        int i;
        struct trident_card *card;
@@ -2760,16 +2815,16 @@ static int trident_install(struct pci_dev *pcidev, int card_type)
        
        iobase = pcidev->resource[0].start;
        
-       if(check_region(iobase, 256))
-       {
-               M_printk(KERN_WARNING "(trident) can't allocate 256 bytes I/O at 0x%4.4lx\n", iobase);
+       if(check_region(iobase, 256)) {
+               printk(KERN_WARNING "trident: can't allocate I/O space at 0x%4.4lx\n",
+                      iobase);
                return 0;
        }
 
        /* this was tripping up some machines */
-       if(pcidev->irq == 0) 
-       {
-               printk(KERN_WARNING "(trident) pci subsystem reports irq 0, this might not be correct.\n");
+       if (pcidev->irq == 0) {
+               printk(KERN_WARNING "trident: pci subsystem reports irq 0,"
+                      " this might not be correct.\n");
        }
 
        /* just to be sure */
@@ -2778,79 +2833,62 @@ static int trident_install(struct pci_dev *pcidev, int card_type)
        pci_read_config_word(pcidev, PCI_COMMAND, &w);
        if((w&(PCI_COMMAND_IO|PCI_COMMAND_MASTER)) != (PCI_COMMAND_IO|PCI_COMMAND_MASTER))
        {
-               printk("(trident) BIOS did not enable I/O access.\n");
+               printk(KERN_WARNING "trident: BIOS did not enable I/O access.\n");
                w|=PCI_COMMAND_IO|PCI_COMMAND_MASTER;
-               pci_write_config_word(pcidev, PCI_COMMAND,w);
+               pci_write_config_word(pcidev, PCI_COMMAND, w);
        }
-
+       
        card = kmalloc(sizeof(struct trident_card), GFP_KERNEL);
 
-       if(card == NULL)
-       {
-               printk(KERN_WARNING "(trident) out of memory\n");
+       if (card == NULL) {
+               printk(KERN_WARNING "trident: out of memory\n");
                return 0;
        }
        
        memset(card, 0, sizeof(*card));
 
 #ifdef CONFIG_APM
-       printk("(trident) apm_reg_callback: %d\n",apm_register_callback(trident_apm_callback));
+       printk("trident: apm_reg_callback: %d\n",
+              apm_register_callback(trident_apm_callback));
 #endif
 
        card->iobase = iobase;
-       card->card_type = card_type;
+       card->pci_info = pci_info;
+       card->pci_id = pci_info->device;
        card->irq = pcidev->irq;
        card->next = devs;
        card->magic = TRIDENT_CARD_MAGIC;
        devs = card;
 
        ChanDwordCount = card->ChanDwordCount = 2;
-       card->ChanPCM = 32;
 
        card->ChRegs.lpChStart = card->ChRegs.data;
        card->ChRegs.lpChStop = card->ChRegs.lpChStart + ChanDwordCount;
        card->ChRegs.lpChAint = card->ChRegs.lpChStop + ChanDwordCount;
        card->ChRegs.lpChAinten = card->ChRegs.lpChAint + ChanDwordCount;
+
        card->ChRegs.lpAChStart = card->ChRegs.lpChAinten + ChanDwordCount;
        card->ChRegs.lpAChStop = card->ChRegs.lpAChStart + ChanDwordCount;
        card->ChRegs.lpAChAint = card->ChRegs.lpAChStop + ChanDwordCount;
        card->ChRegs.lpAChAinten = card->ChRegs.lpAChAint + ChanDwordCount;
-       // Assign addresses.
+
+       // Assign Bank A addresses.
        card->ChRegs.lpAChStart[0] = T4D_START_A;
        card->ChRegs.lpAChStop[0] = T4D_STOP_A;
        card->ChRegs.lpAChAint[0] = T4D_AINT_A;
        card->ChRegs.lpAChAinten[0] = T4D_AINTEN_A;
-
-
+       /* Assign Bank B addresses */
        card->ChRegs.lpAChStart[1] = T4D_START_B;
        card->ChRegs.lpAChStop[1] = T4D_STOP_B;
        card->ChRegs.lpAChAint[1] = T4D_AINT_B;
        card->ChRegs.lpAChAinten[1] = T4D_AINTEN_B;
-       
 
        outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
-       trident_ac97_set(card, 0x0L  , 0L);
-       trident_ac97_set(card, 0x02L , 0L);
-       trident_ac97_set(card, 0x18L , 0L);
+       
 
-       if(card->card_type == TYPE_4DWAVE_NX)
-       {
-       // Enable rear channels
-               outl(0x12, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
-                               // ...or not, since they sound ugly. :)
-                               // outl(0x02, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
-       // S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled
-       // outl(0x200004, TRID_REG(card, NX_SPCSTATUS));
-       // Disable S/PDIF out, 48khz only from ac97 fifo
-               // outb(0x00, TRID_REG(card, NX_SPCTRL_SPCSO + 3));
-       }
-       else 
-       {
-               outl(0x02, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
-       }
-                                                                                                                                                                               
-       for(i=0;i<NR_DSPS;i++)
-       {
+       spin_lock_init(&card->lock);
+       
+       for (i = 0; i < NR_DSPS; i++) {
                struct trident_state *s=&card->channels[i];
 
                s->card = card;
@@ -2859,99 +2897,80 @@ static int trident_install(struct pci_dev *pcidev, int card_type)
                init_waitqueue_head(&s->open_wait);
                init_MUTEX(&s->open_sem);
                s->magic = TRIDENT_STATE_MAGIC;
-               s->channel = i;         
+               s->channel = i;
 
                if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
-                       printk("(trident) BOTCH!\n");
-               
+                       printk(KERN_ERR "trident: BOTCH!\n");
+
                /*
                 *      Now allocate the hardware resources
                 */
-               
+
                //s->dma_dac.chan[0] = AllocateChannelPCM(card);
-               s->dma_dac.chan[1] = AllocateChannelPCM(card);
                //s->dma_adc.chan[0] = AllocateChannelPCM(card);
-               
+               s->dma_dac.chan[1] = trident_alloc_pcm_channel(card);
                /* register devices */
                if ((s->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0)
                        break;
        }
-       
+
        num = i;
-       
+
        /* clear the rest if we ran out of slots to register */
-       for(;i<NR_DSPS;i++)
-       {
+       for (;i < NR_DSPS; i++){
                struct trident_state *s=&card->channels[i];
                s->dev_audio = -1;
        }
-       
+
        trident = &card->channels[0];
 
        /*
         *      Ok card ready. Begin setup proper
         */
 
-       printk(KERN_INFO "(trident) Configuring %s found at IO 0x%04lX IRQ %d\n", 
-               card_names[card_type],card->iobase,card->irq);
+       printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n", 
+              card->pci_info->name, card->iobase, card->irq);
 
 
        /* stake our claim on the iospace */
-       request_region(iobase, 256, card_names[card_type]);
-       
-       /*
-        *      Reset the CODEC
-        */
-        
+       request_region(iobase, 256, card->pci_info->name);
+
        trident_ac97_init(card);
 
-       if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) 
-       {
-               printk("(trident) couldn't register mixer!\n");
+       if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) {
+               printk(KERN_ERR "trident: couldn't register mixer!\n");
        } 
-       else 
-       {
+       else {
                int i;
-               for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) 
-               {
+               for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {
                        struct mixer_defaults *md = &mixer_defaults[i];
 
-                       if(md->mixer == -1) 
+                       if (md->mixer == -1) 
                                break;
-                       if(!supported_mixer(card,md->mixer)) 
+                       if (!supported_mixer(card, md->mixer)) 
                                continue;
-                       set_mixer(card,md->mixer,md->value);
+                       set_mixer(card, md->mixer, md->value);
                }
        }
-       
-       if(request_irq(card->irq, trident_interrupt, SA_SHIRQ, card_names[card_type], card))
-       {
-               printk(KERN_ERR "(trident) unable to allocate irq %d,\n", card->irq);
+
+       if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card->pci_info->name, card)) {
+               printk(KERN_ERR "trident: unable to allocate irq %d,\n", card->irq);
                unregister_sound_mixer(card->dev_mixer);
-               for(i=0;i<NR_DSPS;i++)
-               {
+               for (i = 0; i < NR_DSPS; i++) {
                        struct trident_state *s = &card->channels[i];
                        if(s->dev_audio != -1)
                                unregister_sound_dsp(s->dev_audio);
                }
-               release_region(card->iobase, 256);              
+               release_region(card->iobase, 256);
                kfree(card);
                return 0;
        }
 
-       init_timer(&debug_timer);       
-       debug_timer.function = trident_kick;
-       debug_timer.data = (unsigned long)card;
-       debug_timer.expires = jiffies+1;
-       
-//     add_timer(&debug_timer);
-
-       printk("(trident) %d channels configured.\n", num);
-
-       EnableEndInterrupts(card);
+       trident_enable_end_interrupts(card);
        return 1; 
 }
 
+
 #ifdef MODULE
 int init_module(void)
 #else
@@ -2960,34 +2979,24 @@ int __init init_trident(void)
 {
        struct pci_dev *pcidev = NULL;
        int foundone = 0;
+       int i;
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "(trident) version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n");
-
-       pcidev = NULL;
 
-       /*
-        *      Find the 4DWave DX
-        */
-
-       while( (pcidev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, pcidev))!=NULL
-                       &&
-               ( trident_install(pcidev, TYPE_4DWAVE_DX) )) {
-                       foundone=1;
-       }
-
-       /*
-        *      Find the 4DWave NX
-        */
+       printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
+              DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
-       while((pcidev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, pcidev))!=NULL
-                       &&
-               ( trident_install(pcidev, TYPE_4DWAVE_NX) )) {
-                       foundone=1;
+       for (i = 0; i < sizeof (pci_audio_devices); i++) {
+               pcidev = NULL;
+               while ((pcidev = pci_find_device(pci_audio_devices[i].vendor,
+                                                pci_audio_devices[i].device,
+                                                pcidev)) != NULL) {
+                       foundone += trident_install(pcidev, pci_audio_devices + i);
+               }
        }
 
-       if( ! foundone )
+       if (!foundone)
                return -ENODEV;
        return 0;
 }
@@ -2997,44 +3006,33 @@ int __init init_trident(void)
 #ifdef MODULE
 
 MODULE_AUTHOR("Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("Trident 4DWave Driver");
-#ifdef M_DEBUG
+MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
+#ifdef DEBUG
 MODULE_PARM(debug,"i");
 #endif
 
 void cleanup_module(void)
 {
-       struct trident_card *s;
-
 #ifdef CONFIG_APM
        apm_unregister_callback(trident_apm_callback);
 #endif
 
-       del_timer(&debug_timer);
-       
-       while ((s = devs)) {
+       while (devs != NULL) {
                int i;
-               devs = devs->next;
-               
-               
+
                /* Kill interrupts, and SP/DIF */
-               
-               DisableEndInterrupts(s);
-               if(s->card_type == TYPE_4DWAVE_NX)
-                       outb(0x00, TRID_REG(s, NX_SPCTRL_SPCSO+3));
-       
-               free_irq(s->irq, s);
-               unregister_sound_mixer(s->dev_mixer);
-               for(i=0;i<NR_DSPS;i++)
-               {
-                       struct trident_state *trident = &s->channels[i];
-                       if(trident->dev_audio != -1)
+               trident_disable_end_interrupts(devs);
+               free_irq(devs->irq, devs);
+               unregister_sound_mixer(devs->dev_mixer);
+               for (i = 0; i < NR_DSPS; i++) {
+                       struct trident_state *trident = &devs->channels[i];
+                       if (trident->dev_audio != -1)
                                unregister_sound_dsp(trident->dev_audio);
                }
-               release_region(s->iobase, 256);
-               kfree(s);
+               release_region(devs->iobase, 256);
+               kfree(devs);
+               devs = devs->next;
        }
-       printk("(trident) unloading\n");
 }
 
 #endif /* MODULE */
index 0922cec355f42595b04c7322b90a0d428455c834..f283793d100425174b60b7eeeda4821f6ac88a1e 100644 (file)
  */
 
 #ifndef PCI_VENDOR_ID_TRIDENT
-#define PCI_VENDOR_ID_TRIDENT          0x1023
+#define PCI_VENDOR_ID_TRIDENT          0x1023
 #endif
-#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 
-#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
+
+#ifndef PCI_VENDOR_ID_SI
+#define PCI_VENDOR_ID_SI                       0x0139
 #endif
-#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 
-#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
+
+#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX        0x2000
+#endif
+
+#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_NX
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX        0x2001
+#endif
+
+#ifndef PCI_DEVICE_ID_SI_7018
+#define PCI_DEVICE_ID_SI_7018          0x7018
 #endif
 
 /*
 
 #define TRID_REG( trident, x ) ( (trident) -> iobase + (x) )
 
-#define CHANNEL_REGS    5
-#define CHANNEL_START   0xe0   // The first bytes of the contiguous register space.
+#define CHANNEL_REGS   5
+#define CHANNEL_START  0xe0   // The first bytes of the contiguous register space.
 
-#define ID_4DWAVE_DX        0x2000
-#define ID_4DWAVE_NX        0x2001
+#define BANK_A 0
+#define BANK_B 1
+#define NUM_BANKS 2
 
+#define ID_4DWAVE_DX   0x2000
+#define ID_4DWAVE_NX   0x2001
+#define ID_SI_7018     0x7018
 
 // Register definitions
 
 // Global registers
 
 // T2 legacy dma control registers.
-#define LEGACY_DMAR0                0x00  // ADR0
-#define LEGACY_DMAR4                0x04  // CNT0
-#define LEGACY_DMAR11               0x0b  // MOD 
-#define LEGACY_DMAR15               0x0f  // MMR 
-
-#define T4D_START_A                 0x80
-#define T4D_STOP_A                  0x84
-#define T4D_DLY_A                   0x88
-#define T4D_SIGN_CSO_A              0x8c
-#define T4D_CSPF_A                  0x90
-#define T4D_CEBC_A                  0x94
-#define T4D_AINT_A                  0x98
-#define T4D_AINTEN_A                0x9c
-#define T4D_LFO_GC_CIR               0xa0
-#define T4D_MUSICVOL_WAVEVOL         0xa8
-#define T4D_SBDELTA_DELTA_R          0xac
-#define T4D_MISCINT                  0xb0
-#define T4D_START_B                  0xb4
-#define T4D_STOP_B                   0xb8
-#define T4D_SBBL_SBCL                0xc0
-#define T4D_SBCTRL_SBE2R_SBDD        0xc4
-#define T4D_AINT_B                   0xd8
-#define T4D_AINTEN_B                 0xdc
+#define LEGACY_DMAR0           0x00  // ADR0
+#define LEGACY_DMAR4           0x04  // CNT0
+#define LEGACY_DMAR11          0x0b  // MOD 
+#define LEGACY_DMAR15          0x0f  // MMR 
+
+#define T4D_START_A            0x80
+#define T4D_STOP_A             0x84
+#define T4D_DLY_A                      0x88
+#define T4D_SIGN_CSO_A         0x8c
+#define T4D_CSPF_A             0x90
+#define T4D_CEBC_A             0x94
+#define T4D_AINT_A             0x98
+#define T4D_EINT_A             0x9c
+#define T4D_LFO_GC_CIR         0xa0
+#define T4D_AINTEN_A           0xa4
+#define T4D_MUSICVOL_WAVEVOL   0xa8
+#define T4D_SBDELTA_DELTA_R    0xac
+#define T4D_MISCINT            0xb0
+#define T4D_START_B            0xb4
+#define T4D_STOP_B             0xb8
+#define T4D_CSPF_B             0xbc
+#define T4D_SBBL_SBCL          0xc0
+#define T4D_SBCTRL_SBE2R_SBDD  0xc4
+#define T4D_STIMER             0xc8
+#define T4D_LFO_B_I2S_DELTA    0xcc
+#define T4D_AINT_B             0xd8
+#define T4D_AINTEN_B           0xdc
 
 // MPU-401 UART
-#define T4D_MPU401_BASE             0x20
-#define T4D_MPUR0                   0x20
-#define T4D_MPUR1                   0x21
-#define T4D_MPUR2                   0x22
-#define T4D_MPUR3                   0x23
+#define T4D_MPU401_BASE                0x20
+#define T4D_MPUR0                      0x20
+#define T4D_MPUR1                      0x21
+#define T4D_MPUR2                      0x22
+#define T4D_MPUR3                      0x23
 
 // S/PDIF Registers
-#define NX_SPCTRL_SPCSO             0x24
-#define NX_SPLBA                    0x28
-#define NX_SPESO                    0x2c
-#define NX_SPCSTATUS                0x64
+#define NX_SPCTRL_SPCSO                0x24
+#define NX_SPLBA                       0x28
+#define NX_SPESO                       0x2c
+#define NX_SPCSTATUS           0x64
 
 // Channel Registers
 
-#define CH_DX_CSO_ALPHA_FMS         0xe0
-#define CH_DX_ESO_DELTA             0xe8
-#define CH_DX_FMC_RVOL_CVOL         0xec
+#define CH_DX_CSO_ALPHA_FMS    0xe0
+#define CH_DX_ESO_DELTA                0xe8
+#define CH_DX_FMC_RVOL_CVOL    0xec
 
-#define CH_NX_DELTA_CSO             0xe0
-#define CH_NX_DELTA_ESO             0xe8
+#define CH_NX_DELTA_CSO                0xe0
+#define CH_NX_DELTA_ESO                0xe8
 #define CH_NX_ALPHA_FMS_FMC_RVOL_CVOL 0xec
 
-#define CH_LBA                      0xe4
-#define CH_GVSEL_PAN_VOL_CTRL_EC    0xf0
+#define CH_LBA                 0xe4
+#define CH_GVSEL_PAN_VOL_CTRL_EC       0xf0
 
 // AC-97 Registers
 
-#define DX_ACR0_AC97_W              0x40
-#define DX_ACR1_AC97_R              0x44
-#define DX_ACR2_AC97_COM_STAT       0x48
-
-#define NX_ACR0_AC97_COM_STAT       0x40
-#define NX_ACR1_AC97_W              0x44
-#define NX_ACR2_AC97_R_PRIMARY      0x48
-#define NX_ACR3_AC97_R_SECONDARY    0x4c
-
-#define AC97_SIGMATEL_DAC2INVERT    0x6E
-#define AC97_SIGMATEL_BIAS1         0x70
-#define AC97_SIGMATEL_BIAS2         0x72
-#define AC97_SIGMATEL_CIC1          0x76
-#define AC97_SIGMATEL_CIC2          0x78
-
-#endif                         /* __TRID4DWAVE_H */
+#define DX_ACR0_AC97_W         0x40
+#define DX_ACR1_AC97_R         0x44
+#define DX_ACR2_AC97_COM_STAT  0x48
+
+#define NX_ACR0_AC97_COM_STAT  0x40
+#define NX_ACR1_AC97_W         0x44
+#define NX_ACR2_AC97_R_PRIMARY 0x48
+#define NX_ACR3_AC97_R_SECONDARY       0x4c
+
+#define SI_AC97_WRITE          0x40
+#define SI_AC97_READ           0x44
+#define SI_SERIAL_INTF_CTRL    0x48
+#define SI_AC97_GPIO           0x4c
+
+#define AC97_SIGMATEL_DAC2INVERT       0x6E
+#define AC97_SIGMATEL_BIAS1    0x70
+#define AC97_SIGMATEL_BIAS2    0x72
+#define AC97_SIGMATEL_CIC1     0x76
+#define AC97_SIGMATEL_CIC2     0x78
+
+#define SI_AC97_BUSY_WRITE 0x8000
+#define SI_AC97_AUDIO_BUSY 0x4000
+#define DX_AC97_BUSY_WRITE 0x8000
+#define NX_AC97_BUSY_WRITE 0x0800
+#define SI_AC97_BUSY_READ  0x8000
+#define DX_AC97_BUSY_READ 0x8000
+#define NX_AC97_BUSY_READ 0x0800
+#define AC97_REG_ADDR      0x000000ff
+#define DX_AC97_REG_ADDR   0x000000ff
+#define NX_AC97_REG_ADDR   0x000000ff
+
+enum global_control_bits {
+       CHANNLE_IDX = 0x0000003f, PB_RESET   = 0x00000100,
+       PAUSE_ENG   = 0x00000200,
+       OVERRUN_IE  = 0x00000400, UNDERRUN_IE = 0x00000800,
+       ENDLP_IE    = 0x00001000, MIDLP_IE   = 0x00002000,
+       ETOG_IE     = 0x00004000,
+       EDROP_IE    = 0x00008000, BANK_B_EN  = 0x00010000
+};
+
+enum miscint_bits {
+       PB_UNDERRUN_IRO = 0x00000001, REC_OVERRUN_IRQ = 0x00000002,
+       SB_IRQ          = 0x00000004, MPU401_IRQ      = 0x00000008,
+       OPL3_IRQ        = 0x00000010, ADDRESS_IRQ     = 0x00000020,
+       ENVELOPE_IRQ    = 0x00000040, ST_IRQ          = 0x00000080,
+       PB_UNDERRUN     = 0x00000100, REC_OVERRUN     = 0x00000200,
+       MIXER_UNDERFLOW = 0x00000400, MIXER_OVERFLOW  = 0x00000800,
+       ST_TARGET_REACHED = 0x00008000, PB_24K_MODE   = 0x00010000, 
+       ST_IRQ_EN       = 0x00800000, ACGPIO_IRQ      = 0x01000000
+};
+
+#define IWriteAinten( x ) \
+       {int i; \
+        for( i= 0; i < ChanDwordCount; i++) \
+               outl((x)->lpChAinten[i], TRID_REG(trident, (x)->lpAChAinten[i]));}
+
+#define IReadAinten( x ) \
+       {int i; \
+        for( i= 0; i < ChanDwordCount; i++) \
+        (x)->lpChAinten[i] = inl(TRID_REG(trident, (x)->lpAChAinten[i]));}
+
+#define ReadAint( x ) \
+       IReadAint( x ) 
+
+#define WriteAint( x ) \
+       IWriteAint( x ) 
+
+#define IWriteAint( x ) \
+       {int i; \
+        for( i= 0; i < ChanDwordCount; i++) \
+        outl((x)->lpChAint[i], TRID_REG(trident, (x)->lpAChAint[i]));}
+
+#define IReadAint( x ) \
+       {int i; \
+        for( i= 0; i < ChanDwordCount; i++) \
+        (x)->lpChAint[i] = inl(TRID_REG(trident, (x)->lpAChAint[i]));}
+
+#define VALIDATE_MAGIC(FOO,MAG)                                \
+({                                               \
+       if (!(FOO) || (FOO)->magic != MAG) { \
+               printk(invalid_magic,__FUNCTION__);            \
+               return -ENXIO;                    \
+       }                                         \
+})
+
+#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
+#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
+
+#endif /* __TRID4DWAVE_H */
 
diff --git a/drivers/telephony/Config.in b/drivers/telephony/Config.in
new file mode 100644 (file)
index 0000000..84b18c8
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Telephony device configuration
+#
+mainmenu_option next_comment
+comment 'Telephony Support'
+
+tristate 'Linux telephony support' CONFIG_PHONE
+dep_tristate 'QuickNet Internet LineJack/PhoneJack support' CONFIG_PHONE_IXJ $CONFIG_PHONE
+endmenu
diff --git a/drivers/telephony/Makefile b/drivers/telephony/Makefile
new file mode 100644 (file)
index 0000000..517200a
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# Makefile for the kernel miscellaneous drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := telephony.a
+MX_OBJS  :=
+M_OBJS  :=
+
+ifeq ($(CONFIG_PHONE),y)
+  LX_OBJS += phonedev.o
+else
+  ifeq ($(CONFIG_PHONE),m)
+    MX_OBJS += phonedev.o
+  endif
+endif
+
+ifeq ($(CONFIG_PHONE_IXJ),y)
+  L_OBJS += ixj.o
+else 
+  ifeq ($(CONFIG_PHONE_IXJ),m)
+    M_OBJS += ixj.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
new file mode 100644 (file)
index 0000000..6065dbc
--- /dev/null
@@ -0,0 +1,7517 @@
+/*
+ *    ixj.c
+ *
+ *    Device Driver for the Internet PhoneJACK and
+ *    Internet LineJACK Telephony Cards.
+ *
+ *    (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License
+ *    as published by the Free Software Foundation; either version
+ *    2 of the License, or (at your option) any later version.
+ *
+ * Author:          Ed Okerson, <eokerson@quicknet.net>
+ *    
+ * Contributors:    Greg Herlein, <gherlein@quicknet.net>
+ *                  David W. Erhart, <derhart@quicknet.net>
+ *                  John Sellers, <jsellers@quicknet.net>
+ *                  Mike Preston, <mpreston@quicknet.net>
+ *
+ * Fixes:
+ *
+ *     2.3.x port      :               Alan Cox
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website:    http://www.quicknet.net
+ *
+ */
+
+static char ixj_c_rcsid[] = "$Id: ixj.c,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+//#define PERFMON_STATS
+#define IXJDEBUG 0
+#define MAXRINGS 5
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>      /* printk() */
+#include <linux/fs.h>          /* everything... */
+#include <linux/errno.h>       /* error codes */
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_ISAPNP
+#include <linux/isapnp.h>
+#endif
+
+#include "ixj.h"
+
+#define TYPE(dev) (MINOR(dev) >> 4)
+#define NUM(dev) (MINOR(dev) & 0xf)
+
+static int ixjdebug = 0;
+static int hertz = HZ;
+static int samplerate = 100;
+
+MODULE_PARM(ixjdebug, "i");
+
+static IXJ ixj[IXJMAX];
+
+static struct timer_list ixj_timer;
+
+int ixj_convert_loaded = 0;
+
+/************************************************************************
+*
+* These are function definitions to allow external modules to register
+* enhanced functionality call backs.
+*
+************************************************************************/
+
+static int Stub(IXJ * J, unsigned long arg)
+{
+       return 0;
+}
+
+static IXJ_REGFUNC ixj_DownloadG729 = &Stub;
+static IXJ_REGFUNC ixj_DownloadTS85 = &Stub;
+static IXJ_REGFUNC ixj_PreRead = &Stub;
+static IXJ_REGFUNC ixj_PostRead = &Stub;
+static IXJ_REGFUNC ixj_PreWrite = &Stub;
+static IXJ_REGFUNC ixj_PostWrite = &Stub;
+static IXJ_REGFUNC ixj_PreIoctl = &Stub;
+static IXJ_REGFUNC ixj_PostIoctl = &Stub;
+
+static void ixj_read_frame(int board);
+static void ixj_write_frame(int board);
+static void ixj_init_timer(void);
+static void ixj_add_timer(void);
+static void ixj_del_timer(void);
+static void ixj_timeout(unsigned long ptr);
+static int read_filters(int board);
+static int LineMonitor(int board);
+static int ixj_fasync(int fd, struct file *, int mode);
+static int ixj_hookstate(int board);
+static int ixj_record_start(int board);
+static void ixj_record_stop(int board);
+static int ixj_play_start(int board);
+static void ixj_play_stop(int board);
+static int ixj_set_tone_on(unsigned short arg, int board);
+static int ixj_set_tone_off(unsigned short, int board);
+static int ixj_play_tone(int board, char tone);
+static int idle(int board);
+static void ixj_ring_on(int board);
+static void ixj_ring_off(int board);
+static void aec_stop(int board);
+static void ixj_ringback(int board);
+static void ixj_busytone(int board);
+static void ixj_dialtone(int board);
+static void ixj_cpt_stop(int board);
+static char daa_int_read(int board);
+static int daa_set_mode(int board, int mode);
+static int ixj_linetest(int board);
+static int ixj_daa_cid_read(int board);
+static void DAA_Coeff_US(int board);
+static void DAA_Coeff_UK(int board);
+static void DAA_Coeff_France(int board);
+static void DAA_Coeff_Germany(int board);
+static void DAA_Coeff_Australia(int board);
+static void DAA_Coeff_Japan(int board);
+static int ixj_init_filter(int board, IXJ_FILTER * jf);
+static int ixj_init_tone(int board, IXJ_TONE * ti);
+static int ixj_build_cadence(int board, IXJ_CADENCE * cp);
+// Serial Control Interface funtions
+static int SCI_Control(int board, int control);
+static int SCI_Prepare(int board);
+static int SCI_WaitHighSCI(int board);
+static int SCI_WaitLowSCI(int board);
+static DWORD PCIEE_GetSerialNumber(WORD wAddress);
+
+/************************************************************************
+CT8020/CT8021 Host Programmers Model
+Host address   Function                                        Access
+DSPbase +
+0-1            Aux Software Status Register (reserved)         Read Only
+2-3            Software Status Register                        Read Only
+4-5            Aux Software Control Register (reserved)        Read Write
+6-7            Software Control Register                       Read Write
+8-9            Hardware Status Register                        Read Only
+A-B            Hardware Control Register                       Read Write
+C-D Host Transmit (Write) Data Buffer Access Port (buffer input)Write Only
+E-F Host Recieve (Read) Data Buffer Access Port (buffer input) Read Only
+************************************************************************/
+
+extern __inline__ void ixj_read_HSR(int board)
+{
+       ixj[board].hsr.bytes.low = inb_p(ixj[board].DSPbase + 8);
+       ixj[board].hsr.bytes.high = inb_p(ixj[board].DSPbase + 9);
+}
+extern __inline__ int IsControlReady(int board)
+{
+       ixj_read_HSR(board);
+       return ixj[board].hsr.bits.controlrdy ? 1 : 0;
+}
+
+extern __inline__ int IsStatusReady(int board)
+{
+       ixj_read_HSR(board);
+       return ixj[board].hsr.bits.statusrdy ? 1 : 0;
+}
+
+extern __inline__ int IsRxReady(int board)
+{
+       ixj_read_HSR(board);
+       return ixj[board].hsr.bits.rxrdy ? 1 : 0;
+}
+
+extern __inline__ int IsTxReady(int board)
+{
+       ixj_read_HSR(board);
+       return ixj[board].hsr.bits.txrdy ? 1 : 0;
+}
+
+extern __inline__ BYTE SLIC_GetState(int board)
+{
+       IXJ *j = &ixj[board];
+
+       j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01);
+
+       return j->pld_slicr.bits.state;
+}
+
+static BOOL SLIC_SetState(BYTE byState, int board)
+{
+       BOOL fRetVal = FALSE;
+       IXJ *j = &ixj[board];
+
+       // Set the C1, C2, C3 & B2EN signals.
+       switch (byState) {
+       case PLD_SLIC_STATE_OC:
+               j->pld_slicw.bits.c1 = 0;
+               j->pld_slicw.bits.c2 = 0;
+               j->pld_slicw.bits.c3 = 0;
+               j->pld_slicw.bits.b2en = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               fRetVal = TRUE;
+               break;
+       case PLD_SLIC_STATE_RINGING:
+               j->pld_slicw.bits.c1 = 1;
+               j->pld_slicw.bits.c2 = 0;
+               j->pld_slicw.bits.c3 = 0;
+               j->pld_slicw.bits.b2en = 1;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               fRetVal = TRUE;
+               break;
+       case PLD_SLIC_STATE_ACTIVE:
+               j->pld_slicw.bits.c1 = 0;
+               j->pld_slicw.bits.c2 = 1;
+               j->pld_slicw.bits.c3 = 0;
+               j->pld_slicw.bits.b2en = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               fRetVal = TRUE;
+               break;
+       case PLD_SLIC_STATE_OHT:        // On-hook transmit
+
+               j->pld_slicw.bits.c1 = 1;
+               j->pld_slicw.bits.c2 = 1;
+               j->pld_slicw.bits.c3 = 0;
+               j->pld_slicw.bits.b2en = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               fRetVal = TRUE;
+               break;
+       case PLD_SLIC_STATE_TIPOPEN:
+               j->pld_slicw.bits.c1 = 0;
+               j->pld_slicw.bits.c2 = 0;
+               j->pld_slicw.bits.c3 = 1;
+               j->pld_slicw.bits.b2en = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               fRetVal = TRUE;
+               break;
+       case PLD_SLIC_STATE_STANDBY:
+               j->pld_slicw.bits.c1 = 1;
+               j->pld_slicw.bits.c2 = 0;
+               j->pld_slicw.bits.c3 = 1;
+               j->pld_slicw.bits.b2en = 1;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               fRetVal = TRUE;
+               break;
+       case PLD_SLIC_STATE_APR:        // Active polarity reversal
+
+               j->pld_slicw.bits.c1 = 0;
+               j->pld_slicw.bits.c2 = 1;
+               j->pld_slicw.bits.c3 = 1;
+               j->pld_slicw.bits.b2en = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               fRetVal = TRUE;
+               break;
+       case PLD_SLIC_STATE_OHTPR:      // OHT polarity reversal
+
+               j->pld_slicw.bits.c1 = 1;
+               j->pld_slicw.bits.c2 = 1;
+               j->pld_slicw.bits.c3 = 1;
+               j->pld_slicw.bits.b2en = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               fRetVal = TRUE;
+               break;
+       default:
+               fRetVal = FALSE;
+               break;
+       }
+
+       return fRetVal;
+}
+
+int ixj_register(int index, IXJ_REGFUNC regfunc)
+{
+       int cnt;
+       int retval = 0;
+       switch (index) {
+       case G729LOADER:
+               ixj_DownloadG729 = regfunc;
+               for (cnt = 0; cnt < IXJMAX; cnt++)
+                       ixj_DownloadG729(&ixj[cnt], 0L);
+               break;
+       case TS85LOADER:
+               ixj_DownloadTS85 = regfunc;
+               for (cnt = 0; cnt < IXJMAX; cnt++)
+                       ixj_DownloadTS85(&ixj[cnt], 0L);
+               break;
+       case PRE_READ:
+               ixj_PreRead = regfunc;
+               break;
+       case POST_READ:
+               ixj_PostRead = regfunc;
+               break;
+       case PRE_WRITE:
+               ixj_PreWrite = regfunc;
+               break;
+       case POST_WRITE:
+               ixj_PostWrite = regfunc;
+               break;
+       case PRE_IOCTL:
+               ixj_PreIoctl = regfunc;
+               break;
+       case POST_IOCTL:
+               ixj_PostIoctl = regfunc;
+               break;
+       default:
+               retval = 1;
+       }
+       return retval;
+}
+
+int ixj_unregister(int index)
+{
+       int retval = 0;
+       switch (index) {
+       case G729LOADER:
+               ixj_DownloadG729 = &Stub;
+               break;
+       case TS85LOADER:
+               ixj_DownloadTS85 = &Stub;
+               break;
+       case PRE_READ:
+               ixj_PreRead = &Stub;
+               break;
+       case POST_READ:
+               ixj_PostRead = &Stub;
+               break;
+       case PRE_WRITE:
+               ixj_PreWrite = &Stub;
+               break;
+       case POST_WRITE:
+               ixj_PostWrite = &Stub;
+               break;
+       case PRE_IOCTL:
+               ixj_PreIoctl = &Stub;
+               break;
+       case POST_IOCTL:
+               ixj_PostIoctl = &Stub;
+               break;
+       default:
+               retval = 1;
+       }
+       return retval;
+}
+
+static void ixj_init_timer(void)
+{
+       init_timer(&ixj_timer);
+       ixj_timer.function = ixj_timeout;
+       ixj_timer.data = (int) NULL;
+}
+
+static void ixj_add_timer(void)
+{
+       ixj_timer.expires = jiffies + (hertz / samplerate);
+       add_timer(&ixj_timer);
+}
+
+static void ixj_del_timer(void)
+{
+       del_timer(&ixj_timer);
+}
+
+static void ixj_tone_timeout(int board)
+{
+       IXJ *j = &ixj[board];
+       IXJ_TONE ti;
+       
+       j->tone_state++;
+       if (j->tone_state == 3) {
+               j->tone_state = 0;
+               if (j->cadence_t) {
+                       j->tone_cadence_state++;
+                       if (j->tone_cadence_state >= j->cadence_t->elements_used) 
+                       {
+                               switch (j->cadence_t->termination) 
+                               {
+                                       case PLAY_ONCE:
+                                               ixj_cpt_stop(board);
+                                                       break;
+                                       case REPEAT_LAST_ELEMENT:
+                                               j->tone_cadence_state--;
+                                               ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index);
+                                               break;
+                                       case REPEAT_ALL:
+                                               j->tone_cadence_state = 0;
+                                               if (j->cadence_t->ce[j->tone_cadence_state].freq0) 
+                                               {
+                                                       ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+                                                       ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+                                                       ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+                                                       ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+                                                       ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+                                                       ixj_init_tone(board, &ti);
+                                               }
+                                               ixj_set_tone_on(j->cadence_t->ce[0].tone_on_time, board);
+                                               ixj_set_tone_off(j->cadence_t->ce[0].tone_off_time, board);
+                                               ixj_play_tone(board, j->cadence_t->ce[0].index);
+                                               break;
+                               }
+                       } else {
+                               if (j->cadence_t->ce[j->tone_cadence_state].gain0) 
+                               {
+                                       ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+                                       ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+                                       ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+                                       ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+                                       ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+                                       ixj_init_tone(board, &ti);
+                               }
+                               ixj_set_tone_on(j->cadence_t->ce[j->tone_cadence_state].tone_on_time, board);
+                               ixj_set_tone_off(j->cadence_t->ce[j->tone_cadence_state].tone_off_time, board);
+                               ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index);
+                       }
+               }
+       }
+}
+
+static void ixj_timeout(unsigned long ptr)
+{
+       int board;
+       unsigned long jifon;
+       IXJ *j;
+
+       for (board = 0; board < IXJMAX; board++) 
+       {
+               j = &ixj[board];
+
+               if (j->DSPbase) 
+               {
+#ifdef PERFMON_STATS
+                       j->timerchecks++;
+#endif
+                       if (j->tone_state) 
+                       {
+                               if (!ixj_hookstate(board)) 
+                               {
+                                       ixj_cpt_stop(board);
+                                       if (j->m_hook) 
+                                       {
+                                               j->m_hook = 0;
+                                               j->ex.bits.hookstate = 1;
+                                               if (j->async_queue)
+                                                       kill_fasync(j->async_queue, SIGIO, POLL_IN);    // Send apps notice of change
+                                       }
+                                       goto timer_end;
+                               }
+                               if (j->tone_state == 1)
+                                       jifon = (hertz * j->tone_on_time * 25 / 100000);
+                               else
+                                       jifon = (hertz * j->tone_on_time * 25 / 100000) +
+                                           (hertz * j->tone_off_time * 25 / 100000);
+                               if (jiffies < j->tone_start_jif + jifon) {
+                                       if (j->tone_state == 1) {
+                                               ixj_play_tone(board, j->tone_index);
+                                               if (j->dsp.low == 0x20) {
+                                                       goto timer_end;
+                                               }
+                                       } else {
+                                               ixj_play_tone(board, 0);
+                                               if (j->dsp.low == 0x20) {
+                                                       goto timer_end;
+                                               }
+                                       }
+                               } else {
+                                       ixj_tone_timeout(board);
+                                       if (j->flags.dialtone) {
+                                               ixj_dialtone(board);
+                                       }
+                                       if (j->flags.busytone) {
+                                               ixj_busytone(board);
+                                               if (j->dsp.low == 0x20) {
+                                                       goto timer_end;
+                                               }
+                                       }
+                                       if (j->flags.ringback) {
+                                               ixj_ringback(board);
+                                               if (j->dsp.low == 0x20) {
+                                                       goto timer_end;
+                                               }
+                                       }
+                                       if (!j->tone_state) {
+                                               if (j->dsp.low == 0x20 || (j->play_mode == -1 && j->rec_mode == -1))
+                                                       idle(board);
+                                               if (j->dsp.low == 0x20 && j->play_mode != -1)
+                                                       ixj_play_start(board);
+                                               if (j->dsp.low == 0x20 && j->rec_mode != -1)
+                                                       ixj_record_start(board);
+                                       }
+                               }
+                       }
+                       if (!j->tone_state || j->dsp.low != 0x20) {
+                               if (IsRxReady(board)) {
+                                       ixj_read_frame(board);
+                               }
+                               if (IsTxReady(board)) {
+                                       ixj_write_frame(board);
+                               }
+                       }
+                       if (j->flags.cringing) {
+                               if (ixj_hookstate(board) & 1) {
+                                       j->flags.cringing = 0;
+                                       ixj_ring_off(board);
+                               } else {
+                                       if (jiffies - j->ring_cadence_jif >= (.5 * hertz)) {
+                                               j->ring_cadence_t--;
+                                               if (j->ring_cadence_t == -1)
+                                                       j->ring_cadence_t = 15;
+                                               j->ring_cadence_jif = jiffies;
+                                       }
+                                       if (j->ring_cadence & 1 << j->ring_cadence_t) {
+                                               ixj_ring_on(board);
+                                       } else {
+                                               ixj_ring_off(board);
+                                       }
+                                       goto timer_end;
+                               }
+                       }
+                       if (!j->flags.ringing) {
+                               if (ixj_hookstate(board)) {
+                                       if (j->dsp.low == 0x21 &&
+                                           j->pld_slicr.bits.state != PLD_SLIC_STATE_ACTIVE)
+               // Internet LineJACK
+                                       {
+                                               SLIC_SetState(PLD_SLIC_STATE_ACTIVE, board);
+                                       }
+                                       LineMonitor(board);
+                                       read_filters(board);
+                                       ixj_WriteDSPCommand(0x511B, board);
+                                       j->proc_load = j->ssr.high << 8 | j->ssr.low;
+                                       if (!j->m_hook) {
+                                               j->m_hook = j->ex.bits.hookstate = 1;
+                                               if (j->async_queue)
+                                                       kill_fasync(j->async_queue, SIGIO, POLL_IN);    // Send apps notice of change
+                                       }
+                               } else {
+                                       if (j->dsp.low == 0x21 &&
+                                           j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE)
+               // Internet LineJACK
+                                       {
+                                               SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+                                       }
+                                       if (j->ex.bits.dtmf_ready) {
+                                               j->dtmf_wp = j->dtmf_rp = j->ex.bits.dtmf_ready = 0;
+                                       }
+                                       if (j->m_hook) {
+                                               j->m_hook = 0;
+                                               j->ex.bits.hookstate = 1;
+                                               if (j->async_queue)
+                                                       kill_fasync(j->async_queue, SIGIO, POLL_IN);    // Send apps notice of change
+                                       }
+                               }
+                       }
+                       if (j->cardtype == 300) {
+                               if (j->flags.pstn_present) {
+                                       j->pld_scrr.byte = inb_p(j->XILINXbase);
+                                       if (jiffies >= j->pstn_sleeptil && j->pld_scrr.bits.daaflag) {
+                                               daa_int_read(board);
+                                               if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.RING) {
+                                                       if (!j->flags.pstn_ringing) {
+                                                               j->flags.pstn_ringing = 1;
+                                                               if (j->daa_mode != SOP_PU_RINGING)
+                                                                       daa_set_mode(board, SOP_PU_RINGING);
+                                                       }
+                                               }
+                                               if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+                                                       j->pstn_winkstart = 0;
+                                                       if (j->flags.pstn_ringing && !j->pstn_envelope) {
+                                                               j->ex.bits.pstn_ring = 0;
+                                                               j->pstn_envelope = 1;
+                                                               j->pstn_ring_start = jiffies;
+                                                       }
+                                               } else {
+                                                       if (j->flags.pstn_ringing && j->pstn_envelope &&
+                                                           jiffies > j->pstn_ring_start + ((hertz * 15) / 10)) {
+                                                               j->ex.bits.pstn_ring = 1;
+                                                               j->pstn_envelope = 0;
+                                                       } else if (j->daa_mode == SOP_PU_CONVERSATION) {
+                                                               if (!j->pstn_winkstart) {
+                                                                       j->pstn_winkstart = jiffies;
+                                                               } else if (jiffies > j->pstn_winkstart + (hertz * j->winktime / 1000)) {
+                                                                       daa_set_mode(board, SOP_PU_SLEEP);
+                                                                       j->pstn_winkstart = 0;
+                                                                       j->ex.bits.pstn_wink = 1;
+                                                               }
+                                                       } else {
+                                                               j->ex.bits.pstn_ring = 0;
+                                                       }
+                                               }
+                                               if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.Cadence) {
+                                                       if (j->daa_mode == SOP_PU_RINGING) {
+                                                               daa_set_mode(board, SOP_PU_SLEEP);
+                                                               j->flags.pstn_ringing = 0;
+                                                               j->ex.bits.pstn_ring = 0;
+                                                       }
+                                               }
+                                               if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.Caller_ID) {
+                                                       if (j->daa_mode == SOP_PU_RINGING && j->flags.pstn_ringing) {
+                                                               j->pstn_cid_intr = 1;
+                                                               j->pstn_cid_recieved = jiffies;
+                                                       }
+                                               }
+                                       } else {
+                                               if (j->pld_scrr.bits.daaflag) {
+                                                       daa_int_read(board);
+                                               }
+                                               j->ex.bits.pstn_ring = 0;
+                                               if (j->pstn_cid_intr && jiffies > j->pstn_cid_recieved + (hertz * 3)) {
+                                                       if (j->daa_mode == SOP_PU_RINGING) {
+                                                               ixj_daa_cid_read(board);
+                                                               j->ex.bits.caller_id = 1;
+                                                       }
+                                                       j->pstn_cid_intr = 0;
+                                               } else {
+                                                       j->ex.bits.caller_id = 0;
+                                               }
+                                               if (!j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+                                                       if (j->flags.pstn_ringing && j->pstn_envelope) {
+                                                               j->ex.bits.pstn_ring = 1;
+                                                               j->pstn_envelope = 0;
+                                                       } else if (j->daa_mode == SOP_PU_CONVERSATION) {
+                                                               if (!j->pstn_winkstart) {
+                                                                       j->pstn_winkstart = jiffies;
+                                                               } else if (jiffies > j->pstn_winkstart + (hertz * 320 / 1000)) {
+                                                                       daa_set_mode(board, SOP_PU_SLEEP);
+                                                                       j->pstn_winkstart = 0;
+                                                                       j->ex.bits.pstn_wink = 1;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       if ((j->ex.bits.f0 || j->ex.bits.f1 || j->ex.bits.f2 || j->ex.bits.f3)
+                           && j->filter_cadence) {
+                       }
+                       if (j->ex.bytes) {
+                               wake_up_interruptible(&j->poll_q);      // Wake any blocked selects
+                               if (j->async_queue)
+                                       kill_fasync(j->async_queue, SIGIO, POLL_IN);    // Send apps notice of change
+                       }
+               } else {
+                       break;
+               }
+       }
+timer_end:
+       ixj_add_timer();
+}
+
+static int ixj_status_wait(int board)
+{
+       unsigned long jif;
+
+       jif = jiffies;
+       while (!IsStatusReady(board)) {
+               if (jiffies - jif > (60 * (hertz / 100))) {
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+int ixj_WriteDSPCommand(unsigned short cmd, int board)
+{
+       BYTES bytes;
+       unsigned long jif;
+
+       bytes.high = (cmd & 0xFF00) >> 8;
+       bytes.low = cmd & 0x00FF;
+       jif = jiffies;
+       while (!IsControlReady(board)) {
+               if (jiffies - jif > (60 * (hertz / 100))) {
+                       return -1;
+               }
+       }
+       outb_p(bytes.low, ixj[board].DSPbase + 6);
+       outb_p(bytes.high, ixj[board].DSPbase + 7);
+
+       if (ixj_status_wait(board)) {
+               ixj[board].ssr.low = 0xFF;
+               ixj[board].ssr.high = 0xFF;
+               return -1;
+       }
+/* Read Software Status Register */
+       ixj[board].ssr.low = inb_p(ixj[board].DSPbase + 2);
+       ixj[board].ssr.high = inb_p(ixj[board].DSPbase + 3);
+       return 0;
+}
+
+/***************************************************************************
+*
+*  General Purpose IO Register read routine
+*
+***************************************************************************/
+extern __inline__ int ixj_gpio_read(int board)
+{
+       if (ixj_WriteDSPCommand(0x5143, board))
+               return -1;
+
+       ixj[board].gpio.bytes.low = ixj[board].ssr.low;
+       ixj[board].gpio.bytes.high = ixj[board].ssr.high;
+
+       return 0;
+}
+
+extern __inline__ void LED_SetState(int state, int board)
+{
+       if (ixj[board].dsp.low == 0x21) {
+               ixj[board].pld_scrw.bits.led1 = state & 0x1 ? 1 : 0;
+               ixj[board].pld_scrw.bits.led2 = state & 0x2 ? 1 : 0;
+               ixj[board].pld_scrw.bits.led3 = state & 0x4 ? 1 : 0;
+               ixj[board].pld_scrw.bits.led4 = state & 0x8 ? 1 : 0;
+
+               outb_p(ixj[board].pld_scrw.byte, ixj[board].XILINXbase);
+       }
+}
+
+/*********************************************************************
+*  GPIO Pins are configured as follows on the Quicknet Internet
+*  PhoneJACK Telephony Cards
+* 
+* POTS Select        GPIO_6=0 GPIO_7=0
+* Mic/Speaker Select GPIO_6=0 GPIO_7=1
+* Handset Select     GPIO_6=1 GPIO_7=0
+*
+* SLIC Active        GPIO_1=0 GPIO_2=1 GPIO_5=0
+* SLIC Ringing       GPIO_1=1 GPIO_2=1 GPIO_5=0
+* SLIC Open Circuit  GPIO_1=0 GPIO_2=0 GPIO_5=0
+*
+* Hook Switch changes reported on GPIO_3
+*********************************************************************/
+static int ixj_set_port(int board, int arg)
+{
+       IXJ *j = &ixj[board];
+
+       if (j->cardtype == 400) {
+               if (arg != PORT_POTS)
+                       return 10;
+               else
+                       return 0;
+       }
+       switch (arg) {
+       case PORT_POTS:
+               j->port = PORT_POTS;
+               switch (j->cardtype) {
+               case 500:
+                       j->pld_slicw.pcib.mic = 0;
+                       j->pld_slicw.pcib.spk = 0;
+                       outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                       break;
+               case 300:
+                       if (ixj_WriteDSPCommand(0xC528, board))         /* Write CODEC config to
+                                                                          Software Control Register */
+                               return 2;
+                       j->pld_scrw.bits.daafsyncen = 0;        // Turn off DAA Frame Sync
+
+                       outb_p(j->pld_scrw.byte, j->XILINXbase);
+                       j->pld_clock.byte = 0;
+                       outb_p(j->pld_clock.byte, j->XILINXbase + 0x04);
+                       j->pld_slicw.bits.rly1 = 1;
+                       j->pld_slicw.bits.spken = 0;
+                       outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                       SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+                       break;
+               case 100:
+                       j->gpio.bytes.high = 0x0B;
+                       j->gpio.bits.gpio6 = 0;
+                       j->gpio.bits.gpio7 = 0;
+                       ixj_WriteDSPCommand(j->gpio.word, board);
+                       break;
+               }
+               break;
+       case PORT_PSTN:
+               if (j->cardtype == 300) {
+                       ixj_WriteDSPCommand(0xC534, board);     /* Write CODEC config to Software Control Register */
+
+                       j->pld_slicw.bits.rly3 = 0;
+                       j->pld_slicw.bits.rly1 = 1;
+                       j->pld_slicw.bits.spken = 0;
+                       outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                       j->port = PORT_PSTN;
+               } else {
+                       return 4;
+               }
+               break;
+       case PORT_SPEAKER:
+               j->port = PORT_SPEAKER;
+               switch (j->cardtype) {
+               case 500:
+                       j->pld_slicw.pcib.mic = 1;
+                       j->pld_slicw.pcib.spk = 1;
+                       outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                       break;
+               case 300:
+                       break;
+               case 100:
+                       j->gpio.bytes.high = 0x0B;
+                       j->gpio.bits.gpio6 = 0;
+                       j->gpio.bits.gpio7 = 1;
+                       ixj_WriteDSPCommand(j->gpio.word, board);
+                       break;
+               }
+               break;
+       case PORT_HANDSET:
+               if (j->cardtype == 300 || j->cardtype == 500) {
+                       return 5;
+               } else {
+                       j->gpio.bytes.high = 0x0B;
+                       j->gpio.bits.gpio6 = 1;
+                       j->gpio.bits.gpio7 = 0;
+                       ixj_WriteDSPCommand(j->gpio.word, board);
+                       j->port = PORT_HANDSET;
+               }
+               break;
+       default:
+               return 6;
+               break;
+       }
+       return 0;
+}
+
+static int ixj_set_pots(int board, int arg)
+{
+       IXJ *j = &ixj[board];
+
+       if (j->cardtype == 300) {
+               if (arg) {
+                       if (j->port == PORT_PSTN) {
+                               j->pld_slicw.bits.rly1 = 0;
+                               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                               return 1;
+                       } else {
+                               return 0;
+                       }
+               } else {
+                       j->pld_slicw.bits.rly1 = 1;
+                       outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                       return 1;
+               }
+       } else {
+               return 0;
+       }
+}
+
+static void ixj_ring_on(int board)
+{
+       IXJ *j = &ixj[board];
+       if (j->dsp.low == 0x20) // Internet PhoneJACK
+        {
+               if (ixjdebug > 0)
+                       printk(KERN_INFO "IXJ Ring On /dev/phone%d\n", board);
+
+               j->gpio.bytes.high = 0x0B;
+               j->gpio.bytes.low = 0x00;
+               j->gpio.bits.gpio1 = 1;
+               j->gpio.bits.gpio2 = 1;
+               j->gpio.bits.gpio5 = 0;
+               ixj_WriteDSPCommand(j->gpio.word, board);       /* send the ring signal */
+       } else                  //  Internet LineJACK, Internet PhoneJACK Lite or
+              //  Internet PhoneJACK PCI
+        {
+               if (ixjdebug > 0)
+                       printk(KERN_INFO "IXJ Ring On /dev/phone%d\n", board);
+
+               SLIC_SetState(PLD_SLIC_STATE_RINGING, board);
+       }
+}
+
+static int ixj_hookstate(int board)
+{
+       unsigned long det;
+       IXJ *j = &ixj[board];
+       int fOffHook = 0;
+
+       switch (j->cardtype) {
+       case 100:
+               ixj_gpio_read(board);
+               fOffHook = j->gpio.bits.gpio3read ? 1 : 0;
+               break;
+       case 300:
+       case 400:
+       case 500:
+               SLIC_GetState(board);
+               if (j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE ||
+                   j->pld_slicr.bits.state == PLD_SLIC_STATE_STANDBY) 
+               {
+                       if (j->flags.ringing) 
+                       {
+                               if(!in_interrupt())
+                               {
+                                       det = jiffies + (hertz / 50);
+                                       while (time_before(jiffies, det)) {
+                                               current->state = TASK_INTERRUPTIBLE;
+                                               schedule_timeout(1);
+                                       }
+                               }
+                               SLIC_GetState(board);
+                               if (j->pld_slicr.bits.state == PLD_SLIC_STATE_RINGING) {
+                                       ixj_ring_on(board);
+                               }
+                       }
+                       if (j->cardtype == 500) {
+                               j->pld_scrr.byte = inb_p(j->XILINXbase);
+                               fOffHook = j->pld_scrr.pcib.det ? 1 : 0;
+                       } else
+                               fOffHook = j->pld_slicr.bits.det ? 1 : 0;
+               }
+               break;
+       }
+       if (j->r_hook != fOffHook) {
+               j->r_hook = fOffHook;
+               if (j->port != PORT_POTS) {
+                       j->ex.bits.hookstate = 1;
+                       if (j->async_queue)
+                               kill_fasync(j->async_queue, SIGIO, POLL_IN);    // Send apps notice of change
+
+               }
+       }
+       if (j->port == PORT_PSTN && j->daa_mode == SOP_PU_CONVERSATION)
+               fOffHook |= 2;
+
+       if (j->port == PORT_SPEAKER)
+               fOffHook |= 2;
+
+       if (j->port == PORT_HANDSET)
+               fOffHook |= 2;
+
+       return fOffHook;
+}
+
+static void ixj_ring_off(board)
+{
+       IXJ *j = &ixj[board];
+
+       if (j->dsp.low == 0x20) // Internet PhoneJACK
+        {
+               if (ixjdebug > 0)
+                       printk(KERN_INFO "IXJ Ring Off\n");
+               j->gpio.bytes.high = 0x0B;
+               j->gpio.bytes.low = 0x00;
+               j->gpio.bits.gpio1 = 0;
+               j->gpio.bits.gpio2 = 1;
+               j->gpio.bits.gpio5 = 0;
+               ixj_WriteDSPCommand(j->gpio.word, board);
+       } else                  // Internet LineJACK
+        {
+               if (ixjdebug > 0)
+                       printk(KERN_INFO "IXJ Ring Off\n");
+
+               SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);   
+
+               SLIC_GetState(board);
+       }
+}
+
+static void ixj_ring_start(int board)
+{
+       IXJ *j = &ixj[board];
+
+       j->flags.cringing = 1;
+       if (ixj_hookstate(board) & 1) {
+               if (j->port == PORT_POTS)
+                       ixj_ring_off(board);
+               j->flags.cringing = 0;
+       } else {
+               j->ring_cadence_jif = jiffies;
+               j->ring_cadence_t = 15;
+               if (j->ring_cadence & 1 << j->ring_cadence_t) {
+                       ixj_ring_on(board);
+               } else {
+                       ixj_ring_off(board);
+               }
+       }
+}
+
+static int ixj_ring(int board)
+{
+       char cntr;
+       unsigned long jif, det;
+       IXJ *j = &ixj[board];
+
+       j->flags.ringing = 1;
+       if (ixj_hookstate(board) & 1) {
+               ixj_ring_off(board);
+               j->flags.ringing = 0;
+               return 1;
+       }
+       det = 0;
+       for (cntr = 0; cntr < j->maxrings; cntr++) {
+               jif = jiffies + (1 * hertz);
+               ixj_ring_on(board);
+               while (time_before(jiffies, jif)) {
+                       if (ixj_hookstate(board) & 1) {
+                               ixj_ring_off(board);
+                               j->flags.ringing = 0;
+                               return 1;
+                       }
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+                       if(signal_pending(current))
+                               break;
+               }
+               jif = jiffies + (3 * hertz);
+               ixj_ring_off(board);
+               while (time_before(jiffies, jif)) {
+                       if (ixj_hookstate(board) & 1) {
+                               det = jiffies + (hertz / 100);
+                               while (time_before(jiffies, det)) {
+                                       current->state = TASK_INTERRUPTIBLE;
+                                       schedule_timeout(1);
+                                       if(signal_pending(current))
+                                               break;
+                               }
+                               if (ixj_hookstate(board) & 1) {
+                                       j->flags.ringing = 0;
+                                       return 1;
+                               }
+                       }
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+                       if(signal_pending(current))
+                               break;
+               }
+       }
+       ixj_ring_off(board);
+       j->flags.ringing = 0;
+       return 0;
+}
+
+int ixj_open(struct phone_device *p, struct file *file_p)
+{
+       IXJ *j = &ixj[p->board];
+
+       if (!j->DSPbase)
+               return -ENODEV;
+
+       if (file_p->f_mode & FMODE_READ)
+               j->readers++;
+       if (file_p->f_mode & FMODE_WRITE)
+               j->writers++;
+
+       MOD_INC_USE_COUNT;
+
+       if (ixjdebug > 0)
+//    printk(KERN_INFO "Opening board %d\n", NUM(inode->i_rdev));
+               printk(KERN_INFO "Opening board %d\n", p->board);
+
+       return 0;
+}
+
+int ixj_release(struct inode *inode, struct file *file_p)
+{
+       IXJ_TONE ti;
+       int board = NUM(inode->i_rdev);
+       IXJ *j = &ixj[board];
+
+       if (ixjdebug > 0)
+               printk(KERN_INFO "Closing board %d\n", NUM(inode->i_rdev));
+
+       daa_set_mode(board, SOP_PU_SLEEP);
+       ixj_set_port(board, PORT_POTS);
+       aec_stop(board);
+       ixj_play_stop(board);
+       ixj_record_stop(board);
+
+       ti.tone_index = 10;
+       ti.gain0 = 1;
+       ti.freq0 = hz941;
+       ti.gain1 = 0;
+       ti.freq1 = hz1209;
+       ti.tone_index = 11;
+       ti.gain0 = 1;
+       ti.freq0 = hz941;
+       ti.gain1 = 0;
+       ti.freq1 = hz1336;
+       ti.tone_index = 12;
+       ti.gain0 = 1;
+       ti.freq0 = hz941;
+       ti.gain1 = 0;
+       ti.freq1 = hz1477;
+       ti.tone_index = 13;
+       ti.gain0 = 1;
+       ti.freq0 = hz800;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 14;
+       ti.gain0 = 1;
+       ti.freq0 = hz1000;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 15;
+       ti.gain0 = 1;
+       ti.freq0 = hz1250;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 16;
+       ti.gain0 = 1;
+       ti.freq0 = hz950;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 17;
+       ti.gain0 = 1;
+       ti.freq0 = hz1100;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 18;
+       ti.gain0 = 1;
+       ti.freq0 = hz1400;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 19;
+       ti.gain0 = 1;
+       ti.freq0 = hz1500;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 20;
+       ti.gain0 = 1;
+       ti.freq0 = hz1600;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 21;
+       ti.gain0 = 1;
+       ti.freq0 = hz1800;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 22;
+       ti.gain0 = 1;
+       ti.freq0 = hz2100;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 23;
+       ti.gain0 = 1;
+       ti.freq0 = hz1300;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 24;
+       ti.gain0 = 1;
+       ti.freq0 = hz2450;
+       ti.gain1 = 0;
+       ti.freq1 = 0;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 25;
+       ti.gain0 = 1;
+       ti.freq0 = hz350;
+       ti.gain1 = 0;
+       ti.freq1 = hz440;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 26;
+       ti.gain0 = 1;
+       ti.freq0 = hz440;
+       ti.gain1 = 0;
+       ti.freq1 = hz480;
+       ixj_init_tone(board, &ti);
+       ti.tone_index = 27;
+       ti.gain0 = 1;
+       ti.freq0 = hz480;
+       ti.gain1 = 0;
+       ti.freq1 = hz620;
+       ixj_init_tone(board, &ti);
+
+       idle(board);
+
+       if (file_p->f_mode & FMODE_READ)
+               j->readers--;
+       if (file_p->f_mode & FMODE_WRITE)
+               j->writers--;
+
+       if (j->read_buffer && !j->readers) {
+               kfree(j->read_buffer);
+               j->read_buffer = NULL;
+               j->read_buffer_size = 0;
+       }
+       if (j->write_buffer && !j->writers) {
+               kfree(j->write_buffer);
+               j->write_buffer = NULL;
+               j->write_buffer_size = 0;
+       }
+       j->rec_codec = j->play_codec = 0;
+       j->rec_frame_size = j->play_frame_size = 0;
+       ixj_fasync(-1, file_p, 0);      // remove from list of async notification
+
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int read_filters(int board)
+{
+       unsigned short fc, cnt;
+       IXJ *j = &ixj[board];
+
+       if (ixj_WriteDSPCommand(0x5144, board))
+               return -1;
+
+       fc = j->ssr.high << 8 | j->ssr.low;
+       if (fc == j->frame_count)
+               return 1;
+
+       j->frame_count = fc;
+
+       for (cnt = 0; cnt < 4; cnt++) {
+               if (ixj_WriteDSPCommand(0x5154 + cnt, board))
+                       return -1;
+
+               if (ixj_WriteDSPCommand(0x515C, board))
+                       return -1;
+
+               j->filter_hist[cnt] = j->ssr.high << 8 | j->ssr.low;
+               if ((j->filter_hist[cnt] & 1 && !(j->filter_hist[cnt] & 2)) ||
+               (j->filter_hist[cnt] & 2 && !(j->filter_hist[cnt] & 1))) {
+                       switch (cnt) {
+                       case 0:
+                               j->ex.bits.f0 = 1;
+                               break;
+                       case 1:
+                               j->ex.bits.f1 = 1;
+                               break;
+                       case 2:
+                               j->ex.bits.f2 = 1;
+                               break;
+                       case 3:
+                               j->ex.bits.f3 = 1;
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int LineMonitor(int board)
+{
+       IXJ *j = &ixj[board];
+
+       if (j->dtmf_proc) {
+               return -1;
+       }
+       j->dtmf_proc = 1;
+
+       if (ixj_WriteDSPCommand(0x7000, board))         // Line Monitor
+
+               return -1;
+
+       j->dtmf.bytes.high = j->ssr.high;
+       j->dtmf.bytes.low = j->ssr.low;
+       if (!j->dtmf_state && j->dtmf.bits.dtmf_valid) {
+               j->dtmf_state = 1;
+               j->dtmf_current = j->dtmf.bits.digit;
+       }
+       if (j->dtmf_state && !j->dtmf.bits.dtmf_valid)  // && j->dtmf_wp != j->dtmf_rp)
+        {
+               j->dtmfbuffer[j->dtmf_wp] = j->dtmf_current;
+               j->dtmf_wp++;
+               if (j->dtmf_wp == 79)
+                       j->dtmf_wp = 0;
+               j->ex.bits.dtmf_ready = 1;
+               j->dtmf_state = 0;
+       }
+       j->dtmf_proc = 0;
+
+       return 0;
+}
+
+ssize_t ixj_read(struct file * file_p, char *buf, size_t length, loff_t * ppos)
+{
+       unsigned long i = *ppos;
+       IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(&j->read_q, &wait);
+       current->state = TASK_INTERRUPTIBLE;
+       mb();
+
+       while (!j->read_buffer_ready || (j->dtmf_state && j->flags.dtmf_oob)) {
+               ++j->read_wait;
+               if (file_p->f_flags & O_NONBLOCK) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(&j->read_q, &wait);
+                       return -EAGAIN;
+               }
+               if (!ixj_hookstate(NUM(file_p->f_dentry->d_inode->i_rdev))) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(&j->read_q, &wait);
+                       return 0;
+               }
+               interruptible_sleep_on(&j->read_q);
+               if (signal_pending(current)) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(&j->read_q, &wait);
+                       return -EINTR;
+               }
+       }
+
+       remove_wait_queue(&j->read_q, &wait);
+       current->state = TASK_RUNNING;
+       /* Don't ever copy more than the user asks */
+       i = copy_to_user(buf, j->read_buffer, min(length, j->read_buffer_size));
+       j->read_buffer_ready = 0;
+       if (i)
+               return -EFAULT;
+       else
+               return min(length, j->read_buffer_size);
+}
+
+ssize_t ixj_enhanced_read(struct file * file_p, char *buf, size_t length,
+                         loff_t * ppos)
+{
+       int pre_retval;
+       ssize_t read_retval = 0;
+       IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+       pre_retval = ixj_PreRead(j, 0L);
+       switch (pre_retval) {
+       case NORMAL:
+               read_retval = ixj_read(file_p, buf, length, ppos);
+               ixj_PostRead(j, 0L);
+               break;
+       case NOPOST:
+               read_retval = ixj_read(file_p, buf, length, ppos);
+               break;
+       case POSTONLY:
+               ixj_PostRead(j, 0L);
+               break;
+       default:
+               read_retval = pre_retval;
+       }
+       return read_retval;
+}
+
+ssize_t ixj_write(struct file * file_p, const char *buf, size_t count, loff_t * ppos)
+{
+       unsigned long i = *ppos;
+       int board = NUM(file_p->f_dentry->d_inode->i_rdev);
+       IXJ *j = &ixj[board];
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(&j->read_q, &wait);
+       current->state = TASK_INTERRUPTIBLE;
+       mb();
+
+
+       while (!j->write_buffers_empty) {
+               ++j->write_wait;
+               if (file_p->f_flags & O_NONBLOCK) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(&j->read_q, &wait);
+                       return -EAGAIN;
+               }
+               if (!ixj_hookstate(NUM(file_p->f_dentry->d_inode->i_rdev))) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(&j->read_q, &wait);
+                       return 0;
+               }
+               interruptible_sleep_on(&j->write_q);
+               if (signal_pending(current)) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(&j->read_q, &wait);
+                       return -EINTR;
+               }
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&j->read_q, &wait);
+       if (j->write_buffer_wp + count >= j->write_buffer_end)
+               j->write_buffer_wp = j->write_buffer;
+       i = copy_from_user(j->write_buffer_wp, buf, min(count, j->write_buffer_size));
+       if (i)
+               return -EFAULT;
+
+       return min(count, j->write_buffer_size);
+}
+
+ssize_t ixj_enhanced_write(struct file * file_p, const char *buf, size_t count,
+                          loff_t * ppos)
+{
+       int pre_retval;
+       ssize_t write_retval = 0;
+       IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+       pre_retval = ixj_PreWrite(j, 0L);
+       switch (pre_retval) {
+       case NORMAL:
+               write_retval = ixj_write(file_p, buf, count, ppos);
+               if (write_retval != -EFAULT) {
+                       ixj_PostWrite(j, 0L);
+                       j->write_buffer_wp += count;
+                       j->write_buffers_empty--;
+               }
+               break;
+       case NOPOST:
+               write_retval = ixj_write(file_p, buf, count, ppos);
+               if (write_retval != -EFAULT) {
+                       j->write_buffer_wp += count;
+                       j->write_buffers_empty--;
+               }
+               break;
+       case POSTONLY:
+               ixj_PostWrite(j, 0L);
+               break;
+       default:
+               write_retval = pre_retval;
+       }
+       return write_retval;
+}
+
+static void ixj_read_frame(int board)
+{
+       int cnt, dly;
+       IXJ *j = &ixj[board];
+
+       if (j->read_buffer) {
+               for (cnt = 0; cnt < j->rec_frame_size * 2; cnt += 2) {
+                       if (!(cnt % 16) && !IsRxReady(board)) {
+                               dly = 0;
+                               while (!IsRxReady(board)) {
+                                       if (dly++ > 5) {
+                                               dly = 0;
+                                               break;
+                                       }
+                                       udelay(10);
+                               }
+                       }
+                       // Throw away word 0 of the 8021 compressed format to get standard G.729.
+                       if (j->rec_codec == G729 && (cnt == 0 || cnt == 5 || cnt == 10)) {
+                               inb_p(j->DSPbase + 0x0E);
+                               inb_p(j->DSPbase + 0x0F);
+                       }
+                       *(j->read_buffer + cnt) = inb_p(j->DSPbase + 0x0E);
+                       *(j->read_buffer + cnt + 1) = inb_p(j->DSPbase + 0x0F);
+               }
+#ifdef PERFMON_STATS
+               ++j->framesread;
+#endif
+               if (j->intercom != -1) {
+                       if (IsTxReady(j->intercom)) {
+                               for (cnt = 0; cnt < j->rec_frame_size * 2; cnt += 2) {
+                                       if (!(cnt % 16) && !IsTxReady(board)) {
+                                               dly = 0;
+                                               while (!IsTxReady(board)) {
+                                                       if (dly++ > 5) {
+                                                               dly = 0;
+                                                               break;
+                                                       }
+                                                       udelay(10);
+                                               }
+                                       }
+                                       outb_p(*(j->read_buffer + cnt), ixj[j->intercom].DSPbase + 0x0C);
+                                       outb_p(*(j->read_buffer + cnt + 1), ixj[j->intercom].DSPbase + 0x0D);
+                               }
+#ifdef PERFMON_STATS
+                               ++ixj[j->intercom].frameswritten;
+#endif
+                       }
+               } else {
+                       j->read_buffer_ready = 1;
+                       wake_up_interruptible(&j->read_q);      // Wake any blocked readers
+
+                       wake_up_interruptible(&j->poll_q);      // Wake any blocked selects
+
+                       if (j->async_queue)
+                               kill_fasync(j->async_queue, SIGIO, POLL_IN);    // Send apps notice of frame
+
+               }
+       }
+}
+
+static void ixj_write_frame(int board)
+{
+       int cnt, frame_count, dly;
+       BYTES blankword;
+       IXJ *j = &ixj[board];
+
+       frame_count = 0;
+       if (j->write_buffer && j->write_buffers_empty < 2) {
+               if (j->write_buffer_wp > j->write_buffer_rp) {
+                       frame_count =
+                           (j->write_buffer_wp - j->write_buffer_rp) / (j->play_frame_size * 2);
+               }
+               if (j->write_buffer_rp > j->write_buffer_wp) {
+                       frame_count =
+                           (j->write_buffer_wp - j->write_buffer) / (j->play_frame_size * 2) +
+                           (j->write_buffer_end - j->write_buffer_rp) / (j->play_frame_size * 2);
+               }
+               if (frame_count >= 1) {
+                       if (j->ver.low == 0x12 && j->play_mode && j->flags.play_first_frame) {
+                               switch (j->play_mode) {
+                               case PLAYBACK_MODE_ULAW:
+                               case PLAYBACK_MODE_ALAW:
+                                       blankword.low = blankword.high = 0xFF;
+                                       break;
+                               case PLAYBACK_MODE_8LINEAR:
+                               case PLAYBACK_MODE_16LINEAR:
+                                       blankword.low = blankword.high = 0x00;
+                                       break;
+                               case PLAYBACK_MODE_8LINEAR_WSS:
+                                       blankword.low = blankword.high = 0x80;
+                                       break;
+                               }
+                               for (cnt = 0; cnt < 16; cnt++) {
+                                       if (!(cnt % 16) && !IsTxReady(board)) {
+                                               dly = 0;
+                                               while (!IsTxReady(board)) {
+                                                       if (dly++ > 5) {
+                                                               dly = 0;
+                                                               break;
+                                                       }
+                                                       udelay(10);
+                                               }
+                                       }
+                                       outb_p((blankword.low), j->DSPbase + 0x0C);
+                                       outb_p((blankword.high), j->DSPbase + 0x0D);
+                               }
+                               j->flags.play_first_frame = 0;
+                       }
+                       for (cnt = 0; cnt < j->play_frame_size * 2; cnt += 2) {
+                               if (!(cnt % 16) && !IsTxReady(board)) {
+                                       dly = 0;
+                                       while (!IsTxReady(board)) {
+                                               if (dly++ > 5) {
+                                                       dly = 0;
+                                                       break;
+                                               }
+                                               udelay(10);
+                                       }
+                               }
+// Add word 0 to G.729 frames for the 8021.  Right now we don't do VAD/CNG 
+                               // so all frames are type 1.
+                               if (j->play_codec == G729 && (cnt == 0 || cnt == 5 || cnt == 10)) {
+                                       outb_p(0x01, j->DSPbase + 0x0C);
+                                       outb_p(0x00, j->DSPbase + 0x0D);
+                               }
+                               outb_p(*(j->write_buffer_rp + cnt), j->DSPbase + 0x0C);
+                               outb_p(*(j->write_buffer_rp + cnt + 1), j->DSPbase + 0x0D);
+                               *(j->write_buffer_rp + cnt) = 0;
+                               *(j->write_buffer_rp + cnt + 1) = 0;
+                       }
+                       j->write_buffer_rp += j->play_frame_size * 2;
+                       if (j->write_buffer_rp >= j->write_buffer_end) {
+                               j->write_buffer_rp = j->write_buffer;
+                       }
+                       j->write_buffers_empty++;
+                       wake_up_interruptible(&(j->write_q));   // Wake any blocked writers
+
+                       wake_up_interruptible(&j->poll_q);      // Wake any blocked selects
+
+                       if (j->async_queue)
+                               kill_fasync(j->async_queue, SIGIO, POLL_IN);    // Send apps notice of empty buffer
+#ifdef PERFMON_STATS
+                       ++j->frameswritten;
+#endif
+               }
+       } else {
+               j->drybuffer++;
+       }
+}
+
+static int idle(int board)
+{
+       IXJ *j = &ixj[board];
+
+       if (ixj_WriteDSPCommand(0x0000, board))         // DSP Idle
+
+               return 0;
+       if (j->ssr.high || j->ssr.low)
+               return 0;
+       else
+               return 1;
+}
+
+static int set_base_frame(int board, int size)
+{
+       unsigned short cmd;
+       int cnt;
+       IXJ *j = &ixj[board];
+
+       aec_stop(board);
+       for (cnt = 0; cnt < 10; cnt++) {
+               if (idle(board))
+                       break;
+       }
+       if (j->ssr.high || j->ssr.low)
+               return -1;
+       if (j->dsp.low != 0x20) {
+               switch (size) {
+               case 30:
+                       cmd = 0x07F0;
+                       /* Set Base Frame Size to 240 pg9-10 8021 */
+                       break;
+               case 20:
+                       cmd = 0x07A0;
+                       /* Set Base Frame Size to 160 pg9-10 8021 */
+                       break;
+               case 10:
+                       cmd = 0x0750;
+                       /* Set Base Frame Size to 80 pg9-10 8021 */
+                       break;
+               default:
+                       return -1;
+               }
+       } else {
+               if (size == 30)
+                       return size;
+               else
+                       return -1;
+       }
+       if (ixj_WriteDSPCommand(cmd, board)) {
+               j->baseframe.high = j->baseframe.low = 0xFF;
+               return -1;
+       } else {
+               j->baseframe.high = j->ssr.high;
+               j->baseframe.low = j->ssr.low;
+       }
+       return size;
+}
+
+static int set_rec_codec(int board, int rate)
+{
+       int retval = 0;
+       IXJ *j = &ixj[board];
+
+       j->rec_codec = rate;
+
+       switch (rate) {
+       case G723_63:
+               if (j->ver.low != 0x12 || ixj_convert_loaded) {
+                       j->rec_frame_size = 12;
+                       j->rec_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case G723_53:
+               if (j->ver.low != 0x12 || ixj_convert_loaded) {
+                       j->rec_frame_size = 10;
+                       j->rec_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case TS85:
+               if (j->dsp.low == 0x20 || j->flags.ts85_loaded) {
+                       j->rec_frame_size = 16;
+                       j->rec_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case TS48:
+               if (j->ver.low != 0x12 || ixj_convert_loaded) {
+                       j->rec_frame_size = 9;
+                       j->rec_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case TS41:
+               if (j->ver.low != 0x12 || ixj_convert_loaded) {
+                       j->rec_frame_size = 8;
+                       j->rec_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case G728:
+               if (j->dsp.low != 0x20) {
+                       j->rec_frame_size = 48;
+                       j->rec_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case G729:
+               if (j->dsp.low != 0x20) {
+                       if (!j->flags.g729_loaded) {
+                               retval = 1;
+                               break;
+                       }
+                       switch (j->baseframe.low) {
+                       case 0xA0:
+                               j->rec_frame_size = 10;
+                               break;
+                       case 0x50:
+                               j->rec_frame_size = 5;
+                               break;
+                       default:
+                               j->rec_frame_size = 15;
+                               break;
+                       }
+                       j->rec_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case ULAW:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->rec_frame_size = 80;
+                       break;
+               case 0x50:
+                       j->rec_frame_size = 40;
+                       break;
+               default:
+                       j->rec_frame_size = 120;
+                       break;
+               }
+               j->rec_mode = 4;
+               break;
+       case ALAW:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->rec_frame_size = 80;
+                       break;
+               case 0x50:
+                       j->rec_frame_size = 40;
+                       break;
+               default:
+                       j->rec_frame_size = 120;
+                       break;
+               }
+               j->rec_mode = 4;
+               break;
+       case LINEAR16:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->rec_frame_size = 160;
+                       break;
+               case 0x50:
+                       j->rec_frame_size = 80;
+                       break;
+               default:
+                       j->rec_frame_size = 240;
+                       break;
+               }
+               j->rec_mode = 5;
+               break;
+       case LINEAR8:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->rec_frame_size = 80;
+                       break;
+               case 0x50:
+                       j->rec_frame_size = 40;
+                       break;
+               default:
+                       j->rec_frame_size = 120;
+                       break;
+               }
+               j->rec_mode = 6;
+               break;
+       case WSS:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->rec_frame_size = 80;
+                       break;
+               case 0x50:
+                       j->rec_frame_size = 40;
+                       break;
+               default:
+                       j->rec_frame_size = 120;
+                       break;
+               }
+               j->rec_mode = 7;
+               break;
+       default:
+               j->rec_frame_size = 0;
+               j->rec_mode = -1;
+               if (j->read_buffer) {
+                       kfree(j->read_buffer);
+                       j->read_buffer = NULL;
+                       j->read_buffer_size = 0;
+               }
+               retval = 1;
+               break;
+       }
+       return retval;
+}
+
+static int ixj_record_start(int board)
+{
+       unsigned short cmd = 0x0000;
+       IXJ *j = &ixj[board];
+
+       if (!j->rec_mode) {
+               switch (j->rec_codec) {
+               case G723_63:
+                       cmd = 0x5131;
+                       break;
+               case G723_53:
+                       cmd = 0x5132;
+                       break;
+               case TS85:
+                       cmd = 0x5130;   // TrueSpeech 8.5
+
+                       break;
+               case TS48:
+                       cmd = 0x5133;   // TrueSpeech 4.8
+
+                       break;
+               case TS41:
+                       cmd = 0x5134;   // TrueSpeech 4.1
+
+                       break;
+               case G728:
+                       cmd = 0x5135;
+                       break;
+               case G729:
+                       cmd = 0x5136;
+                       break;
+               default:
+                       return 1;
+               }
+               if (ixj_WriteDSPCommand(cmd, board))
+                       return -1;
+       }
+       if (!j->read_buffer) {
+               if (!j->read_buffer)
+                       j->read_buffer = kmalloc(j->rec_frame_size * 2, GFP_ATOMIC);
+               if (!j->read_buffer) {
+                       printk("Read buffer allocation for ixj board %d failed!\n", board);
+                       return -ENOMEM;
+               }
+       }
+       j->read_buffer_size = j->rec_frame_size * 2;
+
+       if (ixj_WriteDSPCommand(0x5102, board))         // Set Poll sync mode
+
+               return -1;
+
+       switch (j->rec_mode) {
+       case 0:
+               cmd = 0x1C03;   // Record C1
+
+               break;
+       case 4:
+               if (j->ver.low == 0x12) {
+                       cmd = 0x1E03;   // Record C1
+
+               } else {
+                       cmd = 0x1E01;   // Record C1
+
+               }
+               break;
+       case 5:
+               if (j->ver.low == 0x12) {
+                       cmd = 0x1E83;   // Record C1
+
+               } else {
+                       cmd = 0x1E81;   // Record C1
+
+               }
+               break;
+       case 6:
+               if (j->ver.low == 0x12) {
+                       cmd = 0x1F03;   // Record C1
+
+               } else {
+                       cmd = 0x1F01;   // Record C1
+
+               }
+               break;
+       case 7:
+               if (j->ver.low == 0x12) {
+                       cmd = 0x1F83;   // Record C1
+
+               } else {
+                       cmd = 0x1F81;   // Record C1
+
+               }
+               break;
+       }
+       if (ixj_WriteDSPCommand(cmd, board))
+               return -1;
+
+       return 0;
+}
+
+static void ixj_record_stop(int board)
+{
+       IXJ *j = &ixj[board];
+
+       if (j->rec_mode > -1) {
+               ixj_WriteDSPCommand(0x5120, board);
+               j->rec_mode = -1;
+       }
+}
+
+static void set_rec_depth(int board, int depth)
+{
+       if (depth > 60)
+               depth = 60;
+       if (depth < 0)
+               depth = 0;
+       ixj_WriteDSPCommand(0x5180 + depth, board);
+}
+
+static void set_rec_volume(int board, int volume)
+{
+       ixj_WriteDSPCommand(0xCF03, board);
+       ixj_WriteDSPCommand(volume, board);
+}
+
+static int get_rec_level(int board)
+{
+       IXJ *j = &ixj[board];
+
+       ixj_WriteDSPCommand(0xCF88, board);
+
+       return j->ssr.high << 8 | j->ssr.low;
+}
+
+static void ixj_aec_start(int board, int level)
+{
+       IXJ *j = &ixj[board];
+
+       j->aec_level = level;
+       if (!level) {
+               ixj_WriteDSPCommand(0xB002, board);
+       } else {
+               if (j->rec_codec == G729 || j->play_codec == G729) {
+                       ixj_WriteDSPCommand(0xE022, board);     // Move AEC filter buffer
+
+                       ixj_WriteDSPCommand(0x0300, board);
+               }
+               ixj_WriteDSPCommand(0xB001, board);     // AEC On
+
+               ixj_WriteDSPCommand(0xE013, board);     // Advanced AEC C1
+
+               switch (level) {
+               case 1:
+                       ixj_WriteDSPCommand(0x0000, board);     // Advanced AEC C2 = off
+
+                       ixj_WriteDSPCommand(0xE011, board);
+                       ixj_WriteDSPCommand(0xFFFF, board);
+                       break;
+
+               case 2:
+                       ixj_WriteDSPCommand(0x0600, board);     // Advanced AEC C2 = on medium
+
+                       ixj_WriteDSPCommand(0xE011, board);
+                       ixj_WriteDSPCommand(0x0080, board);
+                       break;
+
+               case 3:
+                       ixj_WriteDSPCommand(0x0C00, board);     // Advanced AEC C2 = on high
+
+                       ixj_WriteDSPCommand(0xE011, board);
+                       ixj_WriteDSPCommand(0x0080, board);
+                       break;
+               }
+       }
+}
+
+static void aec_stop(int board)
+{
+       IXJ *j = &ixj[board];
+
+       if (j->rec_codec == G729 || j->play_codec == G729) {
+               ixj_WriteDSPCommand(0xE022, board);     // Move AEC filter buffer back
+
+               ixj_WriteDSPCommand(0x0700, board);
+       }
+       if (ixj[board].play_mode != -1 && ixj[board].rec_mode != -1);
+       {
+               ixj_WriteDSPCommand(0xB002, board);     // AEC Stop
+
+       }
+}
+
+static int set_play_codec(int board, int rate)
+{
+       int retval = 0;
+       IXJ *j = &ixj[board];
+
+       j->play_codec = rate;
+
+       switch (rate) {
+       case G723_63:
+               if (j->ver.low != 0x12 || ixj_convert_loaded) {
+                       j->play_frame_size = 12;
+                       j->play_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case G723_53:
+               if (j->ver.low != 0x12 || ixj_convert_loaded) {
+                       j->play_frame_size = 10;
+                       j->play_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case TS85:
+               if (j->dsp.low == 0x20 || j->flags.ts85_loaded) {
+                       j->play_frame_size = 16;
+                       j->play_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case TS48:
+               if (j->ver.low != 0x12 || ixj_convert_loaded) {
+                       j->play_frame_size = 9;
+                       j->play_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case TS41:
+               if (j->ver.low != 0x12 || ixj_convert_loaded) {
+                       j->play_frame_size = 8;
+                       j->play_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case G728:
+               if (j->dsp.low != 0x20) {
+                       j->play_frame_size = 48;
+                       j->play_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case G729:
+               if (j->dsp.low != 0x20) {
+                       if (!j->flags.g729_loaded) {
+                               retval = 1;
+                               break;
+                       }
+                       switch (j->baseframe.low) {
+                       case 0xA0:
+                               j->play_frame_size = 10;
+                               break;
+                       case 0x50:
+                               j->play_frame_size = 5;
+                               break;
+                       default:
+                               j->play_frame_size = 15;
+                               break;
+                       }
+                       j->play_mode = 0;
+               } else {
+                       retval = 1;
+               }
+               break;
+       case ULAW:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->play_frame_size = 80;
+                       break;
+               case 0x50:
+                       j->play_frame_size = 40;
+                       break;
+               default:
+                       j->play_frame_size = 120;
+                       break;
+               }
+               j->play_mode = 2;
+               break;
+       case ALAW:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->play_frame_size = 80;
+                       break;
+               case 0x50:
+                       j->play_frame_size = 40;
+                       break;
+               default:
+                       j->play_frame_size = 120;
+                       break;
+               }
+               j->play_mode = 2;
+               break;
+       case LINEAR16:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->play_frame_size = 160;
+                       break;
+               case 0x50:
+                       j->play_frame_size = 80;
+                       break;
+               default:
+                       j->play_frame_size = 240;
+                       break;
+               }
+               j->play_mode = 6;
+               break;
+       case LINEAR8:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->play_frame_size = 80;
+                       break;
+               case 0x50:
+                       j->play_frame_size = 40;
+                       break;
+               default:
+                       j->play_frame_size = 120;
+                       break;
+               }
+               j->play_mode = 4;
+               break;
+       case WSS:
+               switch (j->baseframe.low) {
+               case 0xA0:
+                       j->play_frame_size = 80;
+                       break;
+               case 0x50:
+                       j->play_frame_size = 40;
+                       break;
+               default:
+                       j->play_frame_size = 120;
+                       break;
+               }
+               j->play_mode = 5;
+               break;
+       default:
+               j->play_frame_size = 0;
+               j->play_mode = -1;
+               if (j->write_buffer) {
+                       kfree(j->write_buffer);
+                       j->write_buffer = NULL;
+                       j->write_buffer_size = 0;
+               }
+               retval = 1;
+               break;
+       }
+       return retval;
+}
+
+static int ixj_play_start(int board)
+{
+       unsigned short cmd = 0x0000;
+       IXJ *j = &ixj[board];
+
+       j->flags.play_first_frame = 1;
+       j->drybuffer = 0;
+
+       if (!j->play_mode) {
+               switch (j->play_codec) {
+               case G723_63:
+                       cmd = 0x5231;
+                       break;
+               case G723_53:
+                       cmd = 0x5232;
+                       break;
+               case TS85:
+                       cmd = 0x5230;   // TrueSpeech 8.5
+
+                       break;
+               case TS48:
+                       cmd = 0x5233;   // TrueSpeech 4.8
+
+                       break;
+               case TS41:
+                       cmd = 0x5234;   // TrueSpeech 4.1
+
+                       break;
+               case G728:
+                       cmd = 0x5235;
+                       break;
+               case G729:
+                       cmd = 0x5236;
+                       break;
+               default:
+                       return 1;
+               }
+               if (ixj_WriteDSPCommand(cmd, board))
+                       return -1;
+       }
+       if (!j->write_buffer) {
+               j->write_buffer = kmalloc(j->play_frame_size * 2, GFP_ATOMIC);
+               if (!j->write_buffer) {
+                       printk("Write buffer allocation for ixj board %d failed!\n", board);
+                       return -ENOMEM;
+               }
+       }
+       j->write_buffers_empty = 2;
+       j->write_buffer_size = j->play_frame_size * 2;
+       j->write_buffer_end = j->write_buffer + j->play_frame_size * 2;
+       j->write_buffer_rp = j->write_buffer_wp = j->write_buffer;
+
+       if (ixj_WriteDSPCommand(0x5202, board))         // Set Poll sync mode
+
+               return -1;
+
+       switch (j->play_mode) {
+       case 0:
+               cmd = 0x2C03;
+               break;
+       case 2:
+               if (j->ver.low == 0x12) {
+                       cmd = 0x2C23;
+               } else {
+                       cmd = 0x2C21;
+               }
+               break;
+       case 4:
+               if (j->ver.low == 0x12) {
+                       cmd = 0x2C43;
+               } else {
+                       cmd = 0x2C41;
+               }
+               break;
+       case 5:
+               if (j->ver.low == 0x12) {
+                       cmd = 0x2C53;
+               } else {
+                       cmd = 0x2C51;
+               }
+               break;
+       case 6:
+               if (j->ver.low == 0x12) {
+                       cmd = 0x2C63;
+               } else {
+                       cmd = 0x2C61;
+               }
+               break;
+       }
+       if (ixj_WriteDSPCommand(cmd, board))
+               return -1;
+
+       if (ixj_WriteDSPCommand(0x2000, board))         // Playback C2
+
+               return -1;
+
+       if (ixj_WriteDSPCommand(0x2000 + ixj[board].play_frame_size, board))    // Playback C3
+
+               return -1;
+
+       return 0;
+}
+
+static void ixj_play_stop(int board)
+{
+       IXJ *j = &ixj[board];
+
+       if (j->play_mode > -1) {
+               ixj_WriteDSPCommand(0x5221, board);     // Stop playback
+
+               j->play_mode = -1;
+       }
+}
+
+extern __inline__ void set_play_depth(int board, int depth)
+{
+       if (depth > 60)
+               depth = 60;
+       if (depth < 0)
+               depth = 0;
+       ixj_WriteDSPCommand(0x5280 + depth, board);
+}
+
+extern __inline__ void set_play_volume(int board, int volume)
+{
+       ixj_WriteDSPCommand(0xCF02, board);
+       ixj_WriteDSPCommand(volume, board);
+}
+
+extern __inline__ int get_play_level(int board)
+{
+       ixj_WriteDSPCommand(0xCF8F, board);
+       return ixj[board].ssr.high << 8 | ixj[board].ssr.low;
+}
+
+static unsigned int ixj_poll(struct file *file_p, poll_table * wait)
+{
+       unsigned int mask = 0;
+       IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+       poll_wait(file_p, &(j->poll_q), wait);
+       if (j->read_buffer_ready > 0)
+               mask |= POLLIN | POLLRDNORM;    /* readable */
+       if (j->write_buffers_empty > 0)
+               mask |= POLLOUT | POLLWRNORM;   /* writable */
+       if (j->ex.bytes)
+               mask |= POLLPRI;
+       return mask;
+}
+
+static int ixj_play_tone(int board, char tone)
+{
+       IXJ *j = &ixj[board];
+
+       if (!j->tone_state)
+               idle(board);
+
+       j->tone_index = tone;
+       if (ixj_WriteDSPCommand(0x6000 + j->tone_index, board))
+               return -1;
+
+       if (!j->tone_state) {
+               j->tone_start_jif = jiffies;
+
+               j->tone_state = 1;
+       }
+       return 0;
+}
+
+static int ixj_set_tone_on(unsigned short arg, int board)
+{
+       IXJ *j = &ixj[board];
+
+       j->tone_on_time = arg;
+
+       if (ixj_WriteDSPCommand(0x6E04, board))         // Set Tone On Period
+
+               return -1;
+
+       if (ixj_WriteDSPCommand(arg, board))
+               return -1;
+
+       return 0;
+}
+
+static int SCI_WaitHighSCI(int board)
+{
+       int cnt;
+       IXJ *j = &ixj[board];
+
+       j->pld_scrr.byte = inb_p(j->XILINXbase);
+       if (!j->pld_scrr.bits.sci) {
+               for (cnt = 0; cnt < 10; cnt++) {
+                       udelay(32);
+                       j->pld_scrr.byte = inb_p(j->XILINXbase);
+
+                       if ((j->pld_scrr.bits.sci))
+                               return 1;
+               }
+               if (ixjdebug > 1)
+                       printk(KERN_INFO "SCI Wait High failed %x\n", j->pld_scrr.byte);
+               return 0;
+       } else
+               return 1;
+}
+
+static int SCI_WaitLowSCI(int board)
+{
+       int cnt;
+       IXJ *j = &ixj[board];
+
+       j->pld_scrr.byte = inb_p(j->XILINXbase);
+       if (j->pld_scrr.bits.sci) {
+               for (cnt = 0; cnt < 10; cnt++) {
+                       udelay(32);
+                       j->pld_scrr.byte = inb_p(j->XILINXbase);
+
+                       if (!(j->pld_scrr.bits.sci))
+                               return 1;
+               }
+               if (ixjdebug > 1)
+                       printk(KERN_INFO "SCI Wait Low failed %x\n", j->pld_scrr.byte);
+               return 0;
+       } else
+               return 1;
+}
+
+static int SCI_Control(int board, int control)
+{
+       IXJ *j = &ixj[board];
+
+       switch (control) {
+       case SCI_End:
+               j->pld_scrw.bits.c0 = 0;        // Set PLD Serial control interface
+
+               j->pld_scrw.bits.c1 = 0;        // to no selection 
+
+               break;
+       case SCI_Enable_DAA:
+               j->pld_scrw.bits.c0 = 1;        // Set PLD Serial control interface
+
+               j->pld_scrw.bits.c1 = 0;        // to write to DAA
+
+               break;
+       case SCI_Enable_Mixer:
+               j->pld_scrw.bits.c0 = 0;        // Set PLD Serial control interface
+
+               j->pld_scrw.bits.c1 = 1;        // to write to mixer 
+
+               break;
+       case SCI_Enable_EEPROM:
+               j->pld_scrw.bits.c0 = 1;        // Set PLD Serial control interface
+
+               j->pld_scrw.bits.c1 = 1;        // to write to EEPROM 
+
+               break;
+       default:
+               return 0;
+               break;
+       }
+       outb_p(j->pld_scrw.byte, j->XILINXbase);
+
+       switch (control) {
+       case SCI_End:
+               return 1;
+               break;
+       case SCI_Enable_DAA:
+       case SCI_Enable_Mixer:
+       case SCI_Enable_EEPROM:
+               if (!SCI_WaitHighSCI(board))
+                       return 0;
+               break;
+       default:
+               return 0;
+               break;
+       }
+       return 1;
+}
+
+static int SCI_Prepare(int board)
+{
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       return 1;
+}
+
+static int ixj_mixer(long val, int board)
+{
+       BYTES bytes;
+       IXJ *j = &ixj[board];
+
+       bytes.high = (val & 0xFF00) >> 8;
+       bytes.low = val & 0x00FF;
+
+       outb_p(bytes.high & 0x1F, j->XILINXbase + 0x03);        // Load Mixer Address
+
+       outb_p(bytes.low, j->XILINXbase + 0x02);        // Load Mixer Data
+
+       SCI_Control(board, SCI_Enable_Mixer);
+
+       SCI_Control(board, SCI_End);
+
+       return 0;
+}
+
+static int daa_load(BYTES * p_bytes, int board)
+{
+       IXJ *j = &ixj[board];
+
+       outb_p(p_bytes->high, j->XILINXbase + 0x03);
+       outb_p(p_bytes->low, j->XILINXbase + 0x02);
+       if (!SCI_Control(board, SCI_Enable_DAA))
+               return 0;
+       else
+               return 1;
+}
+
+static int ixj_daa_cr4(int board, char reg)
+{
+       IXJ *j = &ixj[board];
+       BYTES bytes;
+
+       switch (j->daa_mode) {
+       case SOP_PU_SLEEP:
+               bytes.high = 0x14;
+               break;
+       case SOP_PU_RINGING:
+               bytes.high = 0x54;
+               break;
+       case SOP_PU_CONVERSATION:
+               bytes.high = 0x94;
+               break;
+       case SOP_PU_PULSEDIALING:
+               bytes.high = 0xD4;
+               break;
+       }
+
+       switch (j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGX) {
+       case 0:
+               j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 0;
+               break;
+       case 1:
+               j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 2;
+               break;
+       case 2:
+               j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 1;
+               break;
+       case 3:
+               j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 3;
+               break;
+       }
+
+       bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg;
+
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       return 1;
+}
+
+static char daa_int_read(int board)
+{
+       BYTES bytes;
+       IXJ *j = &ixj[board];
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       bytes.high = 0x38;
+       bytes.low = 0x00;
+       outb_p(bytes.high, j->XILINXbase + 0x03);
+       outb_p(bytes.low, j->XILINXbase + 0x02);
+
+       if (!SCI_Control(board, SCI_Enable_DAA))
+               return 0;
+
+       bytes.high = inb_p(j->XILINXbase + 0x03);
+       bytes.low = inb_p(j->XILINXbase + 0x02);
+       if (bytes.low != ALISDAA_ID_BYTE) {
+               if (ixjdebug > 0)
+                       printk("Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+               return 0;
+       }
+       if (!SCI_Control(board, SCI_Enable_DAA))
+               return 0;
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+
+       bytes.high = inb_p(j->XILINXbase + 0x03);
+       bytes.low = inb_p(j->XILINXbase + 0x02);
+
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.reg = bytes.high;
+       return 1;
+}
+
+static int ixj_daa_cid_reset(int board)
+{
+       int i;
+       BYTES bytes;
+       IXJ *j = &ixj[board];
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       bytes.high = 0x58;
+       bytes.low = 0x00;
+       outb_p(bytes.high, j->XILINXbase + 0x03);
+       outb_p(bytes.low, j->XILINXbase + 0x02);
+
+       if (!SCI_Control(board, SCI_Enable_DAA))
+               return 0;
+
+       if (!SCI_WaitHighSCI(board))
+               return 0;
+
+       for (i = 0; i < ALISDAA_CALLERID_SIZE - 1; i += 2) {
+               bytes.high = bytes.low = 0x00;
+               outb_p(bytes.high, j->XILINXbase + 0x03);
+
+               if (i < ALISDAA_CALLERID_SIZE - 1)
+                       outb_p(bytes.low, j->XILINXbase + 0x02);
+
+               if (!SCI_Control(board, SCI_Enable_DAA))
+                       return 0;
+
+               if (!SCI_WaitHighSCI(board))
+                       return 0;
+
+       }
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+
+       return 1;
+}
+
+static int ixj_daa_cid_read(int board)
+{
+       int i;
+       BYTES bytes;
+       char CID[ALISDAA_CALLERID_SIZE], mContinue;
+       char *pIn, *pOut;
+       IXJ *j = &ixj[board];
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       bytes.high = 0x78;
+       bytes.low = 0x00;
+       outb_p(bytes.high, j->XILINXbase + 0x03);
+       outb_p(bytes.low, j->XILINXbase + 0x02);
+
+       if (!SCI_Control(board, SCI_Enable_DAA))
+               return 0;
+
+       if (!SCI_WaitHighSCI(board))
+               return 0;
+
+       bytes.high = inb_p(j->XILINXbase + 0x03);
+       bytes.low = inb_p(j->XILINXbase + 0x02);
+       if (bytes.low != ALISDAA_ID_BYTE) {
+               if (ixjdebug > 0)
+                       printk("DAA Get Version Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+               return 0;
+       }
+       for (i = 0; i < ALISDAA_CALLERID_SIZE; i += 2) {
+               bytes.high = bytes.low = 0x00;
+               outb_p(bytes.high, j->XILINXbase + 0x03);
+               outb_p(bytes.low, j->XILINXbase + 0x02);
+
+               if (!SCI_Control(board, SCI_Enable_DAA))
+                       return 0;
+
+               if (!SCI_WaitHighSCI(board))
+                       return 0;
+
+               CID[i + 0] = inb_p(j->XILINXbase + 0x03);
+               CID[i + 1] = inb_p(j->XILINXbase + 0x02);
+       }
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+
+       pIn = CID;
+       pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID;
+       mContinue = 1;
+       while (mContinue) {
+               if ((pIn[1] & 0x03) == 0x01) {
+                       pOut[0] = pIn[0];
+               }
+               if ((pIn[2] & 0x0c) == 0x04) {
+                       pOut[1] = ((pIn[2] & 0x03) << 6) | ((pIn[1] & 0xfc) >> 2);
+               }
+               if ((pIn[3] & 0x30) == 0x10) {
+                       pOut[2] = ((pIn[3] & 0x0f) << 4) | ((pIn[2] & 0xf0) >> 4);
+               }
+               if ((pIn[4] & 0xc0) == 0x40) {
+                       pOut[3] = ((pIn[4] & 0x3f) << 2) | ((pIn[3] & 0xc0) >> 6);
+               } else {
+                       mContinue = FALSE;
+               }
+               pIn += 5, pOut += 4;
+       }
+       memset(&j->cid, 0, sizeof(IXJ_CID));
+       pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID;
+       pOut += 4;
+       strncpy(j->cid.month, pOut, 2);
+       pOut += 2;
+       strncpy(j->cid.day, pOut, 2);
+       pOut += 2;
+       strncpy(j->cid.hour, pOut, 2);
+       pOut += 2;
+       strncpy(j->cid.min, pOut, 2);
+       pOut += 3;
+       j->cid.numlen = *pOut;
+       pOut += 1;
+       strncpy(j->cid.number, pOut, j->cid.numlen);
+       pOut += j->cid.numlen + 1;
+       j->cid.namelen = *pOut;
+       pOut += 1;
+       strncpy(j->cid.name, pOut, j->cid.namelen);
+
+       ixj_daa_cid_reset(board);
+       return 1;
+}
+
+static char daa_get_version(int board)
+{
+       BYTES bytes;
+       IXJ *j = &ixj[board];
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       bytes.high = 0x35;
+       bytes.low = 0x00;
+       outb_p(bytes.high, j->XILINXbase + 0x03);
+       outb_p(bytes.low, j->XILINXbase + 0x02);
+
+       if (!SCI_Control(board, SCI_Enable_DAA))
+               return 0;
+
+       bytes.high = inb_p(j->XILINXbase + 0x03);
+       bytes.low = inb_p(j->XILINXbase + 0x02);
+       if (bytes.low != ALISDAA_ID_BYTE) {
+               if (ixjdebug > 0)
+                       printk("DAA Get Version Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+               return 0;
+       }
+       if (!SCI_Control(board, SCI_Enable_DAA))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+
+       bytes.high = inb_p(j->XILINXbase + 0x03);
+       bytes.low = inb_p(j->XILINXbase + 0x02);
+       if (ixjdebug > 0)
+               printk("DAA CR5 Byte high = 0x%x low = 0x%x\n", bytes.high, bytes.low);
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr5.reg = bytes.high;
+       return bytes.high;
+}
+
+static int daa_set_mode(int board, int mode)
+{
+       // NOTE:
+       //      The DAA *MUST* be in the conversation mode if the
+       //      PSTN line is to be seized (PSTN line off-hook).
+       //      Taking the PSTN line off-hook while the DAA is in
+       //      a mode other than conversation mode will cause a
+       //      hardware failure of the ALIS-A part.
+
+       // NOTE:
+       //      The DAA can only go to SLEEP, RINGING or PULSEDIALING modes
+       //      if the PSTN line is on-hook.  Failure to have the PSTN line
+       //      in the on-hook state WILL CAUSE A HARDWARE FAILURE OF THE
+       //      ALIS-A part.
+       //
+
+
+       BYTES bytes;
+       IXJ *j = &ixj[board];
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       switch (mode) {
+       case SOP_PU_SLEEP:
+               j->pld_scrw.bits.daafsyncen = 0;        // Turn off DAA Frame Sync
+
+               outb_p(j->pld_scrw.byte, j->XILINXbase);
+               j->pld_slicw.bits.rly2 = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               bytes.high = 0x10;
+               bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+               daa_load(&bytes, board);
+               if (!SCI_Prepare(board))
+                       return 0;
+               j->daa_mode = SOP_PU_SLEEP;
+               j->flags.pstn_ringing = 0;
+               j->pstn_sleeptil = jiffies + (hertz * 3);
+               break;
+       case SOP_PU_RINGING:
+               j->pld_scrw.bits.daafsyncen = 0;        // Turn off DAA Frame Sync
+
+               outb_p(j->pld_scrw.byte, j->XILINXbase);
+               j->pld_slicw.bits.rly2 = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               bytes.high = 0x50;
+               bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+               daa_load(&bytes, board);
+               if (!SCI_Prepare(board))
+                       return 0;
+               j->daa_mode = SOP_PU_RINGING;
+               break;
+       case SOP_PU_CONVERSATION:
+               bytes.high = 0x90;
+               bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+               daa_load(&bytes, board);
+               if (!SCI_Prepare(board))
+                       return 0;
+               j->pld_slicw.bits.rly2 = 1;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               j->pld_scrw.bits.daafsyncen = 1;        // Turn on DAA Frame Sync
+
+               outb_p(j->pld_scrw.byte, j->XILINXbase);
+               j->daa_mode = SOP_PU_CONVERSATION;
+               j->flags.pstn_ringing = 0;
+               j->ex.bits.pstn_ring = 0;
+               break;
+       case SOP_PU_PULSEDIALING:
+               j->pld_scrw.bits.daafsyncen = 0;        // Turn off DAA Frame Sync
+
+               outb_p(j->pld_scrw.byte, j->XILINXbase);
+               j->pld_slicw.bits.rly2 = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               bytes.high = 0xD0;
+               bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+               daa_load(&bytes, board);
+               if (!SCI_Prepare(board))
+                       return 0;
+               j->daa_mode = SOP_PU_PULSEDIALING;
+               break;
+       default:
+               break;
+       }
+       return 1;
+}
+
+static int ixj_daa_write(int board)
+{
+       BYTES bytes;
+       IXJ *j = &ixj[board];
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       bytes.high = 0x14;
+       bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg;
+       bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg;
+       bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       bytes.high = 0x1F;
+       bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.XOP_xr6_W.reg;
+       bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg;
+       bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg;
+       bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.XOP_xr0_W.reg;
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Prepare(board))
+               return 0;
+
+       bytes.high = 0x00;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x01;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x02;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x03;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x04;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x05;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x06;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x07;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x08;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x09;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x0A;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x0B;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x0C;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x0D;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x0E;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+       if (!SCI_WaitLowSCI(board))
+               return 0;
+
+       bytes.high = 0x0F;
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2];
+       bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1];
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0];
+       bytes.low = 0x00;
+       if (!daa_load(&bytes, board))
+               return 0;
+
+       udelay(32);
+       j->pld_scrr.byte = inb_p(j->XILINXbase);
+       if (!SCI_Control(board, SCI_End))
+               return 0;
+
+       return 1;
+}
+
+int ixj_set_tone_off(unsigned short arg, int board)
+{
+       ixj[board].tone_off_time = arg;
+
+       if (ixj_WriteDSPCommand(0x6E05, board))         // Set Tone Off Period
+
+               return -1;
+
+       if (ixj_WriteDSPCommand(arg, board))
+               return -1;
+
+       return 0;
+}
+
+static int ixj_get_tone_on(int board)
+{
+       if (ixj_WriteDSPCommand(0x6E06, board))         // Get Tone On Period
+
+               return -1;
+
+       return 0;
+}
+
+static int ixj_get_tone_off(int board)
+{
+       if (ixj_WriteDSPCommand(0x6E07, board))         // Get Tone Off Period
+
+               return -1;
+
+       return 0;
+}
+
+static void ixj_busytone(int board)
+{
+       ixj[board].flags.ringback = 0;
+       ixj[board].flags.dialtone = 0;
+       ixj[board].flags.busytone = 1;
+
+       ixj_set_tone_on(0x07D0, board);
+       ixj_set_tone_off(0x07D0, board);
+       ixj_play_tone(board, 27);
+}
+
+static void ixj_dialtone(int board)
+{
+       ixj[board].flags.ringback = 0;
+       ixj[board].flags.dialtone = 1;
+       ixj[board].flags.busytone = 0;
+
+       if (ixj[board].dsp.low == 0x20) {
+               return;
+       } else {
+               ixj_set_tone_on(0xFFFF, board);
+               ixj_set_tone_off(0x0000, board);
+
+               ixj_play_tone(board, 25);
+       }
+}
+
+static void ixj_cpt_stop(board)
+{
+       IXJ *j = &ixj[board];
+
+       j->flags.dialtone = 0;
+       j->flags.busytone = 0;
+       j->flags.ringback = 0;
+
+       ixj_set_tone_on(0x0001, board);
+       ixj_set_tone_off(0x0000, board);
+
+       ixj_play_tone(board, 0);
+
+       j->tone_state = 0;
+
+       ixj_del_timer();
+       if (j->cadence_t) {
+               if (j->cadence_t->ce) {
+                       kfree(j->cadence_t->ce);
+               }
+               kfree(j->cadence_t);
+               j->cadence_t = NULL;
+       }
+       ixj_add_timer();
+       if (j->dsp.low == 0x20 || (j->play_mode == -1 && j->rec_mode == -1))
+               idle(board);
+       if (j->play_mode != -1)
+               ixj_play_start(board);
+       if (j->rec_mode != -1)
+               ixj_record_start(board);
+}
+
+static void ixj_ringback(int board)
+{
+       ixj[board].flags.busytone = 0;
+       ixj[board].flags.dialtone = 0;
+       ixj[board].flags.ringback = 1;
+
+       ixj_set_tone_on(0x0FA0, board);
+       ixj_set_tone_off(0x2EE0, board);
+       ixj_play_tone(board, 26);
+}
+
+static void ixj_testram(int board)
+{
+       ixj_WriteDSPCommand(0x3001, board);     /* Test External SRAM */
+}
+
+static int ixj_build_cadence(int board, IXJ_CADENCE * cp)
+{
+       IXJ_CADENCE *lcp;
+       IXJ_CADENCE_ELEMENT *lcep;
+       IXJ_TONE ti;
+       IXJ *j = &ixj[board];
+
+       lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL);
+       if (lcp == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)))
+               return -EFAULT;
+
+       lcep = kmalloc(sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used, GFP_KERNEL);
+       if (lcep == NULL) {
+               kfree(lcp);
+               return -ENOMEM;
+       }
+       if (copy_from_user(lcep, lcp->ce, sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used))
+               return -EFAULT;
+
+       if(j->cadence_t)
+       {
+               kfree(j->cadence_t->ce);
+               kfree(j->cadence_t);
+       }
+       
+       lcp->ce = (void *) lcep;
+       j->cadence_t = lcp;
+       j->tone_cadence_state = 0;
+       ixj_set_tone_on(lcp->ce[0].tone_on_time, board);
+       ixj_set_tone_off(lcp->ce[0].tone_off_time, board);
+       if (j->cadence_t->ce[j->tone_cadence_state].freq0) {
+               ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+               ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+               ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+               ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+               ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+               ixj_init_tone(board, &ti);
+       }
+       ixj_play_tone(board, lcp->ce[0].index);
+
+       return 1;
+}
+
+static void add_caps(int board)
+{
+       IXJ *j = &ixj[board];
+       j->caps = 0;
+
+       j->caplist[j->caps].cap = vendor;
+       strcpy(j->caplist[j->caps].desc, "Quicknet Technologies, Inc. (www.quicknet.net)");
+       j->caplist[j->caps].captype = vendor;
+       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].captype = device;
+       switch (j->cardtype) {
+       case 100:
+               strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK");
+               j->caplist[j->caps].cap = 100;
+               break;
+       case 300:
+               strcpy(j->caplist[j->caps].desc, "Quicknet Internet LineJACK");
+               j->caplist[j->caps].cap = 300;
+               break;
+       case 400:
+               strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK Lite");
+               j->caplist[j->caps].cap = 400;
+               break;
+       case 500:
+               strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK PCI");
+               j->caplist[j->caps].cap = 500;
+               break;
+       }
+       j->caplist[j->caps].handle = j->caps++;
+       strcpy(j->caplist[j->caps].desc, "POTS");
+       j->caplist[j->caps].captype = port;
+       j->caplist[j->caps].cap = pots;
+       j->caplist[j->caps].handle = j->caps++;
+       switch (ixj[board].cardtype) {
+       case 100:
+               strcpy(j->caplist[j->caps].desc, "SPEAKER");
+               j->caplist[j->caps].captype = port;
+               j->caplist[j->caps].cap = speaker;
+               j->caplist[j->caps].handle = j->caps++;
+               strcpy(j->caplist[j->caps].desc, "HANDSET");
+               j->caplist[j->caps].captype = port;
+               j->caplist[j->caps].cap = handset;
+               j->caplist[j->caps].handle = j->caps++;
+               break;
+       case 300:
+               strcpy(j->caplist[j->caps].desc, "SPEAKER");
+               j->caplist[j->caps].captype = port;
+               j->caplist[j->caps].cap = speaker;
+               j->caplist[j->caps].handle = j->caps++;
+               strcpy(j->caplist[j->caps].desc, "PSTN");
+               j->caplist[j->caps].captype = port;
+               j->caplist[j->caps].cap = pstn;
+               j->caplist[j->caps].handle = j->caps++;
+               break;
+       }
+       strcpy(j->caplist[j->caps].desc, "ULAW");
+       j->caplist[j->caps].captype = codec;
+       j->caplist[j->caps].cap = ULAW;
+       j->caplist[j->caps].handle = j->caps++;
+       strcpy(j->caplist[j->caps].desc, "LINEAR 16 bit");
+       j->caplist[j->caps].captype = codec;
+       j->caplist[j->caps].cap = LINEAR16;
+       j->caplist[j->caps].handle = j->caps++;
+       strcpy(j->caplist[j->caps].desc, "LINEAR 8 bit");
+       j->caplist[j->caps].captype = codec;
+       j->caplist[j->caps].cap = LINEAR8;
+       j->caplist[j->caps].handle = j->caps++;
+       strcpy(j->caplist[j->caps].desc, "Windows Sound System");
+       j->caplist[j->caps].captype = codec;
+       j->caplist[j->caps].cap = WSS;
+       j->caplist[j->caps].handle = j->caps++;
+       if (j->ver.low != 0x12) {
+               strcpy(j->caplist[j->caps].desc, "G.723.1 6.3Kbps");
+               j->caplist[j->caps].captype = codec;
+               j->caplist[j->caps].cap = G723_63;
+               j->caplist[j->caps].handle = j->caps++;
+               strcpy(j->caplist[j->caps].desc, "G.723.1 5.3Kbps");
+               j->caplist[j->caps].captype = codec;
+               j->caplist[j->caps].cap = G723_53;
+               j->caplist[j->caps].handle = j->caps++;
+               strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.8Kbps");
+               j->caplist[j->caps].captype = codec;
+               j->caplist[j->caps].cap = TS48;
+               j->caplist[j->caps].handle = j->caps++;
+               strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.1Kbps");
+               j->caplist[j->caps].captype = codec;
+               j->caplist[j->caps].cap = TS41;
+               j->caplist[j->caps].handle = j->caps++;
+       }
+       if (j->cardtype == 100) {
+               strcpy(j->caplist[j->caps].desc, "TrueSpeech 8.5Kbps");
+               j->caplist[j->caps].captype = codec;
+               j->caplist[j->caps].cap = TS85;
+               j->caplist[j->caps].handle = j->caps++;
+       }
+}
+static int capabilities_check(int board, struct phone_capability *pcreq)
+{
+       int cnt;
+       IXJ *j = &ixj[board];
+       int retval = 0;
+
+       for (cnt = 0; cnt < j->caps; cnt++) {
+               if (pcreq->captype == j->caplist[cnt].captype &&
+                   pcreq->cap == j->caplist[cnt].cap) {
+                       retval = 1;
+                       break;
+               }
+       }
+       return retval;
+}
+
+int ixj_ioctl(struct inode *inode, struct file *file_p,
+             unsigned int cmd, unsigned long arg)
+{
+       IXJ_TONE ti;
+       IXJ_FILTER jf;
+       unsigned int minor = MINOR(inode->i_rdev);
+       int board = NUM(inode->i_rdev);
+       IXJ *j = &ixj[NUM(inode->i_rdev)];
+       int retval = 0;
+
+       if (ixjdebug > 1)
+               printk(KERN_DEBUG "phone%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
+       if (minor >= IXJMAX)
+               return -ENODEV;
+
+       /*
+        *    Check ioctls only root can use.
+        */
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               switch (cmd) {
+               case IXJCTL_TESTRAM:
+               case IXJCTL_HZ:
+                       return -EPERM;
+               }
+       }
+       switch (cmd) {
+       case IXJCTL_TESTRAM:
+               ixj_testram(board);
+               retval = (j->ssr.high << 8) + j->ssr.low;
+               break;
+       case IXJCTL_CARDTYPE:
+               retval = j->cardtype;
+               break;
+       case IXJCTL_SERIAL:
+               retval = j->serial;
+               break;
+       case PHONE_RING_CADENCE:
+               j->ring_cadence = arg;
+               break;
+       case PHONE_RING_START:
+               ixj_ring_start(board);
+               break;
+       case PHONE_RING_STOP:
+               j->flags.cringing = 0;
+               ixj_ring_off(board);
+               break;
+       case PHONE_RING:
+               retval = ixj_ring(board);
+               break;
+       case PHONE_EXCEPTION:
+               retval = j->ex.bytes;
+               j->ex.bytes &= 0x03;
+               break;
+       case PHONE_HOOKSTATE:
+               j->ex.bits.hookstate = 0;
+               retval = j->r_hook;
+               break;
+       case IXJCTL_SET_LED:
+               LED_SetState(arg, board);
+               break;
+       case PHONE_FRAME:
+               retval = set_base_frame(board, arg);
+               break;
+       case PHONE_REC_CODEC:
+               retval = set_rec_codec(board, arg);
+               break;
+       case PHONE_REC_START:
+               ixj_record_start(board);
+               break;
+       case PHONE_REC_STOP:
+               ixj_record_stop(board);
+               break;
+       case PHONE_REC_DEPTH:
+               set_rec_depth(board, arg);
+               break;
+       case PHONE_REC_VOLUME:
+               set_rec_volume(board, arg);
+               break;
+       case PHONE_REC_LEVEL:
+               retval = get_rec_level(board);
+               break;
+       case IXJCTL_AEC_START:
+               ixj_aec_start(board, arg);
+               break;
+       case IXJCTL_AEC_STOP:
+               aec_stop(board);
+               break;
+       case IXJCTL_AEC_GET_LEVEL:
+               retval = j->aec_level;
+               break;
+       case PHONE_PLAY_CODEC:
+               retval = set_play_codec(board, arg);
+               break;
+       case PHONE_PLAY_START:
+               ixj_play_start(board);
+               break;
+       case PHONE_PLAY_STOP:
+               ixj_play_stop(board);
+               break;
+       case PHONE_PLAY_DEPTH:
+               set_play_depth(board, arg);
+               break;
+       case PHONE_PLAY_VOLUME:
+               set_play_volume(board, arg);
+               break;
+       case PHONE_PLAY_LEVEL:
+               retval = get_play_level(board);
+               break;
+       case IXJCTL_DSP_TYPE:
+               retval = (j->dsp.high << 8) + j->dsp.low;
+               break;
+       case IXJCTL_DSP_VERSION:
+               retval = (j->ver.high << 8) + j->ver.low;
+               break;
+       case IXJCTL_HZ:
+               hertz = arg;
+               break;
+       case IXJCTL_RATE:
+               if (arg > hertz)
+                       retval = -1;
+               else
+                       samplerate = arg;
+               break;
+       case IXJCTL_DRYBUFFER_READ:
+               put_user(j->drybuffer, (unsigned long *) arg);
+               break;
+       case IXJCTL_DRYBUFFER_CLEAR:
+               j->drybuffer = 0;
+               break;
+       case IXJCTL_FRAMES_READ:
+               put_user(j->framesread, (unsigned long *) arg);
+               break;
+       case IXJCTL_FRAMES_WRITTEN:
+               put_user(j->frameswritten, (unsigned long *) arg);
+               break;
+       case IXJCTL_READ_WAIT:
+               put_user(j->read_wait, (unsigned long *) arg);
+               break;
+       case IXJCTL_WRITE_WAIT:
+               put_user(j->write_wait, (unsigned long *) arg);
+               break;
+       case PHONE_MAXRINGS:
+               j->maxrings = arg;
+               break;
+       case PHONE_SET_TONE_ON_TIME:
+               ixj_set_tone_on(arg, board);
+               break;
+       case PHONE_SET_TONE_OFF_TIME:
+               ixj_set_tone_off(arg, board);
+               break;
+       case PHONE_GET_TONE_ON_TIME:
+               if (ixj_get_tone_on(board)) {
+                       retval = -1;
+               } else {
+                       retval = (j->ssr.high << 8) + j->ssr.low;
+               }
+               break;
+       case PHONE_GET_TONE_OFF_TIME:
+               if (ixj_get_tone_off(board)) {
+                       retval = -1;
+               } else {
+                       retval = (j->ssr.high << 8) + j->ssr.low;
+               }
+               break;
+       case PHONE_PLAY_TONE:
+               if (!j->tone_state)
+                       ixj_play_tone(board, arg);
+               break;
+       case PHONE_GET_TONE_STATE:
+               retval = j->tone_state;
+               break;
+       case PHONE_DTMF_READY:
+               retval = j->ex.bits.dtmf_ready;
+               break;
+       case PHONE_GET_DTMF:
+               if (ixj_hookstate(board)) {
+                       if (j->dtmf_rp != j->dtmf_wp) {
+                               retval = j->dtmfbuffer[j->dtmf_rp];
+                               j->dtmf_rp++;
+                               if (j->dtmf_rp == 79)
+                                       j->dtmf_rp = 0;
+                               if (j->dtmf_rp == j->dtmf_wp) {
+                                       j->ex.bits.dtmf_ready = j->dtmf_rp = j->dtmf_wp = 0;
+                               }
+                       }
+               }
+               break;
+       case PHONE_GET_DTMF_ASCII:
+               if (ixj_hookstate(board)) {
+                       if (j->dtmf_rp != j->dtmf_wp) {
+                               switch (j->dtmfbuffer[j->dtmf_rp]) {
+                               case 10:
+                                       retval = 42;    //'*';
+
+                                       break;
+                               case 11:
+                                       retval = 48;    //'0';
+
+                                       break;
+                               case 12:
+                                       retval = 35;    //'#';
+
+                                       break;
+                               case 28:
+                                       retval = 65;    //'A';
+
+                                       break;
+                               case 29:
+                                       retval = 66;    //'B';
+
+                                       break;
+                               case 30:
+                                       retval = 67;    //'C';
+
+                                       break;
+                               case 31:
+                                       retval = 68;    //'D';
+
+                                       break;
+                               default:
+                                       retval = 48 + j->dtmfbuffer[j->dtmf_rp];
+                                       break;
+                               }
+                               j->dtmf_rp++;
+                               if (j->dtmf_rp == 79)
+                                       j->dtmf_rp = 0;
+//          if(j->dtmf_rp == j->dtmf_wp)
+                               {
+                                       j->ex.bits.dtmf_ready = j->dtmf_rp = j->dtmf_wp = 0;
+                               }
+                       }
+               }
+               break;
+       case PHONE_DTMF_OOB:
+               j->flags.dtmf_oob = arg;
+               break;
+       case PHONE_DIALTONE:
+               ixj_dialtone(board);
+               break;
+       case PHONE_BUSY:
+               ixj_busytone(board);
+               break;
+       case PHONE_RINGBACK:
+               ixj_ringback(board);
+               break;
+       case PHONE_CPT_STOP:
+               ixj_cpt_stop(board);
+               break;
+       case IXJCTL_DSP_IDLE:
+               idle(board);
+               break;
+       case IXJCTL_MIXER:
+               ixj_mixer(arg, board);
+               break;
+       case IXJCTL_DAA_COEFF_SET:
+               switch (arg) {
+               case DAA_US:
+                       DAA_Coeff_US(board);
+                       ixj_daa_write(board);
+                       break;
+               case DAA_UK:
+                       DAA_Coeff_UK(board);
+                       ixj_daa_write(board);
+                       break;
+               case DAA_FRANCE:
+                       DAA_Coeff_France(board);
+                       ixj_daa_write(board);
+                       break;
+               case DAA_GERMANY:
+                       DAA_Coeff_Germany(board);
+                       ixj_daa_write(board);
+                       break;
+               case DAA_AUSTRALIA:
+                       DAA_Coeff_Australia(board);
+                       ixj_daa_write(board);
+                       break;
+               case DAA_JAPAN:
+                       DAA_Coeff_Japan(board);
+                       ixj_daa_write(board);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case IXJCTL_DAA_AGAIN:
+               ixj_daa_cr4(board, arg | 0x02);
+               break;
+       case IXJCTL_PSTN_LINETEST:
+               retval = ixj_linetest(board);
+               break;
+       case IXJCTL_CID:
+               if (copy_to_user((char *) arg, &j->cid, sizeof(IXJ_CID)))
+                       return -EFAULT;
+               j->ex.bits.caller_id = 0;
+               break;
+       case IXJCTL_WINK_DURATION:
+               j->winktime = arg;
+               break;
+       case IXJCTL_PORT:
+               if (arg)
+                       retval = ixj_set_port(board, arg);
+               else
+                       retval = j->port;
+               break;
+       case IXJCTL_POTS_PSTN:
+               retval = ixj_set_pots(board, arg);
+               break;
+       case PHONE_CAPABILITIES:
+               retval = j->caps;
+               break;
+       case PHONE_CAPABILITIES_LIST:
+               if (copy_to_user((char *) arg, j->caplist, sizeof(struct phone_capability) * j->caps))
+                       return -EFAULT;
+               break;
+       case PHONE_CAPABILITIES_CHECK:
+               retval = capabilities_check(board, (struct phone_capability *) arg);
+               break;
+       case PHONE_PSTN_SET_STATE:
+               daa_set_mode(board, arg);
+               break;
+       case PHONE_PSTN_GET_STATE:
+               retval = j->daa_mode;
+               j->ex.bits.pstn_ring = 0;
+               break;
+       case IXJCTL_SET_FILTER:
+               if (copy_from_user(&jf, (char *) arg, sizeof(ti)))
+                       return -EFAULT;
+               retval = ixj_init_filter(board, &jf);
+               break;
+       case IXJCTL_GET_FILTER_HIST:
+               retval = j->filter_hist[arg];
+               break;
+       case IXJCTL_INIT_TONE:
+               copy_from_user(&ti, (char *) arg, sizeof(ti));
+               retval = ixj_init_tone(board, &ti);
+               break;
+       case IXJCTL_TONE_CADENCE:
+               retval = ixj_build_cadence(board, (IXJ_CADENCE *) arg);
+               break;
+       case IXJCTL_INTERCOM_STOP:
+               ixj[board].intercom = -1;
+               ixj[arg].intercom = -1;
+               ixj_record_stop(board);
+               ixj_record_stop(arg);
+               ixj_play_stop(board);
+               ixj_play_stop(arg);
+               idle(board);
+               idle(arg);
+               break;
+       case IXJCTL_INTERCOM_START:
+               ixj[board].intercom = arg;
+               ixj[arg].intercom = board;
+               ixj_play_start(arg);
+               ixj_record_start(board);
+               ixj_play_start(board);
+               ixj_record_start(arg);
+               idle(board);
+               idle(arg);
+               break;
+       }
+       return retval;
+}
+
+static int ixj_fasync(int fd, struct file *file_p, int mode)
+{
+       IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+       return fasync_helper(fd, file_p, mode, &j->async_queue);
+}
+
+struct file_operations ixj_fops =
+{
+       NULL,                   /* ixj_lseek */
+       ixj_enhanced_read,
+       ixj_enhanced_write,
+       NULL,                   /* ixj_readdir */
+       ixj_poll,
+       ixj_ioctl,
+       NULL,                   /* ixj_mmap */
+//  ixj_open,
+       NULL,                   /* ixj_open */
+       NULL,                   /* ixj_flush */
+       ixj_release,
+       NULL,                   /* ixj_fsync */
+       ixj_fasync,             /* ixj_fasync */
+       NULL,                   /* media change */
+       NULL,                   /* revalidate */
+       NULL                    /* lock */
+};
+
+static int ixj_linetest(int board)
+{
+       unsigned long jifwait;
+       IXJ *j = &ixj[board];
+
+       if (!j->flags.pots_correct) {
+               j->flags.pots_correct = 1;      // Testing
+
+               daa_int_read(board);    //Clear DAA Interrupt flags
+               //
+               // Hold all relays in the normally de-energized position.
+               //
+
+               j->pld_slicw.bits.rly1 = 0;
+               j->pld_slicw.bits.rly2 = 0;
+               j->pld_slicw.bits.rly3 = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               j->pld_scrw.bits.daafsyncen = 0;        // Turn off DAA Frame Sync
+
+               outb_p(j->pld_scrw.byte, j->XILINXbase);
+               j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01);
+               if (j->pld_slicr.bits.potspstn) {
+                       j->flags.pots_pstn = 1;
+                       j->flags.pots_correct = 0;
+                       LED_SetState(0x4, board);
+               } else {
+                       j->flags.pots_pstn = 0;
+                       j->pld_slicw.bits.rly1 = 0;
+                       j->pld_slicw.bits.rly2 = 0;
+                       j->pld_slicw.bits.rly3 = 1;
+                       outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                       j->pld_scrw.bits.daafsyncen = 0;        // Turn off DAA Frame Sync
+
+                       outb_p(j->pld_scrw.byte, j->XILINXbase);
+                       daa_set_mode(board, SOP_PU_CONVERSATION);
+                       jifwait = jiffies + hertz;
+                       while (time_before(jiffies, jifwait)) {
+                               current->state = TASK_INTERRUPTIBLE;
+                               schedule_timeout(1);
+                       }
+                       daa_int_read(board);
+                       daa_set_mode(board, SOP_PU_SLEEP);
+                       if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+                               j->flags.pots_correct = 0;      // Should not be line voltage on POTS port.
+
+                               LED_SetState(0x4, board);
+                               j->pld_slicw.bits.rly3 = 0;
+                               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                       } else {
+                               j->flags.pots_correct = 1;
+                               LED_SetState(0x8, board);
+                               j->pld_slicw.bits.rly1 = 1;
+                               j->pld_slicw.bits.rly2 = 0;
+                               j->pld_slicw.bits.rly3 = 0;
+                               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                       }
+               }
+       }
+       if (!j->flags.pstn_present) {
+               j->pld_slicw.bits.rly3 = 0;
+               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+               daa_set_mode(board, SOP_PU_CONVERSATION);
+               jifwait = jiffies + hertz;
+               while (time_before(jiffies, jifwait)) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+               }
+               daa_int_read(board);
+               daa_set_mode(board, SOP_PU_SLEEP);
+               if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+                       j->flags.pstn_present = 1;
+               } else {
+                       j->flags.pstn_present = 0;
+               }
+       }
+       if (j->flags.pstn_present) {
+               if (j->flags.pots_correct) {
+                       LED_SetState(0xA, board);
+               } else {
+                       LED_SetState(0x6, board);
+               }
+       } else {
+               if (j->flags.pots_correct) {
+                       LED_SetState(0x9, board);
+               } else {
+                       LED_SetState(0x5, board);
+               }
+       }
+       return j->flags.pstn_present;
+}
+
+static int ixj_selfprobe(int board)
+{
+       unsigned short cmd;
+       unsigned long jif;
+       BYTES bytes;
+       IXJ *j = &ixj[board];
+       
+       /*
+        *      First initialise the queues
+        */
+
+       init_waitqueue_head(&j->read_q);
+       init_waitqueue_head(&j->write_q);
+       init_waitqueue_head(&j->poll_q);
+
+       /*
+        *      Now we can probe
+        */
+        
+       if (ixjdebug > 0)
+               printk(KERN_INFO "Write IDLE to Software Control Register\n");
+
+       if (ixj_WriteDSPCommand(0x0000, board))         /* Write IDLE to Software Control Register */
+               return -1;
+
+// The read values of the SSR should be 0x00 for the IDLE command
+       if (j->ssr.low || j->ssr.high)
+               return -1;
+
+       if (ixjdebug > 0)
+               printk(KERN_INFO "Get Device ID Code\n");
+
+       if (ixj_WriteDSPCommand(0x3400, board))         /* Get Device ID Code */
+               return -1;
+
+       j->dsp.low = j->ssr.low;
+       j->dsp.high = j->ssr.high;
+
+       if (ixjdebug > 0)
+               printk(KERN_INFO "Get Device Version Code\n");
+
+       if (ixj_WriteDSPCommand(0x3800, board))         /* Get Device Version Code */
+               return -1;
+
+       j->ver.low = j->ssr.low;
+       j->ver.high = j->ssr.high;
+
+       if (!j->cardtype) {
+               if (j->dsp.low == 0x21) {
+                       j->XILINXbase = j->DSPbase + 0x10;
+                       bytes.high = bytes.low = inb_p(j->XILINXbase + 0x02);
+                       outb_p(bytes.low ^ 0xFF, j->XILINXbase + 0x02);
+                       // Test for Internet LineJACK or Internet PhoneJACK Lite
+                       bytes.low = inb_p(j->XILINXbase + 0x02);
+                       if (bytes.low == bytes.high)    //  Register is read only on
+                                    //  Internet PhoneJack Lite
+                       {
+                               j->cardtype = 400;      // Internet PhoneJACK Lite
+
+                               if (check_region(j->XILINXbase, 4)) {
+                                       printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+                                       return -1;
+                               }
+                               request_region(j->XILINXbase, 4, "ixj control");
+                               j->pld_slicw.pcib.e1 = 1;
+                               outb_p(j->pld_slicw.byte, j->XILINXbase);
+                       } else {
+                               j->cardtype = 300;      // Internet LineJACK
+
+                               if (check_region(j->XILINXbase, 8)) {
+                                       printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+                                       return -1;
+                               }
+                               request_region(j->XILINXbase, 8, "ixj control");
+                       }
+               } else if (j->dsp.low == 0x22) {
+                       j->cardtype = 500;      // Internet PhoneJACK PCI
+
+                       request_region(j->XILINXbase, 4, "ixj control");
+                       j->pld_slicw.pcib.e1 = 1;
+                       outb_p(j->pld_slicw.byte, j->XILINXbase);
+               } else
+                       j->cardtype = 100;      // Internet PhoneJACK
+
+       } else {
+               switch (j->cardtype) {
+               case 100:       // Internet PhoneJACK
+
+                       if (!j->dsp.low != 0x20) {
+                               j->dsp.high = 0x80;
+                               j->dsp.low = 0x20;
+                               ixj_WriteDSPCommand(0x3800, board);
+                               j->ver.low = j->ssr.low;
+                               j->ver.high = j->ssr.high;
+                       }
+                       break;
+               case 300:       // Internet LineJACK
+
+                       if (check_region(j->XILINXbase, 8)) {
+                               printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+                               return -1;
+                       }
+                       request_region(j->XILINXbase, 8, "ixj control");
+                       break;
+               case 400:       //Internet PhoneJACK Lite
+
+               case 500:       //Internet PhoneJACK PCI
+
+                       if (check_region(j->XILINXbase, 4)) {
+                               printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+                               return -1;
+                       }
+                       request_region(j->XILINXbase, 4, "ixj control");
+                       j->pld_slicw.pcib.e1 = 1;
+                       outb_p(j->pld_slicw.byte, j->XILINXbase);
+                       break;
+               }
+       }
+       if (j->dsp.low == 0x20 || j->cardtype == 400 || j->cardtype == 500) {
+               if (ixjdebug > 0)
+                       printk(KERN_INFO "Write CODEC config to Software Control Register\n");
+
+               if (ixj_WriteDSPCommand(0xC462, board))         /* Write CODEC config to Software Control Register */
+                       return -1;
+
+               if (ixjdebug > 0)
+                       printk(KERN_INFO "Write CODEC timing to Software Control Register\n");
+
+               if (j->cardtype == 100) {
+                       cmd = 0x9FF2;
+               } else {
+                       cmd = 0x9FF5;
+               }
+               if (ixj_WriteDSPCommand(cmd, board))    /* Write CODEC timing to Software Control Register */
+                       return -1;
+       } else {
+               if (set_base_frame(board, 30) != 30)
+                       return -1;
+
+               if (j->cardtype == 300) {
+                       if (ixjdebug > 0)
+                               printk(KERN_INFO "Write CODEC config to Software Control Register\n");
+
+                       if (ixj_WriteDSPCommand(0xC528, board))         /* Write CODEC config to Software Control Register */
+                               return -1;
+
+                       if (ixjdebug > 0)
+                               printk(KERN_INFO "Turn on the PLD Clock at 8Khz\n");
+
+                       j->pld_clock.byte = 0;
+                       outb_p(j->pld_clock.byte, j->XILINXbase + 0x04);
+               }
+       }
+
+       if (j->dsp.low == 0x20) {
+               if (ixjdebug > 0)
+                       printk(KERN_INFO "Configure GPIO pins\n");
+
+               j->gpio.bytes.high = 0x09;
+               /*  bytes.low = 0xEF;  0xF7 */
+               j->gpio.bits.gpio1 = 1;
+               j->gpio.bits.gpio2 = 1;
+               j->gpio.bits.gpio3 = 0;
+               j->gpio.bits.gpio4 = 1;
+               j->gpio.bits.gpio5 = 1;
+               j->gpio.bits.gpio6 = 1;
+               j->gpio.bits.gpio7 = 1;
+               ixj_WriteDSPCommand(ixj[board].gpio.word, board);       /* Set GPIO pin directions */
+
+               if (ixjdebug > 0)
+                       printk(KERN_INFO "Enable SLIC\n");
+
+               j->gpio.bytes.high = 0x0B;
+               j->gpio.bytes.low = 0x00;
+               j->gpio.bits.gpio1 = 0;
+               j->gpio.bits.gpio2 = 1;
+               j->gpio.bits.gpio5 = 0;
+               ixj_WriteDSPCommand(ixj[board].gpio.word, board);       /* send the ring stop signal */
+               j->port = PORT_POTS;
+       } else {
+               if (j->cardtype == 300) {
+                       LED_SetState(0x1, board);
+                       jif = jiffies + (hertz / 10);
+                       while (time_before(jiffies, jif)) {
+                               current->state = TASK_INTERRUPTIBLE;
+                               schedule_timeout(1);
+                       }
+                       LED_SetState(0x2, board);
+                       jif = jiffies + (hertz / 10);
+                       while (time_before(jiffies, jif)) {
+                               current->state = TASK_INTERRUPTIBLE;
+                               schedule_timeout(1);
+                       }
+                       LED_SetState(0x4, board);
+                       jif = jiffies + (hertz / 10);
+                       while (time_before(jiffies, jif)) {
+                               current->state = TASK_INTERRUPTIBLE;
+                               schedule_timeout(1);
+                       }
+                       LED_SetState(0x8, board);
+                       jif = jiffies + (hertz / 10);
+                       while (time_before(jiffies, jif)) {
+                               current->state = TASK_INTERRUPTIBLE;
+                               schedule_timeout(1);
+                       }
+                       LED_SetState(0x0, board);
+
+                       daa_get_version(board);
+
+                       if (ixjdebug > 0)
+                               printk("Loading DAA Coefficients\n");
+
+                       DAA_Coeff_US(board);
+                       if (!ixj_daa_write(board))
+                               printk("DAA write failed on board %d\n", board);
+
+                       ixj_daa_cid_reset(board);
+
+                       j->flags.pots_correct = 0;
+                       j->flags.pstn_present = 0;
+
+                       ixj_linetest(board);
+
+                       if (j->flags.pots_correct) {
+                               j->pld_scrw.bits.daafsyncen = 0;        // Turn off DAA Frame Sync
+
+                               outb_p(j->pld_scrw.byte, j->XILINXbase);
+                               j->pld_slicw.bits.rly1 = 1;
+                               j->pld_slicw.bits.spken = 1;
+                               outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+                               SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+                               j->port = PORT_POTS;
+                       }
+                       if (ixjdebug > 0)
+                               printk(KERN_INFO "Enable Mixer\n");
+
+                       ixj_mixer(0x0000, board);       //Master Volume Left unmute 0db
+
+                       ixj_mixer(0x0100, board);       //Master Volume Right unmute 0db
+
+                       ixj_mixer(0x0F00, board);       //Mono Out Volume unmute 0db
+
+                       ixj_mixer(0x0C00, board);       //Mono1 Volume unmute 0db
+
+                       ixj_mixer(0x0200, board);       //Voice Left Volume unmute 0db
+
+                       ixj_mixer(0x0300, board);       //Voice Right Volume unmute 0db
+
+                       ixj_mixer(0x110C, board);       //Voice Left and Right out
+
+                       ixj_mixer(0x1401, board);       //Mono1 switch on mixer left
+
+                       ixj_mixer(0x1501, board);       //Mono1 switch on mixer right
+
+                       ixj_mixer(0x1700, board);       //Clock select
+
+                       ixj_mixer(0x1800, board);       //ADC Source select
+
+               } else {
+                       j->port = PORT_POTS;
+                       SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+               }
+       }
+
+       j->intercom = -1;
+       j->framesread = j->frameswritten = 0;
+       j->rxreadycheck = j->txreadycheck = 0;
+
+       if (ixj_WriteDSPCommand(0x0000, board))         /* Write IDLE to Software Control Register */
+               return -1;
+
+       // The read values of the SSR should be 0x00 for the IDLE command
+       if (j->ssr.low || j->ssr.high)
+               return -1;
+
+       if (ixjdebug > 0)
+               printk(KERN_INFO "Enable Line Monitor\n");
+
+       if (ixjdebug > 0)
+               printk(KERN_INFO "Set Line Monitor to Asyncronous Mode\n");
+
+       if (ixj_WriteDSPCommand(0x7E01, board))         // Asynchronous Line Monitor
+
+               return -1;
+
+       if (ixjdebug > 0)
+               printk(KERN_INFO "Enable DTMF Detectors\n");
+
+       if (ixj_WriteDSPCommand(0x5151, board))         // Enable DTMF detection
+
+               return -1;
+
+       if (ixj_WriteDSPCommand(0x6E01, board))         // Set Asyncronous Tone Generation
+
+               return -1;
+
+       set_rec_depth(board, 2);        // Set Record Channel Limit to 2 frames
+
+       set_play_depth(board, 2);       // Set Playback Channel Limit to 2 frames
+
+       j->ex.bits.dtmf_ready = 0;
+       j->dtmf_state = 0;
+       j->dtmf_wp = ixj[board].dtmf_rp = 0;
+
+       j->rec_mode = ixj[board].play_mode = -1;
+       j->flags.ringing = 0;
+       j->maxrings = MAXRINGS;
+       j->ring_cadence = USA_RING_CADENCE;
+       j->drybuffer = 0;
+       j->winktime = 320;
+       j->flags.dtmf_oob = 0;
+
+       /* must be a device on the specified address */
+       /* Register with the Telephony for Linux subsystem */
+       j->p.f_op = &ixj_fops;
+       j->p.open = ixj_open;
+       phone_register_device(&j->p, PHONE_UNIT_ANY);
+
+       add_caps(board);
+
+       return 0;
+}
+
+static void cleanup(void)
+{
+       int cnt;
+
+       del_timer(&ixj_timer);
+//  if (ixj_major)
+       //    unregister_chrdev(ixj_major, "ixj");
+       for (cnt = 0; cnt < IXJMAX; cnt++) {
+               if (ixj[cnt].cardtype == 300) {
+                       ixj[cnt].pld_scrw.bits.daafsyncen = 0;  // Turn off DAA Frame Sync
+
+                       outb_p(ixj[cnt].pld_scrw.byte, ixj[cnt].XILINXbase);
+                       ixj[cnt].pld_slicw.bits.rly1 = 0;
+                       ixj[cnt].pld_slicw.bits.rly2 = 0;
+                       ixj[cnt].pld_slicw.bits.rly3 = 0;
+                       outb_p(ixj[cnt].pld_slicw.byte, ixj[cnt].XILINXbase + 0x01);
+                       LED_SetState(0x0, cnt);
+
+                       release_region(ixj[cnt].XILINXbase, 8);
+               }
+               if (ixj[cnt].cardtype == 400 || ixj[cnt].cardtype == 500) {
+                       release_region(ixj[cnt].XILINXbase, 4);
+               }
+               if (ixj[cnt].DSPbase) {
+                       release_region(ixj[cnt].DSPbase, 16);
+                       phone_unregister_device(&ixj[cnt].p);
+               }
+               if (ixj[cnt].read_buffer)
+                       kfree(ixj[cnt].read_buffer);
+               if (ixj[cnt].write_buffer)
+                       kfree(ixj[cnt].write_buffer);
+#ifdef CONFIG_ISAPNP
+               if (ixj[cnt].dev)
+                       ixj[cnt].dev->deactivate(ixj[cnt].dev);
+#endif
+       }
+}
+
+
+// Typedefs
+typedef struct {
+       BYTE length;
+       DWORD bits;
+} DATABLOCK;
+
+static void PCIEE_WriteBit(WORD wEEPROMAddress, BYTE lastLCC, BYTE byData)
+{
+       lastLCC = lastLCC & 0xfb;
+       lastLCC = lastLCC | (byData ? 4 : 0);
+       outb(lastLCC, wEEPROMAddress);  //set data out bit as appropriate
+
+       udelay(1000);
+       lastLCC = lastLCC | 0x01;
+       outb(lastLCC, wEEPROMAddress);  //SK rising edge
+
+       byData = byData << 1;
+       lastLCC = lastLCC & 0xfe;
+
+       udelay(1000);
+       outb(lastLCC, wEEPROMAddress);  //after delay, SK falling edge
+
+}
+
+static BYTE PCIEE_ReadBit(WORD wEEPROMAddress, BYTE lastLCC)
+{
+       udelay(1000);
+       lastLCC = lastLCC | 0x01;
+       outb(lastLCC, wEEPROMAddress);  //SK rising edge
+
+       lastLCC = lastLCC & 0xfe;
+       udelay(1000);
+       outb(lastLCC, wEEPROMAddress);  //after delay, SK falling edge
+
+       return ((inb(wEEPROMAddress) >> 3) & 1);
+}
+
+static BOOL PCIEE_ReadWord(WORD wAddress, WORD wLoc, WORD * pwResult)
+{
+       BYTE lastLCC;
+       WORD wEEPROMAddress = wAddress + 3;
+       DWORD i;
+       BYTE byResult;
+
+       *pwResult = 0;
+
+       lastLCC = inb(wEEPROMAddress);
+
+       lastLCC = lastLCC | 0x02;
+       lastLCC = lastLCC & 0xfe;
+       outb(lastLCC, wEEPROMAddress);  // CS hi, SK lo
+
+       udelay(1000);           // delay
+
+       PCIEE_WriteBit(wEEPROMAddress, lastLCC, 1);
+       PCIEE_WriteBit(wEEPROMAddress, lastLCC, 1);
+       PCIEE_WriteBit(wEEPROMAddress, lastLCC, 0);
+
+       for (i = 0; i < 8; i++) {
+               PCIEE_WriteBit(wEEPROMAddress, lastLCC, wLoc & 0x80 ? 1 : 0);
+               wLoc <<= 1;
+       }
+
+       for (i = 0; i < 16; i++) {
+               byResult = PCIEE_ReadBit(wEEPROMAddress, lastLCC);
+               *pwResult = (*pwResult << 1) | byResult;
+       }
+
+       udelay(1000);           // another delay
+
+       lastLCC = lastLCC & 0xfd;
+       outb(lastLCC, wEEPROMAddress);  // negate CS
+
+       return 0;
+}
+
+static DWORD PCIEE_GetSerialNumber(WORD wAddress)
+{
+       WORD wLo, wHi;
+
+       if (PCIEE_ReadWord(wAddress, 62, &wLo))
+               return 0;
+
+       if (PCIEE_ReadWord(wAddress, 63, &wHi))
+               return 0;
+
+       return (((DWORD) wHi << 16) | wLo);
+}
+
+static int dspio[IXJMAX + 1] = {0,};
+static int xio[IXJMAX + 1] = {0,};
+
+MODULE_DESCRIPTION("Internet PhoneJACK/Internet LineJACK module - www.quicknet.net");
+MODULE_AUTHOR("Ed Okerson <eokerson@quicknet.net>");
+
+MODULE_PARM(dspio, "1-" __MODULE_STRING(IXJMAX) "i");
+MODULE_PARM(xio, "1-" __MODULE_STRING(IXJMAX) "i");
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+       cleanup();
+}
+
+int init_module(void)
+#else
+int __init ixj_init(void)
+#endif
+{
+       int result;
+
+       int func = 0x110, i = 0;
+       int cnt = 0;
+       int probe = 0;
+       struct pci_dev *dev = NULL, *old_dev = NULL;
+       struct pci_dev *pci = NULL;
+
+#ifdef CONFIG_ISAPNP
+       while (1) {
+               do {
+                       old_dev = dev;
+                       dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('Q', 'T', 'I'),
+                                        ISAPNP_FUNCTION(func), old_dev);
+                       if (!dev)
+                               break;
+                       printk("preparing %x\n", func);
+                       result = dev->prepare(dev);
+                       if (result < 0) {
+                               printk("preparing failed %d \n", result);
+                               break;
+                       }
+                       if (!(dev->resource[0].flags & IORESOURCE_IO))
+                               return -ENODEV;
+                       dev->resource[0].flags |= IORESOURCE_AUTO;
+                       if (func != 0x110)
+                               dev->resource[1].flags |= IORESOURCE_AUTO;
+                       if (dev->activate(dev) < 0) {
+                               printk("isapnp configure failed (out of resources?)\n");
+                               return -ENOMEM;
+                       }
+                       ixj[cnt].DSPbase = dev->resource[0].start;      /* get real port */
+                       if (func != 0x110)
+                               ixj[cnt].XILINXbase = dev->resource[1].start;   /* get real port */
+
+                       result = check_region(ixj[cnt].DSPbase, 16);
+                       if (result) {
+                               printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+                               cleanup();
+                               return result;
+                       }
+                       request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+                       switch (func) {
+                       case (0x110):
+                               ixj[cnt].cardtype = 100;
+                               break;
+                       case (0x310):
+                               ixj[cnt].cardtype = 300;
+                               break;
+                       case (0x410):
+                               ixj[cnt].cardtype = 400;
+                               break;
+                       }
+                       probe = ixj_selfprobe(cnt);
+
+                       ixj[cnt].serial = dev->bus->serial;
+                       ixj[cnt].dev = dev;
+                       printk(KERN_INFO "ixj: found card at 0x%x\n", ixj[cnt].DSPbase);
+                       cnt++;
+               } while (dev);
+
+               if (func == 0x410)
+                       break;
+               if (func == 0x310)
+                       func = 0x410;
+               if (func == 0x110)
+                       func = 0x310;
+               dev = NULL;
+       }
+#else                          //CONFIG_ISAPNP
+       /* Use passed parameters for older kernels without PnP */
+
+       for (cnt = 0; cnt < IXJMAX; cnt++) {
+               if (dspio[cnt]) {
+                       ixj[cnt].DSPbase = dspio[cnt];
+                       ixj[cnt].XILINXbase = xio[cnt];
+                       ixj[cnt].cardtype = 0;
+                       result = check_region(ixj[cnt].DSPbase, 16);
+                       if (result) {
+                               printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+                               cleanup();
+                               return result;
+                       }
+                       request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+                       probe = ixj_selfprobe(cnt);
+                       ixj[cnt].dev = NULL;
+               }
+       }
+#endif
+#ifdef CONFIG_PCI
+       if (pci_present()) {
+               for (i = 0; i < IXJMAX - cnt; i++) {
+                       pci = pci_find_device(0x15E2, 0x0500, pci);
+                       if (!pci)
+                               break;
+                       {
+                               ixj[cnt].DSPbase = pci->resource[0].start;
+                               ixj[cnt].XILINXbase = ixj[cnt].DSPbase + 0x10;
+                               ixj[cnt].serial = PCIEE_GetSerialNumber(pci->resource[2].start);
+
+                               result = check_region(ixj[cnt].DSPbase, 16);
+                               if (result) {
+                                       printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+                                       cleanup();
+                                       return result;
+                               }
+                               request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+                               ixj[cnt].cardtype = 500;
+                               probe = ixj_selfprobe(cnt);
+                               cnt++;
+                       }
+               }
+       }
+#endif
+       printk("%s\n", ixj_c_rcsid);
+
+       ixj_init_timer();
+       ixj_add_timer();        
+       return probe;
+}
+
+static void DAA_Coeff_US(int board)
+{
+       IXJ *j = &ixj[board];
+
+       int i;
+
+       //-----------------------------------------------
+       // CAO
+       for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+               j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+       }
+
+       // Bytes for IM-filter part 1 (04): 0E,32,E2,2F,C2,5A,C0,00
+           j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xE2;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2F;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xC2;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xC0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 72,85,00,0E,2B,3A,D0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x72;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x85;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x2B;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x3A;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xD0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 03,8F,48,F2,8F,48,70,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x03;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x8F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x48;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0xF2;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x8F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x48;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x70;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 04,8F,38,7F,9B,EA,B0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x04;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0x38;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x7F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9B;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xEA;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xB0;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 16,55,DD,CA
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x16;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0x55;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 52,D3,11,42
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xD3;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x11;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0x42;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,B3,80,00,98
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,F2,33,A0,68,AB,8A,AD
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xF2;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x33;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xA0;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x68;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0xAB;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x8A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xAD;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,54,A4,BA,2D,BB
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x54;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0xA4;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x2D;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xBB;
+
+// ;  (10K, 0.68uF)
+       // 
+       // Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x9B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0xD4;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x1C;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x13;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x42;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0xD4;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x73;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// 
+       // Levelmetering Ringing        (0D):B2,45,0F,8E      
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xB2;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone           (0E):CA,0E,CA,09,99,99,99,99
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone           (0F):FD,B5,BA,07,DA,00,00,00
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// 
+       // ;CR Registers
+       // Config. Reg. 0 (filters)       (cr0):FE ; CLK gen. by crystal
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFE;
+
+// Config. Reg. 1 (dialing)       (cr1):05
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)     (cr2):04
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)     (cr3):03 ; SEL Bit==0, HP-disabled
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x03;
+
+// Config. Reg. 4 (analog gain)   (cr4):01
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;         //0x01;
+
+// Config. Reg. 5 (Version)       (cr5):02
+       // Config. Reg. 6 (Reserved)      (cr6):00
+       // Config. Reg. 7 (Reserved)      (cr7):00
+       // 
+
+// ;xr Registers
+       // Ext. Reg. 0 (Interrupt Reg.)   (xr0):02
+       j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;        // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable) (xr1):1C // Cadence, RING, Caller ID, VDD_OK
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x3C;
+
+// Ext. Reg. 2 (Cadence Time Out) (xr2):7D
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)          (xr3):32 ; B-Filter Off == 1
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x12;         //0x32;
+
+// Ext. Reg. 4 (Cadence)          (xr4):00
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)       (xr5):22
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)      (xr6):00
+       j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)              (xr7):40
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40;         // 0x40 ??? Should it be 0x00?
+
+// 
+       // DTMF Tone 1                     (0B): 11,B3,5A,2C ;   697 Hz  
+       //                                       12,33,5A,C3 ;  770 Hz  
+       //                                       13,3C,5B,32 ;  852 Hz  
+       //                                       1D,1B,5C,CC ;  941 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3 ;  1209 Hz  
+       //                                       EC,1D,52,22 ;  1336 Hz  
+       //                                       AA,AC,51,D2 ;  1477 Hz  
+       //                                       9B,3B,51,25 ;  1633 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static void DAA_Coeff_UK(int board)
+{
+       IXJ *j = &ixj[board];
+
+       int i;
+
+       //-----------------------------------------------
+       // CAO
+       for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+               j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+       }
+
+       //  Bytes for IM-filter part 1 (04): 00,C2,BB,A8,CB,81,A0,00
+           j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xC2;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xBB;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0xA8;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xCB;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x81;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+       // Bytes for IM-filter part 2 (05): 40,00,00,0A,A4,33,E0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x40;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0A;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0xA4;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 07,9B,ED,24,B2,A2,A0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x9B;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xED;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x24;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0xB2;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0xA2;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xA0;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 0F,92,F2,B2,87,D2,30,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x0F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x92;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xF2;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0xB2;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x87;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xD2;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x30;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 1B,A5,DD,CA
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x1B;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xA5;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): E2,27,10,D6
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0xE2;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x27;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 80,2D,38,8B,D0,00,00,98
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x2D;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x38;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x8B;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xD0;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,5A,53,F0,0B,5F,84,D4
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x53;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xF0;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x0B;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x5F;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x84;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xD4;
+
+// Bytes for TH-filter part 3 (02): 00,88,6A,A4,8F,52,F5,32
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x6A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0xA4;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x8F;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0xF5;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x32;
+
+// ; idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing           (0D):AA,35,0F,8E     ; 25Hz 30V less possible?
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xAA;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x35;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone              (0E):CA,0E,CA,09,99,99,99,99
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone              (0F):FD,B5,BA,07,DA,00,00,00
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+       // Config. Reg. 0 (filters)        (cr0):FF
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;         //0xFE;
+
+// Config. Reg. 1 (dialing)        (cr1):05
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00        ; 
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;         //0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+       // Config. Reg. 6 (Reserved)       (cr6):00
+       // Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+       // Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+       j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;        // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;         // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):36        ; 
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x36;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+       j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):46
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x46;         // 0x46 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+       //                                       12,33,5A,C3    ;  770 Hz  
+       //                                       13,3C,5B,32    ;  852 Hz  
+       //                                       1D,1B,5C,CC    ;  941 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+       //                                       EC,1D,52,22    ;  1336 Hz  
+       //                                       AA,AC,51,D2    ;  1477 Hz  
+       //                                       9B,3B,51,25    ;  1633 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_France(int board)
+{
+       IXJ *j = &ixj[board];
+
+       int i;
+
+       //-----------------------------------------------
+       // CAO
+       for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+               j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+       }
+
+       // Bytes for IM-filter part 1 (04): 02,A2,43,2C,22,AF,A0,00
+           j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xA2;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0x43;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2C;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0xAF;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 67,CE,00,0C,22,33,E0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x67;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0xCE;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x2C;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 07,9A,28,F6,23,4A,B0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x9A;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x28;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0xF6;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x23;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x4A;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xB0;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 03,8F,F9,2F,9E,FA,20,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x03;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xF9;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x2F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9E;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xFA;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x20;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 16,B5,DD,CA
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x16;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 52,C7,10,D6
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0xE2;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xC7;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,A6,80,00,98
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xA6;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,AC,2A,30,78,AC,8A,2C
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xAC;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x2A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x30;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x78;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0xAC;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x8A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x2C;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,A5,22,BA,2C,45
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0xA5;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x2C;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x45;
+
+// ; idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing           (0D):32,45,B5,84     ; 50Hz 20V
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x84;
+
+// Caller ID 1st Tone              (0E):CA,0E,CA,09,99,99,99,99
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone              (0F):FD,B5,BA,07,DA,00,00,00
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+       // Config. Reg. 0 (filters)        (cr0):FF
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing)        (cr1):05
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00        ; 
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;         //0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+       // Config. Reg. 6 (Reserved)       (cr6):00
+       // Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+       // Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+       j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;        // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;         // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):36        ; 
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x36;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+       j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):46
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x46;         // 0x46 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+       //                                       12,33,5A,C3    ;  770 Hz  
+       //                                       13,3C,5B,32    ;  852 Hz  
+       //                                       1D,1B,5C,CC    ;  941 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+       //                                       EC,1D,52,22    ;  1336 Hz  
+       //                                       AA,AC,51,D2    ;  1477 Hz  
+       //                                       9B,3B,51,25    ;  1633 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_Germany(int board)
+{
+       IXJ *j = &ixj[board];
+
+       int i;
+
+       //-----------------------------------------------
+       // CAO
+       for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+               j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+       }
+
+       // Bytes for IM-filter part 1 (04): 00,CE,BB,B8,D2,81,B0,00
+           j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xCE;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xBB;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0xB8;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xD2;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x81;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xB0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 45,8F,00,0C,D2,3A,D0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x45;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x8F;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0C;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0xD2;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x3A;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xD0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 07,AA,E2,34,24,89,20,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0xAA;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xE2;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x34;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x24;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x89;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x20;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 02,87,FA,37,9A,CA,B0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x87;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xFA;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x37;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9A;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xB0;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 72,D5,DD,CA
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x72;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xD5;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 72,42,13,4B
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x72;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x42;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x13;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0x4B;
+
+// Bytes for TH-filter part 1 (00): 80,52,48,81,AD,80,00,98
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAD;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,42,5A,20,E8,1A,81,27
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0x42;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x20;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0xE8;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x1A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x81;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x27;
+
+// Bytes for TH-filter part 3 (02): 00,88,63,26,BD,4B,A3,C2
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x63;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x26;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0xBD;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x4B;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0xA3;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xC2;
+
+// ;  (10K, 0.68uF)
+
+// Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x9B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0xD4;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x1C;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x13;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x42;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0xD4;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x73;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing        (0D):B2,45,0F,8E      
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xB2;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone           (0E):CA,0E,CA,09,99,99,99,99
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone           (0F):FD,B5,BA,07,DA,00,00,00
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+       // Config. Reg. 0 (filters)        (cr0):FF ; all Filters enabled, CLK from ext. source
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing)        (cr1):05 ; Manual Ring, Ring metering enabled
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04 ; Analog Gain 0dB, FSC internal
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00 ; SEL Bit==0, HP-enabled
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;         //0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+       // Config. Reg. 6 (Reserved)       (cr6):00
+       // Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+       // Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+       j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;        // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C ; Ring, CID, VDDOK Interrupts enabled
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;         // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):32 ; B-Filter Off==1, U0=3.5V, R=200Ohm
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x32;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+       j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):40 ; VDD=4.25 V
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40;         // 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+       //                                       12,33,5A,C3    ;  770 Hz  
+       //                                       13,3C,5B,32    ;  852 Hz  
+       //                                       1D,1B,5C,CC    ;  941 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+       //                                       EC,1D,52,22    ;  1336 Hz  
+       //                                       AA,AC,51,D2    ;  1477 Hz  
+       //                                       9B,3B,51,25    ;  1633 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_Australia(int board)
+{
+       IXJ *j = &ixj[board];
+
+       int i;
+
+       //-----------------------------------------------
+       // CAO
+       for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+               j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+       }
+
+       // Bytes for IM-filter part 1 (04): 00,A3,AA,28,B3,82,D0,00
+           j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xA3;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xAA;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x28;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x82;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xD0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 70,96,00,09,32,6B,C0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x70;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x96;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x09;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x6B;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xC0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 07,96,E2,34,32,9B,30,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x96;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xE2;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x34;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x9B;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x30;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 0F,9A,E9,2F,22,CC,A0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x0F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x9A;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xE9;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x2F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xCC;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xA0;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): CB,45,DD,CA
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0xCB;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0x45;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 1B,67,10,D6
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x1B;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x67;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 80,52,48,81,AF,80,00,98
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAF;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,DB,52,B0,38,01,82,AC
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xDB;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xB0;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x38;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x01;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x82;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xAC;
+
+// Bytes for TH-filter part 3 (02): 00,88,4A,3E,2C,3B,24,46
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x4A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x3E;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x2C;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x3B;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x24;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x46;
+
+// ;  idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing           (0D):32,45,B5,84   ; 50Hz 20V
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x84;
+
+// Caller ID 1st Tone              (0E):CA,0E,CA,09,99,99,99,99
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone              (0F):FD,B5,BA,07,DA,00,00,00
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+       // Config. Reg. 0 (filters)        (cr0):FF
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing)        (cr1):05
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00        ; 
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;         //0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+       // Config. Reg. 6 (Reserved)       (cr6):00
+       // Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+       // Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+       j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;        // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;         // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):2B      ; 
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x2B;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+       j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):40
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40;         // 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+       //                                       12,33,5A,C3    ;  770 Hz  
+       //                                       13,3C,5B,32    ;  852 Hz  
+       //                                       1D,1B,5C,CC    ;  941 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+       //                                       EC,1D,52,22    ;  1336 Hz  
+       //                                       AA,AC,51,D2    ;  1477 Hz  
+       //                                       9B,3B,51,25    ;  1633 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static void DAA_Coeff_Japan(int board)
+{
+       IXJ *j = &ixj[board];
+
+       int i;
+
+       //-----------------------------------------------
+       // CAO
+       for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+               j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+       }
+
+       // Bytes for IM-filter part 1 (04): 06,BD,E2,2D,BA,F9,A0,00
+           j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x06;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xBD;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xE2;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2D;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0xF9;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 6F,F7,00,0E,34,33,E0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x6F;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0xF7;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x34;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+       j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 02,8F,68,77,9C,58,F0,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x8F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x68;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x77;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x9C;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x58;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xF0;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 03,8F,38,73,87,EA,20,08
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x03;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0x38;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x73;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x87;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xEA;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x20;
+       j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 51,C5,DD,CA
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x51;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xC5;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+       j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 25,A7,10,D6
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x25;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xA7;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+       j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,AE,80,00,98
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAE;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,AB,2A,20,99,5B,89,28
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xAB;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x2A;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x20;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x5B;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x89;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x28;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,25,34,C5,4C,BA
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x25;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x34;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xC5;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x4C;
+       j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xBA;
+
+// ;  idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+       j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing           (0D):AA,35,0F,8E    ; 25Hz 30V ?????????
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xAA;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x35;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+       j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone              (0E):CA,0E,CA,09,99,99,99,99
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone              (0F):FD,B5,BA,07,DA,00,00,00
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+       j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+       // Config. Reg. 0 (filters)        (cr0):FF
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing)        (cr1):05
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00        ; 
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+       j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;         //0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+       // Config. Reg. 6 (Reserved)       (cr6):00
+       // Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+       // Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+       j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;        // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;         // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):22        ; 
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x22;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+       j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):40
+       j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40;         // 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+       //                                       12,33,5A,C3    ;  770 Hz  
+       //                                       13,3C,5B,32    ;  852 Hz  
+       //                                       1D,1B,5C,CC    ;  941 Hz  
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+       //                                       EC,1D,52,22    ;  1336 Hz  
+       //                                       AA,AC,51,D2    ;  1477 Hz  
+       //                                       9B,3B,51,25    ;  1633 Hz  
+
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+       j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static s16 tone_table[][19] =
+{
+       {                       // f20_50[]
+               32538,          // A1 = 1.985962
+                -32325,        // A2 = -0.986511
+                -343,          // B2 = -0.010493
+                0,             // B1 = 0
+                343,           // B0 = 0.010493
+                32619,         // A1 = 1.990906
+                -32520,        // A2 = -0.992462
+                19179,         // B2 = 0.585327
+                -19178,        // B1 = -1.170593
+                19179,         // B0 = 0.585327
+                32723,         // A1 = 1.997314
+                -32686,        // A2 = -0.997528
+                9973,          // B2 = 0.304352
+                -9955,         // B1 = -0.607605
+                9973,          // B0 = 0.304352
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f133_200[]
+               32072,          // A1 = 1.95752
+                -31896,        // A2 = -0.973419
+                -435,          // B2 = -0.013294
+                0,             // B1 = 0
+                435,           // B0 = 0.013294
+                32188,         // A1 = 1.9646
+                -32400,        // A2 = -0.98877
+                15139,         // B2 = 0.462036
+                -14882,        // B1 = -0.908356
+                15139,         // B0 = 0.462036
+                32473,         // A1 = 1.981995
+                -32524,        // A2 = -0.992584
+                23200,         // B2 = 0.708008
+                -23113,        // B1 = -1.410706
+                23200,         // B0 = 0.708008
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 300.txt
+               31769,          // A1 = -1.939026
+                -32584,        // A2 = 0.994385
+                -475,          // B2 = -0.014522
+                0,             // B1 = 0.000000
+                475,           // B0 = 0.014522
+                31789,         // A1 = -1.940247
+                -32679,        // A2 = 0.997284
+                17280,         // B2 = 0.527344
+                -16865,        // B1 = -1.029358
+                17280,         // B0 = 0.527344
+                31841,         // A1 = -1.943481
+                -32681,        // A2 = 0.997345
+                543,           // B2 = 0.016579
+                -525,          // B1 = -0.032097
+                543,           // B0 = 0.016579
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f300_420[]
+               30750,          // A1 = 1.876892
+                -31212,        // A2 = -0.952515
+                -804,          // B2 = -0.024541
+                0,             // B1 = 0
+                804,           // B0 = 0.024541
+                30686,         // A1 = 1.872925
+                -32145,        // A2 = -0.980988
+                14747,         // B2 = 0.450043
+                -13703,        // B1 = -0.836395
+                14747,         // B0 = 0.450043
+                31651,         // A1 = 1.931824
+                -32321,        // A2 = -0.986389
+                24425,         // B2 = 0.745422
+                -23914,        // B1 = -1.459595
+                24427,         // B0 = 0.745483
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 330.txt
+               31613,          // A1 = -1.929565
+                -32646,        // A2 = 0.996277
+                -185,          // B2 = -0.005657
+                0,             // B1 = 0.000000
+                185,           // B0 = 0.005657
+                31620,         // A1 = -1.929932
+                -32713,        // A2 = 0.998352
+                19253,         // B2 = 0.587585
+                -18566,        // B1 = -1.133179
+                19253,         // B0 = 0.587585
+                31674,         // A1 = -1.933228
+                -32715,        // A2 = 0.998413
+                2575,          // B2 = 0.078590
+                -2495,         // B1 = -0.152283
+                2575,          // B0 = 0.078590
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f300_425[]
+               30741,          // A1 = 1.876282
+                -31475,        // A2 = -0.960541
+                -703,          // B2 = -0.021484
+                0,             // B1 = 0
+                703,           // B0 = 0.021484
+                30688,         // A1 = 1.873047
+                -32248,        // A2 = -0.984161
+                14542,         // B2 = 0.443787
+                -13523,        // B1 = -0.825439
+                14542,         // B0 = 0.443817
+                31494,         // A1 = 1.922302
+                -32366,        // A2 = -0.987762
+                21577,         // B2 = 0.658508
+                -21013,        // B1 = -1.282532
+                21577,         // B0 = 0.658508
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f330_440[]
+               30627,          // A1 = 1.869324
+                -31338,        // A2 = -0.95636
+                -843,          // B2 = -0.025749
+                0,             // B1 = 0
+                843,           // B0 = 0.025749
+                30550,         // A1 = 1.864685
+                -32221,        // A2 = -0.983337
+                13594,         // B2 = 0.414886
+                -12589,        // B1 = -0.768402
+                13594,         // B0 = 0.414886
+                31488,         // A1 = 1.921936
+                -32358,        // A2 = -0.987518
+                24684,         // B2 = 0.753296
+                -24029,        // B1 = -1.466614
+                24684,         // B0 = 0.753296
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 340.txt
+               31546,          // A1 = -1.925476
+                -32646,        // A2 = 0.996277
+                -445,          // B2 = -0.013588
+                0,             // B1 = 0.000000
+                445,           // B0 = 0.013588
+                31551,         // A1 = -1.925781
+                -32713,        // A2 = 0.998352
+                23884,         // B2 = 0.728882
+                -22979,        // B1 = -1.402527
+                23884,         // B0 = 0.728882
+                31606,         // A1 = -1.929138
+                -32715,        // A2 = 0.998413
+                863,           // B2 = 0.026367
+                -835,          // B1 = -0.050985
+                863,           // B0 = 0.026367
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f350_400[]
+               31006,          // A1 = 1.892517
+                -32029,        // A2 = -0.977448
+                -461,          // B2 = -0.014096
+                0,             // B1 = 0
+                461,           // B0 = 0.014096
+                30999,         // A1 = 1.892029
+                -32487,        // A2 = -0.991455
+                11325,         // B2 = 0.345612
+                -10682,        // B1 = -0.651978
+                11325,         // B0 = 0.345612
+                31441,         // A1 = 1.919067
+                -32526,        // A2 = -0.992615
+                24324,         // B2 = 0.74231
+                -23535,        // B1 = -1.436523
+                24324,         // B0 = 0.74231
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f350_440[]
+               30634,          // A1 = 1.869751
+                -31533,        // A2 = -0.962341
+                -680,          // B2 = -0.020782
+                0,             // B1 = 0
+                680,           // B0 = 0.020782
+                30571,         // A1 = 1.865906
+                -32277,        // A2 = -0.985016
+                12894,         // B2 = 0.393524
+                -11945,        // B1 = -0.729065
+                12894,         // B0 = 0.393524
+                31367,         // A1 = 1.91449
+                -32379,        // A2 = -0.988129
+                23820,         // B2 = 0.726929
+                -23104,        // B1 = -1.410217
+                23820,         // B0 = 0.726929
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f350_450[]
+               30552,          // A1 = 1.864807
+                -31434,        // A2 = -0.95929
+                -690,          // B2 = -0.021066
+                0,             // B1 = 0
+                690,           // B0 = 0.021066
+                30472,         // A1 = 1.859924
+                -32248,        // A2 = -0.984161
+                13385,         // B2 = 0.408478
+                -12357,        // B1 = -0.754242
+                13385,         // B0 = 0.408478
+                31358,         // A1 = 1.914001
+                -32366,        // A2 = -0.987732
+                26488,         // B2 = 0.80835
+                -25692,        // B1 = -1.568176
+                26490,         // B0 = 0.808411
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 360.txt
+               31397,          // A1 = -1.916321
+                -32623,        // A2 = 0.995605
+                -117,          // B2 = -0.003598
+                0,             // B1 = 0.000000
+                117,           // B0 = 0.003598
+                31403,         // A1 = -1.916687
+                -32700,        // A2 = 0.997925
+                3388,          // B2 = 0.103401
+                -3240,         // B1 = -0.197784
+                3388,          // B0 = 0.103401
+                31463,         // A1 = -1.920410
+                -32702,        // A2 = 0.997986
+                13346,         // B2 = 0.407288
+                -12863,        // B1 = -0.785126
+                13346,         // B0 = 0.407288
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f380_420[]
+               30831,          // A1 = 1.881775
+                -32064,        // A2 = -0.978546
+                -367,          // B2 = -0.01122
+                0,             // B1 = 0
+                367,           // B0 = 0.01122
+                30813,         // A1 = 1.880737
+                -32456,        // A2 = -0.990509
+                11068,         // B2 = 0.337769
+                -10338,        // B1 = -0.631042
+                11068,         // B0 = 0.337769
+                31214,         // A1 = 1.905212
+                -32491,        // A2 = -0.991577
+                16374,         // B2 = 0.499695
+                -15781,        // B1 = -0.963196
+                16374,         // B0 = 0.499695
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 392.txt
+               31152,          // A1 = -1.901428
+                -32613,        // A2 = 0.995300
+                -314,          // B2 = -0.009605
+                0,             // B1 = 0.000000
+                314,           // B0 = 0.009605
+                31156,         // A1 = -1.901672
+                -32694,        // A2 = 0.997742
+                28847,         // B2 = 0.880371
+                -2734,         // B1 = -0.166901
+                28847,         // B0 = 0.880371
+                31225,         // A1 = -1.905823
+                -32696,        // A2 = 0.997803
+                462,           // B2 = 0.014108
+                -442,          // B1 = -0.027019
+                462,           // B0 = 0.014108
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f400_425[]
+               30836,          // A1 = 1.882141
+                -32296,        // A2 = -0.985596
+                -324,          // B2 = -0.009903
+                0,             // B1 = 0
+                324,           // B0 = 0.009903
+                30825,         // A1 = 1.881409
+                -32570,        // A2 = -0.993958
+                16847,         // B2 = 0.51416
+                -15792,        // B1 = -0.963898
+                16847,         // B0 = 0.51416
+                31106,         // A1 = 1.89856
+                -32584,        // A2 = -0.994415
+                9579,          // B2 = 0.292328
+                -9164,         // B1 = -0.559357
+                9579,          // B0 = 0.292328
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f400_440[]
+               30702,          // A1 = 1.873962
+                -32134,        // A2 = -0.980682
+                -517,          // B2 = -0.015793
+                0,             // B1 = 0
+                517,           // B0 = 0.015793
+                30676,         // A1 = 1.872375
+                -32520,        // A2 = -0.992462
+                8144,          // B2 = 0.24855
+                -7596,         // B1 = -0.463684
+                8144,          // B0 = 0.24855
+                31084,         // A1 = 1.897217
+                -32547,        // A2 = -0.993256
+                22713,         // B2 = 0.693176
+                -21734,        // B1 = -1.326599
+                22713,         // B0 = 0.693176
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f400_450[]
+               30613,          // A1 = 1.86853
+                -32031,        // A2 = -0.977509
+                -618,          // B2 = -0.018866
+                0,             // B1 = 0
+                618,           // B0 = 0.018866
+                30577,         // A1 = 1.866272
+                -32491,        // A2 = -0.991577
+                9612,          // B2 = 0.293335
+                -8935,         // B1 = -0.54541
+                9612,          // B0 = 0.293335
+                31071,         // A1 = 1.896484
+                -32524,        // A2 = -0.992584
+                21596,         // B2 = 0.659058
+                -20667,        // B1 = -1.261414
+                21596,         // B0 = 0.659058
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 420.txt
+               30914,          // A1 = -1.886841
+                -32584,        // A2 = 0.994385
+                -426,          // B2 = -0.013020
+                0,             // B1 = 0.000000
+                426,           // B0 = 0.013020
+                30914,         // A1 = -1.886841
+                -32679,        // A2 = 0.997314
+                17520,         // B2 = 0.534668
+                -16471,        // B1 = -1.005310
+                17520,         // B0 = 0.534668
+                31004,         // A1 = -1.892334
+                -32683,        // A2 = 0.997406
+                819,           // B2 = 0.025023
+                -780,          // B1 = -0.047619
+                819,           // B0 = 0.025023
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 425.txt
+               30881,          // A1 = -1.884827
+                -32603,        // A2 = 0.994965
+                -496,          // B2 = -0.015144
+                0,             // B1 = 0.000000
+                496,           // B0 = 0.015144
+                30880,         // A1 = -1.884766
+                -32692,        // A2 = 0.997711
+                24767,         // B2 = 0.755859
+                -23290,        // B1 = -1.421509
+                24767,         // B0 = 0.755859
+                30967,         // A1 = -1.890076
+                -32694,        // A2 = 0.997772
+                728,           // B2 = 0.022232
+                -691,          // B1 = -0.042194
+                728,           // B0 = 0.022232
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f425_450[]
+               30646,          // A1 = 1.870544
+                -32327,        // A2 = -0.986572
+                -287,          // B2 = -0.008769
+                0,             // B1 = 0
+                287,           // B0 = 0.008769
+                30627,         // A1 = 1.869324
+                -32607,        // A2 = -0.995087
+                13269,         // B2 = 0.404968
+                -12376,        // B1 = -0.755432
+                13269,         // B0 = 0.404968
+                30924,         // A1 = 1.887512
+                -32619,        // A2 = -0.995453
+                19950,         // B2 = 0.608826
+                -18940,        // B1 = -1.156006
+                19950,         // B0 = 0.608826
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f425_475[]
+               30396,          // A1 = 1.855225
+                -32014,        // A2 = -0.97699
+                -395,          // B2 = -0.012055
+                0,             // B1 = 0
+                395,           // B0 = 0.012055
+                30343,         // A1 = 1.85199
+                -32482,        // A2 = -0.991302
+                17823,         // B2 = 0.543945
+                -16431,        // B1 = -1.002869
+                17823,         // B0 = 0.543945
+                30872,         // A1 = 1.884338
+                -32516,        // A2 = -0.99231
+                18124,         // B2 = 0.553101
+                -17246,        // B1 = -1.052673
+                18124,         // B0 = 0.553101
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 435.txt
+               30796,          // A1 = -1.879639
+                -32603,        // A2 = 0.994965
+                -254,          // B2 = -0.007762
+                0,             // B1 = 0.000000
+                254,           // B0 = 0.007762
+                30793,         // A1 = -1.879456
+                -32692,        // A2 = 0.997711
+                18934,         // B2 = 0.577820
+                -17751,        // B1 = -1.083496
+                18934,         // B0 = 0.577820
+                30882,         // A1 = -1.884888
+                -32694,        // A2 = 0.997772
+                1858,          // B2 = 0.056713
+                -1758,         // B1 = -0.107357
+                1858,          // B0 = 0.056713
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f440_450[]
+               30641,          // A1 = 1.870239
+                -32458,        // A2 = -0.99057
+                -155,          // B2 = -0.004735
+                0,             // B1 = 0
+                155,           // B0 = 0.004735
+                30631,         // A1 = 1.869568
+                -32630,        // A2 = -0.995789
+                11453,         // B2 = 0.349548
+                -10666,        // B1 = -0.651001
+                11453,         // B0 = 0.349548
+                30810,         // A1 = 1.880554
+                -32634,        // A2 = -0.995941
+                12237,         // B2 = 0.373474
+                -11588,        // B1 = -0.707336
+                12237,         // B0 = 0.373474
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f440_480[]
+               30367,          // A1 = 1.853455
+                -32147,        // A2 = -0.981079
+                -495,          // B2 = -0.015113
+                0,             // B1 = 0
+                495,           // B0 = 0.015113
+                30322,         // A1 = 1.850769
+                -32543,        // A2 = -0.993134
+                10031,         // B2 = 0.306152
+                -9252,         // B1 = -0.564728
+                10031,         // B0 = 0.306152
+                30770,         // A1 = 1.878052
+                -32563,        // A2 = -0.993774
+                22674,         // B2 = 0.691956
+                -21465,        // B1 = -1.31012
+                22674,         // B0 = 0.691956
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 445.txt
+               30709,          // A1 = -1.874329
+                -32603,        // A2 = 0.994965
+                -83,           // B2 = -0.002545
+                0,             // B1 = 0.000000
+                83,            // B0 = 0.002545
+                30704,         // A1 = -1.874084
+                -32692,        // A2 = 0.997711
+                10641,         // B2 = 0.324738
+                -9947,         // B1 = -0.607147
+                10641,         // B0 = 0.324738
+                30796,         // A1 = -1.879639
+                -32694,        // A2 = 0.997772
+                10079,         // B2 = 0.307587
+                9513,          // B1 = 0.580688
+                10079,         // B0 = 0.307587
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 450.txt
+               30664,          // A1 = -1.871643
+                -32603,        // A2 = 0.994965
+                -164,          // B2 = -0.005029
+                0,             // B1 = 0.000000
+                164,           // B0 = 0.005029
+                30661,         // A1 = -1.871399
+                -32692,        // A2 = 0.997711
+                15294,         // B2 = 0.466736
+                -14275,        // B1 = -0.871307
+                15294,         // B0 = 0.466736
+                30751,         // A1 = -1.876953
+                -32694,        // A2 = 0.997772
+                3548,          // B2 = 0.108284
+                -3344,         // B1 = -0.204155
+                3548,          // B0 = 0.108284
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 452.txt
+               30653,          // A1 = -1.870911
+                -32615,        // A2 = 0.995361
+                -209,          // B2 = -0.006382
+                0,             // B1 = 0.000000
+                209,           // B0 = 0.006382
+                30647,         // A1 = -1.870605
+                -32702,        // A2 = 0.997986
+                18971,         // B2 = 0.578979
+                -17716,        // B1 = -1.081299
+                18971,         // B0 = 0.578979
+                30738,         // A1 = -1.876099
+                -32702,        // A2 = 0.998016
+                2967,          // B2 = 0.090561
+                -2793,         // B1 = -0.170502
+                2967,          // B0 = 0.090561
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 475.txt
+               30437,          // A1 = -1.857727
+                -32603,        // A2 = 0.994965
+                -264,          // B2 = -0.008062
+                0,             // B1 = 0.000000
+                264,           // B0 = 0.008062
+                30430,         // A1 = -1.857300
+                -32692,        // A2 = 0.997711
+                21681,         // B2 = 0.661682
+                -20082,        // B1 = -1.225708
+                21681,         // B0 = 0.661682
+                30526,         // A1 = -1.863220
+                -32694,        // A2 = 0.997742
+                1559,          // B2 = 0.047600
+                -1459,         // B1 = -0.089096
+                1559,          // B0 = 0.047600
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f480_620[]
+               28975,          // A1 = 1.768494
+                -30955,        // A2 = -0.944672
+                -1026,         // B2 = -0.03133
+                0,             // B1 = 0
+                1026,          // B0 = 0.03133
+                28613,         // A1 = 1.746399
+                -32089,        // A2 = -0.979309
+                14214,         // B2 = 0.433807
+                -12202,        // B1 = -0.744812
+                14214,         // B0 = 0.433807
+                30243,         // A1 = 1.845947
+                -32238,        // A2 = -0.983856
+                24825,         // B2 = 0.757629
+                -23402,        // B1 = -1.428345
+                24825,         // B0 = 0.757629
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 494.txt
+               30257,          // A1 = -1.846741
+                -32605,        // A2 = 0.995056
+                -249,          // B2 = -0.007625
+                0,             // B1 = 0.000000
+                249,           // B0 = 0.007625
+                30247,         // A1 = -1.846191
+                -32694,        // A2 = 0.997772
+                18088,         // B2 = 0.552002
+                -16652,        // B1 = -1.016418
+                18088,         // B0 = 0.552002
+                30348,         // A1 = -1.852295
+                -32696,        // A2 = 0.997803
+                2099,          // B2 = 0.064064
+                -1953,         // B1 = -0.119202
+                2099,          // B0 = 0.064064
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 500.txt
+               30202,          // A1 = -1.843431
+                -32624,        // A2 = 0.995622
+                -413,          // B2 = -0.012622
+                0,             // B1 = 0.000000
+                413,           // B0 = 0.012622
+                30191,         // A1 = -1.842721
+                -32714,        // A2 = 0.998364
+                25954,         // B2 = 0.792057
+                -23890,        // B1 = -1.458131
+                25954,         // B0 = 0.792057
+                30296,         // A1 = -1.849172
+                -32715,        // A2 = 0.998397
+                2007,          // B2 = 0.061264
+                -1860,         // B1 = -0.113568
+                2007,          // B0 = 0.061264
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 520.txt
+               30001,          // A1 = -1.831116
+                -32613,        // A2 = 0.995270
+                -155,          // B2 = -0.004750
+                0,             // B1 = 0.000000
+                155,           // B0 = 0.004750
+                29985,         // A1 = -1.830200
+                -32710,        // A2 = 0.998260
+                6584,          // B2 = 0.200928
+                -6018,         // B1 = -0.367355
+                6584,          // B0 = 0.200928
+                30105,         // A1 = -1.837524
+                -32712,        // A2 = 0.998291
+                23812,         // B2 = 0.726685
+                -21936,        // B1 = -1.338928
+                23812,         // B0 = 0.726685
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 523.txt
+               29964,          // A1 = -1.828918
+                -32601,        // A2 = 0.994904
+                -101,          // B2 = -0.003110
+                0,             // B1 = 0.000000
+                101,           // B0 = 0.003110
+                29949,         // A1 = -1.827942
+                -32700,        // A2 = 0.997925
+                11041,         // B2 = 0.336975
+                -10075,        // B1 = -0.614960
+                11041,         // B0 = 0.336975
+                30070,         // A1 = -1.835388
+                -32702,        // A2 = 0.997986
+                16762,         // B2 = 0.511536
+                -15437,        // B1 = -0.942230
+                16762,         // B0 = 0.511536
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 525.txt
+               29936,          // A1 = -1.827209
+                -32584,        // A2 = 0.994415
+                -91,           // B2 = -0.002806
+                0,             // B1 = 0.000000
+                91,            // B0 = 0.002806
+                29921,         // A1 = -1.826233
+                -32688,        // A2 = 0.997559
+                11449,         // B2 = 0.349396
+                -10426,        // B1 = -0.636383
+                11449,         // B0 = 0.349396
+                30045,         // A1 = -1.833862
+                -32688,        // A2 = 0.997589
+                13055,         // B2 = 0.398407
+                -12028,        // B1 = -0.734161
+                13055,         // B0 = 0.398407
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f540_660[]
+               28499,          // A1 = 1.739441
+                -31129,        // A2 = -0.949982
+                -849,          // B2 = -0.025922
+                0,             // B1 = 0
+                849,           // B0 = 0.025922
+                28128,         // A1 = 1.716797
+                -32130,        // A2 = -0.98056
+                14556,         // B2 = 0.444214
+                -12251,        // B1 = -0.747772
+                14556,         // B0 = 0.444244
+                29667,         // A1 = 1.81073
+                -32244,        // A2 = -0.984039
+                23038,         // B2 = 0.703064
+                -21358,        // B1 = -1.303589
+                23040,         // B0 = 0.703125
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 587.txt
+               29271,          // A1 = -1.786560
+                -32599,        // A2 = 0.994873
+                -490,          // B2 = -0.014957
+                0,             // B1 = 0.000000
+                490,           // B0 = 0.014957
+                29246,         // A1 = -1.785095
+                -32700,        // A2 = 0.997925
+                28961,         // B2 = 0.883850
+                -25796,        // B1 = -1.574463
+                28961,         // B0 = 0.883850
+                29383,         // A1 = -1.793396
+                -32700,        // A2 = 0.997955
+                1299,          // B2 = 0.039650
+                -1169,         // B1 = -0.071396
+                1299,          // B0 = 0.039650
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 590.txt
+               29230,          // A1 = -1.784058
+                -32584,        // A2 = 0.994415
+                -418,          // B2 = -0.012757
+                0,             // B1 = 0.000000
+                418,           // B0 = 0.012757
+                29206,         // A1 = -1.782593
+                -32688,        // A2 = 0.997559
+                36556,         // B2 = 1.115601
+                -32478,        // B1 = -1.982300
+                36556,         // B0 = 1.115601
+                29345,         // A1 = -1.791077
+                -32688,        // A2 = 0.997589
+                897,           // B2 = 0.027397
+                -808,          // B1 = -0.049334
+                897,           // B0 = 0.027397
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 600.txt
+               29116,          // A1 = -1.777100
+                -32603,        // A2 = 0.994965
+                -165,          // B2 = -0.005039
+                0,             // B1 = 0.000000
+                165,           // B0 = 0.005039
+                29089,         // A1 = -1.775452
+                -32708,        // A2 = 0.998199
+                6963,          // B2 = 0.212494
+                -6172,         // B1 = -0.376770
+                6963,          // B0 = 0.212494
+                29237,         // A1 = -1.784485
+                -32710,        // A2 = 0.998230
+                24197,         // B2 = 0.738464
+                -21657,        // B1 = -1.321899
+                24197,         // B0 = 0.738464
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 660.txt
+               28376,          // A1 = -1.731934
+                -32567,        // A2 = 0.993896
+                -363,          // B2 = -0.011102
+                0,             // B1 = 0.000000
+                363,           // B0 = 0.011102
+                28337,         // A1 = -1.729614
+                -32683,        // A2 = 0.997434
+                21766,         // B2 = 0.664246
+                -18761,        // B1 = -1.145081
+                21766,         // B0 = 0.664246
+                28513,         // A1 = -1.740356
+                -32686,        // A2 = 0.997498
+                2509,          // B2 = 0.076584
+                -2196,         // B1 = -0.134041
+                2509,          // B0 = 0.076584
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 700.txt
+               27844,          // A1 = -1.699463
+                -32563,        // A2 = 0.993744
+                -366,          // B2 = -0.011187
+                0,             // B1 = 0.000000
+                366,           // B0 = 0.011187
+                27797,         // A1 = -1.696655
+                -32686,        // A2 = 0.997498
+                22748,         // B2 = 0.694214
+                -19235,        // B1 = -1.174072
+                22748,         // B0 = 0.694214
+                27995,         // A1 = -1.708740
+                -32688,        // A2 = 0.997559
+                2964,          // B2 = 0.090477
+                -2546,         // B1 = -0.155449
+                2964,          // B0 = 0.090477
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 740.txt
+               27297,          // A1 = -1.666077
+                -32551,        // A2 = 0.993408
+                -345,          // B2 = -0.010540
+                0,             // B1 = 0.000000
+                345,           // B0 = 0.010540
+                27240,         // A1 = -1.662598
+                -32683,        // A2 = 0.997406
+                22560,         // B2 = 0.688477
+                -18688,        // B1 = -1.140625
+                22560,         // B0 = 0.688477
+                27461,         // A1 = -1.676147
+                -32684,        // A2 = 0.997467
+                3541,          // B2 = 0.108086
+                -2985,         // B1 = -0.182220
+                3541,          // B0 = 0.108086
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 750.txt
+               27155,          // A1 = -1.657410
+                -32551,        // A2 = 0.993408
+                -462,          // B2 = -0.014117
+                0,             // B1 = 0.000000
+                462,           // B0 = 0.014117
+                27097,         // A1 = -1.653870
+                -32683,        // A2 = 0.997406
+                32495,         // B2 = 0.991699
+                -26776,        // B1 = -1.634338
+                32495,         // B0 = 0.991699
+                27321,         // A1 = -1.667542
+                -32684,        // A2 = 0.997467
+                1835,          // B2 = 0.056007
+                -1539,         // B1 = -0.093948
+                1835,          // B0 = 0.056007
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f750_1450[]
+               19298,          // A1 = 1.177917
+                -24471,        // A2 = -0.746796
+                -4152,         // B2 = -0.126709
+                0,             // B1 = 0
+                4152,          // B0 = 0.126709
+                12902,         // A1 = 0.787476
+                -29091,        // A2 = -0.887817
+                12491,         // B2 = 0.38121
+                -1794,         // B1 = -0.109528
+                12494,         // B0 = 0.381317
+                26291,         // A1 = 1.604736
+                -30470,        // A2 = -0.929901
+                28859,         // B2 = 0.880737
+                -26084,        // B1 = -1.592102
+                28861,         // B0 = 0.880798
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 770.txt
+               26867,          // A1 = -1.639832
+                -32551,        // A2 = 0.993408
+                -123,          // B2 = -0.003755
+                0,             // B1 = 0.000000
+                123,           // B0 = 0.003755
+                26805,         // A1 = -1.636108
+                -32683,        // A2 = 0.997406
+                17297,         // B2 = 0.527863
+                -14096,        // B1 = -0.860382
+                17297,         // B0 = 0.527863
+                27034,         // A1 = -1.650085
+                -32684,        // A2 = 0.997467
+                12958,         // B2 = 0.395477
+                -10756,        // B1 = -0.656525
+                12958,         // B0 = 0.395477
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 800.txt
+               26413,          // A1 = -1.612122
+                -32547,        // A2 = 0.993286
+                -223,          // B2 = -0.006825
+                0,             // B1 = 0.000000
+                223,           // B0 = 0.006825
+                26342,         // A1 = -1.607849
+                -32686,        // A2 = 0.997498
+                6391,          // B2 = 0.195053
+                -5120,         // B1 = -0.312531
+                6391,          // B0 = 0.195053
+                26593,         // A1 = -1.623108
+                -32688,        // A2 = 0.997559
+                23681,         // B2 = 0.722717
+                -19328,        // B1 = -1.179688
+                23681,         // B0 = 0.722717
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 816.txt
+               26168,          // A1 = -1.597209
+                -32528,        // A2 = 0.992706
+                -235,          // B2 = -0.007182
+                0,             // B1 = 0.000000
+                235,           // B0 = 0.007182
+                26092,         // A1 = -1.592590
+                -32675,        // A2 = 0.997192
+                20823,         // B2 = 0.635498
+                -16510,        // B1 = -1.007751
+                20823,         // B0 = 0.635498
+                26363,         // A1 = -1.609070
+                -32677,        // A2 = 0.997253
+                6739,          // B2 = 0.205688
+                -5459,         // B1 = -0.333206
+                6739,          // B0 = 0.205688
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 850.txt
+               25641,          // A1 = -1.565063
+                -32536,        // A2 = 0.992950
+                -121,          // B2 = -0.003707
+                0,             // B1 = 0.000000
+                121,           // B0 = 0.003707
+                25560,         // A1 = -1.560059
+                -32684,        // A2 = 0.997437
+                18341,         // B2 = 0.559753
+                -14252,        // B1 = -0.869904
+                18341,         // B0 = 0.559753
+                25837,         // A1 = -1.577026
+                -32684,        // A2 = 0.997467
+                16679,         // B2 = 0.509003
+                -13232,        // B1 = -0.807648
+                16679,         // B0 = 0.509003
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f857_1645[]
+               16415,          // A1 = 1.001953
+                -23669,        // A2 = -0.722321
+                -4549,         // B2 = -0.138847
+                0,             // B1 = 0
+                4549,          // B0 = 0.138847
+                8456,          // A1 = 0.516174
+                -28996,        // A2 = -0.884918
+                13753,         // B2 = 0.419724
+                -12,           // B1 = -0.000763
+                13757,         // B0 = 0.419846
+                24632,         // A1 = 1.503418
+                -30271,        // A2 = -0.923828
+                29070,         // B2 = 0.887146
+                -25265,        // B1 = -1.542114
+                29073,         // B0 = 0.887268
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 900.txt
+               24806,          // A1 = -1.514099
+                -32501,        // A2 = 0.991852
+                -326,          // B2 = -0.009969
+                0,             // B1 = 0.000000
+                326,           // B0 = 0.009969
+                24709,         // A1 = -1.508118
+                -32659,        // A2 = 0.996674
+                20277,         // B2 = 0.618835
+                -15182,        // B1 = -0.926636
+                20277,         // B0 = 0.618835
+                25022,         // A1 = -1.527222
+                -32661,        // A2 = 0.996735
+                4320,          // B2 = 0.131836
+                -3331,         // B1 = -0.203339
+                4320,          // B0 = 0.131836
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f900_1300[]
+               19776,          // A1 = 1.207092
+                -27437,        // A2 = -0.837341
+                -2666,         // B2 = -0.081371
+                0,             // B1 = 0
+                2666,          // B0 = 0.081371
+                16302,         // A1 = 0.995026
+                -30354,        // A2 = -0.926361
+                10389,         // B2 = 0.317062
+                -3327,         // B1 = -0.203064
+                10389,         // B0 = 0.317062
+                24299,         // A1 = 1.483154
+                -30930,        // A2 = -0.943909
+                25016,         // B2 = 0.763428
+                -21171,        // B1 = -1.292236
+                25016,         // B0 = 0.763428
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f935_1215[]
+               20554,          // A1 = 1.254517
+                -28764,        // A2 = -0.877838
+                -2048,         // B2 = -0.062515
+                0,             // B1 = 0
+                2048,          // B0 = 0.062515
+                18209,         // A1 = 1.11145
+                -30951,        // A2 = -0.94458
+                9390,          // B2 = 0.286575
+                -3955,         // B1 = -0.241455
+                9390,          // B0 = 0.286575
+                23902,         // A1 = 1.458923
+                -31286,        // A2 = -0.954803
+                23252,         // B2 = 0.709595
+                -19132,        // B1 = -1.167725
+                23252,         // B0 = 0.709595
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f941_1477[]
+               17543,          // A1 = 1.07074
+                -26220,        // A2 = -0.800201
+                -3298,         // B2 = -0.100647
+                0,             // B1 = 0
+                3298,          // B0 = 0.100647
+                12423,         // A1 = 0.75827
+                -30036,        // A2 = -0.916626
+                12651,         // B2 = 0.386078
+                -2444,         // B1 = -0.14917
+                12653,         // B0 = 0.386154
+                23518,         // A1 = 1.435425
+                -30745,        // A2 = -0.938293
+                27282,         // B2 = 0.832581
+                -22529,        // B1 = -1.375122
+                27286,         // B0 = 0.832703
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 942.txt
+               24104,          // A1 = -1.471252
+                -32507,        // A2 = 0.992065
+                -351,          // B2 = -0.010722
+                0,             // B1 = 0.000000
+                351,           // B0 = 0.010722
+                23996,         // A1 = -1.464600
+                -32671,        // A2 = 0.997040
+                22848,         // B2 = 0.697266
+                -16639,        // B1 = -1.015564
+                22848,         // B0 = 0.697266
+                24332,         // A1 = -1.485168
+                -32673,        // A2 = 0.997101
+                4906,          // B2 = 0.149727
+                -3672,         // B1 = -0.224174
+                4906,          // B0 = 0.149727
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 950.txt
+               23967,          // A1 = -1.462830
+                -32507,        // A2 = 0.992065
+                -518,          // B2 = -0.015821
+                0,             // B1 = 0.000000
+                518,           // B0 = 0.015821
+                23856,         // A1 = -1.456055
+                -32671,        // A2 = 0.997040
+                26287,         // B2 = 0.802246
+                -19031,        // B1 = -1.161560
+                26287,         // B0 = 0.802246
+                24195,         // A1 = -1.476746
+                -32673,        // A2 = 0.997101
+                2890,          // B2 = 0.088196
+                -2151,         // B1 = -0.131317
+                2890,          // B0 = 0.088196
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f950_1400[]
+               18294,          // A1 = 1.116638
+                -26962,        // A2 = -0.822845
+                -2914,         // B2 = -0.088936
+                0,             // B1 = 0
+                2914,          // B0 = 0.088936
+                14119,         // A1 = 0.861786
+                -30227,        // A2 = -0.922455
+                11466,         // B2 = 0.349945
+                -2833,         // B1 = -0.172943
+                11466,         // B0 = 0.349945
+                23431,         // A1 = 1.430115
+                -30828,        // A2 = -0.940796
+                25331,         // B2 = 0.773071
+                -20911,        // B1 = -1.276367
+                25331,         // B0 = 0.773071
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 975.txt
+               23521,          // A1 = -1.435608
+                -32489,        // A2 = 0.991516
+                -193,          // B2 = -0.005915
+                0,             // B1 = 0.000000
+                193,           // B0 = 0.005915
+                23404,         // A1 = -1.428467
+                -32655,        // A2 = 0.996582
+                17740,         // B2 = 0.541412
+                -12567,        // B1 = -0.767029
+                17740,         // B0 = 0.541412
+                23753,         // A1 = -1.449829
+                -32657,        // A2 = 0.996613
+                9090,          // B2 = 0.277405
+                -6662,         // B1 = -0.406647
+                9090,          // B0 = 0.277405
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1000.txt
+               23071,          // A1 = -1.408203
+                -32489,        // A2 = 0.991516
+                -293,          // B2 = -0.008965
+                0,             // B1 = 0.000000
+                293,           // B0 = 0.008965
+                22951,         // A1 = -1.400818
+                -32655,        // A2 = 0.996582
+                5689,          // B2 = 0.173645
+                -3951,         // B1 = -0.241150
+                5689,          // B0 = 0.173645
+                23307,         // A1 = -1.422607
+                -32657,        // A2 = 0.996613
+                18692,         // B2 = 0.570435
+                -13447,        // B1 = -0.820770
+                18692,         // B0 = 0.570435
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1020.txt
+               22701,          // A1 = -1.385620
+                -32474,        // A2 = 0.991058
+                -292,          // B2 = -0.008933
+                0,             //163840      , // B1 = 10.000000
+                292,           // B0 = 0.008933
+                22564,         // A1 = -1.377258
+                -32655,        // A2 = 0.996552
+                20756,         // B2 = 0.633423
+                -14176,        // B1 = -0.865295
+                20756,         // B0 = 0.633423
+                22960,         // A1 = -1.401428
+                -32657,        // A2 = 0.996613
+                6520,          // B2 = 0.198990
+                -4619,         // B1 = -0.281937
+                6520,          // B0 = 0.198990
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1050.txt
+               22142,          // A1 = -1.351501
+                -32474,        // A2 = 0.991058
+                -147,          // B2 = -0.004493
+                0,             // B1 = 0.000000
+                147,           // B0 = 0.004493
+                22000,         // A1 = -1.342834
+                -32655,        // A2 = 0.996552
+                15379,         // B2 = 0.469360
+                -10237,        // B1 = -0.624847
+                15379,         // B0 = 0.469360
+                22406,         // A1 = -1.367554
+                -32657,        // A2 = 0.996613
+                17491,         // B2 = 0.533783
+                -12096,        // B1 = -0.738312
+                17491,         // B0 = 0.533783
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f1100_1750[]
+               12973,          // A1 = 0.79184
+                -24916,        // A2 = -0.760376
+                6655,          // B2 = 0.203102
+                367,           // B1 = 0.0224
+                6657,          // B0 = 0.203171
+                5915,          // A1 = 0.361053
+                -29560,        // A2 = -0.90213
+                -7777,         // B2 = -0.23735
+                0,             // B1 = 0
+                7777,          // B0 = 0.23735
+                20510,         // A1 = 1.251892
+                -30260,        // A2 = -0.923462
+                26662,         // B2 = 0.81366
+                -20573,        // B1 = -1.255737
+                26668,         // B0 = 0.813843
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1140.txt
+               20392,          // A1 = -1.244629
+                -32460,        // A2 = 0.990601
+                -270,          // B2 = -0.008240
+                0,             // B1 = 0.000000
+                270,           // B0 = 0.008240
+                20218,         // A1 = -1.234009
+                -32655,        // A2 = 0.996582
+                21337,         // B2 = 0.651154
+                -13044,        // B1 = -0.796143
+                21337,         // B0 = 0.651154
+                20684,         // A1 = -1.262512
+                -32657,        // A2 = 0.996643
+                8572,          // B2 = 0.261612
+                -5476,         // B1 = -0.334244
+                8572,          // B0 = 0.261612
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1200.txt
+               19159,          // A1 = -1.169373
+                -32456,        // A2 = 0.990509
+                -335,          // B2 = -0.010252
+                0,             // B1 = 0.000000
+                335,           // B0 = 0.010252
+                18966,         // A1 = -1.157593
+                -32661,        // A2 = 0.996735
+                6802,          // B2 = 0.207588
+                -3900,         // B1 = -0.238098
+                6802,          // B0 = 0.207588
+                19467,         // A1 = -1.188232
+                -32661,        // A2 = 0.996765
+                25035,         // B2 = 0.764008
+                -15049,        // B1 = -0.918579
+                25035,         // B0 = 0.764008
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1209.txt
+               18976,          // A1 = -1.158264
+                -32439,        // A2 = 0.989990
+                -183,          // B2 = -0.005588
+                0,             // B1 = 0.000000
+                183,           // B0 = 0.005588
+                18774,         // A1 = -1.145874
+                -32650,        // A2 = 0.996429
+                15468,         // B2 = 0.472076
+                -8768,         // B1 = -0.535217
+                15468,         // B0 = 0.472076
+                19300,         // A1 = -1.177979
+                -32652,        // A2 = 0.996490
+                19840,         // B2 = 0.605499
+                -11842,        // B1 = -0.722809
+                19840,         // B0 = 0.605499
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1330.txt
+               16357,          // A1 = -0.998413
+                -32368,        // A2 = 0.987793
+                -217,          // B2 = -0.006652
+                0,             // B1 = 0.000000
+                217,           // B0 = 0.006652
+                16107,         // A1 = -0.983126
+                -32601,        // A2 = 0.994904
+                11602,         // B2 = 0.354065
+                -5555,         // B1 = -0.339111
+                11602,         // B0 = 0.354065
+                16722,         // A1 = -1.020630
+                -32603,        // A2 = 0.994965
+                15574,         // B2 = 0.475311
+                -8176,         // B1 = -0.499069
+                15574,         // B0 = 0.475311
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1336.txt
+               16234,          // A1 = -0.990875
+                32404,         // A2 = -0.988922
+                -193,          // B2 = -0.005908
+                0,             // B1 = 0.000000
+                193,           // B0 = 0.005908
+                15986,         // A1 = -0.975769
+                -32632,        // A2 = 0.995880
+                18051,         // B2 = 0.550903
+                -8658,         // B1 = -0.528473
+                18051,         // B0 = 0.550903
+                16591,         // A1 = -1.012695
+                -32634,        // A2 = 0.995941
+                15736,         // B2 = 0.480240
+                -8125,         // B1 = -0.495926
+                15736,         // B0 = 0.480240
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1366.txt
+               15564,          // A1 = -0.949982
+                -32404,        // A2 = 0.988922
+                -269,          // B2 = -0.008216
+                0,             // B1 = 0.000000
+                269,           // B0 = 0.008216
+                15310,         // A1 = -0.934479
+                -32632,        // A2 = 0.995880
+                10815,         // B2 = 0.330063
+                -4962,         // B1 = -0.302887
+                10815,         // B0 = 0.330063
+                15924,         // A1 = -0.971924
+                -32634,        // A2 = 0.995941
+                18880,         // B2 = 0.576172
+                -9364,         // B1 = -0.571594
+                18880,         // B0 = 0.576172
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1380.txt
+               15247,          // A1 = -0.930603
+                -32397,        // A2 = 0.988708
+                -244,          // B2 = -0.007451
+                0,             // B1 = 0.000000
+                244,           // B0 = 0.007451
+                14989,         // A1 = -0.914886
+                -32627,        // A2 = 0.995697
+                18961,         // B2 = 0.578644
+                -8498,         // B1 = -0.518707
+                18961,         // B0 = 0.578644
+                15608,         // A1 = -0.952667
+                -32628,        // A2 = 0.995758
+                11145,         // B2 = 0.340134
+                -5430,         // B1 = -0.331467
+                11145,         // B0 = 0.340134
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1400.txt
+               14780,          // A1 = -0.902130
+                -32393,        // A2 = 0.988586
+                -396,          // B2 = -0.012086
+                0,             // B1 = 0.000000
+                396,           // B0 = 0.012086
+                14510,         // A1 = -0.885651
+                -32630,        // A2 = 0.995819
+                6326,          // B2 = 0.193069
+                -2747,         // B1 = -0.167671
+                6326,          // B0 = 0.193069
+                15154,         // A1 = -0.924957
+                -32632,        // A2 = 0.995850
+                23235,         // B2 = 0.709076
+                -10983,        // B1 = -0.670380
+                23235,         // B0 = 0.709076
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1477.txt
+               13005,          // A1 = -0.793793
+                -32368,        // A2 = 0.987823
+                -500,          // B2 = -0.015265
+                0,             // B1 = 0.000000
+                500,           // B0 = 0.015265
+                12708,         // A1 = -0.775665
+                -32615,        // A2 = 0.995331
+                11420,         // B2 = 0.348526
+                -4306,         // B1 = -0.262833
+                11420,         // B0 = 0.348526
+                13397,         // A1 = -0.817688
+                -32615,        // A2 = 0.995361
+                9454,          // B2 = 0.288528
+                -3981,         // B1 = -0.243027
+                9454,          // B0 = 0.288528
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1600.txt
+               10046,          // A1 = -0.613190
+                -32331,        // A2 = 0.986694
+                -455,          // B2 = -0.013915
+                0,             // B1 = 0.000000
+                455,           // B0 = 0.013915
+                9694,          // A1 = -0.591705
+                -32601,        // A2 = 0.994934
+                6023,          // B2 = 0.183815
+                -1708,         // B1 = -0.104279
+                6023,          // B0 = 0.183815
+                10478,         // A1 = -0.639587
+                -32603,        // A2 = 0.994965
+                22031,         // B2 = 0.672333
+                -7342,         // B1 = -0.448151
+                22031,         // B0 = 0.672333
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // f1633_1638[]
+               9181,           // A1 = 0.560394
+                -32256,        // A2 = -0.984375
+                -556,          // B2 = -0.016975
+                0,             // B1 = 0
+                556,           // B0 = 0.016975
+                8757,          // A1 = 0.534515
+                -32574,        // A2 = -0.99408
+                8443,          // B2 = 0.25769
+                -2135,         // B1 = -0.130341
+                8443,          // B0 = 0.25769
+                9691,          // A1 = 0.591522
+                -32574,        // A2 = -0.99411
+                15446,         // B2 = 0.471375
+                -4809,         // B1 = -0.293579
+                15446,         // B0 = 0.471375
+                7,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1800.txt
+               5076,           // A1 = -0.309875
+                -32304,        // A2 = 0.985840
+                -508,          // B2 = -0.015503
+                0,             // B1 = 0.000000
+                508,           // B0 = 0.015503
+                4646,          // A1 = -0.283600
+                -32605,        // A2 = 0.995026
+                6742,          // B2 = 0.205780
+                -878,          // B1 = -0.053635
+                6742,          // B0 = 0.205780
+                5552,          // A1 = -0.338928
+                -32605,        // A2 = 0.995056
+                23667,         // B2 = 0.722260
+                -4297,         // B1 = -0.262329
+                23667,         // B0 = 0.722260
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },
+       {                       // 1860.txt
+               3569,           // A1 = -0.217865
+                -32292,        // A2 = 0.985504
+                -239,          // B2 = -0.007322
+                0,             // B1 = 0.000000
+                239,           // B0 = 0.007322
+                3117,          // A1 = -0.190277
+                -32603,        // A2 = 0.994965
+                18658,         // B2 = 0.569427
+                -1557,         // B1 = -0.095032
+                18658,         // B0 = 0.569427
+                4054,          // A1 = -0.247437
+                -32603,        // A2 = 0.994965
+                18886,         // B2 = 0.576385
+                -2566,         // B1 = -0.156647
+                18886,         // B0 = 0.576385
+                5,             // Internal filter scaling
+                159,           // Minimum in-band energy threshold
+                21,            // 21/32 in-band to broad-band ratio
+                0x0FF5         // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+       },};
+
+static int ixj_init_filter(int board, IXJ_FILTER * jf)
+{
+       unsigned short cmd;
+       int cnt, max;
+       IXJ *j = &ixj[board];
+
+       if (jf->filter > 3) {
+               return -1;
+       }
+       if (ixj_WriteDSPCommand(0x5154 + jf->filter, board))    // Select Filter
+
+               return -1;
+
+       if (!jf->enable) {
+               if (ixj_WriteDSPCommand(0x5152, board))         // Disable Filter
+
+                       return -1;
+               else
+                       return 0;
+       } else {
+               if (ixj_WriteDSPCommand(0x5153, board))         // Enable Filter
+
+                       return -1;
+
+               // Select the filter (f0 - f3) to use.
+               if (ixj_WriteDSPCommand(0x5154 + jf->filter, board))
+                       return -1;
+       }
+       if (jf->freq < 12 && jf->freq > 3) {
+               // Select the frequency for the selected filter.
+               if (ixj_WriteDSPCommand(0x5170 + jf->freq, board))
+                       return -1;
+       } else if (jf->freq > 11) {
+               // We need to load a programmable filter set for undefined
+               // frequencies.  So we will point the filter to a programmable set.
+               // Since there are only 4 filters and 4 programmable sets, we will
+               // just point the filter to the same number set and program it for the
+               // frequency we want.
+               if (ixj_WriteDSPCommand(0x5170 + jf->filter, board))
+                       return -1;
+
+               if (j->ver.low != 0x12) {
+                       cmd = 0x515B;
+                       max = 19;
+               } else {
+                       cmd = 0x515E;
+                       max = 15;
+               }
+               if (ixj_WriteDSPCommand(cmd, board))
+                       return -1;
+
+               for (cnt = 0; cnt < max; cnt++) {
+                       if (ixj_WriteDSPCommand(tone_table[jf->freq][cnt], board))
+                               return -1;
+               }
+/*    if(j->ver.low != 0x12)
+   {
+   if(ixj_WriteDSPCommand(7, board))
+   return -1;
+   if(ixj_WriteDSPCommand(159, board))
+   return -1;
+   if(ixj_WriteDSPCommand(21, board))
+   return -1;
+   if(ixj_WriteDSPCommand(0x0FF5, board))
+   return -1;
+   } */
+       }
+       return 0;
+}
+
+static int ixj_init_tone(int board, IXJ_TONE * ti)
+{
+       int freq0, freq1;
+       unsigned short data;
+
+       if (ti->freq0) {
+               freq0 = ti->freq0;
+       } else {
+               freq0 = 0x7FFF;
+       }
+
+       if (ti->freq1) {
+               freq1 = ti->freq1;
+       } else {
+               freq1 = 0x7FFF;
+       }
+
+//  if(ti->tone_index > 12 && ti->tone_index < 28)
+       {
+               if (ixj_WriteDSPCommand(0x6800 + ti->tone_index, board))
+                       return -1;
+
+               if (ixj_WriteDSPCommand(0x6000 + (ti->gain0 << 4) + ti->gain1, board))
+                       return -1;
+
+               data = freq0;
+               if (ixj_WriteDSPCommand(data, board))
+                       return -1;
+
+               data = freq1;
+               if (ixj_WriteDSPCommand(data, board))
+                       return -1;
+       }
+       return freq0;
+}
diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h
new file mode 100644 (file)
index 0000000..3559cc5
--- /dev/null
@@ -0,0 +1,974 @@
+/*
+ *    ixj.h
+ *
+ *    Device Driver for the Internet PhoneJACK and
+ *    Internet LineJACK Telephony Cards.
+ *
+ *    (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License
+ *    as published by the Free Software Foundation; either version
+ *    2 of the License, or (at your option) any later version.
+ *
+ * Author:          Ed Okerson, <eokerson@quicknet.net>
+ *    
+ * Contributors:    Greg Herlein, <gherlein@quicknet.net>
+ *                  David W. Erhart, <derhart@quicknet.net>
+ *                  John Sellers, <jsellers@quicknet.net>
+ *                  Mike Preston, <mpreston@quicknet.net>
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website:    http://www.quicknet.net
+ *
+ * Fixes:
+ *     Linux 2.3 port,         Alan Cox
+ */
+static char ixj_h_rcsid[] = "$Id: ixj.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+#ifndef _I386_TYPES_H
+#include <asm/types.h>
+#endif
+
+#include <linux/ixjuser.h>
+#include <linux/phonedev.h>
+
+typedef __u16 WORD;
+typedef __u32 DWORD;
+typedef __u8 BYTE;
+typedef __u8 BOOL;
+
+#define IXJMAX 16
+
+#define TRUE 1
+#define FALSE 0
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/******************************************************************************
+*
+*  This structure when unioned with the structures below makes simple byte
+*  access to the registers easier.
+*
+******************************************************************************/
+typedef struct {
+       unsigned char low;
+       unsigned char high;
+} BYTES;
+
+int ixj_WriteDSPCommand(unsigned short, int board);
+
+/******************************************************************************
+*
+*  This structure represents the Hardware Control Register of the CT8020/8021
+*  The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+       unsigned int rxrdy:1;
+       unsigned int txrdy:1;
+       unsigned int status:1;
+       unsigned int auxstatus:1;
+       unsigned int rxdma:1;
+       unsigned int txdma:1;
+       unsigned int rxburst:1;
+       unsigned int txburst:1;
+       unsigned int dmadir:1;
+       unsigned int cont:1;
+       unsigned int irqn:1;
+       unsigned int t:5;
+} HCRBIT;
+
+typedef union {
+       HCRBIT bits;
+       BYTES bytes;
+} HCR;
+
+/******************************************************************************
+*
+*  This structure represents the Hardware Status Register of the CT8020/8021
+*  The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+       unsigned int controlrdy:1;
+       unsigned int auxctlrdy:1;
+       unsigned int statusrdy:1;
+       unsigned int auxstatusrdy:1;
+       unsigned int rxrdy:1;
+       unsigned int txrdy:1;
+       unsigned int restart:1;
+       unsigned int irqn:1;
+       unsigned int rxdma:1;
+       unsigned int txdma:1;
+       unsigned int cohostshutdown:1;
+       unsigned int t:5;
+} HSRBIT;
+
+typedef union {
+       HSRBIT bits;
+       BYTES bytes;
+} HSR;
+
+/******************************************************************************
+*
+*  This structure represents the General Purpose IO Register of the CT8020/8021
+*  The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+       unsigned int x:1;
+       unsigned int gpio1:1;
+       unsigned int gpio2:1;
+       unsigned int gpio3:1;
+       unsigned int gpio4:1;
+       unsigned int gpio5:1;
+       unsigned int gpio6:1;
+       unsigned int gpio7:1;
+       unsigned int xread:1;
+       unsigned int gpio1read:1;
+       unsigned int gpio2read:1;
+       unsigned int gpio3read:1;
+       unsigned int gpio4read:1;
+       unsigned int gpio5read:1;
+       unsigned int gpio6read:1;
+       unsigned int gpio7read:1;
+} GPIOBIT;
+
+typedef union {
+       GPIOBIT bits;
+       BYTES bytes;
+       unsigned short word;
+} GPIO;
+
+/******************************************************************************
+*
+*  This structure represents the Line Monitor status response
+*
+******************************************************************************/
+typedef struct {
+       unsigned int digit:4;
+       unsigned int cpf_valid:1;
+       unsigned int dtmf_valid:1;
+       unsigned int peak:1;
+       unsigned int z:1;
+       unsigned int f0:1;
+       unsigned int f1:1;
+       unsigned int f2:1;
+       unsigned int f3:1;
+       unsigned int frame:4;
+} LMON;
+
+typedef union {
+       LMON bits;
+       BYTES bytes;
+} DTMF;
+
+typedef struct {
+       unsigned int z:7;
+       unsigned int dtmf_en:1;
+       unsigned int y:4;
+       unsigned int F3:1;
+       unsigned int F2:1;
+       unsigned int F1:1;
+       unsigned int F0:1;
+} CP;
+
+typedef union {
+       CP bits;
+       BYTES bytes;
+} CPTF;
+
+/******************************************************************************
+*
+*  This structure represents the Status Control Register on the Internet
+*  LineJACK
+*
+******************************************************************************/
+typedef struct {
+       unsigned int c0:1;
+       unsigned int c1:1;
+       unsigned int stereo:1;
+       unsigned int daafsyncen:1;
+       unsigned int led1:1;
+       unsigned int led2:1;
+       unsigned int led3:1;
+       unsigned int led4:1;
+} PSCRWI;                      // Internet LineJACK and Internet PhoneJACK Lite
+
+typedef struct {
+       unsigned int eidp:1;
+       unsigned int eisd:1;
+       unsigned int x:6;
+} PSCRWP;                      // Internet PhoneJACK PCI
+
+typedef union {
+       PSCRWI bits;
+       PSCRWP pcib;
+       char byte;
+} PLD_SCRW;
+
+typedef struct {
+       unsigned int c0:1;
+       unsigned int c1:1;
+       unsigned int x:1;
+       unsigned int d0ee:1;
+       unsigned int mixerbusy:1;
+       unsigned int sci:1;
+       unsigned int dspflag:1;
+       unsigned int daaflag:1;
+} PSCRRI;
+
+typedef struct {
+       unsigned int eidp:1;
+       unsigned int eisd:1;
+       unsigned int x:4;
+       unsigned int dspflag:1;
+       unsigned int det:1;
+} PSCRRP;
+
+typedef union {
+       PSCRRI bits;
+       PSCRRP pcib;
+       char byte;
+} PLD_SCRR;
+
+/******************************************************************************
+*
+*  These structures represents the SLIC Control Register on the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+       unsigned int c1:1;
+       unsigned int c2:1;
+       unsigned int c3:1;
+       unsigned int b2en:1;
+       unsigned int spken:1;
+       unsigned int rly1:1;
+       unsigned int rly2:1;
+       unsigned int rly3:1;
+} PSLICWRITE;
+
+typedef struct {
+       unsigned int state:3;
+       unsigned int b2en:1;
+       unsigned int spken:1;
+       unsigned int c3:1;
+       unsigned int potspstn:1;
+       unsigned int det:1;
+} PSLICREAD;
+
+typedef struct {
+       unsigned int c1:1;
+       unsigned int c2:1;
+       unsigned int c3:1;
+       unsigned int b2en:1;
+       unsigned int e1:1;
+       unsigned int mic:1;
+       unsigned int spk:1;
+       unsigned int x:1;
+} PSLICPCI;
+
+typedef union {
+       PSLICPCI pcib;
+       PSLICWRITE bits;
+       PSLICREAD slic;
+       char byte;
+} PLD_SLICW;
+
+typedef union {
+       PSLICPCI pcib;
+       PSLICREAD bits;
+       char byte;
+} PLD_SLICR;
+
+/******************************************************************************
+*
+*  These structures represents the Clock Control Register on the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+       unsigned int clk0:1;
+       unsigned int clk1:1;
+       unsigned int clk2:1;
+       unsigned int x0:1;
+       unsigned int slic_e1:1;
+       unsigned int x1:1;
+       unsigned int x2:1;
+       unsigned int x3:1;
+} PCLOCK;
+
+typedef union {
+       PCLOCK bits;
+       char byte;
+} PLD_CLOCK;
+
+/******************************************************************************
+*
+*  These structures deal with the mixer on the Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct {
+       unsigned short vol[10];
+       unsigned int recsrc;
+       unsigned int modcnt;
+       unsigned short micpreamp;
+} MIX;
+
+/******************************************************************************
+*
+*  These structures deal with the DAA on the Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct _DAA_REGS {
+       //-----------------------------------------------
+       // SOP Registers
+       //
+       BYTE bySOP;
+
+       union _SOP_REGS {
+               struct _SOP {
+                       union   // SOP - CR0 Register
+                        {
+                               BYTE reg;
+                               struct _CR0_BITREGS {
+                                       BYTE CLK_EXT:1;         // cr0[0:0]
+
+                                       BYTE RIP:1;     // cr0[1:1]
+
+                                       BYTE AR:1;      // cr0[2:2]
+
+                                       BYTE AX:1;      // cr0[3:3]
+
+                                       BYTE FRR:1;     // cr0[4:4]
+
+                                       BYTE FRX:1;     // cr0[5:5]
+
+                                       BYTE IM:1;      // cr0[6:6]
+
+                                       BYTE TH:1;      // cr0[7:7]
+
+                               } bitreg;
+                       } cr0;
+
+                       union   // SOP - CR1 Register
+                        {
+                               BYTE reg;
+                               struct _CR1_REGS {
+                                       BYTE RM:1;      // cr1[0:0]
+
+                                       BYTE RMR:1;     // cr1[1:1]
+
+                                       BYTE No_auto:1;         // cr1[2:2]
+
+                                       BYTE Pulse:1;   // cr1[3:3]
+
+                                       BYTE P_Tone1:1;         // cr1[4:4]
+
+                                       BYTE P_Tone2:1;         // cr1[5:5]
+
+                                       BYTE E_Tone1:1;         // cr1[6:6]
+
+                                       BYTE E_Tone2:1;         // cr1[7:7]
+
+                               } bitreg;
+                       } cr1;
+
+                       union   // SOP - CR2 Register
+                        {
+                               BYTE reg;
+                               struct _CR2_REGS {
+                                       BYTE Call_II:1;         // CR2[0:0]
+
+                                       BYTE Call_I:1;  // CR2[1:1]
+
+                                       BYTE Call_en:1;         // CR2[2:2]
+
+                                       BYTE Call_pon:1;        // CR2[3:3]
+
+                                       BYTE IDR:1;     // CR2[4:4]
+
+                                       BYTE COT_R:3;   // CR2[5:7]
+
+                               } bitreg;
+                       } cr2;
+
+                       union   // SOP - CR3 Register
+                        {
+                               BYTE reg;
+                               struct _CR3_REGS {
+                                       BYTE DHP_X:1;   // CR3[0:0]
+
+                                       BYTE DHP_R:1;   // CR3[1:1]
+
+                                       BYTE Cal_pctl:1;        // CR3[2:2]
+
+                                       BYTE SEL:1;     // CR3[3:3]
+
+                                       BYTE TestLoops:4;       // CR3[4:7]
+
+                               } bitreg;
+                       } cr3;
+
+                       union   // SOP - CR4 Register
+                        {
+                               BYTE reg;
+                               struct _CR4_REGS {
+                                       BYTE Fsc_en:1;  // CR4[0:0]
+
+                                       BYTE Int_en:1;  // CR4[1:1]
+
+                                       BYTE AGX:2;     // CR4[2:3]
+
+                                       BYTE AGR_R:2;   // CR4[4:5]
+
+                                       BYTE AGR_Z:2;   // CR4[6:7]
+
+                               } bitreg;
+                       } cr4;
+
+                       union   // SOP - CR5 Register
+                        {
+                               BYTE reg;
+                               struct _CR5_REGS {
+                                       BYTE V_0:1;     // CR5[0:0]
+
+                                       BYTE V_1:1;     // CR5[1:1]
+
+                                       BYTE V_2:1;     // CR5[2:2]
+
+                                       BYTE V_3:1;     // CR5[3:3]
+
+                                       BYTE V_4:1;     // CR5[4:4]
+
+                                       BYTE V_5:1;     // CR5[5:5]
+
+                                       BYTE V_6:1;     // CR5[6:6]
+
+                                       BYTE V_7:1;     // CR5[7:7]
+
+                               } bitreg;
+                       } cr5;
+
+                       union   // SOP - CR6 Register
+                        {
+                               BYTE reg;
+                               struct _CR6_REGS {
+                                       BYTE reserved:8;        // CR6[0:7]
+
+                               } bitreg;
+                       } cr6;
+
+                       union   // SOP - CR7 Register
+                        {
+                               BYTE reg;
+                               struct _CR7_REGS {
+                                       BYTE reserved:8;        // CR7[0:7]
+
+                               } bitreg;
+                       } cr7;
+               } SOP;
+
+               BYTE ByteRegs[sizeof(struct _SOP)];
+
+       } SOP_REGS;
+
+       // DAA_REGS.SOP_REGS.SOP.CR5.reg
+       // DAA_REGS.SOP_REGS.SOP.CR5.bitreg
+       // DAA_REGS.SOP_REGS.SOP.CR5.bitreg.V_2
+       // DAA_REGS.SOP_REGS.ByteRegs[5]
+
+       //-----------------------------------------------
+       // XOP Registers
+       //
+       BYTE byXOP;
+
+       union _XOP_REGS {
+               struct _XOP {
+                       union   // XOP - XR0 Register - Read values
+                        {
+                               BYTE reg;
+                               struct _XR0_BITREGS {
+                                       BYTE SI_0:1;    // XR0[0:0] - Read
+
+                                       BYTE SI_1:1;    // XR0[1:1] - Read
+
+                                       BYTE VDD_OK:1;  // XR0[2:2] - Read
+
+                                       BYTE Caller_ID:1;       // XR0[3:3] - Read
+
+                                       BYTE RING:1;    // XR0[4:4] - Read
+
+                                       BYTE Cadence:1;         // XR0[5:5] - Read
+
+                                       BYTE Wake_up:1;         // XR0[6:6] - Read
+
+                                       BYTE unused:1;  // XR0[7:7] - Read
+
+                               } bitreg;
+                       } xr0;
+
+                       union   // XOP - XR1 Register
+                        {
+                               BYTE reg;
+                               struct _XR1_BITREGS {
+                                       BYTE M_SI_0:1;  // XR1[0:0]
+
+                                       BYTE M_SI_1:1;  // XR1[1:1]
+
+                                       BYTE M_VDD_OK:1;        // XR1[2:2]
+
+                                       BYTE M_Caller_ID:1;     // XR1[3:3]
+
+                                       BYTE M_RING:1;  // XR1[4:4]
+
+                                       BYTE M_Cadence:1;       // XR1[5:5]
+
+                                       BYTE M_Wake_up:1;       // XR1[6:6]
+
+                                       BYTE unused:1;  // XR1[7:7]
+
+                               } bitreg;
+                       } xr1;
+
+                       union   // XOP - XR2 Register
+                        {
+                               BYTE reg;
+                               struct _XR2_BITREGS {
+                                       BYTE CTO0:1;    // XR2[0:0]
+
+                                       BYTE CTO1:1;    // XR2[1:1]
+
+                                       BYTE CTO2:1;    // XR2[2:2]
+
+                                       BYTE CTO3:1;    // XR2[3:3]
+
+                                       BYTE CTO4:1;    // XR2[4:4]
+
+                                       BYTE CTO5:1;    // XR2[5:5]
+
+                                       BYTE CTO6:1;    // XR2[6:6]
+
+                                       BYTE CTO7:1;    // XR2[7:7]
+
+                               } bitreg;
+                       } xr2;
+
+                       union   // XOP - XR3 Register
+                        {
+                               BYTE reg;
+                               struct _XR3_BITREGS {
+                                       BYTE DCR0:1;    // XR3[0:0]
+
+                                       BYTE DCR1:1;    // XR3[1:1]
+
+                                       BYTE DCI:1;     // XR3[2:2]
+
+                                       BYTE DCU0:1;    // XR3[3:3]
+
+                                       BYTE DCU1:1;    // XR3[4:4]
+
+                                       BYTE B_off:1;   // XR3[5:5]
+
+                                       BYTE AGB0:1;    // XR3[6:6]
+
+                                       BYTE AGB1:1;    // XR3[7:7]
+
+                               } bitreg;
+                       } xr3;
+
+                       union   // XOP - XR4 Register
+                        {
+                               BYTE reg;
+                               struct _XR4_BITREGS {
+                                       BYTE C_0:1;     // XR4[0:0]
+
+                                       BYTE C_1:1;     // XR4[1:1]
+
+                                       BYTE C_2:1;     // XR4[2:2]
+
+                                       BYTE C_3:1;     // XR4[3:3]
+
+                                       BYTE C_4:1;     // XR4[4:4]
+
+                                       BYTE C_5:1;     // XR4[5:5]
+
+                                       BYTE C_6:1;     // XR4[6:6]
+
+                                       BYTE C_7:1;     // XR4[7:7]
+
+                               } bitreg;
+                       } xr4;
+
+                       union   // XOP - XR5 Register
+                        {
+                               BYTE reg;
+                               struct _XR5_BITREGS {
+                                       BYTE T_0:1;     // XR5[0:0]
+
+                                       BYTE T_1:1;     // XR5[1:1]
+
+                                       BYTE T_2:1;     // XR5[2:2]
+
+                                       BYTE T_3:1;     // XR5[3:3]
+
+                                       BYTE T_4:1;     // XR5[4:4]
+
+                                       BYTE T_5:1;     // XR5[5:5]
+
+                                       BYTE T_6:1;     // XR5[6:6]
+
+                                       BYTE T_7:1;     // XR5[7:7]
+
+                               } bitreg;
+                       } xr5;
+
+                       union   // XOP - XR6 Register - Read Values
+                        {
+                               BYTE reg;
+                               struct _XR6_BITREGS {
+                                       BYTE CPS0:1;    // XR6[0:0]
+
+                                       BYTE CPS1:1;    // XR6[1:1]
+
+                                       BYTE unused1:2;         // XR6[2:3]
+
+                                       BYTE CLK_OFF:1;         // XR6[4:4]
+
+                                       BYTE unused2:3;         // XR6[5:7]
+
+                               } bitreg;
+                       } xr6;
+
+                       union   // XOP - XR7 Register
+                        {
+                               BYTE reg;
+                               struct _XR7_BITREGS {
+                                       BYTE unused1:1;         // XR7[0:0]
+
+                                       BYTE Vdd0:1;    // XR7[1:1]
+
+                                       BYTE Vdd1:1;    // XR7[2:2]
+
+                                       BYTE unused2:5;         // XR7[3:7]
+
+                               } bitreg;
+                       } xr7;
+               } XOP;
+
+               BYTE ByteRegs[sizeof(struct _XOP)];
+
+       } XOP_REGS;
+
+       // DAA_REGS.XOP_REGS.XOP.XR7.reg
+       // DAA_REGS.XOP_REGS.XOP.XR7.bitreg
+       // DAA_REGS.XOP_REGS.XOP.XR7.bitreg.Vdd0
+       // DAA_REGS.XOP_REGS.ByteRegs[7]
+
+       //-----------------------------------------------
+       // COP Registers
+       //
+       BYTE byCOP;
+
+       union _COP_REGS {
+               struct _COP {
+                       BYTE THFilterCoeff_1[8];        // COP - TH Filter Coefficients,      CODE=0, Part 1
+
+                       BYTE THFilterCoeff_2[8];        // COP - TH Filter Coefficients,      CODE=1, Part 2
+
+                       BYTE THFilterCoeff_3[8];        // COP - TH Filter Coefficients,      CODE=2, Part 3
+
+                       BYTE RingerImpendance_1[8];     // COP - Ringer Impendance Coefficients,  CODE=3, Part 1
+
+                       BYTE IMFilterCoeff_1[8];        // COP - IM Filter Coefficients,      CODE=4, Part 1
+
+                       BYTE IMFilterCoeff_2[8];        // COP - IM Filter Coefficients,      CODE=5, Part 2
+
+                       BYTE RingerImpendance_2[8];     // COP - Ringer Impendance Coefficients,  CODE=6, Part 2
+
+                       BYTE FRRFilterCoeff[8];         // COP - FRR Filter Coefficients,      CODE=7
+
+                       BYTE FRXFilterCoeff[8];         // COP - FRX Filter Coefficients,      CODE=8
+
+                       BYTE ARFilterCoeff[4];  // COP - AR Filter Coefficients,      CODE=9
+
+                       BYTE AXFilterCoeff[4];  // COP - AX Filter Coefficients,      CODE=10 
+
+                       BYTE Tone1Coeff[4];     // COP - Tone1 Coefficients,        CODE=11
+
+                       BYTE Tone2Coeff[4];     // COP - Tone2 Coefficients,        CODE=12
+
+                       BYTE LevelmeteringRinging[4];   // COP - Levelmetering Ringing,        CODE=13
+
+                       BYTE CallerID1stTone[8];        // COP - Caller ID 1st Tone,        CODE=14
+
+                       BYTE CallerID2ndTone[8];        // COP - Caller ID 2nd Tone,        CODE=15
+
+               } COP;
+
+               BYTE ByteRegs[sizeof(struct _COP)];
+
+       } COP_REGS;
+
+       // DAA_REGS.COP_REGS.COP.XR7.Tone1Coeff[3]
+       // DAA_REGS.COP_REGS.COP.XR7.bitreg
+       // DAA_REGS.COP_REGS.COP.XR7.bitreg.Vdd0
+       // DAA_REGS.COP_REGS.ByteRegs[57]
+
+       //-----------------------------------------------
+       // CAO Registers
+       //
+       BYTE byCAO;
+
+       union _CAO_REGS {
+               struct _CAO {
+                       BYTE CallerID[512];     // CAO - Caller ID Bytes
+
+               } CAO;
+
+               BYTE ByteRegs[sizeof(struct _CAO)];
+       } CAO_REGS;
+
+       union                   // XOP - XR0 Register - Write values
+        {
+               BYTE reg;
+               struct _XR0_BITREGSW {
+                       BYTE SO_0:1;    // XR1[0:0] - Write
+
+                       BYTE SO_1:1;    // XR1[1:1] - Write
+
+                       BYTE SO_2:1;    // XR1[2:2] - Write
+
+                       BYTE unused:5;  // XR1[3:7] - Write
+
+               } bitreg;
+       } XOP_xr0_W;
+
+       union                   // XOP - XR6 Register - Write values
+        {
+               BYTE reg;
+               struct _XR6_BITREGSW {
+                       BYTE unused1:4;         // XR6[0:3]
+
+                       BYTE CLK_OFF:1;         // XR6[4:4]
+
+                       BYTE unused2:3;         // XR6[5:7]
+
+               } bitreg;
+       } XOP_xr6_W;
+
+} DAA_REGS;
+
+#define ALISDAA_ID_BYTE      0x81
+#define ALISDAA_CALLERID_SIZE  512
+
+//------------------------------
+//
+//  Misc definitions
+//
+
+// Power Up Operation
+#define SOP_PU_SLEEP    0
+#define SOP_PU_RINGING    1
+#define SOP_PU_CONVERSATION  2
+#define SOP_PU_PULSEDIALING  3
+
+#define ALISDAA_CALLERID_SIZE 512
+
+#define PLAYBACK_MODE_COMPRESSED       0       //        Selects: Compressed modes, TrueSpeech 8.5-4.1, G.723.1, G.722, G.728, G.729
+#define PLAYBACK_MODE_TRUESPEECH_V40   0       //        Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps
+#define PLAYBACK_MODE_TRUESPEECH       8       //        Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps Version 5.1
+#define PLAYBACK_MODE_ULAW             2       //        Selects: 64 Kbit/sec MuA-law PCM
+#define PLAYBACK_MODE_ALAW             10      //        Selects: 64 Kbit/sec A-law PCM
+#define PLAYBACK_MODE_16LINEAR         6       //        Selects: 128 Kbit/sec 16-bit linear
+#define PLAYBACK_MODE_8LINEAR          4       //        Selects: 64 Kbit/sec 8-bit signed linear
+#define PLAYBACK_MODE_8LINEAR_WSS      5       //        Selects: 64 Kbit/sec WSS 8-bit unsigned linear
+
+#define RECORD_MODE_COMPRESSED         0       //        Selects: Compressed modes, TrueSpeech 8.5-4.1, G.723.1, G.722, G.728, G.729
+#define RECORD_MODE_TRUESPEECH         0       //        Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps
+#define RECORD_MODE_ULAW               4       //        Selects: 64 Kbit/sec Mu-law PCM
+#define RECORD_MODE_ALAW               12      //        Selects: 64 Kbit/sec A-law PCM
+#define RECORD_MODE_16LINEAR           5       //        Selects: 128 Kbit/sec 16-bit linear
+#define RECORD_MODE_8LINEAR            6       //        Selects: 64 Kbit/sec 8-bit signed linear
+#define RECORD_MODE_8LINEAR_WSS                7       //        Selects: 64 Kbit/sec WSS 8-bit unsigned linear
+
+enum SLIC_STATES {
+       PLD_SLIC_STATE_OC = 0,
+       PLD_SLIC_STATE_RINGING,
+       PLD_SLIC_STATE_ACTIVE,
+       PLD_SLIC_STATE_OHT,
+       PLD_SLIC_STATE_TIPOPEN,
+       PLD_SLIC_STATE_STANDBY,
+       PLD_SLIC_STATE_APR,
+       PLD_SLIC_STATE_OHTPR
+};
+
+enum SCI_CONTROL {
+       SCI_End = 0,
+       SCI_Enable_DAA,
+       SCI_Enable_Mixer,
+       SCI_Enable_EEPROM
+};
+
+enum Mode {
+       T63, T53, T48, T40
+};
+enum Dir {
+       V3_TO_V4, V4_TO_V3, V4_TO_V5, V5_TO_V4
+};
+
+typedef struct Proc_Info_Tag {
+       enum Mode convert_mode;
+       enum Dir convert_dir;
+       int Prev_Frame_Type;
+       int Current_Frame_Type;
+} Proc_Info_Type;
+
+enum PREVAL {
+       NORMAL = 0,
+       NOPOST,
+       POSTONLY,
+       PREERROR
+};
+
+enum IXJ_EXTENSIONS {
+       G729LOADER = 0,
+       TS85LOADER,
+       PRE_READ,
+       POST_READ,
+       PRE_WRITE,
+       POST_WRITE,
+       PRE_IOCTL,
+       POST_IOCTL
+};
+
+typedef struct {
+       unsigned int busytone:1;
+       unsigned int dialtone:1;
+       unsigned int ringback:1;
+       unsigned int ringing:1;
+       unsigned int cringing:1;
+       unsigned int play_first_frame:1;
+       unsigned int pstn_present:1;
+       unsigned int pstn_ringing:1;
+       unsigned int pots_correct:1;
+       unsigned int pots_pstn:1;
+       unsigned int g729_loaded:1;
+       unsigned int ts85_loaded:1;
+       unsigned int dtmf_oob:1;        // DTMF Out-Of-Band
+
+} IXJ_FLAGS;
+
+/******************************************************************************
+*
+*  This structure represents the Internet PhoneJACK and Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct {
+       struct phone_device p;
+       unsigned int board;
+       unsigned int DSPbase;
+       unsigned int XILINXbase;
+       unsigned int serial;
+       struct phone_capability caplist[30];
+       unsigned int caps;
+       struct pci_dev *dev;
+       unsigned int cardtype;
+       unsigned int rec_codec;
+       char rec_mode;
+       unsigned int play_codec;
+       char play_mode;
+       IXJ_FLAGS flags;
+       unsigned int rec_frame_size;
+       unsigned int play_frame_size;
+       int aec_level;
+       int readers, writers;
+       wait_queue_head_t poll_q;
+       wait_queue_head_t read_q;
+       char *read_buffer, *read_buffer_end;
+       char *read_convert_buffer;
+       unsigned int read_buffer_size;
+       unsigned int read_buffer_ready;
+       wait_queue_head_t write_q;
+       char *write_buffer, *write_buffer_end;
+       char *write_convert_buffer;
+       unsigned int write_buffer_size;
+       unsigned int write_buffers_empty;
+       unsigned long drybuffer;
+       char *write_buffer_rp, *write_buffer_wp;
+       char dtmfbuffer[80];
+       char dtmf_current;
+       int dtmf_wp, dtmf_rp, dtmf_state, dtmf_proc;
+       int tone_off_time, tone_on_time;
+       struct fasync_struct *async_queue;
+       unsigned long tone_start_jif;
+       char tone_index;
+       char tone_state;
+       char maxrings;
+       IXJ_CADENCE *cadence_t;
+       int tone_cadence_state;
+       DTMF dtmf;
+       CPTF cptf;
+       BYTES dsp;
+       BYTES ver;
+       BYTES scr;
+       BYTES ssr;
+       BYTES baseframe;
+       HSR hsr;
+       GPIO gpio;
+       PLD_SCRR pld_scrr;
+       PLD_SCRW pld_scrw;
+       PLD_SLICW pld_slicw;
+       PLD_SLICR pld_slicr;
+       PLD_CLOCK pld_clock;
+       MIX mix;
+       unsigned short ring_cadence;
+       int ring_cadence_t;
+       unsigned long ring_cadence_jif;
+       int intercom;
+       int m_hook;
+       int r_hook;
+       char pstn_envelope;
+       char pstn_cid_intr;
+       unsigned pstn_cid_recieved;
+       IXJ_CID cid;
+       unsigned long pstn_ring_start;
+       unsigned long pstn_winkstart;
+       unsigned int winktime;
+       char port;
+       union telephony_exception ex;
+       char daa_mode;
+       unsigned long pstn_sleeptil;
+       DAA_REGS m_DAAShadowRegs;
+       Proc_Info_Type Info_read;
+       Proc_Info_Type Info_write;
+       unsigned short frame_count;
+       unsigned int filter_cadence;
+       unsigned int filter_hist[4];
+       unsigned short proc_load;
+       unsigned long framesread;
+       unsigned long frameswritten;
+       unsigned long read_wait;
+       unsigned long write_wait;
+       unsigned long timerchecks;
+       unsigned long txreadycheck;
+       unsigned long rxreadycheck;
+} IXJ;
+
+typedef int (*IXJ_REGFUNC) (IXJ * j, unsigned long arg);
+
+int ixj_register(int index, IXJ_REGFUNC regfunc);
+int ixj_unregister(int index);
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
new file mode 100644 (file)
index 0000000..fa6d415
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *            Telephony registration for Linux
+ *
+ *              (c) Copyright 1999 Red Hat Software Inc.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Author:      Alan Cox, <alan@redhat.com>
+ *
+ * Fixes:
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/phonedev.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kmod.h>
+
+
+#define PHONE_NUM_DEVICES      256
+
+/*
+ *    Active devices 
+ */
+
+static struct phone_device *phone_device[PHONE_NUM_DEVICES];
+
+/*
+ *    Open a phone device.
+ */
+
+static int phone_open(struct inode *inode, struct file *file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       int err;
+       struct phone_device *p;
+
+       if (minor >= PHONE_NUM_DEVICES)
+               return -ENODEV;
+
+       p = phone_device[minor];
+       if (p == NULL) {
+               char modname[32];
+
+               sprintf(modname, "char-major-%d-%d", PHONE_MAJOR, minor);
+               request_module(modname);
+               p = phone_device[minor];
+               if (p == NULL)
+                       return -ENODEV;
+       }
+       if (p->open) {
+               err = p->open(p, file); /* Tell the device it is open */
+               if (err)
+                       return err;
+       }
+       file->f_op = p->f_op;
+       return 0;
+}
+
+/*
+ *    Telephony For Linux device drivers request registration here.
+ */
+
+int phone_register_device(struct phone_device *p, int unit)
+{
+       int base;
+       int end;
+       int i;
+
+       base = 0;
+       end = PHONE_NUM_DEVICES - 1;
+
+       if (unit != PHONE_UNIT_ANY) {
+               base = unit;
+               end = unit;
+       }
+       for (i = base; i < end; i++) {
+               if (phone_device[i] == NULL) {
+                       phone_device[i] = p;
+                       p->minor = i;
+                       MOD_INC_USE_COUNT;
+                       return 0;
+               }
+       }
+       return -ENFILE;
+}
+
+/*
+ *    Unregister an unused Telephony for linux device
+ */
+
+void phone_unregister_device(struct phone_device *pfd)
+{
+       if (phone_device[pfd->minor] != pfd)
+               panic("phone: bad unregister");
+       phone_device[pfd->minor] = NULL;
+       MOD_DEC_USE_COUNT;
+}
+
+
+static struct file_operations phone_fops =
+{
+       NULL,
+       NULL,
+       NULL,
+       NULL,                   /* readdir */
+       NULL,
+       NULL,
+       NULL,
+       phone_open,
+       NULL,                   /* flush */
+       NULL
+};
+
+/*
+ *     Board init functions
+ */
+extern int ixj_init(void);
+
+/*
+ *    Initialise Telephony for linux
+ */
+
+int telephony_init(void)
+{
+       printk(KERN_INFO "Linux telephony interface: v1.00\n");
+       if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
+               printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
+               return -EIO;
+       }
+       /*
+        *    Init kernel installed drivers
+        */
+#ifdef CONFIG_PHONE_IXJ
+       ixj_init();      
+#endif
+       return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       return telephony_init();
+}
+
+void cleanup_module(void)
+{
+       unregister_chrdev(PHONE_MAJOR, "telephony");
+}
+
+#endif
+
+EXPORT_SYMBOL(phone_register_device);
+EXPORT_SYMBOL(phone_unregister_device);
index 64ae14b413c03f9f961fee139bd006fad9cbadf3..9f71d0814d45c2eb471b8900583305cbb03a23ec 100644 (file)
@@ -6,6 +6,8 @@ O_TARGET := cramfs.o
 
 O_OBJS := inode.o uncompress.o inflate/zlib.o
 
+M_OBJS := $(O_TARGET)
+
 include $(TOPDIR)/Rules.make
 
 inflate/zlib.o:
index 40b4ae2afd9f1d0b9f4dade2d63596bf1c63ab8a..7a7858066dfe227d6ea5eba7cfd0364c73b81b5a 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -261,6 +261,41 @@ int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
        return r; 
 }
 
+/*
+ * This routine is used to map in a page into an address space: needed by
+ * execve() for the initial stack and environment pages.
+ */
+static void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
+{
+       pgd_t * pgd;
+       pmd_t * pmd;
+       pte_t * pte;
+
+       if (page_count(page) != 1)
+               printk("mem_map disagrees with %p at %08lx\n", page, address);
+       pgd = pgd_offset(tsk->mm, address);
+       pmd = pmd_alloc(pgd, address);
+       if (!pmd) {
+               __free_page(page);
+               oom(tsk);
+               return;
+       }
+       pte = pte_alloc(pmd, address);
+       if (!pte) {
+               __free_page(page);
+               oom(tsk);
+               return;
+       }
+       if (!pte_none(*pte)) {
+               pte_ERROR(*pte);
+               __free_page(page);
+               return;
+       }
+       flush_page_to_ram(page);
+       set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
+/* no need for flush_tlb */
+}
+
 int setup_arg_pages(struct linux_binprm *bprm)
 {
        unsigned long stack_base;
index 11f99b4dc2917012229fb76ce69abce8cfbea482..cefde46fdf817a4280dd48b9a32d5f145c81e5a2 100644 (file)
@@ -791,7 +791,7 @@ static int __init init_ext2_fs(void)
         return register_filesystem(&ext2_fs_type);
 }
 
-static int __exit exit_ext2_fs(void)
+static void __exit exit_ext2_fs(void)
 {
        unregister_filesystem(&ext2_fs_type);
 }
index 836038e59d6e2af1b939757e67bd5a64d33d0905..45a0f7f94d1ef24e4a1a3d520559c15e86f372ca 100644 (file)
@@ -597,7 +597,6 @@ extern void ext2_put_super (struct super_block *);
 extern void ext2_write_super (struct super_block *);
 extern int ext2_remount (struct super_block *, int *, char *);
 extern struct super_block * ext2_read_super (struct super_block *,void *,int);
-extern int init_ext2_fs(void);
 extern int ext2_statfs (struct super_block *, struct statfs *, int);
 
 /* truncate.c */
index 62511afd67130d8c03151eb4df0803971d914e4d..9598d2cbf718a907d2b464f4171ba534963f6160 100644 (file)
@@ -21,6 +21,8 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-algo-bit.h,v 1.7 1999/12/21 23:45:58 frodo Exp $ */
+
 #ifndef I2C_ALGO_BIT_H
 #define I2C_ALGO_BIT_H 1
 
index c205a308a63dfa341407ea3752d01bf06a197cfa..edb6ce644434453c607b4083680c6c81685484da 100644 (file)
@@ -22,6 +22,8 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-algo-pcf.h,v 1.6 1999/12/21 23:45:58 frodo Exp $ */
+
 #ifndef I2C_ALGO_PCF_H
 #define I2C_AGLO_PCF_H 1
 
index 9c1791072334895b7f61107fcd4cb4f33387fb2a..7d52e52bce76ba9a7c511425f0dad156e167217d 100644 (file)
@@ -19,6 +19,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+/* $Id: i2c-dev.h,v 1.3 1999/12/21 23:45:58 frodo Exp $ */
+
 #ifndef I2C_DEV_H
 #define I2C_DEV_H
 
index 3a1a9abfc48cf2291e2acb9ef715c6267386f390..e10311f225b52746ac026c981bfdf750d233f6c2 100644 (file)
@@ -22,6 +22,8 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c-elektor.h,v 1.3 1999/12/21 23:45:58 frodo Exp $ */
+
 #ifndef I2C_PCF_ELEKTOR_H
 #define I2C_PCF_ELEKTOR_H 1
 
index 124d05de0b019e3af3764a311b8c4303faec56d8..d0d2ce2f9223641a4f7a7199addf862451e143b2 100644 (file)
@@ -19,8 +19,8 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
 /* ------------------------------------------------------------------------- */
-/* $Revision: 1.4 $ $Date: 1999/12/02 02:05:34 $*/
-/* ------------------------------------------------------------------------- */
+
+/* $Id: i2c-id.h,v 1.6 1999/12/21 23:45:58 frodo Exp $ */
 
 #ifndef I2C_ID_H
 #define I2C_ID_H
@@ -71,6 +71,8 @@
 #define I2C_DRIVERID_EXP2      0xF2
 #define I2C_DRIVERID_EXP3      0xF3
 
+#define I2C_DRIVERID_MGATVO    0x0101  /* Matrox TVOut                 */
+
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_I2CPROC   901
 
 #define I2C_HW_B_WNV   0x06    /* Winnov Videums                       */
 #define I2C_HW_B_VIA    0x07    /* Via vt82c586b                       */
 #define I2C_HW_B_HYDRA  0x08    /* Apple Hydra Mac I/O                  */
+#define I2C_HW_B_G400  0x09    /* Matrox G400                          */
 
 /* --- PCF 8584 based algorithms                                       */
 #define I2C_HW_P_LP    0x00    /* Parallel port interface              */
index 5b56f952288941471527a3e32e39d04824ef1d92..9dcc57d49500c723cf0d40d7b1ca7d9937b96bd2 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
 /* ------------------------------------------------------------------------- */
-/* $Revision: 1.30 $ $Date: 1999/11/16 08:12:38 $*/
-/* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
    Frodo Looijaard <frodol@dds.nl> */
 
+/* $Id: i2c.h,v 1.32 1999/12/21 23:45:58 frodo Exp $ */
+
 #ifndef I2C_H
 #define I2C_H
 
@@ -324,6 +324,10 @@ extern int i2c_detach_client(struct i2c_client *);
 extern void i2c_inc_use_client(struct i2c_client *);
 extern void i2c_dec_use_client(struct i2c_client *);
 
+/* returns -EBUSY if address has been taken, 0 if not. Note that the only
+   other place at which this is called is within i2c_attach_client; so
+   you can cheat by simply not registering. Not recommended, of course! */
+extern int i2c_check_addr (struct i2c_adapter *adapter, int addr);
 
 /* Detect function. It itterates over all possible addresses itself.
  * It will only call found_proc if some client is connected at the
@@ -427,6 +431,10 @@ union i2c_smbus_data {
 /* this is for i2c-dev.c       */
 #define I2C_SLAVE      0x0703  /* Change slave address                 */
                                /* Attn.: Slave address is 7 or 10 bits */
+#define I2C_SLAVE_FORCE        0x0706  /* Change slave address                 */
+                               /* Attn.: Slave address is 7 or 10 bits */
+                                /* This changes the address, even if it */
+                                /* is already taken!                    */
 #define I2C_TENBIT     0x0704  /* 0 for 7 bit addrs, != 0 for 10 bit   */
 
 #define I2C_FUNCS       0x0705  /* Get the adapter functionality */
index 04cae89353828713815099998c419c2cccc69e1f..d01a0216ad0e85eb1c8f7332ed482aee1ec5c7a8 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Mar  8 14:06:12 1999
- * Modified at:   Sun Dec 12 12:23:11 1999
+ * Modified at:   Tue Dec 21 09:00:59 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -83,20 +83,21 @@ enum {
 
 #define IRLMP_ENUMDEVICES        1
 #define IRLMP_IAS_SET            2
-#define IRLMP_IAS_GET            3
-#define IRLMP_IAS_QUERY          4
-#define IRLMP_HINTS_SET          5
+#define IRLMP_IAS_QUERY          3
+#define IRLMP_HINTS_SET          4
+#define IRLMP_QOS_SET            5
+#define IRLMP_QOS_GET            6
+#define IRLMP_MAX_SDU_SIZE       7
+#define IRLMP_IAS_GET            8
 
-#define IRTTP_QOS_SET            6
-#define IRTTP_QOS_GET            7
-#define IRTTP_MAX_SDU_SIZE       8
+#define IRTTP_MAX_SDU_SIZE IRLMP_MAX_SDU_SIZE /* Compatibility */
 
 #define IAS_MAX_STRING         256
 #define IAS_MAX_OCTET_STRING  1024
 #define IAS_MAX_CLASSNAME       64
 #define IAS_MAX_ATTRIBNAME     256
 
-#define LSAP_ANY               0xff
+#define LSAP_ANY              0xff
 
 struct sockaddr_irda {
        sa_family_t   sir_family;   /* AF_IRDA */
diff --git a/include/linux/ixjuser.h b/include/linux/ixjuser.h
new file mode 100644 (file)
index 0000000..a701953
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ *    ixjuser.h
+ *
+ *    User-space include file for the Internet PhoneJACK and
+ *    Internet LineJACK Telephony Cards.
+ *
+ *    (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License
+ *    as published by the Free Software Foundation; either version
+ *    2 of the License, or (at your option) any later version.
+ *
+ * Author:          Ed Okerson, <eokerson@quicknet.net>
+ *    
+ * Contributors:    Greg Herlein, <gherlein@quicknet.net>
+ *                  David W. Erhart, <derhart@quicknet.net>
+ *                  John Sellers, <jsellers@quicknet.net>
+ *                  Mike Preston, <mpreston@quicknet.net>
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website:    http://www.quicknet.net
+ *
+ * Fixes:
+ */
+
+static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+#include <linux/telephony.h>
+
+/***************************************************************************
+
+  If you use the IXJCTL_TESTRAM command, the card must be power
+  cycled to reset the SRAM values before futher use.
+
+***************************************************************************/
+#define IXJCTL_DSP_RESET               _IO  ('q', 0xC0)
+
+#define IXJCTL_RING         PHONE_RING
+#define IXJCTL_HOOKSTATE    PHONE_HOOKSTATE
+#define IXJCTL_MAXRINGS                        PHONE_MAXRINGS
+#define IXJCTL_RING_CADENCE    PHONE_RING_CADENCE
+#define IXJCTL_RING_START              PHONE_RING_START
+#define IXJCTL_RING_STOP               PHONE_RING_STOP
+
+#define IXJCTL_CARDTYPE                        _IOR ('q', 0xC1, int)
+#define IXJCTL_SERIAL                    _IOR ('q', 0xC2, int)
+#define IXJCTL_DSP_TYPE     _IOR ('q', 0xC3, int)
+#define IXJCTL_DSP_VERSION  _IOR ('q', 0xC4, int)
+#define IXJCTL_DSP_IDLE                        _IO  ('q', 0xC5)
+#define IXJCTL_TESTRAM                 _IO  ('q', 0xC6)
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the record settings of the DSP
+*
+* The IXJCTL_REC_DEPTH command sets the internal buffer depth of the DSP.
+* Setting a lower depth reduces latency, but increases the demand of the
+* application to service the driver without frame loss.  The DSP has 480
+* bytes of physical buffer memory for the record channel so the true
+* maximum limit is determined by how many frames will fit in the buffer.
+*
+* 1 uncompressed (480 byte) 16-bit linear frame.
+* 2 uncompressed (240 byte) 8-bit A-law/mu-law frames.
+* 15 TrueSpeech 8.5 frames.
+* 20 TrueSpeech 6.3,5.3,4.8 or 4.1 frames.
+*
+* The default in the driver is currently set to 2 frames.
+*
+* The IXJCTL_REC_VOLUME and IXJCTL_PLAY_VOLUME commands both use a Q8
+* number as a parameter, 0x100 scales the signal by 1.0, 0x200 scales the
+* signal by 2.0, 0x80 scales the signal by 0.5.  No protection is given
+* against over-scaling, if the multiplication factor times the input
+* signal exceeds 16 bits, overflow distortion will occur.  The default
+* setting is 0x100 (1.0).
+*
+* The IXJCTL_REC_LEVEL returns the average signal level (not r.m.s.) on
+* the most recently recorded frame as a 16 bit value.
+******************************************************************************/
+
+#define IXJCTL_REC_CODEC                PHONE_REC_CODEC
+#define IXJCTL_REC_START                PHONE_REC_START
+#define IXJCTL_REC_STOP                 PHONE_REC_STOP
+#define IXJCTL_REC_DEPTH               PHONE_REC_DEPTH
+#define IXJCTL_FRAME                   PHONE_FRAME
+#define IXJCTL_REC_VOLUME              PHONE_REC_VOLUME
+#define IXJCTL_REC_LEVEL               PHONE_REC_LEVEL
+
+typedef enum {
+       f300_640 = 4, f300_500, f1100, f350, f400, f480, f440, f620, f20_50,
+       f133_200, f300, f300_420, f330, f300_425, f330_440, f340, f350_400,
+       f350_440, f350_450, f360, f380_420, f392, f400_425, f400_440, f400_450,
+       f420, f425, f425_450, f425_475, f435, f440_450, f440_480, f445, f450,
+       f452, f475, f480_620, f494, f500, f520, f523, f525, f540_660, f587,
+       f590, f600, f660, f700, f740, f750, f750_1450, f770, f800, f816, f850,
+       f857_1645, f900, f900_1300, f935_1215, f941_1477, f942, f950, f950_1400,
+       f975, f1000, f1020, f1050, f1100_1750, f1140, f1200, f1209, f1330, f1336,
+       lf1366, f1380, f1400, f1477, f1600, f1633_1638, f1800, f1860
+} IXJ_FILTER_FREQ;
+
+typedef struct {
+       unsigned int filter;
+       IXJ_FILTER_FREQ freq;
+       char enable;
+} IXJ_FILTER;
+
+#define IXJCTL_SET_FILTER              _IOW ('q', 0xC7, IXJ_FILTER *)
+#define IXJCTL_GET_FILTER_HIST         _IOW ('q', 0xC8, int)
+/******************************************************************************
+*
+* This IOCTL allows you to reassign values in the tone index table.  The
+* tone table has 32 entries (0 - 31), but the driver only allows entries
+* 13 - 27 to be modified, entry 0 is reserved for silence and 1 - 12 are
+* the standard DTMF digits and 28 - 31 are the DTMF tones for A, B, C & D.
+* The positions used internally for Call Progress Tones are as follows:
+*    Dial Tone   - 25
+*    Ring Back   - 26
+*    Busy Signal - 27
+*
+* The freq values are calculated as:
+* freq = cos(2 * PI * frequency / 8000)
+*
+* The most commonly needed values are already calculated and listed in the
+* enum IXJ_TONE_FREQ.  Each tone index can have two frequencies with
+* different gains, if you are only using a single frequency set the unused
+* one to 0.
+*
+* The gain values range from 0 to 15 indicating +6dB to -24dB in 2dB
+* increments.
+*
+******************************************************************************/
+
+typedef enum {
+       hz20 = 0x7ffa,
+       hz50 = 0x7fe5,
+       hz133 = 0x7f4c,
+       hz200 = 0x7e6b,
+       hz261 = 0x7d50,         /* .63 C1  */
+       hz277 = 0x7cfa,         /* .18 CS1 */
+       hz293 = 0x7c9f,         /* .66 D1  */
+       hz300 = 0x7c75,
+       hz311 = 0x7c32,         /* .13 DS1 */
+       hz329 = 0x7bbf,         /* .63 E1  */
+       hz330 = 0x7bb8,
+       hz340 = 0x7b75,
+       hz349 = 0x7b37,         /* .23 F1  */
+       hz350 = 0x7b30,
+       hz360 = 0x7ae9,
+       hz369 = 0x7aa8,         /* .99 FS1 */
+       hz380 = 0x7a56,
+       hz392 = 0x79fa,         /* .00 G1  */
+       hz400 = 0x79bb,
+       hz415 = 0x7941,         /* .30 GS1 */
+       hz420 = 0x7918,
+       hz425 = 0x78ee,
+       hz435 = 0x7899,
+       hz440 = 0x786d,         /* .00 A1  */
+       hz445 = 0x7842,
+       hz450 = 0x7815,
+       hz452 = 0x7803,
+       hz466 = 0x7784,         /* .16 AS1 */
+       hz475 = 0x7731,
+       hz480 = 0x7701,
+       hz493 = 0x7685,         /* .88 B1  */
+       hz494 = 0x767b,
+       hz500 = 0x7640,
+       hz520 = 0x7578,
+       hz523 = 0x7559,         /* .25 C2  */
+       hz525 = 0x7544,
+       hz540 = 0x74a7,
+       hz554 = 0x7411,         /* .37 CS2 */
+       hz587 = 0x72a1,         /* .33 D2  */
+       hz590 = 0x727f,
+       hz600 = 0x720b,
+       hz620 = 0x711e,
+       hz622 = 0x7106,         /* .25 DS2 */
+       hz659 = 0x6f3b,         /* .26 E2  */
+       hz660 = 0x6f2e,
+       hz698 = 0x6d3d,         /* .46 F2  */
+       hz700 = 0x6d22,
+       hz739 = 0x6b09,         /* .99 FS2 */
+       hz740 = 0x6afa,
+       hz750 = 0x6a6c,
+       hz770 = 0x694b,
+       hz783 = 0x688b,         /* .99 G2  */
+       hz800 = 0x678d,
+       hz816 = 0x6698,
+       hz830 = 0x65bf,         /* .61 GS2 */
+       hz850 = 0x6484,
+       hz857 = 0x6414,
+       hz880 = 0x629f,         /* .00 A2  */
+       hz900 = 0x6154,
+       hz932 = 0x5f35,         /* .33 AS2 */
+       hz935 = 0x5f01,
+       hz941 = 0x5e9a,
+       hz942 = 0x5e88,
+       hz950 = 0x5dfd,
+       hz975 = 0x5c44,
+       hz1000 = 0x5a81,
+       hz1020 = 0x5912,
+       hz1050 = 0x56e2,
+       hz1100 = 0x5320,
+       hz1140 = 0x5007,
+       hz1200 = 0x4b3b,
+       hz1209 = 0x4a80,
+       hz1215 = 0x4a02,
+       hz1250 = 0x471c,
+       hz1300 = 0x42e0,
+       hz1330 = 0x4049,
+       hz1336 = 0x3fc4,
+       hz1366 = 0x3d22,
+       hz1380 = 0x3be4,
+       hz1400 = 0x3a1b,
+       hz1450 = 0x3596,
+       hz1477 = 0x331c,
+       hz1500 = 0x30fb,
+       hz1600 = 0x278d,
+       hz1633 = 0x2462,
+       hz1638 = 0x23e7,
+       hz1645 = 0x233a,
+       hz1750 = 0x18f8,
+       hz1800 = 0x1405,
+       hz1860 = 0xe0b,
+       hz2100 = 0xf5f6,
+       hz2450 = 0xd3b3
+} IXJ_FREQ;
+
+typedef enum {
+       C1 = hz261,
+       CS1 = hz277,
+       D1 = hz293,
+       DS1 = hz311,
+       E1 = hz329,
+       F1 = hz349,
+       FS1 = hz369,
+       G1 = hz392,
+       GS1 = hz415,
+       A1 = hz440,
+       AS1 = hz466,
+       B1 = hz493,
+       C2 = hz523,
+       CS2 = hz554,
+       D2 = hz587,
+       DS2 = hz622,
+       E2 = hz659,
+       F2 = hz698,
+       FS2 = hz739,
+       G2 = hz783,
+       GS2 = hz830,
+       A2 = hz880,
+       AS2 = hz932,
+} IXJ_NOTE;
+
+typedef struct {
+       int tone_index;
+       int freq0;
+       int gain0;
+       int freq1;
+       int gain1;
+} IXJ_TONE;
+
+#define IXJCTL_INIT_TONE               _IOW ('q', 0xC9, IXJ_TONE *)
+
+/******************************************************************************
+*
+* The IXJCTL_TONE_CADENCE ioctl defines tone sequences used for various
+* Call Progress Tones (CPT).  This is accomplished by setting up an array of
+* IXJ_CADENCE_ELEMENT structures that sequentially define the states of
+* the tone sequence.  The tone_on_time and tone_off time are in
+* 250 microsecond intervals.  A pointer to this array is passed to the
+* driver as the ce element of an IXJ_CADENCE structure.  The elements_used
+* must be set to the number of IXJ_CADENCE_ELEMENTS in the array.  The
+* termination variable defines what to do at the end of a cadence, the
+* options are to play the cadence once and stop, to repeat the last
+* element of the cadence indefinatly, or to repeat the entire cadence
+* indefinatly.  The ce variable is a pointer to the array of IXJ_TONE
+* structures.  If the freq0 variable is non-zero, the tone table contents
+* for the tone_index are updated to the frequencies and gains defined.  It
+* should be noted that DTMF tones cannot be reassigned, so if DTMF tone
+* table indexs are used in a cadence the frequency and gain variables will
+* be ignored.
+*
+* If the array elements contain frequency parameters the driver will
+* initialize the needed tone table elements and begin playing the tone,
+* there is no preset limit on the number of elements in the cadence.  If
+* there is more than one frequency used in the cadence, sequential elements
+* of different frequencies MUST use different tone table indexes.  Only one
+* cadence can be played at a time.  It is possible to build complex
+* cadences with multiple frequencies using 2 tone table indexes by
+* alternating between them.
+*
+******************************************************************************/
+
+typedef struct {
+       int index;
+       int tone_on_time;
+       int tone_off_time;
+       int freq0;
+       int gain0;
+       int freq1;
+       int gain1;
+} IXJ_CADENCE_ELEMENT;
+
+typedef enum {
+       PLAY_ONCE,
+       REPEAT_LAST_ELEMENT,
+       REPEAT_ALL
+} IXJ_CADENCE_TERM;
+
+typedef struct {
+       int elements_used;
+       IXJ_CADENCE_TERM termination;
+       IXJ_CADENCE_ELEMENT *ce;
+} IXJ_CADENCE;
+
+#define IXJCTL_TONE_CADENCE            _IOW ('q', 0xCA, IXJ_CADENCE *)
+/******************************************************************************
+*
+* This group of IOCTLs deal with the playback settings of the DSP
+*
+******************************************************************************/
+
+#define IXJCTL_PLAY_CODEC               PHONE_PLAY_CODEC
+#define IXJCTL_PLAY_START               PHONE_PLAY_START
+#define IXJCTL_PLAY_STOP                PHONE_PLAY_STOP
+#define IXJCTL_PLAY_DEPTH              PHONE_PLAY_DEPTH
+#define IXJCTL_PLAY_VOLUME             PHONE_PLAY_VOLUME
+#define IXJCTL_PLAY_LEVEL              PHONE_PLAY_LEVEL
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the Acoustic Echo Cancellation settings
+* of the DSP
+*
+* Issueing the IXJCTL_AEC_START command with a value of AEC_OFF has the
+* same effect as IXJCTL_AEC_STOP.  This is to simplify slider bar
+* controls.  IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC.
+******************************************************************************/
+#define IXJCTL_AEC_START               _IOW ('q', 0xCB, int)
+#define IXJCTL_AEC_STOP                        _IO  ('q', 0xCC)
+#define IXJCTL_AEC_GET_LEVEL           _IO  ('q', 0xCD)
+
+#define AEC_OFF   0
+#define AEC_LOW   1
+#define AEC_MED   2
+#define AEC_HIGH  3
+/******************************************************************************
+*
+* Call Progress Tones, DTMF, etc.
+* IXJCTL_DTMF_OOB determines if dtmf signaling is sent as Out-Of-Band
+* only.  If you pass a 1, dtmf is suppressed from the audio stream.
+* Tone on and off times are in 250 microsecond intervals so
+* ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360);
+* will set the tone on time of board ixj1 to 360 * 250us = 90ms
+* the default values of tone on and off times is 840 or 210ms
+******************************************************************************/
+
+#define IXJCTL_DTMF_READY              PHONE_DTMF_READY
+#define IXJCTL_GET_DTMF                 PHONE_GET_DTMF
+#define IXJCTL_GET_DTMF_ASCII           PHONE_GET_DTMF_ASCII
+#define IXJCTL_DTMF_OOB                        PHONE_DTMF_OOB
+#define IXJCTL_EXCEPTION               PHONE_EXCEPTION
+#define IXJCTL_PLAY_TONE               PHONE_PLAY_TONE
+#define IXJCTL_SET_TONE_ON_TIME                PHONE_SET_TONE_ON_TIME
+#define IXJCTL_SET_TONE_OFF_TIME       PHONE_SET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_ON_TIME                PHONE_GET_TONE_ON_TIME
+#define IXJCTL_GET_TONE_OFF_TIME       PHONE_GET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_STATE          PHONE_GET_TONE_STATE
+#define IXJCTL_BUSY                    PHONE_BUSY
+#define IXJCTL_RINGBACK                        PHONE_RINGBACK
+#define IXJCTL_DIALTONE                        PHONE_DIALTONE
+#define IXJCTL_CPT_STOP                        PHONE_CPT_STOP
+
+/******************************************************************************
+* LineJack specific IOCTLs
+*
+* The lsb 4 bits of the LED argument represent the state of each of the 4
+* LED's on the LineJack
+******************************************************************************/
+
+#define IXJCTL_SET_LED                 _IOW ('q', 0xCE, int)
+#define IXJCTL_MIXER                   _IOW ('q', 0xCF, int)
+
+/******************************************************************************
+* 
+* The master volume controls use attenuation with 32 levels from 0 to -62dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_MASTER_L         0x0100
+#define MIXER_MASTER_R         0x0200
+#define ATT00DB                        0x00
+#define ATT02DB                        0x01
+#define ATT04DB                        0x02
+#define ATT06DB                        0x03
+#define ATT08DB                        0x04
+#define ATT10DB                        0x05
+#define ATT12DB                        0x06
+#define ATT14DB                        0x07
+#define ATT16DB                        0x08
+#define ATT18DB                        0x09
+#define ATT20DB                        0x0A
+#define ATT22DB                        0x0B
+#define ATT24DB                        0x0C
+#define ATT26DB                        0x0D
+#define ATT28DB                        0x0E
+#define ATT30DB                        0x0F
+#define ATT32DB                        0x10
+#define ATT34DB                        0x11
+#define ATT36DB                        0x12
+#define ATT38DB                        0x13
+#define ATT40DB                        0x14
+#define ATT42DB                        0x15
+#define ATT44DB                        0x16
+#define ATT46DB                        0x17
+#define ATT48DB                        0x18
+#define ATT50DB                        0x19
+#define ATT52DB                        0x1A
+#define ATT54DB                        0x1B
+#define ATT56DB                        0x1C
+#define ATT58DB                        0x1D
+#define ATT60DB                        0x1E
+#define ATT62DB                        0x1F
+#define MASTER_MUTE            0x80
+
+/******************************************************************************
+* 
+* The input volume controls use gain with 32 levels from +12dB to -50dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_PORT_CD_L                0x0600
+#define MIXER_PORT_CD_R                0x0700
+#define MIXER_PORT_LINE_IN_L   0x0800
+#define MIXER_PORT_LINE_IN_R   0x0900
+#define MIXER_PORT_POTS_REC    0x0C00
+#define MIXER_PORT_MIC         0x0E00
+
+#define GAIN12DB               0x00
+#define GAIN10DB               0x01
+#define GAIN08DB               0x02
+#define GAIN06DB               0x03
+#define GAIN04DB               0x04
+#define GAIN02DB               0x05
+#define GAIN00DB               0x06
+#define GAIN_02DB              0x07
+#define GAIN_04DB              0x08
+#define GAIN_06DB              0x09
+#define GAIN_08DB              0x0A
+#define GAIN_10DB              0x0B
+#define GAIN_12DB              0x0C
+#define GAIN_14DB              0x0D
+#define GAIN_16DB              0x0E
+#define GAIN_18DB              0x0F
+#define GAIN_20DB              0x10
+#define GAIN_22DB              0x11
+#define GAIN_24DB              0x12
+#define GAIN_26DB              0x13
+#define GAIN_28DB              0x14
+#define GAIN_30DB              0x15
+#define GAIN_32DB              0x16
+#define GAIN_34DB              0x17
+#define GAIN_36DB              0x18
+#define GAIN_38DB              0x19
+#define GAIN_40DB              0x1A
+#define GAIN_42DB              0x1B
+#define GAIN_44DB              0x1C
+#define GAIN_46DB              0x1D
+#define GAIN_48DB              0x1E
+#define GAIN_50DB              0x1F
+#define INPUT_MUTE             0x80
+
+/******************************************************************************
+* 
+* The POTS volume control use attenuation with 8 levels from 0dB to -28dB
+* with steps of 4dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_PORT_POTS_PLAY   0x0F00
+
+#define POTS_ATT_00DB          0x00
+#define POTS_ATT_04DB          0x01
+#define POTS_ATT_08DB          0x02
+#define POTS_ATT_12DB          0x03
+#define POTS_ATT_16DB          0x04
+#define POTS_ATT_20DB          0x05
+#define POTS_ATT_24DB          0x06
+#define POTS_ATT_28DB          0x07
+#define POTS_MUTE              0x80
+
+/******************************************************************************
+* 
+* The DAA controls the interface to the PSTN port.  The driver loads the
+* US coefficients by default, so if you live in a different country you
+* need to load the set for your countries phone system.
+* 
+******************************************************************************/
+#define IXJCTL_DAA_COEFF_SET           _IOW ('q', 0xD0, int)
+
+#define DAA_US                 1       //PITA 8kHz
+#define DAA_UK                 2       //ISAR34 8kHz
+#define DAA_FRANCE     3       //
+#define DAA_GERMANY    4
+#define DAA_AUSTRALIA  5
+#define DAA_JAPAN      6
+
+/******************************************************************************
+* 
+* Use IXJCTL_PORT to set or query the port the card is set to.  If the
+* argument is set to PORT_QUERY, the return value of the ioctl will
+* indicate which port is currently in use, otherwise it will change the
+* port.
+* 
+******************************************************************************/
+#define IXJCTL_PORT                    _IOW ('q', 0xD1, int)
+
+#define PORT_QUERY     0
+#define PORT_POTS      1
+#define PORT_PSTN      2
+#define PORT_SPEAKER   3
+#define PORT_HANDSET   4
+
+#define IXJCTL_PSTN_SET_STATE          PHONE_PSTN_SET_STATE
+#define IXJCTL_PSTN_GET_STATE          PHONE_PSTN_GET_STATE
+
+#define PSTN_ON_HOOK   0
+#define PSTN_RINGING   1
+#define PSTN_OFF_HOOK  2
+#define PSTN_PULSE_DIAL        3
+
+/******************************************************************************
+* 
+* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR), 
+* and the transmit gain (AGX).  OR together the components and pass them
+* as the parameter to IXJCTL_DAA_AGAIN.  The default setting is both at 0dB.
+* 
+******************************************************************************/
+#define IXJCTL_DAA_AGAIN               _IOW ('q', 0xD2, int)
+
+#define AGRR00DB       0x00    // Analog gain in receive direction 0dB
+#define AGRR3_5DB      0x10    // Analog gain in receive direction 3.5dB
+#define AGRR06DB       0x30    // Analog gain in receive direction 6dB
+
+#define AGX00DB                0x00    // Analog gain in transmit direction 0dB
+#define AGX_6DB                0x04    // Analog gain in transmit direction -6dB
+#define AGX3_5DB       0x08    // Analog gain in transmit direction 3.5dB
+#define AGX_2_5B       0x0C    // Analog gain in transmit direction -2.5dB
+
+#define IXJCTL_PSTN_LINETEST           _IO  ('q', 0xD3)
+
+typedef struct {
+       char month[3];
+       char day[3];
+       char hour[3];
+       char min[3];
+       int numlen;
+       char number[11];
+       int namelen;
+       char name[80];
+} IXJ_CID;
+
+#define IXJCTL_CID                     _IOR ('q', 0xD4, IXJ_CID *)
+/******************************************************************************
+* 
+* The wink duration is tunable with this ioctl.  The default wink duration  
+* is 320ms.  You do not need to use this ioctl if you do not require a
+* different wink duration.
+* 
+******************************************************************************/
+#define IXJCTL_WINK_DURATION           PHONE_WINK_DURATION
+
+/******************************************************************************
+* 
+* This ioctl will connect the POTS port to the PSTN port on the LineJACK
+* In order for this to work properly the port selection should be set to
+* the PSTN port with IXJCTL_PORT prior to calling this ioctl.  This will
+* enable conference calls between PSTN callers and network callers.
+* Passing a 1 to this ioctl enables the POTS<->PSTN connection while
+* passing a 0 turns it back off.
+* 
+******************************************************************************/
+#define IXJCTL_POTS_PSTN               _IOW ('q', 0xD5, int)
+
+/******************************************************************************
+*
+* IOCTLs added by request.
+*
+* IXJCTL_HZ sets the value your Linux kernel uses for HZ as defined in
+*           /usr/include/asm/param.h, this determines the fundamental
+*           frequency of the clock ticks on your Linux system.  The kernel
+*           must be rebuilt if you change this value, also all modules you
+*           use (except this one) must be recompiled.  The default value
+*           is 100, and you only need to use this IOCTL if you use some
+*           other value.
+*
+*
+* IXJCTL_RATE sets the number of times per second that the driver polls
+*             the DSP.  This value cannot be larger than HZ.  By
+*             increasing both of these values, you may be able to reduce
+*             latency because the max hang time that can exist between the
+*             driver and the DSP will be reduced.
+*
+******************************************************************************/
+
+#define IXJCTL_HZ                       _IOW ('q', 0xE0, int)
+#define IXJCTL_RATE                     _IOW ('q', 0xE1, int)
+#define IXJCTL_FRAMES_READ             _IOR ('q', 0xE2, unsigned long)
+#define IXJCTL_FRAMES_WRITTEN          _IOR ('q', 0xE3, unsigned long)
+#define IXJCTL_READ_WAIT               _IOR ('q', 0xE4, unsigned long)
+#define IXJCTL_WRITE_WAIT              _IOR ('q', 0xE5, unsigned long)
+#define IXJCTL_DRYBUFFER_READ          _IOR ('q', 0xE6, unsigned long)
+#define IXJCTL_DRYBUFFER_CLEAR         _IO  ('q', 0xE7)
+
+/******************************************************************************
+*
+* The intercom IOCTL's short the output from one card to the input of the
+* other and vice versa (actually done in the DSP read function).  It is only
+* necessary to execute the IOCTL on one card, but it is necessary to have
+* both devices open to be able to detect hook switch changes.  The record
+* codec and rate of each card must match the playback codec and rate of
+* the other card for this to work properly.
+*
+******************************************************************************/
+
+#define IXJCTL_INTERCOM_START          _IOW ('q', 0xFD, int)
+#define IXJCTL_INTERCOM_STOP           _IOW ('q', 0xFE, int)
index 847697b4d13c656a3b8f6ed02b49661da2350ff5..d5e28c25837bab1c3117aab1bc1287e615196acf 100644 (file)
 
 #define AURORA_MAJOR 79
 
+#define PHONE_MAJOR    100
+
 #define RTF_MAJOR      150
 #define RAW_MAJOR      162
 
index 2acbd21103e986ff9267d96ab68c6e4c9e13866e..6d1d2f94d514de546eb05e47ad5b22e8747c4a1e 100644 (file)
@@ -376,8 +376,6 @@ extern inline void free_pages(unsigned long addr, unsigned long order)
 
 extern void show_free_areas(void);
 extern void show_free_areas_node(int nid);
-extern struct page * put_dirty_page(struct task_struct * tsk, struct page *page,
-       unsigned long address);
 
 extern void clear_page_tables(struct mm_struct *, unsigned long, int);
 
diff --git a/include/linux/phonedev.h b/include/linux/phonedev.h
new file mode 100644 (file)
index 0000000..d54049e
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __LINUX_PHONEDEV_H
+#define __LINUX_PHONEDEV_H
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+struct phone_device {
+       struct phone_device *next;
+       struct file_operations *f_op;
+       int (*open) (struct phone_device *, struct file *);
+       int board;              /* Device private index */
+       int minor;
+};
+
+extern int phonedev_init(void);
+#define PHONE_MAJOR    100
+extern int phone_register_device(struct phone_device *, int unit);
+#define PHONE_UNIT_ANY -1
+extern void phone_unregister_device(struct phone_device *);
+
+#endif
+#endif
diff --git a/include/linux/telephony.h b/include/linux/telephony.h
new file mode 100644 (file)
index 0000000..082b885
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ *              telephony.h
+ *
+ *              Basic Linux Telephony Interface
+ *
+ *              (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Authors:       Ed Okerson, <eokerson@quicknet.net>
+ *                Greg Herlein, <gherlein@quicknet.net>
+ *
+ * Contributors:  Alan Cox, <acox@redhat.com>
+ *                David Erhart, <derhart@quicknet.net>
+ *
+ * Version:       0.1.0 - December 19, 1999
+ *
+ * Fixes:
+ */
+
+#ifndef TELEPHONY_H
+#define TELEPHONY_H
+
+/* vendor identification numbers */
+#define PHONE_VENDOR_IXJ          1
+#define PHONE_VENDOR_QUICKNET     PHONE_IXJ
+#define PHONE_VENDOR_VOICETRONIX  2
+#define PHONE_VENDOR_ACULAB       3
+#define PHONE_VENDOR_DIGI         4
+#define PHONE_VENDOR_FRANKLIN     5
+
+/******************************************************************************
+ *  Vendor Summary Information Area
+ *
+ *  Quicknet Technologies, Inc. - makes low density analog telephony cards
+ *    with audio compression, POTS and PSTN interfaces (www.quicknet.net)
+ *
+ *  (other vendors following this API shuld add a short description of
+ *  the telephony products they support under Linux)
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+*
+* The capabilities ioctls can inform you of the capabilities of each phone
+* device installed in your system.  The PHONECTL_CAPABILITIES ioctl
+* returns an integer value indicating the number of capabilities the   
+* device has.  The PHONECTL_CAPABILITIES_LIST will fill an array of 
+* capability structs with all of it's capabilities.  The
+* PHONECTL_CAPABILITIES_CHECK takes a single capability struct and returns
+* a TRUE if the device has that capability, otherwise it returns false.
+* 
+******************************************************************************/
+typedef enum {
+       vendor = 0,
+       device,
+       port,
+       codec,
+       dsp
+} phone_cap;
+
+struct phone_capability {
+       char desc[80];
+       phone_cap captype;
+       int cap;
+       int handle;
+};
+
+typedef enum {
+       pots = 0,
+       pstn,
+       handset,
+       speaker
+} phone_ports;
+
+#define PHONE_CAPABILITIES              _IO  ('q', 0x80)
+#define PHONE_CAPABILITIES_LIST         _IOR ('q', 0x81, struct phone_capability *)
+#define PHONE_CAPABILITIES_CHECK        _IOW ('q', 0x82, struct phone_capability *)
+
+#define PHONE_RING                     _IO  ('q', 0x83)
+#define PHONE_HOOKSTATE                        _IO  ('q', 0x84)
+#define PHONE_MAXRINGS                 _IOW ('q', 0x85, char)
+#define PHONE_RING_CADENCE             _IOW ('q', 0x86, short)
+#define PHONE_RING_START               _IO  ('q', 0x87)
+#define PHONE_RING_STOP                        _IO  ('q', 0x88)
+
+#define USA_RING_CADENCE        0xC0C0
+
+#define PHONE_REC_CODEC                        _IOW ('q', 0x89, int)
+#define PHONE_REC_START                        _IO  ('q', 0x8A)
+#define PHONE_REC_STOP                 _IO  ('q', 0x8B)
+#define PHONE_REC_DEPTH                        _IOW ('q', 0x8C, int)
+#define PHONE_FRAME                    _IOW ('q', 0x8D, int)
+#define PHONE_REC_VOLUME               _IOW ('q', 0x8E, int)
+#define PHONE_REC_LEVEL                        _IO  ('q', 0x8F)
+
+#define PHONE_PLAY_CODEC               _IOW ('q', 0x90, int)
+#define PHONE_PLAY_START               _IO  ('q', 0x91)
+#define PHONE_PLAY_STOP                        _IO  ('q', 0x92)
+#define PHONE_PLAY_DEPTH               _IOW ('q', 0x93, int)
+#define PHONE_PLAY_VOLUME              _IOW ('q', 0x94, int)
+#define PHONE_PLAY_LEVEL               _IO  ('q', 0x95)
+#define PHONE_DTMF_READY               _IOR ('q', 0x96, int)
+#define PHONE_GET_DTMF                 _IOR ('q', 0x97, int)
+#define PHONE_GET_DTMF_ASCII           _IOR ('q', 0x98, int)
+#define PHONE_DTMF_OOB                 _IOW ('q', 0x99, int)
+#define PHONE_EXCEPTION                        _IOR ('q', 0x9A, int)
+#define PHONE_PLAY_TONE                        _IOW ('q', 0x9B, char)
+#define PHONE_SET_TONE_ON_TIME         _IOW ('q', 0x9C, int)
+#define PHONE_SET_TONE_OFF_TIME                _IOW ('q', 0x9D, int)
+#define PHONE_GET_TONE_ON_TIME         _IO  ('q', 0x9E)
+#define PHONE_GET_TONE_OFF_TIME                _IO  ('q', 0x9F)
+#define PHONE_GET_TONE_STATE           _IO  ('q', 0xA0)
+#define PHONE_BUSY                     _IO  ('q', 0xA1)
+#define PHONE_RINGBACK                 _IO  ('q', 0xA2)
+#define PHONE_DIALTONE                 _IO  ('q', 0xA3)
+#define PHONE_CPT_STOP                 _IO  ('q', 0xA4)
+
+#define PHONE_PSTN_SET_STATE           _IOW ('q', 0xA4, int)
+#define PHONE_PSTN_GET_STATE           _IO  ('q', 0xA5)
+
+#define PSTN_ON_HOOK           0
+#define PSTN_RINGING           1
+#define PSTN_OFF_HOOK          2
+#define PSTN_PULSE_DIAL                3
+
+/******************************************************************************
+* 
+* The wink duration is tunable with this ioctl.  The default wink duration  
+* is 320ms.  You do not need to use this ioctl if you do not require a
+* different wink duration.
+* 
+******************************************************************************/
+#define PHONE_WINK_DURATION            _IOW ('q', 0xA6, int)
+
+
+/******************************************************************************
+* 
+*  Codec Definitions
+* 
+******************************************************************************/
+typedef enum {
+       G723_63 = 1,
+       G723_53 = 2,
+       TS85 = 3,
+       TS48 = 4,
+       TS41 = 5,
+       G728 = 6,
+       G729 = 7,
+       ULAW = 8,
+       ALAW = 9,
+       LINEAR16 = 10,
+       LINEAR8 = 11,
+       WSS = 12
+} phone_codec;
+
+/******************************************************************************
+*
+* The exception structure allows us to multiplex multiple events onto the
+* select() exception set.  If any of these flags are set select() will
+* return with a positive indication on the exception set.  The dtmf_ready
+* bit indicates if there is data waiting in the DTMF buffer.  The
+* hookstate bit is set if there is a change in hookstate status, it does not
+* indicate the current state of the hookswitch.  The pstn_ring bit
+* indicates that the DAA on a LineJACK card has detected ring voltage on
+* the PSTN port.  The caller_id bit indicates that caller_id data has been
+* recieved and is available.  The pstn_wink bit indicates that the DAA on
+* the LineJACK has recieved a wink from the telco switch.  The f0, f1, f2
+* and f3 bits indicate that the filter has been triggered by detecting the
+* frequency programmed into that filter.
+*
+* The remaining bits should be set to zero. They will become defined over time
+* for other interface cards and their needs.
+*
+******************************************************************************/
+struct phone_except
+{
+       unsigned int dtmf_ready:1;
+       unsigned int hookstate:1;
+       unsigned int pstn_ring:1;
+       unsigned int caller_id:1;
+       unsigned int pstn_wink:1;
+       unsigned int f0:1;
+       unsigned int f1:1;
+       unsigned int f2:1;
+       unsigned int f3:1;
+       unsigned int reserved:23;
+};
+
+union telephony_exception {
+       struct phone_except bits;
+       unsigned int bytes;
+};
+
+
+#endif                         /* TELEPHONY_H */
index d9cedda121faf18839e5f8a903b496d832b297f9..88465e5676292bcd8eaba44cfc6e677dd73e0c12 100644 (file)
@@ -235,6 +235,17 @@ struct video_unit
        int     teletext;       /* Teletext minor */
 };
 
+struct vbi_format {
+       __u32   sampling_rate;  /* in Hz */
+       __u32   samples_per_line;
+       __u32   sample_format;  /* VIDEO_PALETTE_RAW only (1 byte) */
+       __s32   start[2];       /* starting line for each frame */
+       __u32   count[2];       /* count of lines for each frame */
+       __u32   flags;
+#define        VBI_UNSYNC      1       /* can distingues between top/bottom field */
+#define        VBI_INTERLACED  2       /* lines are interlaced */
+};
+
 /* video_info is biased towards hardware mpeg encode/decode */
 /* but it could apply generically to any hardware compressor/decompressor */
 struct video_info
@@ -284,14 +295,17 @@ struct video_code
 #define VIDIOCSAUDIO           _IOW('v',17, struct video_audio)        /* Audio source, mute etc */
 #define VIDIOCSYNC             _IOW('v',18, int)                       /* Sync with mmap grabbing */
 #define VIDIOCMCAPTURE         _IOW('v',19, struct video_mmap)         /* Grab frames */
-#define VIDIOCGMBUF            _IOR('v', 20, struct video_mbuf)        /* Memory map buffer info */
-#define VIDIOCGUNIT            _IOR('v', 21, struct video_unit)        /* Get attached units */
-#define VIDIOCGCAPTURE         _IOR('v',22, struct video_capture)      /* Get frame buffer */
-#define VIDIOCSCAPTURE         _IOW('v',23, struct video_capture)      /* Set frame buffer - root only */
+#define VIDIOCGMBUF            _IOR('v',20, struct video_mbuf)         /* Memory map buffer info */
+#define VIDIOCGUNIT            _IOR('v',21, struct video_unit)         /* Get attached units */
+#define VIDIOCGCAPTURE         _IOR('v',22, struct video_capture)      /* Get subcapture */
+#define VIDIOCSCAPTURE         _IOW('v',23, struct video_capture)      /* Set subcapture */
 #define VIDIOCSPLAYMODE                _IOW('v',24, struct video_play_mode)    /* Set output video mode/feature */
 #define VIDIOCSWRITEMODE       _IOW('v',25, int)                       /* Set write mode */
 #define VIDIOCGPLAYINFO                _IOR('v',26, struct video_info)         /* Get current playback info from hardware */
 #define VIDIOCSMICROCODE       _IOW('v',27, struct video_code)         /* Load microcode into hardware */
+#define        VIDIOCGVBIFMT           _IOR('v',28, struct vbi_format)         /* Get VBI information */
+#define        VIDIOCSVBIFMT           _IOW('v',29, struct vbi_format)         /* Set VBI information */
+
 
 #define BASE_VIDIOCPRIVATE     192             /* 192-255 are private */
 
index e809144e736ba953fa9a268426bc31d6ad786d94..54f5349fafa2cbbdedfb7a984bd26a15f02b7e4e 100644 (file)
@@ -7,7 +7,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Wed Dec  8 10:49:17 1999
+ * Modified at:   Tue Dec 21 11:20:30 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -80,14 +80,20 @@ typedef enum {
        RECV_TEST_RSP,
        RECV_UA_RSP,
        RECV_DM_RSP,
+       RECV_RD_RSP,
        RECV_I_CMD,
        RECV_I_RSP,
        RECV_UI_FRAME,
        RECV_FRMR_RSP,
        RECV_RR_CMD,
        RECV_RR_RSP,
-       RECV_RNR_FRAME,
-       RECV_DISC_FRAME,
+       RECV_RNR_CMD,
+       RECV_RNR_RSP,
+       RECV_REJ_CMD,
+       RECV_REJ_RSP,
+       RECV_SREJ_CMD,
+       RECV_SREJ_RSP,
+       RECV_DISC_CMD,
 
        /* Timer events */
        SLOT_TIMER_EXPIRED,
index 643a004cc4341f091980441180100fe0ccc24df9..e1d36e2fafa31406c1dfee66fad259050553eacb 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Thu Dec  9 15:50:09 1999
+ * Modified at:   Tue Dec 21 11:10:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>,
@@ -116,15 +116,17 @@ void irlap_send_snrm_frame(struct irlap_cb *, struct qos_info *);
 void irlap_send_test_frame(struct irlap_cb *self, __u32 daddr, 
                           struct sk_buff *cmd);
 void irlap_send_ua_response_frame(struct irlap_cb *, struct qos_info *);
-void irlap_send_dm_frame(struct irlap_cb *);
-void irlap_send_disc_frame(struct irlap_cb *);
-void irlap_send_rr_frame(struct irlap_cb *, int command);
+void irlap_send_dm_frame(struct irlap_cb *self);
+void irlap_send_rd_frame(struct irlap_cb *self);
+void irlap_send_disc_frame(struct irlap_cb *self);
+void irlap_send_rr_frame(struct irlap_cb *self, int command);
 
 void irlap_send_data_primary(struct irlap_cb *, struct sk_buff *);
 void irlap_send_data_primary_poll(struct irlap_cb *, struct sk_buff *);
 void irlap_send_data_secondary(struct irlap_cb *, struct sk_buff *);
 void irlap_send_data_secondary_final(struct irlap_cb *, struct sk_buff *);
 void irlap_resend_rejected_frames(struct irlap_cb *, int command);
+void irlap_resend_rejected_frame(struct irlap_cb *self, int command);
 
 void irlap_send_i_frame(struct irlap_cb *, struct sk_buff *, int command);
 void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
index e653fd22cdca570d3d11900aa80bbca6f7163dab..eb29bf649f820367c7b302212892220c387e4e9b 100644 (file)
@@ -273,6 +273,7 @@ send_now:
        tsk = cpu_curr(this_cpu);
        if (preemption_goodness(tsk, p, this_cpu) > 0)
                tsk->need_resched = 1;
+       spin_unlock_irqrestore(&runqueue_lock, flags);
 #endif
 }
 
index ccd1f33b3b5d148661695369df618e8519443754..b2eab8252258def1765ef4e679df89cbc156942b 100644 (file)
@@ -331,7 +331,7 @@ repeat_page:
        } else
                bh->b_end_io = bounce_end_io_read;
        bh->b_dev_id = (void *)bh_orig;
-       bh->b_rsector = -1;
+       bh->b_rsector = bh_orig->b_rsector;
        memset(&bh->b_wait, -1, sizeof(bh->b_wait));
        bh->b_kiobuf = NULL;
 
index 744221c4043d6124f3192683fedb9ae71808dcda..efa64bd3acc7763ea5b1bc9fd96a2b8efd25890e 100644 (file)
@@ -711,43 +711,6 @@ int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long
        return error;
 }
 
-/*
- * This routine is used to map in a page into an address space: needed by
- * execve() for the initial stack and environment pages.
- */
-struct page * put_dirty_page(struct task_struct * tsk, struct page *page,
-                                                unsigned long address)
-{
-       pgd_t * pgd;
-       pmd_t * pmd;
-       pte_t * pte;
-
-       if (page_count(page) != 1)
-               printk("mem_map disagrees with %p at %08lx\n", page, address);
-       pgd = pgd_offset(tsk->mm, address);
-       pmd = pmd_alloc(pgd, address);
-       if (!pmd) {
-               __free_page(page);
-               oom(tsk);
-               return 0;
-       }
-       pte = pte_alloc(pmd, address);
-       if (!pte) {
-               __free_page(page);
-               oom(tsk);
-               return 0;
-       }
-       if (!pte_none(*pte)) {
-               pte_ERROR(*pte);
-               __free_page(page);
-               return 0;
-       }
-       flush_page_to_ram(page);
-       set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_COPY)));
-/* no need for flush_tlb */
-       return page;
-}
-
 /*
  * This routine handles present pages, when users try to write
  * to a shared page. It is done by copying the page to a new address
index 369934f3f3dc06ee41b41fcdb979845d816e2f04..fbd1946040390c9e3c90aa97f01b5e382d8d8b8b 100644 (file)
@@ -87,6 +87,7 @@
 #include <linux/rtnetlink.h>
 #include <net/br.h>
 #include <linux/proc_fs.h>
+#include <linux/br.h>
 
 #ifndef min
 #define min(a, b) (((a) <= (b)) ? (a) : (b))
@@ -2425,7 +2426,7 @@ int __init brg_probe(struct net_device *dev)
 
   /* Set up MAC address based on BogoMIPs figure for first CPU and time
    */ 
-  bogomips = (boot_cpu_data.loops_per_sec+2500)/500000 ;
+  bogomips = (loops_per_sec+2500)/500000 ;
   get_fast_time(&utime);
 
   /* Ummmm....  YES! */
index 5a93602e2f0143dba17fc6c4e5dfab1b8efe12f4..19663d4b8673035d674897d9fef72a2469283443 100644 (file)
@@ -1604,7 +1604,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
        struct sock *sk = sock->sk;
        struct irda_sock *self;
        struct irda_ias_set     ias_opt;
-       struct ias_object *     ias_obj;
+       struct ias_object      *ias_obj;
        int opt;
        
        self = sk->protinfo.irda;
@@ -1676,7 +1676,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
 
                IRDA_DEBUG(0, __FUNCTION__ "(), sorry not impl. yet!\n");
                return -ENOPROTOOPT;
-       case IRTTP_MAX_SDU_SIZE:
+       case IRLMP_MAX_SDU_SIZE:
                if (optlen < sizeof(int))
                        return -EINVAL;
        
@@ -1904,7 +1904,7 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
                                 sizeof(struct irda_device_info)))
                        return -EFAULT;
                break;
-       case IRTTP_MAX_SDU_SIZE:
+       case IRLMP_MAX_SDU_SIZE:
                val = self->max_data_size;
                len = sizeof(int);
                if (put_user(len, optlen))
index 30ec9c4913eb46cd30140716777351a57b280242..09a4d34c724270cae098f83d82961605a587b5a0 100644 (file)
@@ -148,9 +148,10 @@ static int __ircomm_close(struct ircomm_cb *self)
        ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
 
        /* Remove TSAP */
-       if (self->tsap)
+       if (self->tsap) {
                irttp_close_tsap(self->tsap);
-       self->tsap = NULL;
+               self->tsap = NULL;
+       }
 
        /* Remove LSAP */
        if (self->lsap) {
index fb6fba4ddfc0e978b10068df4e8ee227684214cd..c21107813a03f54ea55678a86bbdc0a254af0ca4 100644 (file)
@@ -1115,10 +1115,16 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
        /* 
         * If we receive data when hardware is stopped then something is wrong.
         * We try to poll the peers line settings to check if we are up todate.
+        * Devices like WinCE can do this, and since they don't send any 
+        * params, we can just as well declare the hardware for running.
         */
        if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
                IRDA_DEBUG(0, __FUNCTION__ "(), polling for line settings!\n");
                ircomm_param_request(self, IRCOMM_POLL, TRUE);
+
+               /* We can just as well declare the hardware for running */
+               ircomm_tty_send_initial_parameters(self);
+               ircomm_tty_link_established(self);
        }
 
        /* 
index 0b5f4f54398be6d79fb6213f45f4c99e5306a9c0..1d95a69b47f09366986c5c6966405a6b578598a9 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Oct  9 09:22:27 1999
- * Modified at:   Sun Dec 12 12:24:32 1999
+ * Modified at:   Tue Dec 21 21:53:45 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -419,7 +419,7 @@ int irda_device_setup(struct net_device *dev)
         dev->hard_header_len = 0;
         dev->addr_len        = 0;
 
-       /* dev->new_style       = 1; */
+       dev->new_style       = 1;
        /* dev->destructor      = irda_device_destructor; */
 
         dev->type            = ARPHRD_IRDA;
index 34eae6c2f2fa4ab023611487c5353a27a1838030..3da2e514ad8a135f6934d18aba2da8975f2cee3c 100644 (file)
@@ -150,7 +150,7 @@ struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
 {
        struct iriap_cb *self;
 
-       IRDA_DEBUG(0, __FUNCTION__ "()\n");
+       IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
        self = kmalloc(sizeof(struct iriap_cb), GFP_ATOMIC);
        if (!self) {
@@ -199,6 +199,9 @@ static void __iriap_close(struct iriap_cb *self)
 
        del_timer(&self->watchdog_timer);
 
+       if (self->skb)
+               dev_kfree_skb(self->skb);
+
        self->magic = 0;
 
        kfree(self);
@@ -213,7 +216,7 @@ void iriap_close(struct iriap_cb *self)
 {
        struct iriap_cb *entry;
 
-       IRDA_DEBUG(0, __FUNCTION__ "()\n");
+       IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IAS_MAGIC, return;);
@@ -233,7 +236,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
 {
        notify_t notify;
 
-       IRDA_DEBUG(0, __FUNCTION__ "()\n");
+       IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
        irda_notify_init(&notify);
        notify.connect_confirm       = iriap_connect_confirm;
@@ -296,6 +299,7 @@ static void iriap_disconnect_indication(void *instance, void *sap,
                IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as server\n");
                iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, 
                                      NULL);
+               iriap_close(self);
        }
 
        if (userdata)
@@ -609,8 +613,6 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
                break;
        }
        iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb);
-
-       iriap_close(self);
 }
 
 /*
@@ -648,16 +650,14 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
        memcpy(attr, fp+n, attr_len); n+=attr_len;
        attr[attr_len] = '\0';
 
+       /* We do not need the buffer anymore */
        dev_kfree_skb(skb);
 
-       /* 
-        *  Now, do some advanced parsing! :-) 
-        */
        IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr);
        obj = irias_find_object(name);
        
        if (obj == NULL) {
-               IRDA_DEBUG(2, "LM-IAS: Object not found\n");
+               IRDA_DEBUG(2, "LM-IAS: Object %s not found\n", name);
                iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN,
                                               &missing);
                return;
@@ -666,20 +666,16 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
        
        attrib = irias_find_attrib(obj, attr);
        if (attrib == NULL) {
-               IRDA_DEBUG(0, "LM-IAS: Attribute %s not found\n", attr);
+               IRDA_DEBUG(2, "LM-IAS: Attribute %s not found\n", attr);
                iriap_getvaluebyclass_response(self, obj->id,
                                               IAS_ATTRIB_UNKNOWN, &missing);
                return;
        }
        
-       IRDA_DEBUG(4, "LM-IAS: found %s\n", attrib->name);
-       
-       /*
-        * We have a match; send the value.
-        */
+       /* We have a match; send the value.  */
        iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS, 
                                       attrib->value);
-
+       
        return;
 }
 
index cd21cdaff6676694dd67e44ef3a572a5974841ca..c03de649049978552caf57a09b92635eb4b97b0a 100644 (file)
@@ -176,6 +176,7 @@ static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
        switch (event) {
        case IAP_CALL_REQUEST_GVBC:
                iriap_next_client_state(self, S_CONNECTING);
+               ASSERT(self->skb == NULL, return;);
                self->skb = skb;
                ret = irlmp_connect_request(self->lsap, LSAP_IAS, 
                                            self->saddr, self->daddr, 
index ecff0953497b6000cc5ce9c0264ad46fb519d40e..1680b31a8d08c16763439c04f8f69f17fd902770 100644 (file)
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      irlap_event.c
- * Version:       0.8
+ * Version:       0.9
  * Description:   IrLAP state machine implementation
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Tue Dec 14 18:58:28 1999
+ * Modified at:   Tue Dec 21 11:27:22 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
@@ -93,14 +93,20 @@ static const char *irlap_event[] = {
        "RECV_TEST_RSP",
        "RECV_UA_RSP",
        "RECV_DM_RSP",
+       "RECV_RD_RSP",
        "RECV_I_CMD",
        "RECV_I_RSP",
        "RECV_UI_FRAME",
        "RECV_FRMR_RSP",
        "RECV_RR_CMD",
        "RECV_RR_RSP",
-       "RECV_RNR_FRAME",
-       "RECV_DISC_FRAME",
+       "RECV_RNR_CMD",
+       "RECV_RNR_RSP",
+       "RECV_REJ_CMD",
+       "RECV_REJ_RSP",
+       "RECV_SREJ_CMD",
+       "RECV_SREJ_RSP",
+       "RECV_DISC_CMD",
        "SLOT_TIMER_EXPIRED",
        "QUERY_TIMER_EXPIRED",
        "FINAL_TIMER_EXPIRED",
@@ -348,9 +354,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
                        
                        irlap_connect_indication(self, skb);
                } else {
-                       IRDA_DEBUG(0, __FUNCTION__ 
-                                  "(), SNRM frame does not contain"
-                                  " and I field!\n");
+                       IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame does not "
+                                  "contain an I field!\n");
                        dev_kfree_skb(skb);
                }
                break;
@@ -792,14 +797,14 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
 
                irlap_connect_confirm(self, skb);
                break;
-       case RECV_DISC_FRAME:
+       case RECV_DM_RSP:     /* FALLTHROUGH */
+       case RECV_DISC_CMD: 
                del_timer(&self->final_timer);
                irlap_next_state(self, LAP_NDM);
 
                irlap_disconnect_indication(self, LAP_DISC_INDICATION);
                dev_kfree_skb(skb);
                break;
-       /* DM handled in irlap_frame.c, irlap_driver_rcv() */           
        default:
                IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
                           irlap_event[event]);         
@@ -949,7 +954,8 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
        ASSERT(self->magic == LAP_MAGIC, return -1;);   
 
        switch (event) {
-       case RECV_UA_RSP:
+       case RECV_UA_RSP: /* FALLTHROUGH */
+       case RECV_DM_RSP:
                del_timer(&self->final_timer);
                
                irlap_apply_default_connection_parameters(self);
@@ -970,9 +976,7 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
                } else {
                        irlap_apply_default_connection_parameters(self);
 
-                       /* 
-                        *  Always switch state before calling upper layers 
-                        */
+                       /*  Always switch state before calling upper layers */
                        irlap_next_state(self, LAP_NDM);
 
                        irlap_disconnect_indication(self, LAP_NO_RESPONSE);
@@ -1268,12 +1272,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
                }
                dev_kfree_skb(skb);
                break;
-       case RECV_RNR_FRAME:
-               IRDA_DEBUG(4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, "
-                          "nr=%d, va=%d, vs=%d, vr=%d\n",
-                          self->retry_count, info->nr, self->va, self->vs, 
-                          self->vr);
-
+       case RECV_RNR_RSP:
                ASSERT(info != NULL, return -1;);
 
                /* Stop final timer */
@@ -1302,7 +1301,9 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
                 *  of receiving a frame (page 45, IrLAP). Check that
                 *  we only do this once for each frame.
                 */
-               if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
+               if (irda_device_is_receiving(self->netdev) && 
+                   !self->add_wait) 
+               {
                        IRDA_DEBUG(1, "FINAL_TIMER_EXPIRED when receiving a "
                              "frame! Waiting a little bit more!\n");
                        irlap_start_final_timer(self, MSECS_TO_JIFFIES(300));
@@ -1348,28 +1349,38 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
                        irlap_disconnect_indication(self, LAP_NO_RESPONSE);
                }
                break;
-       case RECV_DISC_FRAME: /* FIXME: Check how this is in the standard! */
-               IRDA_DEBUG(1, __FUNCTION__ "(), RECV_DISC_FRAME()\n");
-
-               /* Always switch state before calling upper layers */
-               irlap_next_state(self, LAP_NDM);
-               
-               irlap_wait_min_turn_around(self, &self->qos_tx);
-               irlap_send_ua_response_frame(self, NULL);
-
-               del_timer(&self->final_timer);
-               /* del_timer( &self->poll_timer); */
+       case RECV_REJ_RSP:
+               irlap_update_nr_received(self, info->nr);
+               if (self->remote_busy) {
+                       irlap_wait_min_turn_around(self, &self->qos_tx);
+                       irlap_send_rr_frame(self, CMD_FRAME);
+               } else
+                       irlap_resend_rejected_frames(self, CMD_FRAME);
+               irlap_start_final_timer(self, self->final_timeout);
+               dev_kfree_skb(skb);
+               break;
+       case RECV_SREJ_RSP:
+               irlap_update_nr_received(self, info->nr);
+               if (self->remote_busy) {
+                       irlap_wait_min_turn_around(self, &self->qos_tx);
+                       irlap_send_rr_frame(self, CMD_FRAME);
+               } else
+                       irlap_resend_rejected_frame(self, CMD_FRAME);
+               irlap_start_final_timer(self, self->final_timeout);
+               dev_kfree_skb(skb);
+               break;
+       case RECV_RD_RSP:
+               IRDA_DEBUG(0, __FUNCTION__ "(), RECV_RD_RSP\n");
 
+               irlap_next_state(self, LAP_PCLOSE);
+               irlap_send_disc_frame(self);
                irlap_flush_all_queues(self);
-               irlap_apply_default_connection_parameters(self);
-
-               irlap_disconnect_indication(self, LAP_DISC_INDICATION);
-               dev_kfree_skb(skb);             
+               irlap_start_final_timer(self, self->final_timeout);
+               self->retry_count = 0;
                break;
        default:
                IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", 
                           irlap_event[event]);
-
                if (skb)
                        dev_kfree_skb(skb);
 
@@ -1446,7 +1457,7 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
        ASSERT(self->magic == LAP_MAGIC, return -1;);
        
        switch (event) {
-       case RECV_DISC_FRAME:
+       case RECV_DISC_CMD:
                del_timer(&self->final_timer);
 
                irlap_apply_default_connection_parameters(self);
@@ -1510,7 +1521,6 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
                } else {
                        IRDA_DEBUG(0, __FUNCTION__ 
                                   "(), SNRM frame contained an I field!\n");
-                       
                }
                dev_kfree_skb(skb);
                break;
@@ -1594,6 +1604,12 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
                        ret = -EPROTO;
                }
                break;
+       case DISCONNECT_REQUEST:
+               irlap_send_rd_frame(self);
+               irlap_flush_all_queues(self);
+               irlap_start_wd_timer(self, self->wd_timeout);
+               irlap_next_state(self, LAP_SCLOSE);
+               break;
        default:
                IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
                           irlap_event[event]);
@@ -1655,8 +1671,9 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
                                 *  Starting WD-timer here is optional, but
                                 *  not recommended. Note 6 IrLAP p. 83
                                 */
-                               /* irda_start_timer(WD_TIMER, self->wd_timeout); */
-
+#if 0
+                               irda_start_timer(WD_TIMER, self->wd_timeout);
+#endif
                                /* Keep state, do not move this line */
                                irlap_next_state(self, LAP_NRM_S);
                                
@@ -1870,6 +1887,26 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
                }
                dev_kfree_skb(skb);
                break;
+       case RECV_REJ_CMD:
+               irlap_update_nr_received(self, info->nr);
+               if (self->remote_busy) {
+                       irlap_wait_min_turn_around(self, &self->qos_tx);
+                       irlap_send_rr_frame(self, CMD_FRAME);
+               } else
+                       irlap_resend_rejected_frames(self, CMD_FRAME);
+               irlap_start_wd_timer(self, self->wd_timeout);
+               dev_kfree_skb(skb);
+               break;
+       case RECV_SREJ_CMD:
+               irlap_update_nr_received(self, info->nr);
+               if (self->remote_busy) {
+                       irlap_wait_min_turn_around(self, &self->qos_tx);
+                       irlap_send_rr_frame(self, CMD_FRAME);
+               } else
+                       irlap_resend_rejected_frame(self, CMD_FRAME);
+               irlap_start_wd_timer(self, self->wd_timeout);
+               dev_kfree_skb(skb);
+               break;
        case WD_TIMER_EXPIRED:
                /*
                 *  Wait until retry_count * n matches negotiated threshold/
@@ -1896,7 +1933,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
                        irlap_disconnect_indication(self, LAP_NO_RESPONSE);
                }
                break;
-       case RECV_DISC_FRAME:
+       case RECV_DISC_CMD:
                /* Always switch state before calling upper layers */
                irlap_next_state(self, LAP_NDM);
 
@@ -1951,10 +1988,50 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
 static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, 
                              struct sk_buff *skb, struct irlap_info *info) 
 {
-       IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
+       int ret = 0;
+
+       IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+       ASSERT(self != NULL, return -ENODEV;);
+       ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+       
+       switch (event) {
+       case RECV_DISC_CMD:
+               /* Always switch state before calling upper layers */
+               irlap_next_state(self, LAP_NDM);
+               
+               irlap_wait_min_turn_around(self, &self->qos_tx);
+               irlap_send_ua_response_frame(self, NULL);
+               del_timer(&self->wd_timer);
+               irlap_apply_default_connection_parameters(self);
+
+               irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+               dev_kfree_skb(skb);
+               break;
+       case RECV_DM_RSP:
+               /* Always switch state before calling upper layers */
+               irlap_next_state(self, LAP_NDM);
 
-       if (skb)
+               del_timer(&self->wd_timer);
+               irlap_apply_default_connection_parameters(self);
+               
+               irlap_disconnect_indication(self, LAP_DISC_INDICATION);
                dev_kfree_skb(skb);
+               break;
+       case WD_TIMER_EXPIRED:
+               irlap_apply_default_connection_parameters(self);
+               
+               irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+               break;
+       default:
+               IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n", 
+                          event, irlap_event[event]);
+               if (skb)
+                       dev_kfree_skb(skb);
+               
+               ret = -EINVAL;
+               break;
+       }
 
        return -1;
 }
@@ -1980,14 +2057,14 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event,
                irlap_next_state(self, LAP_NRM_S);
                break;
        case DISCONNECT_REQUEST:
-               irlap_wait_min_turn_around( self, &self->qos_tx);
-               /* irlap_send_rd_frame(self); */
-               irlap_start_wd_timer( self, WD_TIMEOUT);
+               irlap_wait_min_turn_around(self, &self->qos_tx);
+               irlap_send_rd_frame(self);
+               irlap_start_wd_timer(self, WD_TIMEOUT);
+               irlap_next_state(self, LAP_SCLOSE);
                break;
        default:
                IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n", 
-                     event, irlap_event[event]);
-
+                          event, irlap_event[event]);
                if (skb)
                        dev_kfree_skb(skb);
 
index 3dc631b6c9c906ba874545ce97cb177452591eae..53f9ccbd4d9cd68be4959e3c28923ba9fe44c909 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Tue Dec 14 09:45:25 1999
+ * Modified at:   Tue Dec 21 11:19:19 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -66,7 +66,7 @@ static inline void irlap_insert_info(struct irlap_cb *self,
        self->mtt_required = 0;
        
        /* 
-        * Delay equals negotiated BOFs count plus the number of BOFs to 
+        * Delay equals negotiated BOFs count, plus the number of BOFs to 
         * force the negotiated minimum turnaround time 
         */
        cb->xbofs = self->bofs_count+self->xbofs_delay;
@@ -570,6 +570,29 @@ void irlap_send_rr_frame(struct irlap_cb *self, int command)
        irlap_queue_xmit(self, skb);
 }
 
+/*
+ * Function irlap_send_rd_frame (self)
+ *
+ *    Request disconnect. Used by a secondary station to request the 
+ *    disconnection of the link.
+ */
+void irlap_send_rd_frame(struct irlap_cb *self)
+{
+       struct sk_buff *skb;
+       __u8 *frame;
+
+       skb = dev_alloc_skb(16);
+       if (!skb)
+               return;
+       
+       frame = skb_put(skb, 2);
+       
+       frame[0] = self->caddr;
+       frame[1] = RD_RSP | PF_BIT;
+
+       irlap_queue_xmit(self, skb);
+}
+
 /*
  * Function irlap_recv_rr_frame (skb, info)
  *
@@ -625,16 +648,56 @@ void irlap_send_frmr_frame( struct irlap_cb *self, int command)
  *
  */
 static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, 
-                                struct irlap_info *info) 
+                                struct irlap_info *info, int command
 {
-       ASSERT(skb != NULL, return;);
-       ASSERT(info != NULL, return;);
-
        info->nr = skb->data[1] >> 5;
 
        IRDA_DEBUG(4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
 
-       irlap_do_event(self, RECV_RNR_FRAME, skb, info);
+       if (command)
+               irlap_do_event(self, RECV_RNR_CMD, skb, info);
+       else
+               irlap_do_event(self, RECV_RNR_RSP, skb, info);
+}
+
+static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, 
+                                struct irlap_info *info, int command)
+{
+       IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+       info->nr = skb->data[1] >> 5;
+       
+       /* Check if this is a command or a response frame */
+       if (command)
+               irlap_do_event(self, RECV_REJ_CMD, skb, info);
+       else
+               irlap_do_event(self, RECV_REJ_RSP, skb, info);
+}
+
+static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, 
+                                 struct irlap_info *info, int command)
+{
+       IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+       info->nr = skb->data[1] >> 5;
+       
+       /* Check if this is a command or a response frame */
+       if (command)
+               irlap_do_event(self, RECV_SREJ_CMD, skb, info);
+       else
+               irlap_do_event(self, RECV_SREJ_RSP, skb, info);
+}
+
+static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, 
+                                 struct irlap_info *info, int command)
+{
+       IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+       /* Check if this is a command or a response frame */
+       if (command)
+               irlap_do_event(self, RECV_DISC_CMD, skb, info);
+       else
+               irlap_do_event(self, RECV_RD_RSP, skb, info);
 }
 
 /*
@@ -643,8 +706,9 @@ static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb,
  *    Received UA (Unnumbered Acknowledgement) frame
  *
  */
-static void irlap_recv_ua_frame(struct irlap_cb *self, struct sk_buff *skb, 
-                               struct irlap_info *info) 
+static inline void irlap_recv_ua_frame(struct irlap_cb *self, 
+                                      struct sk_buff *skb, 
+                                      struct irlap_info *info) 
 {
        irlap_do_event(self, RECV_UA_RSP, skb, info);
 }
@@ -691,7 +755,7 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
 
                irlap_send_i_frame( self, tx_skb, CMD_FRAME);
        } else {
-               IRDA_DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n");
+               IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
                irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
                self->window -= 1;
        }
@@ -872,13 +936,11 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
 /*
  * Function irlap_resend_rejected_frames (nr)
  *
- *    Resend frames which has not been acknowledged. TODO: check that the 
- *    traversal of the list is atomic, i.e that no-one tries to insert or
- *    remove frames from the list while we travers it!
- * 
- *    FIXME: It is not safe to traverse a this list without locking it!
+ *    Resend frames which has not been acknowledged. Should be safe to 
+ *    traverse the list without locking it since this function will only be 
+ *    called from interrupt context (BH)
  */
-void irlap_resend_rejected_frames(struct irlap_cb *self, int command) 
+void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
 {
        struct sk_buff *tx_skb;
        struct sk_buff *skb;
@@ -890,10 +952,9 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
        /* Initialize variables */
        skb = tx_skb = NULL;
 
-       /* 
-        *  Resend all unacknowledged frames 
-        */
        count = skb_queue_len(&self->wx_list);
+
+       /*  Resend unacknowledged frame(s) */
        skb = skb_peek(&self->wx_list);
        while (skb != NULL) {
                irlap_wait_min_turn_around(self, &self->qos_tx);
@@ -903,13 +964,9 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
                 */
                /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
                tx_skb = skb_copy(skb, GFP_ATOMIC);
-               if (tx_skb == NULL) {
-                       /* Unlink tx_skb from list */
-                       tx_skb->next = tx_skb->prev = NULL;
-                       tx_skb->list = NULL;
-               
-                       dev_kfree_skb(skb);
-                       return; 
+               if (!tx_skb) {
+                       IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
+                       return;
                }
                /* Unlink tx_skb from list */
                tx_skb->next = tx_skb->prev = NULL;
@@ -938,16 +995,15 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
                 *  If our skb is the last buffer in the list, then
                 *  we are finished, if not, move to the next sk-buffer
                 */
-               if (skb == skb_peek_tail( &self->wx_list))
+               if (skb == skb_peek_tail(&self->wx_list))
                        skb = NULL;
                else
                        skb = skb->next;
        }
+#if 0 /* Not yet */
        /* 
         *  We can now fill the window with additinal data frames
         */
-       return; /* Skip this for now, DB */
-
        while (skb_queue_len( &self->txq) > 0) {
                
                IRDA_DEBUG(0, __FUNCTION__ "(), sending additional frames!\n");
@@ -969,6 +1025,52 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
                        }
                }
        }
+#endif
+}
+
+void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
+{
+       struct sk_buff *tx_skb;
+       struct sk_buff *skb;
+
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
+
+       /* Initialize variables */
+       skb = tx_skb = NULL;
+
+       /*  Resend unacknowledged frame(s) */
+       skb = skb_peek(&self->wx_list);
+       if (skb != NULL) {
+               irlap_wait_min_turn_around(self, &self->qos_tx);
+
+               /* We copy the skb to be retransmitted since we will have to 
+                * modify it. Cloning will confuse packet sniffers 
+                */
+               /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
+               tx_skb = skb_copy(skb, GFP_ATOMIC);
+               if (!tx_skb) {
+                       IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
+                       return; 
+               }
+               /* Unlink tx_skb from list */
+               tx_skb->next = tx_skb->prev = NULL;
+               tx_skb->list = NULL;
+
+               /*
+                *  make sure the skb->sk accounting of memory usage is sane
+                */
+               if (skb->sk != NULL)
+                       skb_set_owner_w(tx_skb, skb->sk);
+
+               /* Clear old Nr field + poll bit */
+               tx_skb->data[1] &= 0x0f;
+
+               /*  Set poll/final bit */
+               tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
+               
+               irlap_send_i_frame(self, tx_skb, command);
+       }
 }
 
 /*
@@ -1069,7 +1171,7 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
        frame = skb->data;
 
        info->nr = frame[2] >> 5;          /* Next to receive */
-       info->pf = frame[2] & PF_BIT;        /* Final bit */
+       info->pf = frame[2] & PF_BIT;      /* Final bit */
        info->ns = (frame[2] >> 1) & 0x07; /* Next to send */
 
        w = frame[3] & 0x01;
@@ -1145,8 +1247,8 @@ void irlap_send_test_frame(struct irlap_cb *self, __u32 daddr,
  *    Receive a test frame
  *
  */
-void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, 
-                          struct irlap_info *info, int command)
+static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, 
+                                 struct irlap_info *info, int command)
 {
        struct test_frame *frame;
 
@@ -1243,15 +1345,13 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
                        irlap_recv_rr_frame(self, skb, &info, command);
                        break;
                case RNR:
-                       irlap_recv_rnr_frame(self, skb, &info);
+                       irlap_recv_rnr_frame(self, skb, &info, command);
                        break;
                case REJ:
-                       IRDA_DEBUG( 0, "*** REJ frame received! ***\n");
-                       dev_kfree_skb(skb);
+                       irlap_recv_rej_frame(self, skb, &info, command);
                        break;
                case SREJ:
-                       IRDA_DEBUG( 0, "*** SREJ frame received! ***\n");
-                       dev_kfree_skb(skb);
+                       irlap_recv_srej_frame(self, skb, &info, command);
                        break;
                default:
                        WARNING(__FUNCTION__ 
@@ -1276,12 +1376,10 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
                irlap_recv_snrm_cmd(self, skb, &info);
                break;
        case DM_RSP:
-               IRDA_DEBUG( 0, "DM rsp frame received!\n");
-               irlap_next_state(self, LAP_NDM);
-               dev_kfree_skb(skb);
+               irlap_do_event(self, RECV_DM_RSP, skb, &info);
                break;
-       case DISC_CMD:
-               irlap_do_event(self, RECV_DISC_FRAME, skb, &info);
+       case DISC_CMD: /* And RD_RSP */
+               irlap_recv_disc_frame(self, skb, &info, command);
                break;
        case TEST_CMD:
                irlap_recv_test_frame(self, skb, &info, command);
index 505058cb1b1b5187747afb38cf2c1da3e0ce7ca4..0928e2ff9deb4bf81f7ba737777b1a67e0786aa5 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:55:39 1997
- * Modified at:   Thu Dec 16 21:46:38 1999
+ * Modified at:   Tue Dec 21 21:39:31 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
@@ -212,7 +212,7 @@ EXPORT_SYMBOL(irtty_set_packet_mode);
 
 int __init irda_init(void)
 {
-       MESSAGE("IrDA (tm) Protocols for Linux-2.2 (Dag Brattli)\n");
+       MESSAGE("IrDA (tm) Protocols for Linux-2.3 (Dag Brattli)\n");
        
        irlmp_init();
        irlap_init();
index 50fb5836eb33a66521fe236c20495ec886aa534a..c775863fb23283983cd23d953555bebf047dc191 100644 (file)
@@ -1111,13 +1111,22 @@ void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason,
        
        self->connected = FALSE;
        
+       /* Check if client has already tried to close the TSAP */
+       if (self->close_pend) {
+               irttp_close_tsap(self);
+               return;
+       }
+
+       /* No need to notify the client if has already tried to disconnect */
+       if (self->disconnect_pend)
+               return;
+       
        if (self->notify.disconnect_indication)
-               self->notify.disconnect_indication(self->notify.instance, 
-                                                  self, reason, skb);
-       else {
+               self->notify.disconnect_indication(self->notify.instance, self,
+                                                  reason, skb);
+       else
                if (skb)
                        dev_kfree_skb(skb);
-       }
 }
 
 /*
@@ -1131,6 +1140,12 @@ void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb)
 {
        int err;
 
+       /* Check if client has already tried to close the TSAP */
+       if (self->close_pend || self->disconnect_pend) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
        err = self->notify.data_indication(self->notify.instance, self, skb);
 
        /* Usually the layer above will notify that it's input queue is