diff -u --recursive --new-file pre2.0.5/linux/CREDITS linux/CREDITS
--- pre2.0.5/linux/CREDITS	Fri May 17 15:32:09 1996
+++ linux/CREDITS	Sun May 19 15:22:19 1996
@@ -434,6 +434,15 @@
 E: philipg@onsett.com
 D: Kernel / timekeeping stuff
 
+N: Michael A. Griffith
+E: grif@cs.ucr.edu
+W: http://www.cs.ucr.edu/~grif
+D: Loopback speedup, qlogic scsi hacking, VT_LOCKSWITCH
+S: Department of Computer Science
+S: University of California, Riverside
+S: Riverside, CA  92521-0304
+S: USA
+
 N: Dmitry S. Gorodchanin
 E: begemot@bgm.rosprint.net
 D: RISCom/8 driver, misc kernel fixes.
@@ -1270,8 +1279,10 @@
 
 N: Stephen Tweedie
 E: sct@dcs.ed.ac.uk
+P: 1024/E7A417AD E2 FE A4 20 34 EC ED FC 7D 7E 67 8D E0 31 D1 69
 D: Second extended file system developer
 D: General filesystem hacker
+D: kswap vm management code
 S: Dept. of Computer Science
 S: University of Edinburgh
 S: JCMB, The King's Buildings
@@ -1349,6 +1360,13 @@
 S: Roger Maris Cancer Center
 S: 820 4th St. N.
 S: Fargo, ND  58122
+
+N: Hans-Joachim Widmaier
+E: jbhr@sofal.tynet.sub.org
+D: AFFS rewrite
+S: Eichenweg 16
+S: 73650 Winterbach
+S: Germany
 
 N: Marco van Wieringen
 E: mvw@mercury.mcs.nl.mugnet.org
diff -u --recursive --new-file pre2.0.5/linux/Documentation/Changes linux/Documentation/Changes
--- pre2.0.5/linux/Documentation/Changes	Fri May 17 15:32:09 1996
+++ linux/Documentation/Changes	Fri May 17 18:30:39 1996
@@ -324,8 +324,8 @@
 numbers are used, and their use will be discontinued entirely in 2.1.x
 
    In order to avoid trouble, you need to recompile any programs that
-emit floppy ioctls. These include mtools and fdutils. You can get
-mtools at:
+emit floppy ioctls. These include mtools, fdutils and dosemu. You can
+get mtools at:
 
 ftp://ftp.imag.fr/pub/Linux/ZLIBC/mtools/mtools-3.0.src.tar.gz
 ftp://sunsite.unc.edu/pub/Linux/utils/disk-management/mtools-3.0.src.tar.gz
@@ -336,6 +336,8 @@
 ftp://ftp.imag.fr/pub/Linux/ZLIBC/fdutils/fdutils-4.3.src.tar.gz
 ftp://sunsite.unc.edu/pub/Linux/system/Misc/fdutils-4.3.src.tar.gz
 ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-4.3.src.tar.gz
+
+   For dosemu, see above.
 
    In the future, the ioctl used by fdformat might be discontinued
 altogether. Please use superformat (included in fdutils) instead.
diff -u --recursive --new-file pre2.0.5/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- pre2.0.5/linux/Documentation/Configure.help	Fri May 17 15:32:09 1996
+++ linux/Documentation/Configure.help	Sun May 19 15:29:28 1996
@@ -1,8 +1,7 @@
 # Maintained by Axel Boldt (boldt@math.ucsb.edu) 
 #
 # This version of the Linux kernel configuration help texts
-# corresponds to the kernel versions 1.3.x. Be aware that these
-# are development kernels.
+# corresponds to the kernel versions 2.0.x.
 #
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
@@ -45,7 +44,6 @@
   may not meet the normal level of reliability or it may fail to work
   in some special cases. Detailed bug reports from people familiar with
   the kernel internals are usually welcomed by the developers. 
-
   Unless you intend to help test and develop a feature or driver that
   falls into this category, or you have a situation that requires using 
   these features you should probably say N here, which will cause this 
@@ -128,7 +126,7 @@
   interfaces, for a combination of up to eight IDE disk/cdrom/tape
   drives.  Useful information about large (>540MB) IDE disks,
   soundcard IDE ports, and other topics, is all contained in
-  drivers/block/README.ide.  If you have one or more IDE drives, say Y
+  Documentation/ide.txt.  If you have one or more IDE drives, say Y
   here.  If your system has no IDE drives, or if memory requirements
   are really tight, you could say N here, and select the Old harddisk
   driver instead to save about 13kB of memory in the kernel.  To
@@ -156,11 +154,13 @@
   the new enhanced driver by itself.  This option installs the old
   harddisk driver to control the primary IDE/disk interface in the
   system, leaving the new enhanced IDE driver take care of only the
-  2nd/3rd/4th IDE interfaces.  Choosing this option may be useful for
-  older systems which have MFM/RLL/ESDI controller+drives at the
-  primary port address (0x1f0), along with IDE drives at the
-  secondary/3rd/4th port addresses.  Normally, just say N here; you
-  will then use the new driver for all 4 interfaces.
+  2nd/3rd/4th IDE interfaces. Doing this will prevent you from having
+  an IDE/ATAPI CDROM or tape drive connected to the primary IDE
+  interface. Choosing this option may be useful for older systems
+  which have MFM/RLL/ESDI controller+drives at the primary port
+  address (0x1f0), along with IDE drives at the secondary/3rd/4th port
+  addresses.  Normally, just say N here; you will then use the new
+  driver for all 4 interfaces.
   
 Include IDE/ATAPI CDROM support
 CONFIG_BLK_DEV_IDECD
@@ -174,9 +174,10 @@
   If this is your only CDROM drive, you can say N to all other CDROM
   options, but be sure to say Y to the ISO9660 filesystem.  Read the
   CDROM-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that older versions of
-  lilo (the linux boot loader) cannot properly deal with IDE/ATAPI
-  CDROMs, so install lilo-16 or higher, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO and the file
+  Documentation/cdrom/ide-cd.  Note that older versions of lilo (the
+  linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so
+  install lilo-16 or higher, available from
   sunsite.unc.edu:/pub/Linux/system/Linux-boot/lilo.
 
 Include IDE/ATAPI TAPE support
@@ -186,7 +187,7 @@
   similar to the SCSI protocol.  At boot time, the TAPE drive will
   be identified along with other IDE devices, as "hdb" or "hdc",
   or something similar.  Be sure to consult the drivers/block/ide-tape.c
-  and README.ide files for usage information.
+  and Documentation/ide.txt files for usage information.
 
 Support removable IDE interfaces (PCMCIA)
 CONFIG_BLK_DEV_IDE_PCMCIA
@@ -278,8 +279,12 @@
 
 XT harddisk support
 CONFIG_BLK_DEV_XD
-  Very old 8 bit hard disk controllers used in the IBM XT
-  computer. Pretty unlikely that you have this: say N.
+  Very old 8 bit hard disk controllers used in the IBM XT computer. To
+  include a driver for these, say Y. If you want to compile the driver
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt. It's pretty unlikely that you have one of
+  these: say N.
 
 Multiple devices driver support
 CONFIG_BLK_DEV_MD
@@ -390,15 +395,15 @@
 
 Network aliasing
 CONFIG_NET_ALIAS
-  This is for setting several network addresses on the same low-level
+  This is for setting multiple IP addresses on the same low-level
   network device driver. Typically used for services that act
-  differently based on the address they listen on (e.g. Apache httpd)
-  or for connecting to different logical networks through the same
-  physical interface.  This is the generic part, later when
-  configuring network protocol options you will be asked for
-  protocol-specific aliasing support.  See
+  differently based on the address they listen on (e.g. "multihosting"
+  on Apache httpd) or for connecting to different logical networks
+  through the same physical interface.  This is the generic part,
+  later when configuring network protocol options you will be asked
+  for protocol-specific aliasing support.  See
   Documentation/networking/alias.txt for more info.  If you need this
-  features (for any protocol, like IP) say Y; if unsure, say N.
+  feature (for any protocol, like IP) say Y; if unsure, say N.
 
 Network firewalls
 CONFIG_FIREWALL
@@ -407,8 +412,16 @@
   net is inspected by the firewall first. If you want to configure
   your Linux box as a firewall for a local network, say Y here. If
   your local network is TCP/IP based, you will have to say Y to "IP:
-  firewalling", below. Chances are that you should use this on any
-  machine being run as a router and not on a host.
+  firewalling", below.  You also need to say Y here and enable "IP
+  firewalling" below in order to be able to use IP masquerading
+  (i.e. local computers can chat with an outside host, but that
+  outside host is made to think that it is talking to the firewall
+  box. Makes the local network completely invisible and avoids the
+  need to allocate valid IP host addresses for the machines on the
+  local net) or to use the ip packet accounting to see what is using
+  all your network bandwidth. Chances are that you should use this on
+  any machine being run as a router and not on a host. If unsure, say
+  N.
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
@@ -512,8 +525,9 @@
   Find out whether you have a PCI motherboard. PCI is the name of a
   bus system, i.e. the way the CPU talks to the other stuff inside
   your box. Other bus systems are ISA, EISA, Microchannel (MCA) or
-  VESA. If you have PCI, say Y, otherwise N. Note1: MCA systems are
-  not supported by the standard kernels, but patches exist at
+  VESA. If you have PCI, say Y, otherwise N. Note1: MCA systems
+  (notably some IBM PS/2's) are not supported by the standard kernels,
+  but patches exist at
   http://www.undergrad.math.uwaterloo.ca/~cpbeaure/mca-linux.html on
   the WWW. Note2: some old PCI motherboards have BIOS bugs and may
   crash if "PCI bios support" is enabled (but they run fine without
@@ -615,19 +629,26 @@
 
 Kernel support for JAVA binaries
 CONFIG_BINFMT_JAVA
-  JAVA binaries are becoming a universal executable format. This
-  option allows Java binaries and Java Applets to be handled invisibly
-  to the OS. As more and more Java programs become available, the use
-  for this will gradually increase. If you want to use this, read the
-  Java on Linux HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. In order to execute Java binaries,
-  you will also need to install the Java Developers Kit. If you disable
-  this option it will reduce your kernel by about one page. This is not
-  much and by itself does not warrant removing support. However its
-  removal is a good idea if you do not have the JDK installed. If you
-  don't know what to answer at this point then answer Y. You may answer
-  M for module support and later load the module when you install the
-  JDK or find a interesting Java program that you can't live without.
+  JAVA is an object oriented programming language developed by SUN;
+  JAVA programs are compiled into "JAVA bytecode" which can then be
+  interpreted by run time systems on many different operating systems.
+  These JAVA binaries are becoming a universal executable format. This
+  option allows you to run a Java binary just like any other Linux
+  program: by typing in its name. As more and more Java programs
+  become available, the use for this will gradually increase. You can
+  even execute HTML files containing JAVA applets (= JAVA binaries) if
+  those files start with the string "<!--applet-->". If you want to
+  use this, read Documentation/java.txt and the Java on Linux HOWTO,
+  available via ftp (user: anonymous) at
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. You will then need to install
+  the run time system contained in the Java Developers Kit (JDK) as
+  described in the HOWTO. If you disable this option it will reduce
+  your kernel by about 4kB. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  do not have the JDK installed. If you don't know what to answer at
+  this point then answer Y. You may answer M for module support and
+  later load the module when you install the JDK or find a interesting
+  Java program that you can't live without.
 
 Processor type
 CONFIG_M386
@@ -704,25 +725,23 @@
   available via ftp (user: anonymous) from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If unsure, say Y.
 
-ARP daemon support
+ARP daemon support (EXPERIMENTAL)
 CONFIG_ARPD
   Normally, the kernel maintains an internal cache which maps IP 
   addresses to hardware addresses on the local network, so that
-  Ethernet/Token Ring/ etc. frames are sent to the proper address
-  on the physical networking layer.  For small networks having
-  a few hundred directly connected hosts or less, keeping  this
-  address resolution cache (ARP) inside the kernel works well.
-  However, maintaining an internal ARP cache does not work well for
-  very large switched networks, and will use a lot of kernel memory
-  if TCP/IP connections are made to many machines on the network.
-  By enabling this option, the kernel's internal ARP cache will
-  never grow to more than 256 entries (the oldest entries are 
-  expired in a LIFO manner) and communication will be attempted
-  with an external ARP daemon, arpd, via the kerneld message
-  queue.  This code is still experimental.  If you do enable
-  arpd support, you should obtain a copy of arpd from
-  http://www.loran.com/~layes/arpd/index.html.  If unsure,
-  say N.  
+  Ethernet/Token Ring/ etc. frames are sent to the proper address on
+  the physical networking layer.  For small networks having a few
+  hundred directly connected hosts or less, keeping this address
+  resolution (ARP) cache inside the kernel works well.  However,
+  maintaining an internal ARP cache does not work well for very large
+  switched networks, and will use a lot of kernel memory if TCP/IP
+  connections are made to many machines on the network.  By enabling
+  this option, the kernel's internal ARP cache will never grow to more
+  than 256 entries (the oldest entries are expired in a LIFO manner)
+  and communication will be attempted with an external ARP daemon,
+  arpd.  This code is still experimental.  If you do enable arpd
+  support, you should obtain a copy of arpd from
+  http://www.loran.com/~layes/arpd/index.html.  If unsure, say N.
 
 TCP/IP networking
 CONFIG_INET
@@ -778,9 +797,9 @@
 CONFIG_IP_MULTICAST
   This is code for addressing several networked computers at once,
   enlarging your kernel by about 2 kB. If you are using gated, the
-  to update your computer's routing tables and are using RIP2 or OSPF
-  you will need to have this option compiled in. You also need
-  multicasting if you intend to participate in the MBONE, a high
+  daemon that updates your computer's routing tables, and are using
+  RIP2 or OSPF you will need to have this option compiled in. You also
+  need multicasting if you intend to participate in the MBONE, a high
   bandwidth network on top of the internet which carries audio and
   video broadcasts. More information about the MBONE is on the WWW at
   http://www.best.com/~prince/techinfo/mbone.html (to browse the WWW,
@@ -799,17 +818,19 @@
 
 IP: firewalling
 CONFIG_IP_FIREWALL
-  If you want to configure your Linux box as a firewall for a local 
+  If you want to configure your Linux box as a firewall for a local
   TCP/IP based network, say Y here. This will enlarge your kernel by
   about 2kB. You may need to read the FIREWALL-HOWTO, available via
-  ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also,
-  you will need the ipfwadm tool to allow selective blocking of internet
-  traffic based on type, origin and destination.  You need to enable IP
-  firewalling in order to be able to use IP masquerading (i.e. local 
-  computers can chat with an outside host, but that outside host is 
-  made to think that it is talking to the firewall box. Makes the local
-  network completely invisible) or to use the ip packet accounting to see
-  what is using all your network bandwidth.
+  ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will need the
+  ipfwadm tool to allow selective blocking of internet traffic based
+  on type, origin and destination.  You need to enable IP firewalling
+  in order to be able to use IP masquerading (i.e. local computers can
+  chat with an outside host, but that outside host is made to think
+  that it is talking to the firewall box. Makes the local network
+  completely invisible and avoids the need to allocate valid IP host
+  addresses for the machines on the local net) or to use the ip packet
+  accounting to see what is using all your network bandwidth.
 
 IP: accounting
 CONFIG_IP_ACCT
@@ -882,7 +903,7 @@
   syntax explained in Documentation/networking/alias.txt. If you want
   this, say Y. Most people don't need it and say N.
 
-IP: multicast routing(in progress)
+IP: multicast routing (EXPERIMENTAL)
 CONFIG_IP_MROUTE
   This is used if you want your machine to act as a router for IP
   packets that have several destination addresses. It is needed on the
@@ -1041,11 +1062,11 @@
   use a low speed TNC (a Terminal Node Controller acts as a kind of
   modem connecting your computer's serial port to your radio's
   microphone input and speaker output) supporting the KISS protocol or
-  the  various SCC cards that are supported by the Ottowa PI, the
+  the  various SCC cards that are supported by the Ottawa PI, the
   Gracilis Packetwin and the generic Z8530 driver. 
   At the moment there is no driver for the Baycom modem serial and parallel
   port hacks although one is being written (see the HAM-HOWTO). The other
-  baycom cards (SCC) are supported by the Z8530 driver.
+  Baycom cards (SCC) are supported by the Z8530 driver.
   In order to use AX.25, you need to get a set of all the software for 
   Linux amateur radio users as well as information about how to 
   configure an AX.25 port is contained in the HAM-HOWTO, available via
@@ -1083,19 +1104,21 @@
 
 Bridging (EXPERIMENTAL)
 CONFIG_BRIDGE
-  If you enable this, your Linux box will be able to act as an
+  If you say Y here, then your Linux box will be able to act as an
   ethernet bridge, which means that the different ethernet segments it
   is connected to will appear as one ethernet to the
   participants. Several such bridges can work together to create even
   larger networks of ethernets using the IEEE802.1 spanning tree
-  algorithm. As this is a standard Linux bridges will interwork properly
-  with other third party bridge products. Note that if your box acts as 
-  a bridge, it probably contains several ethernet devices, but the kernel
-  is not able to recognize more than one at boot time without help; for 
-  details read the Multiple-Ethernet-mini-HOWTO, available via ftp (user:
-  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The
-  Bridging code is still in test. If unsure, say N.
-  The bridge configuration tools are available via ftp from shadow.cabi.net.
+  algorithm. As this is a standard, Linux bridges will interwork
+  properly with other third party bridge products. In order to use
+  this, you'll need the bridge configuration tools available via ftp
+  (user: anonymous) from shadow.cabi.net. Note that if your box acts
+  as a bridge, it probably contains several ethernet devices, but the
+  kernel is not able to recognize more than one at boot time without
+  help; for details read the Multiple-Ethernet-mini-HOWTO, available
+  via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The Bridging code is
+  still in test. If unsure, say N.
 
 Kernel/User network link driver(ALPHA)
 CONFIG_NETLINK
@@ -1107,6 +1130,10 @@
   messages", below. Say Y if you want to experiment with it; this is
   ALPHA code, which means that it need not be completely stable; it
   has nothing to do with the computer architecture of the same name.
+  You need to include this if you want to use arpd, a daemon that
+  helps keep the internal ARP cache (a mapping between IP addresses
+  and hardware addresses on the local network) small. If unsure, say
+  N.
 
 Routing messages
 CONFIG_RTNETLINK
@@ -1375,9 +1402,14 @@
  
 allow DISCONNECT
 CONFIG_SCSI_NCR53C7xx_DISCONNECT
-###
-### Dunno
-###
+  This enables the disconnect/reconnect feature of the NCR SCSI controller.
+  When this is enabled, a slow SCSI device will not lock the SCSI bus
+  while processing a request, allowing simultaneous use of e.g. a SCSI
+  hard disk and SCSI tape or CD-ROM drive, and providing much better 
+  performance when using slow and fast SCSI devices at the same time. Some 
+  devices, however, do not operate properly with this option enabled, and 
+  will cause your SCSI system to hang, which might cause a system crash. 
+  The safe answer therefore is to say N.
 
 Always IN2000 SCSI support
 CONFIG_SCSI_IN2000
@@ -1523,22 +1555,33 @@
   read Olaf Kirch's excellent book "Network Administrator's Guide", to
   be found in sunsite.unc.edu:/pub/Linux/docs/LDP.  If unsure, say Y.
 
+CONFIG_NET_ETHERNET
+  Ethernet is the most common protocol used on Local Area Networks
+  (LANs) in universities or companies. 10-base-2 and 10-base-T and
+  100-base-<whatever> are common types of ethernet. If your Linux
+  machine will be connected to an Ethernet and you have an ethernet
+  network card installed in your computer, say Y here and read the
+  Ethernet-HOWTO, available via ftp (user: anonymous) from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that the answer to this
+  question won't directly affect the kernel: saying N will just cause
+  this configure script to skip all the questions about Ethernet
+  network cards. If unsure, say N.
+
 Dummy net driver support
 CONFIG_DUMMY
-  This is essentially a bit-bucket device (i.e. traffic you send to 
+  This is essentially a bit-bucket device (i.e. traffic you send to
   this device is consigned into oblivion) with a configurable IP
-  address different from the usual 127.0.0.1. It is most commonly used
-  in order to make your currently inactive SLIP address seem like a
-  real address for local programs. If you use SLIP or PPP, you might
-  want to enable it. Read about it in the Network Administrator's
-  Guide, available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/docs/LDP. Since this thing comes often
-  handy, the default is Y. It won't enlarge your kernel either. What a
-  deal.  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. If you want to use
-  more than one dummy device at a time, you need to compile it as a
-  module. 
+  address. It is most commonly used in order to make your currently
+  inactive SLIP address seem like a real address for local
+  programs. If you use SLIP or PPP, you might want to enable it. Read
+  about it in the Network Administrator's Guide, available via ftp
+  (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/LDP. Since
+  this thing comes often handy, the default is Y. It won't enlarge
+  your kernel either. What a deal.  If you want to compile this as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt. If you want to use more than one dummy
+  device at a time, you need to compile it as a module.
   
 SLIP (serial line) support
 CONFIG_SLIP
@@ -1588,17 +1631,23 @@
 
 Six bit SLIP encapsulation
 CONFIG_SLIP_MODE_SLIP6
-  Just occasionally you may need to run IP over hostile serial networks that
-  don't pass all control characters or are only seven bit. This adds an
-  extra mode you can use with SLIP "slip6" which contains only the normal
-  ascii symbols. Its good enough, for example, to run IP over the async
-  ports of a Camtec JNT Pad.
+  Just occasionally you may need to run IP over hostile serial
+  networks that don't pass all control characters or are only seven
+  bit. Saying Y here adds an extra mode you can use with SLIP:
+  "slip6". In this mode, SLIP will only send normal ascii symbols over
+  the serial device. Naturally, this has to be supported at the other
+  end of the link as well. It's good enough, for example, to run IP
+  over the async ports of a Camtec JNT Pad. If unsure, say N.
 
 Radio network interfaces
 CONFIG_NET_RADIO
-  Radio based interfaces for Linux. Both amateur radio (AX.25) and other
-  systems. In addition shadow.cabi.net carries user mode drivers for the
-  Scarab devices. These need no kernel support.
+  Radio based interfaces for Linux. This includes amateur radio
+  (AX.25), support for wireless ethernet and other systems. Note that
+  the answer to this question won't directly affect the kernel:
+  saying N will just cause this configure script to skip all the
+  questions about radio interfaces. Some user-level drivers for scarab
+  devices which don't require special kernel support are available via
+  ftp (user: anonymous) from shadow.cabi.net. If unsure, say N.
 
 PPP (point-to-point) support
 CONFIG_PPP
@@ -1654,17 +1703,20 @@
 WIC (Radio IP bridge)
 CONFIG_WIC
   Support for the WIC parallel port radio bridge. You'll probably want
-  to say N.
+  to say N.  If you want to compile this driver as a module though ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read Documentation/modules.txt.
 
 Z8530 SCC kiss emulation driver for AX.25
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
-  and communicate with other computers.  If you want to use this, read
-  Documentation/networking/z8530drv.txt and the HAM-HOWTO, available
-  via ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt.
+  in order to communicate with other computers.  If you want to use
+  this, read Documentation/networking/z8530drv.txt and the HAM-HOWTO,
+  available via ftp (user: anonymous) at
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt.
 
 BAYCOM ser12 and par96 kiss emulation driver for AX.25
 CONFIG_BAYCOM
@@ -1688,11 +1740,11 @@
   on bidirectional parallel ports only, which can transmit 8 bits at a
   time (you can find the wiring of these cables in
   drivers/net/README?.plip). The cables can be up to 15m long. This
-  works also if one of the machines runs DOS and has some PLIP
+  works also if one of the machines runs DOS/Windows and has some PLIP
   software installed, e.g. the Crynwr PLIP packet driver
   (http://sunsite.cnam.fr/packages/Telnet/PC/msdos/misc/pktdrvr.txt)
-  and NCSA's telnet.  If you want to use this, say Y and read the PLIP
-  mini-HOWTO, available via ftp (user: anonymous) in
+  and winsock or NCSA's telnet.  If you want to use this, say Y and
+  read the PLIP mini-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini as well as the
   NET-2-HOWTO in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the
   PLIP protocol was changed and this PLIP driver won't work together
@@ -1776,10 +1828,6 @@
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
-Ethernet (10 or 100Mbit)
-CONFIG_NET_ETHERNET
-  Say yes if you want to select support for ethernet cards.
-
 Sun LANCE Ethernet support
 CONFIG_SUN_LANCE
   This is support for lance ethernet cards on Sun workstations such as
@@ -2577,15 +2625,7 @@
   use it. Probably this is only useful for multi user systems. If
   unsure, say N.
 
-Mandatory lock support
-CONFIG_LOCK_MANDATORY
-  Mandatory locking is used by some System 5 style database applications.
-  To use this option safely you must have newer NFS daemons, new samba,
-  new netatalk, new mars-nwe and other file servers. At the time of 
-  writing none of these are available. Unless you need this feature say
-  N.
-  
-Standard (minix) fs support
+Minix fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about
   OS's. The minix filesystem (= method to organize files on a harddisk
@@ -2916,23 +2956,23 @@
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt.
 
-Amiga FFS filesystem support (read only)
+Amiga FFS filesystem support (EXPERIMENTAL)
 CONFIG_AFFS_FS
   The Fast File System (FFS) is the common filesystem used on harddisks
   by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also
   possible to mount diskfiles used by the Un*X Amiga Emulator by Bernd
   Schmidt (http://www-users.informatik.rwth-aachen.de/~crux/uae.html)
   If you want to do the latter, you will also need the loop device
-  support. Because it's in an early development state, the AFFS is 
-  read only. Say Y if you want to be able to read files from an Amiga
-  FFS partition of your harddrive. Amiga floppies however cannot be
-  read with this driver due to an incompatibility of the floppy
-  controller used in an Amiga and the standard floppy controller in
-  PCs and workstations. Read Documentation/filesystems/affs.txt. This
-  filesystem is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you
-  want). If you want to compile it as a module, say M here and read
-  Documentation/modules.txt. If unsure, say N.
+  support. Say Y if you want to be able to read and write files from
+  and to an Amiga FFS partition of your harddrive. Amiga floppies
+  however cannot be read with this driver due to an incompatibility of
+  the floppy controller used in an Amiga and the standard floppy
+  controller in PCs and workstations. Read
+  Documentation/filesystems/affs.txt. This filesystem is also available
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+  If unsure, say N.
 
 Standard/generic serial support
 CONFIG_SERIAL
@@ -3216,11 +3256,14 @@
   result in rebooting the machine. This could be useful for a
   networked machine that needs to come back online as fast as possible
   after a lock-up. There's a watchdog implementation entirely in
-  software (which can sometimes fail to reboot the machine) and a driver
-  for hardware watchdog boards, which are more robust and can also
-  keep track of the temperature inside your computer. For details,
-  read Documentation/watchdog.txt in the kernel source. If unsure, say
-  N.
+  software (which can sometimes fail to reboot the machine) and a
+  driver for hardware watchdog boards, which are more robust and can
+  also keep track of the temperature inside your computer. For
+  details, read Documentation/watchdog.txt in the kernel source. If
+  unsure, say N. This driver is also available as a module ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
 
 Disable watchdog shutdown on close
 CONFIG_WATCHDOG_NOWAYOUT
@@ -3257,7 +3300,10 @@
 CONFIG_SOFT_WATCHDOG
   A software monitoring watchdog. This will fail to reboot your system
   from some situations that the hardware watchdog will recover
-  from. Equally it's a lot cheaper to install.
+  from. Equally it's a lot cheaper to install. This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
 
 Enhanced Real Time Clock Support
 CONFIG_RTC
@@ -3317,20 +3363,30 @@
 
 ISDN subsystem
 CONFIG_ISDN
-  This allows you to use an ISDN-card for networking connections and
-  as dialin/out device. The isdn-tty's have a built in AT-compatible
-  modem emulator. Network devices support autodial, channel-bundling,
+  ISDN ("Integrated Services Digital Networks", called RNIS in
+  France) is a special type of fully digital telephone line; it's
+  mostly used to connect to your Internet service provider (with SLIP
+  or PPP). The main advantage is that the speed is higher than
+  ordinary modem/telephone connections. It only works if your computer
+  is equipped with an ISDN card and both you and your service provider
+  purchased an ISDN line from your phone company.  For details, read
+  http://alumni.caltech.edu/~dank/isdn/ on the WWW. (To browse the
+  WWW, you need to have access to a machine on the Internet that has
+  one of the programs lynx, netscape or Mosaic.)  This driver allows
+  you to use an ISDN-card for networking connections and as dialin/out
+  device. The isdn-tty's have a built in AT-compatible modem
+  emulator. Network devices support autodial, channel-bundling,
   callback and caller-authentication without having a daemon
   running. A reduced T.70 protocol is supported with tty's suitable
-  for German BTX. Currently cards by Teles and compatibles and ICN are
-  supported. On D-Channel, the protocols EDSS1 and 1TR6 are
+  for German BTX. On D-Channel, the protocols EDSS1 and 1TR6 are
   supported. See Documentation/isdn/README for more information.
 
 Support synchronous PPP
 CONFIG_ISDN_PPP
   This enables synchronous PPP via ISDN. This protocol is used by
-  Cisco or Sun for example. You will need a special version of pppd
-  (called ipppd) for using this feature. See
+  Cisco or Sun for example. So you want say Y here if the other end of
+  your ISDN connection supports it. You will need a special version of
+  pppd (called ipppd) for using this feature. See
   Documentation/isdn/README.syncppp and Documentation/isdn/syncPPP.FAQ
   for more information.
 
@@ -3344,11 +3400,21 @@
 CONFIG_ISDN_PPP_VJ
   This enables Van Jacobson header compression for synchronous PPP.
 
-ICN B1 and B2 support
+Support audio via ISDN
+CONFIG_ISDN_AUDIO
+  With this option enabled, the modem-emulator supports a subset
+  of the EIA Class 8 Voice commands. Using a getty with voice-support
+  (mgetty+sendfax by gert@greenie.muc.de with an extension, available
+  with the ISDN utily package for example), you will be able
+  to use your Linux box as an ISDN-answering machine. Of course, this
+  must be supported by the lowlevel driver also. Currently, the Teles
+  driver is the only voice-supporting one.
+
+ICN 2B and 4B support
 CONFIG_ISDN_DRV_ICN
   This enables support for two kinds of ISDN-cards made by a German
-  company called ICN. 1B is the standard version for a single ISDN
-  line with two B-channels, 2B supports two ISDN lines. For running
+  company called ICN. 2B is the standard version for a single ISDN
+  line with two B-channels, 4B supports two ISDN lines. For running
   this card, additional firmware is necessary, which has to be
   downloaded into the card using a utility which is distributed
   separately.  See Documentation/isdn/README and README.icn for more
@@ -3452,4 +3518,8 @@
 # LocalWords:  Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo ufs
 # LocalWords:  hitchcock Crynwr cnam pktdrvr NCSA's CyDROM CyCDROM FreeBSD NeXT
 # LocalWords:  NeXTstep disklabel disklabels SMD FFS tm AmigaOS diskfiles Un
-# LocalWords:  Bernd informatik rwth aachen uae affs
+# LocalWords:  Bernd informatik rwth aachen uae affs multihosting bytecode java
+# LocalWords:  applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab
+# LocalWords:  winsock RNIS caltech OSPF honour Honouring Mbit Localtalk Ottowa
+# LocalWords:  localtalk download Packetwin Baycom baycom interwork ascii JNT
+# LocalWords:  Camtec
diff -u --recursive --new-file pre2.0.5/linux/Documentation/cdrom/aztcd linux/Documentation/cdrom/aztcd
--- pre2.0.5/linux/Documentation/cdrom/aztcd	Mon Apr 29 18:05:15 1996
+++ linux/Documentation/cdrom/aztcd	Sun May 19 15:17:57 1996
@@ -1,10 +1,10 @@
-$Id: README.aztcd,v 2.30 1996/04/26 05:32:23 root Exp root $
+$Id: README.aztcd,v 2.50 1996/05/16 18:31:22 root Exp root $
           Readme-File /usr/src/Documentation/cdrom/aztcd
            			for 
 	     AZTECH CD-ROM CDA268-01A, ORCHID CD-3110,
       OKANO/WEARNES CDD110, CONRAD TXC, CyCDROM CR520, CR540
                            CD-ROM Drives 
-                       Version 2.3 and newer
+                       Version 2.5 and newer
                    (for other drives see 6.-8.)
 
 NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE
diff -u --recursive --new-file pre2.0.5/linux/Documentation/cdrom/cdrom-standard.tex linux/Documentation/cdrom/cdrom-standard.tex
--- pre2.0.5/linux/Documentation/cdrom/cdrom-standard.tex	Fri May 17 15:32:09 1996
+++ linux/Documentation/cdrom/cdrom-standard.tex	Sat May 18 11:15:10 1996
@@ -77,7 +77,7 @@
 the drive door has closed without having a disk inside; without any
 new software layer or any structures which are not already present in
 \cdromh.  This `other' group of \linux\ \cdrom\ driver writers
-explicitely does {\em not\/} support the idea to define an additional
+explicitly does {\em not\/} support the idea to define an additional
 software layer between driver and user program.
 
 The following text reflects the opinion of the first mentioned \linux\ 
diff -u --recursive --new-file pre2.0.5/linux/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd
--- pre2.0.5/linux/Documentation/cdrom/ide-cd	Sun May 12 22:54:22 1996
+++ linux/Documentation/cdrom/ide-cd	Sun May 19 15:16:34 1996
@@ -1,5 +1,5 @@
 IDE-CD driver documentation
-10 May 1996
+19 May 1996
 scott snyder  <snyder@fnald0.fnal.gov>
 
 1. Introduction
@@ -45,7 +45,7 @@
 ---------------
 
 0. The ide-cd relies on the ide disk driver.  See
-   drivers/block/README.ide for up-to-date information on the ide
+   Documentation/ide.txt for up-to-date information on the ide
    driver.
 
 1. Make sure that the ide and ide-cd drivers are compiled into the
@@ -61,7 +61,7 @@
 
    Depending on what type of IDE interface you have, you may need to
    specify additional configuration options.  See
-   drivers/block/README.ide.
+   Documentation/ide.txt.
 
 2. You should also ensure that the iso9660 filesystem is either
    compiled into the kernel or available as a loadable module.  You
@@ -81,7 +81,7 @@
    on the primary IDE interface are called `hda' and `hdb',
    respectively.  The drives on the secondary interface are called
    `hdc' and `hdd'.  (Interfaces at other locations get other letters
-   in the third position; see drivers/block/README.ide.)
+   in the third position; see Documentation/ide.txt.)
 
    If you want your cdrom drive to be found automatically by the
    driver, you should make sure your IDE interface uses either the
@@ -90,7 +90,7 @@
    be jumpered as `master'.  (If for some reason you cannot configure
    your system in this manner, you can probably still use the driver.
    You may have to pass extra configuration information to the kernel
-   when you boot, however.  See drivers/block/README.ide for more
+   when you boot, however.  See Documentation/ide.txt for more
    information.)
 
 4. Boot the system.  If the drive is recognized, you should see a
@@ -194,7 +194,7 @@
 This section discusses some common problems encountered when trying to
 use the driver, and some possible solutions.  Note that if you are
 experiencing problems, you should probably also review
-drivers/block/README.ide for current information about the underlying
+Documentation/ide.txt for current information about the underlying
 IDE support code.  Some of these items apply only to earlier versions
 of the driver, but are mentioned here for completeness.
 
@@ -204,7 +204,7 @@
 a. Drive is not detected during booting.
 
    - Review the configuration instructions above and in
-     drivers/block/README.ide, and check how your hardware is
+     Documentation/ide.txt, and check how your hardware is
      configured.
 
    - If your drive is the only device on an IDE interface, it should
@@ -212,7 +212,7 @@
 
    - If your IDE interface is not at the standard addresses of 0x170
      or 0x1f0, you'll need to explicitly inform the driver using a
-     lilo option.  See drivers/block/README.ide.  (This feature was
+     lilo option.  See Documentation/ide.txt.  (This feature was
      added around kernel version 1.3.30.)
 
    - If the autoprobing is not finding your drive, you can tell the
@@ -238,7 +238,7 @@
      Support for some interfaces needing extra initialization is
      provided in later 1.3.x kernels.  You may need to turn on
      additional kernel configuration options to get them to work;
-     see drivers/block/README.ide.
+     see Documentation/ide.txt.
 
      Even if support is not available for your interface, you may be
      able to get it to work with the following procedure.  First boot
@@ -283,7 +283,7 @@
     be worked around by specifying the `serialize' option when
     booting.  Recent kernels should be able to detect the need for
     this automatically in most cases, but the detection is not
-    foolproof.  See drivers/block/README.ide for more information
+    foolproof.  See Documentation/ide.txt for more information
     about the `serialize' option and the CMD640B.
 
   - Note that many MS-DOS cdrom drivers will work with such buggy
@@ -319,7 +319,7 @@
 
     Some early Slackware releases had these defined incorrectly.  If
     these are wrong, you can remake them by running the script
-    drivers/block/MAKEDEV.ide.  (You may have to make it executable
+    scripts/MAKEDEV.ide.  (You may have to make it executable
     with chmod first.)
 
     If you have a /dev/cdrom symbolic link, check that it is pointing
diff -u --recursive --new-file pre2.0.5/linux/Documentation/filesystems/affs.txt linux/Documentation/filesystems/affs.txt
--- pre2.0.5/linux/Documentation/filesystems/affs.txt	Sat May 11 10:42:04 1996
+++ linux/Documentation/filesystems/affs.txt	Sun May 19 15:22:19 1996
@@ -6,14 +6,12 @@
 
 DOS\0		The old or original filesystem, not really suited for
 		hard disks and normally not used on them, either.
-		Not supported.
 
 DOS\1		The original Fast File System. Supported.
 
 DOS\2		The old "international" filesystem. International means that
 		a bug has been fixed so that accented ("international") letters
 		in file names are case-insensitive, as they ought to be.
-		Not supported.
 
 DOS\3		The "international" Fast File System.  Supported.
 
@@ -29,7 +27,10 @@
 speed up almost everything with the expense of wasted disk space. The speed
 gain above 4K seems not really worth the price, so you don't lose too
 much here, either.
-  
+
+The muFS (multi user File System) equivalents of the above file systems
+are supported, too.
+
 Mount options for the AFFS
 ==========================
 
@@ -68,6 +69,9 @@
 quiet		The file system will not return an error for disallowed
 		mode changes.
 
+verbose		The volume name, file system type and block size will
+		be written to the syslog.
+
 Handling of the Users/Groups and protection flags
 =================================================
 
@@ -104,22 +108,47 @@
     
 Newly created files and directories will get the user and group id
 of the current user and a mode according to the umask.
-Linux can read, but not write, Amiga FFS partitions.
-
-Mount options are
-    size	has the size in 512 byte blocks of the mounted medium. 
-
-Case is significant in filename matching, different to real AFFS.
-
 
 Command line example
+====================
     mount  Archive/Amiga/Workbench3.1.adf /mnt -t affs -o loop,size=1760
     mount  /dev/sda3 /Amiga -t affs
 
 /etc/fstab example
     /dev/sdb5	/d/f    affs    ro
 
-This file system will probably be writeable in future releases.
+Bugs, Restrictions, Caveats
+===========================
+
+Quite a few things may not work as advertised. Not everything is
+tested, though several hundred MB have been read and written using
+this fs.
+
+Filenames are truncated to 30 characters without warning.
+
+Currently there are no checks against invalid characters (':')
+in filenames.
+
+Case is ignored by the affs in filename matching, but Linux shells
+do care about the case. Example (with /mnt being an affs mounted fs):
+    rm /mnt/WRONGCASE
+will remove /mnt/wrongcase, but
+    rm /mnt/WR*
+will not since the names are matched by the shell.
+
+The block allocation is designed for hard disk partitions. If more
+than 1 process writes to a (small) diskette, the blocks are allocated
+in an ugly way (but the real AFFS doesn't do much better). This
+is also true when space gets tight.
+
+The bitmap valid flag in the root block may not be accurate when the
+system crashes while an affs partition is mounted. There's currently
+no way to fix this without an Amiga (disk validator) or manually
+(who would do this?). Maybe later.
+
+A fsck.affs and mkfs.affs will probably be available in the future.
+Until then, you should do
+    ln -s /bin/true /etc/fs/mkfs.affs
 
 It's not possible to read floppy disks with a normal PC or workstation
 due to an incompatibility to the Amiga floppy controller.
diff -u --recursive --new-file pre2.0.5/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE
--- pre2.0.5/linux/Documentation/isdn/INTERFACE	Tue May  7 16:22:15 1996
+++ linux/Documentation/isdn/INTERFACE	Sun May 19 15:29:28 1996
@@ -1,3 +1,4 @@
+$Id: INTERFACE,v 1.2 1996/05/18 15:58:53 fritz Exp $
 
 Description of the Interface between Linklevel and Hardwarelevel
   of isdn4linux:
@@ -12,9 +13,29 @@
   the fields. All further communication is done via callbacks using
   the function-pointers defined in isdn_if.
 
-  ATTENTION, CHANGES since version 0.6 are marked with   "***CHANGE0.6"!
-  ATTENTION, CHANGES since version 0.7 are marked with   "***CHANGE0.7"!
-  ATTENTION, CHANGES since version 0.71 are marked with  "***CHANGE0.7.1"!
+  Changes/Version numbering:
+
+  During development of the ISDN subsystem, several changes have been
+  made to the interface. Before it went into kernel, the package
+  had a unique version number. The last version, distributed separately
+  was 0.7.4. When the subsystem went into kernel, every functional unit
+  got a separate version number. These numbers are shown at initialization,
+  separated by slashes:
+
+     c.c/t.t/n.n/p.p/a.a
+
+  where
+
+   c.c is the revision of the common code.
+   t.t is the revision of the tty related code.
+   n.n is the revision of the network related code.
+   p.p is the revision of the ppp related code.
+   a.a is the revision of the audio related code.
+
+  Changes in this document are marked with '***CHANGEx' where x representing
+  the version number. If that number starts with 0, it refers to the old,
+  separately distributed package. If it starts with one of the letters
+  above, it refers to the revision of the corresponding module. 
 
 1. Description of the fields of isdn_if:
 
@@ -53,6 +74,11 @@
 
   void (*rcvcallb)(int, int, u_char*, int);
 
+    ***CHANGEc1.14: Declared obsolete. Do NOT use this field/function
+                    anymore, since it will be removed when all current
+                    LL drivers have been changed accordingly. Use
+                    rcvcallb_skb instead.
+
     This field will be set by LL. The HL-driver delivers received data-
     packets by calling this function.
 
@@ -114,6 +140,11 @@
 
   int (*writebuf)(int, int, u_char*, int, int);
 
+    ***CHANGEc1.14: Declared obsolete. Do NOT use this field/function
+                    anymore, since it will be removed when all current
+                    LL drivers have been changed accordingly. Set this
+                    field to NULL and use writebuf_skb instead.
+
     This field has to be preset by the HL-driver. The given function will
     be called by the LL for delivering data to be send via B-Channel.
 
@@ -149,11 +180,7 @@
       Length of data accepted on success, else error-code (-EINVAL on
       oversized packets etc.)
 
-NOTE on writebuf and writebuf_skb:
-    The HL-driver may initialize one of the fields to NULL, in which case
-    the LL will call the non-NULL function only.
-
-  int (*writecmd)(u_char*, int, int);
+  int (*writecmd)(u_char*, int, int, int, int);
 
     This field has to be preset by the HL-driver. The given function will be
     called to perform write-requests on /dev/isdnctrl (i.e. sending commands
@@ -169,11 +196,15 @@
                         memcpy, may NOT use schedule())
                     1 = call from user-space. (HL-driver must use
                         memcpy_fromfs, use of schedule() allowed)
+      int     driver-Id.
+      int     channel-number locally to the HL-driver. (starts with 0)
+
+***CHANGEc1.14: The driver-Id and channel-number are new since this revision.
 
     Returnvalue:
       Length of data accepted on success, else error-code (-EINVAL etc.)
 
-  int (*readstat)(u_char*, int, int);
+  int (*readstat)(u_char*, int, int, int, int);
 
     This field has to be preset by the HL-driver. The given function will be
     called to perform read-requests on /dev/isdnctrl (i.e. reading replies
@@ -189,6 +220,10 @@
                         memcpy, may NOT use schedule())
                     1 = call from user-space. (HL-driver must use
                         memcpy_fromfs, use of schedule() allowed)
+      int     driver-Id.
+      int     channel-number locally to the HL-driver. (starts with 0)
+
+***CHANGEc1.14: The driver-Id and channel-number are new since this revision.
 
     Returnvalue:
       Length of data on success, else error-code (-EINVAL etc.)
diff -u --recursive --new-file pre2.0.5/linux/Documentation/isdn/README linux/Documentation/isdn/README
--- pre2.0.5/linux/Documentation/isdn/README	Tue May  7 16:22:15 1996
+++ linux/Documentation/isdn/README	Sun May 19 15:29:28 1996
@@ -119,6 +119,8 @@
                AT&X0	BTX-mode off (default)
 	       AT&X1    BTX-mode on. (S13.1=1, S14=0, S16=7, S18=7, S19=0)
 
+           For voice-mode commands refer to README.audio
+
 	   1.3.2 Escape sequence:
                During a connection, the emulation reacts just like
                a normal modem to the escape sequence <DELAY>+++<DELAY>.
@@ -168,18 +170,34 @@
                                       1 = Direct tty-send.
                             Bit 1:    0 = T.70 protocol (Only for BTX!) off
                                       1 = T.70 protocol (Only for BTX!) on
-	     14   0         Layer-2 protocol: (with the ICN-driver 
-                                                currently always 0)
+	     14   0         Layer-2 protocol:
 				      0 = X75/LAPB with I-frames
 				      1 = X75/LAPB with UI-frames
                                       2 = X75/LAPB with BUI-frames
                                       3 = HDLC
+                                      4 = Transparent (audio)
              15   0         Layer-3 protocol: (at the moment always 0)
                                       0 = transparent
 	     16   250       Send-Packet-size/16
              17   8         Window-size for Teles-driver (not yet implemented)
-             18   7         Service-Octet-1
+             18   4         Bit coded register, Service-Octet-1 to accept,
+                            or to be used on dialout:
+                            Bit 0:    Service 1 (audio) when set.
+                            Bit 1:    Service 5 (BTX) when set.
+                            Bit 2:    Service 7 (data) when set.
+                            Note: It is possible to set more than one
+                                  bit. In this case, on incoming calls
+                                  the selected services are accepted,
+                                  and if the service is "audio", the
+                                  Layer-2-protocol is automatically
+                                  changed to 4 regardless of the setting
+                                  of register 14. On outgoing calls,
+                                  the most significant 1-bit is choosen to
+                                  select the outgoing service octet.
              19   0         Service-Octet-2
+             20   0         Bit coded register (readonly)
+                            Service-Octet-1 of last call.
+                            Bit mapping is the same like register 18
 
   Last but not least a (at the moment fairly primitive) device to request
   the line-status (/dev/isdninfo) is made available.
@@ -272,9 +290,8 @@
        Due to limited hardware-capabilities, there is no way to check the
        existence of a card. Therefore you need to be sure your card's setup
        is correct. Also there are bugs in the printed manual of some newer
-       16.3 cards. The manual tells the port has to be 0x180. THIS IS WRONG!!
-       0xd80 is the correct value! Have a look to the kernel-syslog. With
-       most of the cards, you should see a line "HSCX version A:5 B:5" there.
+       16.3 cards. Have a look to the kernel-syslog. With most of the cards,
+       you should see a line "HSCX version A:5 B:5" there.
        
      3.1.2 ICN driver.
 
@@ -292,9 +309,10 @@
        When using the ICN double card, you MUST define TWO idstrings.
        idstring must start with a character!
 
-       The ICN driver supports only one card at the moment. If you like to
-       use more than one card, build the modularized version, loading it
-       more than one time, each module driving a single card.
+       If you like to use more than one card, you can use the program
+       "icnctrl" from the utility-package to configure additional cards.
+       You need to configure shared memory only once, since the icn-driver
+       maps all cards into the same address-space.
 
        Using the "icnctrl"-utility, portbase and shared memory can also be
        changed during runtime.
@@ -335,12 +353,8 @@
        When using the ICN double card, you MUST define TWO idstrings.
        idstring must start with a character!
 
-       The ICN driver supports only one card at the moment. If you like to
-       use more than one card, build the modularized version, loading it
-       more than one time, each module driving a single card.
-
-       Using the "icnctrl"-utility, portbase and shared memory can also be
-       changed during runtime.
+       Using the "icnctrl"-utility, the same features apply to the modularized
+       version like to the kernel-builtin one.
 
        The D-channel protocol is configured by loading different firmware
        into the card's memory using the "icnctrl"-utility.
@@ -365,12 +379,15 @@
      For Euro-ISDN:
        icnctrl [-d IDstring] load download/loadpg.bin download/pc_eu_ca.bin
 
-     When using the ICN-2B, the protocol-software for the second half of
+     When using the ICN-4B, the protocol-software for the second half of
      the card must be appended to the command line.
 
-     -> The two LEDs at the back cover of the card (ICN-2B: 4 LEDs) must be
+     -> The two LEDs at the back cover of the card (ICN-4B: 4 LEDs) must be
         blinking intermittently now. If a connection is up, the corresponding
         led is lit continuously.
+
+     For loading pcbit-firmware, refer to Documentation/isdn/README.pcbit
+     and the pcbit manpage, included in the utility-package.
 
    b) If you only intend to use ttys, you are nearly ready now.
 
diff -u --recursive --new-file pre2.0.5/linux/Documentation/isdn/README.icn linux/Documentation/isdn/README.icn
--- pre2.0.5/linux/Documentation/isdn/README.icn	Fri Apr 12 15:51:44 1996
+++ linux/Documentation/isdn/README.icn	Sun May 19 15:29:28 1996
@@ -1,3 +1,5 @@
+$Id: README.icn,v 1.3 1996/05/19 00:10:37 fritz Exp $
+
 You can get the ICN-ISDN-card from:
 
 Thinking Objects Software GmbH
@@ -16,7 +18,8 @@
   2. A memory window with 16KB-256KB size, which can be setup in 16k steps
      over the whole range of 16MB. Isdn4linux only uses a 16k window.
      The base address of the window can be configured when loading
-     the lowlevel-module (see README).
+     the lowlevel-module (see README). If using more than one card,
+     all cards are mapped to the same window and activated as needed.
 
 Setting up the IO-address dipswitches for the ICN-ISDN-card:
 
diff -u --recursive --new-file pre2.0.5/linux/Documentation/isdn/README.syncppp linux/Documentation/isdn/README.syncppp
--- pre2.0.5/linux/Documentation/isdn/README.syncppp	Sun Apr 21 19:21:59 1996
+++ linux/Documentation/isdn/README.syncppp	Sun May 19 15:29:28 1996
@@ -12,7 +12,7 @@
 to answer the appropriate question when doing a "make config"
 Don't forget to load the slhc.o
 module before the isdn.o module, if VJ-compression support
-is not compiled into your kernel. (e.g if you have PPP or
+is not compiled into your kernel. (e.g if you have no PPP or
 CSLIP in the kernel)
 
 Using isdn4linux with sync PPP:
@@ -20,11 +20,13 @@
 Sync PPP is just another encapsulation for isdn4linux. The
 name to enable sync PPP encapsulation is 'syncppp' .. e.g:
 
-  isdn/isdnctrl encap ippp0 syncppp
+  /sbin/isdnctrl encap ippp0 syncppp
 
 The name of the interface is here 'ippp0'. You need 
 one interface with the name 'ippp0' to saturate the
 ipppd, which checks the ppp version via this interface.
+Currently, all devices must have the name ipppX where
+'X' is a decimal value.
 
 To set up a PPP connection you need the ipppd .. You must start 
 the ipppd once after installing the modules. The ipppd 
@@ -46,7 +48,8 @@
 To use the MPPP stuff, you must configure a slave device
 with isdn4linux. Now call the ipppd with the '+mp' option.
 To increase the number of links, you must use the
-'addlink' option of the isdnctrl tool.
+'addlink' option of the isdnctrl tool. (rc.isdn.syncppp.MPPP is
+an example script)
 
 enjoy it,
     michael
diff -u --recursive --new-file pre2.0.5/linux/Documentation/isdn/syncPPP.FAQ linux/Documentation/isdn/syncPPP.FAQ
--- pre2.0.5/linux/Documentation/isdn/syncPPP.FAQ	Wed Apr 24 17:00:33 1996
+++ linux/Documentation/isdn/syncPPP.FAQ	Sun May 19 15:29:28 1996
@@ -1,32 +1,50 @@
 simple isdn4linux PPP FAQ .. to be continued .. not 'debugged' 
+-------------------------------------------------------------------
 
-Q: pppd,ipppd, syncPPP , asyncPPP .. what is that ?
-  what should I use?
-A: The pppd is for asynchronous PPP .. asynchronous means
-here, the framing is character based. (e.g when
-using ttyI* or tty* devices)
-
-The ipppd handles PPP packets coming in HDLC
-frames (bit based protocol) ... The PPP driver
-in isdn4linux pushes all IP packets direct
-to the network layer and all PPP protocol
-frames to the /dev/ippp* device. 
-So, the ipppd is a simple external network
-protocol handler.
-
-If you login into a remote machine using the
-/dev/ttyI* devices and then enable PPP on the
-remote terminal server -> use the 'old' pppd
-
-If your remote side immediately starts to send
-frames ... you probably connect to a 
-syncPPP machine .. use the network device part
-of isdn4linux with the 'syncppp' encapsulation
-and make sure, that the ipppd is running and 
-connected to at least one /dev/ippp*. Check the 
-isdn4linux manual on how to configure a network device.
+Q01: what's pppd,ipppd, syncPPP , asyncPPP ??
+Q02: error message "this systems lacks PPP support"
+Q03: strange information using 'ifconfig'
+Q04: MPPP?? What's that and how can I use it ...
+Q05: I tried MPPP but it doesn't work 
+Q06: can I use asynchronous PPP encapuslation with network devices
+Q07: A SunISDN machine can't connect to my i4l system
+Q08: I wanna talk to several machines, which need different configs
+Q09: Starting the ipppd, I get only error messages from i4l
+Q10: I wanna use dynamic IP address assignment 
+Q11: I can't connect. How can I check where the problem is.
+Q12: How can I reduce login delay? 
+
+-------------------------------------------------------------------
+
+Q01: pppd,ipppd, syncPPP , asyncPPP .. what is that ?
+   what should I use?
+A: The pppd is for asynchronous PPP .. asynchron means
+   here, the framing is character based. (e.g when
+   using ttyI* or tty* devices)
+
+   The ipppd handles PPP packets coming in HDLC
+   frames (bit based protocol) ... The PPP driver
+   in isdn4linux pushes all IP packets direct
+   to the network layer and all PPP protocol
+   frames to the /dev/ippp* device. 
+   So, the ipppd is a simple externel network
+   protocol handler.
+
+   If you login into a remote machine using the
+   /dev/ttyI* devices and then enable PPP on the
+   remote terminal server -> use the 'old' pppd
+
+   If your remote side immediately starts to send
+   frames ... you probably connect to a 
+   syncPPP machine .. use the network device part
+   of isdn4linux with the 'syncppp' encapsulation
+   and make sure, that the ipppd is running and 
+   conneted to at least one /dev/ippp*. Check the 
+   isdn4linux manual on how to configure a network device.
 
-Q: when I start the ipppd .. I only get the
+--
+
+Q02: when I start the ipppd .. I only get the
    error message "this systems lacks PPP support"
 A: check that at least the device 'ippp0' exists.
    (you can check this e.g with the program 'ifconfig')
@@ -39,12 +57,168 @@
    kernel source tree than the kernel you currently
    run ... 
 
-Q: when I list the netdevices with ifconfig I see, that
+--
+
+Q03: when I list the netdevices with ifconfig I see, that
    my ISDN interface has a HWaddr and IRQ=0 and Base 
    address = 0 
-A: The device is a fake ethernet device .. ignore IRQ and baseaddr
+A: The device is a fake ethernetdevice .. ignore IRQ and baseaddr
    You need the HWaddr only for ethernet encapsulation.
    
+--
+
+Q04: MPPP?? What's that and how can I use it ...
+
+A: MPPP or MP or MPP (Warning: MP is also an 
+   acronym for 'Multi Processor') stands for
+   Multi Point to Point and means bundling
+   of several channels to one logical stream.
+   To enable MPPP negotiation you must call the
+   ipppd with the '+mp' option. 
+   You must also configure a slave device for
+   every additional channel. (see the i4l manual
+   for more)
+   To use channel bundling you must first activate
+   the 'master' or inital call. Now you can add 
+   the slave channels with the command:
+       isdnctrl addlink <device>
+   e.g:
+       isdnctrl addlink ippp0
+   This is different to other encapsualtions of
+   isdn4linux! With syncPPP, there is no automatic
+   activation of slave devices.
+
+--
+
+Q05: I tried MPPP but it doesn't work .. the ipppd
+   writes in the debug log something like:
+   .. rcvd [0][proto=0x3d] c0 00 00 00 80 fd 01 01 00 0a ...
+   .. sent [0][LCP ProtRej id=0x2 00 3d c0 00 00 00 80 fd 01 ...
+
+A: you forgot to compile MPPP/RFC1717 support into the
+   ISDN Subsystem. Recompile with this option enabled.
+
+--
+
+Q06: can I use asynchronous PPP encapuslation
+   over the network interface of isdn4linux ..
+
+A: No .. that's not possible .. Use the standard
+   PPP package over the /dev/ttyI* devices. You
+   must not use the ipppd for this.
+   
+--
+
+Q07: A SunISDN machine tries to connect my i4l system,
+   which doesn't work.
+   Checking the debug log I just saw garbage like:
+!![ ... fill in the line ... ]!!
+
+A: The Sun tries to talk asynchronous PPP ... i4l
+   can't understand this ... try to use the ttyI*
+   devices with the standard PPP/pppd package
+
+A: (from Alexanter Strauss: )
+!![ ... fill in mail ]!!
+
+--
+
+Q08: A wanna talk to remote machines, which need
+   a different configuration. The only way
+   I found to do this is to kill the ipppd and
+   start a new one with another config to connect
+   to the second machine. 
+
+A: you must bind a network interface explicitly to
+   an ippp device, where you can connect a (for this
+   interface) individualy configured ipppd.
+
+--
+
+Q09: When I start the ipppd I only get error messages
+   from the i4l driver .. 
+
+A: When starting, the ipppd calls functions which may 
+   trigger a network packet. (e.g gethostbyname()).
+   Without the ipppd (at this moment, it is not
+   fully started) we can't handle this network request.
+   Try to configure hostnames necessary for the ipppd
+   in your local /etc/hosts file or in a way, that
+   your system can resolve it without using an
+   isdn/ippp network-interface.
+
+--
+
+Q10: I wanna use dynamic IP address assignment ... How 
+   must I configure the network device.
+
+A: At least you must have a routing, which forwards
+   a packet to the ippp network-interface to trigger
+   the dial-on-demand.
+   A default routing to the ippp-interface will work.
+   Now you must choose a dummy IP address for your
+   interface.
+   If for some reason you can't set the default
+   routing to the ippp interface, you may take any 
+   address of the subnet from which you expect your
+   dynamic IP number and set a 'network route' for
+   this subnet to the ippp interface.
+   To allow overriding of the dummy address you
+   must call the ipppd with the 'ipcp-accept-local' option.
+
+A: You must know, how the ipppd gets the addresses it wanna
+   configure. If you don't give any option, the ipppd
+   tries to negotiate the local host address!
+   With the option 'noipdefault' it requests an address
+   from the remote machine. With 'useifip' it gets the
+   addresses from the net interface. Or you set the addresse
+   on the option line with the <a.b.c.d:e.f.g.h> option.
+   Note: the IP address of the remote machine must be configured
+   locally or the remote machine must send it in an IPCP request.
+   If your side doesn't know the IP address after negotiation, it
+   closes the connection!
+   You must allow overriding of address with the 'ipcp-accept-*'
+   options, if you have set your own or the remote address 
+   explicitly.
+
+A: Maybe you try these options .. e.g:   
+
+    /sbin/ipppd :$REMOTE noipdefault /dev/ippp0
+
+   where REMOTE must be the address of the remote machine (the
+   machine, which gives you your address)
+
+--
+
+Q11: I can't connect. How can I check where the problem is.
+
+A: A good help log is the debug output from the ipppd...
+   Check whether you can find there:
+   - only a few LCP-conf-req SENT messages (less then 10)
+     and then a Term-REQ:
+     -> check whether your ISDN card is well configured
+        it seems, that your machine doesn't dial
+        (IRQ,IO,Proto, etc problems)
+        Configure your ISDN card to print debug messages and
+        check the /dev/isdnctrl output next time. There
+        you can see, whether there is activity on the card/line.
+   - there are at least a few RECV messages in the log:
+     -> fine: your card is dialing and your remote machine
+        tries to talk with you. Maybe only a missing 
+        authentification. Check your ipppd configuration again.
+   - the ipppd exits for some reason:
+     -> not good ... check /var/adm/syslog and /var/adm/daemon.
+        Could be a bug in the ipppd.
+
+--
+
+Q12: How can I reduce login delay?
+
+A: Log a login session ('debug' log) and check which options 
+  your remote side rejects. Next time configure your ipppd
+  to not negotiate these options. Another 'side effect' is, that
+  this increases redundancy. (e.g your remote side is buggy and
+  rejects options in a wrong way).
 
 
 
diff -u --recursive --new-file pre2.0.5/linux/Makefile linux/Makefile
--- pre2.0.5/linux/Makefile	Fri May 17 15:32:10 1996
+++ linux/Makefile	Fri May 17 15:32:53 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 99
-SUBLEVEL = 5
+SUBLEVEL = 6
 
 ARCH = i386
 
diff -u --recursive --new-file pre2.0.5/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- pre2.0.5/linux/arch/alpha/defconfig	Mon May 13 23:02:47 1996
+++ linux/arch/alpha/defconfig	Sun May 19 16:41:54 1996
@@ -24,6 +24,7 @@
 # CONFIG_ALPHA_EB66P is not set
 # CONFIG_ALPHA_EB64P is not set
 CONFIG_ALPHA_EB164=y
+# CONFIG_ALPHA_PC164 is not set
 # CONFIG_ALPHA_JENSEN is not set
 # CONFIG_ALPHA_NONAME is not set
 # CONFIG_ALPHA_P2K is not set
@@ -47,11 +48,15 @@
 # Please see drivers/block/README.ide for help/info on IDE drives
 #
 # CONFIG_BLK_DEV_HD_ONLY is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_MD is not set
 
 #
 # Networking options
@@ -120,7 +125,7 @@
 # CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_QLOGIC is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_ULTRASTOR is not set
diff -u --recursive --new-file pre2.0.5/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- pre2.0.5/linux/arch/alpha/kernel/traps.c	Sat Apr 27 15:19:44 1996
+++ linux/arch/alpha/kernel/traps.c	Sun May 19 17:02:31 1996
@@ -70,9 +70,9 @@
 	force_sig(SIGFPE, current);
 }
 
-asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
-			 unsigned long a3, unsigned long a4, unsigned long a5,
-			 struct pt_regs regs)
+asmlinkage void do_entIF(unsigned long type, unsigned long a1,
+			 unsigned long a2, unsigned long a3, unsigned long a4,
+			 unsigned long a5, struct pt_regs regs)
 {
 	extern int ptrace_cancel_bpt (struct task_struct *who);
 
@@ -201,18 +201,18 @@
 	if (reg >= 16 && reg <= 18)
 		reg += 19;
 	switch (opcode) {
-		case 0x28: /* ldl */
-			*(reg+regs.regs) = (int) ldl_u(va);
-			return;
-		case 0x29: /* ldq */
-			*(reg+regs.regs) = ldq_u(va);
-			return;
-		case 0x2c: /* stl */
-			stl_u(*(reg+regs.regs), va);
-			return;
-		case 0x2d: /* stq */
-			stq_u(*(reg+regs.regs), va);
-			return;
+	      case 0x28: /* ldl */
+		*(reg+regs.regs) = get_unaligned((int *)va);
+		return;
+	      case 0x29: /* ldq */
+		*(reg+regs.regs) = get_unaligned((long *)va);
+		return;
+	      case 0x2c: /* stl */
+		put_unaligned(*(reg+regs.regs), (int *)va);
+		return;
+	      case 0x2d: /* stq */
+		put_unaligned(*(reg+regs.regs), (long *)va);
+		return;
 	}
 	printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
 		regs.pc, va, opcode, reg);
@@ -321,45 +321,79 @@
 	reg_addr = frame;
 	if (opcode >= 0x28) {
 		/* it's an integer load/store */
-		if (reg < 9) {
-			reg_addr += 7 + reg;			/* v0-t7 in SAVE_ALL frame */
-		} else if (reg < 16) {
-			reg_addr += (reg - 9);			/* s0-s6 in entUna frame */
-		} else if (reg < 19) {
-			reg_addr += 7 + 20 + 3 + (reg - 16);	/* a0-a2 in PAL frame */
-		} else if (reg < 29) {
-			reg_addr += 7 + 9 + (reg - 19);		/* a3-at in SAVE_ALL frame */
-		} else {
-			switch (reg) {
-			      case 29:				/* gp in PAL frame */
-				reg_addr += 7 + 20 + 2;
-				break;
-			      case 30:				/* usp in PAL regs */
-				usp = rdusp();
-				reg_addr = &usp;
-				break;
-			      case 31:				/* zero "register" */
-				reg_addr = &zero;
-				break;
-			}
+		switch (reg) {
+		      case 0: case 1: case 2: case 3: case 4:
+		      case 5: case 6: case 7: case 8:
+			/* v0-t7 in SAVE_ALL frame */
+			reg_addr += 7 + reg;
+			break;
+
+		      case 9: case 10: case 11: case 12:
+		      case 13: case 14: case 15:
+			/* s0-s6 in entUna frame */
+			reg_addr += (reg - 9);
+			break;
+
+		      case 16: case 17: case 18: 
+			/* a0-a2 in PAL frame */
+			reg_addr += 7 + 20 + 3 + (reg - 16);
+			break;
+
+		      case 19: case 20: case 21: case 22: case 23: 
+		      case 24: case 25: case 26: case 27: case 28:
+			/* a3-at in SAVE_ALL frame */
+			reg_addr += 7 + 9 + (reg - 19);
+			break;
+
+		      case 29:
+			/* gp in PAL frame */
+			reg_addr += 7 + 20 + 2;
+			break;
+
+		      case 30:
+			/* usp in PAL regs */
+			usp = rdusp();
+			reg_addr = &usp;
+			break;
+
+		      case 31:
+			/* zero "register" */
+			reg_addr = &zero;
+			break;
 		}
 	}
 
 	switch (opcode) {
-	      case 0x22:						/* lds */
-		alpha_write_fp_reg(reg, s_mem_to_reg(ldl_u(va)));
+	      case 0x22: /* lds */
+		alpha_write_fp_reg(reg, s_mem_to_reg(
+			get_unaligned((unsigned int *)va)));
 		break;
-	      case 0x26:						/* lds */
-		alpha_write_fp_reg(reg, s_reg_to_mem(ldl_u(va)));
+	      case 0x26: /* sts */
+		put_unaligned(s_reg_to_mem(alpha_read_fp_reg(reg)),
+			      (unsigned int *)va);
 		break;
 
-	      case 0x23: alpha_write_fp_reg(reg, ldq_u(va)); break;	/* ldt */
-	      case 0x27: stq_u(alpha_read_fp_reg(reg), va);  break;	/* stt */
+	      case 0x23: /* ldt */
+		alpha_write_fp_reg(reg, get_unaligned((unsigned long *)va));
+		break;	
+	      case 0x27: /* stt */
+		put_unaligned(alpha_read_fp_reg(reg), (unsigned long *)va);
+		break;
+
+	      case 0x28: /* ldl */
+		*reg_addr = get_unaligned((int *)va);
+		break;
+	      case 0x2c: /* stl */
+		put_unaligned(*reg_addr, (int *)va);
+		break;
+
+	      case 0x29: /* ldq */
+		*reg_addr = get_unaligned((long *)va);
+		break;
+	      case 0x2d: /* stq */
+		put_unaligned(*reg_addr, (long *)va);
+		break;
 
-	      case 0x28: *reg_addr = (int) ldl_u(va);	     break;	/* ldl */
-	      case 0x29: *reg_addr = ldq_u(va);		     break;	/* ldq */
-	      case 0x2c: stl_u(*reg_addr, va);		     break;	/* stl */
-	      case 0x2d: stq_u(*reg_addr, va);		     break;	/* stq */
 	      default:
 		*pc_addr -= 4;	/* make pc point to faulting insn */
 		force_sig(SIGBUS, current);
@@ -383,10 +417,11 @@
  * got terminally tainted by VMS at some point.
  */
 asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
-	unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs)
+			  unsigned long a3, unsigned long a4, unsigned long a5,
+			  struct pt_regs regs)
 {
 	if (regs.r0 != 112)
-	  printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
+		printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
 	return -1;
 }
 
diff -u --recursive --new-file pre2.0.5/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- pre2.0.5/linux/arch/i386/boot/video.S	Mon May 13 23:02:47 1996
+++ linux/arch/i386/boot/video.S	Sat May 18 11:15:10 1996
@@ -880,7 +880,7 @@
 	cmp	ax,#0x0080	! Check validity of mode ID
 	jc	vesa2
 	or	ah,ah		! Valid ID's are 0x0000-0x007f and 0x0100-0x07ff
-	jz	vesan		! [Certain BIOSes errorneously report 0x80-0xff]
+	jz	vesan		! [Certain BIOSes erroneously report 0x80-0xff]
 	cmp	ax,#0x0800
 	jnc	vesae
 vesa2:	push	cx
diff -u --recursive --new-file pre2.0.5/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- pre2.0.5/linux/arch/i386/defconfig	Mon May 13 23:02:47 1996
+++ linux/arch/i386/defconfig	Sun May 19 16:22:52 1996
@@ -44,13 +44,17 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDE_PCMCIA is not set
 CONFIG_BLK_DEV_CMD640=y
-CONFIG_BLK_DEV_RZ1000=y
 # CONFIG_BLK_DEV_TRITON is not set
+CONFIG_BLK_DEV_RZ1000=y
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_RAM is not set
+
+#
+# Additional Block Devices
+#
 # CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_XD is not set
 
 #
 # Networking options
diff -u --recursive --new-file pre2.0.5/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- pre2.0.5/linux/arch/m68k/kernel/head.S	Fri May 17 15:32:11 1996
+++ linux/arch/m68k/kernel/head.S	Sat May 18 11:15:10 1996
@@ -375,7 +375,7 @@
 	movel	%d1,%a2@+
 	/*
 	 * %a2 points now to the page table entry for available pages at %a6,
-	 * hence caching modes for new pages can easiely set unless increasing
+	 * hence caching modes for new pages can easily set unless increasing
 	 * of %a2 are forgotten.
 	 */
 Lnot040:
diff -u --recursive --new-file pre2.0.5/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- pre2.0.5/linux/drivers/block/genhd.c	Mon May 13 23:02:47 1996
+++ linux/drivers/block/genhd.c	Sun May 19 13:29:22 1996
@@ -30,21 +30,16 @@
 
 #include <asm/system.h>
 
-#ifdef __alpha__
 /*
- * On the Alpha, we get unaligned access exceptions on
- *  p->nr_sects and p->start_sect, when the partition table
- *  is not on a 4-byte boundary, which is frequently the case.
- * This code uses unaligned load instructions to prevent
- *  such exceptions.
+ * Many architectures don't like unaligned accesses, which is
+ * frequently the case with the nr_sects and start_sect partition
+ * table entries.
  */
 #include <asm/unaligned.h>
-#define NR_SECTS(p)	ldl_u(&p->nr_sects)
-#define START_SECT(p)	ldl_u(&p->start_sect)
-#else /* __alpha__ */
-#define NR_SECTS(p)	p->nr_sects
-#define START_SECT(p)	p->start_sect
-#endif /* __alpha__ */
+
+#define NR_SECTS(p)	get_unaligned(&p->nr_sects)
+#define START_SECT(p)	get_unaligned(&p->start_sect)
+
 
 struct gendisk *gendisk_head = NULL;
 
diff -u --recursive --new-file pre2.0.5/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- pre2.0.5/linux/drivers/block/ide-cd.c	Sat May 11 10:42:05 1996
+++ linux/drivers/block/ide-cd.c	Sun May 19 15:16:34 1996
@@ -97,6 +97,7 @@
  * 3.12  May  7, 1996 -- Rudimentary changer support.  Based on patches
  *                        from Gerhard Zuber <zuber@berlin.snafu.de>.
  *                       Let open succeed even if there's no loaded disc.
+ * 3.13  May 19, 1996 -- Fixes for changer code.
  *
  * NOTE: Direct audio reads will only work on some types of drive.
  * So far, i've received reports of success for Sony and Toshiba drives.
@@ -106,6 +107,7 @@
  * uses a different protocol.
  *
  * ATAPI cd-rom driver.  To be used with ide.c.
+ * See Documentation/cdrom/ide-cd for usage information.
  *
  * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
  * May be copied or modified under the terms of the GNU General Public License
@@ -130,9 +132,7 @@
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/segment.h>
-#ifdef __alpha__
-# include <asm/unaligned.h>
-#endif
+#include <asm/unaligned.h>
 
 #include "ide.h"
 
@@ -1149,11 +1149,7 @@
 	pc.c[0] = READ_10;
 	pc.c[7] = (nframes >> 8);
 	pc.c[8] = (nframes & 0xff);
-#ifdef __alpha__
-	stl_u (htonl (frame), (unsigned int *) &pc.c[2]);
-#else
-	*(int *)(&pc.c[2]) = htonl (frame);
-#endif
+	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
 
 	/* Send the command to the drive and return. */
 	(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c),
@@ -1937,11 +1933,7 @@
 		pc.c[0] = READ_CD;
 
 	pc.c[1] = (format << 2);
-#ifdef __alpha__
-	stl_u(htonl (lba), (unsigned int *) &pc.c[2]);
-#else
-	*(int *)(&pc.c[2]) = htonl (lba);
-#endif
+	put_unaligned(htonl(lba), (unsigned int *) &pc.c[2]);
 	pc.c[8] = 1;  /* one block */
 	pc.c[9] = 0x10;
 
@@ -1968,7 +1960,7 @@
 
 /* If SLOT<0, unload the current slot.  Otherwise, try to load SLOT. */
 static int
-cdrom_load_unload (ide_drive_t *drive, unsigned long slot,
+cdrom_load_unload (ide_drive_t *drive, int slot,
 		   struct atapi_request_sense *reqbuf)
 {
 	struct packet_command pc;
@@ -2403,16 +2395,14 @@
 		if (drive->usage > 1)
 			return -EBUSY;
 
-		stat = cdrom_load_unload (drive, -1, NULL);
-		if (stat) return stat;
+		(void) cdrom_load_unload (drive, -1, NULL);
 
                 cdrom_saw_media_change (drive);
                 if (arg == -1) {
 			(void) cdrom_lockdoor (drive, 0, NULL);
 			return 0;
 		}
-		stat = cdrom_load_unload (drive, arg, NULL);
-		if (stat) return stat;
+		(void) cdrom_load_unload (drive, (int)arg, NULL);
 
 		stat = cdrom_check_status (drive, &my_reqbuf);
 		if (stat && my_reqbuf.sense_key == NOT_READY) {
@@ -2642,7 +2632,6 @@
  *  Establish interfaces for an IDE port driver, and break out the cdrom
  *   code into a loadable module.
  *  Support changers better.
- *  Write some real documentation.
  */
 
 
diff -u --recursive --new-file pre2.0.5/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- pre2.0.5/linux/drivers/block/ll_rw_blk.c	Sat May 11 10:42:05 1996
+++ linux/drivers/block/ll_rw_blk.c	Fri May 17 18:30:40 1996
@@ -286,9 +286,17 @@
 
 	count = bh->b_size >> 9;
 	sector = bh->b_rsector;
+
+	/* Uhhuh.. Nasty dead-lock possible here.. */
+	if (buffer_locked(bh))
+		return;
+	/* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
+
+	lock_buffer(bh);
+
 	if (blk_size[major])
 		if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) {
-			bh->b_state = 0;
+			bh->b_state &= (1 << BH_Lock) | (1 << BH_FreeOnIO);
                         /* This may well happen - the kernel calls bread()
                            without checking the size of the device, e.g.,
                            when mounting a device. */
@@ -298,13 +306,9 @@
                                kdevname(bh->b_rdev), rw,
                                (sector + count)>>1,
                                blk_size[major][MINOR(bh->b_rdev)]);
+			unlock_buffer(bh);
 			return;
 		}
-	/* Uhhuh.. Nasty dead-lock possible here.. */
-	if (buffer_locked(bh))
-		return;
-	/* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
-	lock_buffer(bh);
 
 	rw_ahead = 0;	/* normal case; gets changed below for READA/WRITEA */
 	switch (rw) {
diff -u --recursive --new-file pre2.0.5/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c
--- pre2.0.5/linux/drivers/cdrom/aztcd.c	Tue May  7 16:22:23 1996
+++ linux/drivers/cdrom/aztcd.c	Sun May 19 15:17:57 1996
@@ -1,5 +1,5 @@
-#define AZT_VERSION "2.40"
-/*      $Id: aztcd.c,v 2.40 1996/05/01 11:09:35 root Exp root $
+#define AZT_VERSION "2.50"
+/*      $Id: aztcd.c,v 2.50 1996/05/17 16:19:03 root Exp root $
 	linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver
 
 	Copyright (C) 1994,95,96 Werner Zimmermann(zimmerma@rz.fht-esslingen.de)
@@ -151,6 +151,9 @@
         V2.40   Reorganized the placement of functions in the source code file
                 to reflect the layered approach; did not actually change code
                 Werner Zimmermann, May 1, 96
+        V2.50   Heiko Eissfeld suggested to remove some VERIFY_READs in 
+                aztcd_ioctl; check_aztcd_media_change modified 
+                Werner Zimmermann, May 16, 96       
 */
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -1053,10 +1056,15 @@
 }
 
 /* 
- * Checking if the media has been changed not yet implemented
+ * Checking if the media has been changed
 */
 static int check_aztcd_media_change(kdev_t full_dev)
-{ return 0;
+{ if (aztDiskChanged)          /* disk changed */
+     { aztDiskChanged=0;
+       return 1;
+     }
+  else
+       return 0;               /* no change */
 }
 
 /*
@@ -1127,7 +1135,7 @@
 #ifdef AZT_DEBUG
    		  printk("aztcd ioctl MULTISESSION\n");
 #endif
-		  st = verify_area(VERIFY_READ, (void*) arg, sizeof(struct cdrom_multisession));
+		  st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession));
 		  if (st) return st;
 		  memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
 		  if (ms.addr_format == CDROM_MSF) 
@@ -1140,8 +1148,6 @@
 		  else
 		       return -EINVAL;
 		  ms.xa_flag = DiskInfo.xa;
- 		  st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession));
-		  if (st) return st;
 	  	  memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
 #ifdef AZT_DEBUG 
  		  if (ms.addr_format == CDROM_MSF) 
@@ -1225,8 +1231,6 @@
 		memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
 		break;
 	case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
-		st = verify_area(VERIFY_READ, (void *) arg, sizeof entry);
-		if (st) return st;
 		st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
 		if (st) return st;
 		memcpy_fromfs(&entry, (void *) arg, sizeof entry);
@@ -1254,17 +1258,10 @@
 		memcpy_tofs((void *) arg, &entry, sizeof entry);
 		break;
 	case CDROMSUBCHNL:   /* Get subchannel info */
-		st = verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl));
-		if (st) { 
-#ifdef AZT_DEBUG
-		          printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd);
-#endif
-		          return st;
-		        }  
 		st = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
 		if (st) { 
 #ifdef AZT_DEBUG
-		          printk("aztcd: exiting aztcd_ioctl - Error 2 - Command:%x\n",cmd);
+		          printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd);
 #endif
 		          return st;
 		        }  
@@ -1340,9 +1337,7 @@
 #if AZT_PRIVATE_IOCTLS 
 	case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes)*/
 	case CDROMREADRAW:    /*read data in mode 2 (2336 Bytes)*/
-		{ st = verify_area(VERIFY_READ,  (void *) arg, sizeof msf);
-		  if (st) return st;
-		  st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf);
+		{ st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf);
 		  if (st) return st;
 		  memcpy_fromfs(&msf, (void *) arg, sizeof msf);
 		  /* convert to bcd */
diff -u --recursive --new-file pre2.0.5/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- pre2.0.5/linux/drivers/cdrom/mcdx.c	Fri May 17 15:32:13 1996
+++ linux/drivers/cdrom/mcdx.c	Sat May 18 11:15:10 1996
@@ -27,7 +27,7 @@
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
- *  Andreas Kies (testing the mysterious hang up's)
+ *  Andreas Kies (testing the mysterious hangups)
  *  ... somebody forgotten?
  * 
  * 2.1  1996/04/29 Marcin Dalecki <dalecki@namu03.gwdg.de>
@@ -38,8 +38,8 @@
  * 2.3  1996/05/15 Marcin Dalecki <dalecki@namu03.gwdg.de>
  *	Fixed stereo support. 
  * NOTE:
- *	There will be propably a 3.0 adhering to the new generic non ATAPI
- *	cdrom interface in the unforseen future.
+ *	There will be probably a 3.0 adhering to the new generic non ATAPI
+ *	cdrom interface in the unforeseen future.
  */
 #define VERSION "2.3"
 
@@ -261,8 +261,8 @@
  * Return drives status in case of success, -1 otherwise.
  *
  * First we try to get the status information quickly.
- * Then we sleep repeatedly for about 10 usecs, befor we finally reach the 
- * timeout. For this reason this command must be called with the drive beeing 
+ * Then we sleep repeatedly for about 10 usecs, before we finally reach the 
+ * timeout. For this reason this command must be called with the drive being 
  * locked!
  */
 static int get_status(struct s_drive_stuff *stuffp,
@@ -462,7 +462,7 @@
 		set_drive_mode(stuffp, DATA);
 		return -EIO;
 	}
-	/* now read actually the index tarcks */
+	/* now read actually the index tracks */
 	for (trk = 0;
 	     trk < (stuffp->n_last - stuffp->n_first + 1);
 	     trk++)
@@ -563,8 +563,8 @@
 	/*
 	 * Update disk information, when necessary.
 	 * This part will only work, when the new disk is of the same type as 
-	 * the one which was previousley there, esp. also for audio diks.
-	 * This doesn't hurt us, since otherwise the mouting/unmounting scheme 
+	 * the one which was previously there, esp. also for audio disks.
+	 * This doesn't hurt us, since otherwise the mounting/unmounting scheme 
 	 * will ensure correct operation.
 	 */
 	if (stuffp->xxx) {	/* disk changed */
@@ -797,7 +797,7 @@
 			return ans;
 
 		memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
-		/* Adjust for the wiredness of workman. */
+		/* Adjust for the weirdness of workman. */
 		volctrl.channel2 = volctrl.channel1;
 		volctrl.channel1 = volctrl.channel3 = 0x00;
 		return talk(stuffp, MCDX_CMD_SET_ATTENATOR,
@@ -815,7 +815,7 @@
  * This does actually the transfer from the drive.
  * Return:      -1 on timeout or other error
  * else status byte (as in stuff->st) 
- * FIXME: the excessive jumping throught wait queues degrades the
+ * FIXME: the excessive jumping through wait queues degrades the
  * performance significantly.
  */
 static int transfer_data(struct s_drive_stuff *stuffp,
@@ -1179,7 +1179,7 @@
 	MCDX_TRACE(("mcdx_media_change()\n"));
 
 	/*
-	 * FIXME: propably this is unneded or should be simplified!
+	 * FIXME: probably this is unneeded or should be simplified!
 	 */
 	issue_command(stuffp = mcdx_stuffp[MINOR(full_dev)],
 		      MCDX_CMD_GET_STATUS, 5 * HZ);
@@ -1197,7 +1197,7 @@
 	u_char b;
 
 	if (!(stuffp = mcdx_irq_map[irq])) {
-		return;		/* hugh? */
+		return;		/* huh? */
 	}
 	
 	/* NOTE: We only should get interrupts if data were requested.
@@ -1225,7 +1225,7 @@
 
 /*
  * FIXME!
- * This seems to hang badly, when the driver is loaded with inappriopriate
+ * This seems to hang badly, when the driver is loaded with inappropriate
  * port/irq settings!
  */
 int mcdx_init(void)
diff -u --recursive --new-file pre2.0.5/linux/drivers/char/README.baycom linux/drivers/char/README.baycom
--- pre2.0.5/linux/drivers/char/README.baycom	Fri May 17 15:32:14 1996
+++ linux/drivers/char/README.baycom	Sat May 18 11:15:09 1996
@@ -79,7 +79,7 @@
 
 Configuring the driver
 
-Everytime the driver is inserted into the kernel, it has to know which
+Every time the driver is inserted into the kernel, it has to know which
 modems it should access at which ports. This can be done with the setbaycom
 utility. If you are only using one modem, you can also configure the
 driver from the insmod command line (or by means of an option line in
diff -u --recursive --new-file pre2.0.5/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- pre2.0.5/linux/drivers/char/pcxx.c	Tue May  7 16:22:25 1996
+++ linux/drivers/char/pcxx.c	Sun May 19 15:24:50 1996
@@ -1868,6 +1868,9 @@
 			return 0;
 
 		case TIOCSSOFTCAR:
+			error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
+			if(error)
+				return error;
 			arg = get_fs_long((unsigned long *) arg);
 			tty->termios->c_cflag =	((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
 			return 0;
@@ -1905,6 +1908,9 @@
 		case TIOCMBIC:
 		case TIOCMODS:
 		case TIOCMSET:
+			error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
+			if(error)
+				return error;
 			mstat = get_fs_long((unsigned long *) arg);
 
 			mflag = 0;
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- pre2.0.5/linux/drivers/isdn/Config.in	Fri May 17 15:32:14 1996
+++ linux/drivers/isdn/Config.in	Sun May 19 15:29:29 1996
@@ -8,6 +8,7 @@
     bool 'Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
   fi
 fi
-dep_tristate 'ICN B1 and B2 support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
+dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
 dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
 dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile
--- pre2.0.5/linux/drivers/isdn/Makefile	Sun Apr 21 19:22:06 1996
+++ linux/drivers/isdn/Makefile	Sun May 19 15:29:29 1996
@@ -18,6 +18,9 @@
   ifdef CONFIG_ISDN_PPP
     L_OBJS += isdn_ppp.o
   endif
+  ifdef CONFIG_ISDN_AUDIO
+    L_OBJS += isdn_audio.o
+  endif
 else
   ifeq ($(CONFIG_ISDN),m)
     M_OBJS += isdn.o
@@ -26,6 +29,9 @@
     OX_OBJS += isdn_common.o
     ifdef CONFIG_ISDN_PPP
       O_OBJS += isdn_ppp.o
+    endif
+    ifdef CONFIG_ISDN_AUDIO
+      O_OBJS += isdn_audio.o
     endif
   endif
 endif
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
--- pre2.0.5/linux/drivers/isdn/icn/icn.c	Sun Apr 21 19:22:06 1996
+++ linux/drivers/isdn/icn/icn.c	Sun May 19 15:29:29 1996
@@ -1,4 +1,4 @@
-/* $Id icn.c,v 1.15 1996/01/10 20:57:39 fritz Exp fritz $
+/* $Id: icn.c,v 1.22 1996/05/17 15:46:41 fritz Exp $
  *
  * ISDN low-level module for the ICN active ISDN-Card.
  *
@@ -19,6 +19,22 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: icn.c,v $
+ * Revision 1.22  1996/05/17 15:46:41  fritz
+ * Removed own queue management.
+ * Changed queue management to use sk_buffs.
+ *
+ * Revision 1.21  1996/05/02 04:01:20  fritz
+ * Bugfix:
+ *  - icn_addcard() evalueated wrong driverId.
+ *
+ * Revision 1.20  1996/05/02 00:40:27  fritz
+ * Major rewrite to support more than one card
+ * with a single module.
+ * Support for new firmware.
+ *
+ * Revision 1.19  1996/04/21 17:43:32  fritz
+ * Changes for Support of new Firmware BRV3.02
+ *
  * Revision 1.18  1996/04/20 16:50:26  fritz
  * Fixed status-buffer overrun.
  * Misc. typos
@@ -86,8 +102,6 @@
 
 #include "icn.h"
 
-
-
 /*
  * Verbose bootcode- and protocol-downloading.
  */
@@ -98,58 +112,29 @@
  */
 #undef MAP_DEBUG
 
-/* If defined, no bootcode- and protocol-downloading is supported and
- * you must use an external loader
- */
-#undef LOADEXTERN
-
 static char
-*revision = "$Revision: 1.18 $";
+*revision = "$Revision: 1.22 $";
 
-static void icn_pollcard(unsigned long dummy);
+static int icn_addcard(int, char *, char *);
 
-/* Try to allocate a new buffer, link it into queue. */
-static u_char *
- icn_new_buf(pqueue ** queue, int length)
-{
-	pqueue *p;
-	pqueue *q;
-
-	if ((p = *queue)) {
-		while (p) {
-			q = p;
-			p = (pqueue *) p->next;
-		}
-		p = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC);
-		q->next = (u_char *) p;
-	} else
-		p = *queue = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC);
-	if (p) {
-		p->size = sizeof(pqueue) + length;
-		p->length = length;
-		p->next = NULL;
-		p->rptr = p->buffer;
-		return p->buffer;
-	} else {
-		return (u_char *) NULL;
-	}
-}
-
-#ifdef MODULE
-static void icn_free_queue(pqueue ** queue)
+/*
+ * Free queue completely.
+ * Parameter:
+ *   queue = pointer to queue-head
+ */
+static void icn_free_queue(struct sk_buff_head *queue)
 {
-	pqueue *p;
-	pqueue *q;
-
-	p = *queue;
-	while (p) {
-		q = p;
-		p = (pqueue *) p->next;
-		kfree_s(q, q->size);
-	}
-	*queue = (pqueue *) 0;
+        struct sk_buff *skb;
+        unsigned long flags;
+        
+        save_flags(flags);
+        cli();
+        while ((skb = skb_dequeue(queue))) {
+                skb->free = 1;
+                kfree_skb(skb, FREE_WRITE);
+        }
+        restore_flags(flags);
 }
-#endif
 
 /* Put a value into a shift-register, highest bit first.
  * Parameters:
@@ -159,241 +144,257 @@
  *            bitcount = Number of bits to output
  */
 static inline void icn_shiftout(unsigned short port,
-		     unsigned long val,
-		     int firstbit,
-		     int bitcount)
+                     unsigned long val,
+                     int firstbit,
+                     int bitcount)
 {
 
-	register u_char s;
-	register u_char c;
+        register u_char s;
+        register u_char c;
 
-	for (s = firstbit, c = bitcount; c > 0; s--, c--)
-		OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
+        for (s = firstbit, c = bitcount; c > 0; s--, c--)
+                OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
 }
 
 /*
- * Map Cannel0 (Bank0/Bank8) or Channel1 (Bank4/Bank12)
+ * disable a cards shared memory
  */
-static inline void icn_map_channel(int channel)
+static inline void icn_disable_ram(icn_card *card)
 {
-	static u_char chan2bank[] =
-	{0, 4, 8, 12};
+        OUTB_P(0, ICN_MAPRAM);
+}
 
+/*
+ * enable a cards shared memory
+ */
+static inline void icn_enable_ram(icn_card *card)
+{
+        OUTB_P(0xff, ICN_MAPRAM);
+}
+
+/*
+ * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
+ */
+static inline void icn_map_channel(icn_card *card, int channel)
+{
 #ifdef MAP_DEBUG
-	printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel);
+        printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel);
 #endif
-	if (channel == dev->channel)
-		return;
-	OUTB_P(0, ICN_MAPRAM);	/* Disable RAM          */
-	icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4);	/* Select Bank          */
-	OUTB_P(0xff, ICN_MAPRAM);	/* Enable RAM           */
-	dev->channel = channel;
+        if ((channel == dev.channel) && (card == dev.mcard))
+                return;
+        if (dev.mcard)
+                icn_disable_ram(dev.mcard);
+        icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4);        /* Select Bank          */
+        icn_enable_ram(card);
+        dev.mcard = card;
+        dev.channel = channel;
 #ifdef MAP_DEBUG
-	printk(KERN_DEBUG "icn_map_channel done\n");
+        printk(KERN_DEBUG "icn_map_channel done\n");
 #endif
 }
 
-static inline int icn_lock_channel(int channel)
+/*
+ * Lock a cards channel.
+ * Return 0 if requested card/channel is unmapped (failure).
+ * Return 1 on success.
+ */
+static inline int icn_lock_channel(icn_card *card, int channel)
 {
-	register int retval;
-	ulong flags;
+        register int retval;
+        ulong flags;
 
 #ifdef MAP_DEBUG
-	printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
+        printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
 #endif
-	save_flags(flags);
-	cli();
-	if (dev->channel == channel) {
-		dev->chanlock++;
-		retval = 1;
+        save_flags(flags);
+        cli();
+        if ((dev.channel == channel) && (card == dev.mcard)) {
+                dev.chanlock++;
+                retval = 1;
 #ifdef MAP_DEBUG
-		printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
+                printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
 #endif
-	} else {
-		retval = 0;
+        } else {
+                retval = 0;
 #ifdef MAP_DEBUG
-		printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev->channel);
+                printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, device->channel);
 #endif
-	}
-	restore_flags(flags);
-	return retval;
+        }
+        restore_flags(flags);
+        return retval;
 }
 
+/*
+ * Release current card/channel lock
+ */
 static inline void icn_release_channel(void)
 {
-	ulong flags;
+        ulong flags;
 
 #ifdef MAP_DEBUG
-	printk(KERN_DEBUG "icn_release_channel l=%d\n", dev->chanlock);
+        printk(KERN_DEBUG "icn_release_channel l=%d\n", device->chanlock);
 #endif
-	save_flags(flags);
-	cli();
-	if (dev->chanlock)
-		dev->chanlock--;
-	restore_flags(flags);
+        save_flags(flags);
+        cli();
+        if (dev.chanlock)
+                dev.chanlock--;
+        restore_flags(flags);
 }
 
-static inline int icn_trymaplock_channel(int channel)
+/*
+ * Try to map and lock a cards channel.
+ * Return 1 on success, 0 on failure.
+ */
+static inline int icn_trymaplock_channel(icn_card *card, int channel)
 {
-	ulong flags;
+        ulong flags;
 
-	save_flags(flags);
-	cli();
+        save_flags(flags);
+        cli();
 #ifdef MAP_DEBUG
-	printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev->channel,
-	       dev->chanlock);
+        printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
+               dev.chanlock);
 #endif
-	if ((!dev->chanlock) || (dev->channel == channel)) {
-		dev->chanlock++;
-		icn_map_channel(channel);
-		restore_flags(flags);
+        if ((!dev.chanlock) ||
+            ((dev.channel == channel) && (dev.mcard == card))) {
+                dev.chanlock++;
+                icn_map_channel(card,channel);
+                restore_flags(flags);
 #ifdef MAP_DEBUG
-		printk(KERN_DEBUG "trymaplock %d OK\n", channel);
+                printk(KERN_DEBUG "trymaplock %d OK\n", channel);
 #endif
-		return 1;
-	}
-	restore_flags(flags);
+                return 1;
+        }
+        restore_flags(flags);
 #ifdef MAP_DEBUG
-	printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
+        printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
 #endif
-	return 0;
+        return 0;
 }
 
-static inline void icn_maprelease_channel(int channel)
+/*
+ * Release currend card/channel lock,
+ * then map same or other channel without locking.
+ */
+static inline void icn_maprelease_channel(icn_card *card, int channel)
 {
-	ulong flags;
+        ulong flags;
 
-	save_flags(flags);
-	cli();
+        save_flags(flags);
+        cli();
 #ifdef MAP_DEBUG
-	printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev->chanlock);
+        printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
 #endif
-	if (dev->chanlock)
-		dev->chanlock--;
-	if (!dev->chanlock)
-		icn_map_channel(channel);
-	restore_flags(flags);
+        if (dev.chanlock)
+                dev.chanlock--;
+        if (!dev.chanlock)
+                icn_map_channel(card,channel);
+        restore_flags(flags);
 }
 
 /* Get Data from the B-Channel, assemble fragmented packets and put them
  * into receive-queue. Wake up any B-Channel-reading processes.
- * This routine is called via timer-callback from pollbchan().
- * It schedules itself while any B-Channel is open.
+ * This routine is called via timer-callback from icn_pollbchan().
  */
 
-#ifdef DEBUG_RCVCALLBACK
-static int max_pending[2] =
-{0, 0};
-#endif
-
-static void icn_pollbchan_receive(int channel, icn_dev * dev)
-{
-	int mch = channel + ((dev->secondhalf) ? 2 : 0);
-	int eflag;
-	int cnt;
-	int flags;
-#ifdef DEBUG_RCVCALLBACK
-	int rcv_pending1;
-	int rcv_pending2;
-	int akt_pending;
-#endif
-
-	if (icn_trymaplock_channel(mch)) {
-		while (rbavl) {
-			cnt = rbuf_l;
-			if ((dev->rcvidx[channel] + cnt) > 4000) {
-				printk(KERN_WARNING "icn: bogus packet on ch%d, dropping.\n",
-				       channel + 1);
-				dev->rcvidx[channel] = 0;
-				eflag = 0;
-			} else {
-				memcpy(&dev->rcvbuf[channel][dev->rcvidx[channel]], rbuf_d, cnt);
-				dev->rcvidx[channel] += cnt;
-				eflag = rbuf_f;
-			}
-			rbnext;
-			icn_maprelease_channel(mch & 2);
-			if (!eflag) {
-				save_flags(flags);
-				cli();
-#ifdef DEBUG_RCVCALLBACK
-				rcv_pending1 =
-				    (dev->shmem->data_control.ecnr > dev->shmem->data_control.ecns) ?
-				    0xf - dev->shmem->data_control.ecnr + dev->shmem->data_control.ecns :
-				    dev->shmem->data_control.ecns - dev->shmem->data_control.ecnr;
-#endif
-				dev->interface.rcvcallb(dev->myid, channel, dev->rcvbuf[channel],
-						   dev->rcvidx[channel]);
-				dev->rcvidx[channel] = 0;
-#ifdef DEBUG_RCVCALLBACK
-				rcv_pending2 =
-				    (dev->shmem->data_control.ecnr > dev->shmem->data_control.ecns) ?
-				    0xf - dev->shmem->data_control.ecnr + dev->shmem->data_control.ecns :
-				    dev->shmem->data_control.ecns - dev->shmem->data_control.ecnr;
-				akt_pending = rcv_pending2 - rcv_pending1;
-				if (akt_pending > max_pending[channel]) {
-					max_pending[channel] = akt_pending;
-					printk(KERN_DEBUG "ICN_DEBUG: pend: %d %d\n", max_pending[0], max_pending[1]);
-				}
-#endif
-				restore_flags(flags);
-			}
-			if (!icn_trymaplock_channel(mch))
-				break;
-		}
-		icn_maprelease_channel(mch & 2);
-	}
+static void icn_pollbchan_receive(int channel, icn_card *card)
+{
+        int mch = channel + ((card->secondhalf) ? 2 : 0);
+        int eflag;
+        int cnt;
+	struct sk_buff *skb;
+
+        if (icn_trymaplock_channel(card,mch)) {
+                while (rbavl) {
+                        cnt = rbuf_l;
+                        if ((card->rcvidx[channel] + cnt) > 4000) {
+                                printk(KERN_WARNING 
+                                       "icn: (%s) bogus packet on ch%d, dropping.\n",
+                                       CID,
+                                       channel + 1);
+                                card->rcvidx[channel] = 0;
+                                eflag = 0;
+                        } else {
+                                memcpy(&card->rcvbuf[channel][card->rcvidx[channel]], rbuf_d, cnt);
+                                card->rcvidx[channel] += cnt;
+                                eflag = rbuf_f;
+                        }
+                        rbnext;
+                        icn_maprelease_channel(card, mch & 2);
+                        if (!eflag) {
+                                if ((cnt = card->rcvidx[channel])) {
+                                        if (!(skb = dev_alloc_skb(cnt))) {
+                                                printk(KERN_WARNING "ïcn: receive out of memory\n");
+                                                break;
+                                        }
+                                        memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt); 
+                                        card->rcvidx[channel] = 0;
+                                        card->interface.rcvcallb_skb(card->myid, channel, skb);
+                                }
+                        }
+                        if (!icn_trymaplock_channel(card, mch))
+                                break;
+                }
+                icn_maprelease_channel(card, mch & 2);
+        }
 }
 
 /* Send data-packet to B-Channel, split it up into fragments of
  * ICN_FRAGSIZE length. If last fragment is sent out, signal
  * success to upper layers via statcallb with ISDN_STAT_BSENT argument.
- * This routine is called via timer-callback from pollbchan() or
- * directly from sendbuf().
+ * This routine is called via timer-callback from icn_pollbchan() or
+ * directly from icn_sendbuf().
  */
 
-static void icn_pollbchan_send(int channel, icn_dev * dev)
+static void icn_pollbchan_send(int channel, icn_card *card)
 {
-	int mch = channel + ((dev->secondhalf) ? 2 : 0);
-	int eflag = 0;
-	int cnt;
-	int left;
-	int flags;
-	pqueue *p;
-	isdn_ctrl cmd;
-
-	if (!dev->sndcount[channel])
-		return;
-	if (icn_trymaplock_channel(mch)) {
-		while (sbfree && dev->sndcount[channel]) {
-			left = dev->spqueue[channel]->length;
-			cnt =
-			    (sbuf_l =
-			     (left > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), left));
-			memcpy(sbuf_d, dev->spqueue[channel]->rptr, cnt);
-			sbnext;	/* switch to next buffer        */
-			icn_maprelease_channel(mch & 2);
-			dev->spqueue[channel]->rptr += cnt;
-			eflag = ((dev->spqueue[channel]->length -= cnt) == 0);
-			save_flags(flags);
-			cli();
-			p = dev->spqueue[channel];
-			dev->sndcount[channel] -= cnt;
-			if (eflag)
-				dev->spqueue[channel] = (pqueue *) dev->spqueue[channel]->next;
-			restore_flags(flags);
-			if (eflag) {
-				kfree_s(p, p->size);
-				cmd.command = ISDN_STAT_BSENT;
-				cmd.driver = dev->myid;
-				cmd.arg = channel;
-				dev->interface.statcallb(&cmd);
-			}
-			if (!icn_trymaplock_channel(mch))
-				break;
-		}
-		icn_maprelease_channel(mch & 2);
-	}
+        int mch = channel + ((card->secondhalf) ? 2 : 0);
+        int cnt;
+	unsigned long flags;
+        struct sk_buff *skb;
+        isdn_ctrl cmd;
+
+        if (!card->sndcount[channel])
+                return;
+        if (icn_trymaplock_channel(card,mch)) {
+                while (sbfree && card->sndcount[channel]) {
+                        save_flags(flags);
+                        cli();
+                        skb = skb_peek(&card->spqueue[channel]);
+                        if (!skb) {
+                                restore_flags(flags);
+                                break;
+                        }
+                        if (skb->lock) {
+                                restore_flags(flags);
+                                break;
+                        }
+                        skb->lock = 1;
+                        restore_flags(flags);
+                        cnt =
+                            (sbuf_l =
+                             (skb->len > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), skb->len));
+                        memcpy(sbuf_d, skb->data, cnt);
+                        skb_pull(skb, cnt);
+                        card->sndcount[channel] -= cnt;
+                        sbnext;        /* switch to next buffer        */
+                        icn_maprelease_channel(card, mch & 2);
+                        if (!skb->len) {
+                                skb = skb_dequeue(&card->spqueue[channel]);
+                                skb->free = 1;
+                                skb->lock = 0;
+                                kfree_skb(skb, FREE_WRITE);
+                                cmd.command = ISDN_STAT_BSENT;
+                                cmd.driver = card->myid;
+                                cmd.arg = channel;
+                                card->interface.statcallb(&cmd);
+                        } else
+                                skb->lock = 0;
+                        if (!icn_trymaplock_channel(card, mch))
+                                break;
+                }
+                icn_maprelease_channel(card, mch & 2);
+        }
 }
 
 /* Send/Receive Data to/from the B-Channel.
@@ -401,253 +402,56 @@
  * It schedules itself while any B-Channel is open.
  */
 
-static void icn_pollbchan(unsigned long dummy)
+static void icn_pollbchan(unsigned long data)
 {
-	unsigned long flags;
+        icn_card *card = (icn_card *)data;
+        unsigned long flags;
 
-	dev->flags |= ICN_FLAGS_RBTIMER;
-	if (dev->flags & ICN_FLAGS_B1ACTIVE) {
-		icn_pollbchan_receive(0, dev);
-		icn_pollbchan_send(0, dev);
-	}
-	if (dev->flags & ICN_FLAGS_B2ACTIVE) {
-		icn_pollbchan_receive(1, dev);
-		icn_pollbchan_send(1, dev);
-	}
-	if (dev->doubleS0) {
-		if (dev2->flags & ICN_FLAGS_B1ACTIVE) {
-			icn_pollbchan_receive(0, dev2);
-			icn_pollbchan_send(0, dev2);
-		}
-		if (dev2->flags & ICN_FLAGS_B2ACTIVE) {
-			icn_pollbchan_receive(1, dev2);
-			icn_pollbchan_send(1, dev2);
-		}
-	}
-	if (dev->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
-		/* schedule b-channel polling again */
-		save_flags(flags);
-		cli();
-		del_timer(&dev->rb_timer);
-		dev->rb_timer.function = icn_pollbchan;
-		dev->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
-		add_timer(&dev->rb_timer);
-		restore_flags(flags);
-	} else
-		dev->flags &= ~ICN_FLAGS_RBTIMER;
-	if (dev->doubleS0) {
-		if (dev2->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
-			/* schedule b-channel polling again */
-			save_flags(flags);
-			cli();
-			del_timer(&dev2->rb_timer);
-			dev2->rb_timer.function = icn_pollbchan;
-			dev2->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
-			add_timer(&dev2->rb_timer);
-			restore_flags(flags);
-		} else
-			dev2->flags &= ~ICN_FLAGS_RBTIMER;
-	}
-}
-
-static void icn_pollit(icn_dev * dev)
-{
-	int mch = dev->secondhalf ? 2 : 0;
-	int avail = 0;
-	int dflag = 0;
-	int left;
-	u_char c;
-	int ch;
-	int flags;
-	int i;
-	u_char *p;
-	isdn_ctrl cmd;
-
-	if (icn_trymaplock_channel(mch)) {
-		avail = msg_avail;
-		for (left = avail, i = msg_o; left > 0; i++, left--) {
-			c = dev->shmem->comm_buffers.iopc_buf[i & 0xff];
-			save_flags(flags);
-			cli();
-			*dev->msg_buf_write++ = (c == 0xff) ? '\n' : c;
-                        if (dev->msg_buf_write == dev->msg_buf_read) {
-                                if (++dev->msg_buf_read > dev->msg_buf_end)
-                                        dev->msg_buf_read = dev->msg_buf;
-                        }
-			if (dev->msg_buf_write > dev->msg_buf_end)
-				dev->msg_buf_write = dev->msg_buf;
-			restore_flags(flags);
-			if (c == 0xff) {
-				dev->imsg[dev->iptr] = 0;
-				dev->iptr = 0;
-				if (dev->imsg[0] == '0' && dev->imsg[1] >= '0' &&
-				    dev->imsg[1] <= '2' && dev->imsg[2] == ';') {
-					ch = dev->imsg[1] - '0';
-					p = &dev->imsg[3];
-					if (!strncmp(p, "BCON_", 5)) {
-						switch (ch) {
-						case 1:
-							dev->flags |= ICN_FLAGS_B1ACTIVE;
-							break;
-						case 2:
-							dev->flags |= ICN_FLAGS_B2ACTIVE;
-							break;
-						}
-						cmd.command = ISDN_STAT_BCONN;
-						cmd.driver = dev->myid;
-						cmd.arg = ch - 1;
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "TEI OK", 6)) {
-						cmd.command = ISDN_STAT_RUN;
-						cmd.driver = dev->myid;
-						cmd.arg = ch - 1;
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "BDIS_", 5)) {
-						switch (ch) {
-						case 1:
-							dev->flags &= ~ICN_FLAGS_B1ACTIVE;
-							dflag |= 1;
-							break;
-						case 2:
-							dev->flags &= ~ICN_FLAGS_B2ACTIVE;
-							dflag |= 2;
-							break;
-						}
-						cmd.command = ISDN_STAT_BHUP;
-						cmd.arg = ch - 1;
-						cmd.driver = dev->myid;
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "DCON_", 5)) {
-						cmd.command = ISDN_STAT_DCONN;
-						cmd.arg = ch - 1;
-						cmd.driver = dev->myid;
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "DDIS_", 5)) {
-						cmd.command = ISDN_STAT_DHUP;
-						cmd.arg = ch - 1;
-						cmd.driver = dev->myid;
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "E_L1: ACT FAIL", 14)) {
-						cmd.command = ISDN_STAT_BHUP;
-						cmd.arg = 0;
-						cmd.driver = dev->myid;
-						dev->interface.statcallb(&cmd);
-						cmd.command = ISDN_STAT_DHUP;
-						cmd.arg = 0;
-						cmd.driver = dev->myid;
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "CIF", 3)) {
-						cmd.command = ISDN_STAT_CINF;
-						cmd.arg = ch - 1;
-						strncpy(cmd.num, p + 3, sizeof(cmd.num) - 1);
-						cmd.driver = dev->myid;
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "CAU", 3)) {
-						cmd.command = ISDN_STAT_CAUSE;
-						cmd.arg = ch - 1;
-						strncpy(cmd.num, p + 3, sizeof(cmd.num) - 1);
-						cmd.driver = dev->myid;
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "DCAL_I", 6)) {
-						cmd.command = ISDN_STAT_ICALL;
-						cmd.driver = dev->myid;
-						cmd.arg = ch - 1;
-						strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1);
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "FCALL", 5)) {
-						cmd.command = ISDN_STAT_ICALL;
-						cmd.driver = dev->myid;
-						cmd.arg = ch - 1;
-						strcpy(cmd.num, "LEASED,07,00,1");
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "DSCA_I", 6)) {
-						cmd.command = ISDN_STAT_ICALL;
-						cmd.driver = dev->myid;
-						cmd.arg = ch - 1;
-						strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1);
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-					if (!strncmp(p, "NO D-CHAN", 9)) {
-						cmd.command = ISDN_STAT_NODCH;
-						cmd.driver = dev->myid;
-						cmd.arg = ch - 1;
-						strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1);
-						dev->interface.statcallb(&cmd);
-						continue;
-					}
-				} else {
-					p = dev->imsg;
-					if (!strncmp(p, "DRV1.", 5)) {
-                                                printk(KERN_INFO "icn: %s\n",p);
-						if (!strncmp(p + 7, "TC", 2)) {
-							dev->ptype = ISDN_PTYPE_1TR6;
-							dev->interface.features |= ISDN_FEATURE_P_1TR6;
-							printk(KERN_INFO "icn: 1TR6-Protocol loaded and running\n");
-						}
-						if (!strncmp(p + 7, "EC", 2)) {
-							dev->ptype = ISDN_PTYPE_EURO;
-							dev->interface.features |= ISDN_FEATURE_P_EURO;
-							printk(KERN_INFO "icn: Euro-Protocol loaded and running\n");
-						}
-						continue;
-					}
-				}
-			} else {
-				dev->imsg[dev->iptr] = c;
-				if (dev->iptr < 59)
-					dev->iptr++;
-			}
-		}
-		msg_o = (msg_o + avail) & 0xff;
-		icn_release_channel();
-	}
-	if (avail) {
-		cmd.command = ISDN_STAT_STAVAIL;
-		cmd.driver = dev->myid;
-		cmd.arg = avail;
-		dev->interface.statcallb(&cmd);
-	}
-	if (dflag & 1)
-		dev->interface.rcvcallb(dev->myid, 0, dev->rcvbuf[0], 0);
-	if (dflag & 2)
-		dev->interface.rcvcallb(dev->myid, 1, dev->rcvbuf[1], 0);
-	if (dev->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
-		if (!(dev->flags & ICN_FLAGS_RBTIMER)) {
-			/* schedule b-channel polling */
-			dev->flags |= ICN_FLAGS_RBTIMER;
-			save_flags(flags);
-			cli();
-			del_timer(&dev->rb_timer);
-			dev->rb_timer.function = icn_pollbchan;
-			dev->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
-			add_timer(&dev->rb_timer);
-			restore_flags(flags);
-		}
-}
+                if (card->flags & ICN_FLAGS_B1ACTIVE) {
+                        icn_pollbchan_receive(0, card);
+                        icn_pollbchan_send(0, card);
+                }
+                if (card->flags & ICN_FLAGS_B2ACTIVE) {
+                        icn_pollbchan_receive(1, card);
+                        icn_pollbchan_send(1, card);
+                }
+                if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
+                        /* schedule b-channel polling again */
+                        save_flags(flags);
+                        cli();
+                        card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+                        add_timer(&card->rb_timer);
+                        card->flags |= ICN_FLAGS_RBTIMER;
+                        restore_flags(flags);
+                } else
+                        card->flags &= ~ICN_FLAGS_RBTIMER;
+}
+
+typedef struct icn_stat {
+        char *statstr;
+        int  command;
+        int  action;
+} icn_stat;
+
+static icn_stat icn_stat_table[] = {
+        {"BCON_",          ISDN_STAT_BCONN, 1}, /* B-Channel connected        */
+        {"BDIS_",          ISDN_STAT_BHUP,  2}, /* B-Channel disconnected     */
+        {"DCON_",          ISDN_STAT_DCONN, 0}, /* D-Channel connected        */
+        {"DDIS_",          ISDN_STAT_DHUP,  0}, /* D-Channel disconnected     */
+        {"DCAL_I",         ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line  */
+        {"DSCA_I",         ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV     */
+        {"FCALL",          ISDN_STAT_ICALL, 4}, /* Leased line connection up  */
+        {"CIF",            ISDN_STAT_CINF,  5}, /* Charge-info, 1TR6-type     */
+        {"AOC",            ISDN_STAT_CINF,  6}, /* Charge-info, DSS1-type     */
+        {"CAU",            ISDN_STAT_CAUSE, 7}, /* Cause code                 */
+        {"TEI OK",         ISDN_STAT_RUN,   0}, /* Card connected to wallplug */
+        {"NO D-CHAN",      ISDN_STAT_NODCH, 0}, /* No D-channel available     */
+        {"E_L1: ACT FAIL", ISDN_STAT_BHUP,  8}, /* Layer-1 activation failed  */
+        {NULL,             0             , -1}
+};
 
 /*
- * Check Statusqueue-Pointer from isdn-card.
+ * Check Statusqueue-Pointer from isdn-cards.
  * If there are new status-replies from the interface, check
  * them against B-Channel-connects/disconnects and set flags accordingly.
  * Wake-Up any processes, who are reading the status-device.
@@ -656,93 +460,260 @@
  * This routine is called periodically via timer.
  */
 
-static void icn_pollcard(unsigned long dummy)
+static int icn_parse_status(u_char *status, int channel, icn_card *card)
 {
-	ulong flags;
-
-	icn_pollit(dev);
-	if (dev->doubleS0)
-		icn_pollit(dev2);
-	/* schedule again */
-	save_flags(flags);
-	cli();
-	del_timer(&dev->st_timer);
-	dev->st_timer.function = icn_pollcard;
-	dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-	add_timer(&dev->st_timer);
-	restore_flags(flags);
+        icn_stat  *s = icn_stat_table;
+        int       action = -1;
+        int       dflag  = 0;
+        unsigned long flags;
+        isdn_ctrl cmd;
+
+        while (s->statstr) {
+                if (!strncmp(status,s->statstr,strlen(s->statstr))) {
+                        cmd.command = s->command;
+                        action = s->action;
+                        break;
+                }
+                s++;
+        }
+        if (action==-1)
+                return 0;
+        cmd.driver = card->myid;
+        cmd.arg = channel;
+        switch (action) {
+                case 1:
+                        card->flags |= (channel)?
+                                ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE;
+                        break;
+                case 2:
+                        card->flags &= ~((channel)?
+                                ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE);
+                        icn_free_queue(&card->spqueue[channel]);
+                        save_flags(flags);
+                        cli();
+                        card->rcvidx[channel] = 0;
+                        restore_flags(flags);
+                        dflag |= (channel+1);
+                        break;
+                case 3:
+                        strncpy(cmd.num, status + 6, sizeof(cmd.num) - 1);
+                        break;
+                case 4:
+                        sprintf(cmd.num,"LEASED%d,07,00,%d",
+                                 card->myid,channel+1);
+                        break;
+                case 5:
+                        strncpy(cmd.num, status + 3, sizeof(cmd.num) - 1);
+                        break;
+                case 6:
+                        sprintf(cmd.num,"%d",
+                                (int)simple_strtoul(status + 7,NULL,16));
+                        break;
+                case 7:
+                        status += 3;
+                        if (strlen(status)==4)
+                                sprintf(cmd.num,"%s%c%c",
+                                        status+2,*status,*(status+1));
+                        else
+                                strncpy(cmd.num, status+1, sizeof(cmd.num) - 1);
+                        break;
+                case 8:
+                        cmd.arg = 0;
+                        cmd.driver = card->myid;
+                        card->interface.statcallb(&cmd);
+                        cmd.command = ISDN_STAT_DHUP;
+                        cmd.arg = 0;
+                        cmd.driver = card->myid;
+                        card->interface.statcallb(&cmd);
+                        cmd.command = ISDN_STAT_BHUP;
+                        cmd.arg = 1;
+                        cmd.driver = card->myid;
+                        card->interface.statcallb(&cmd);
+                        cmd.command = ISDN_STAT_DHUP;
+                        cmd.arg = 1;
+                        cmd.driver = card->myid;
+                        break;
+        }
+        card->interface.statcallb(&cmd);
+        return dflag;
+}
+
+static void icn_polldchan(unsigned long data)
+{
+        icn_card *card = (icn_card *)data;
+        int mch = card->secondhalf ? 2 : 0;
+        int avail = 0;
+        int dflag = 0;
+        int left;
+        u_char c;
+        int ch;
+        int flags;
+        int i;
+        u_char *p;
+        isdn_ctrl cmd;
+
+        if (icn_trymaplock_channel(card,mch)) {
+                avail = msg_avail;
+                for (left = avail, i = msg_o; left > 0; i++, left--) {
+                        c = dev.shmem->comm_buffers.iopc_buf[i & 0xff];
+                        save_flags(flags);
+                        cli();
+                        *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+                        if (card->msg_buf_write == card->msg_buf_read) {
+                                if (++card->msg_buf_read > card->msg_buf_end)
+                                        card->msg_buf_read = card->msg_buf;
+                        }
+                        if (card->msg_buf_write > card->msg_buf_end)
+                                card->msg_buf_write = card->msg_buf;
+                        restore_flags(flags);
+                        if (c == 0xff) {
+                                card->imsg[card->iptr] = 0;
+                                card->iptr = 0;
+                                if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
+                                    card->imsg[1] <= '2' && card->imsg[2] == ';') {
+                                        ch = (card->imsg[1] - '0') - 1;
+                                        p = &card->imsg[3];
+                                        dflag |= icn_parse_status(p, ch, card);
+                                } else {
+                                        p = card->imsg;
+                                        if (!strncmp(p, "DRV1.", 5)) {
+                                                u_char vstr[10];
+                                                u_char *q = vstr;
+
+                                                printk(KERN_INFO "icn: (%s) %s\n",CID,p);
+                                                if (!strncmp(p + 7, "TC", 2)) {
+                                                        card->ptype = ISDN_PTYPE_1TR6;
+                                                        card->interface.features |= ISDN_FEATURE_P_1TR6;
+                                                        printk(KERN_INFO
+                                                               "icn: (%s) 1TR6-Protocol loaded and running\n",CID);
+                                                }
+                                                if (!strncmp(p + 7, "EC", 2)) {
+                                                        card->ptype = ISDN_PTYPE_EURO;
+                                                        card->interface.features |= ISDN_FEATURE_P_EURO;
+                                                        printk(KERN_INFO
+                                                               "icn: (%s) Euro-Protocol loaded and running\n",CID);
+                                                }
+                                                p = strstr(card->imsg,"BRV") + 3;
+                                                while (*p) {
+                                                        if (*p>='0' && *p<='9')
+                                                                *q++ = *p;
+                                                        p++;
+                                                }
+                                                *q = '\0';
+                                                strcat(vstr,"000");
+                                                vstr[3] = '\0';
+                                                card->fw_rev = (int)simple_strtoul(vstr,NULL,10);
+                                                continue;
+                                                
+                                        }
+                                }
+                        } else {
+                                card->imsg[card->iptr] = c;
+                                if (card->iptr < 59)
+                                        card->iptr++;
+                        }
+                }
+                msg_o = (msg_o + avail) & 0xff;
+                icn_release_channel();
+        }
+        if (avail) {
+                cmd.command = ISDN_STAT_STAVAIL;
+                cmd.driver = card->myid;
+                cmd.arg = avail;
+                card->interface.statcallb(&cmd);
+        }
+        if (dflag & 1)
+                card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0);
+        if (dflag & 2)
+                card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0);
+        if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
+                if (!(card->flags & ICN_FLAGS_RBTIMER)) {
+                        /* schedule b-channel polling */
+                        card->flags |= ICN_FLAGS_RBTIMER;
+                        save_flags(flags);
+                        cli();
+                        del_timer(&card->rb_timer);
+                        card->rb_timer.function = icn_pollbchan;
+                        card->rb_timer.data = (unsigned long)card;
+                        card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+                        add_timer(&card->rb_timer);
+                        restore_flags(flags);
+                }
+        /* schedule again */
+        save_flags(flags);
+        cli();
+        card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+        add_timer(&card->st_timer);
+        restore_flags(flags);
 }
 
-/* Send a packet to the transmit-buffers, handle fragmentation if necessary.
+/* Append a packet to the transmit buffer-queue.
  * Parameters:
- *            channel = Number of B-channel
- *            buffer  = pointer to packet
- *            len     = size of packet (max 4000)
- *            dev     = pointer to device-struct
- *            user    = 1 = call from userproc, 0 = call from kernel
+ *   channel = Number of B-channel
+ *   buffer  = pointer to packet
+ *   len     = size of packet (max 4000)
+ *   user    = 1 = call from userproc, 0 = call from kernel
+ *   card    = pointer to card-struct
  * Return:
- *        Number of bytes transferred, -E??? on error
+ *   Number of bytes transferred, -E??? on error
  */
 
-static int icn_sendbuf(int channel, const u_char * buffer, int len, int user, icn_dev * dev)
+static int icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
 {
-	register u_char *p;
-	int flags;
+        int len = skb->len;
+        unsigned long flags;
 
-	if (len > 4000)
-		return -EINVAL;
-	if (len) {
-		if (dev->sndcount[channel] > ICN_MAX_SQUEUE)
-			return 0;
-		save_flags(flags);
-		cli();
-		p = icn_new_buf(&dev->spqueue[channel], len);
-		if (!p) {
-		        restore_flags(flags);
-			return 0;
-		}
-		if (user) {
-			memcpy_fromfs(p, buffer, len);
-		} else {
-			memcpy(p, buffer, len);
-		}
-		dev->sndcount[channel] += len;
-		icn_pollbchan_send(channel, dev);
-		restore_flags(flags);
-	}
-	return len;
+        if (len > 4000) {
+                skb->free = 1;
+                kfree_skb(skb, FREE_WRITE);
+                return -EINVAL;
+        }
+        if (len) {
+                if (!(card->flags & (channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE))
+                        return 0;
+                if (card->sndcount[channel] > ICN_MAX_SQUEUE)
+                        return 0;
+                save_flags(flags);
+                cli();
+                card->sndcount[channel] += len;
+                skb_queue_tail(&card->spqueue[channel], skb);
+                restore_flags(flags);
+                icn_pollbchan_send(channel, card);
+        }
+        return len;
 }
 
-#ifndef LOADEXTERN
 static int icn_check_loader(int cardnumber)
 {
-	int timer = 0;
+        int timer = 0;
 
-	while (1) {
+        while (1) {
 #ifdef BOOT_DEBUG
-		printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
+                printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
 #endif
-		if (dev->shmem->data_control.scns ||
-		    dev->shmem->data_control.scnr) {
-			if (timer++ > 5) {
-				printk(KERN_WARNING "icn: Boot-Loader %d timed out.\n", cardnumber);
-				icn_release_channel();
-				return -EIO;
-			}
+                if (dev.shmem->data_control.scns ||
+                    dev.shmem->data_control.scnr) {
+                        if (timer++ > 5) {
+                                printk(KERN_WARNING
+                                       "icn: Boot-Loader %d timed out.\n",
+                                       cardnumber);
+                                icn_release_channel();
+                                return -EIO;
+                        }
 #ifdef BOOT_DEBUG
-			printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
+                        printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
 #endif
-			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-			schedule();
-		} else {
+                        current->state = TASK_INTERRUPTIBLE;
+                        current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+                        schedule();
+                } else {
 #ifdef BOOT_DEBUG
-			printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
+                        printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
 #endif
-			icn_release_channel();
-			return 0;
-		}
-	}
+                        icn_release_channel();
+                        return 0;
+                }
+        }
 }
 
 /* Load the boot-code into the interface-card's memory and start it.
@@ -769,585 +740,782 @@
 #define SLEEP(sec)
 #endif
 
-static int icn_loadboot(u_char * buffer, icn_dev * dev)
+static int icn_loadboot(u_char * buffer, icn_card * card)
 {
-	int ret;
-	ulong flags;
+        int ret;
+        ulong flags;
 
 #ifdef BOOT_DEBUG
-	printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
+        printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
 #endif
-	if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1)))
-		return ret;
-	save_flags(flags);
-	cli();
-	if (!dev->rvalid) {
-		if (check_region(dev->port, ICN_PORTLEN)) {
-			printk(KERN_WARNING "icn: ports 0x%03x-0x%03x in use.\n", dev->port,
-			       dev->port + ICN_PORTLEN);
-			restore_flags(flags);
-			return -EBUSY;
-		}
-		request_region(dev->port, ICN_PORTLEN, regname);
-		dev->rvalid = 1;
-	}
-	if (!dev->mvalid) {
-		if (check_shmem((ulong) dev->shmem, 0x4000)) {
-			printk(KERN_WARNING "icn: memory at 0x%08lx in use.\n", (ulong) dev->shmem);
-			restore_flags(flags);
-			return -EBUSY;
-		}
-		request_shmem((ulong) dev->shmem, 0x4000, regname);
-		dev->mvalid = 1;
-	}
-	restore_flags(flags);
-	OUTB_P(0, ICN_RUN);	/* Reset Controller */
-	OUTB_P(0, ICN_MAPRAM);	/* Disable RAM      */
-	icn_shiftout(ICN_CFG, 0x0f, 3, 4);	/* Windowsize= 16k */
-	icn_shiftout(ICN_CFG, (unsigned long) dev->shmem, 23, 10);	/* Set RAM-Addr.   */
+        if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1)))
+                return ret;
+        save_flags(flags);
+        cli();
+        if (!card->rvalid) {
+                if (check_region(card->port, ICN_PORTLEN)) {
+                        printk(KERN_WARNING
+                               "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+                               CID,
+                               card->port,
+                               card->port + ICN_PORTLEN);
+                        restore_flags(flags);
+                        return -EBUSY;
+                }
+                request_region(card->port, ICN_PORTLEN, card->regname);
+                card->rvalid = 1;
+                if (card->doubleS0)
+                        card->other->rvalid = 1;
+        }
+        if (!dev.mvalid) {
+                if (check_shmem((ulong) dev.shmem, 0x4000)) {
+                        printk(KERN_WARNING
+                               "icn: memory at 0x%08lx in use.\n",
+                               (ulong) dev.shmem);
+                        restore_flags(flags);
+                        return -EBUSY;
+                }
+                request_shmem((ulong) dev.shmem, 0x4000, "icn");
+                dev.mvalid = 1;
+        }
+        restore_flags(flags);
+        OUTB_P(0, ICN_RUN);                                       /* Reset Controller */
+        OUTB_P(0, ICN_MAPRAM);                                    /* Disable RAM      */
+        icn_shiftout(ICN_CFG, 0x0f, 3, 4);                        /* Windowsize= 16k  */
+        icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10); /* Set RAM-Addr.    */
 #ifdef BOOT_DEBUG
-	printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev->shmem);
+        printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
 #endif
-	SLEEP(1);
-	save_flags(flags);
-	cli();
-	dev->channel = 1;	/* Force Mapping   */
+        SLEEP(1);
+        save_flags(flags);
+        cli();
+        dev.channel = 1;                                           /* Force Mapping    */
+        dev.mcard   = NULL;
 #ifdef BOOT_DEBUG
-	printk(KERN_DEBUG "Map Bank 0\n");
+        printk(KERN_DEBUG "Map Bank 0\n");
 #endif
-	icn_map_channel(0);		/* Select Bank 0   */
-	icn_lock_channel(0);	/* Lock Bank 0     */
-	restore_flags(flags);
-	SLEEP(1);
-	memcpy_fromfs(dev->shmem, buffer, ICN_CODE_STAGE1);	/* Copy code       */
+        icn_map_channel(card,0);                                   /* Select Bank 0    */
+        icn_lock_channel(card,0);                                  /* Lock Bank 0      */
+        restore_flags(flags);
+        SLEEP(1);
+        memcpy_fromfs(dev.shmem, buffer, ICN_CODE_STAGE1);         /* Copy code        */
 #ifdef BOOT_DEBUG
-	printk(KERN_DEBUG "Bootloader transfered\n");
+        printk(KERN_DEBUG "Bootloader transfered\n");
 #endif
-	if (dev->doubleS0) {
-		SLEEP(1);
-		save_flags(flags);
-		cli();
-		icn_release_channel();
+        if (card->doubleS0) {
+                SLEEP(1);
+                save_flags(flags);
+                cli();
+                icn_release_channel();
 #ifdef BOOT_DEBUG
-		printk(KERN_DEBUG "Map Bank 8\n");
+                printk(KERN_DEBUG "Map Bank 8\n");
 #endif
-		icn_map_channel(2);	/* Select Bank 8   */
-		icn_lock_channel(2);	/* Lock Bank 8     */
-		restore_flags(flags);
-		SLEEP(1);
-		memcpy_fromfs(dev->shmem, buffer, ICN_CODE_STAGE1);	/* Copy code       */
+                icn_map_channel(card,2);                           /* Select Bank 8   */
+                icn_lock_channel(card,2);                          /* Lock Bank 8     */
+                restore_flags(flags);
+                SLEEP(1);
+                memcpy_fromfs(dev.shmem, buffer, ICN_CODE_STAGE1); /* Copy code       */
 #ifdef BOOT_DEBUG
-		printk(KERN_DEBUG "Bootloader transfered\n");
+                printk(KERN_DEBUG "Bootloader transfered\n");
 #endif
-	}
-	SLEEP(1);
-	OUTB_P(0xff, ICN_RUN);	/* Start Boot-Code */
-	if ((ret = icn_check_loader(dev->doubleS0 ? 2 : 1)))
-		return ret;
-	if (!dev->doubleS0)
-		return 0;
-	/* reached only, if we have a Double-S0-Card */
-	save_flags(flags);
-	cli();
+        }
+        SLEEP(1);
+        OUTB_P(0xff, ICN_RUN);                                     /* Start Boot-Code */
+        if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1)))
+                return ret;
+        if (!card->doubleS0)
+                return 0;
+        /* reached only, if we have a Double-S0-Card */
+        save_flags(flags);
+        cli();
 #ifdef BOOT_DEBUG
-	printk(KERN_DEBUG "Map Bank 0\n");
+        printk(KERN_DEBUG "Map Bank 0\n");
 #endif
-	icn_map_channel(0);		/* Select Bank 0   */
-	icn_lock_channel(0);	/* Lock Bank 0     */
-	restore_flags(flags);
-	SLEEP(1);
-	return (icn_check_loader(1));
-}
-
-static int icn_loadproto(u_char * buffer, icn_dev * ldev)
-{
-	register u_char *p = buffer;
-	uint left = ICN_CODE_STAGE2;
-	uint cnt;
-	int timer;
-	int ret;
-	unsigned long flags;
+        icn_map_channel(card,0);                                   /* Select Bank 0   */
+        icn_lock_channel(card,0);                                  /* Lock Bank 0     */
+        restore_flags(flags);
+        SLEEP(1);
+        return (icn_check_loader(1));
+}
+
+static int icn_loadproto(u_char * buffer, icn_card * card)
+{
+        register u_char *p = buffer;
+        uint left = ICN_CODE_STAGE2;
+        uint cnt;
+        int timer;
+        int ret;
+        unsigned long flags;
 
 #ifdef BOOT_DEBUG
-	printk(KERN_DEBUG "icn_loadproto called\n");
+        printk(KERN_DEBUG "icn_loadproto called\n");
 #endif
-	if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2)))
-		return ret;
-	timer = 0;
-	save_flags(flags);
-	cli();
-	if (ldev->secondhalf) {
-		icn_map_channel(2);
-		icn_lock_channel(2);
-	} else {
-		icn_map_channel(0);
-		icn_lock_channel(0);
-	}
-	restore_flags(flags);
-	while (left) {
-		if (sbfree) {	/* If there is a free buffer...  */
-			cnt = MIN(256, left);
-			memcpy_fromfs(&sbuf_l, p, cnt);		/* copy data                     */
-			sbnext;	/* switch to next buffer         */
-			p += cnt;
-			left -= cnt;
-			timer = 0;
-		} else {
+        if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2)))
+                return ret;
+        timer = 0;
+        save_flags(flags);
+        cli();
+        if (card->secondhalf) {
+                icn_map_channel(card, 2);
+                icn_lock_channel(card, 2);
+        } else {
+                icn_map_channel(card, 0);
+                icn_lock_channel(card, 0);
+        }
+        restore_flags(flags);
+        while (left) {
+                if (sbfree) {                           /* If there is a free buffer...  */
+                        cnt = MIN(256, left);
+                        memcpy_fromfs(&sbuf_l, p, cnt); /* copy data                     */
+                        sbnext;                         /* switch to next buffer         */
+                        p += cnt;
+                        left -= cnt;
+                        timer = 0;
+                } else {
 #ifdef BOOT_DEBUG
-			printk(KERN_DEBUG "boot 2 !sbfree\n");
+                        printk(KERN_DEBUG "boot 2 !sbfree\n");
 #endif
-			if (timer++ > 5) {
-				icn_maprelease_channel(0);
-				return -EIO;
-			}
-			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + 10;
-			schedule();
-		}
-	}
-	sbuf_n = 0x20;
-	timer = 0;
-	while (1) {
-		if (cmd_o || cmd_i) {
+                        if (timer++ > 5) {
+                                icn_maprelease_channel(card, 0);
+                                return -EIO;
+                        }
+                        current->state = TASK_INTERRUPTIBLE;
+                        current->timeout = jiffies + 10;
+                        schedule();
+                }
+        }
+        sbuf_n = 0x20;
+        timer = 0;
+        while (1) {
+                if (cmd_o || cmd_i) {
 #ifdef BOOT_DEBUG
-			printk(KERN_DEBUG "Proto?\n");
+                        printk(KERN_DEBUG "Proto?\n");
 #endif
-			if (timer++ > 5) {
-				printk(KERN_WARNING "icn: Protocol timed out.\n");
+                        if (timer++ > 5) {
+                                printk(KERN_WARNING
+                                       "icn: (%s) Protocol timed out.\n",
+                                       CID);
 #ifdef BOOT_DEBUG
-				printk(KERN_DEBUG "Proto TO!\n");
+                                printk(KERN_DEBUG "Proto TO!\n");
 #endif
-				icn_maprelease_channel(0);
-				return -EIO;
-			}
+                                icn_maprelease_channel(card, 0);
+                                return -EIO;
+                        }
 #ifdef BOOT_DEBUG
-			printk(KERN_DEBUG "Proto TO?\n");
+                        printk(KERN_DEBUG "Proto TO?\n");
 #endif
-			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-			schedule();
-		} else {
-			if ((ldev->secondhalf) || (!dev->doubleS0)) {
-				save_flags(flags);
-				cli();
+                        current->state = TASK_INTERRUPTIBLE;
+                        current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+                        schedule();
+                } else {
+                        if ((card->secondhalf) || (!card->doubleS0)) {
+                                save_flags(flags);
+                                cli();
 #ifdef BOOT_DEBUG
-				printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
-				       ldev->secondhalf);
+                                printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
+                                       card->secondhalf);
 #endif
-				init_timer(&dev->st_timer);
-				dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-				dev->st_timer.function = icn_pollcard;
-				add_timer(&dev->st_timer);
-				restore_flags(flags);
-			}
-			icn_maprelease_channel(0);
-			return 0;
-		}
-	}
+                                init_timer(&card->st_timer);
+                                card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+                                card->st_timer.function = icn_polldchan;
+                                card->st_timer.data = (unsigned long)card;
+                                add_timer(&card->st_timer);
+                                card->flags |= ICN_FLAGS_RUNNING;
+                                if (card->doubleS0) {
+                                        init_timer(&card->other->st_timer);
+                                        card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+                                        card->other->st_timer.function = icn_polldchan;
+                                        card->other->st_timer.data = (unsigned long)card->other;
+                                        add_timer(&card->other->st_timer);
+                                        card->other->flags |= ICN_FLAGS_RUNNING;
+                                }
+                                restore_flags(flags);
+                        }
+                        icn_maprelease_channel(card, 0);
+                        return 0;
+                }
+        }
 }
-#endif				/* !LOADEXTERN */
 
 /* Read the Status-replies from the Interface */
-static int icn_readstatus(u_char * buf, int len, int user, icn_dev * dev)
+static int icn_readstatus(u_char * buf, int len, int user, icn_card * card)
 {
-	int count;
-	u_char *p;
+        int count;
+        u_char *p;
 
-	for (p = buf, count = 0; count < len; p++, count++) {
-                if (dev->msg_buf_read == dev->msg_buf_write)
+        for (p = buf, count = 0; count < len; p++, count++) {
+                if (card->msg_buf_read == card->msg_buf_write)
                         return count;
-		if (user)
-			put_fs_byte(*dev->msg_buf_read++, p);
-		else
-			*p = *dev->msg_buf_read++;
-		if (dev->msg_buf_read > dev->msg_buf_end)
-			dev->msg_buf_read = dev->msg_buf;
-	}
-	return count;
+                if (user)
+                        put_fs_byte(*card->msg_buf_read++, p);
+                else
+                        *p = *card->msg_buf_read++;
+                if (card->msg_buf_read > card->msg_buf_end)
+                        card->msg_buf_read = card->msg_buf;
+        }
+        return count;
 }
 
 /* Put command-strings into the command-queue of the Interface */
-static int icn_writecmd(const u_char * buf, int len, int user, icn_dev * dev, int waitflg)
+static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card, int waitflg)
 {
-	int mch = dev->secondhalf ? 2 : 0;
-	int avail;
-	int pp;
-	int i;
-	int count;
-	int ocount;
-	unsigned long flags;
-	u_char *p;
-	isdn_ctrl cmd;
-	u_char msg[0x100];
-
-	while (1) {
-		if (icn_trymaplock_channel(mch)) {
-			avail = cmd_free;
-			count = MIN(avail, len);
-			if (user)
-				memcpy_fromfs(msg, buf, count);
-			else
-				memcpy(msg, buf, count);
-			save_flags(flags);
-			cli();
-			ocount = 1;
-			*dev->msg_buf_write++ = '>';
-			if (dev->msg_buf_write > dev->msg_buf_end)
-				dev->msg_buf_write = dev->msg_buf;
-			for (p = msg, pp = cmd_i, i = count; i > 0; i--, p++, pp++) {
-				dev->shmem->comm_buffers.pcio_buf[pp & 0xff] = (*p == '\n') ? 0xff : *p;
-				*dev->msg_buf_write++ = *p;
-				if ((*p == '\n') && (i > 1)) {
-					*dev->msg_buf_write++ = '>';
-					if (dev->msg_buf_write > dev->msg_buf_end)
-						dev->msg_buf_write = dev->msg_buf;
-					ocount++;
-				}
-				/* No checks for buffer overflow of raw-status-device */
-				if (dev->msg_buf_write > dev->msg_buf_end)
-					dev->msg_buf_write = dev->msg_buf;
-				ocount++;
-			}
-			restore_flags(flags);
-			cmd.command = ISDN_STAT_STAVAIL;
-			cmd.driver = dev->myid;
-			cmd.arg = ocount;
-			dev->interface.statcallb(&cmd);
-			cmd_i = (cmd_i + count) & 0xff;
-			icn_release_channel();
-			waitflg = 0;
-		} else
-			count = 0;
-		if (!waitflg)
-			break;
-		current->timeout = jiffies + 10;
-		schedule();
-	}
-	return count;
+        int mch = card->secondhalf ? 2 : 0;
+        int avail;
+        int pp;
+        int i;
+        int count;
+        int ocount;
+        unsigned long flags;
+        u_char *p;
+        isdn_ctrl cmd;
+        u_char msg[0x100];
+
+        while (1) {
+                if (icn_trymaplock_channel(card, mch)) {
+                        avail = cmd_free;
+                        count = MIN(avail, len);
+                        if (user)
+                                memcpy_fromfs(msg, buf, count);
+                        else
+                                memcpy(msg, buf, count);
+                        save_flags(flags);
+                        cli();
+                        ocount = 1;
+                        *card->msg_buf_write++ = '>';
+                        if (card->msg_buf_write > card->msg_buf_end)
+                                card->msg_buf_write = card->msg_buf;
+                        for (p = msg, pp = cmd_i, i = count; i > 0; i--, p++, pp++) {
+                                dev.shmem->comm_buffers.pcio_buf[pp & 0xff] = (*p == '\n') ? 0xff : *p;
+                                *card->msg_buf_write++ = *p;
+                                if ((*p == '\n') && (i > 1)) {
+                                        *card->msg_buf_write++ = '>';
+                                        if (card->msg_buf_write > card->msg_buf_end)
+                                                card->msg_buf_write = card->msg_buf;
+                                        ocount++;
+                                }
+                                /* No checks for buffer overflow of raw-status-device */
+                                if (card->msg_buf_write > card->msg_buf_end)
+                                        card->msg_buf_write = card->msg_buf;
+                                ocount++;
+                        }
+                        restore_flags(flags);
+                        cmd.command = ISDN_STAT_STAVAIL;
+                        cmd.driver = card->myid;
+                        cmd.arg = ocount;
+                        card->interface.statcallb(&cmd);
+                        cmd_i = (cmd_i + count) & 0xff;
+                        icn_release_channel();
+                        waitflg = 0;
+                } else
+                        count = 0;
+                if (!waitflg)
+                        break;
+                current->timeout = jiffies + 10;
+                schedule();
+        }
+        return count;
 }
 
-static void icn_stopdriver(icn_dev * ldev)
+/*
+ * Delete card's pending timers, send STOP to linklevel
+ */
+static void icn_stopcard(icn_card * card)
 {
-	unsigned long flags;
-	isdn_ctrl cmd;
+        unsigned long flags;
+        isdn_ctrl cmd;
 
-	save_flags(flags);
-	cli();
-	del_timer(&dev->st_timer);
-	del_timer(&ldev->rb_timer);
-	cmd.command = ISDN_STAT_STOP;
-	cmd.driver = ldev->myid;
-	ldev->interface.statcallb(&cmd);
-	restore_flags(flags);
-}
-
-static int my_atoi(char *s)
-{
-	int i, n;
-
-	n = 0;
-	if (!s)
-		return -1;
-	for (i = 0; *s >= '0' && *s <= '9'; i++, s++)
-		n = 10 * n + (*s - '0');
-	return n;
-}
-
-static int icn_command(isdn_ctrl * c, icn_dev * ldev)
-{
-	ulong a;
-	ulong flags;
-	int i;
-	char cbuf[60];
-	isdn_ctrl cmd;
-
-	switch (c->command) {
-	case ISDN_CMD_IOCTL:
-		memcpy(&a, c->num, sizeof(ulong));
-		switch (c->arg) {
-		case ICN_IOCTL_SETMMIO:
-			if ((unsigned long) dev->shmem != (a & 0x0ffc000)) {
-				if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
-					printk(KERN_WARNING "icn: memory at 0x%08lx in use.\n",
-					       (ulong) (a & 0x0ffc000));
-					return -EINVAL;
-				}
-				icn_stopdriver(dev);
-				if (dev->doubleS0)
-					icn_stopdriver(dev2);
-				save_flags(flags);
-				cli();
-				if (dev->mvalid)
-					release_shmem((ulong) dev->shmem, 0x4000);
-				dev->mvalid = 0;
-				dev->shmem = (icn_shmem *) (a & 0x0ffc000);
-				if (dev->doubleS0)
-					dev2->shmem = (icn_shmem *) (a & 0x0ffc000);
-				restore_flags(flags);
-				printk(KERN_INFO "icn: mmio set to 0x%08lx\n",
-				       (unsigned long) dev->shmem);
-			}
-			break;
-		case ICN_IOCTL_GETMMIO:
-			return (int) dev->shmem;
-		case ICN_IOCTL_SETPORT:
-			if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
-			    || a == 0x340 || a == 0x350 || a == 0x360 ||
-			    a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
-			    || a == 0x348 || a == 0x358 || a == 0x368) {
-				if (dev->port != (unsigned short) a) {
-					if (check_region((unsigned short) a, ICN_PORTLEN)) {
-						printk(KERN_WARNING "icn: ports 0x%03x-0x%03x in use.\n",
-						       (int) a, (int) a + ICN_PORTLEN);
-						return -EINVAL;
-					}
-					icn_stopdriver(dev);
-					if (dev->doubleS0)
-						icn_stopdriver(dev2);
-					save_flags(flags);
-					cli();
-					if (dev->rvalid)
-						release_region(dev->port, ICN_PORTLEN);
-					dev->port = (unsigned short) a;
-					dev->rvalid = 0;
-					if (dev->doubleS0) {
-						dev2->port = (unsigned short) a;
-						dev2->rvalid = 0;
-					}
-					restore_flags(flags);
-					printk(KERN_INFO "icn: port set to 0x%03x\n", dev->port);
-				}
-			} else
-				return -EINVAL;
-			break;
-		case ICN_IOCTL_GETPORT:
-			return (int) dev->port;
-		case ICN_IOCTL_GETDOUBLE:
-			return (int) dev->doubleS0;
-		case ICN_IOCTL_DEBUGVAR:
-			return (ulong) ldev;
-#ifndef LOADEXTERN
-		case ICN_IOCTL_LOADBOOT:
-			icn_stopdriver(dev);
-			if (dev->doubleS0)
-				icn_stopdriver(dev2);
-			return (icn_loadboot((u_char *) a, dev));
-		case ICN_IOCTL_LOADPROTO:
-			icn_stopdriver(dev);
-			if (dev->doubleS0)
-				icn_stopdriver(dev2);
-			if ((i = (icn_loadproto((u_char *) a, dev))))
-				return i;
-			if (dev->doubleS0)
-				i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), dev2);
-			return i;
-#endif
-		case ICN_IOCTL_LEASEDCFG:
-			if (a) {
-				if (!ldev->leased) {
-					ldev->leased = 1;
-					while (ldev->ptype == ISDN_PTYPE_UNKNOWN) {
-						current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-						schedule();
-					}
-					current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-					schedule();
-					sprintf(cbuf, "00;FV2ON\n01;EAZ1\n");
-					i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-					printk(KERN_INFO "icn: Leased-line mode enabled\n");
-					cmd.command = ISDN_STAT_RUN;
-					cmd.driver = ldev->myid;
-					cmd.arg = 0;
-					ldev->interface.statcallb(&cmd);
-				}
-			} else {
-				if (ldev->leased) {
-					ldev->leased = 0;
-					sprintf(cbuf, "00;FV2OFF\n");
-					i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-					printk(KERN_INFO "icn: Leased-line mode disabled\n");
-					cmd.command = ISDN_STAT_RUN;
-					cmd.driver = ldev->myid;
-					cmd.arg = 0;
-					ldev->interface.statcallb(&cmd);
-				}
-			}
-			return 0;
-		default:
-			return -EINVAL;
-		}
-		break;
-	case ISDN_CMD_DIAL:
-		if (ldev->leased)
-			break;
-		if ((c->arg & 255) < ICN_BCH) {
-			char *p;
-			char *p2;
-			char dial[50];
-			char sis[50];
-			char dcode[4];
-			int si1, si2;
-
-			a = c->arg;
-			strcpy(sis, c->num);
-			p = strrchr(sis, ',');
-			*p++ = '\0';
-			si2 = my_atoi(p);
-			p = strrchr(sis, ',') + 1;
-			si1 = my_atoi(p);
-			p = c->num;
-			if (*p == 's' || *p == 'S') {
-				/* Dial for SPV */
-				p++;
-				strcpy(dcode, "SCA");
-			} else
-				/* Normal Dial */
-				strcpy(dcode, "CAL");
-			strcpy(dial, p);
-			p = strchr(dial, ',');
-			*p++ = '\0';
-			p2 = strchr(p, ',');
-			*p2 = '\0';
-			sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1,
-				si2, p);
-			i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-		}
-		break;
-	case ISDN_CMD_ACCEPTD:
-		if (c->arg < ICN_BCH) {
-			a = c->arg + 1;
-			sprintf(cbuf, "%02d;DCON_R\n", (int) a);
-			i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-		}
-		break;
-	case ISDN_CMD_ACCEPTB:
-		if (c->arg < ICN_BCH) {
-			a = c->arg + 1;
-			sprintf(cbuf, "%02d;BCON_R\n", (int) a);
-			i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-		}
-		break;
-	case ISDN_CMD_HANGUP:
-		if (c->arg < ICN_BCH) {
-			a = c->arg + 1;
-			sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
-			i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-		}
-		break;
-	case ISDN_CMD_SETEAZ:
-		if (ldev->leased)
-			break;
-		if (c->arg < ICN_BCH) {
-			a = c->arg + 1;
-			if (ldev->ptype == ISDN_PTYPE_EURO) {
-				sprintf(cbuf, "%02d;MS%s%s\n", (int) a, c->num[0] ? "N" : "ALL", c->num);
-			} else
-				sprintf(cbuf, "%02d;EAZ%s\n", (int) a, c->num[0] ? c->num : "0123456789");
-			i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-		}
-		break;
-	case ISDN_CMD_CLREAZ:
-		if (ldev->leased)
-			break;
-		if (c->arg < ICN_BCH) {
-			a = c->arg + 1;
-			if (ldev->ptype == ISDN_PTYPE_EURO)
-				sprintf(cbuf, "%02d;MSNC\n", (int) a);
-			else
-				sprintf(cbuf, "%02d;EAZC\n", (int) a);
-			i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-		}
-		break;
-	case ISDN_CMD_SETL2:
-		if ((c->arg & 255) < ICN_BCH) {
-			a = c->arg;
-			switch (a >> 8) {
-			case ISDN_PROTO_L2_X75I:
-				sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
-				break;
-			case ISDN_PROTO_L2_HDLC:
-				sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
-				break;
-			default:
-				return -EINVAL;
-			}
-			i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
-			ldev->l2_proto[a & 255] = (a >> 8);
-		}
-		break;
-	case ISDN_CMD_GETL2:
-		if ((c->arg & 255) < ICN_BCH)
-			return ldev->l2_proto[c->arg & 255];
-		else
-			return -ENODEV;
-	case ISDN_CMD_SETL3:
-		return 0;
-	case ISDN_CMD_GETL3:
-		if ((c->arg & 255) < ICN_BCH)
-			return ISDN_PROTO_L3_TRANS;
-		else
-			return -ENODEV;
-	case ISDN_CMD_GETEAZ:
-		break;
-	case ISDN_CMD_SETSIL:
-		break;
-	case ISDN_CMD_GETSIL:
-		break;
-	case ISDN_CMD_LOCK:
-		MOD_INC_USE_COUNT;
-		break;
-	case ISDN_CMD_UNLOCK:
-		MOD_DEC_USE_COUNT;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
+        save_flags(flags);
+        cli();
+        if (card->flags & ICN_FLAGS_RUNNING) {
+                card->flags &= ~ICN_FLAGS_RUNNING;
+                del_timer(&card->st_timer);
+                del_timer(&card->rb_timer);
+                cmd.command = ISDN_STAT_STOP;
+                cmd.driver  = card->myid;
+                card->interface.statcallb(&cmd);
+                if (card->doubleS0)
+                        icn_stopcard(card->other);
+        }
+        restore_flags(flags);
+}
+
+static void icn_stopallcards(void)
+{
+        icn_card *p = cards;
+
+        while (p) {
+                icn_stopcard(p);
+                p = p->next;
+        }
+}
+
+static int icn_command(isdn_ctrl * c, icn_card * card)
+{
+        ulong a;
+        ulong flags;
+        int i;
+        char cbuf[60];
+        isdn_ctrl cmd;
+        icn_cdef cdef;
+
+        switch (c->command) {
+        case ISDN_CMD_IOCTL:
+                memcpy(&a, c->num, sizeof(ulong));
+                switch (c->arg) {
+                        case ICN_IOCTL_SETMMIO:
+                                if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {
+                                        if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
+                                                printk(KERN_WARNING
+                                                       "icn: memory at 0x%08lx in use.\n",
+                                                       (ulong) (a & 0x0ffc000));
+                                                return -EINVAL;
+                                        }
+                                        icn_stopallcards();
+                                        save_flags(flags);
+                                        cli();
+                                        if (dev.mvalid)
+                                                release_shmem((ulong) dev.shmem, 0x4000);
+                                        dev.mvalid = 0;
+                                        dev.shmem = (icn_shmem *) (a & 0x0ffc000);
+                                        restore_flags(flags);
+                                        printk(KERN_INFO
+                                               "icn: (%s) mmio set to 0x%08lx\n",
+                                               CID,
+                                               (unsigned long) dev.shmem);
+                                }
+                                break;
+                        case ICN_IOCTL_GETMMIO:
+                                return (int) dev.shmem;
+                        case ICN_IOCTL_SETPORT:
+                                if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
+                                    || a == 0x340 || a == 0x350 || a == 0x360 ||
+                                    a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
+                                    || a == 0x348 || a == 0x358 || a == 0x368) {
+                                        if (card->port != (unsigned short) a) {
+                                                if (check_region((unsigned short) a, ICN_PORTLEN)) {
+                                                        printk(KERN_WARNING
+                                                               "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+                                                               CID, (int) a, (int) a + ICN_PORTLEN);
+                                                        return -EINVAL;
+                                                }
+                                                icn_stopcard(card);
+                                                save_flags(flags);
+                                                cli();
+                                                if (card->rvalid)
+                                                        release_region(card->port, ICN_PORTLEN);
+                                                card->port = (unsigned short) a;
+                                                card->rvalid = 0;
+                                                if (card->doubleS0) {
+                                                        card->other->port = (unsigned short) a;
+                                                        card->other->rvalid = 0;
+                                                }
+                                                restore_flags(flags);
+                                                printk(KERN_INFO
+                                                       "icn: (%s) port set to 0x%03x\n",
+                                                       CID, card->port);
+                                        }
+                                } else
+                                        return -EINVAL;
+                                break;
+                        case ICN_IOCTL_GETPORT:
+                                return (int) card->port;
+                        case ICN_IOCTL_GETDOUBLE:
+                                return (int) card->doubleS0;
+                        case ICN_IOCTL_DEBUGVAR:
+                                return (ulong) card;
+                        case ICN_IOCTL_LOADBOOT:
+                                icn_stopcard(card);
+                                return (icn_loadboot((u_char *) a, card));
+                        case ICN_IOCTL_LOADPROTO:
+                                icn_stopcard(card);
+                                if ((i = (icn_loadproto((u_char *) a, card))))
+                                        return i;
+                                if (card->doubleS0)
+                                        i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other);
+                                return i;
+                                break;
+                        case ICN_IOCTL_ADDCARD:
+                                if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef))))
+                                        return i;
+                                memcpy_fromfs((char *)&cdef, (char *)a, sizeof(cdef));
+                                return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
+                                break;
+                        case ICN_IOCTL_LEASEDCFG:
+                                if (a) {
+                                        if (!card->leased) {
+                                                card->leased = 1;
+                                                while (card->ptype == ISDN_PTYPE_UNKNOWN) {
+                                                        current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+                                                        schedule();
+                                                }
+                                                current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+                                                schedule();
+                                                sprintf(cbuf, "00;FV2ON\n01;EAZ1\n");
+                                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                                printk(KERN_INFO
+                                                       "icn: (%s) Leased-line mode enabled\n",
+                                                       CID);
+                                                cmd.command = ISDN_STAT_RUN;
+                                                cmd.driver = card->myid;
+                                                cmd.arg = 0;
+                                                card->interface.statcallb(&cmd);
+                                        }
+                                } else {
+                                        if (card->leased) {
+                                                card->leased = 0;
+                                                sprintf(cbuf, "00;FV2OFF\n");
+                                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                                printk(KERN_INFO
+                                                       "icn: (%s) Leased-line mode disabled\n",
+                                                       CID);
+                                                cmd.command = ISDN_STAT_RUN;
+                                                cmd.driver = card->myid;
+                                                cmd.arg = 0;
+                                                card->interface.statcallb(&cmd);
+                                        }
+                                }
+                                return 0;
+                        default:
+                                return -EINVAL;
+                }
+                break;
+                case ISDN_CMD_DIAL:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if (card->leased)
+                                break;
+                        if ((c->arg & 255) < ICN_BCH) {
+                                char *p;
+                                char *p2;
+                                char dial[50];
+                                char sis[50];
+                                char dcode[4];
+                                int si1, si2;
+                                
+                                a = c->arg;
+                                strcpy(sis, c->num);
+                                p = strrchr(sis, ',');
+                                *p++ = '\0';
+                                si2 = simple_strtoul(p,NULL,10);
+                                p = strrchr(sis, ',') + 1;
+                                si1 = simple_strtoul(p,NULL,10);
+                                p = c->num;
+                                if (*p == 's' || *p == 'S') {
+                                        /* Dial for SPV */
+                                        p++;
+                                        strcpy(dcode, "SCA");
+                                } else
+                                        /* Normal Dial */
+                                        strcpy(dcode, "CAL");
+                                strcpy(dial, p);
+                                p = strchr(dial, ',');
+                                *p++ = '\0';
+                                p2 = strchr(p, ',');
+                                *p2 = '\0';
+                                sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1,
+                                        si2, p);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                        }
+                        break;
+                case ISDN_CMD_ACCEPTD:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if (c->arg < ICN_BCH) {
+                                a = c->arg + 1;
+                                if (card->fw_rev >= 300) {
+                                        switch (card->l2_proto[a-1]) {
+                                                case ISDN_PROTO_L2_X75I:
+                                                        sprintf(cbuf, "%02d;BX75\n", (int) a);
+                                                        break;
+                                                case ISDN_PROTO_L2_HDLC:
+                                                        sprintf(cbuf, "%02d;BTRA\n", (int) a);
+                                                        break;
+                                        }
+                                        i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                }
+                                sprintf(cbuf, "%02d;DCON_R\n", (int) a);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                        }
+                        break;
+                case ISDN_CMD_ACCEPTB:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if (c->arg < ICN_BCH) {
+                                a = c->arg + 1;
+                                if (card->fw_rev >= 300)
+                                        switch (card->l2_proto[a-1]) {
+                                                case ISDN_PROTO_L2_X75I:
+                                                        sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
+                                                        break;
+                                                case ISDN_PROTO_L2_HDLC:
+                                                        sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
+                                                        break;
+                                        }
+                                else
+                                        sprintf(cbuf, "%02d;BCON_R\n", (int) a);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                        }
+                        break;
+                case ISDN_CMD_HANGUP:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if (c->arg < ICN_BCH) {
+                                a = c->arg + 1;
+                                sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                        }
+                        break;
+                case ISDN_CMD_SETEAZ:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if (card->leased)
+                                break;
+                        if (c->arg < ICN_BCH) {
+                                a = c->arg + 1;
+                                if (card->ptype == ISDN_PTYPE_EURO) {
+                                        sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
+                                                c->num[0] ? "N" : "ALL", c->num);
+                                } else
+                                        sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
+                                                c->num[0] ? c->num : "0123456789");
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                        }
+                        break;
+                case ISDN_CMD_CLREAZ:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if (card->leased)
+                                break;
+                        if (c->arg < ICN_BCH) {
+                                a = c->arg + 1;
+                                if (card->ptype == ISDN_PTYPE_EURO)
+                                        sprintf(cbuf, "%02d;MSNC\n", (int) a);
+                                else
+                                        sprintf(cbuf, "%02d;EAZC\n", (int) a);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                        }
+                        break;
+                case ISDN_CMD_SETL2:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if ((c->arg & 255) < ICN_BCH) {
+                                a = c->arg;
+                                switch (a >> 8) {
+                                        case ISDN_PROTO_L2_X75I:
+                                                sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
+                                                break;
+                                        case ISDN_PROTO_L2_HDLC:
+                                                sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
+                                                break;
+                                        default:
+                                                return -EINVAL;
+                                }
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                card->l2_proto[a & 255] = (a >> 8);
+                        }
+                        break;
+                case ISDN_CMD_GETL2:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if ((c->arg & 255) < ICN_BCH)
+                                return card->l2_proto[c->arg & 255];
+                        else
+                                return -ENODEV;
+                case ISDN_CMD_SETL3:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        return 0;
+                case ISDN_CMD_GETL3:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        if ((c->arg & 255) < ICN_BCH)
+                                return ISDN_PROTO_L3_TRANS;
+                        else
+                                return -ENODEV;
+                case ISDN_CMD_GETEAZ:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        break;
+                case ISDN_CMD_SETSIL:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        break;
+                case ISDN_CMD_GETSIL:
+                        if (!card->flags & ICN_FLAGS_RUNNING)
+                                return -ENODEV;
+                        break;
+                case ISDN_CMD_LOCK:
+                        MOD_INC_USE_COUNT;
+                        break;
+                case ISDN_CMD_UNLOCK:
+                        MOD_DEC_USE_COUNT;
+                        break;
+                default:
+                        return -EINVAL;
+        }
+        return 0;
 }
 
 /*
- * For second half of doubleS0-Card add channel-offset.
+ * Find card with given driverId
  */
-static int if_command1(isdn_ctrl * c)
+static inline icn_card *
+  icn_findcard(int driverid)
 {
-	return (icn_command(c, dev));
-}
+        icn_card *p = cards;
 
-static int if_command2(isdn_ctrl * c)
-{
-	return (icn_command(c, dev2));
+        while (p) {
+                if (p->myid == driverid)
+                        return p;
+                p = p->next;
+        }
+        return (icn_card *)0;
 }
 
-static int if_writecmd1(const u_char * buf, int len, int user)
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int if_command(isdn_ctrl * c)
 {
-	return (icn_writecmd(buf, len, user, dev, 0));
-}
+        icn_card *card = icn_findcard(c->driver);
 
-static int if_writecmd2(const u_char * buf, int len, int user)
-{
-	return (icn_writecmd(buf, len, user, dev2, 0));
+        if (card)
+                return (icn_command(c, card));
+        printk(KERN_ERR
+               "icn: if_command called with invalid driverId!\n");
+        return -ENODEV;
 }
 
-static int if_readstatus1(u_char * buf, int len, int user)
+static int if_writecmd(const u_char * buf, int len, int user, int id, int channel)
 {
-	return (icn_readstatus(buf, len, user, dev));
+        icn_card *card = icn_findcard(id);
+
+        if (card) {
+                if (!card->flags & ICN_FLAGS_RUNNING)
+                        return -ENODEV;
+                return (icn_writecmd(buf, len, user, card, 0));
+        }
+        printk(KERN_ERR
+               "icn: if_writecmd called with invalid driverId!\n");
+        return -ENODEV;
 }
 
-static int if_readstatus2(u_char * buf, int len, int user)
+static int if_readstatus(u_char * buf, int len, int user, int id, int channel)
 {
-	return (icn_readstatus(buf, len, user, dev2));
+        icn_card *card = icn_findcard(id);
+
+        if (card) {
+                if (!card->flags & ICN_FLAGS_RUNNING)
+                        return -ENODEV;
+                return (icn_readstatus(buf, len, user, card));
+        }
+        printk(KERN_ERR
+               "icn: if_readstatus called with invalid driverId!\n");
+        return -ENODEV;
 }
 
-static int if_sendbuf1(int id, int channel, const u_char * buffer, int len,
-		       int user)
+static int if_sendbuf(int id, int channel, struct sk_buff *skb)
 {
-	return (icn_sendbuf(channel, buffer, len, user, dev));
+        icn_card *card = icn_findcard(id);
+
+        if (card) {
+                if (!card->flags & ICN_FLAGS_RUNNING)
+                        return -ENODEV;
+                return (icn_sendbuf(channel, skb, card));
+        }
+        printk(KERN_ERR
+               "icn: if_readstatus called with invalid driverId!\n");
+        return -ENODEV;
 }
 
-static int if_sendbuf2(int id, int channel, const u_char * buffer, int len,
-		       int user)
-{
-	return (icn_sendbuf(channel, buffer, len, user, dev2));
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list and register it at linklevel.
+ */
+static icn_card *icn_initcard(int port, char *id) {
+        icn_card *card;
+        int i;
+
+        if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
+                printk(KERN_WARNING
+                       "icn: (%s) Could not allocate card-struct.\n", id);
+                return (icn_card *)0;
+        }
+        memset((char *) card, 0, sizeof(icn_card));
+        card->port = port;
+        card->interface.channels = ICN_BCH;
+        card->interface.maxbufsize = 4000;
+        card->interface.command = if_command;
+	/*
+        card->interface.writebuf = if_sendbuf;
+	*/
+	card->interface.writebuf_skb = if_sendbuf;
+        card->interface.writecmd = if_writecmd;
+        card->interface.readstat = if_readstatus;
+        card->interface.features = ISDN_FEATURE_L2_X75I |
+                ISDN_FEATURE_L2_HDLC |
+                ISDN_FEATURE_L3_TRANS |
+                ISDN_FEATURE_P_UNKNOWN;
+        card->ptype = ISDN_PTYPE_UNKNOWN;
+        strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+        card->msg_buf_write = card->msg_buf;
+        card->msg_buf_read = card->msg_buf;
+        card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
+        for (i=0;i<ICN_BCH;i++) {
+                card->l2_proto[i] = ISDN_PROTO_L2_X75I;
+                skb_queue_head_init(&card->spqueue[i]);
+        }
+        card->next = cards;
+        cards = card;
+        if (!register_isdn(&card->interface)) {
+                cards = cards->next;
+                printk(KERN_WARNING
+                       "icn: Unable to register %s\n", id);
+                kfree(card);
+                return (icn_card*)0;
+        }
+        card->myid = card->interface.channels;
+        sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
+        return card;
+}
+
+static int icn_addcard(int port, char *id1, char *id2)
+{
+        ulong flags;
+        icn_card *card;
+        icn_card *card2;
+
+        save_flags(flags);
+        cli();
+        if (!(card = icn_initcard(port,id1))) {
+                restore_flags(flags);
+                return -EIO;
+        }
+        if (!strlen(id2)) {
+                restore_flags(flags);
+                printk(KERN_INFO
+                       "icn: (%s) ICN-2B, port 0x%x added\n",
+                       card->interface.id, port);
+                return 0;
+        }
+        if (!(card2 = icn_initcard(port,id2))) {
+                restore_flags(flags);
+                printk(KERN_INFO
+                       "icn: (%s) half ICN-4B, port 0x%x added\n",
+                       card2->interface.id, port);
+                return 0;
+        }
+        card->doubleS0 = 1;
+        card->secondhalf = 0;
+        card->other = card2;
+        card2->doubleS0 = 1;
+        card2->secondhalf = 1;
+        card2->other = card;
+        restore_flags(flags);
+        printk(KERN_INFO
+               "icn: (%s and %s) ICN-4B, port 0x%x added\n",
+               card->interface.id, card2->interface.id, port);
+        return 0;
 }
 
 #ifdef MODULE
@@ -1355,158 +1523,81 @@
 #else
 void icn_setup(char *str, int *ints)
 {
-	char *p;
-	static char sid[20];
-	static char sid2[20];
-
-	if (ints[0])
-		portbase = ints[1];
-	if (ints[0]>1)
-		membase  = ints[2];
-	if (strlen(str)) {
-		strcpy(sid,str);
-		icn_id = sid;
-		if ((p = strchr(sid,','))) {
-			*p++ = 0;
-			strcpy(sid2,p);
-			icn_id2 = sid2;
-		}
-	}
+        char *p;
+        static char sid[20];
+        static char sid2[20];
+
+        if (ints[0])
+                portbase = ints[1];
+        if (ints[0]>1)
+                membase = ints[2];
+        if (strlen(str)) {
+                strcpy(sid,str);
+                icn_id = sid;
+                if ((p = strchr(sid,','))) {
+                        *p++ = 0;
+                        strcpy(sid2,p);
+                        icn_id2 = sid2;
+                }
+        }
 }
 #endif
 
 int icn_init(void)
 {
-#ifdef LOADEXTERN
-	unsigned long flags;
-#endif
-	char *p;
-	isdn_ctrl cmd;
-	char rev[10];
-
-	if (!(dev = (icn_devptr) kmalloc(sizeof(icn_dev), GFP_KERNEL))) {
-		printk(KERN_WARNING "icn: Could not allocate device-struct.\n");
-		return -EIO;
-	}
-	memset((char *) dev, 0, sizeof(icn_dev));
-	dev->port = portbase;
-	dev->shmem = (icn_shmem *) (membase & 0x0ffc000);
-	if (strlen(icn_id2))
-		dev->doubleS0 = 1;
-	dev->interface.channels = ICN_BCH;
-	dev->interface.maxbufsize = 4000;
-	dev->interface.command = if_command1;
-	dev->interface.writebuf = if_sendbuf1;
-	dev->interface.writecmd = if_writecmd1;
-	dev->interface.readstat = if_readstatus1;
-	dev->interface.features = ISDN_FEATURE_L2_X75I |
-                ISDN_FEATURE_L2_HDLC |
-                ISDN_FEATURE_L3_TRANS |
-                ISDN_FEATURE_P_UNKNOWN;
-	dev->ptype = ISDN_PTYPE_UNKNOWN;
-	strncpy(dev->interface.id, icn_id, sizeof(dev->interface.id) - 1);
-	dev->msg_buf_write = dev->msg_buf;
-	dev->msg_buf_read = dev->msg_buf;
-	dev->msg_buf_end = &dev->msg_buf[sizeof(dev->msg_buf) - 1];
-	memset((char *) dev->l2_proto, ISDN_PROTO_L2_X75I, sizeof(dev->l2_proto));
-	if (strlen(icn_id2)) {
-		if (!(dev2 = (icn_devptr) kmalloc(sizeof(icn_dev), GFP_KERNEL))) {
-			printk(KERN_WARNING "icn: Could not allocate device-struct.\n");
-			kfree(dev);
-			kfree(dev2);
-			return -EIO;
-		}
-		memcpy((char *) dev2, (char *) dev, sizeof(icn_dev));
-		dev2->interface.command = if_command2;
-		dev2->interface.writebuf = if_sendbuf2;
-		dev2->interface.writecmd = if_writecmd2;
-		dev2->interface.readstat = if_readstatus2;
-		strncpy(dev2->interface.id, icn_id2,
-                        sizeof(dev->interface.id) - 1);
-		dev2->msg_buf_write = dev2->msg_buf;
-		dev2->msg_buf_read = dev2->msg_buf;
-		dev2->msg_buf_end = &dev2->msg_buf[sizeof(dev2->msg_buf) - 1];
-		dev2->secondhalf = 1;
-	}
-	if (!register_isdn(&dev->interface)) {
-		printk(KERN_WARNING "icn: Unable to register\n");
-		kfree(dev);
-		if (dev->doubleS0)
-			kfree(dev2);
-		return -EIO;
-	}
-	dev->myid = dev->interface.channels;
-	sprintf(regname, "icn-isdn (%s)", dev->interface.id);
-	if (dev->doubleS0) {
-		if (!register_isdn(&dev2->interface)) {
-			printk(KERN_WARNING "icn: Unable to register\n");
-			kfree(dev2);
-			if (dev->doubleS0) {
-				icn_stopdriver(dev);
-				cmd.command = ISDN_STAT_UNLOAD;
-				cmd.driver = dev->myid;
-				dev->interface.statcallb(&cmd);
-				kfree(dev);
-			}
-			return -EIO;
-		}
-		dev2->myid = dev2->interface.channels;
-	}
-	
-	/* No symbols to export, hide all symbols */
-	register_symtab(NULL);
-
-	if ((p = strchr(revision, ':'))) {
-		strcpy(rev, p + 1);
-		p = strchr(rev, '$');
-		*p = 0;
-	} else
-		strcpy(rev, " ??? ");
-	printk(KERN_NOTICE "ICN-ISDN-driver Rev%sport=0x%03x mmio=0x%08x id='%s'\n",
-	       rev, dev->port, (uint) dev->shmem, dev->interface.id);
-#ifdef LOADEXTERN
-	save_flags(flags);
-	cli();
-	init_timer(&dev->st_timer);
-	dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-	dev->st_timer.function = icn_pollcard;
-	add_timer(&dev->st_timer);
-	restore_flags(flags);
-#endif
-	return 0;
+        char *p;
+        char rev[10];
+
+        memset(&dev, 0, sizeof(icn_dev));
+        dev.shmem = (icn_shmem *) (membase & 0x0ffc000);
+
+        /* No symbols to export, hide all symbols */
+        register_symtab(NULL);
+
+        if ((p = strchr(revision, ':'))) {
+                strcpy(rev, p + 1);
+                p = strchr(rev, '$');
+                *p = 0;
+        } else
+                strcpy(rev, " ??? ");
+        printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08x\n", rev,
+               (uint) dev.shmem);
+        return (icn_addcard(portbase,icn_id,icn_id2));
 }
 
 #ifdef MODULE
 void cleanup_module(void)
 {
-	isdn_ctrl cmd;
-	int i;
-
-	icn_stopdriver(dev);
-	cmd.command = ISDN_STAT_UNLOAD;
-	cmd.driver = dev->myid;
-	dev->interface.statcallb(&cmd);
-	if (dev->doubleS0) {
-		icn_stopdriver(dev2);
-		cmd.command = ISDN_STAT_UNLOAD;
-		cmd.driver = dev2->myid;
-		dev2->interface.statcallb(&cmd);
-	}
-	if (dev->rvalid) {
-		OUTB_P(0, ICN_RUN);	/* Reset Controller     */
-		OUTB_P(0, ICN_MAPRAM);	/* Disable RAM          */
-		release_region(dev->port, ICN_PORTLEN);
-	}
-	if (dev->mvalid)
-		release_shmem((ulong) dev->shmem, 0x4000);
-	if (dev->doubleS0) {
-		for (i = 0; i < ICN_BCH; i++)
-			icn_free_queue(&dev2->spqueue[1]);
-		kfree(dev2);
-	}
-	for (i = 0; i < ICN_BCH; i++)
-		icn_free_queue(&dev->spqueue[1]);
-	kfree(dev);
-	printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
+        isdn_ctrl cmd;
+        icn_card *card = cards;
+        icn_card *last;
+        int i;
+
+        icn_stopallcards();
+        while (card) {
+                cmd.command = ISDN_STAT_UNLOAD;
+                cmd.driver = card->myid;
+                card->interface.statcallb(&cmd);
+                if (card->rvalid) {
+                        OUTB_P(0, ICN_RUN);    /* Reset Controller     */
+                        OUTB_P(0, ICN_MAPRAM); /* Disable RAM          */
+                        if (card->secondhalf || (!card->doubleS0)) {
+                                release_region(card->port, ICN_PORTLEN);
+                                card->rvalid = 0;
+                        }
+                        for (i = 0; i < ICN_BCH; i++)
+                                icn_free_queue(&card->spqueue[i]);
+                }
+                card = card->next;
+        }
+        card = card;
+        while (card) {
+                last = card;
+                card = card->next;
+                kfree(last);
+        }
+        if (dev.mvalid)
+                release_shmem((ulong) dev.shmem, 0x4000);
+        printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
 }
 #endif
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h
--- pre2.0.5/linux/drivers/isdn/icn/icn.h	Sun Apr 21 19:22:06 1996
+++ linux/drivers/isdn/icn/icn.h	Sun May 19 16:15:17 1996
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.13 1996/04/20 16:51:41 fritz Exp $
+/* $Id: icn.h,v 1.17 1996/05/18 00:47:04 fritz Exp $
  *
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
@@ -19,6 +19,21 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: icn.h,v $
+ * Revision 1.17  1996/05/18 00:47:04  fritz
+ * Removed callback debug code.
+ *
+ * Revision 1.16  1996/05/17 15:46:43  fritz
+ * Removed own queue management.
+ * Changed queue management to use sk_buffs.
+ *
+ * Revision 1.15  1996/05/02 04:01:57  fritz
+ * Removed ICN_MAXCARDS
+ *
+ * Revision 1.14  1996/05/02 00:40:29  fritz
+ * Major rewrite to support more than one card
+ * with a single module.
+ * Support for new firmware.
+ *
  * Revision 1.13  1996/04/20 16:51:41  fritz
  * Increased status buffer.
  * Misc. typos
@@ -75,6 +90,14 @@
 #define ICN_IOCTL_LEASEDCFG 6
 #define ICN_IOCTL_GETDOUBLE 7
 #define ICN_IOCTL_DEBUGVAR  8
+#define ICN_IOCTL_ADDCARD   9
+
+/* Struct for adding new cards */
+typedef struct icn_cdef {
+        int port;
+        char id1[10];
+        char id2[10];
+} icn_cdef;
 
 #if defined(__KERNEL__) || defined(__DEBUGVAR__)
 
@@ -98,7 +121,7 @@
 #include <linux/wait.h>
 #include <linux/isdnif.h>
 
-#endif				/* __KERNEL__ */
+#endif /* __KERNEL__ */
 
 /* some useful macros for debugging */
 #ifdef ICN_DEBUG_PORT
@@ -112,177 +135,190 @@
 #define ICN_PORTLEN (0x04)
 #define ICN_MEMADDR 0x0d0000
 
-/* Macros for accessing ports */
-#define ICN_CFG    (dev->port)
-#define ICN_MAPRAM (dev->port+1)
-#define ICN_RUN    (dev->port+2)
-#define ICN_BANK   (dev->port+3)
-
-#define ICN_FLAGS_B1ACTIVE 1	/* B-Channel-1 is open                 */
-#define ICN_FLAGS_B2ACTIVE 2	/* B-Channel-2 is open                 */
-#define ICN_FLAGS_RBTIMER  8	/* cyclic scheduling of B-Channel-poll */
-
-#define ICN_BOOT_TIMEOUT1  100	/* Delay for Boot-download (jiffies)   */
-#define ICN_CHANLOCK_DELAY  10	/* Delay for Channel-mapping (jiffies) */
-
-#define ICN_TIMER_BCREAD 3	/* B-Channel poll-cycle                */
-#define ICN_TIMER_DCREAD 50	/* D-Channel poll-cycle                */
-
-#define ICN_CODE_STAGE1 4096	/* Size of bootcode                    */
-#define ICN_CODE_STAGE2 65536	/* Size of protocol-code               */
-
-#define ICN_MAX_SQUEUE 65536	/* Max. outstanding send-data          */
-#define ICN_FRAGSIZE (250)	/* Max. size of send-fragments         */
-#define ICN_BCH 2		/* Number of supported channels        */
+#define ICN_FLAGS_B1ACTIVE 1     /* B-Channel-1 is open                     */
+#define ICN_FLAGS_B2ACTIVE 2     /* B-Channel-2 is open                     */
+#define ICN_FLAGS_RUNNING  4     /* Cards driver activated                  */
+#define ICN_FLAGS_RBTIMER  8     /* cyclic scheduling of B-Channel-poll     */
+
+#define ICN_BOOT_TIMEOUT1  100   /* Delay for Boot-download (jiffies)       */
+#define ICN_CHANLOCK_DELAY  10   /* Delay for Channel-mapping (jiffies)     */
+
+#define ICN_TIMER_BCREAD 3       /* B-Channel poll-cycle                    */
+#define ICN_TIMER_DCREAD 50      /* D-Channel poll-cycle                    */
+
+#define ICN_CODE_STAGE1 4096     /* Size of bootcode                        */
+#define ICN_CODE_STAGE2 65536    /* Size of protocol-code                   */
+
+#define ICN_MAX_SQUEUE 65536     /* Max. outstanding send-data              */
+#define ICN_FRAGSIZE (250)       /* Max. size of send-fragments             */
+#define ICN_BCH 2                /* Number of supported channels per card   */
 
 /* type-definitions for accessing the mmap-io-areas */
 
-#define SHM_DCTL_OFFSET (0)	/* Offset to data-controlstructures in shm */
-#define SHM_CCTL_OFFSET (0x1d2)	/* Offset to comm-controlstructures in shm */
-#define SHM_CBUF_OFFSET (0x200)	/* Offset to comm-buffers in shm           */
-#define SHM_DBUF_OFFSET (0x2000)	/* Offset to data-buffers in shm           */
+#define SHM_DCTL_OFFSET (0)      /* Offset to data-controlstructures in shm */
+#define SHM_CCTL_OFFSET (0x1d2)  /* Offset to comm-controlstructures in shm */
+#define SHM_CBUF_OFFSET (0x200)  /* Offset to comm-buffers in shm           */
+#define SHM_DBUF_OFFSET (0x2000) /* Offset to data-buffers in shm           */
 
+/*
+ * Layout of card's data buffers
+ */
 typedef struct {
-	unsigned char length;	/* Bytecount of fragment (max 250)     */
-	unsigned char endflag;	/* 0=last frag., 0xff=frag. continued  */
-	unsigned char data[ICN_FRAGSIZE];	/* The data                            */
-	/* Fill to 256 bytes */
-	char unused[0x100 - ICN_FRAGSIZE - 2];
+        unsigned char length;             /* Bytecount of fragment (max 250)    */
+        unsigned char endflag;            /* 0=last frag., 0xff=frag. continued */
+        unsigned char data[ICN_FRAGSIZE]; /* The data                           */
+        /* Fill to 256 bytes */
+        char unused[0x100 - ICN_FRAGSIZE - 2];
 } frag_buf;
 
+/*
+ * Layout of card's shared memory
+ */
 typedef union {
-	struct {
-		unsigned char scns;	/* Index to free SendFrag.             */
-		unsigned char scnr;	/* Index to active SendFrag   READONLY */
-		unsigned char ecns;	/* Index to free RcvFrag.     READONLY */
-		unsigned char ecnr;	/* Index to valid RcvFrag              */
-		char unused[6];
-		unsigned short fuell1;	/* Internal Buf Bytecount              */
-	} data_control;
-	struct {
-		char unused[SHM_CCTL_OFFSET];
-		unsigned char iopc_i;	/* Read-Ptr Status-Queue      READONLY */
-		unsigned char iopc_o;	/* Write-Ptr Status-Queue              */
-		unsigned char pcio_i;	/* Write-Ptr Command-Queue             */
-		unsigned char pcio_o;	/* Read-Ptr Command Queue     READONLY */
-	} comm_control;
-	struct {
-		char unused[SHM_CBUF_OFFSET];
-		unsigned char pcio_buf[0x100];	/* Ring-Buffer Command-Queue           */
-		unsigned char iopc_buf[0x100];	/* Ring-Buffer Status-Queue            */
-	} comm_buffers;
-	struct {
-		char unused[SHM_DBUF_OFFSET];
-		frag_buf receive_buf[0x10];
-		frag_buf send_buf[0x10];
-	} data_buffers;
+        struct {
+                unsigned char scns;            /* Index to free SendFrag.             */
+                unsigned char scnr;            /* Index to active SendFrag   READONLY */
+                unsigned char ecns;            /* Index to free RcvFrag.     READONLY */
+                unsigned char ecnr;            /* Index to valid RcvFrag              */
+                char unused[6];
+                unsigned short fuell1;         /* Internal Buf Bytecount              */
+        } data_control;
+        struct {
+                char unused[SHM_CCTL_OFFSET];
+                unsigned char iopc_i;          /* Read-Ptr Status-Queue      READONLY */
+                unsigned char iopc_o;          /* Write-Ptr Status-Queue              */
+                unsigned char pcio_i;          /* Write-Ptr Command-Queue             */
+                unsigned char pcio_o;          /* Read-Ptr Command Queue     READONLY */
+        } comm_control;
+        struct {
+                char unused[SHM_CBUF_OFFSET];
+                unsigned char pcio_buf[0x100]; /* Ring-Buffer Command-Queue           */
+                unsigned char iopc_buf[0x100]; /* Ring-Buffer Status-Queue            */
+        } comm_buffers;
+        struct {
+                char unused[SHM_DBUF_OFFSET];
+                frag_buf receive_buf[0x10];
+                frag_buf send_buf[0x10];
+        } data_buffers;
 } icn_shmem;
 
-/* Sendbuffer-queue-element */
-typedef struct {
-	char *next;
-	short length;
-	short size;
-	u_char *rptr;
-	u_char buffer[1];
-} pqueue;
+/*
+ * Per card driver data
+ */
+typedef struct icn_card {
+        struct icn_card *next;        /* Pointer to next device struct    */
+        struct icn_card *other;       /* Pointer to other card for ICN4B  */
+        unsigned short port;          /* Base-port-address                */
+        int myid;                     /* Driver-Nr. assigned by linklevel */
+        int rvalid;                   /* IO-portregion has been requested */
+        int leased;                   /* Flag: This Adapter is connected  */
+                                      /*       to a leased line           */
+        unsigned short flags;         /* Statusflags                      */
+        int doubleS0;                 /* Flag: ICN4B                      */
+        int secondhalf;               /* Flag: Second half of a doubleS0  */
+        int fw_rev;                   /* Firmware revision loaded         */
+        int ptype;                    /* Protocol type (1TR6 or Euro)     */
+        struct timer_list st_timer;   /* Timer for Status-Polls           */
+        struct timer_list rb_timer;   /* Timer for B-Channel-Polls        */
+        u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers        */
+        int rcvidx[ICN_BCH];          /* Index for above buffers          */
+        int l2_proto[ICN_BCH];        /* Current layer-2-protocol         */
+        isdn_if interface;            /* Interface to upper layer         */
+        int iptr;                     /* Index to imsg-buffer             */
+        char imsg[60];                /* Internal buf for status-parsing  */
+        char msg_buf[2048];           /* Buffer for status-messages       */
+        char *msg_buf_write;          /* Writepointer for statusbuffer    */
+        char *msg_buf_read;           /* Readpointer for statusbuffer     */
+        char *msg_buf_end;            /* Pointer to end of statusbuffer   */
+        int sndcount[ICN_BCH];        /* Byte-counters for B-Ch.-send     */
+        struct sk_buff_head
+                spqueue[ICN_BCH];     /* Sendqueue                        */
+        char regname[35];             /* Name used for request_region     */
+} icn_card;
 
-typedef struct {
-	unsigned short port;	/* Base-port-address                */
-	icn_shmem *shmem;	/* Pointer to memory-mapped-buffers */
-	int myid;		/* Driver-Nr. assigned by linklevel */
-	int rvalid;		/* IO-portregion has been requested */
-	int mvalid;		/* IO-shmem has been requested      */
-	int leased;		/* Flag: This Adapter is connected  */
-	/*       to a leased line           */
-	unsigned short flags;	/* Statusflags                      */
-	int doubleS0;		/* Flag: Double-S0-Card             */
-	int secondhalf;		/* Flag: Second half of a doubleS0  */
-	int ptype;		/* Protocol type (1TR6 or Euro)     */
-	struct timer_list st_timer;	/* Timer for Status-Polls           */
-	struct timer_list rb_timer;	/* Timer for B-Channel-Polls        */
-	int channel;		/* Currently mapped Channel         */
-	int chanlock;		/* Semaphore for Channel-Mapping    */
-	u_char rcvbuf[ICN_BCH][4096];	/* B-Channel-Receive-Buffers      */
-	int rcvidx[ICN_BCH];	/* Index for above buffers          */
-	int l2_proto[ICN_BCH];	/* Current layer-2-protocol         */
-	isdn_if interface;	/* Interface to upper layer         */
-	int iptr;		/* Index to imsg-buffer             */
-	char imsg[60];		/* Internal buf for status-parsing  */
-	char msg_buf[2048];	/* Buffer for status-messages       */
-	char *msg_buf_write;	/* Writepointer for statusbuffer    */
-	char *msg_buf_read;	/* Readpointer for statusbuffer     */
-	char *msg_buf_end;	/* Pointer to end of statusbuffer   */
-	int sndcount[ICN_BCH];	/* Byte-counters for B-Ch.-send     */
-	pqueue *spqueue[ICN_BCH];	/* Pointers to start of Send-Queue  */
-#ifdef DEBUG_RCVCALLBACK
-	int akt_pending[ICN_BCH];
-	int max_pending[ICN_BCH];
-#endif
+/*
+ * Main driver data
+ */
+typedef struct icn_dev {
+        icn_shmem *shmem;             /* Pointer to memory-mapped-buffers */
+        int mvalid;                   /* IO-shmem has been requested      */
+        int channel;                  /* Currently mapped channel         */
+        struct icn_card *mcard;       /* Currently mapped card            */
+        int chanlock;                 /* Semaphore for channel-mapping    */
 } icn_dev;
 
 typedef icn_dev *icn_devptr;
 
 #ifdef __KERNEL__
-static icn_dev *dev = (icn_dev *) 0;
-static icn_dev *dev2 = (icn_dev *) 0;
+
+static icn_card *cards  = (icn_card *) 0;
+static u_char   chan2bank[] = { 0, 4, 8, 12 }; /* for icn_map_channel() */ 
+
+static icn_dev  dev;
 
 /* With modutils >= 1.1.67 Integers can be changed while loading a
  * module. For this reason define the Port-Base an Shmem-Base as
  * integers.
  */
-int portbase = ICN_BASEADDR;
-int membase = ICN_MEMADDR;
-char *icn_id = "\0";
+int portbase  = ICN_BASEADDR;
+int membase   = ICN_MEMADDR;
+char *icn_id  = "\0";
 char *icn_id2 = "\0";
-static char regname[35];	/* Name used for port/mem-registration */
 
-#endif				/* __KERNEL__ */
+#endif                                /* __KERNEL__ */
 
 /* Utility-Macros */
 
+/* Macros for accessing ports */
+#define ICN_CFG    (card->port)
+#define ICN_MAPRAM (card->port+1)
+#define ICN_RUN    (card->port+2)
+#define ICN_BANK   (card->port+3)
+
 /* Return true, if there is a free transmit-buffer */
-#define sbfree (((dev->shmem->data_control.scns+1) & 0xf) != \
-                dev->shmem->data_control.scnr)
+#define sbfree (((dev.shmem->data_control.scns+1) & 0xf) != \
+                dev.shmem->data_control.scnr)
 
 /* Switch to next transmit-buffer */
-#define sbnext (dev->shmem->data_control.scns = \
-               ((dev->shmem->data_control.scns+1) & 0xf))
+#define sbnext (dev.shmem->data_control.scns = \
+               ((dev.shmem->data_control.scns+1) & 0xf))
 
 /* Shortcuts for transmit-buffer-access */
-#define sbuf_n dev->shmem->data_control.scns
-#define sbuf_d dev->shmem->data_buffers.send_buf[sbuf_n].data
-#define sbuf_l dev->shmem->data_buffers.send_buf[sbuf_n].length
-#define sbuf_f dev->shmem->data_buffers.send_buf[sbuf_n].endflag
+#define sbuf_n dev.shmem->data_control.scns
+#define sbuf_d dev.shmem->data_buffers.send_buf[sbuf_n].data
+#define sbuf_l dev.shmem->data_buffers.send_buf[sbuf_n].length
+#define sbuf_f dev.shmem->data_buffers.send_buf[sbuf_n].endflag
 
 /* Return true, if there is receive-data is available */
-#define rbavl  (dev->shmem->data_control.ecnr != \
-                dev->shmem->data_control.ecns)
+#define rbavl  (dev.shmem->data_control.ecnr != \
+                dev.shmem->data_control.ecns)
 
 /* Switch to next receive-buffer */
-#define rbnext (dev->shmem->data_control.ecnr = \
-               ((dev->shmem->data_control.ecnr+1) & 0xf))
+#define rbnext (dev.shmem->data_control.ecnr = \
+               ((dev.shmem->data_control.ecnr+1) & 0xf))
 
 /* Shortcuts for receive-buffer-access */
-#define rbuf_n dev->shmem->data_control.ecnr
-#define rbuf_d dev->shmem->data_buffers.receive_buf[rbuf_n].data
-#define rbuf_l dev->shmem->data_buffers.receive_buf[rbuf_n].length
-#define rbuf_f dev->shmem->data_buffers.receive_buf[rbuf_n].endflag
+#define rbuf_n dev.shmem->data_control.ecnr
+#define rbuf_d dev.shmem->data_buffers.receive_buf[rbuf_n].data
+#define rbuf_l dev.shmem->data_buffers.receive_buf[rbuf_n].length
+#define rbuf_f dev.shmem->data_buffers.receive_buf[rbuf_n].endflag
 
 /* Shortcuts for command-buffer-access */
-#define cmd_o (dev->shmem->comm_control.pcio_o)
-#define cmd_i (dev->shmem->comm_control.pcio_i)
+#define cmd_o (dev.shmem->comm_control.pcio_o)
+#define cmd_i (dev.shmem->comm_control.pcio_i)
 
 /* Return free space in command-buffer */
 #define cmd_free ((cmd_i>=cmd_o)?0x100-cmd_i+cmd_o:cmd_o-cmd_i)
 
 /* Shortcuts for message-buffer-access */
-#define msg_o (dev->shmem->comm_control.iopc_o)
-#define msg_i (dev->shmem->comm_control.iopc_i)
+#define msg_o (dev.shmem->comm_control.iopc_o)
+#define msg_i (dev.shmem->comm_control.iopc_i)
 
 /* Return length of Message, if avail. */
 #define msg_avail ((msg_o>msg_i)?0x100-msg_o+msg_i:msg_i-msg_o)
 
+#define CID (card->interface.id)
+
 #define MIN(a,b) ((a<b)?a:b)
 #define MAX(a,b) ((a>b)?a:b)
 
@@ -294,5 +330,5 @@
 #define release_shmem release_region
 #define request_shmem request_region
 
-#endif				/* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif				/* icn_h */
+#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif /* icn_h */
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c
--- pre2.0.5/linux/drivers/isdn/isdn_audio.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/isdn/isdn_audio.c	Sun May 19 15:29:29 1996
@@ -0,0 +1,428 @@
+/* $Id: isdn_audio.c,v 1.4 1996/05/17 03:48:01 fritz Exp $
+ *
+ * Linux ISDN subsystem, audio conversion and compression (linklevel).
+ *
+ * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * $Log: isdn_audio.c,v $
+ * Revision 1.4  1996/05/17 03:48:01  fritz
+ * Removed some test statements.
+ * Added revision string.
+ *
+ * Revision 1.3  1996/05/10 08:48:11  fritz
+ * Corrected adpcm bugs.
+ *
+ * Revision 1.2  1996/04/30 09:31:17  fritz
+ * General rewrite.
+ *
+ * Revision 1.1.1.1  1996/04/28 12:25:40  fritz
+ * Taken under CVS control
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/isdn.h>
+#include "isdn_audio.h"
+
+char *isdn_audio_revision        = "$Revision: 1.4 $";
+
+/*
+ * Misc. lookup-tables.
+ */
+
+/* ulaw -> signed 16-bit */
+static short isdn_audio_ulaw_to_s16[] = {
+        0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
+        0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
+        0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
+        0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
+        0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
+        0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
+        0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
+        0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
+        0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
+        0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
+        0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
+        0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
+        0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
+        0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
+        0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
+        0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
+        0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
+        0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
+        0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
+        0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
+        0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
+        0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
+        0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
+        0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
+        0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
+        0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
+        0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
+        0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
+        0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
+        0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
+        0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
+        0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
+};
+
+/* alaw -> signed 16-bit */
+static short isdn_audio_alaw_to_s16[] = {
+        0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
+        0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
+        0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
+        0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
+        0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
+        0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
+        0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
+        0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
+        0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
+        0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
+        0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
+        0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
+        0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
+        0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
+        0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
+        0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
+        0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
+        0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
+        0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
+        0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
+        0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
+        0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
+        0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
+        0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
+        0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
+        0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
+        0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
+        0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
+        0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
+        0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
+        0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
+        0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
+};
+
+/* alaw -> ulaw */
+static char isdn_audio_alaw_to_ulaw[] = {
+        0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
+        0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
+        0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
+        0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
+        0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
+        0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
+        0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
+        0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
+        0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
+        0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
+        0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
+        0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
+        0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
+        0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
+        0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
+        0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
+        0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
+        0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
+        0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
+        0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
+        0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
+        0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
+        0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
+        0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
+        0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
+        0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
+        0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
+        0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
+        0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
+        0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
+        0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
+        0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
+};
+
+/* ulaw -> alaw */
+static char isdn_audio_ulaw_to_alaw[] = {
+        0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
+        0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
+        0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
+        0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
+        0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
+        0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
+        0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
+        0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
+        0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
+        0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
+        0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
+        0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
+        0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
+        0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
+        0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
+        0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
+        0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
+        0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
+        0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
+        0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
+        0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
+        0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
+        0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
+        0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
+        0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
+        0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
+        0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
+        0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
+        0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
+        0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
+        0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
+        0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
+};
+
+#if ((CPU == 386) || (CPU == 486) || (CPU == 586))
+static inline void
+isdn_audio_tlookup(const void *table, void *buff, unsigned long n)
+{
+        __asm__("cld\n"
+                "1:\tlodsb\n\t"
+                "xlatb\n\t"
+                "stosb\n\t"
+                "loop 1b\n\t"
+                ::"b" ((long)table), "c" (n), "D" ((long)buff), "S" ((long)buff)
+                :"bx","cx","di","si","ax");
+}
+#else
+static inline void
+isdn_audio_tlookup(const char *table, char *buff, unsigned long n)
+{
+        while (n--) 
+                *buff++ = table[*buff];
+}
+#endif
+
+void
+isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
+{
+        isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
+}
+
+void
+isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
+{
+        isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
+}
+
+/*
+ * linear <-> adpcm conversion stuff
+ * Most parts from the mgetty-package.
+ * (C) by Gert Doering and Klaus Weidner
+ * Used by permission of Gert Doering
+ */
+
+
+#define ZEROTRAP    /* turn on the trap as per the MIL-STD */
+#undef ZEROTRAP
+#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
+#define CLIP 32635
+
+static unsigned char
+isdn_audio_linear2ulaw(int sample) {
+        static int exp_lut[256] = {
+                0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+                4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+                5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+                5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+                6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+                6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+                6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+                6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+        };
+        int sign, exponent, mantissa;
+        unsigned char ulawbyte;
+
+        /* Get the sample into sign-magnitude. */
+        sign = (sample >> 8) & 0x80;      /* set aside the sign  */
+        if(sign != 0) sample = -sample;   /* get magnitude       */
+        if(sample > CLIP) sample = CLIP;  /* clip the magnitude  */
+
+        /* Convert from 16 bit linear to ulaw. */
+        sample = sample + BIAS;
+        exponent = exp_lut[( sample >> 7 ) & 0xFF];
+        mantissa = (sample >> (exponent + 3)) & 0x0F;
+        ulawbyte = ~(sign | (exponent << 4) | mantissa);
+#ifdef ZEROTRAP
+        /* optional CCITT trap */
+        if (ulawbyte == 0) ulawbyte = 0x02;
+#endif
+        return(ulawbyte);
+}
+
+
+static int Mx[3][8] = {
+        { 0x3800, 0x5600, 0,0,0,0,0,0 },
+        { 0x399a, 0x3a9f, 0x4d14, 0x6607, 0,0,0,0 },
+        { 0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607 },
+};
+
+static int bitmask[9] = {
+        0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
+}; 
+
+static int
+isdn_audio_get_bits (adpcm_state *s, unsigned char **in, int *len)
+{
+        while( s->nleft < s->nbits) {
+                int d = *((*in)++);
+                (*len)--;
+                s->word = (s->word << 8) | d;
+                s->nleft += 8;
+        }
+        s->nleft -= s->nbits;
+        return (s->word >> s->nleft) & bitmask[s->nbits];
+}
+
+static void
+isdn_audio_put_bits (int data, int nbits, adpcm_state *s,
+                     unsigned char **out, int *len)
+{
+        s->word = (s->word << nbits) | (data & bitmask[nbits]);
+        s->nleft += nbits;
+        while(s->nleft >= 8) {
+                int d = (s->word >> (s->nleft-8));
+                *(out[0]++) = d & 255;
+                (*len)++;
+                s->nleft -= 8;
+        }
+}
+
+adpcm_state *
+isdn_audio_adpcm_init(int nbits)
+{
+static adpcm_state *s;
+
+#ifdef ATEST
+        s = (adpcm_state *) malloc(sizeof(adpcm_state));
+#else
+        s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
+#endif
+        if (s) {
+                s->a     = 0;
+                s->d     = 5;
+                s->word  = 0;
+                s->nleft = 0;
+                s->nbits = nbits;
+        }
+        return s;
+}
+
+/*
+ * Decompression of adpcm data to a/u-law
+ *
+ */
+ 
+int
+isdn_audio_adpcm2xlaw (adpcm_state *s, int fmt, unsigned char *in,
+                      unsigned char *out, int len)
+{
+        int a = s->a;
+        int d = s->d;
+        int nbits = s->nbits;
+        int olen = 0;
+        
+        while (len) {
+                int e = isdn_audio_get_bits(s, &in, &len);
+                int sign;
+
+                if (nbits == 4 && e == 0)
+                        d = 4;
+                sign = (e >> (nbits-1))?-1:1;
+                e &= bitmask[nbits-1];
+                a += sign * ((e << 1) + 1) * d >> 1;
+                if (d & 1)
+                        a++;
+                if (fmt)
+                        *out++ = isdn_audio_ulaw_to_alaw[
+                                 isdn_audio_linear2ulaw(a << 2)];
+                else
+                        *out++ = isdn_audio_linear2ulaw(a << 2);
+                olen++;
+                d = (d * Mx[nbits-2][ e ] + 0x2000) >> 14;
+                if ( d < 5 )
+                        d = 5;     
+        }
+        s->a = a;
+        s->d = d;
+        return olen;
+}
+
+int
+isdn_audio_2adpcm_flush (adpcm_state *s, unsigned char *out)
+{
+	int olen = 0;
+
+        if (s->nleft)
+                isdn_audio_put_bits(0, 8-s->nleft, s, &out, &olen);
+        return olen;
+}
+
+int
+isdn_audio_xlaw2adpcm (adpcm_state *s, int fmt, unsigned char *in,
+                      unsigned char *out, int len)
+{
+        int a = s->a;
+        int d = s->d;
+        int nbits = s->nbits;
+        int olen = 0;
+
+        while (len--) {
+                int e = 0, nmax = 1 << (nbits - 1);
+                int sign, delta;
+              
+                if (fmt)
+                        delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
+                else
+                        delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
+                if (delta < 0) {
+                        e = nmax;
+                        delta = -delta;
+                }
+                while( --nmax && delta > d ) {
+                        delta -= d;
+                        e++;
+                }
+                if (nbits == 4 && ((e & 0x0f) == 0))
+                        e = 8;
+                isdn_audio_put_bits(e, nbits, s, &out, &olen);
+                sign = (e >> (nbits-1))?-1:1 ;
+                e &= bitmask[nbits-1];
+                
+                a += sign * ((e << 1) + 1) * d >> 1;
+                if (d & 1)
+                        a++;
+                d = (d * Mx[nbits-2][ e ] + 0x2000) >> 14;
+                if (d < 5)
+                        d=5;
+        }
+	s->a = a;
+	s->d = d;
+        return olen;
+}
+
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_audio.h linux/drivers/isdn/isdn_audio.h
--- pre2.0.5/linux/drivers/isdn/isdn_audio.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/isdn/isdn_audio.h	Sun May 19 15:29:29 1996
@@ -0,0 +1,43 @@
+/* $Id: isdn_audio.h,v 1.2 1996/05/10 08:48:32 fritz Exp $
+ *
+ * Linux ISDN subsystem, audio conversion and compression (linklevel).
+ *
+ * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * $Log: isdn_audio.h,v $
+ * Revision 1.2  1996/05/10 08:48:32  fritz
+ * Corrected adpcm bugs.
+ *
+ * Revision 1.1  1996/04/30 09:29:06  fritz
+ * Taken under CVS control.
+ *
+ */
+
+typedef struct adpcm_state {
+        int a;
+        int d;
+        int word;
+        int nleft;
+        int nbits;
+} adpcm_state;
+
+extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
+extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
+extern adpcm_state *isdn_audio_adpcm_init(int);
+extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
+extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
+extern int isdn_audio_2adpcm_flush(adpcm_state *s, unsigned char *out);
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- pre2.0.5/linux/drivers/isdn/isdn_common.c	Tue May  7 16:22:26 1996
+++ linux/drivers/isdn/isdn_common.c	Sun May 19 15:29:29 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.5 1996/04/20 16:19:07 fritz Exp $
+/* $Id: isdn_common.c,v 1.14 1996/05/18 01:36:55 fritz Exp $
  *
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -21,6 +21,39 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.14  1996/05/18 01:36:55  fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.13  1996/05/17 15:43:30  fritz
+ * Bugfix: decrement of rcvcount in readbchan() corrected.
+ *
+ * Revision 1.12  1996/05/17 03:55:43  fritz
+ * Changed DLE handling for audio receive.
+ * Some cleanup.
+ * Added display of isdn_audio_revision.
+ *
+ * Revision 1.11  1996/05/11 21:51:32  fritz
+ * Changed queue management to use sk_buffs.
+ *
+ * Revision 1.10  1996/05/10 08:49:16  fritz
+ * Checkin before major changes of tty-code.
+ *
+ * Revision 1.9  1996/05/07 09:19:41  fritz
+ * Adapted to changes in isdn_tty.c
+ *
+ * Revision 1.8  1996/05/06 11:34:51  hipp
+ * fixed a few bugs
+ *
+ * Revision 1.7  1996/05/02 03:55:17  fritz
+ * Bugfixes:
+ *  - B-channel connect message for modem devices
+ *    sometimes did not result in a CONNECT-message.
+ *  - register_isdn did not check for driverId-conflicts.
+ *
+ * Revision 1.6  1996/04/30 20:57:21  fritz
+ * Commit test
+ *
  * Revision 1.5  1996/04/20 16:19:07  fritz
  * Changed slow timer handlers to increase accuracy.
  * Added statistic information for usage by xisdnload.
@@ -48,9 +81,7 @@
  *
  */
 
-#ifndef STANDALONE
 #include <linux/config.h>
-#endif
 #include <linux/module.h>
 #include <linux/version.h>
 #ifndef __GENKSYMS__      /* Don't want genksyms report unneeded structs */
@@ -60,17 +91,18 @@
 #include "isdn_tty.h"
 #include "isdn_net.h"
 #include "isdn_ppp.h"
+#ifdef CONFIG_ISDN_AUDIO
+#include "isdn_audio.h"
+#endif
 #include "isdn_cards.h"
 
-
-
 /* Debugflags */
 #undef  ISDN_DEBUG_STATCALLB
 
 isdn_dev *dev = (isdn_dev *) 0;
 
 static int  has_exported = 0;
-static char *isdn_revision      = "$Revision: 1.5 $";
+static char *isdn_revision      = "$Revision: 1.14 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -79,6 +111,11 @@
 #else
 static char *isdn_ppp_revision = ": none $";
 #endif
+#ifdef CONFIG_ISDN_AUDIO
+extern char *isdn_audio_revision;
+#else
+static char *isdn_audio_revision = ": none $";
+#endif
 
 void isdn_MOD_INC_USE_COUNT(void)
 {
@@ -102,45 +139,23 @@
 }
 #endif
 
-/* Try to allocate a new buffer, link it into queue. */
-u_char *
- isdn_new_buf(pqueue ** queue, int length)
+static __inline void isdn_trash_skb(struct sk_buff *skb, int rw)
 {
-	pqueue *p;
-	pqueue *q;
-
-	if ((p = *queue)) {
-		while (p) {
-			q = p;
-			p = (pqueue *) p->next;
-		}
-		p = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC);
-		q->next = (u_char *) p;
-	} else
-		p = *queue = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC);
-	if (p) {
-		p->size = sizeof(pqueue) + length;
-		p->length = length;
-		p->next = NULL;
-		p->rptr = p->buffer;
-		return p->buffer;
-	} else {
-		return (u_char *) NULL;
-	}
+        skb->free = 1;
+        kfree_skb(skb, rw);
 }
 
-static void isdn_free_queue(pqueue ** queue)
+static void isdn_free_queue(struct sk_buff_head *queue)
 {
-	pqueue *p;
-	pqueue *q;
+        struct sk_buff *skb;
+        unsigned long flags;
 
-	p = *queue;
-	while (p) {
-		q = p;
-		p = (pqueue *) p->next;
-		kfree_s(q, q->size);
-	}
-	*queue = (pqueue *) 0;
+        save_flags(flags);
+        cli();
+        if (skb_queue_len(queue))
+                while ((skb = skb_dequeue(queue)))
+                        isdn_trash_skb(skb, FREE_READ);
+        restore_flags(flags);
 }
 
 int isdn_dc2minor(int di, int ch)
@@ -222,75 +237,107 @@
 	restore_flags(flags);
 }
 
-/* Receive a packet from B-Channel. (Called from low-level-module)
- * Parameters:
- *
- * di      = Driver-Index.
- * channel = Number of B-Channel (0...)
- * buf     = pointer to packet-data
- * len     = Length of packet-data
- *
+/*
+ * Receive a packet from B-Channel. (Called from low-level-module)
  */
-static void isdn_receive_callback(int di, int channel, u_char * buf, int len)
+static void isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
 {
 	ulong flags;
-	char *p;
 	int i;
-	int midx;
-
-	if (dev->global_flags & ISDN_GLOBAL_STOPPED)
-		return;
-        if ((i = isdn_dc2minor(di,channel))==-1)
+        int midx;
+	modem_info *info;
+        
+        if ((i = isdn_dc2minor(di,channel))==-1) {
+                isdn_trash_skb(skb, FREE_READ);
                 return;
+        }
 	/* Update statistics */
-        dev->ibytes[i] += len;
+        dev->ibytes[i] += skb->len;
 	/* First, try to deliver data to network-device */
-	if (isdn_net_receive_callback(i, buf, len))
+	if (isdn_net_rcv_skb(i, skb))
 		return;
 	/* No network-device found, deliver to tty or raw-channel */
-	if (len) {
-		save_flags(flags);
-		cli();
-                midx = dev->m_idx[i];
-                if (dev->mdm.atmodem[midx].mdmreg[13] & 2)
+	if (skb->len) {
+                if ((midx = dev->m_idx[i])<0) {
+                        /* if midx is invalid, drop packet */
+                        isdn_trash_skb(skb, FREE_READ);
+                        return;
+                }
+                info  = &dev->mdm.info[midx];
+                if ((info->online < 2) &&
+                    (info->vonline != 1)) {
+                        /* If Modem not listening, drop data */
+                        isdn_trash_skb(skb, FREE_READ);
+                        return;
+                }
+                if (info->emu.mdmreg[13] & 2)
                         /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
-                        if ((buf[0] == 1) && ((buf[1] == 0) || (buf[1] == 1))) {
+                        if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1))) {
 #ifdef ISDN_DEBUG_MODEM_DUMP
-                                isdn_dumppkt("T70strip1:", buf, len, len);
+                                isdn_dumppkt("T70strip1:", skb->data, skb->len, skb->len);
 #endif
-                                buf += 4;
-                                len -= 4;
+                                skb_pull(skb,4);
 #ifdef ISDN_DEBUG_MODEM_DUMP
-                                isdn_dumppkt("T70strip2:", buf, len, len);
+                                isdn_dumppkt("T70strip2:", skb->data, skb->len, skb->len);
 #endif
                         }
+                /* The users field of an sk_buff is used in a special way
+                 * with tty's incoming data:
+                 *   users is set to the number of DLE codes when in audio mode.
+                 */
+                skb->users = 0;
+#ifdef CONFIG_ISDN_AUDIO
+                if (info->vonline == 1) {
+                        int ifmt = 1;
+                        /* voice conversion/compression */
+                        switch (info->emu.vpar[3]) {
+                                case 2:
+                                case 3:
+                                case 4:
+                                        /* adpcm
+                                         * Since compressed data takes less
+                                         * space, we can overwrite the buffer.
+                                         */
+                                        skb_trim(skb,isdn_audio_xlaw2adpcm(info->adpcmr,
+                                                                           ifmt,
+                                                                           skb->data,
+                                                                           skb->data,
+                                                                           skb->len));
+                                        break;
+                                case 5:
+                                        /* a-law */
+                                        if (!ifmt)
+                                                isdn_audio_ulaw2alaw(skb->data,skb->len);
+                                        break;
+                                case 6:
+                                        /* u-law */
+                                        if (ifmt)
+                                                isdn_audio_alaw2ulaw(skb->data,skb->len);
+                                        break;
+                        }
+                        skb->users = isdn_tty_countDLE(skb->data,skb->len);
+                }
+#endif
                 /* Try to deliver directly via tty-flip-buf if queue is empty */
-                if (!dev->drv[di]->rpqueue[channel])
-                        if (isdn_tty_try_read(midx, buf, len)) {
+                save_flags(flags);
+                cli();
+                if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
+                        if (isdn_tty_try_read(info, skb)) {
                                 restore_flags(flags);
                                 return;
                         }
                 /* Direct deliver failed or queue wasn't empty.
                  * Queue up for later dequeueing via timer-irq.
                  */
-                p = isdn_new_buf(&dev->drv[di]->rpqueue[channel], len);
-                if (!p) {
-                        printk(KERN_WARNING "isdn: malloc of rcvbuf failed, dropping.\n");
-                        dev->drv[di]->rcverr[channel]++;
-                        restore_flags(flags);
-                        return;
-                } else {
-                        memcpy(p, buf, len);
-                        dev->drv[di]->rcvcount[channel] += len;
-                }
+                __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
+                dev->drv[di]->rcvcount[channel] += (skb->len + skb->users);
+                restore_flags(flags);
                 /* Schedule dequeuing */
-                if ((dev->modempoll) && (midx >= 0)) {
-                        if (dev->mdm.rcvsched[midx])
-                                isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-                }
+                if ((dev->modempoll) && (info->rcvsched))
+                        isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
                 wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
-		restore_flags(flags);
-	}
+	} else
+                isdn_trash_skb(skb, FREE_READ);
 }
 
 void isdn_all_eaz(int di, int ch)
@@ -311,6 +358,7 @@
 	ulong flags;
 	int i;
 	int r;
+        modem_info *info;
 	isdn_ctrl cmd;
 
 	di = c->driver;
@@ -323,9 +371,7 @@
                                 return 0;
                         if (isdn_net_stat_callback(i, c->command))
                                 return 0;
-#if FUTURE
                         isdn_tty_bsent(di, c->arg);
-#endif
                         wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
                         break;
                 case ISDN_STAT_STAVAIL:
@@ -366,8 +412,9 @@
                                          * tty and set RI-bit of modem-status.
                                          */
                                         if ((mi = isdn_tty_find_icall(di, c->arg, c->num)) >= 0) {
-                                                dev->mdm.msr[mi] |= UART_MSR_RI;
-                                                isdn_tty_modem_result(2, &dev->mdm.info[mi]);
+                                                info = &dev->mdm.info[mi];
+                                                info->msr |= UART_MSR_RI;
+                                                isdn_tty_modem_result(2, info);
                                                 isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
                                         } else if (dev->drv[di]->reject_bus) {
                                                 cmd.driver = di;
@@ -428,12 +475,14 @@
                         /* Find any network-device, waiting for D-channel setup */
                         if (isdn_net_stat_callback(i, c->command))
                                 break;
-			if ((mi = dev->m_idx[i]) >= 0)
+
+			if ((mi = dev->m_idx[i]) >= 0) {
 				/* If any tty has just dialed-out, setup B-Channel */
-				if (dev->mdm.info[mi].flags &
+                                info = &dev->mdm.info[mi];
+				if (info->flags &
 				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					if (dev->mdm.dialing[mi] == 1) {
-						dev->mdm.dialing[mi] = 2;
+					if (info->dialing == 1) {
+						info->dialing = 2;
 						cmd.driver = di;
 						cmd.arg = c->arg;
 						cmd.command = ISDN_CMD_ACCEPTB;
@@ -441,6 +490,7 @@
 						return 0;
 					}
 				}
+                        }
                         break;
                 case ISDN_STAT_DHUP:
 			if (i<0)
@@ -457,19 +507,19 @@
                                 break;
 			if ((mi = dev->m_idx[i]) >= 0) {
 				/* Signal hangup to tty-device */
-				if (dev->mdm.info[mi].flags &
+                                info = &dev->mdm.info[mi];
+				if (info->flags &
 				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					if (dev->mdm.dialing[mi] == 1) {
-						dev->mdm.dialing[mi] = 0;
-						isdn_tty_modem_result(7, &dev->mdm.info[mi]);
+					if (info->dialing == 1) {
+						info->dialing = 0;
+						isdn_tty_modem_result(7, info);
 					}
-					if (dev->mdm.online[mi])
-						isdn_tty_modem_result(3, &dev->mdm.info[mi]);
+					if (info->online)
+						isdn_tty_modem_result(3, info);
 #ifdef ISDN_DEBUG_MODEM_HUP
 					printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
 #endif
-					isdn_tty_modem_hup(&dev->mdm.info[mi]);
-					dev->mdm.msr[mi] &= ~(UART_MSR_DCD | UART_MSR_RI);
+					isdn_tty_modem_hup(info);
 					return 0;
 				}
 			}
@@ -491,13 +541,17 @@
 				/* Schedule CONNECT-Message to any tty, waiting for it and
 				 * set DCD-bit of its modem-status.
 				 */
-				if (dev->mdm.info[mi].flags &
+                                info = &dev->mdm.info[mi];
+				if (info->flags &
 				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					dev->mdm.msr[mi] |= UART_MSR_DCD;
-					if (dev->mdm.dialing[mi])
-						dev->mdm.dialing[mi] = 0;
-					dev->mdm.rcvsched[mi] = 1;
-					isdn_tty_modem_result(5, &dev->mdm.info[mi]);
+					info->msr |= UART_MSR_DCD;
+					if (info->dialing)
+						info->dialing = 0;
+					info->rcvsched = 1;
+                                        if (USG_MODEM(dev->usage[i]))
+                                          isdn_tty_modem_result(5, info);
+                                        if (USG_VOICE(dev->usage[i]))
+                                          isdn_tty_modem_result(11, info);
 				}
 			}
                         break;
@@ -513,15 +567,16 @@
                         isdn_info_update();
 			if ((mi = dev->m_idx[i]) >= 0) {
 				/* Signal hangup to tty-device, schedule NO CARRIER-message */
-				if (dev->mdm.info[mi].flags &
+                                info = &dev->mdm.info[mi];
+				if (info->flags &
 				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					dev->mdm.msr[mi] &= ~(UART_MSR_DCD | UART_MSR_RI);
-					if (dev->mdm.online[mi])
-						isdn_tty_modem_result(3, &dev->mdm.info[mi]);
+					info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
+					if (info->online)
+						isdn_tty_modem_result(3, info);
 #ifdef ISDN_DEBUG_MODEM_HUP
 					printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
 #endif
-					isdn_tty_modem_hup(&dev->mdm.info[mi]);
+					isdn_tty_modem_hup(info);
 				}
 			}
                         break;
@@ -536,16 +591,17 @@
                         if (isdn_net_stat_callback(i, c->command))
                                 break;
 			if ((mi = dev->m_idx[i]) >= 0) {
-				if (dev->mdm.info[mi].flags &
+                                info = &dev->mdm.info[mi];
+				if (info->flags &
 				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					if (dev->mdm.dialing[mi]) {
-						dev->mdm.dialing[mi] = 0;
-						isdn_tty_modem_result(6, &dev->mdm.info[mi]);
+					if (info->dialing) {
+						info->dialing = 0;
+						isdn_tty_modem_result(6, info);
 					}
-					dev->mdm.msr[mi] &= ~UART_MSR_DCD;
-					if (dev->mdm.online[mi]) {
-						isdn_tty_modem_result(3, &dev->mdm.info[mi]);
-						dev->mdm.online[mi] = 0;
+					info->msr &= ~UART_MSR_DCD;
+					if (info->online) {
+						isdn_tty_modem_result(3, info);
+						info->online = 0;
 					}
 				}
 			}
@@ -569,6 +625,7 @@
                         kfree(dev->drv[di]->rcvcount);
                         for (i = 0; i < dev->drv[di]->channels; i++)
                                 isdn_free_queue(&dev->drv[di]->rpqueue[i]);
+                        kfree(dev->drv[di]->rpqueue);
                         kfree(dev->drv[di]->rcv_waitq);
                         kfree(dev->drv[di]->snd_waitq);
                         kfree(dev->drv[di]);
@@ -595,66 +652,109 @@
 	return v;
 }
 
+#define DLE 0x10
+
+/*
+ * isdn_readbchan() tries to get data from the read-queue.
+ * It MUST be called with interrupts off.
+ */
 int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
 {
-	int avail;
 	int left;
 	int count;
-	int copy_l;
+	int count_pull;
+        int count_put;
 	int dflag;
-	int flags;
-	pqueue *p;
+        struct sk_buff *skb;
 	u_char *cp;
 
-	if (!dev->drv[di]->rpqueue[channel]) {
+	if (!dev->drv[di])
+		return 0;
+	if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
 		if (user)
 			interruptible_sleep_on(&dev->drv[di]->rcv_waitq[channel]);
 		else
 			return 0;
 	}
-	if (!dev->drv[di])
-		return 0;
-	save_flags(flags);
-	cli();
-	avail = dev->drv[di]->rcvcount[channel];
-	restore_flags(flags);
-	left = MIN(len, avail);
+	left = MIN(len, dev->drv[di]->rcvcount[channel]);
 	cp = buf;
 	count = 0;
 	while (left) {
-		if ((copy_l = dev->drv[di]->rpqueue[channel]->length) > left) {
-			copy_l = left;
-			dflag = 0;
-		} else
-			dflag = 1;
-		p = dev->drv[di]->rpqueue[channel];
-		if (user)
-			memcpy_tofs(cp, p->rptr, copy_l);
-		else
-			memcpy(cp, p->rptr, copy_l);
-		if (fp) {
-			memset(fp, 0, copy_l);
-			fp += copy_l;
-		}
-		left -= copy_l;
-		count += copy_l;
-		cp += copy_l;
-		if (dflag) {
+                if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
+                        break;
+                if (skb->lock)
+                        break;
+                skb->lock = 1;
+                if (skb->users) {
+                        /* users is the count of DLE's in
+                         * this buff when in voice mode.
+                         */
+                        char *p = skb->data;
+                        unsigned long DLEmask = (1 << channel);
+
+                        dflag = 0;
+                        count_pull = count_put = 0;
+                        while ((count_pull < skb->len) && (left-- > 0)) {
+                                if (dev->drv[di]->DLEflag & DLEmask) {
+                                        if (user)
+                                                put_fs_byte(DLE,cp++);
+                                        else
+                                                *cp++ = DLE;
+                                        dev->drv[di]->DLEflag &= ~DLEmask;
+                                } else {
+                                        if (user)
+                                                put_fs_byte(*p,cp++);
+                                        else
+                                                *cp++ = *p;
+                                        if (*p == DLE) {
+                                                dev->drv[di]->DLEflag |= DLEmask;
+                                                skb->users--;
+                                        }
+                                        p++;
+                                        count_pull++;
+                                }
+                                count_put++;
+                        }
+                        if (count_pull >= skb->len)
+                                dflag = 1;
+                } else {
+                        /* No DLE's in buff, so simply copy it */
+                        dflag = 1;
+                        if ((count_pull = skb->len) > left) {
+                                count_pull = left;
+                                dflag = 0;
+                        }
+                        count_put = count_pull;
+                        if (user)
+                                memcpy_tofs(cp, skb->data, count_put);
+                        else
+                                memcpy(cp, skb->data, count_put);
+                        cp += count_put;
+                        left -= count_put;
+                }
+                count += count_put;
+                if (fp) {
+                        memset(fp, 0, count_put);
+                        fp += count_put;
+                }
+                if (dflag) {
+                        /* We got all the data in this buff.
+                         * Now we can dequeue it.
+                         */
 			if (fp)
 				*(fp - 1) = 0xff;
-			save_flags(flags);
-			cli();
-			dev->drv[di]->rpqueue[channel] = (pqueue *) p->next;
-			kfree_s(p, p->size);
-			restore_flags(flags);
+                        skb->lock = 0;
+                        skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
+                        isdn_trash_skb(skb, FREE_READ);
 		} else {
-			p->rptr += copy_l;
-			p->length -= copy_l;
-		}
-		save_flags(flags);
-		cli();
-		dev->drv[di]->rcvcount[channel] -= copy_l;
-		restore_flags(flags);
+                        /* Not yet emptied this buff, so it
+                         * must stay in the queue, for further calls
+                         * but we pull off the data we got until now.
+                         */
+			skb_pull(skb,count_pull);
+                        skb->lock = 0;
+                }
+		dev->drv[di]->rcvcount[channel] -= count_put;
 	}
 	return count;
 }
@@ -749,9 +849,7 @@
                                 return -EAGAIN;
 			interruptible_sleep_on(&(dev->info_waitq));
                 }
-		save_flags(flags);
 		p = isdn_statstr();
-		restore_flags(flags);
 		file->private_data = 0;
 		if ((len = strlen(p)) <= count) {
 			memcpy_tofs(buf, p, len);
@@ -769,8 +867,11 @@
 		if (!dev->drv[drvidx]->running)
 			return -ENODEV;
 		chidx = isdn_minor2chan(minor);
+                save_flags(flags);
+                cli();
 		len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1);
 		file->f_pos += len;
+                restore_flags(flags);
 		return len;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
@@ -784,7 +885,8 @@
                 }
 		if (dev->drv[drvidx]->interface->readstat)
 			len = dev->drv[drvidx]->interface->
-			    readstat(buf, MIN(count, dev->drv[drvidx]->stavail), 1);
+			    readstat(buf, MIN(count, dev->drv[drvidx]->stavail),
+				     1, drvidx, isdn_minor2chan(minor));
 		else
 			len = 0;
 		save_flags(flags);
@@ -826,7 +928,6 @@
 		if (!dev->drv[drvidx]->running)
 			return -ENODEV;
 		chidx = isdn_minor2chan(minor);
-                dev->obytes[minor] += count;
 		while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
 			interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
 		return count;
@@ -842,7 +943,8 @@
 		 return -ENODEV;
 		 */
 		if (dev->drv[drvidx]->interface->writecmd)
-			return (dev->drv[drvidx]->interface->writecmd(buf, count, 1));
+			return (dev->drv[drvidx]->interface->
+				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)));
 		else
 			return count;
 	}
@@ -856,6 +958,7 @@
 static int isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
 {
 	uint minor = MINOR(inode->i_rdev);
+        int drvidx  = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 
 	if (minor == ISDN_MINOR_STATUS) {
 		if (file->private_data)
@@ -866,8 +969,18 @@
 			return 0;
 		}
 	}
-	if (minor <= ISDN_MINOR_CTRLMAX)
+	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
+		if (drvidx < 0)
+			return -ENODEV;
+		if (dev->drv[drvidx]->stavail)
+                        return 1;
+                else {
+                        if (st)
+                                select_wait(&(dev->drv[drvidx]->st_waitq), st);
+                        return 0;
+                }
 		return 1;
+	 }
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX)
 		return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st));
@@ -1178,8 +1291,15 @@
                                 memcpy_fromfs(name,(char*)arg,sizeof(name));
                                 return isdn_ppp_dial_slave(name);
                         case IIOCNETDLN:
-                                /* remove one link from bundle; removed for i4l 0.7.1  */
-                                return 2;
+                                if(arg) {
+                                        if ((ret = verify_area(VERIFY_READ,
+                                                               (void*)arg,
+                                                               sizeof(name))))
+                                                return ret;
+                                } else
+                                        return -EINVAL;
+                                memcpy_fromfs(name,(char*)arg,sizeof(name));
+                                return isdn_ppp_hangup_slave(name);
 #endif
                         case IIOCNETHUP:
                                 /* Force hangup of a network-interface */
@@ -1212,7 +1332,8 @@
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg,
                                                                sizeof(isdn_ioctl_struct))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
+                                        memcpy_fromfs((char *) &iocts, (char *) arg,
+                                                      sizeof(isdn_ioctl_struct));
                                         if (strlen(iocts.drvid)) {
                                                 if ((p = strchr(iocts.drvid, ',')))
                                                         *p = 0;
@@ -1260,9 +1381,10 @@
                                                 return ret;
                                         
                                         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                                memcpy_tofs(p, dev->mdm.atmodem[i].profile, ISDN_MODEM_ANZREG);
+                                                memcpy_tofs(p, dev->mdm.info[i].emu.profile,
+                                                            ISDN_MODEM_ANZREG);
                                                 p += ISDN_MODEM_ANZREG;
-                                                memcpy_tofs(p, dev->mdm.atmodem[i].pmsn, ISDN_MSNLEN);
+                                                memcpy_tofs(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN);
                                                 p += ISDN_MSNLEN;
                                         }
                                         return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
@@ -1281,9 +1403,10 @@
                                                 return ret;
                                         
                                         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                                memcpy_fromfs(dev->mdm.atmodem[i].profile, p, ISDN_MODEM_ANZREG);
+                                                memcpy_fromfs(dev->mdm.info[i].emu.profile, p,
+                                                              ISDN_MODEM_ANZREG);
                                                 p += ISDN_MODEM_ANZREG;
-                                                memcpy_fromfs(dev->mdm.atmodem[i].pmsn, p, ISDN_MSNLEN);
+                                                memcpy_fromfs(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN);
                                                 p += ISDN_MSNLEN;
                                         }
                                         return 0;
@@ -1410,6 +1533,7 @@
 
 	if (minor == ISDN_MINOR_STATUS) {
 		infostruct *p;
+
 		if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) {
 			MOD_INC_USE_COUNT;
 			p->next = (char *) dev->infochain;
@@ -1605,7 +1729,8 @@
                         dev->ibytes[i] = 0;
                         dev->obytes[i] = 0;
 			isdn_info_update();
-			restore_flags(flags);
+                        isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
+                        restore_flags(flags);
 			return;
 		}
 	restore_flags(flags);
@@ -1633,54 +1758,62 @@
 }
 
 /*
- *  receive callback handler for drivers supporting sk_buff's.
+ * receive callback handler for drivers not supporting sk_buff's.
+ * Parameters:
+ *
+ * di      = Driver-Index.
+ * channel = Number of B-Channel (0...)
+ * buf     = pointer to packet-data
+ * len     = Length of packet-data
+ *
  */
-
-void isdn_receive_skb_callback(int drvidx, int chan, struct sk_buff *skb) 
+void isdn_receive_callback(int drvidx, int chan, u_char *buf, int len) 
 {
-        int i, len;
+        struct sk_buff *skb;
 
 	if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 		return;
-        if ((i = isdn_dc2minor(drvidx,chan))==-1)
-                return;
-        len = skb->len;
-	if (isdn_net_rcv_skb(i, skb) == 0) {
-		isdn_receive_callback(drvidx, chan, skb->data, skb->len);
-		skb->free = 1;
-		kfree_skb(skb, FREE_READ);
-	} else
-                /* Update statistics */
-                dev->ibytes[i] += len;
+        skb = dev_alloc_skb(len);
+        if (skb) {
+                memcpy(skb_put(skb, len), buf, len);
+                isdn_receive_skb_callback(drvidx, chan, skb);
+        } else
+                printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n");
 }
 
 /*
  *  writebuf replacement for SKB_ABLE drivers
  */
-
 int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len, 
 		       int user)
 {
+	int ret;
+
         if (dev->drv[drvidx]->interface->writebuf)
-          return dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
-                                                       len, user);
+                ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
+                                                            len, user);
         else {
-          struct sk_buff * skb;
+                struct sk_buff * skb;
 
-          skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, GFP_ATOMIC);
-          if (skb == NULL)
-                  return 0;
+                skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len,
+                                GFP_ATOMIC);
+                if (skb == NULL)
+                        return 0;
 
-          skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
-          skb->free = 1;
+                skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
+                skb->free = 1;
 
-          if (user)
-                  memcpy_fromfs(skb_put(skb, len), buf, len);
-          else
-                  memcpy(skb_put(skb, len), buf, len);
+                if (user)
+                        memcpy_fromfs(skb_put(skb, len), buf, len);
+                else
+                        memcpy(skb_put(skb, len), buf, len);
 
-          return dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb);
+                ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
+                                                                chan, skb);
         }
+        if (ret > 0)
+                dev->obytes[isdn_dc2minor(drvidx,chan)] += ret;
+        return ret;
 }
 
 /*
@@ -1703,6 +1836,8 @@
                      writebuf(drvidx,chan,skb->data,skb->len,0))==skb->len)
 		        dev_kfree_skb(skb, FREE_WRITE);
         }
+        if (ret > 0)
+                dev->obytes[isdn_dc2minor(drvidx,chan)] += skb->len;
         return ret;
 }
 
@@ -1750,14 +1885,17 @@
 		return 0;
 	}
 	memset((char *) d->rcvcount, 0, sizeof(int) * n);
-	if (!(d->rpqueue = (pqueue **) kmalloc(sizeof(pqueue *) * n, GFP_KERNEL))) {
-		printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
-		kfree(d->rcvcount);
-		kfree(d->rcverr);
-		kfree(d);
-		return 0;
-	}
-	memset((char *) d->rpqueue, 0, sizeof(pqueue *) * n);
+        if (!(d->rpqueue =
+              (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
+                printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
+                kfree(d->rcvcount);
+                kfree(d->rcverr);
+                kfree(d);
+                return 0;
+        }
+        for (j = 0; j < n; j++) {
+                skb_queue_head_init(&d->rpqueue[j]);
+        }
 	if (!(d->rcv_waitq = (struct wait_queue **)
 	      kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
 		printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
@@ -1799,6 +1937,9 @@
 		sprintf(i->id, "line%d", drvidx);
 	save_flags(flags);
 	cli();
+        for (j = 0; j < drvidx; j++)
+                if (!strcmp(i->id,dev->drvid[j]))
+                    sprintf(i->id, "line%d", drvidx);                    
 	for (j = 0; j < n; j++)
 		for (k = 0; k < ISDN_MAX_CHANNELS; k++)
 			if (dev->chanmap[k] < 0) {
@@ -1894,7 +2035,7 @@
 		tty_unregister_driver(&dev->mdm.tty_modem);
 		tty_unregister_driver(&dev->mdm.cua_modem);
 		for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-			kfree(dev->mdm.info[i].xmit_buf - 4);
+			kfree(dev->mdm.info[i].xmit_buf);
 		unregister_chrdev(ISDN_MAJOR, "isdn");
 		kfree(dev);
 		return -EIO;
@@ -1904,11 +2045,11 @@
         if (!has_exported)
                 isdn_export_syms();
 
-	printk(KERN_NOTICE "ISDN subsystem Rev: %s/%s/%s/%s",
-	       isdn_getrev(isdn_revision),
-	       isdn_getrev(isdn_tty_revision),
-	       isdn_getrev(isdn_net_revision),
-	       isdn_getrev(isdn_ppp_revision));
+	printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(isdn_revision));
+        printk("%s/", isdn_getrev(isdn_tty_revision));
+        printk("%s/", isdn_getrev(isdn_net_revision));
+        printk("%s/", isdn_getrev(isdn_ppp_revision));
+        printk("%s", isdn_getrev(isdn_audio_revision));
 
 #ifdef MODULE
 	printk(" loaded\n");
@@ -1949,8 +2090,10 @@
 		restore_flags(flags);
 		return;
 	}
-	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-		kfree(dev->mdm.info[i].xmit_buf - 4);
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+                isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
+		kfree(dev->mdm.info[i].xmit_buf);
+        }
 	if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
 		printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
 	} else {
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h
--- pre2.0.5/linux/drivers/isdn/isdn_common.h	Sun Apr 21 19:22:06 1996
+++ linux/drivers/isdn/isdn_common.h	Sun May 19 15:29:29 1996
@@ -38,7 +38,6 @@
 #undef  ISDN_DEBUG_AT
 #undef  ISDN_DEBUG_NET_DUMP
 #undef  ISDN_DEBUG_NET_DIAL
-#undef  ISDN_DEBUG_NET_BUILDHDR
 #undef  ISDN_DEBUG_NET_ICALL
 
 /* Prototypes */
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- pre2.0.5/linux/drivers/isdn/isdn_net.c	Tue May  7 16:22:26 1996
+++ linux/drivers/isdn/isdn_net.c	Sun May 19 15:29:29 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.5 1996/04/20 16:28:38 fritz Exp $
+/* $Id: isdn_net.c,v 1.11 1996/05/18 01:36:59 fritz Exp $
  *
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -21,6 +21,25 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.11  1996/05/18 01:36:59  fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.10  1996/05/17 03:49:01  fritz
+ * Some cleanup.
+ *
+ * Revision 1.9  1996/05/06 11:34:57  hipp
+ * fixed a few bugs
+ *
+ * Revision 1.8  1996/04/30 21:04:40  fritz
+ * Test commit
+ *
+ * Revision 1.7  1996/04/30 11:10:42  fritz
+ * Added Michael's ippp-bind patch.
+ *
+ * Revision 1.6  1996/04/30 09:34:35  fritz
+ * Removed compatibility-macros.
+ *
  * Revision 1.5  1996/04/20 16:28:38  fritz
  * Made more parameters of the dial statemachine user-configurable and
  * added hangup after dial for more reliability using callback.
@@ -55,9 +74,7 @@
  *
  */
 
-#ifndef STANDALONE
 #include <linux/config.h>
-#endif
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/isdn.h>
@@ -79,7 +96,9 @@
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
 static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
  
-char *isdn_net_revision = "$Revision: 1.5 $";
+extern void dev_purge_queues(struct device *dev);	/* move this to net/core/dev.c */
+
+char *isdn_net_revision = "$Revision: 1.11 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -143,6 +162,32 @@
 }
 
 /*
+ * unbind a net-interface (resets interface after an error)
+ */
+static void
+isdn_net_unbind_channel(isdn_net_local * lp)
+{
+	ulong flags;
+
+	save_flags(flags);
+	cli();
+        if (lp->first_skb) {
+                dev_kfree_skb(lp->first_skb,FREE_WRITE);
+                lp->first_skb = NULL;
+        }
+	dev_purge_queues(&lp->netdev->dev);
+	lp->dialstate = 0;
+	dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
+	dev->st_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
+	isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
+	lp->flags &= ~ISDN_NET_CONNECTED;
+	lp->isdn_device = -1;
+	lp->isdn_channel = -1;
+
+        restore_flags(flags);
+}
+
+/*
  * Perform auto-hangup and cps-calculation for net-interfaces.
  *
  * auto-hangup:
@@ -232,6 +277,8 @@
 				/* Either D-Channel-hangup or error during dialout */
 				if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
 					lp->flags &= ~ISDN_NET_CONNECTED;
+					if(lp->first_skb)
+						dev_kfree_skb(lp->first_skb,FREE_WRITE);
 					isdn_free_channel(lp->isdn_device, lp->isdn_channel,
                                                           ISDN_USAGE_NET);
 #ifdef CONFIG_ISDN_PPP
@@ -541,6 +588,7 @@
                 dev_kfree_skb(lp->first_skb,FREE_WRITE);
                 lp->first_skb = NULL;
         }
+	dev_purge_queues(d);
 	if (lp->flags & ISDN_NET_CONNECTED) {
 		printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
 		lp->dialstate = 0;
@@ -695,8 +743,10 @@
 
 	/* For the other encaps the header has already been built */
 #ifdef CONFIG_ISDN_PPP
-	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-		return (isdn_ppp_xmit(skb, ndev));
+	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+		ndev->tbusy = ret = isdn_ppp_xmit(skb, ndev);
+		return ret;
+	}
 #endif		
 	/* Reset hangup-timeout */
 	lp->huptimer = 0;
@@ -755,7 +805,6 @@
 {
 	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
 
-
 	if (ndev->tbusy) {
 		if (jiffies - ndev->trans_start < 20)
 			return 1;
@@ -795,6 +844,8 @@
                                                "isdn_net_start_xmit: No channel for %s\n",
                                                ndev->name);
 					restore_flags(flags);
+		/* we probably should drop the skb here and return 0 to omit
+		   'socket destroy delayed' messages */
 					return 1;
 				}
                                 /* Log packet, which triggered dialing */
@@ -805,15 +856,18 @@
 				/* Connect interface with channel */
 				isdn_net_bind_channel(lp, chi);
 #ifdef CONFIG_ISDN_PPP
-				if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+				if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+					/* no 'first_skb' handling for syncPPP */
 					if (isdn_ppp_bind(lp) < 0) {
-						lp->dialstate = 0;
-						isdn_free_channel(lp->isdn_device,
-                                                                  lp->isdn_channel,
-                                                                  ISDN_USAGE_NET);
+						lp->first_skb = skb;	/* net_unbind will free skb */
+						isdn_net_unbind_channel(lp);
                                                 restore_flags(flags);
-						return 1;
+						return 0;	/* STN (skb to nirvana) ;) */
 					}
+	                                isdn_net_dial();	/* Initiate dialing */
+					restore_flags(flags);
+					return 1;	/* let upper layer requeue skb packet */
+				}
 #endif
                                 /* remember first skb to speed up arp
                                  * when using encap ETHER
@@ -1630,9 +1684,7 @@
 #ifdef CONFIG_ISDN_PPP
 						if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 							if (isdn_ppp_bind(lp) < 0) {
-								isdn_free_channel(p->local.isdn_device, p->local.isdn_channel,
-									     ISDN_USAGE_NET);
-								lp->dialstate = 0;
+								isdn_net_unbind_channel(lp);
 								restore_flags(flags);
 								return 0;
 							}
@@ -1647,15 +1699,6 @@
 				} else {
 					printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr,
 					       eaz);
-#if 0
-/* why is this a CONFIG_ISDN_PPP feature ??? */
-#ifdef CONFIG_ISDN_PPP
-					if (p->local.isdn_device != -1) {
-						isdn_free_channel(p->local.isdn_device, p->local.isdn_channel,
-							 ISDN_USAGE_NET);
-					}
-#endif
-#endif
 					/* if this interface is dialing, it does it probably on a different
 					   device, so free this device */
 					if ((p->local.dialstate == 4) || (p->local.dialstate == 12))
@@ -1669,6 +1712,7 @@
 					p->local.isdn_device = di;
 					p->local.isdn_channel = ch;
 					p->local.ppp_minor = -1;
+					p->local.pppbind = -1;
 					p->local.flags |= ISDN_NET_CONNECTED;
 					p->local.dialstate = 7;
 					p->local.dtimer = 0;
@@ -1679,9 +1723,7 @@
 #ifdef CONFIG_ISDN_PPP
 					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 						if (isdn_ppp_bind(lp) < 0) {
-							isdn_free_channel(p->local.isdn_device, p->local.isdn_channel,
-							 ISDN_USAGE_NET);
-							lp->dialstate = 0;
+							isdn_net_unbind_channel(lp);
 							restore_flags(flags);
 							return 0;
 						}
@@ -1745,9 +1787,9 @@
 #ifdef CONFIG_ISDN_PPP
 			if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 				if (isdn_ppp_bind(lp) < 0) {
-					lp->dialstate = 0;
-					isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
-					return 1;
+					isdn_net_unbind_channel(lp);
+					restore_flags(flags);
+					return -EAGAIN;
 				}
 #endif
 			/* Initiate dialing */
@@ -1841,6 +1883,7 @@
 	netdev->local.pre_channel = -1;
 	netdev->local.exclusive = -1;
 	netdev->local.ppp_minor = -1;
+	netdev->local.pppbind = -1;
 	netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
 	netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
 	netdev->local.slavedelay = 10 * HZ;
@@ -1987,6 +2030,7 @@
                 p->local.cbdelay     = cfg->cbdelay;
                 p->local.dialmax     = cfg->dialmax;
 		p->local.slavedelay  = cfg->slavedelay * HZ;
+		p->local.pppbind     = cfg->pppbind;
 		if (cfg->secure)
 			p->local.flags |= ISDN_NET_SECURE;
 		else
@@ -2062,14 +2106,16 @@
 		cfg->l3_proto = p->local.l3_proto;
 		cfg->p_encap = p->local.p_encap;
 		cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
-		cfg->callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
-		cfg->callback = (p->local.flags & ISDN_NET_CBOUT) ? 2 : 0;
+		cfg->callback = 0;
+                if (p->local.flags & ISDN_NET_CALLBACK)
+                        cfg->callback = (p->local.flags & ISDN_NET_CBOUT)?2:1;
 		cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0;
 		cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0;
 		cfg->ihup = (p->local.hupflags & 8) ? 1 : 0;
                 cfg->cbdelay = p->local.cbdelay;
                 cfg->dialmax = p->local.dialmax;
 		cfg->slavedelay = p->local.slavedelay / HZ;
+		cfg->pppbind = p->local.pppbind;
 		if (p->local.slave)
 			strcpy(cfg->slave, ((isdn_net_local *) p->local.slave->priv)->name);
 		else
@@ -2287,7 +2333,7 @@
 	restore_flags(flags);
 
 #ifdef CONFIG_ISDN_PPP
-	isdn_ppp_free_mpqueue(p);
+	isdn_ppp_free_mpqueue(p);	/* still necessary? */
 #endif
 	kfree(p);
 
@@ -2341,6 +2387,26 @@
 	restore_flags(flags);
 	return 0;
 }
+
+/* 
+ * helper function to flush device queues
+ * the better place would be net/core/dev.c
+ */
+void dev_purge_queues(struct device *dev)
+{
+	int i;
+	for(i=0;i<DEV_NUMBUFFS;i++) {
+		struct sk_buff *skb;
+		while((skb=skb_dequeue(&dev->buffs[i])))
+			if(skb->free)
+				kfree_skb(skb,FREE_WRITE);
+        }
+	
+}
+
+
+
+
 
 
 
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- pre2.0.5/linux/drivers/isdn/isdn_ppp.c	Tue May  7 16:22:26 1996
+++ linux/drivers/isdn/isdn_ppp.c	Sun May 19 15:29:29 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.5 1996/04/20 16:32:32 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.9 1996/05/18 01:37:01 fritz Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,19 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.9  1996/05/18 01:37:01  fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.8  1996/05/06 11:34:55  hipp
+ * fixed a few bugs
+ *
+ * Revision 1.7  1996/04/30 11:07:42  fritz
+ * Added Michael's ippp-bind patch.
+ *
+ * Revision 1.6  1996/04/30 09:33:09  fritz
+ * Removed compatibility-macros.
+ *
  * Revision 1.5  1996/04/20 16:32:32  fritz
  * Changed ippp_table to an array of pointers, allocating each part
  * separately.
@@ -43,9 +56,7 @@
 
 /* TODO: right tbusy handling when using MP */
 
-#ifndef STANDALONE
 #include <linux/config.h>
-#endif
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/isdn.h>
@@ -58,8 +69,8 @@
 #endif
  
 /* Prototypes */
-static int isdn_ppp_fill_rq(char *buf, int len, int minor);
-static int isdn_ppp_hangup(int);
+static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor);
+static int isdn_ppp_closewait(int);
 static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
 			struct sk_buff *skb, int proto);
 static int isdn_ppp_if_get_unit(char **namebuf);
@@ -72,47 +83,53 @@
 		int BEbyte, int *sqno, int min_sqno);
 #endif
 
-char *isdn_ppp_revision              = "$Revision: 1.5 $";
+char *isdn_ppp_revision              = "$Revision: 1.9 $";
 struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
 extern int isdn_net_force_dial_lp(isdn_net_local *);
 
-int isdn_ppp_free(isdn_net_local * lp)
+/*
+ * unbind isdn_net_local <=> ippp-device 
+ * note: it can happen, that we hangup/free the master before the slaves
+ */
+int isdn_ppp_free(isdn_net_local *lp)
 {
+	isdn_net_local *master_lp=lp;
+
 	if (lp->ppp_minor < 0)
 		return 0;
 
 #ifdef CONFIG_ISDN_MPP
 	if(lp->master)
-	{
-		isdn_net_dev *p = dev->netdev;
-		lp->last->next = lp->next;
-		lp->next->last = lp->last;
-		if(lp->netdev->queue == lp)
-			lp->netdev->queue = lp->next;
-                lp->next = lp->last = lp;
-		while(p) {
-			if(lp == &p->local) {
-				lp->netdev = p;
-				break;
-			}
-			p=p->next;
+		master_lp = (isdn_net_local *) lp->master->priv;
+
+	lp->last->next = lp->next;
+	lp->next->last = lp->last;
+	if(master_lp->netdev->queue == lp) {
+		master_lp->netdev->queue = lp->next;
+		if(lp->next == lp) {	/* last link in queue? */
+               		master_lp->netdev->ib.bundled = 0;
+			isdn_ppp_free_mpqueue(master_lp->netdev);
+			isdn_ppp_free_sqqueue(master_lp->netdev);
 		}
-	} else {
-                lp->netdev->ib.bundled = 0;
-		/* last link: free mpqueue, free sqqueue ? */
 	}
-
+	lp->next = lp->last = lp;	/* (re)set own pointers */
 #endif
 
-	isdn_ppp_hangup(lp->ppp_minor);
-#if 0
-	printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_minor, (long) lp,(long) ippp_table[lp->ppp_minor]->lp);
-#endif
-	ippp_table[lp->ppp_minor]->lp = NULL;
+	isdn_ppp_closewait(lp->ppp_minor);	/* force wakeup on ippp device */
+
+	if(ippp_table[lp->ppp_minor]->debug & 0x1)
+		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_minor, (long) lp,(long) ippp_table[lp->ppp_minor]->lp);
+
+	ippp_table[lp->ppp_minor]->lp = NULL;	/* link is down .. set lp to NULL */
+	lp->ppp_minor = -1;			/* is this OK ?? */
+
 	return 0;
 }
 
+/*
+ * bind isdn_net_local <=> ippp-device
+ */
 int isdn_ppp_bind(isdn_net_local * lp)
 {
 	int i;
@@ -126,16 +143,31 @@
 	save_flags(flags);
 	cli();
 
-        /* 
-         * search a free device 
-         */
-	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		if (ippp_table[i]->state == IPPP_OPEN) {		/* OPEN, but not connected! */
-#if 0
-			printk(KERN_DEBUG "find_minor, %d lp: %08lx\n", i, (long) lp);
-#endif
-			break;
+	if(lp->pppbind < 0)	/* device bounded to ippp device ? */
+	{
+ 		isdn_net_dev *net_dev = dev->netdev;
+		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */
+		memset(exclusive,0,ISDN_MAX_CHANNELS);
+		while (net_dev) {	/* step through net devices to find exclusive minors */
+			isdn_net_local *lp = &net_dev->local;
+			if(lp->pppbind >= 0)
+				exclusive[lp->pppbind] = 1;
+			net_dev = net_dev->next;
 		}
+		/*
+		 * search a free device 
+		 */
+		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+			if (ippp_table[i]->state == IPPP_OPEN && !exclusive[i]) { /* OPEN, but not connected! */
+				break;
+			}
+		}
+	}
+	else {
+		if (ippp_table[lp->pppbind]->state == IPPP_OPEN) /* OPEN, but not connected! */
+			i = lp->pppbind;
+		else
+			i = ISDN_MAX_CHANNELS;	/* trigger error */
 	}
 
 	if (i >= ISDN_MAX_CHANNELS) {
@@ -163,7 +195,12 @@
 	return lp->ppp_minor;
 }
 
-static int isdn_ppp_hangup(int minor)
+/*
+ * there was a hangup on the netdevice
+ * force wakeup of the ippp device 
+ * go into 'device waits for release' state
+ */
+static int isdn_ppp_closewait(int minor)
 {
 	if (minor < 0 || minor >= ISDN_MAX_CHANNELS)
 		return 0;
@@ -181,9 +218,8 @@
 
 int isdn_ppp_open(int minor, struct file *file)
 {
-#if 0
-	printk(KERN_DEBUG "ippp, open, minor: %d state: %04x\n", minor,ippp_table[minor]->state);
-#endif
+	if(ippp_table[minor]->debug & 0x1)
+		printk(KERN_DEBUG "ippp, open, minor: %d state: %04x\n", minor,ippp_table[minor]->state);
 	if (ippp_table[minor]->state)
 		return -EBUSY;
 
@@ -219,6 +255,9 @@
 	return 0;
 }
 
+/*
+ * release ippp device
+ */
 void isdn_ppp_release(int minor, struct file *file)
 {
 	int i;
@@ -226,29 +265,24 @@
 	if (minor < 0 || minor >= ISDN_MAX_CHANNELS)
 		return;
 
-#if 0
-	printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) ippp_table[minor]->lp);
-#endif
+	if(ippp_table[minor]->debug & 0x1)
+		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) ippp_table[minor]->lp);
 
 	if (ippp_table[minor]->lp) {	/* a lp address says: this link is still up */
 		isdn_net_dev *p = dev->netdev;
-		while(p) {	/* find interface for our lp; */
-			if(&p->local == ippp_table[minor]->lp)
-				break;
-			p = p->next;
-		}
-		if(!p) {
-			printk(KERN_ERR "isdn_ppp_release: Can't find device for net_local\n");
-			p = ippp_table[minor]->lp->netdev;
-		}
+		p = ippp_table[minor]->lp->netdev;
 		ippp_table[minor]->lp->ppp_minor = -1;
-		isdn_net_hangup(&p->dev); /* lp->ppp_minor==-1 => no calling of isdn_ppp_hangup() */
+		isdn_net_hangup(&p->dev); /* lp->ppp_minor==-1 => no calling of isdn_ppp_closewait() */
 		ippp_table[minor]->lp = NULL;
 	}
 	for (i = 0; i < NUM_RCV_BUFFS; i++) {
-		if (ippp_table[minor]->rq[i].buf)
+		if (ippp_table[minor]->rq[i].buf) {
 			kfree(ippp_table[minor]->rq[i].buf);
+			ippp_table[minor]->rq[i].buf = NULL;
+		}
 	}
+        ippp_table[minor]->first = ippp_table[minor]->rq + NUM_RCV_BUFFS - 1; /* receive queue */
+        ippp_table[minor]->last = ippp_table[minor]->rq;
 
 #ifdef CONFIG_ISDN_PPP_VJ
 	slhc_free(ippp_table[minor]->slcomp);
@@ -258,6 +292,9 @@
 	ippp_table[minor]->state = 0;
 }
 
+/*
+ * get_arg .. ioctl helper
+ */
 static int get_arg(void *b, unsigned long *val)
 {
 	int r;
@@ -267,6 +304,9 @@
 	return 0;
 }
 
+/*
+ * set arg .. ioctl helper
+ */
 static int set_arg(void *b, unsigned long val)
 {
 	int r;
@@ -276,15 +316,17 @@
 	return 0;
 }
 
+/*
+ * ippp device ioctl 
+ */
 int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	unsigned long val;
 	int r;
 
-#if 0
-	printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x",minor,cmd);
-	printk(KERN_DEBUG " state: %x\n",ippp_table[minor]->state);
-#endif
+	if(ippp_table[minor]->debug & 0x1)
+		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n",
+			minor,cmd,ippp_table[minor]->state);
 
 	if (!(ippp_table[minor]->state & IPPP_OPEN))
 		return -EINVAL;
@@ -328,8 +370,9 @@
 			return r;
 		}
 		if (val & SC_ENABLE_IP && !(ippp_table[minor]->pppcfg & SC_ENABLE_IP)) {
-			ippp_table[minor]->lp->netdev->dev.tbusy = 0;
-			mark_bh(NET_BH); /* OK .. we are ready to send the first buffer */
+			isdn_net_local *lp = ippp_table[minor]->lp;
+			lp->netdev->dev.tbusy = 0;
+			mark_bh(NET_BH); /* OK .. we are ready to send buffers */
 		}
 		ippp_table[minor]->pppcfg = val;
 		break;
@@ -354,8 +397,13 @@
 		ippp_table[minor]->maxcid = val;
 		break;
 	case PPPIOCGDEBUG:
+		if ((r = set_arg((void *) arg, ippp_table[minor]->debug)))
+			return r;
 		break;
 	case PPPIOCSDEBUG:
+		if ((r = get_arg((void *) arg, &val)))
+			return r;
+		ippp_table[minor]->debug = val;
 		break;
 	default:
 		break;
@@ -368,9 +416,8 @@
 	struct ippp_buf_queue *bf, *bl;
 	unsigned long flags;
 
-#if 0
-	printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",minor,type);
-#endif
+	if(ippp_table[minor]->debug & 0x2)
+		printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",minor,type);
 
 	if (!(ippp_table[minor]->state & IPPP_OPEN))
 		return -EINVAL;
@@ -381,6 +428,9 @@
 		cli();
 		bl = ippp_table[minor]->last;
 		bf = ippp_table[minor]->first;
+		/* 
+		 * if IPPP_NOBLOCK is set we return even if we have nothing to read 
+		 */
 		if (bf->next == bl && !(ippp_table[minor]->state & IPPP_NOBLOCK)) {
 			select_wait(&ippp_table[minor]->wq, st);
 			restore_flags(flags);
@@ -403,7 +453,7 @@
  *  fill up isdn_ppp_read() queue ..
  */
 
-static int isdn_ppp_fill_rq(char *buf, int len, int minor)
+static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor)
 {
 	struct ippp_buf_queue *bf, *bl;
 	unsigned long flags;
@@ -428,15 +478,19 @@
 		kfree(bf->buf);
 		ippp_table[minor]->first = bf;
 	}
-	bl->buf = (char *) kmalloc(len, GFP_ATOMIC);
+	bl->buf = (char *) kmalloc(len+4, GFP_ATOMIC);
 	if (!bl->buf) {
 		printk(KERN_WARNING "ippp: Can't alloc buf\n");
 		restore_flags(flags);
 		return 0;
 	}
-	bl->len = len;
+	bl->len = len+4;
 
-	memcpy(bl->buf, buf, len);
+	bl->buf[0] = PPP_ALLSTATIONS;
+	bl->buf[1] = PPP_UI;
+	bl->buf[2] = proto >> 8;
+	bl->buf[3] = proto & 0xff;
+	memcpy(bl->buf+4, buf, len);
 
 	ippp_table[minor]->last = bl->next;
 	restore_flags(flags);
@@ -502,6 +556,7 @@
 	if (!lp)
 		printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
 	else {
+		lp->huptimer = 0;
 		if (lp->isdn_device < 0 || lp->isdn_channel < 0)
 			return 0;
 
@@ -526,11 +581,11 @@
 	        if (!(ippp_table[i] = (struct ippp_struct *)
 	                kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
 		        printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
-                        for (j = 0; j < i; j++)
-                          kfree(ippp_table[i]);
+			for (j = 0; j < i; j++)
+				kfree(ippp_table[i]);
 		        return -1;
 	        }
-                memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
+		memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
 		ippp_table[i]->state = 0;
 		ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
 		ippp_table[i]->last = ippp_table[i]->rq;
@@ -559,14 +614,15 @@
 
 void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
 {
-#if 0
-	printk(KERN_DEBUG "recv, skb %d\n",skb->len);
-#endif
+	if(ippp_table[lp->ppp_minor]->debug & 0x4)
+		printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len);
 
 	if(skb->data[0] == 0xff && skb->data[1] == 0x03)
 		skb_pull(skb,2);
-	else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC)
+	else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) {
+		dev_kfree_skb(skb,FREE_WRITE);
 		return;		/* discard it silently */
+	}
 
 #ifdef CONFIG_ISDN_MPP
 	if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_REJ_MP_PROT)) {
@@ -583,11 +639,10 @@
 			isdn_net_local *lpq;
 			int sqno, min_sqno, tseq;
 			u_char BEbyte = skb->data[0];
-#if 0
-			printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_minor, proto ,
-				(int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], 
-				(int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
-#endif
+			if(ippp_table[lp->ppp_minor]->debug & 0x8)
+	 			printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_minor, proto ,
+					(int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], 
+					(int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
 			if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_IN_SHORT_SEQ)) {
 				sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3];
 				skb_pull(skb,4);
@@ -657,8 +712,9 @@
 
 				q = (struct sqqueue *) kmalloc(sizeof(struct sqqueue), GFP_ATOMIC);
 				if (!q) {
-					printk(KERN_WARNING "ippp: err, no memory !!\n");
 					net_dev->ib.modify = 0;
+					printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
+					dev_kfree_skb(skb,FREE_WRITE);
 					return;		/* discard */
 				}
 				q->skb = skb;
@@ -726,9 +782,8 @@
 		}
 	}
 
-#if 0
-	printk(KERN_DEBUG "push, skb %d %04x\n",skb->len,proto);
-#endif
+	if(ippp_table[lp->ppp_minor]->debug & 0x10)
+		printk(KERN_DEBUG "push, skb %ld %04x\n",skb->len,proto);
 
 	switch (proto) {
 	case PPP_IPX: /* untested */
@@ -755,6 +810,7 @@
 			if (!skb) {
 				printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
 				net_dev->local.stats.rx_dropped++;
+				dev_kfree_skb(skb_old,FREE_WRITE);
 				return;
 			}
 			skb->dev = dev;
@@ -770,16 +826,12 @@
 #else
 		printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
 		lp->stats.rx_dropped++;
+		dev_kfree_skb(skb,FREE_WRITE);
 		return;
 #endif
 		break;
 	default:
-		skb_push(skb,4);
-		skb->data[0] = 0xff;
-		skb->data[1] = 0x03;
-		skb->data[2] = (proto>>8);
-		skb->data[3] = proto & 0xff;
-		isdn_ppp_fill_rq(skb->data, skb->len, lp->ppp_minor);	/* push data to pppd device */
+		isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_minor);	/* push data to pppd device */
 		dev_kfree_skb(skb,FREE_WRITE);
 		return;
 	}
@@ -793,19 +845,32 @@
 }
 
 /*
- * send ppp frame .. we expect a PIDCOMPable proto -- 
+ * send ppp frame .. we expect a PIDCOMPressable proto -- 
  *  (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
  */
 int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 {
-	isdn_net_dev *nd = ((isdn_net_local *) dev->priv)->netdev;
-	isdn_net_local *lp = nd->queue;
+	struct device *mdev = ((isdn_net_local *) (dev->priv) )->master;	/* get master (for redundancy) */
+	isdn_net_local *lp,*mlp;
+	isdn_net_dev *nd;
 	int proto = PPP_IP;	/* 0x21 */
-	struct ippp_struct *ipt = ippp_table[lp->ppp_minor];
-#if defined(CONFIG_ISDN_PPP_VJ) || defined(CONFIG_ISDN_MPP)
-	struct ippp_struct *ipts = ippp_table[lp->netdev->local.ppp_minor];
-#endif
+	struct ippp_struct *ipt,*ipts;
 
+	if(mdev)
+		mlp = (isdn_net_local *) (mdev->priv); 
+	else
+		mlp = (isdn_net_local *) (dev->priv);
+	nd = mlp->netdev;	/* get master lp */
+	lp = nd->queue;		/* get lp on top of queue */
+	ipt = ippp_table[lp->ppp_minor];
+	ipts = ippp_table[mlp->ppp_minor];
+
+	if (!(ipt->pppcfg & SC_ENABLE_IP)) {    /* PPP connected ? */
+		printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel);
+		return 1;
+        }
+        lp->huptimer = 0;
+ 
         /* If packet is to be resent, it has already been processed and
          * therefore its first bytes are already initialized. In this case
          * send it immediately ...
@@ -817,17 +882,16 @@
 
 /* future: step to next 'lp' when this lp is 'tbusy' */
 
-#if 0
-	printk(KERN_DEBUG  "xmit, skb %d\n",skb->len);
-#endif
+	if(ippp_table[lp->ppp_minor]->debug & 0x4)
+		printk(KERN_DEBUG  "xmit skb, len %ld\n",skb->len);
 
 #ifdef CONFIG_ISDN_PPP_VJ
-	if (ipt->pppcfg & SC_COMP_TCP) {
+	if (ipt->pppcfg & SC_COMP_TCP) {	/* ipt or ipts ? -> check this again! */
 		u_char *buf = skb->data;
 		int pktlen;
 		int len = 4;
 #ifdef CONFIG_ISDN_MPP
-		if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ 
+		if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ 	/* ipt or ipts ?? */
 			if (ipt->mpppcfg & SC_OUT_SHORT_SEQ)
 				len += 3;
 			else
@@ -851,9 +915,8 @@
 	}
 #endif
 
-#if 0
-	printk(KERN_DEBUG  "xmit, skb %d %04x\n",skb->len,proto);
-#endif
+        if(ippp_table[lp->ppp_minor]->debug & 0x24)
+ 		printk(KERN_DEBUG  "xmit2 skb, len %ld, proto %04x\n",skb->len,proto);
 
 #ifdef CONFIG_ISDN_MPP
 	if (ipt->mpppcfg & SC_MP_PROT) {
@@ -883,15 +946,25 @@
 	skb->data[2] = proto >> 8;
 	skb->data[3] = proto & 0xff;
 
-	lp->huptimer = 0;
-	if (!(ipt->pppcfg & SC_ENABLE_IP)) {	/* PPP connected ? */
-		printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel);
-		return 1;
-	}
         /* tx-stats are now updated via BSENT-callback */
 	return (isdn_net_send_skb(dev , lp , skb));
 }
 
+void isdn_ppp_free_sqqueue(isdn_net_dev * p) 
+{
+	struct sqqueue *q = p->ib.sq;
+
+	p->ib.sq = NULL;
+	while(q) {
+		struct sqqueue *qn = q->next;
+		if(q->skb)
+			dev_kfree_skb(q->skb,FREE_WRITE);
+		kfree(q);
+		q = qn;
+	}
+
+}
+
 void isdn_ppp_free_mpqueue(isdn_net_dev * p)
 {
 	struct mpqueue *ql, *q = p->mp_last;
@@ -932,8 +1005,6 @@
 	nlp->next = lp;
 	p->queue = nlp;
 
-	nlp->netdev = lp->netdev;
-
 	ippp_table[nlp->ppp_minor]->unit = ippp_table[lp->ppp_minor]->unit;
 /* maybe also SC_CCP stuff */
 	ippp_table[nlp->ppp_minor]->pppcfg |= ippp_table[lp->ppp_minor]->pppcfg &
@@ -1239,4 +1310,34 @@
 #endif
 }
 
+int isdn_ppp_hangup_slave(char *name)
+{
+#ifdef CONFIG_ISDN_MPP
+        isdn_net_dev *ndev;
+        isdn_net_local *lp;
+        struct device *sdev;
+
+	if(!(ndev = isdn_net_findif(name)))
+		return 1;
+	lp = &ndev->local;
+	if(!(lp->flags & ISDN_NET_CONNECTED))
+		return 5;
+
+	sdev = lp->slave;
+	while(sdev)
+	{
+		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
+		if((mlp->flags & ISDN_NET_CONNECTED))
+			break;
+		sdev = mlp->slave;
+	}
+	if(!sdev)
+		return 2;
+
+	isdn_net_hangup(sdev);
+	return 0;
+#else
+	return -1;
+#endif
+}
 
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h
--- pre2.0.5/linux/drivers/isdn/isdn_ppp.h	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/isdn_ppp.h	Sun May 19 15:29:29 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.h,v 1.2 1996/04/20 16:35:11 fritz Exp $
+/* $Id: isdn_ppp.h,v 1.4 1996/05/06 11:34:56 hipp Exp $
  *
  * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,12 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_ppp.h,v $
+ * Revision 1.4  1996/05/06 11:34:56  hipp
+ * fixed a few bugs
+ *
+ * Revision 1.3  1996/04/30 09:33:10  fritz
+ * Removed compatibility-macros.
+ *
  * Revision 1.2  1996/04/20 16:35:11  fritz
  * Changed isdn_ppp_receive to use sk_buff as parameter.
  * Added definition of isdn_ppp_dial_slave and ippp_table.
@@ -40,6 +46,7 @@
 extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
 extern int  isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int);
 extern void isdn_ppp_free_mpqueue(isdn_net_dev *);
+extern void isdn_ppp_free_sqqueue(isdn_net_dev *);
 extern int  isdn_ppp_select(int, struct file *, int, select_table *);
 extern int  isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
 extern void isdn_ppp_release(int, struct file *);
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- pre2.0.5/linux/drivers/isdn/isdn_tty.c	Mon May 13 23:02:49 1996
+++ linux/drivers/isdn/isdn_tty.c	Sun May 19 16:14:53 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.4 1996/04/20 16:39:54 fritz Exp $
+/* $Id: isdn_tty.c,v 1.11 1996/05/18 01:37:03 fritz Exp $
  *
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -20,6 +20,35 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.11  1996/05/18 01:37:03  fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.10  1996/05/17 03:51:49  fritz
+ * Changed DLE handling for audio receive.
+ *
+ * Revision 1.9  1996/05/11 21:52:07  fritz
+ * Changed queue management to use sk_buffs.
+ *
+ * Revision 1.8  1996/05/10 08:49:43  fritz
+ * Checkin before major changes of tty-code.
+ *
+ * Revision 1.7  1996/05/07 09:15:09  fritz
+ * Reorganized and general cleanup.
+ * Bugfixes:
+ *  - Audio-transmit working now.
+ *  - "NO CARRIER" now reported, when hanging up with DTR low.
+ *  - Corrected CTS handling.
+ *
+ * Revision 1.6  1996/05/02 03:59:25  fritz
+ * Bugfixes:
+ *  - On dialout, layer-2 setup had been incomplete
+ *    when using new auto-layer2 feature.
+ *  - On hangup, "NO CARRIER" message sometimes missing.
+ *
+ * Revision 1.5  1996/04/30 21:05:25  fritz
+ * Test commit
+ *
  * Revision 1.4  1996/04/20 16:39:54  fritz
  * Changed all io to go through generic routines in isdn_common.c
  * Fixed a real ugly bug in modem-emulator: 'ATA' had been accepted
@@ -39,14 +68,22 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/isdn.h>
+#include <linux/config.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
+#ifdef CONFIG_ISDN_AUDIO
+#include "isdn_audio.h"
+#define VBUF 0x300
+#define VBUFX (VBUF/16)
+#endif
 
 /* Prototypes */
 
 static int  isdn_tty_edit_at(const char *, int, modem_info *, int);
 static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int);
 static void isdn_tty_modem_reset_regs(atemu *, int);
+static void isdn_tty_cmd_ATA(modem_info *);
+static void isdn_tty_at_cout(char *, modem_info *);
 
 /* Leave this unchanged unless you know what you do! */
 #define MODEM_PARANOIA_CHECK
@@ -54,31 +91,53 @@
 
 static char *isdn_ttyname_ttyI = "ttyI";
 static char *isdn_ttyname_cui  = "cui";
-char *isdn_tty_revision        = "$Revision: 1.4 $";
-
-int isdn_tty_try_read(int i, u_char * buf, int len)
+static int bit2si[8] = {1,5,7,7,7,7,7,7};
+static int si2bit[8] = {4,1,4,4,4,4,4,4};
+                                
+char *isdn_tty_revision        = "$Revision: 1.11 $";
+
+/* isdn_tty_try_read() is called from within isdn_receive_callback()
+ * to stuff incoming data directly into a tty's flip-buffer. This
+ * is done to speed up tty-receiving if the receive-queue is empty.
+ * This routine MUST be called with interrupts off.
+ * Return:
+ *  1 = Success
+ *  0 = Failure, data has to be bufferd and later processed by
+ *      isdn_tty_readmodem().
+ */
+#define DLE 0x10
+#define ETX 0x03
+int isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
 {
         int c;
+        int len;
         struct tty_struct *tty;
 
-	if (i < 0)
-		return 0;
-	if (dev->mdm.online[i]) {
-		if ((tty = dev->mdm.info[i].tty)) {
-			if (dev->mdm.info[i].MCR & UART_MCR_RTS) {
-				c = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
+	if (info->online) {
+		if ((tty = info->tty)) {
+			if (info->mcr & UART_MCR_RTS) {
+				c = TTY_FLIPBUF_SIZE - tty->flip.count;
+                                len = skb->len + skb->users;
 				if (c >= len) {
-					if (len > 1) {
-						memcpy(tty->flip.char_buf_ptr, buf, len);
-						tty->flip.count += len;
-						memset(tty->flip.flag_buf_ptr, 0, len);
-						if (dev->mdm.atmodem[i].mdmreg[12] & 128)
-							tty->flip.flag_buf_ptr[len - 1] = 0xff;
-						tty->flip.flag_buf_ptr += len;
-						tty->flip.char_buf_ptr += len;
-					} else
-						tty_insert_flip_char(tty, buf[0], 0);
+                                        if (skb->users)
+                                                while (skb->len--) {
+                                                        if (*skb->data == DLE)
+                                                                tty_insert_flip_char(tty, DLE, 0);
+                                                        tty_insert_flip_char(tty, *skb->data++, 0);
+                                                }
+                                        else {
+                                                memcpy(tty->flip.char_buf_ptr,
+                                                       skb->data, len);
+                                                tty->flip.count += len;
+                                                tty->flip.char_buf_ptr += len;
+                                                memset(tty->flip.flag_buf_ptr, 0, len);
+                                                tty->flip.flag_buf_ptr += len;
+                                        }
+                                        if (info->emu.mdmreg[12] & 128)
+                                                tty->flip.flag_buf_ptr[len - 1] = 0xff;
 					queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+                                        skb->free = 1;
+                                        kfree_skb(skb, FREE_READ);
 					return 1;
 				}
 			}
@@ -87,6 +146,10 @@
 	return 0;
 }
 
+/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
+ * It tries getting received data from the receive queue an stuff it into
+ * the tty's flip-buffer.
+ */
 void isdn_tty_readmodem(void)
 {
 	int resched = 0;
@@ -99,43 +162,140 @@
 	modem_info *info;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		if ((midx = dev->m_idx[i]) >= 0)
-			if (dev->mdm.online[midx]) {
-				save_flags(flags);
-				cli();
+		if ((midx = dev->m_idx[i]) >= 0) {
+                        info = &dev->mdm.info[midx];
+			if (info->online) {
 				r = 0;
-				info = &dev->mdm.info[midx];
 				if ((tty = info->tty)) {
-					if (info->MCR & UART_MCR_RTS) {
-						c = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
+					if (info->mcr & UART_MCR_RTS) {
+						c = TTY_FLIPBUF_SIZE - tty->flip.count;
 						if (c > 0) {
+                                                        save_flags(flags);
+                                                        cli();
 							r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
 								      tty->flip.char_buf_ptr,
 								      tty->flip.flag_buf_ptr, c, 0);
-							if (!(dev->mdm.atmodem[midx].mdmreg[12] & 128))
+                                                        /* CISCO AsyncPPP Hack */
+							if (!(info->emu.mdmreg[12] & 128))
 								memset(tty->flip.flag_buf_ptr, 0, r);
 							tty->flip.count += r;
 							tty->flip.flag_buf_ptr += r;
 							tty->flip.char_buf_ptr += r;
 							if (r)
 								queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+                                                        restore_flags(flags);
 						}
 					} else
 						r = 1;
 				} else
 					r = 1;
-				restore_flags(flags);
 				if (r) {
-					dev->mdm.rcvsched[midx] = 0;
+					info->rcvsched = 0;
 					resched = 1;
 				} else
-					dev->mdm.rcvsched[midx] = 1;
+					info->rcvsched = 1;
 			}
+                }
 	}
 	if (!resched)
 		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
 }
 
+void isdn_tty_cleanup_xmit(modem_info *info)
+{
+        struct sk_buff *skb;
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+        if (info->xmit_buf->qlen)
+                while ((skb = skb_dequeue(info->xmit_buf))) {
+                        skb->free = 1;
+                        kfree_skb(skb,FREE_WRITE);
+                }
+        restore_flags(flags);
+}
+
+/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
+ * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
+ * outgoing data from the tty's xmit-buffer, handles voice-decompression or
+ * T.70 if necessary, and finally sends it out via isdn_writebuf_stub.
+ */
+static void isdn_tty_senddown(modem_info * info)
+{
+        struct tty_struct *tty = info->tty;
+        struct sk_buff *skb = skb_dequeue(info->xmit_buf);
+
+        if (!skb)
+                return;
+        if (skb->free > 1) {
+                /* Post processing only once, if skb->free > 1 */
+#ifdef CONFIG_ISDN_AUDIO
+                if (info->vonline==2) {
+                        char *ptr = skb->data;
+                        int len = skb->len;
+
+                        /* For now, ifmt is fixed to 1 (alaw), since this
+                         * is used with ISDN everywhere in the world, except
+                         * US, Canadia and Japan.
+                         * Later, when US-ISDN protocols are implemented,
+                         * this setting will depend on the D-channel protocol.
+                         */
+                        int ifmt = 1;
+                        /* voice conversion/decompression */
+                        switch (info->emu.vpar[3]) {
+                                case 4:
+                                        skb_put(skb, len);
+                                        /* fall through */
+                                case 3:
+                                        skb_put(skb, len);
+                                        /* fall through */
+                                case 2:
+                                        skb_put(skb, len * 2);
+                                        /* adpcm, compatible to ZyXel 1496 modem
+                                         * with ROM revision 6.01
+                                         */
+                                        skb_pull(skb, len);
+                                        skb_trim(skb, isdn_audio_adpcm2xlaw(info->adpcms,
+                                                                       ifmt,
+                                                                       ptr,
+                                                                       skb->data,
+                                                                       len));
+                                        break;
+                                case 5:
+                                        /* a-law */
+                                        if (!ifmt)
+                                                isdn_audio_alaw2ulaw(ptr,len);
+                                        break;
+                                case 6:
+                                        /* u-law */
+                                        if (ifmt)
+                                                isdn_audio_ulaw2alaw(ptr,len);
+                                        break;
+                        }
+                }
+#endif          /* CONFIG_ISDN_AUDIO */
+                if (info->emu.mdmreg[13] & 2)
+                        /* Add T.70 simplified header */
+                        memcpy(skb_push(skb,4), "\1\0\1\0", 4);
+                /* Mark skb post-processed */
+                skb->free = 1;
+        }
+        if (isdn_writebuf_skb_stub(info->isdn_driver, info->isdn_channel,
+                                   skb) > 0) {
+                if (skb_queue_empty(info->xmit_buf))
+                        info->xmit_count = 0;
+                if ((info->send_outstanding++) > 10)
+                        info->msr &= ~UART_MSR_CTS;
+                info->lsr |= UART_LSR_TEMT;
+                if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                    tty->ldisc.write_wakeup)
+                        (tty->ldisc.write_wakeup) (tty);
+                wake_up_interruptible(&tty->write_wait);
+        } else
+                skb_queue_head(info->xmit_buf,skb);
+}
+
 /************************************************************
  *
  * Modem-functions
@@ -144,78 +304,149 @@
  *
  ************************************************************/
 
+/* The nex routine is called once from within timer-interrupt
+ * triggered within isdn_tty_modem_ncarrier(). It calls
+ * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
+ * into the tty's flip-buffer.
+ */
+static void isdn_tty_modem_do_ncarrier(unsigned long data)
+{
+        modem_info * info = (modem_info *)data;
+        isdn_tty_modem_result(3, info);
+}
+
+/* Next routine is called, whenever the DTR-signal is raised.
+ * It checks the ncarrier-flag, and triggers the above routine
+ * when necessary. The ncarrier-flag is set, whenever DTR goes
+ * low.
+ */      
+static void isdn_tty_modem_ncarrier(modem_info * info)
+{
+        if (info->ncarrier) {
+                info->ncarrier = 0;
+                info->nc_timer.expires = jiffies + HZ;
+                info->nc_timer.function = isdn_tty_modem_do_ncarrier;
+                info->nc_timer.data = (unsigned long)info;
+                add_timer(&info->nc_timer);
+        }
+}
+
+/* isdn_tty_dial() performs dialing of a tty an the necessary
+ * setup of the lower levels befor that.
+ */
 static void isdn_tty_dial(char *n, modem_info * info, atemu * m)
 {
+        int usg = ISDN_USAGE_MODEM;
+        int si = 7;
+        int l2 = m->mdmreg[14];
 	isdn_ctrl cmd;
 	ulong flags;
 	int i;
+        int j;
 
+        for (j=7;j>=0;j--)
+                if (m->mdmreg[18] & (1<<j)) {
+                        si = bit2si[j];
+                        break;
+                }
+#ifdef CONFIG_ISDN_AUDIO
+                if (si == 1) {
+                        l2 = 4;
+                        usg = ISDN_USAGE_VOICE;
+                }
+#endif
+        m->mdmreg[20] = si2bit[si];
 	save_flags(flags);
 	cli();
-	i = isdn_get_free_channel(ISDN_USAGE_MODEM, m->mdmreg[14], m->mdmreg[15], -1, -1);
+	i = isdn_get_free_channel(usg, l2, m->mdmreg[15], -1, -1);
 	if (i < 0) {
 		restore_flags(flags);
 		isdn_tty_modem_result(6, info);
 	} else {
-		if (strlen(m->msn)) {
-			info->isdn_driver = dev->drvmap[i];
-			info->isdn_channel = dev->chanmap[i];
-			info->drv_index = i;
-			dev->m_idx[i] = info->line;
-			dev->usage[i] |= ISDN_USAGE_OUTGOING;
-			isdn_info_update();
-			restore_flags(flags);
-			cmd.driver = info->isdn_driver;
-			cmd.arg = info->isdn_channel;
-			cmd.command = ISDN_CMD_CLREAZ;
-			dev->drv[info->isdn_driver]->interface->command(&cmd);
-			strcpy(cmd.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
-			cmd.driver = info->isdn_driver;
-			cmd.command = ISDN_CMD_SETEAZ;
-			dev->drv[info->isdn_driver]->interface->command(&cmd);
-			cmd.driver = info->isdn_driver;
-			cmd.command = ISDN_CMD_SETL2;
-			cmd.arg = info->isdn_channel + (m->mdmreg[14] << 8);
-			dev->drv[info->isdn_driver]->interface->command(&cmd);
-			cmd.driver = info->isdn_driver;
-			cmd.command = ISDN_CMD_SETL3;
-			cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
-			dev->drv[info->isdn_driver]->interface->command(&cmd);
-			cmd.driver = info->isdn_driver;
-			cmd.arg = info->isdn_channel;
-			sprintf(cmd.num, "%s,%s,%d,%d", n, isdn_map_eaz2msn(m->msn, info->isdn_driver),
-				m->mdmreg[18], m->mdmreg[19]);
-			cmd.command = ISDN_CMD_DIAL;
-			dev->mdm.dialing[info->line] = 1;
-			strcpy(dev->num[i], n);
-			isdn_info_update();
-			dev->drv[info->isdn_driver]->interface->command(&cmd);
-		} else
-			restore_flags(flags);
+                info->isdn_driver = dev->drvmap[i];
+                info->isdn_channel = dev->chanmap[i];
+                info->drv_index = i;
+                dev->m_idx[i] = info->line;
+                dev->usage[i] |= ISDN_USAGE_OUTGOING;
+                isdn_info_update();
+                restore_flags(flags);
+                cmd.driver = info->isdn_driver;
+                cmd.arg = info->isdn_channel;
+                cmd.command = ISDN_CMD_CLREAZ;
+                dev->drv[info->isdn_driver]->interface->command(&cmd);
+                strcpy(cmd.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+                cmd.driver = info->isdn_driver;
+                cmd.command = ISDN_CMD_SETEAZ;
+                dev->drv[info->isdn_driver]->interface->command(&cmd);
+                cmd.driver = info->isdn_driver;
+                cmd.command = ISDN_CMD_SETL2;
+                cmd.arg = info->isdn_channel + (l2 << 8);
+                dev->drv[info->isdn_driver]->interface->command(&cmd);
+                cmd.driver = info->isdn_driver;
+                cmd.command = ISDN_CMD_SETL3;
+                cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
+                dev->drv[info->isdn_driver]->interface->command(&cmd);
+                cmd.driver = info->isdn_driver;
+                cmd.arg = info->isdn_channel;
+                sprintf(cmd.num, "%s,%s,%d,%d", n, isdn_map_eaz2msn(m->msn, info->isdn_driver),
+                        si, m->mdmreg[19]);
+                cmd.command = ISDN_CMD_DIAL;
+                info->dialing = 1;
+                strcpy(dev->num[i], n);
+                isdn_info_update();
+                dev->drv[info->isdn_driver]->interface->command(&cmd);
 	}
 }
 
+/* isdn_tty_hangup() disassociates a tty from the real
+ * ISDN-line (hangup). The usage-status is cleared
+ * and some cleanup is done also.
+ */
 void isdn_tty_modem_hup(modem_info * info)
 {
 	isdn_ctrl cmd;
+        int usage;
 
         if (!info)
                 return;
-        dev->mdm.rcvsched[info->line] = 0;
-        dev->mdm.online[info->line] = 0;
+        info->rcvsched = 0;
+        info->online = 0;
+        isdn_tty_cleanup_xmit(info);
+        switch (info->vonline) {
+                case 1:
+                        /* voice-recording, add DLE-ETX */
+                        isdn_tty_at_cout("\020\003", info);
+                        break;
+                case 2:
+                        break;
+        }
+        info->vonline = 0;
+        if (info->adpcms) {
+                kfree(info->adpcms);
+                info->adpcms = NULL;
+        }
+        if (info->adpcmr) {
+                kfree(info->adpcmr);
+                info->adpcmr = NULL;
+        }
+        info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
+        info->lsr &= ~UART_LSR_TEMT;
 	if (info->isdn_driver >= 0) {
 		cmd.driver = info->isdn_driver;
 		cmd.command = ISDN_CMD_HANGUP;
 		cmd.arg = info->isdn_channel;
 		dev->drv[info->isdn_driver]->interface->command(&cmd);
 		isdn_all_eaz(info->isdn_driver, info->isdn_channel);
-		isdn_free_channel(info->isdn_driver, info->isdn_channel, ISDN_USAGE_MODEM);
+                usage = (info->emu.mdmreg[20] == 1)?
+                        ISDN_USAGE_VOICE:ISDN_USAGE_MODEM;
+		isdn_free_channel(info->isdn_driver, info->isdn_channel,
+                                  usage);
 	}
 	info->isdn_driver = -1;
 	info->isdn_channel = -1;
         if (info->drv_index >= 0) {
-                info->drv_index = -1;
                 dev->m_idx[info->drv_index] = -1;
+                info->drv_index = -1;
         }
 }
 
@@ -258,17 +489,20 @@
 			i += 15;
 	}
 	if (quot) {
-		info->MCR |= UART_MCR_DTR;
+		info->mcr |= UART_MCR_DTR;
+                isdn_tty_modem_ncarrier(info);                
 	} else {
-		info->MCR &= ~UART_MCR_DTR;
-		isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0);
+		info->mcr &= ~UART_MCR_DTR;
+                if (info->emu.mdmreg[13] & 4) {
 #ifdef ISDN_DEBUG_MODEM_HUP
-                printk(KERN_DEBUG "Mhup in changespeed\n");
+                        printk(KERN_DEBUG "Mhup in changespeed\n");
 #endif
-                isdn_tty_modem_hup(info);
-		if (dev->mdm.online[info->line])
-			isdn_tty_modem_result(3, info);
-		return;
+                        if (info->online)
+                                info->ncarrier = 1;
+                        isdn_tty_modem_reset_regs(&info->emu, 0);
+                        isdn_tty_modem_hup(info);
+                }
+                return;
 	}
 	/* byte size and parity */
 	cval = cflag & (CSIZE | CSTOPB);
@@ -297,11 +531,6 @@
 
 	if (info->flags & ISDN_ASYNC_INITIALIZED)
 		return 0;
-	if (!info->type) {
-		if (info->tty)
-			set_bit(TTY_IO_ERROR, &info->tty->flags);
-		return 0;
-	}
 	save_flags(flags);
 	cli();
 
@@ -311,7 +540,7 @@
 	/*
 	 * Now, initialize the UART 
 	 */
-	info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
+	info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
 	/*
@@ -320,10 +549,8 @@
 	isdn_tty_change_speed(info);
 
 	info->flags |= ISDN_ASYNC_INITIALIZED;
-	dev->mdm.msr[info->line] |= UART_MSR_DSR;
-#if FUTURE
+	info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
 	info->send_outstanding = 0;
-#endif
 	restore_flags(flags);
 	return 0;
 }
@@ -344,12 +571,14 @@
 	save_flags(flags);
 	cli();			/* Disable interrupts */
 	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
-		info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
-		isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0);
+		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
+                if (info->emu.mdmreg[13] & 4) {
+                        isdn_tty_modem_reset_regs(&info->emu, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
-                printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
+                        printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
 #endif
-                isdn_tty_modem_hup(info);
+                        isdn_tty_modem_hup(info);
+                }
 	}
 	if (info->tty)
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -358,12 +587,111 @@
 	restore_flags(flags);
 }
 
+#ifdef CONFIG_ISDN_AUDIO
+
+
+int isdn_tty_countDLE(unsigned char *buf, int len)
+{
+        int count = 0;
+
+        while (len--)
+                if (*buf++ == DLE)
+                        count++;
+        return count;
+}
+
+/* This routine is called wrom within isdn_tty_write() to perform
+ * DLE-decoding when sending audio-data.
+ */
+static int isdn_tty_handleDLEdown(modem_info *info, atemu *m, struct sk_buff *skb)
+{
+        unsigned char *p = skb->data;
+        int len = skb->len;
+        int count = 0;
+
+        while (len>0) {
+                if (m->lastDLE) {
+                        m->lastDLE = 0;
+                        switch (*p) {
+                                case DLE:
+                                        /* Escape code */
+                                        if (len>1)
+                                                memmove(p,p+1,len-1);
+                                        p--;
+                                        count++;
+                                        break;
+                                case ETX:
+                                        /* End of data */
+                                        info->vonline = 0;
+                                        isdn_tty_at_cout("\r\nVCON\r\n",info);
+                                        return count;
+                                case 'q':
+                                case 's':
+                                        /* Silence */
+                                        if (len>1)
+                                                memmove(p,p+1,len-1);
+                                        p--;
+                                        break;
+                        }
+                } else {
+                        if (*p == DLE)
+                                m->lastDLE = 1;
+                        else
+                                count++;
+                }
+                p++;
+                len--;
+        }
+        if (len<0) {
+                printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
+                return 0;
+        }
+        skb_trim(skb,count);
+        return count;
+}
+
+/* This routine is called from within isdn_tty_write() when receiving
+ * audio-data. It interrupts receiving, if an character other than
+ * ^S or ^Q is sent.
+ */
+static int isdn_tty_end_vrx(const char *buf, int c, int from_user)
+{
+	char tmpbuf[VBUF];
+        char *p;
+
+        if (c > VBUF) {
+                printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n");
+                return 1;
+        }
+	if (from_user) {
+		memcpy_fromfs(tmpbuf, buf, c);
+                p = tmpbuf;
+        } else
+                p = (char *)buf;
+        while (c--) {
+                if ((*p != 0x11) && (*p != 0x13))
+                        return 1;
+                p++;
+        }
+        return 0;
+}
+#endif        /* CONFIG_ISDN_AUDIO */
+
+/* isdn_tty_write() is the main send-routine. It is called from the upper
+ * levels within the kernel to perform sending data. Depending on the
+ * online-flag it either directs output to the at-command-interpreter or
+ * to the lower level. Additional tasks done here:
+ *  - If online, check for escape-sequence (+++)
+ *  - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes.
+ *  - If receiving audio-data, call isdn_tty_end_vrx() to abor if needed.
+ *  - If dialing, abort dial.
+ */
 static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
 {
 	int c, total = 0;
-	modem_info *info = (modem_info *) tty->driver_data;
 	ulong flags;
-	int i;
+	modem_info *info = (modem_info *) tty->driver_data;
+        struct sk_buff *skb;
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
 		return 0;
@@ -372,84 +700,79 @@
 	save_flags(flags);
 	cli();
 	while (1) {
-		c = MIN(count, info->xmit_size - info->xmit_count - 1);
-		if (info->isdn_driver >= 0) {
-#if 0
-			if (info->isdn_driver != 0) {
-				printk(KERN_DEBUG "FIDO: Zwei HW-Treiber geladen? Ansonsten ist was faul.\n");
-				break;
-			}
-			int drvidx = info->isdn_driver;
-			driver *driv = dev->drv[drvidx];
-			i = driv->maxbufsize;
-#else
-			i = dev->drv[info->isdn_driver]->maxbufsize;
-#endif
-			c = MIN(c, i);
-		}
+		c = MIN(count, info->xmit_size - info->xmit_count);
+		if (info->isdn_driver >= 0)
+			c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize);
 		if (c <= 0)
 			break;
-		i = info->line;
-		if (dev->mdm.online[i]) {
-			isdn_tty_check_esc(buf, dev->mdm.atmodem[i].mdmreg[2], c,
-				       &(dev->mdm.atmodem[i].pluscount),
-			     &(dev->mdm.atmodem[i].lastplus), from_user);
-			if (from_user)
-				memcpy_fromfs(&(info->xmit_buf[info->xmit_count]), buf, c);
-			else
-				memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
-			info->xmit_count += c;
-			if (dev->mdm.atmodem[i].mdmreg[13] & 1) {
-				char *bufptr;
-				int buflen;
-#if 0
-				printk(KERN_DEBUG "WB1: %d\n", info->xmit_count);
-#endif
-				bufptr = info->xmit_buf;
-				buflen = info->xmit_count;
-				if (dev->mdm.atmodem[i].mdmreg[13] & 2) {
-					/* Add T.70 simplified header */
-
-#ifdef ISDN_DEBUG_MODEM_DUMP
-					isdn_dumppkt("T70pack1:", bufptr, buflen, 40);
-#endif
-					bufptr -= 4;
-					buflen += 4;
-					memcpy(bufptr, "\1\0\1\0", 4);
-#ifdef ISDN_DEBUG_MODEM_DUMP
-					isdn_dumppkt("T70pack2:", bufptr, buflen, 40);
-#endif
-				}
-				if (isdn_writebuf_stub(info->isdn_driver, info->isdn_channel, bufptr,
-                                                       buflen, 0) > 0) {
-					info->xmit_count = 0;
-					info->xmit_size = dev->mdm.atmodem[i].mdmreg[16] * 16;
-#if FUTURE
-					info->send_outstanding++;
-					dev->mdm.msr[i] &= ~UART_MSR_CTS;
-#endif
-					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-					    tty->ldisc.write_wakeup)
-						(tty->ldisc.write_wakeup) (tty);
-					wake_up_interruptible(&tty->write_wait);
-				}
-			}
+                if ((info->online > 1) ||
+                    (info->vonline == 2)) {
+                        atemu *m = &info->emu;
+
+                        if (info->vonline != 2)
+                                isdn_tty_check_esc(buf, m->mdmreg[2], c,
+                                                   &(m->pluscount),
+                                                   &(m->lastplus),
+                                                   from_user);
+                        if ((skb = alloc_skb(((info->vonline == 2)?
+                                                  (c+(c<<2)):c)+16,GFP_ATOMIC))==NULL) {
+                                printk(KERN_WARNING "isdn_tty: Cannot alloc skb in tty_write\n");
+                                restore_flags(flags);
+                                return total;
+                        }
+                        skb_reserve(skb, 4); /* For T.70 header */
+                        if (from_user)
+                                memcpy_fromfs(skb_put(skb, c), buf, c);
+                        else
+                                memcpy(skb_put(skb, c), buf, c);
+#ifdef CONFIG_ISDN_AUDIO
+                        if (info->vonline == 2) {
+                                int cc = isdn_tty_handleDLEdown(info,m,skb);
+                                info->xmit_count += cc;
+                                if ((cc==0) && (c > 0)) {
+                                        /* If DLE decoding results in zero-transmit, but
+                                         * c originally was non-zero, do a wakeup.
+                                         */
+                                        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                                            tty->ldisc.write_wakeup)
+                                                (tty->ldisc.write_wakeup) (tty);
+                                        wake_up_interruptible(&tty->write_wait);
+                                }
+                        } else
+#endif
+                                info->xmit_count += c;
+                        skb->users = c;
+                        skb_queue_tail(info->xmit_buf,skb);
+			if (m->mdmreg[13] & 1) {
+                                sti();
+                                isdn_tty_senddown(info);
+                        }
 		} else {
-			if (dev->mdm.dialing[i]) {
-				dev->mdm.dialing[i] = 0;
+                        info->msr |= UART_MSR_CTS;
+                        info->lsr |= UART_LSR_TEMT;
+#ifdef CONFIG_ISDN_AUDIO
+                        if (info->vonline == 1) {
+                                if (isdn_tty_end_vrx(buf, c, from_user)) {
+                                        info->vonline = 0;
+                                        isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
+                                }
+                        } else
+#endif
+                                if (info->dialing) {
+                                        info->dialing = 0;
 #ifdef ISDN_DEBUG_MODEM_HUP
-				printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
+                                        printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
 #endif
-				isdn_tty_modem_hup(info);
-				isdn_tty_modem_result(3, info);
-			} else
-				c = isdn_tty_edit_at(buf, c, info, from_user);
+                                        isdn_tty_modem_result(3, info);
+                                        isdn_tty_modem_hup(info);
+                                } else
+                                        c = isdn_tty_edit_at(buf, c, info, from_user);
 		}
 		buf += c;
 		count -= c;
 		total += c;
 	}
-	if (info->xmit_count)
+	if (total)
 		isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
 	restore_flags(flags);
 	return total;
@@ -462,9 +785,9 @@
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write_room"))
 		return 0;
-	if (!dev->mdm.online[info->line])
-		return info->xmit_size - 1;
-	ret = info->xmit_size - info->xmit_count - 1;
+	if (!info->online)
+		return info->xmit_size;
+	ret = info->xmit_size - info->xmit_count;
 	return (ret < 0) ? 0 : ret;
 }
 
@@ -474,7 +797,7 @@
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_chars_in_buffer"))
 		return 0;
-	if (!dev->mdm.online[info->line])
+	if (!info->online)
 		return 0;
 	return (info->xmit_count);
 }
@@ -482,14 +805,11 @@
 static void isdn_tty_flush_buffer(struct tty_struct *tty)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
-	uint flags;
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer"))
 		return;
-	save_flags(flags);
-	cli();
-	info->xmit_count = 0;
-	restore_flags(flags);
+        isdn_tty_cleanup_xmit(info);
+        info->xmit_count = 0;
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
@@ -502,7 +822,7 @@
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_chars"))
 		return;
-	if (info->xmit_count > 0)
+	if (skb_queue_len(info->xmit_buf))
 		isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
 }
 
@@ -522,7 +842,7 @@
 		return;
 	if (I_IXOFF(tty))
 		info->x_char = STOP_CHAR(tty);
-	info->MCR &= ~UART_MCR_RTS;
+	info->mcr &= ~UART_MCR_RTS;
 }
 
 static void isdn_tty_unthrottle(struct tty_struct *tty)
@@ -537,7 +857,7 @@
 		else
 			info->x_char = START_CHAR(tty);
 	}
-	info->MCR |= UART_MCR_RTS;
+	info->mcr |= UART_MCR_RTS;
 }
 
 /*
@@ -564,7 +884,7 @@
 
 	save_flags(flags);
 	cli();
-	status = dev->mdm.msr[info->line];
+	status = info->lsr;
 	restore_flags(flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
 	put_fs_long(result, (ulong *) value);
@@ -578,10 +898,10 @@
 	uint result;
 	ulong flags;
 
-	control = info->MCR;
+	control = info->mcr;
 	save_flags(flags);
 	cli();
-	status = dev->mdm.msr[info->line];
+	status = info->msr;
 	restore_flags(flags);
 	result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
 	    | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
@@ -596,47 +916,66 @@
 static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
 {
 	uint arg = get_fs_long((ulong *) value);
+        int pre_dtr;
 
 	switch (cmd) {
-	case TIOCMBIS:
-		if (arg & TIOCM_RTS) {
-			info->MCR |= UART_MCR_RTS;
-		}
-		if (arg & TIOCM_DTR) {
-			info->MCR |= UART_MCR_DTR;
-		}
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS) {
-			info->MCR &= ~UART_MCR_RTS;
-		}
-		if (arg & TIOCM_DTR) {
-			info->MCR &= ~UART_MCR_DTR;
-			isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0);
+                case TIOCMBIS:
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line);
+#endif
+                        if (arg & TIOCM_RTS) {
+                                info->mcr |= UART_MCR_RTS;
+                        }
+                        if (arg & TIOCM_DTR) {
+                                info->mcr |= UART_MCR_DTR;
+                                isdn_tty_modem_ncarrier(info);
+                        }
+                        break;
+                case TIOCMBIC:
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line);
+#endif
+                        if (arg & TIOCM_RTS) {
+                                info->mcr &= ~UART_MCR_RTS;
+                        }
+                        if (arg & TIOCM_DTR) {
+                                info->mcr &= ~UART_MCR_DTR;
+                                if (info->emu.mdmreg[13] & 4) {
+                                        isdn_tty_modem_reset_regs(&info->emu, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
-                        printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
+                                        printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
 #endif
-                        isdn_tty_modem_hup(info);
-			if (dev->mdm.online[info->line])
-				isdn_tty_modem_result(3, info);
-		}
-		break;
-	case TIOCMSET:
-		info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))
-			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
-			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-		if (!(info->MCR & UART_MCR_DTR)) {
-			isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0);
+                                        if (info->online)
+                                                info->ncarrier = 1;
+                                        isdn_tty_modem_hup(info);
+                                }
+                        }
+                        break;
+                case TIOCMSET:
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line);
+#endif
+                        pre_dtr = (info->mcr & UART_MCR_DTR);
+                        info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
+                                     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+                                     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+                        if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
+                                if (!(info->mcr & UART_MCR_DTR)) {
+                                        if (info->emu.mdmreg[13] & 4) {
+                                                isdn_tty_modem_reset_regs(&info->emu, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
-                        printk(KERN_DEBUG "Mhup in TIOCMSET\n");
+                                                printk(KERN_DEBUG "Mhup in TIOCMSET\n");
 #endif
-                        isdn_tty_modem_hup(info);
-			if (dev->mdm.online[info->line])
-				isdn_tty_modem_result(3, info);
-		}
-		break;
-	default:
-		return -EINVAL;
+                                                if (info->online)
+                                                        info->ncarrier = 1;
+                                                isdn_tty_modem_hup(info);
+                                        }
+                                } else
+                                        isdn_tty_modem_ncarrier(info);
+                        }
+                        break;
+                default:
+                        return -EINVAL;
 	}
 	return 0;
 }
@@ -651,104 +990,72 @@
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
 		return -ENODEV;
 	switch (cmd) {
-	case TCSBRK:		/* SVID version: non-zero arg --> no break */
-		retval = tty_check_change(tty);
-		if (retval)
-			return retval;
-		tty_wait_until_sent(tty, 0);
-		return 0;
-	case TCSBRKP:		/* support for POSIX tcsendbreak() */
-		retval = tty_check_change(tty);
-		if (retval)
-			return retval;
-		tty_wait_until_sent(tty, 0);
-		return 0;
-	case TIOCGSOFTCAR:
-		error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
-		if (error)
-			return error;
-		put_fs_long(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
-		return 0;
-	case TIOCSSOFTCAR:
-		arg = get_fs_long((ulong *) arg);
-		tty->termios->c_cflag =
-		    ((tty->termios->c_cflag & ~CLOCAL) |
-		     (arg ? CLOCAL : 0));
-		return 0;
-	case TIOCMGET:
-		error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-		if (error)
-			return error;
-		return isdn_tty_get_modem_info(info, (uint *) arg);
-	case TIOCMBIS:
-	case TIOCMBIC:
-	case TIOCMSET:
-		return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
-	case TIOCSERGETLSR:	/* Get line status register */
-		error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-		if (error)
-			return error;
-		else
-			return isdn_tty_get_lsr_info(info, (uint *) arg);
-
-	case TIOCGSERIAL:
-		return -ENOIOCTLCMD;
-#if 0
-		error = verify_area(VERIFY_WRITE, (void *) arg,
-				    sizeof(struct serial_struct));
-		if (error)
-			return error;
-		return get_serial_info(info,
-				       (struct serial_struct *) arg);
-#endif
-	case TIOCSSERIAL:
-		return -ENOIOCTLCMD;
-#if 0
-		return set_serial_info(info,
-				       (struct serial_struct *) arg);
-#endif
-	case TIOCSERCONFIG:
-		return -ENOIOCTLCMD;
-#if 0
-		return do_autoconfig(info);
-#endif
-
-	case TIOCSERGWILD:
-		return -ENOIOCTLCMD;
-#if 0
-		error = verify_area(VERIFY_WRITE, (void *) arg,
-				    sizeof(int));
-		if (error)
-			return error;
-		put_fs_long(modem_wild_int_mask, (ulong *) arg);
-		return 0;
+                case TCSBRK:		/* SVID version: non-zero arg --> no break */
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
 #endif
-	case TIOCSERSWILD:
-		return -ENOIOCTLCMD;
-#if 0
-		if (!suser())
-			return -EPERM;
-		modem_wild_int_mask = get_fs_long((ulong *) arg);
-		if (modem_wild_int_mask < 0)
-			modem_wild_int_mask = check_wild_interrupts(0);
-		return 0;
+                        retval = tty_check_change(tty);
+                        if (retval)
+                                return retval;
+                        tty_wait_until_sent(tty, 0);
+                        return 0;
+                case TCSBRKP:		/* support for POSIX tcsendbreak() */
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
 #endif
-	case TIOCSERGSTRUCT:
-		return -ENOIOCTLCMD;
-#if 0
-		error = verify_area(VERIFY_WRITE, (void *) arg,
-				    sizeof(modem_info));
-		if (error)
-			return error;
-		memcpy_tofs((modem_info *) arg,
-			    info, sizeof(modem_info));
-		return 0;
+                        retval = tty_check_change(tty);
+                        if (retval)
+                                return retval;
+                        tty_wait_until_sent(tty, 0);
+                        return 0;
+                case TIOCGSOFTCAR:
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
+#endif
+                        error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+                        if (error)
+                                return error;
+                        put_fs_long(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
+                        return 0;
+                case TIOCSSOFTCAR:
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
+#endif
+                        arg = get_fs_long((ulong *) arg);
+                        tty->termios->c_cflag =
+                                ((tty->termios->c_cflag & ~CLOCAL) |
+                                 (arg ? CLOCAL : 0));
+                        return 0;
+                case TIOCMGET:
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
+#endif
+                        error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
+                        if (error)
+                                return error;
+                        return isdn_tty_get_modem_info(info, (uint *) arg);
+                case TIOCMBIS:
+                case TIOCMBIC:
+                case TIOCMSET:
+                        error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
+                        if (error)
+                                return error;
+                        return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
+                case TIOCSERGETLSR:	/* Get line status register */
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+                        printk(KERN_DEBUG "ttyI%d ioctl TIOSERGETLSR\n", info->line);
 #endif
-	default:
+                        error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
+                        if (error)
+                                return error;
+                        else
+                                return isdn_tty_get_lsr_info(info, (uint *) arg);
+                        
+                default:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-		printk(KERN_DEBUG "unsupp. ioctl 0x%08x on ttyi%d\n", cmd, info->line);
+                        printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
 #endif
-		return -ENOIOCTLCMD;
+                        return -ENOIOCTLCMD;
 	}
 	return 0;
 }
@@ -757,13 +1064,17 @@
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 
-	if (tty->termios->c_cflag == old_termios->c_cflag)
-		return;
-	isdn_tty_change_speed(info);
-	if ((old_termios->c_cflag & CRTSCTS) &&
-	    !(tty->termios->c_cflag & CRTSCTS)) {
-		tty->hw_stopped = 0;
-	}
+        if (!old_termios)
+                isdn_tty_change_speed(info);
+        else {
+                if (tty->termios->c_cflag == old_termios->c_cflag)
+                        return;
+                isdn_tty_change_speed(info);
+                if ((old_termios->c_cflag & CRTSCTS) &&
+                    !(tty->termios->c_cflag & CRTSCTS)) {
+                        tty->hw_stopped = 0;
+                }
+        }
 }
 
 /*
@@ -817,7 +1128,8 @@
 	 * If non-blocking mode is set, then make the check up front
 	 * and then exit.
 	 */
-	if (filp->f_flags & O_NONBLOCK) {
+	if ((filp->f_flags & O_NONBLOCK) ||
+            (tty->flags & (1 << TTY_IO_ERROR))) {
 		if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
 			return -EBUSY;
 		info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
@@ -865,9 +1177,7 @@
 		}
 		if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
 		    !(info->flags & ISDN_ASYNC_CLOSING) &&
-		    (do_clocal || (
-					  dev->mdm.msr[info->line] &
-					  UART_MSR_DCD))) {
+		    (do_clocal || (info->msr & UART_MSR_DCD))) {
 			break;
 		}
 		if (current->signal & ~current->blocked) {
@@ -972,7 +1282,6 @@
 #endif
 		return;
 	}
-	dev->modempoll--;
 	if ((tty->count == 1) && (info->count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
@@ -1007,8 +1316,7 @@
 	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
 		info->callout_termios = *tty->termios;
 
-	tty->closing = 1;
-
+        tty->closing = 1;
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1023,8 +1331,7 @@
 		 * important if there is a transmit FIFO!
 		 */
 		timeout = jiffies + HZ;
-		while (!(dev->mdm.mlr[info->line]
-			 & UART_LSR_TEMT)) {
+		while (!(info->lsr & UART_LSR_TEMT)) {
 			current->state = TASK_INTERRUPTIBLE;
 			current->timeout = jiffies + 20;
 			schedule();
@@ -1032,6 +1339,7 @@
 				break;
 		}
 	}
+	dev->modempoll--;
 	isdn_tty_shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
@@ -1039,22 +1347,10 @@
 		tty->ldisc.flush_buffer(tty);
 	info->tty = 0;
 	tty->closing = 0;
-#if 00
-	if (tty->ldisc.num != ldiscs[N_TTY].num) {
-		if (tty->ldisc.close)
-			(tty->ldisc.close) (tty);
-		tty->ldisc = ldiscs[N_TTY];
-		tty->termios->c_line = N_TTY;
-		if (tty->ldisc.open)
-			(tty->ldisc.open) (tty);
-	}
-#endif
 	if (info->blocked_open) {
-		if (info->close_delay) {
-			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
-		}
+                current->state = TASK_INTERRUPTIBLE;
+                current->timeout = jiffies + 50;
+                schedule();
 		wake_up_interruptible(&info->open_wait);
 	}
 	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE |
@@ -1082,6 +1378,8 @@
 	wake_up_interruptible(&info->open_wait);
 }
 
+/* This routine initializes all emulator-data.
+ */
 static void isdn_tty_reset_profile(atemu * m)
 {
 	m->profile[0] = 0;
@@ -1097,22 +1395,32 @@
 	m->profile[10] = 7;
 	m->profile[11] = 70;
 	m->profile[12] = 0x45;
-	m->profile[13] = 0;
+	m->profile[13] = 4;
 	m->profile[14] = ISDN_PROTO_L2_X75I;
 	m->profile[15] = ISDN_PROTO_L3_TRANS;
 	m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16;
 	m->profile[17] = ISDN_MODEM_WINSIZE;
-	m->profile[18] = 7;
+	m->profile[18] = 4;
 	m->profile[19] = 0;
+	m->profile[20] = 0;
 	m->pmsn[0] = '\0';
 }
 
+static void isdn_tty_modem_reset_vpar(atemu *m)
+{
+        m->vpar[0] = 2;  /* Voice-device            (2 = phone line) */
+        m->vpar[1] = 0;  /* Silence detection level (0 = none      ) */
+        m->vpar[2] = 70; /* Silence interval        (7 sec.        ) */
+        m->vpar[3] = 2;  /* Compression type        (1 = ADPCM-2   ) */
+}
+
 static void isdn_tty_modem_reset_regs(atemu * m, int force)
 {
 	if ((m->mdmreg[12] & 32) || force) {
 		memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
 		memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
 	}
+        isdn_tty_modem_reset_vpar(m);
 	m->mdmcmdl = 0;
 }
 
@@ -1131,10 +1439,6 @@
 	modem_info *info;
 
 	m = &dev->mdm;
-	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		isdn_tty_reset_profile(&(m->atmodem[i]));
-		isdn_tty_modem_reset_regs(&(m->atmodem[i]), 1);
-	}
 	memset(&m->tty_modem, 0, sizeof(struct tty_driver));
 	m->tty_modem.magic = TTY_DRIVER_MAGIC;
 	m->tty_modem.name = isdn_ttyname_ttyI;
@@ -1148,8 +1452,8 @@
 	m->tty_modem.flags = TTY_DRIVER_REAL_RAW;
 	m->tty_modem.refcount = &m->refcount;
 	m->tty_modem.table = m->modem_table;
-	m->tty_modem.termios = m->modem_termios;
-	m->tty_modem.termios_locked = m->modem_termios_locked;
+	m->tty_modem.termios = (struct termios **)m->modem_termios;
+	m->tty_modem.termios_locked = (struct termios **)m->modem_termios_locked;
 	m->tty_modem.open = isdn_tty_open;
 	m->tty_modem.close = isdn_tty_close;
 	m->tty_modem.write = isdn_tty_write;
@@ -1184,11 +1488,12 @@
 		return -2;
 	}
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		info = &(m->info[i]);
+		info = &m->info[i];
+		isdn_tty_reset_profile(&info->emu);
+		isdn_tty_modem_reset_regs(&info->emu, 1);
 		info->magic = ISDN_ASYNC_MAGIC;
 		info->line = i;
 		info->tty = 0;
-		info->close_delay = 50;
 		info->x_char = 0;
 		info->count = 0;
 		info->blocked_open = 0;
@@ -1196,16 +1501,15 @@
 		info->normal_termios = m->tty_modem.init_termios;
 		info->open_wait = 0;
 		info->close_wait = 0;
-		info->type = ISDN_PORT_16550A;
 		info->isdn_driver = -1;
 		info->isdn_channel = -1;
 		info->drv_index = -1;
 		info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
-		if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
+		if (!(info->xmit_buf = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL))) {
 			printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
 			return -3;
 		}
-		info->xmit_buf += 4;	/* Make room for T.70 header */
+                skb_queue_head_init(info->xmit_buf);
 	}
 	return 0;
 }
@@ -1261,16 +1565,16 @@
 	printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
 #endif
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+                modem_info *info = &dev->mdm.info[i];
 #ifdef ISDN_DEBUG_MODEM_ICALL
 		printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i,
-		       dev->mdm.atmodem[i].msn, isdn_map_eaz2msn(dev->mdm.atmodem[i].msn, di),
-		       dev->mdm.atmodem[i].mdmreg[18], dev->mdm.atmodem[i].mdmreg[19]);
+		       info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di),
+		       info->emu.mdmreg[18], info->emu.mdmreg[19]);
 #endif
-		if ((!strcmp(isdn_map_eaz2msn(dev->mdm.atmodem[i].msn, di)
-			     ,eaz)) &&	/* EAZ is matching   */
-		    (dev->mdm.atmodem[i].mdmreg[18] == si1) &&	/* SI1 is matching   */
-		    (dev->mdm.atmodem[i].mdmreg[19] == si2)) {	/* SI2 is matching   */
-			modem_info *info = &dev->mdm.info[i];
+		if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di),
+                             eaz)) &&                             /* EAZ is matching      */
+		    (info->emu.mdmreg[18] & si2bit[si1]) &&       /* SI1 is matching      */
+		    ((info->emu.mdmreg[19] == si2) || !si2)) {    /* SI2 is matching or 0 */
 			idx = isdn_dc2minor(di, ch);
 #ifdef ISDN_DEBUG_MODEM_ICALL
 			printk(KERN_DEBUG "m_fi: match1\n");
@@ -1287,8 +1591,9 @@
 				info->drv_index = idx;
 				dev->m_idx[idx] = info->line;
 				dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
-				dev->usage[idx] |= ISDN_USAGE_MODEM;
+				dev->usage[idx] |= (si1==1)?ISDN_USAGE_VOICE:ISDN_USAGE_MODEM;
 				strcpy(dev->num[idx], nr);
+                                info->emu.mdmreg[20] = si2bit[si1];
 				isdn_info_update();
 				restore_flags(flags);
 				printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
@@ -1316,7 +1621,7 @@
 static void isdn_tty_at_cout(char *msg, modem_info * info)
 {
 	struct tty_struct *tty;
-	atemu *m = &(dev->mdm.atmodem[info->line]);
+	atemu *m = &info->emu;
 	char *p;
 	char c;
 	ulong flags;
@@ -1330,17 +1635,17 @@
 	tty = info->tty;
 	for (p = msg; *p; p++) {
 		switch (*p) {
-		case '\r':
-			c = m->mdmreg[3];
-			break;
-		case '\n':
-			c = m->mdmreg[4];
-			break;
-		case '\b':
-			c = m->mdmreg[5];
-			break;
-		default:
-			c = *p;
+                        case '\r':
+                                c = m->mdmreg[3];
+                                break;
+                        case '\n':
+                                c = m->mdmreg[4];
+                                break;
+                        case '\b':
+                                c = m->mdmreg[5];
+                                break;
+                        default:
+                                c = *p;
 		}
 		if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
 			restore_flags(flags);
@@ -1363,8 +1668,8 @@
 #ifdef ISDN_DEBUG_MODEM_HUP
 		printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
 #endif
-		isdn_tty_modem_hup(info);
 		isdn_tty_modem_result(3, info);
+		isdn_tty_modem_hup(info);
 	}
 }
 
@@ -1433,43 +1738,45 @@
  */
 void isdn_tty_modem_result(int code, modem_info * info)
 {
-	atemu *m = &dev->mdm.atmodem[info->line];
+	atemu *m = &info->emu;
 	static char *msg[] =
 	{"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
 	 "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
-	 "RINGING", "NO MSN/EAZ"};
+	 "RINGING", "NO MSN/EAZ", "VCON"};
 	ulong flags;
 	char s[4];
 
 	switch (code) {
-	case 2:
-		m->mdmreg[1]++;	/* RING */
-		if (m->mdmreg[1] == m->mdmreg[0]) {
-			/* Accept incoming call */
-			isdn_ctrl cmd;
-			m->mdmreg[1] = 0;
-			dev->mdm.msr[info->line] &= ~UART_MSR_RI;
-			cmd.driver = info->isdn_driver;
-			cmd.arg = info->isdn_channel;
-			cmd.command = ISDN_CMD_ACCEPTD;
-			dev->drv[info->isdn_driver]->interface->command(&cmd);
-		}
-		break;
-	case 3:
-		/* NO CARRIER */
-		save_flags(flags);
-		cli();
-		dev->mdm.msr[info->line] &= ~(UART_MSR_DCD | UART_MSR_RI);
-		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
-			restore_flags(flags);
-			return;
-		}
-		restore_flags(flags);
-		break;
-	case 1:
-	case 5:
-		dev->mdm.online[info->line] = 1;
-		break;
+                case 2:
+                        m->mdmreg[1]++;	/* RING */
+                        if (m->mdmreg[1] == m->mdmreg[0])
+                                /* Automatically accept incoming call */
+                                isdn_tty_cmd_ATA(info);
+                        break;
+                case 3:
+                        /* NO CARRIER */
+                        save_flags(flags);
+                        cli();
+#ifdef ISDN_DEBUG_MODEM_HUP
+                        printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
+                               (info->flags & ISDN_ASYNC_CLOSING),
+                               (!info->tty));
+#endif
+                        if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+                                restore_flags(flags);
+                                return;
+                        }
+                        restore_flags(flags);
+                        break;
+                case 1:
+                case 5:
+                        if (!info->online)
+                                info->online = 2;
+                        break;
+                case 11:
+                        if (!info->online)
+                                info->online = 1;
+                        break;
 	}
 	if (m->mdmreg[12] & 1) {
 		/* Show results */
@@ -1503,8 +1810,9 @@
 		}
 		if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
 		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP))))
+		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
 			tty_hangup(info->tty);
+                }
 		restore_flags(flags);
 	}
 }
@@ -1516,7 +1824,7 @@
 {
 	char v[6];
 
-	sprintf(v, "%d\r\n", dev->mdm.atmodem[info->line].mdmreg[ridx]);
+	sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]);
 	isdn_tty_at_cout(v, info);
 }
 
@@ -1546,319 +1854,594 @@
 	*q = 0;
 }
 
+#define PARSE_ERROR { isdn_tty_modem_result(4, info); return; }
+#define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; }
+
+/*
+ * Parse AT&.. commands.
+ */
+static int isdn_tty_cmd_ATand(char **p, modem_info * info)
+{
+        atemu *m = &info->emu;
+        int i;
+        char rb[100];
+
+        switch (*p[0]) {
+                case 'B':
+                        /* &B - Set Buffersize */
+                        p[0]++;
+                        i = isdn_getnum(p);
+                        if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE))
+                                PARSE_ERROR1;
+#ifdef CONFIG_ISDN_AUDIO
+                        if ((m->mdmreg[18] & 1) && (i > VBUF))
+                                PARSE_ERROR1;
+#endif
+                        m->mdmreg[16] = i / 16;
+                        info->xmit_size = m->mdmreg[16] * 16;
+                        break;
+                case 'D':
+                        /* &D - Set DCD-Low-behavior */
+                        p[0]++;
+                        switch (isdn_getnum(p)) {
+                                case 0:
+                                        m->mdmreg[13] &= ~4;
+                                        break;
+                                case 2:
+                                        m->mdmreg[13] |= 4;
+                                        m->mdmreg[12] &= ~32;
+                                        break;
+                                case 3:
+                                        m->mdmreg[13] |= 4;
+                                        m->mdmreg[12] |= 32;
+                                        break;
+                                default:
+                                        PARSE_ERROR1
+                        }
+                        break;
+                case 'E':
+                        /* &E -Set EAZ/MSN */
+                        p[0]++;
+                        isdn_tty_get_msnstr(m->msn, p);
+                        break;
+                case 'F':
+                        /* &F -Set Factory-Defaults */
+                        p[0]++;
+                        isdn_tty_reset_profile(m);
+                        isdn_tty_modem_reset_regs(m, 1);
+                        break;
+                case 'S':
+                        /* &S - Set Windowsize */
+                        p[0]++;
+                        i = isdn_getnum(p);
+                        if ((i > 0) && (i < 9))
+                                m->mdmreg[17] = i;
+                        else
+                                PARSE_ERROR1;
+                        break;
+                case 'V':
+                        /* &V - Show registers */
+                        p[0]++;
+                        for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
+                                sprintf(rb, "S%d=%d%s", i, 
+                                        m->mdmreg[i], (i == 6) ? "\r\n" : " ");
+                                isdn_tty_at_cout(rb, info);
+                        }
+                        sprintf(rb, "\r\nEAZ/MSN: %s\r\n",
+                                strlen(m->msn) ? m->msn : "None");
+                        isdn_tty_at_cout(rb, info);
+                        break;
+                case 'W':
+                        /* &W - Write Profile */
+                        p[0]++;
+                        switch (*p[0]) {
+                                case '0':
+                                        p[0]++;
+                                        modem_write_profile(m);
+                                        break;
+                                default:
+                                        PARSE_ERROR1;
+                        }
+                        break;
+                case 'X':
+                        /* &X - Switch to BTX-Mode */
+                        p[0]++;
+                        switch (isdn_getnum(p)) {
+                                case 0:
+                                        m->mdmreg[13] &= ~2;
+                                        break;
+                                case 1:
+                                        m->mdmreg[13] |= 2;
+                                        m->mdmreg[14] = 0;
+                                        m->mdmreg[16] = 7;
+                                        info->xmit_size = 112;
+                                        m->mdmreg[18] = 4;
+                                        m->mdmreg[19] = 0;
+                                        break;
+                                default:
+                                        PARSE_ERROR1;
+                        }
+                        break;
+                default:
+                        PARSE_ERROR1;
+        }
+        return 0;
+}
+
+/*
+ * Perform ATS command
+ */
+static int isdn_tty_cmd_ATS(char **p, modem_info * info)
+{
+        atemu *m = &info->emu;
+        int mreg;
+        int mval;
+
+        mreg = isdn_getnum(p);
+        if (mreg < 0 || mreg > ISDN_MODEM_ANZREG)
+                PARSE_ERROR1;
+        switch (*p[0]) {
+                case '=':
+                        p[0]++;
+                        mval = isdn_getnum(p);
+                        if (mval < 0 || mval > 255)
+                                PARSE_ERROR1;
+                        switch (mreg) {
+                                /* Some plausibility checks */
+                                case 14:
+                                        if (mval > ISDN_PROTO_L2_TRANS)
+                                                PARSE_ERROR1;
+                                        break;
+                                case 16:
+                                        if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
+                                                PARSE_ERROR1;
+#ifdef CONFIG_ISDN_AUDIO
+                                        if ((m->mdmreg[18] & 1) && (mval > VBUFX))
+                                                PARSE_ERROR1;
+#endif
+                                        info->xmit_size = mval * 16;
+                                        break;
+                                case 20:
+                                        PARSE_ERROR1;
+                        }
+                        m->mdmreg[mreg] = mval;
+                        break;
+                case '?':
+                        p[0]++;
+                        isdn_tty_show_profile(mreg, info);
+                        break;
+                default:
+                        PARSE_ERROR1;
+                        break;
+        }
+        return 0;
+}
+
+/*
+ * Perform ATA command
+ */
+static void isdn_tty_cmd_ATA(modem_info * info)
+{
+        atemu *m = &info->emu;
+        isdn_ctrl cmd;
+        int l2;
+
+        if (info->msr & UART_MSR_RI) {
+                /* Accept incoming call */
+                m->mdmreg[1] = 0;
+                info->msr &= ~UART_MSR_RI;
+                l2 = m->mdmreg[14];
+#ifdef CONFIG_ISDN_AUDIO
+                /* If more than one bit set in reg18, autoselect Layer2 */
+                if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18])
+                        if (m->mdmreg[20] == 1) l2 = 4;
+#endif
+                cmd.driver = info->isdn_driver;
+                cmd.command = ISDN_CMD_SETL2;
+                cmd.arg = info->isdn_channel + (l2 << 8);
+                dev->drv[info->isdn_driver]->interface->command(&cmd);
+                cmd.driver = info->isdn_driver;
+                cmd.command = ISDN_CMD_SETL3;
+                cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
+                dev->drv[info->isdn_driver]->interface->command(&cmd);
+                cmd.driver = info->isdn_driver;
+                cmd.arg = info->isdn_channel;
+                cmd.command = ISDN_CMD_ACCEPTD;
+                dev->drv[info->isdn_driver]->interface->command(&cmd);
+        } else
+                isdn_tty_modem_result(8, info);
+}
+
+#ifdef CONFIG_ISDN_AUDIO
+/*
+ * Parse AT+V.. commands
+ */
+static int isdn_tty_cmd_PLUSV(char **p, modem_info * info)
+{
+        atemu *m = &info->emu;
+        static char *vcmd[] = {"NH","IP","LS","RX","SD","SM","TX",NULL};
+        int i;
+	int par1;
+	int par2;
+	char rs[20];
+
+        i = 0;
+        while (vcmd[i]) {
+                if (!strncmp(vcmd[i],p[0],2)) {
+                        p[0] += 2;
+                        break;
+                }
+                i++;
+        }
+        switch (i) {
+                case 0:
+                        /* AT+VNH - Auto hangup feature */
+                        switch (*p[0]) {
+                                case '?':
+                                        p[0]++;
+                                        isdn_tty_at_cout("\r\n1", info);
+                                        break;
+                                case '=':
+                                        p[0]++;
+                                        switch (*p[0]) {
+                                                case '1':
+                                                        p[0]++;
+                                                        break;
+                                                case '?':
+                                                        p[0]++;
+                                                        isdn_tty_at_cout("\r\n1", info);
+                                                        break;
+                                                default:
+                                                        PARSE_ERROR1;
+                                        }
+                                        break;
+                                default:
+                                        PARSE_ERROR1;
+                        }
+                        break;
+                case 1:
+                        /* AT+VIP - Reset all voice parameters */
+                        isdn_tty_modem_reset_vpar(m);
+                        break;
+                case 2:
+                        /* AT+VLS - Select device, accept incoming call */
+                        switch (*p[0]) {
+                                case '?':
+                                        p[0]++;
+                                        sprintf(rs,"\r\n%d",m->vpar[0]);
+                                        isdn_tty_at_cout(rs, info);
+                                        break;
+                                case '=':
+                                        p[0]++;
+                                        switch (*p[0]) {
+                                                case '0':
+                                                        p[0]++;
+                                                        m->vpar[0] = 0;
+                                                        break;
+                                                case '2':
+                                                        p[0]++;
+                                                        m->vpar[0] = 2;
+                                                        break;
+                                                case '?':
+                                                        p[0]++;
+                                                        isdn_tty_at_cout("\r\n0,2", info);
+                                                        break;
+                                                default:
+                                                        PARSE_ERROR1;
+                                        }
+                                        break;
+                                default:
+                                        PARSE_ERROR1;
+                        }
+                        break;
+                case 3:
+                        /* AT+VRX - Start recording */
+                        if (!m->vpar[0])
+                                PARSE_ERROR1;
+                        if (m->vpar[3] < 5) {
+                                info->adpcmr = isdn_audio_adpcm_init(m->vpar[3]);
+                                if (!info->adpcmr) {
+                                        printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
+                                        PARSE_ERROR1;
+                                }
+                        }
+                        info->vonline = 1;
+                        isdn_tty_modem_result(1, info);
+                        return 1;
+                        break;
+                case 4:
+                        /* AT+VSD - Silence detection */
+                        switch (*p[0]) {
+                                case '?':
+                                        p[0]++;
+                                        sprintf(rs,"\r\n<%d>,<%d>",
+                                                m->vpar[1],
+                                                m->vpar[2]);
+                                        isdn_tty_at_cout(rs, info);
+                                        break;
+                                case '=':
+                                        p[0]++;
+                                        switch (*p[0]) {
+                                                case '0':
+                                                case '1':
+                                                case '2':
+                                                case '3':
+                                                        par1 = isdn_getnum(p);
+                                                        if ((par1 < 0) || (par1 > 31))
+                                                                PARSE_ERROR1;
+                                                        if (*p[0] != ',')
+                                                                PARSE_ERROR1;
+                                                        p[0]++;
+                                                        par2 = isdn_getnum(p);
+                                                        if ((par2 < 0) || (par2 > 255))
+                                                                PARSE_ERROR1;
+                                                        m->vpar[1] = par1;
+                                                        m->vpar[2] = par2;
+                                                        break;
+                                                case '?':
+                                                        p[0]++;
+                                                        isdn_tty_at_cout("\r\n<0-31>,<0-255>",
+                                                                         info);
+                                                        break;
+                                                default:
+                                                        PARSE_ERROR1;
+                                        }
+                                        break;
+                                default:
+                                        PARSE_ERROR1;
+                        }
+                        break;
+                case 5:
+                        /* AT+VSM - Select compression */
+                        switch (*p[0]) {
+                                case '?':
+                                        p[0]++;
+                                        sprintf(rs,"\r\n<%d>,<%d><8000>",
+                                                m->vpar[3],
+                                                m->vpar[1]);
+                                        isdn_tty_at_cout(rs, info);
+                                        break;
+                                case '=':
+                                        p[0]++;
+                                        switch (*p[0]) {
+                                                case '2':
+                                                case '3':
+                                                case '4':
+                                                case '5':
+                                                case '6':
+                                                        par1 = isdn_getnum(p);
+                                                        if ((par1 < 2) || (par1 > 6))
+                                                                PARSE_ERROR1;
+                                                        m->vpar[3] = par1;
+                                                        break;
+                                                case '?':
+                                                        p[0]++;
+                                                        isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
+                                                                         info);
+                                                        isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
+                                                                         info);
+                                                        isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
+                                                                         info);
+                                                        isdn_tty_at_cout("5;ALAW;8;0;(8000)",
+                                                                         info);
+                                                        isdn_tty_at_cout("6;ULAW;8;0;(8000)",
+                                                                         info);
+                                                        break;
+                                                default:
+                                                        PARSE_ERROR1;
+                                        }
+                                        break;
+                                default:
+                                        PARSE_ERROR1;
+                        }
+                        break;
+                case 6:
+                        /* AT+VTX - Start sending */
+                        if (!m->vpar[0])
+                                PARSE_ERROR1;
+                        if (m->vpar[3] < 5) {
+                                info->adpcms = isdn_audio_adpcm_init(m->vpar[3]);
+                                if (!info->adpcms) {
+                                        printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
+                                        PARSE_ERROR1;
+                                }
+                        }
+                        info->vonline = 2;
+                        isdn_tty_modem_result(1, info);
+                        return 1;
+                        break;
+                default:
+                        PARSE_ERROR1;
+        }
+        return 0;
+}
+#endif        /* CONFIG_ISDN_AUDIO */
+
 /*
  * Parse and perform an AT-command-line.
- *
- * Parameter:
- *   channel   index to line (minor-device)
  */
 static void isdn_tty_parse_at(modem_info * info)
 {
-	atemu *m = &dev->mdm.atmodem[info->line];
-	char *p;
-	int mreg;
-	int mval;
-	int i;
-	char rb[100];
-	char ds[40];
-	isdn_ctrl cmd;
+        atemu *m = &info->emu;
+        char *p;
+        char ds[40];
 
 #ifdef ISDN_DEBUG_AT
-	printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
-#endif
-	for (p = &m->mdmcmd[2]; *p;) {
-		switch (*p) {
-		case 'A':
-			/* A - Accept incoming call */
-			p++;
-                        if (dev->mdm.msr[info->line] & UART_MSR_RI) {
-#define FIDOBUG
-#ifdef FIDOBUG
-/* Variables fido... defined temporarily for finding a strange bug */
-				driver *fido_drv;
-				isdn_if *fido_if;
-				int fido_isdn_driver;
-				modem_info *fido_modem_info;
-				int (*fido_command) (isdn_ctrl *);
-#endif
-				/* Accept incoming call */
-				m->mdmreg[1] = 0;
-				dev->mdm.msr[info->line] &= ~UART_MSR_RI;
-				cmd.driver = info->isdn_driver;
-				cmd.command = ISDN_CMD_SETL2;
-				cmd.arg = info->isdn_channel + (m->mdmreg[14] << 8);
-				dev->drv[info->isdn_driver]->interface->command(&cmd);
-				cmd.driver = info->isdn_driver;
-				cmd.command = ISDN_CMD_SETL3;
-				cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
-				dev->drv[info->isdn_driver]->interface->command(&cmd);
-				cmd.driver = info->isdn_driver;
-				cmd.arg = info->isdn_channel;
-				cmd.command = ISDN_CMD_ACCEPTD;
-#ifdef FIDOBUG
-				fido_modem_info = info;
-				fido_isdn_driver = fido_modem_info->isdn_driver;
-				fido_drv = dev->drv[fido_isdn_driver];
-				fido_if = fido_drv->interface;
-				fido_command = fido_if->command;
-				fido_command(&cmd);
-#else
-				dev->drv[info->isdn_driver]->interface->command(&cmd);
+        printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
 #endif
-			} else {
-				isdn_tty_modem_result(8, info);
-				return;
-			}
-			break;
-		case 'D':
-			/* D - Dial */
-			isdn_tty_getdial(++p, ds);
-			p += strlen(p);
-			if (!strlen(m->msn))
-				isdn_tty_modem_result(10, info);
-			else if (strlen(ds))
-				isdn_tty_dial(ds, info, m);
-			else
-				isdn_tty_modem_result(4, info);
-			return;
-		case 'E':
-			/* E - Turn Echo on/off */
-			p++;
-			switch (*p) {
-			case '0':
-				p++;
-				m->mdmreg[12] &= ~4;
-				break;
-			case '1':
-				p++;
-				m->mdmreg[12] |= 4;
-				break;
-			default:
-				isdn_tty_modem_result(4, info);
-				return;
-			}
-			break;
-		case 'H':
-			/* H - On/Off-hook */
-			p++;
-			switch (*p) {
-			case '0':
-				p++;
-				isdn_tty_on_hook(info);
-				break;
-			case '1':
-				p++;
-				isdn_tty_off_hook();
-				break;
-			default:
-				isdn_tty_on_hook(info);
-				break;
-			}
-			break;
-		case 'I':
-			/* I - Information */
-			p++;
-			isdn_tty_at_cout("ISDN for Linux  (c) by Fritz Elfert\r\n", info);
-			switch (*p) {
-			case '0':
-			case '1':
-				p++;
-				break;
-			default:
-			}
-			break;
-		case 'O':
-			/* O - Go online */
-			p++;
-			if (dev->mdm.msr[info->line] & UART_MSR_DCD)	/* if B-Channel is up */
-				isdn_tty_modem_result(5, info);
-			else
-				isdn_tty_modem_result(3, info);
-			return;
-		case 'Q':
-			/* Q - Turn Emulator messages on/off */
-			p++;
-			switch (*p) {
-			case '0':
-				p++;
-				m->mdmreg[12] |= 1;
-				break;
-			case '1':
-				p++;
-				m->mdmreg[12] &= ~1;
-				break;
-			default:
-				isdn_tty_modem_result(4, info);
-				return;
-			}
-			break;
-		case 'S':
-			/* S - Set/Get Register */
-			p++;
-			mreg = isdn_getnum(&p);
-			if (mreg < 0 || mreg > ISDN_MODEM_ANZREG) {
-				isdn_tty_modem_result(4, info);
-				return;
-			}
-			switch (*p) {
-			case '=':
-				p++;
-				mval = isdn_getnum(&p);
-				if (mval >= 0 && mval <= 255) {
-					if ((mreg == 16) && ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)) {
-						isdn_tty_modem_result(4, info);
-						return;
-					}
-					m->mdmreg[mreg] = mval;
-				} else {
-					isdn_tty_modem_result(4, info);
-					return;
-				}
-				break;
-			case '?':
-				p++;
-				isdn_tty_show_profile(mreg, info);
-				return;
-				break;
-			default:
-				isdn_tty_modem_result(4, info);
-				return;
-			}
-			break;
-		case 'V':
-			/* V - Numeric or ASCII Emulator-messages */
-			p++;
-			switch (*p) {
-			case '0':
-				p++;
-				m->mdmreg[12] |= 2;
-				break;
-			case '1':
-				p++;
-				m->mdmreg[12] &= ~2;
-				break;
-			default:
-				isdn_tty_modem_result(4, info);
-				return;
-			}
-			break;
-		case 'Z':
-			/* Z - Load Registers from Profile */
-			p++;
-			isdn_tty_modem_reset_regs(m, 1);
-			break;
-		case '+':
-			p++;
-			switch (*p) {
-			case 'F':
-				break;
-			}
-			break;
-		case '&':
-			p++;
-			switch (*p) {
-			case 'B':
-				/* &B - Set Buffersize */
-				p++;
-				i = isdn_getnum(&p);
-				if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE)) {
-					isdn_tty_modem_result(4, info);
-					return;
-				}
-				m->mdmreg[16] = i / 16;
-				break;
-			case 'D':
-				/* &D - Set DCD-Low-behavior */
-				p++;
-				switch (isdn_getnum(&p)) {
-				case 2:
-					m->mdmreg[12] &= ~32;
-					break;
-				case 3:
-					m->mdmreg[12] |= 32;
-					break;
-				default:
-					isdn_tty_modem_result(4, info);
-					return;
-				}
-				break;
-			case 'E':
-				/* &E -Set EAZ/MSN */
-				p++;
-				isdn_tty_get_msnstr(m->msn, &p);
-				break;
-			case 'F':
-				/* &F -Set Factory-Defaults */
-				p++;
-				isdn_tty_reset_profile(m);
-				isdn_tty_modem_reset_regs(m, 1);
-				break;
-			case 'S':
-				/* &S - Set Windowsize */
-				p++;
-				i = isdn_getnum(&p);
-				if ((i > 0) && (i < 9))
-					m->mdmreg[17] = i;
-				else {
-					isdn_tty_modem_result(4, info);
-					return;
-				}
-				break;
-			case 'V':
-				/* &V - Show registers */
-				p++;
-				for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
-					sprintf(rb, "S%d=%d%s", i, m->mdmreg[i], (i == 6) ? "\r\n" : " ");
-					isdn_tty_at_cout(rb, info);
-				}
-				sprintf(rb, "\r\nEAZ/MSN: %s\r\n", strlen(m->msn) ? m->msn : "None");
-				isdn_tty_at_cout(rb, info);
-				break;
-			case 'W':
-				/* &W - Write Profile */
-				p++;
-				switch (*p) {
-				case '0':
-					p++;
-					modem_write_profile(m);
-					break;
-				default:
-					isdn_tty_modem_result(4, info);
-					return;
-				}
-				break;
-			case 'X':
-				/* &X - Switch to BTX-Mode */
-				p++;
-				switch (*p) {
-				case '0':
-					p++;
-					m->mdmreg[13] &= ~2;
-					break;
-				case '1':
-					p++;
-					m->mdmreg[13] |= 2;
-					m->mdmreg[14] = 0;
-					m->mdmreg[16] = 7;
-					m->mdmreg[18] = 7;
-					m->mdmreg[19] = 0;
-					break;
-				default:
-					isdn_tty_modem_result(4, info);
-					return;
-				}
-				break;
-			default:
-				isdn_tty_modem_result(4, info);
-				return;
-			}
-			break;
-		default:
-			isdn_tty_modem_result(4, info);
-			return;
-		}
-	}
-	isdn_tty_modem_result(0, info);
+        for (p = &m->mdmcmd[2]; *p;) {
+                switch (*p) {
+                        case 'A':
+                                /* A - Accept incoming call */
+                                p++;
+                                isdn_tty_cmd_ATA(info);
+                                return;
+                                break;
+                        case 'D':
+                                /* D - Dial */
+                                isdn_tty_getdial(++p, ds);
+                                p += strlen(p);
+                                if (!strlen(m->msn))
+                                        isdn_tty_modem_result(10, info);
+                                else if (strlen(ds))
+                                        isdn_tty_dial(ds, info, m);
+                                else
+                                        isdn_tty_modem_result(4, info);
+                                return;
+                        case 'E':
+                                /* E - Turn Echo on/off */
+                                p++;
+                                switch (isdn_getnum(&p)) {
+                                        case 0:
+                                                m->mdmreg[12] &= ~4;
+                                                break;
+                                        case 1:
+                                                m->mdmreg[12] |= 4;
+                                                break;
+                                        default:
+                                                PARSE_ERROR;
+                                }
+                                break;
+                        case 'H':
+                                /* H - On/Off-hook */
+                                p++;
+                                switch (*p) {
+                                        case '0':
+                                                p++;
+                                                isdn_tty_on_hook(info);
+                                                break;
+                                        case '1':
+                                                p++;
+                                                isdn_tty_off_hook();
+                                                break;
+                                        default:
+                                                isdn_tty_on_hook(info);
+                                                break;
+                                }
+                                break;
+                        case 'I':
+                                /* I - Information */
+                                p++;
+                                isdn_tty_at_cout("\r\nLinux ISDN", info);
+                                switch (*p) {
+                                        case '0':
+                                        case '1':
+                                                p++;
+                                                break;
+                                        default:
+                                }
+                                break;
+                        case 'O':
+                                /* O - Go online */
+                                p++;
+                                if (info->msr & UART_MSR_DCD)
+                                        /* if B-Channel is up */
+                                        isdn_tty_modem_result(5, info);
+                                else
+                                        isdn_tty_modem_result(3, info);
+                                return;
+                        case 'Q':
+                                /* Q - Turn Emulator messages on/off */
+                                p++;
+                                switch (isdn_getnum(&p)) {
+                                        case 0:
+                                                m->mdmreg[12] |= 1;
+                                                break;
+                                        case 1:
+                                                m->mdmreg[12] &= ~1;
+                                                break;
+                                        default:
+                                                PARSE_ERROR;
+                                }
+                                break;
+                        case 'S':
+                                /* S - Set/Get Register */
+                                p++;
+                                if (isdn_tty_cmd_ATS(&p, info))
+                                        return;
+                                break;
+                        case 'V':
+                                /* V - Numeric or ASCII Emulator-messages */
+                                p++;
+                                switch (isdn_getnum(&p)) {
+                                        case 0:
+                                                m->mdmreg[12] |= 2;
+                                                break;
+                                        case 1:
+                                                m->mdmreg[12] &= ~2;
+                                                break;
+                                        default:
+                                                PARSE_ERROR;
+                                }
+                                break;
+                        case 'Z':
+                                /* Z - Load Registers from Profile */
+                                p++;
+                                isdn_tty_modem_reset_regs(m, 1);
+                                break;
+#ifdef CONFIG_ISDN_AUDIO
+                        case '+':
+                                p++;
+                                switch (*p) {
+                                        case 'F':
+                                                if (strncmp(p,"FCLASS",6))
+                                                        PARSE_ERROR;
+                                                p += 6;
+                                                switch (*p) {
+                                                        case '?':
+                                                                p++;
+                                                                sprintf(ds,"\r\n%d",
+                                                                        (m->mdmreg[18]&1)?8:0);
+                                                                isdn_tty_at_cout(ds, info);
+                                                                break;
+                                                        case '=':
+                                                                p++;
+                                                                switch (*p) {
+                                                                        case '0':
+                                                                                p++;
+                                                                                m->mdmreg[18] = 4;
+                                                                                break;
+                                                                        case '8':
+                                                                                p++;
+                                                                                m->mdmreg[18] = 5;
+                                                                                m->mdmreg[16] = VBUFX;
+                                                                                info->xmit_size = VBUF;
+                                                                                break;
+                                                                        case '?':
+                                                                                p++;
+                                                                                isdn_tty_at_cout("\r\n0,8",
+                                                                                                 info);
+                                                                                break;
+                                                                        default:
+                                                                                PARSE_ERROR;
+                                                                }
+                                                                break;
+                                                        default:
+                                                                PARSE_ERROR;
+                                                                
+                                                }
+                                                break;
+                                        case 'V':
+                                                if (!(m->mdmreg[18] & 1))
+                                                        PARSE_ERROR;
+                                                p++;
+                                                if (isdn_tty_cmd_PLUSV(&p, info))
+                                                        return;
+                                                break;
+                                }
+                                break;
+#endif        /* CONFIG_ISDN_AUDIO */
+                        case '&':
+                                p++;
+                                if (isdn_tty_cmd_ATand(&p, info))
+                                        return;
+                                break;
+                        default:
+                                isdn_tty_modem_result(4, info);
+                                return;
+                }
+        }
+        isdn_tty_modem_result(0, info);
 }
 
 /* Need own toupper() because standard-toupper is not available
@@ -1877,7 +2460,7 @@
  */
 static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
 {
-	atemu *m = &dev->mdm.atmodem[info->line];
+	atemu *m = &info->emu;
 	int total = 0;
 	u_char c;
 	char eb[2];
@@ -1921,16 +2504,16 @@
 			if (m->mdmcmdl < 255) {
 				c = my_toupper(c);
 				switch (m->mdmcmdl) {
-				case 0:
-					if (c == 'A')
-						m->mdmcmd[m->mdmcmdl++] = c;
-					break;
-				case 1:
-					if (c == 'T')
-						m->mdmcmd[m->mdmcmdl++] = c;
-					break;
-				default:
-					m->mdmcmd[m->mdmcmdl++] = c;
+                                        case 0:
+                                                if (c == 'A')
+                                                        m->mdmcmd[m->mdmcmdl++] = c;
+                                                break;
+                                        case 1:
+                                                if (c == 'T')
+                                                        m->mdmcmd[m->mdmcmdl++] = c;
+                                                break;
+                                        default:
+                                                m->mdmcmd[m->mdmcmdl++] = c;
 				}
 			}
 		}
@@ -1952,16 +2535,18 @@
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 		if (USG_MODEM(dev->usage[i]))
-			if ((midx = dev->m_idx[i]) >= 0)
-				if (dev->mdm.online[midx]) {
+			if ((midx = dev->m_idx[i]) >= 0) {
+                                modem_info *info = &dev->mdm.info[midx];
+				if (info->online) {
 					ton = 1;
-					if ((dev->mdm.atmodem[midx].pluscount == 3) &&
-					    ((jiffies - dev->mdm.atmodem[midx].lastplus) > PLUSWAIT2)) {
-						dev->mdm.atmodem[midx].pluscount = 0;
-						dev->mdm.online[midx] = 0;
-						isdn_tty_modem_result(0, &dev->mdm.info[midx]);
+					if ((info->emu.pluscount == 3) &&
+					    ((jiffies - info->emu.lastplus) > PLUSWAIT2)) {
+						info->emu.pluscount = 0;
+						info->online = 0;
+						isdn_tty_modem_result(0, info);
 					}
 				}
+                        }
 	isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
 }
 
@@ -1977,76 +2562,46 @@
 	int midx;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-		if (USG_MODEM(dev->usage[i]))
-			if ((midx = dev->m_idx[i]) >= 0)
-				if (dev->mdm.msr[midx] & UART_MSR_RI) {
+		if (USG_MODEMORVOICE(dev->usage[i]))
+			if ((midx = dev->m_idx[i]) >= 0) {
+                                modem_info *info = &dev->mdm.info[midx];
+				if (info->msr & UART_MSR_RI) {
 					ton = 1;
-					isdn_tty_modem_result(2, &dev->mdm.info[midx]);
+					isdn_tty_modem_result(2, info);
 				}
+                        }
 	isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
 }
 
+/*
+ * For all online tty's, try sending data to
+ * the lower levels.
+ */
 void isdn_tty_modem_xmit(void)
 {
 	int ton = 0;
 	int i;
 	int midx;
-	char *bufptr;
-	int buflen;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-		if (USG_MODEM(dev->usage[i]))
-			if ((midx = dev->m_idx[i]) >= 0)
-				if (dev->mdm.online[midx]) {
-					modem_info *info = &(dev->mdm.info[midx]);
-					ulong flags;
-
-					save_flags(flags);
-					cli();
-					if (info->xmit_count > 0) {
-						struct tty_struct *tty = info->tty;
+		if (USG_MODEMORVOICE(dev->usage[i]))
+			if ((midx = dev->m_idx[i]) >= 0) {
+                                modem_info *info = &dev->mdm.info[midx];
+				if ((info->online > 1) ||
+                                    (info->vonline ==2 )) {
+					if (skb_queue_len(info->xmit_buf)) {
 						ton = 1;
-#if 0
-						printk(KERN_DEBUG "WB2: %d\n", info->xmit_count);
-#endif
-						bufptr = info->xmit_buf;
-						buflen = info->xmit_count;
-						if (dev->mdm.atmodem[midx].mdmreg[13] & 2) {
-							/* Add T.70 simplified header */
-#ifdef ISDN_DEBUG_MODEM_DUMP
-							isdn_dumppkt("T70pack3:", bufptr, buflen, 40);
-#endif
-							bufptr -= 4;
-							buflen += 4;
-							memcpy(bufptr, "\1\0\1\0", 4);
-#ifdef ISDN_DEBUG_MODEM_DUMP
-							isdn_dumppkt("T70pack4:", bufptr, buflen, 40);
-#endif
-						}
-						if (isdn_writebuf_stub(info->isdn_driver, info->isdn_channel,
-                                                                       bufptr, buflen, 0) > 0) {
-							info->xmit_count = 0;
-							info->xmit_size = dev->mdm.atmodem[midx].mdmreg[16] * 16;
-#if FUTURE
-							info->send_outstanding++;
-							dev->mdm.msr[midx] &= ~UART_MSR_CTS;
-#endif
-							if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-							    tty->ldisc.write_wakeup)
-								(tty->ldisc.write_wakeup) (tty);
-							wake_up_interruptible(&tty->write_wait);
-						}
+                                                isdn_tty_senddown(info);
 					}
-					restore_flags(flags);
 				}
+                        }
 	isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
 }
 
-#if FUTURE
 /*
  * A packet has been output successfully.
  * Search the tty-devices for an appropriate device, decrement its
- * counter for outstanding packets, and set CTS if this counter reaches 0.
+ * counter for outstanding packets, and set CTS.
  */
 void isdn_tty_bsent(int drv, int chan)
 {
@@ -2058,15 +2613,13 @@
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		modem_info *info = &dev->mdm.info[i];
 		if ((info->isdn_driver == drv) &&
-		    (info->isdn_channel == chan) &&
-		    (info->send_outstanding)) {
-			if (!(--info->send_outstanding))
-				dev->mdm.msr[i] |= UART_MSR_CTS;
-			restore_flags(flags);
-			return;
-		}
+		    (info->isdn_channel == chan) ) {
+                        info->msr |= UART_MSR_CTS;
+                        if (info->send_outstanding)
+                                if (!(--info->send_outstanding))
+                                        info->lsr &= ~UART_LSR_TEMT;
+                }
 	}
 	restore_flags(flags);
 	return;
 }
-#endif				/* FUTURE */
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h
--- pre2.0.5/linux/drivers/isdn/isdn_tty.h	Mon Feb 26 11:58:05 1996
+++ linux/drivers/isdn/isdn_tty.h	Sun May 19 15:29:29 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.h,v 1.1 1996/01/10 21:39:22 fritz Exp fritz $
+/* $Id: isdn_tty.h,v 1.5 1996/05/17 03:52:31 fritz Exp $
  *
  * header for Linux ISDN subsystem, tty related functions (linklevel).
  *
@@ -20,6 +20,18 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_tty.h,v $
+ * Revision 1.5  1996/05/17 03:52:31  fritz
+ * Changed DLE handling for audio receive.
+ *
+ * Revision 1.4  1996/05/11 21:52:34  fritz
+ * Changed queue management to use sk_buffs.
+ *
+ * Revision 1.3  1996/05/07 09:16:34  fritz
+ * Changed isdn_try_read parameter.
+ *
+ * Revision 1.2  1996/04/30 21:05:27  fritz
+ * Test commit
+ *
  * Revision 1.1  1996/01/10 21:39:22  fritz
  * Initial revision
  *
@@ -32,8 +44,8 @@
 extern void  isdn_tty_modem_hup(modem_info *);
 extern int   isdn_tty_modem_init(void);
 extern void  isdn_tty_readmodem(void);
-extern int   isdn_tty_try_read(int, u_char *, int);
+extern int   isdn_tty_try_read(modem_info *, struct sk_buff *);
 extern int   isdn_tty_find_icall(int, int, char *);
-#if FUTURE
+extern int   isdn_tty_countDLE(unsigned char *, int);
 extern void  isdn_tty_bsent(int, int);
-#endif
+extern void  isdn_tty_cleanup_xmit(modem_info *);
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c
--- pre2.0.5/linux/drivers/isdn/pcbit/drv.c	Wed Apr 24 17:00:39 1996
+++ linux/drivers/isdn/pcbit/drv.c	Sun May 19 15:29:30 1996
@@ -52,9 +52,9 @@
  */
 
 int pcbit_command(isdn_ctrl* ctl);
-int pcbit_stat(u_char* buf, int len, int user);
+int pcbit_stat(u_char* buf, int len, int user, int, int);
 int pcbit_xmit(int driver, int chan, struct sk_buff *skb);
-int pcbit_writecmd(const u_char*, int, int);
+int pcbit_writecmd(const u_char*, int, int, int, int);
 
 static int set_protocol_running(struct pcbit_dev * dev);
 
@@ -390,19 +390,16 @@
 }
 
 
-int pcbit_writecmd(const u_char* buf, int len, int user)
+int pcbit_writecmd(const u_char* buf, int len, int user, int driver, int channel)
 {
 	struct pcbit_dev * dev;
-	int board, i, j;
+	int i, j;
 	const u_char * loadbuf;
 	u_char * ptr = NULL;
 
 	int errstat;
 
-	/* we should have the driver id as input here too - let's say it's 0 */
-	board = 0;
-
-	dev = dev_pcbit[board];
+	dev = finddev(driver);
 
 	if (!dev)
 	{
@@ -760,7 +757,7 @@
 (flag ? memcpy_tofs(d, s, len) : memcpy(d, s, len))
 
 
-int pcbit_stat(u_char* buf, int len, int user)
+int pcbit_stat(u_char* buf, int len, int user, int driver, int channel)
 {
 	int stat_count;
 	stat_count = stat_end - stat_st;
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/buffers.c linux/drivers/isdn/teles/buffers.c
--- pre2.0.5/linux/drivers/isdn/teles/buffers.c	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/buffers.c	Sun May 19 15:29:30 1996
@@ -1,6 +1,9 @@
-/* $Id: buffers.c,v 1.1 1996/04/13 10:19:28 fritz Exp $
+/* $Id: buffers.c,v 1.2 1996/04/29 22:48:14 fritz Exp $
  *
  * $Log: buffers.c,v $
+ * Revision 1.2  1996/04/29 22:48:14  fritz
+ * Removed compatibility-macros. No longer needed.
+ *
  * Revision 1.1  1996/04/13 10:19:28  fritz
  * Initial revision
  *
@@ -47,7 +50,7 @@
 	printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
 #endif
 
-	ptr = (struct Pages *) __get_free_pages(priority,bp->pageorder,0);
+	ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0);
 	if (!ptr) {
 		printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
 		return (-1);
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c
--- pre2.0.5/linux/drivers/isdn/teles/callc.c	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/callc.c	Sun May 19 15:29:30 1996
@@ -1,6 +1,24 @@
-/* $Id: callc.c,v 1.2 1996/04/20 16:42:29 fritz Exp fritz $
+/* $Id: callc.c,v 1.7 1996/05/17 03:40:37 fritz Exp $
  *
  * $Log: callc.c,v $
+ * Revision 1.7  1996/05/17 03:40:37  fritz
+ * General cleanup.
+ *
+ * Revision 1.6  1996/05/10 22:42:07  fritz
+ * Added entry for EV_RELEASE_CNF in ST_OUT (if no D-Channel avail.)
+ *
+ * Revision 1.5  1996/05/06 10:16:15  fritz
+ * Added voice stuff.
+ *
+ * Revision 1.4  1996/04/30 22:04:05  isdn4dev
+ *   improved callback  Karsten Keil
+ *
+ * Revision 1.3  1996/04/30 10:04:19  fritz
+ * Started voice support.
+ * Added printk() to debug-switcher for easier
+ * synchronization between printk()'s and output
+ * of /dev/isdnctrl.
+ *
  * Revision 1.2  1996/04/20 16:42:29  fritz
  * Changed statemachine to allow reject of incoming calls.
  *
@@ -43,17 +61,6 @@
 	teles_putstatus(tmp);
 }
 
-#ifdef DEFINED_BUT_NOT_USED
-static void
-stat_error(struct Channel *chanp, char *s)
-{
-        char            tmp[100];
-
-        sprintf(tmp, "Channel %d: %s\n", chanp->chan, s);
-        teles_putstatus(tmp);
-}
-#endif
-
 enum {
         ST_NULL,           /*  0 inactive                                               */
         ST_OUT,            /*  1 outgoing, awaiting SETUP confirm                       */
@@ -237,6 +244,7 @@
                   chanp->lc_b.l2_establish = !0;
                   break;
           case (ISDN_PROTO_L2_HDLC):
+          case (ISDN_PROTO_L2_TRANS):
                   chanp->lc_b.l2_establish = 0;
                   break;
           default:
@@ -419,6 +427,7 @@
                   chanp->lc_b.l2_establish = !0;
                   break;
           case (ISDN_PROTO_L2_HDLC):
+          case (ISDN_PROTO_L2_TRANS):
                   chanp->lc_b.l2_establish = 0;
                   break;
           default:
@@ -467,16 +476,6 @@
         iif.statcallb(&ic);
 }
 
-#ifdef DEFINED_BUT_NOT_USED
-static void
-prp(byte * p, int size)
-{
-        while (size--)
-                printk("%2x ", *p++);
-        printk("\n");
-}
-#endif
-
 static void
 r15(struct FsmInst *fi, int event, void *arg)
 {
@@ -664,6 +663,7 @@
         {ST_OUT,              EV_SETUP_CNF,           r10},
         {ST_OUT,              EV_HANGUP,              r2_1},
         {ST_OUT,              EV_RELEASE_IND,         r20},
+        {ST_OUT,              EV_RELEASE_CNF,         r20},
         {ST_OUT,              EV_DLRL,                r2_2},
         {ST_OUT_W_HANGUP,     EV_RELEASE_IND,         r2_2},
         {ST_OUT_W_HANGUP,     EV_DLRL,                r20},
@@ -674,7 +674,7 @@
         {ST_IN_W,             EV_DLEST,               r7},
         {ST_IN_W,             EV_DLRL,                r3_1},
         {ST_IN,               EV_DLRL,                r3_1},
-        {ST_IN,               EV_HANGUP,              r3_1},
+        {ST_IN,               EV_HANGUP,              r2_1},
         {ST_IN,               EV_RELEASE_IND,         r2_2},
         {ST_IN,               EV_RELEASE_CNF,         r2_2},
         {ST_IN,               EV_ACCEPTD,             r8},
@@ -830,6 +830,7 @@
                   releasestack_isdnl2(st);
                   break;
           case (ISDN_PROTO_L2_HDLC):
+          case (ISDN_PROTO_L2_TRANS):
                   releasestack_transl2(st);
                   break;
         }
@@ -1121,22 +1122,13 @@
         BufQueueRelease(&st->l2.i_queue);
 }
 
-static void
-release_chan(int chan)
-{
-#if 0
-        release_ds(chan);
-#endif
-        release_is(chan);
-}
-
 void
 CallcFreeChan(void)
 {
         int             i;
 
         for (i = 0; i < chancount; i++)
-                release_chan(i);
+                release_is(i);
         Sfree((void *) chanlist);
 }
 
@@ -1248,6 +1240,14 @@
                   st->l1.hscxmode = 2;
                   st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
                   break;
+          case (ISDN_PROTO_L2_TRANS):
+                  st->l1.l1l2 = lltrans_handler;
+                  st->l1.l1man = dcc_l1man;
+                  st->l4.userdata = chanlist + chan;
+                  st->l4.l1writewakeup = ll_writewakeup;
+                  st->l1.hscxmode = 1;
+                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
+                  break;
         }
 
         return (0);
@@ -1345,6 +1345,7 @@
                             distr_debug();
                             sprintf(tmp, "debugging flags set to %x\n", debugflags);
                             teles_putstatus(tmp);
+			    printk(KERN_DEBUG "%s", tmp);
                             break;
                     case (2):
                             num = *(unsigned int *) ic->num;
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c
--- pre2.0.5/linux/drivers/isdn/teles/card.c	Mon Apr 29 18:05:17 1996
+++ linux/drivers/isdn/teles/card.c	Sun May 19 15:29:30 1996
@@ -1,4 +1,4 @@
-/* $Id: card.c,v 1.1 1996/04/13 10:22:42 fritz Exp $
+/* $Id: card.c,v 1.5 1996/05/17 03:45:02 fritz Exp $
  *
  * card.c     low level stuff for the Teles S0 isdn card
  * 
@@ -7,6 +7,28 @@
  * Beat Doebeli         log all D channel traffic
  * 
  * $Log: card.c,v $
+ * Revision 1.5  1996/05/17 03:45:02  fritz
+ * Made error messages more clearly.
+ * Bugfix: Only 31 bytes of 32-byte audio frames
+ *         have been transfered to upper layers.
+ *
+ * Revision 1.4  1996/05/06 10:17:57  fritz
+ * Added voice-send stuff
+ *  (Not reporting EXIR when in voice-mode, since it's normal).
+ *
+ * Revision 1.3  1996/04/30 22:02:40  isdn4dev
+ * Bugfixes for 16.3
+ *     -improved IO allocation
+ *     -fix second B channel problem
+ *     -correct ph_command patch
+ *
+ * Revision 1.2  1996/04/30 10:00:59  fritz
+ * Bugfix: Added ph_command(8) for 16.3.
+ * Bugfix: Ports did not get registered correctly
+ *         when using a 16.3.
+ *         Started voice support.
+ *         Some experimental changes of waitforXFW().
+ *
  * Revision 1.1  1996/04/13 10:22:42  fritz
  * Initial revision
  *
@@ -21,6 +43,7 @@
 #include <linux/interrupt.h>
 
 #undef DCHAN_VERBOSE
+#define FRITZ_EXPERIMENTAL
 
 extern void     tei_handler(struct PStack *st, byte pr,
 			    struct BufHeader *ibh);
@@ -183,11 +206,16 @@
 static inline void
 waitforXFW_0(byte * base, byte hscx)
 {
+#ifdef FRITZ_EXPERIMENTAL
+	long            to = 20;
+
+	while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
+#else
 	long            to = 10;
 
 	waitforCEC_0(base, hscx);
-
 	while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x40)) && to) {
+#endif
 		udelay(5);
 		to--;
 	}
@@ -198,11 +226,16 @@
 static inline void
 waitforXFW_3(int iobase, byte hscx)
 {
+#ifdef FRITZ_EXPERIMENTAL
+	long            to = 20;
+
+	while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
+#else
 	long            to = 10;
 
 	waitforCEC_3(iobase, hscx);
-
 	while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x40)) && to) {
+#endif
 		udelay(5);
 		to--;
 	}
@@ -332,15 +365,6 @@
                 readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
                 writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80);
         }
-#ifdef BCHAN_VERBOSE
-        {
-                int i;
-                printk(KERN_DEBUG "hscx_empty_fifo");
-                for (i = 0; i < count; i++)
-                        printk(" %2x", ptr[i]);
-                printk("\n");
-        }
-#endif				/* BCHAN_VERBOSE */
 }
 
 static void
@@ -361,15 +385,7 @@
 	if (count <= 0)
 		return;
 
-#if 0
-	if (!hsp->sendptr) {
-		ptr = DATAPTR(ibh);
-		printk(KERN_DEBUG "snd bytes %2x %2x %2x %2x %2x\n", ptr[0], ptr[1], ptr[2],
-		       ptr[3], ptr[4]);
-	}
-#endif
-
-	more = 0;
+	more = (hsp->mode == 1)?1:0;
 	if (count > 32) {
 		more = !0;
 		count = 32;
@@ -417,7 +433,7 @@
 				printk(KERN_WARNING
                                        "Teles: HSCX invalid frame\n");
 			if (r & 0x40)
-				printk(KERN_WARNING "Teles: HSCX RDO\n");
+				printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode);
 			if (!r & 0x20)
 				printk(KERN_WARNING "Teles: HSCX CRC error\n");
 			if (hsp->rcvibh)
@@ -455,7 +471,7 @@
 			if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
 				       GFP_ATOMIC, (void *) 1, 2)) {
 				printk(KERN_WARNING
-                                       "HSCX RME out of buffers at %ld\n",
+                                       "HSCX RPF out of buffers at %ld\n",
                                        jiffies);
 				WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
                                                hsp->hscx, 0x80);
@@ -464,12 +480,14 @@
 				hsp->rcvptr = 0;
 
 		hscx_empty_fifo(hsp, 32);
-#ifdef VOICE
-		hsp->rcvibh->datasize = hsp->rcvptr - 1;
-		BufQueueLink(&hsp->rq, hsp->rcvibh);
-		hsp->rcvibh = NULL;
-		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-#endif
+                if (hsp->mode == 1) {
+                        /* receive audio data */
+                        hsp->rcvibh->datasize = hsp->rcvptr;
+                        BufQueueLink(&hsp->rq, hsp->rcvibh);
+                        hsp->rcvibh = NULL;
+                        hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+                }
+                
 	}
       afterRPF:
 	if (val & 0x10) {	/* XPR */
@@ -651,8 +669,17 @@
 			  ph_command(sp, 9);
 		  break;
 	  case (12):
+	          ph_command(sp, 8);
+		  sp->ph_active = 5;
+		  isac_sched_event(sp, ISAC_PHCHANGE);
+		  if (!sp->xmtibh)
+			  if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
+				  sp->sendptr = 0;
+		  if (sp->xmtibh)
+			  fill_fifo(sp);
+		  break;
 	  case (13):
-	  	  ph_command(sp, 8);
+	          ph_command(sp, 9);
 		  sp->ph_active = 5;
 		  isac_sched_event(sp, ISAC_PHCHANGE);
 		  if (!sp->xmtibh)
@@ -673,7 +700,7 @@
 static void
 teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-	byte                 val, val2, r;
+	byte                 val, val2, r, exval;
 	struct IsdnCardState *sp;
 	unsigned int         count;
 	struct HscxState     *hsp;
@@ -688,10 +715,12 @@
 
 	if (val & 0x01) {
 		hsp = sp->hs + 1;
-		printk(KERN_WARNING "HSCX B EXIR %x xmitbh %lx rcvibh %lx\n",
-                       READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR),
-                       (long) hsp->xmtibh,
-		       (long) hsp->rcvibh);
+                exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR);
+                if ((hsp->mode == 1) || (exval == 0x40))
+                        hscx_fill_fifo(hsp);
+                else
+                        printk(KERN_WARNING "HSCX B EXIR %x xmitbh %lx rcvibh %lx\n",
+                               exval, (long) hsp->xmtibh, (long) hsp->rcvibh);
 	}
 	if (val & 0xf8) {
 		if (sp->debug)
@@ -699,8 +728,12 @@
 		hscx_interrupt(sp, val, 1);
 	}
 	if (val & 0x02) {
-		printk(KERN_WARNING "HSCX A EXIR %x\n",
-                       READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR));
+		hsp = sp->hs;
+                exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR);
+                if ((hsp->mode == 1) && (exval == 0x40))
+                        hscx_fill_fifo(hsp);
+                else
+                        printk(KERN_WARNING "HSCX A EXIR %x\n",exval);
 	}
 
 /* ??? Why do that vvvvvvvvvvvvvvvvvvvvv different on Teles 16-3 ??? */
@@ -1057,17 +1090,46 @@
                         case 0x180:
                         case 0x280:
                         case 0x380:
-                                printk(KERN_INFO "teles: port 0x%x specified, assuming 0x%x\n",
-                                       card->iobase, (card->iobase | 0xc00));
                                 card->iobase |= 0xc00;
                                 break;
                 }
-                if (check_region(card->iobase, 8)) {
-                        printk(KERN_WARNING
-                               "teles: ports %x-%x already in use\n",
-                               card->iobase,
-                               card->iobase + 8 );
-                        return -1;
+                if (card->membase) {  /* 16.0 */
+                	if (check_region(card->iobase, 8)) {
+                        	printk(KERN_WARNING
+                               		"teles: ports %x-%x already in use\n",
+                               		card->iobase,
+                               		card->iobase + 8 );
+                        	return -1;
+                	}
+                } else { /* 16.3 */
+                	if (check_region(card->iobase, 16)) {
+                        	printk(KERN_WARNING
+                               		"teles: 16.3 ports %x-%x already in use\n",
+                               		card->iobase,
+                               		card->iobase + 16 );
+                        	return -1;
+                	}
+                	if (check_region((card->iobase - 0xc00) , 32)) {
+                        	printk(KERN_WARNING
+                  			"teles: 16.3 ports %x-%x already in use\n",
+                               		card->iobase - 0xc00,
+                               		card->iobase - 0xc00 + 32);
+                        	return -1;
+                        }
+                	if (check_region((card->iobase - 0x800) , 32)) {
+                        	printk(KERN_WARNING
+                  			"teles: 16.3 ports %x-%x already in use\n",
+                               		card->iobase - 0x800,
+                               		card->iobase - 0x800 + 32);
+                        	return -1;
+                        }
+                	if (check_region((card->iobase - 0x400) , 32)) {
+                        	printk(KERN_WARNING
+                  			"teles: 16.3 ports %x-%x already in use\n",
+                               		card->iobase - 0x400,
+                               		card->iobase - 0x400 + 32);
+                        	return -1;
+                        }
                 }
                 switch (card->interrupt) {
                 case 2:
@@ -1100,30 +1162,37 @@
                 }
                 if (card->membase) {
                         cfval |= (((unsigned int) card->membase >> 9) & 0xF0);
-                        
-                        if (bytein(card->iobase + 0) != 0x51) {
-                                printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                       card->iobase + 0,
-                                       bytein(card->iobase + 0));
-                                return -2;
-                        }
-                        if (bytein(card->iobase + 1) != 0x93) {
-                                printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                       card->iobase + 1,
-                                       bytein(card->iobase + 1));
-                                return -2;
-                        }
-                        val = bytein(card->iobase + 2);	/* 0x1e=without AB
-                                                         * 0x1f=with AB
-                                                         */
-                        if (val != 0x1e && val != 0x1f) {
-                                printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                       card->iobase + 2,
-                                       bytein(card->iobase + 2));
-                                return -2;
-                        }
+                }   
+                if (bytein(card->iobase + 0) != 0x51) {
+                        printk(KERN_INFO "XXX Byte at %x is %x\n",
+                                card->iobase + 0,
+                                bytein(card->iobase + 0));
+                        return -2;
+                }
+                if (bytein(card->iobase + 1) != 0x93) {
+                        printk(KERN_INFO "XXX Byte at %x is %x\n",
+                                card->iobase + 1,
+                                bytein(card->iobase + 1));
+                        return -2;
+                }
+                val = bytein(card->iobase + 2);	/* 0x1e=without AB
+                                                 * 0x1f=with AB
+                                                 * 0x1c 16.3 ???
+                                                 */
+                if (val != 0x1c && val != 0x1e && val != 0x1f) {
+                        printk(KERN_INFO "XXX Byte at %x is %x\n",
+                                card->iobase + 2,
+                                bytein(card->iobase + 2));
+                        return -2;
+                }
+                if (card->membase) {  /* 16.0 */
+                        request_region(card->iobase, 8, "teles 16.0");
+                } else {
+                	request_region(card->iobase, 16, "teles 16.3");
+                	request_region(card->iobase - 0xC00, 32, "teles HSCX0");
+                	request_region(card->iobase - 0x800, 32, "teles HSCX1");
+                	request_region(card->iobase - 0x400, 32, "teles ISAC");
                 }
-                request_region(card->iobase, 8, "teles");
                 cli();
                 timout = jiffies + (HZ / 10) + 1;
                 byteout(card->iobase + 4, cfval);
@@ -1182,10 +1251,11 @@
 	printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n",
 	       hscx, mode, ichan);
 
-	if (hscx == 0)
-		ichan = 1 - ichan;	/* raar maar waar... */
-
+        hs->mode = mode;
         if (sp->membase) {
+                /* What's that ??? KKeil */
+		if (hscx == 0)
+			ichan = 1 - ichan;	/* raar maar waar... */
                 writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85);
                 writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF);
                 writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF);
@@ -1547,7 +1617,7 @@
 static void
 release_irq(int cardnr)
 {
-	struct IsdnCard *card = cards + cardnr;
+	struct	IsdnCard *card = cards + cardnr;
 
 	irq2dev_map[card->interrupt] = NULL;
 	free_irq(card->interrupt, NULL);
@@ -1584,7 +1654,14 @@
 	close_hscxstate(sp->hs);
 
 	if (cards[cardnr].iobase)
-		release_region(cards[cardnr].iobase, 8);
+        	if (cards[cardnr].membase) {  /* 16.0 */
+			release_region(cards[cardnr].iobase, 8);
+        	} else {
+			release_region(cards[cardnr].iobase, 16);
+                	release_region(cards[cardnr].iobase - 0xC00, 32);
+                	release_region(cards[cardnr].iobase - 0x800, 32);
+                	release_region(cards[cardnr].iobase - 0x400, 32);
+                }
 
 	Sfree((void *) sp);
 }
@@ -1652,35 +1729,35 @@
 	struct HscxState *hsp = sp->hs + st->l1.hscx;
 
 	switch (pr) {
-	  case (PH_DATA):
-		  if (hsp->xmtibh)
-			  BufQueueLink(&hsp->sq, ibh);
-		  else {
-			  hsp->xmtibh = ibh;
-			  hsp->sendptr = 0;
-			  hsp->releasebuf = !0;
-			  hscx_fill_fifo(hsp);
-		  }
-		  break;
-	  case (PH_DATA_PULLED):
-		  if (hsp->xmtibh) {
-			  printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n");
-			  break;
-		  }
-		  hsp->xmtibh = ibh;
-		  hsp->sendptr = 0;
-		  hsp->releasebuf = 0;
-		  hscx_fill_fifo(hsp);
-		  break;
-	  case (PH_REQUEST_PULL):
-		  if (!hsp->xmtibh) {
-			  st->l1.requestpull = 0;
-			  st->l1.l1l2(st, PH_PULL_ACK, NULL);
-		  } else
-			  st->l1.requestpull = !0;
-		  break;
+                case (PH_DATA):
+                        if (hsp->xmtibh)
+                                BufQueueLink(&hsp->sq, ibh);
+                        else {
+                                hsp->xmtibh = ibh;
+                                hsp->sendptr = 0;
+                                hsp->releasebuf = !0;
+                                hscx_fill_fifo(hsp);
+                        }
+                        break;
+                case (PH_DATA_PULLED):
+                        if (hsp->xmtibh) {
+                                printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n");
+                                break;
+                        }
+                        hsp->xmtibh = ibh;
+                        hsp->sendptr = 0;
+                        hsp->releasebuf = 0;
+                        hscx_fill_fifo(hsp);
+                        break;
+                case (PH_REQUEST_PULL):
+                        if (!hsp->xmtibh) {
+                                st->l1.requestpull = 0;
+                                st->l1.l1l2(st, PH_PULL_ACK, NULL);
+                        } else
+                                st->l1.requestpull = !0;
+                        break;
 	}
-
+        
 }
 
 extern struct IsdnBuffers *tracebuf;
@@ -1778,7 +1855,5 @@
 void
 teles_reportcard(int cardnr)
 {
-
 	printk(KERN_DEBUG "teles_reportcard\n");
-
 }
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/fsm.c linux/drivers/isdn/teles/fsm.c
--- pre2.0.5/linux/drivers/isdn/teles/fsm.c	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/fsm.c	Sun May 19 15:29:30 1996
@@ -1,6 +1,9 @@
-/* $Id: fsm.c,v 1.1 1996/04/13 10:23:41 fritz Exp $
+/* $Id: fsm.c,v 1.2 1996/04/29 22:49:57 fritz Exp $
  *
  * $Log: fsm.c,v $
+ * Revision 1.2  1996/04/29 22:49:57  fritz
+ * Removed compatibility-macros.
+ *
  * Revision 1.1  1996/04/13 10:23:41  fritz
  * Initial revision
  *
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/isdnl2.c linux/drivers/isdn/teles/isdnl2.c
--- pre2.0.5/linux/drivers/isdn/teles/isdnl2.c	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/isdnl2.c	Sun May 19 15:29:31 1996
@@ -1,6 +1,9 @@
-/* $Id: isdnl2.c,v 1.1 1996/04/13 10:24:16 fritz Exp $
+/* $Id: isdnl2.c,v 1.2 1996/05/17 03:46:15 fritz Exp $
  *
  * $Log: isdnl2.c,v $
+ * Revision 1.2  1996/05/17 03:46:15  fritz
+ * General cleanup.
+ *
  * Revision 1.1  1996/04/13 10:24:16  fritz
  * Initial revision
  *
@@ -16,43 +19,6 @@
 struct Fsm      l2fsm =
 {NULL, 0, 0};
 
-#if 0
-
-
-enum {
-	ST_PH_NULL,
-	ST_PH_ACTIVATED,
-	ST_PH_ACTIVE,
-};
-
-#define PH_STATE_COUNT (ST_PH_ACTIVE+1)
-
-static char    *strPhState[] =
-{
-	"ST_PH_NULL",
-	"ST_PH_ACTIVATED",
-	"ST_PH_ACTIVE",
-};
-
-enum {
-	EV_PH_ACTIVATE_REQ,
-	EV_PH_ACTIVATE,
-	EV_PH_DEACTIVATE_REQ,
-	EV_PH_DEACTIVATE,
-};
-
-#define PH_EVENT_COUNT (EV_PH_DEACTIVATE+1)
-
-static char    *strPhEvent[] =
-{
-	"EV_PH_ACTIVATE_REQ",
-	"EV_PH_ACTIVATE",
-	"EV_PH_DEACTIVATE_REQ",
-	"EV_PH_DEACTIVATE",
-};
-
-#endif
-
 enum {
 	ST_L2_1,
 	ST_L2_3,
@@ -121,54 +87,6 @@
 	"EV_L2_RNR",
 };
 
-#if 0
-static void
-ph_r1(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	FsmChangeState(fi, ST_PH_ACTIVATED);
-	st->l1.service_down(st, PH_ACTIVATE, NULL);
-}
-
-static void
-ph_r2(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	FsmChangeState(fi, ST_PH_ACTIVE);
-	st->l3.service_up(st, DL_ACTIVATE_CNF, NULL);
-}
-
-static void
-ph_r3(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	FsmChangeState(fi, ST_PH_NULL);
-	st->l1.service_down(st, PH_DEACTIVATE, NULL);
-}
-
-static void
-ph_r4(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	FsmChangeState(fi, ST_PH_NULL);
-	st->l3.service_up(st, DL_DEACTIVATE_IND, NULL);
-}
-
-static struct FsmNode PhFnList[] =
-{
-	{ST_PH_NULL, EV_PH_ACTIVATE_REQ, ph_r1},
-	{ST_PH_ACTIVATED, EV_PH_ACTIVATE, ph_r2},
-	{ST_PH_ACTIVATED, EV_PH_DEACTIVATE, ph_r4},
-	{ST_PH_ACTIVE, EV_PH_DEACTIVATE_REQ, ph_r3},
-};
-
-#define PH_FN_COUNT (sizeof(PhFnList)/sizeof(struct FsmNode))
-#endif
-
 int             errcount = 0;
 
 static int      l2addrsize(struct Layer2 *tsp);
@@ -191,27 +109,6 @@
 		BufPoolRelease(ibh);
 }
 
-#ifdef DEFINED_BUT_NOT_USED
-static void
-discard_window(struct PStack *st)
-{
-	struct BufHeader *ibh;
-	struct Layer2  *l2;
-	int             i, p1, p2;
-
-	l2 = &st->l2;
-	p1 = l2->vs - l2->va;
-	if (p1 < 0)
-		p1 += l2->extended ? 128 : 8;
-
-	for (i = 0; i < p1; i++) {
-		p2 = (i + l2->sow) % l2->window;
-		ibh = l2->windowar[p2];
-		BufPoolRelease(ibh);
-	}
-}
-#endif
-
 int
 l2headersize(struct Layer2 *tsp, int UI)
 {
@@ -254,12 +151,6 @@
 enqueue_ui(struct PStack *st,
 	   struct BufHeader *ibh)
 {
-#ifdef FRITZDEBUG
-	static char     tmp[100];
-
-	sprintf(tmp, "enqueue_ui: %d bytes\n", ibh->datasize);
-	teles_putstatus(tmp);
-#endif
 	st->l2.l2l1(st, PH_DATA, ibh);
 }
 
@@ -267,12 +158,6 @@
 enqueue_super(struct PStack *st,
 	      struct BufHeader *ibh)
 {
-#ifdef FRITZDEBUG
-	static char     tmp[100];
-
-	sprintf(tmp, "enqueue_super: %d bytes\n", ibh->datasize);
-	teles_putstatus(tmp);
-#endif
 	st->l2.l2l1(st, PH_DATA, ibh);
 }
 
@@ -1405,36 +1290,9 @@
 	st->l2.t200_running = 0;
 }
 
-#ifdef DEFINED_BUT_NOT_USED
-static void
-trans_acceptph(struct PStack *st, struct BufHeader *ibh)
-{
-#if 0
-	st->l3.service_up(st, DL_DATA, ibh);
-#endif
-}
-
-
-static void
-transdown(struct PStack *st, int pr,
-	  struct BufHeader *ibh)
-{
-	if (pr == DL_DATA) {
-		ibh->primitive = !0;
-		st->l2.l2l1(st, PH_DATA, ibh);
-	}
-}
-#endif
-
 void
 setstack_transl2(struct PStack *st)
 {
-#if 0
-	st->l2.phdata_up = trans_acceptph;
-	st->l2.service_down = (void *) transdown;
-	st->l2.ihsize = 0;
-	st->l2.debug = 0;
-#endif
 }
 
 void
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/isdnl3.c linux/drivers/isdn/teles/isdnl3.c
--- pre2.0.5/linux/drivers/isdn/teles/isdnl3.c	Wed Apr 24 17:00:40 1996
+++ linux/drivers/isdn/teles/isdnl3.c	Sun May 19 15:29:31 1996
@@ -1,6 +1,16 @@
-/* $Id: isdnl3.c,v 1.2 1996/04/20 16:45:05 fritz Exp $
+/* $Id: isdnl3.c,v 1.5 1996/05/18 01:37:16 fritz Exp $
  *
  * $Log: isdnl3.c,v $
+ * Revision 1.5  1996/05/18 01:37:16  fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.4  1996/05/17 03:46:16  fritz
+ * General cleanup.
+ *
+ * Revision 1.3  1996/04/30 21:57:53  isdn4dev
+ * remove some debugging code, improve callback   Karsten Keil
+ *
  * Revision 1.2  1996/04/20 16:45:05  fritz
  * Changed to report all incoming calls to Linklevel, not just those
  * with Service 7.
@@ -123,17 +133,9 @@
 		  *p++ = 0x90;	/* Packet-Mode 64kbps                      */
 		  break;
 	}
-/*
- * What about info2? Mapping to High-Layer-Compatibility?
- */
-
-#if 0				/* user-user not allowed in The Netherlands! */
-	*p++ = 0x7f;
-	*p++ = 0x2;
-	*p++ = 0x0;
-	*p++ = 66;
-#endif
-
+	/*
+	 * What about info2? Mapping to High-Layer-Compatibility?
+	 */
 	if (st->pa->calling[0] != '\0') {
 		*p++ = 0x6c;
 		*p++ = strlen(st->pa->calling) + 1;
@@ -308,15 +310,6 @@
 	newl3state(st, 0);
 }
 
-#ifdef DEFINED_BUT_NOT_USED
-static void
-l3s15(struct PStack *st, byte pr, void *arg)
-{
-	newl3state(st, 0);
-	st->l3.l3l4(st, CC_REJECT, NULL);
-}
-#endif
-
 static void
 l3s16(struct PStack *st, byte pr,
       void *arg)
@@ -475,11 +468,6 @@
 		ptr = DATAPTR(ibh);
 		ptr += st->l2.ihsize;
 		size = ibh->datasize - st->l2.ihsize;
-		if (DEBUG_1TR6 > 6) {
-			printk(KERN_INFO "isdnl3/l3up DL_DATA size=%d\n", size);
-			for (i = 0; i < size; i++)
-				printk(KERN_INFO "l3up data %x\n", ptr[i]);
-		}
 		mt = ptr[3];
 		switch (ptr[0]) {
 #ifdef P_1TR6
@@ -494,8 +482,8 @@
 			  if (i == datasl_1tr6t_len) {
 				  BufPoolRelease(ibh);
 				  if (DEBUG_1TR6 > 0)
-					  printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %s\n",
-						 st->l3.state, mt_trans(PROTO_DIS_N1, mt));
+					  printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n",
+						 st->l3.state, mt);
 			  } else
 				  datastatelist_1tr6t[i].rout(st, pr, ibh);
 			  break;
@@ -507,6 +495,9 @@
 					  break;
 			  if (i == datasllen) {
 				  BufPoolRelease(ibh);
+				  if (DEBUG_1TR6 > 0)
+			  	  	printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
+				 		st->l3.state, mt);
 			  } else
 				  datastatelist[i].rout(st, pr, ibh);
 		}
@@ -514,11 +505,6 @@
 		ptr = DATAPTR(ibh);
 		ptr += st->l2.uihsize;
 		size = ibh->datasize - st->l2.uihsize;
-		if (DEBUG_1TR6 > 6) {
-			printk(KERN_INFO "isdnl3/l3up DL_UNIT_DATA size=%d\n", size);
-			for (i = 0; i < size; i++)
-				printk(KERN_INFO "l3up data %x\n", ptr[i]);
-		}
 		mt = ptr[3];
 		switch (ptr[0]) {
 #ifdef P_1TR6
@@ -532,8 +518,8 @@
 					  break;
 			  if (i == datasl_1tr6t_len) {
 				  if (DEBUG_1TR6 > 0) {
-					  printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %s\n"
-						 ,st->l3.state, mt_trans(PROTO_DIS_N1, mt));
+					  printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n"
+						 ,st->l3.state, mt);
 				  }
 				  BufPoolRelease(ibh);
 			  } else
@@ -547,6 +533,9 @@
 					  break;
 			  if (i == datasllen) {
 				  BufPoolRelease(ibh);
+				  if (DEBUG_1TR6 > 0)
+			  	  	printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
+				 		st->l3.state, mt);
 			  } else
 				  datastatelist[i].rout(st, pr, ibh);
 		}
@@ -581,6 +570,9 @@
 			      (pr == downstatelist[i].primitive))
 				  break;
 		  if (i == downsllen) {
+			  if (DEBUG_1TR6 > 0) {
+				  printk(KERN_INFO "isdnl3down unhandled E-DSS1 state %d primitiv %x\n", st->l3.state, pr);
+			  }
 		  } else
 			  downstatelist[i].rout(st, pr, ibh);
 	}
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/l3_1TR6.c linux/drivers/isdn/teles/l3_1TR6.c
--- pre2.0.5/linux/drivers/isdn/teles/l3_1TR6.c	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/l3_1TR6.c	Sun May 19 15:29:31 1996
@@ -1,6 +1,9 @@
-/* $Id: l3_1TR6.c,v 1.2 1996/04/20 16:47:23 fritz Exp $
+/* $Id: l3_1TR6.c,v 1.3 1996/04/30 21:54:42 isdn4dev Exp $
  *
  * $Log: l3_1TR6.c,v $
+ * Revision 1.3  1996/04/30 21:54:42  isdn4dev
+ * SPV, callback , remove some debugging code  Karsten Keil
+ *
  * Revision 1.2  1996/04/20 16:47:23  fritz
  * Changed statemachine to allow reject of an incoming call.
  * Report all incoming calls, not just those with Service = 7.
@@ -12,27 +15,6 @@
  *
  */
 
-char           *
-mt_trans(int pd, int mt)
-{
-	int             i;
-
-	if (pd == PROTO_DIS_N0) {
-		for (i = 0; i < (sizeof(mtdesc_n0) / sizeof(struct MTypeDesc)); i++) {
-			if (mt == mtdesc_n0[i].mt)
-				return (mtdesc_n0[i].descr);
-		}
-		return ("unknown Message Type PD=N0");
-	} else if (pd == PROTO_DIS_N1) {
-		for (i = 0; i < (sizeof(mtdesc_n1) / sizeof(struct MTypeDesc)); i++) {
-			if (mt == mtdesc_n1[i].mt)
-				return (mtdesc_n1[i].descr);
-		}
-		return ("unknown Message Type PD=N1");
-	}
-	return ("unknown Protokolldiscriminator");
-}
-
 static void
 l3_1TR6_message(struct PStack *st, int mt, int pd)
 {
@@ -59,10 +41,6 @@
 	byte           *p;
 	char           *teln;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: sent SETUP\n");
-#endif
-
 	st->l3.callref = st->pa->callref;
 	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
 	p = DATAPTR(dibh);
@@ -73,7 +51,21 @@
 	*p++ = st->l3.callref;
 	*p++ = MT_N1_SETUP;
 
-
+	if ('S' == (st->pa->called[0] & 0x5f)) {	/* SPV ??? */
+		/* NSF SPV */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_SPV;	/* SPV */
+		*p++ = st->pa->info; /* 0 for all Services */
+		*p++ = st->pa->info2; /* 0 for all Services */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_Activate;	/* aktiviere SPV (default) */
+		*p++ = st->pa->info; /* 0 for all Services */
+		*p++ = st->pa->info2; /* 0 for all Services */
+	}
 	if (st->pa->calling[0] != '\0') {
 		*p++ = WE0_origAddr;
 		*p++ = strlen(st->pa->calling) + 1;
@@ -84,11 +76,17 @@
 			*p++ = *teln++ & 0x7f;
 	}
 	*p++ = WE0_destAddr;
-	*p++ = strlen(st->pa->called) + 1;
+	teln = st->pa->called;
+	if ('S' != (st->pa->called[0] & 0x5f)) {	/* Keine SPV ??? */
+		*p++ = strlen(st->pa->called) + 1;
+		st->pa->spv = 0;
+	} else {		/* SPV */
+		*p++ = strlen(st->pa->called);
+		teln++;		/* skip S */
+		st->pa->spv = 1;
+	}
 	/* Classify as AnyPref. */
 	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-
-	teln = st->pa->called;
 	while (*teln)
 		*p++ = *teln++ & 0x7f;
 
@@ -106,7 +104,6 @@
 
 }
 
-
 static void
 l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
 {
@@ -118,13 +115,7 @@
 	st->pa->callref = getcallref(p);
 	st->l3.callref = 0x80 + st->pa->callref;
 
-#if DEBUG_1TR6
-        printk(KERN_INFO "1tr6: TU_SETUP cr=%d\n",st->l3.callref);
-#endif
-
-	/*
-         * Channel Identification
-         */
+	/* Channel Identification */
 	p = DATAPTR(ibh);
 	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
 			WE0_chanID, 0))) {
@@ -154,6 +145,13 @@
 	} else
 		strcpy(st->pa->calling, "");
 
+	p = DATAPTR(ibh);
+	st->pa->spv = 0;
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
+			WE0_netSpecFac, 0))) {
+		if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
+			st->pa->spv = 1;
+	}
 	BufPoolRelease(ibh);
 
         /* Signal all services, linklevel takes care of Service-Indicator */
@@ -172,10 +170,6 @@
 	byte           *p;
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: SETUP_ACK\n");
-#endif
-
 	p = DATAPTR(ibh);
 	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
 			WE0_chanID, 0))) {
@@ -183,6 +177,7 @@
 	} else
 		printk(KERN_INFO "octect 3 not found\n");
 
+
 	BufPoolRelease(ibh);
 	newl3state(st, 2);
 }
@@ -193,10 +188,6 @@
 	byte           *p;
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: CALL_SENT\n");
-#endif
-
 	p = DATAPTR(ibh);
 	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
 			WE0_chanID, 0))) {
@@ -215,9 +206,6 @@
 	byte           *p;
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: TU_ALERT\n");
-#endif
 
 	p = DATAPTR(ibh);
 	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
@@ -236,24 +224,22 @@
 l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg)
 {
 	byte           *p;
-	int             i;
+	int             i,tmpcharge=0;
 	char            a_charge[8];
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: TU_INFO\n");
-#endif
-
 	p = DATAPTR(ibh);
 	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
 			WE6_chargingInfo, 6))) {
 		iecpy(a_charge, p, 1);
-		st->pa->chargeinfo = 0;
-		for (i = 0; i < strlen(a_charge); i++) {
-			st->pa->chargeinfo *= 10;
-			st->pa->chargeinfo += a_charge[i] & 0xf;
-			st->l3.l3l4(st, CC_INFO_CHARGE, NULL);
-		}
+                for (i = 0; i < strlen (a_charge); i++) {
+     	                tmpcharge *= 10;
+     	                tmpcharge += a_charge[i] & 0xf;
+     	        }
+                if (tmpcharge > st->pa->chargeinfo) {
+     	                st->pa->chargeinfo = tmpcharge;
+     	                st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
+     	        }
 		if (DEBUG_1TR6 > 2)
 			printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
 	} else if (DEBUG_1TR6 > 2)
@@ -269,10 +255,6 @@
 	int             i;
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: TU_INFO 2\n");
-#endif
-
 	if (DEBUG_1TR6 > 4) {
 		p = DATAPTR(ibh);
 		for (i = 0; i < ibh->datasize; i++) {
@@ -287,10 +269,7 @@
 {
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: CONNECT\n");
-#endif
-
+        st->pa->chargeinfo=0;
 	BufPoolRelease(ibh);
 	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
 	newl3state(st, 10);
@@ -301,11 +280,6 @@
 {
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: REL\n");
-#endif
-
-
 	BufPoolRelease(ibh);
 	l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
 	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
@@ -317,11 +291,6 @@
 {
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: REL_ACK\n");
-#endif
-
-
 	BufPoolRelease(ibh);
 	newl3state(st, 0);
 	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
@@ -332,25 +301,21 @@
 {
 	struct BufHeader *ibh = arg;
 	byte           *p;
-	int             i;
+	int             i,tmpcharge=0;
 	char            a_charge[8];
 
-
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: TU_DISC\n");
-#endif
-
-
 	p = DATAPTR(ibh);
 	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
 			WE6_chargingInfo, 6))) {
 		iecpy(a_charge, p, 1);
-		st->pa->chargeinfo = 0;
-		for (i = 0; i < strlen(a_charge); i++) {
-			st->pa->chargeinfo *= 10;
-			st->pa->chargeinfo += a_charge[i] & 0xf;
-			st->l3.l3l4(st, CC_INFO_CHARGE, NULL);
-		}
+                for (i = 0; i < strlen (a_charge); i++) {
+     	                tmpcharge *= 10;
+     	                tmpcharge += a_charge[i] & 0xf;
+     	        }
+                if (tmpcharge > st->pa->chargeinfo) {
+     	                st->pa->chargeinfo = tmpcharge;
+     	                st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
+     	        }
 		if (DEBUG_1TR6 > 2)
 			printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
 	} else if (DEBUG_1TR6 > 2)
@@ -380,12 +345,8 @@
 {
 	struct BufHeader *ibh = arg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: CONN_ACK\n");
-#endif
-
-
 	BufPoolRelease(ibh);
+	st->pa->chargeinfo = 0;
 	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
 	newl3state(st, 10);
 }
@@ -394,10 +355,6 @@
 l3_1tr6_alert(struct PStack *st, byte pr,
 	      void *arg)
 {
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: send ALERT\n");
-#endif
-
 	l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
 	newl3state(st, 7);
 }
@@ -406,22 +363,45 @@
 l3_1tr6_conn(struct PStack *st, byte pr,
 	     void *arg)
 {
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: send CONNECT\n");
-#endif
+	struct BufHeader *dibh;
+	byte *p;
 
 	st->l3.callref = 0x80 + st->pa->callref;
-	l3_1TR6_message(st, MT_N1_CONN, PROTO_DIS_N1);
+
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	*p++ = PROTO_DIS_N1;
+	*p++ = 0x1;
+	*p++ = st->l3.callref;
+	*p++ = MT_N1_CONN;
+
+	if (st->pa->spv) {	/* SPV ??? */
+		/* NSF SPV */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_SPV;	/* SPV */
+		*p++ = st->pa->info;
+		*p++ = st->pa->info2;
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_Activate;	/* aktiviere SPV */
+		*p++ = st->pa->info;
+		*p++ = st->pa->info2;
+	}
+	dibh->datasize = p - DATAPTR(dibh);
+
+	i_down(st, dibh);
+
 	newl3state(st, 8);
 }
 
 static void
 l3_1tr6_ignore(struct PStack *st, byte pr, void *arg)
 {
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: IGNORE\n");
-#endif
-
 	newl3state(st, 0);
 }
 
@@ -432,10 +412,6 @@
 	byte             *p;
         byte             rejflg;
 
-#if DEBUG_1TR6
-	printk(KERN_INFO "1tr6: send DISCON\n");
-#endif
-
 	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
 	p = DATAPTR(dibh);
 	p += st->l2.ihsize;
@@ -460,10 +436,7 @@
 
 	i_down(st, dibh);
 
-        if (rejflg)
-                newl3state(st, 0);
-        else
-                newl3state(st, 11);
+        newl3state(st, 11);
 }
 
 static void
@@ -472,8 +445,6 @@
 	l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
 	newl3state(st, 19);
 }
-
-
 
 static struct stateentry downstatelist_1tr6t[] =
 {
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/l3_1TR6.h linux/drivers/isdn/teles/l3_1TR6.h
--- pre2.0.5/linux/drivers/isdn/teles/l3_1TR6.h	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/l3_1TR6.h	Sun May 19 15:29:31 1996
@@ -1,6 +1,9 @@
-/* $Id: l3_1TR6.h,v 1.1 1996/04/13 10:25:42 fritz Exp $
+/* $Id: l3_1TR6.h,v 1.3 1996/04/30 21:53:48 isdn4dev Exp $
  *
  * $Log: l3_1TR6.h,v $
+ * Revision 1.3  1996/04/30 21:53:48  isdn4dev
+ * Bugs, SPV, Logging in q931.c  Karsten Keil
+ *
  * Revision 1.1  1996/04/13 10:25:42  fritz
  * Initial revision
  *
@@ -15,16 +18,16 @@
 /*
  * MsgType N0
  */
-#define MT_N0_REG_IND 61
-#define MT_N0_CANC_IND 62
-#define MT_N0_FAC_STA 63
-#define MT_N0_STA_ACK 64
-#define MT_N0_STA_REJ 65
-#define MT_N0_FAC_INF 66
-#define MT_N0_INF_ACK 67
-#define MT_N0_INF_REJ 68
-#define MT_N0_CLOSE 75
-#define MT_N0_CLO_ACK 77
+#define MT_N0_REG_IND 0x61
+#define MT_N0_CANC_IND 0x62
+#define MT_N0_FAC_STA 0x63
+#define MT_N0_STA_ACK 0x64
+#define MT_N0_STA_REJ 0x65
+#define MT_N0_FAC_INF 0x66
+#define MT_N0_INF_ACK 0x67
+#define MT_N0_INF_REJ 0x68
+#define MT_N0_CLOSE   0x75
+#define MT_N0_CLO_ACK 0x77
 
 
 /*
@@ -63,59 +66,6 @@
 #define MT_N1_STAT 0x63
 
 
-struct MTypeDesc {
-	byte            mt;
-	char           *descr;
-};
-
-static struct MTypeDesc mtdesc_n0[] =
-{
-	{MT_N0_REG_IND, "MT_N0_REG_IND"},
-	{MT_N0_CANC_IND, "MT_N0_CANC_IND"},
-	{MT_N0_FAC_STA, "MT_N0_FAC_STA"},
-	{MT_N0_STA_ACK, "MT_N0_STA_ACK"},
-	{MT_N0_STA_REJ, "MT_N0_STA_REJ"},
-	{MT_N0_FAC_INF, "MT_N0_FAC_INF"},
-	{MT_N0_INF_ACK, "MT_N0_INF_ACK"},
-	{MT_N0_INF_REJ, "MT_N0_INF_REJ"},
-	{MT_N0_CLOSE, "MT_N0_CLOSE"},
-	{MT_N0_CLO_ACK, "MT_N0_CLO_ACK"}
-};
-
-static struct MTypeDesc mtdesc_n1[] =
-{
-	{MT_N1_ESC, "MT_N1_ESC"},
-	{MT_N1_ALERT, "MT_N1_ALERT"},
-	{MT_N1_CALL_SENT, "MT_N1_CALL_SENT"},
-	{MT_N1_CONN, "MT_N1_CONN"},
-	{MT_N1_CONN_ACK, "MT_N1_CONN_ACK"},
-	{MT_N1_SETUP, "MT_N1_SETUP"},
-	{MT_N1_SETUP_ACK, "MT_N1_SETUP_ACK"},
-	{MT_N1_RES, "MT_N1_RES"},
-	{MT_N1_RES_ACK, "MT_N1_RES_ACK"},
-	{MT_N1_RES_REJ, "MT_N1_RES_REJ"},
-	{MT_N1_SUSP, "MT_N1_SUSP"},
-	{MT_N1_SUSP_ACK, "MT_N1_SUSP_ACK"},
-	{MT_N1_SUSP_REJ, "MT_N1_SUSP_REJ"},
-	{MT_N1_USER_INFO, "MT_N1_USER_INFO"},
-	{MT_N1_DET, "MT_N1_DET"},
-	{MT_N1_DISC, "MT_N1_DISC"},
-	{MT_N1_REL, "MT_N1_REL"},
-	{MT_N1_REL_ACK, "MT_N1_REL_ACK"},
-	{MT_N1_CANC_ACK, "MT_N1_CANC_ACK"},
-	{MT_N1_CANC_REJ, "MT_N1_CANC_REJ"},
-	{MT_N1_CON_CON, "MT_N1_CON_CON"},
-	{MT_N1_FAC, "MT_N1_FAC"},
-	{MT_N1_FAC_ACK, "MT_N1_FAC_ACK"},
-	{MT_N1_FAC_CAN, "MT_N1_FAC_CAN"},
-	{MT_N1_FAC_REG, "MT_N1_FAC_REG"},
-	{MT_N1_FAC_REJ, "MT_N1_FAC_REJ"},
-	{MT_N1_INFO, "MT_N1_INFO"},
-	{MT_N1_REG_ACK, "MT_N1_REG_ACK"},
-	{MT_N1_REG_REJ, "MT_N1_REG_REJ"},
-	{MT_N1_STAT, "MT_N1_STAT"}
-};
-
 
 /*
  * W Elemente
@@ -172,7 +122,7 @@
 #define FAC_Unterdruecke 0x1B
 #define FAC_Deactivate 0x1E
 #define FAC_Activate 0x1D
-#define FAC_SVC 0x1F
+#define FAC_SPV 0x1F
 #define FAC_Rueckwechsel 0x23
 #define FAC_Umleitung 0x24
 
@@ -187,7 +137,7 @@
 #define CAUSE_FacNotImpl 0x10
 #define CAUSE_FacNotSubscr 0x11
 #define CAUSE_OutgoingBarred 0x20
-#define CAUSE_UserAssessBusy 0x21
+#define CAUSE_UserAccessBusy 0x21
 #define CAUSE_NegativeGBG 0x22
 #define CAUSE_UnknownGBG 0x23
 #define CAUSE_NoSPVknown 0x25
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/llglue.c linux/drivers/isdn/teles/llglue.c
--- pre2.0.5/linux/drivers/isdn/teles/llglue.c	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/llglue.c	Sun May 19 15:29:31 1996
@@ -1,6 +1,12 @@
-/* $Id: llglue.c,v 1.1 1996/04/13 10:26:29 fritz Exp $
+/* $Id: llglue.c,v 1.3 1996/05/01 14:19:57 fritz Exp $
  *
  * $Log: llglue.c,v $
+ * Revision 1.3  1996/05/01 14:19:57  fritz
+ * Added ISDN_FEADTURE_L2_TRANS
+ *
+ * Revision 1.2  1996/04/29 23:01:46  fritz
+ * Added driverId and channel to readstatus().
+ *
  * Revision 1.1  1996/04/13 10:26:29  fritz
  * Initial revision
  *
@@ -25,7 +31,7 @@
 static byte    *teles_status_end = NULL;
 
 int
-teles_readstatus(byte * buf, int len, int user)
+teles_readstatus(byte * buf, int len, int user, int id, int channel)
 {
 	int             count;
 	byte           *p;
@@ -90,6 +96,7 @@
 	iif.features =
 	    ISDN_FEATURE_L2_X75I |
 	    ISDN_FEATURE_L2_HDLC |
+	    ISDN_FEATURE_L2_TRANS |
 	    ISDN_FEATURE_L3_TRANS |
 	    ISDN_FEATURE_P_1TR6 |
 	    ISDN_FEATURE_P_EURO;
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/q931.c linux/drivers/isdn/teles/q931.c
--- pre2.0.5/linux/drivers/isdn/teles/q931.c	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/q931.c	Sun May 19 15:29:31 1996
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.2 1996/04/20 16:48:19 fritz Exp $
+/* $Id: q931.c,v 1.4 1996/05/17 03:46:17 fritz Exp $
  *
  * q931.c               code to decode ITU Q.931 call control messages
  * 
@@ -10,7 +10,16 @@
  * 
  * Beat Doebeli         cause texts, display information element
  * 
+ * Karsten Keil         cause texts, display information element for 1TR6 
+ *
+ * 
  * $Log: q931.c,v $
+ * Revision 1.4  1996/05/17 03:46:17  fritz
+ * General cleanup.
+ *
+ * Revision 1.3  1996/04/30 22:06:50  isdn4dev
+ *   logging 1TR6 messages correctly   Karsten Keil
+ *
  * Revision 1.2  1996/04/20 16:48:19  fritz
  * Misc. typos
  *
@@ -23,6 +32,7 @@
 
 #define __NO_VERSION__
 #include "teles.h"
+#include "l3_1TR6.h"
 
 byte           *
 findie(byte * p, int size, byte ie, int wanted_set)
@@ -174,9 +184,87 @@
 
 #define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
 
+static
+struct MessageType mt_n0[] =
+{
+	{MT_N0_REG_IND, "REGister INDication"},
+	{MT_N0_CANC_IND, "CANCel INDication"},
+	{MT_N0_FAC_STA, "FACility STAtus"},
+	{MT_N0_STA_ACK, "STAtus ACKnowledge"},
+	{MT_N0_STA_REJ, "STAtus REJect"},
+	{MT_N0_FAC_INF, "FACility INFormation"},
+	{MT_N0_INF_ACK, "INFormation ACKnowledge"},
+	{MT_N0_INF_REJ, "INFormation REJect"},
+	{MT_N0_CLOSE, "CLOSE"},
+	{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
+};
+
+int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
 
 static
-int
+struct MessageType mt_n1[] =
+{
+	{MT_N1_ESC, "ESCape"},
+	{MT_N1_ALERT, "ALERT"},
+	{MT_N1_CALL_SENT, "CALL SENT"},
+	{MT_N1_CONN, "CONNect"},
+	{MT_N1_CONN_ACK, "CONNect ACKnowledge"},
+	{MT_N1_SETUP, "SETUP"},
+	{MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
+	{MT_N1_RES, "RESume"},
+	{MT_N1_RES_ACK, "RESume ACKnowledge"},
+	{MT_N1_RES_REJ, "RESume REJect"},
+	{MT_N1_SUSP, "SUSPend"},
+	{MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
+	{MT_N1_SUSP_REJ, "SUSPend REJect"},
+	{MT_N1_USER_INFO, "USER INFO"},
+	{MT_N1_DET, "DETach"},
+	{MT_N1_DISC, "DISConnect"},
+	{MT_N1_REL, "RELease"},
+	{MT_N1_REL_ACK, "RELease ACKnowledge"},
+	{MT_N1_CANC_ACK, "CANCel ACKnowledge"},
+	{MT_N1_CANC_REJ, "CANCel REJect"},
+	{MT_N1_CON_CON, "CONgestion CONtrol"},
+	{MT_N1_FAC, "FACility"},
+	{MT_N1_FAC_ACK, "FACility ACKnowledge"},
+	{MT_N1_FAC_CAN, "FACility CANcel"},
+	{MT_N1_FAC_REG, "FACility REGister"},
+	{MT_N1_FAC_REJ, "FACility REJect"},
+	{MT_N1_INFO, "INFOmation"},
+	{MT_N1_REG_ACK, "REGister ACKnowledge"},
+	{MT_N1_REG_REJ, "REGister REJect"},
+	{MT_N1_STAT, "STATus"}
+};
+
+int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
+
+static struct MessageType fac_1tr6[] =
+{
+	{FAC_Sperre, "Sperre"},
+	{FAC_Forward1, "Forward 1"},
+	{FAC_Forward2, "Forward 2"},
+	{FAC_Konferenz, "Konferenz"},
+	{FAC_GrabBchan, "Grab Bchannel"},
+	{FAC_Reactivate, "Reactivate"},
+	{FAC_Konferenz3, "Dreier Konferenz"},
+	{FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
+	{FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
+	{FAC_NummernIdent, "Rufnummer-Identifizierung"},
+	{FAC_GBG, "GBG"},
+	{FAC_DisplayUebergeben, "Display Uebergeben"},
+	{FAC_DisplayUmgeleitet, "Display Umgeleitet"},
+	{FAC_Unterdruecke, "Unterdruecke Rufnummer"},
+	{FAC_Deactivate, "Deactivate"},
+	{FAC_Activate, "Activate"},
+	{FAC_SPV, "SPV"},
+	{FAC_Rueckwechsel, "Rueckwechsel"},
+	{FAC_Umleitung, "Umleitung"}
+};
+int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
+
+
+
+static int 
 prbits(char *dest, byte b, int start, int len)
 {
 	char           *dp = dest;
@@ -449,12 +537,6 @@
 	else
 		dp += sprintf(dp, "  cause value %x : %s \n", cause, cvlist[i].edescr);
 
-
-#if 0
-	dp += sprintf(dp,"    cause value ");
-        dp += prbits(dp,*p++,7,7);
-        *dp++ = '\n';
-#endif
 	while (!0) {
 		if (p > end)
 			break;
@@ -471,10 +553,76 @@
 }
 
 static
-int
-prchident(char *dest, byte * p)
+struct MessageType cause_1tr6[] =
+{
+	{CAUSE_InvCRef, "Invalid Call Reference"},
+	{CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
+	{CAUSE_CIDunknown, "Caller Identity unknown"},
+	{CAUSE_CIDinUse, "Caller Identity in Use"},
+	{CAUSE_NoChans, "No Channels available"},
+	{CAUSE_FacNotImpl, "Facility Not Implemented"},
+	{CAUSE_FacNotSubscr, "Facility Not Subscribed"},
+	{CAUSE_OutgoingBarred, "Outgoing calls barred"},
+	{CAUSE_UserAccessBusy, "User Access Busy"},
+	{CAUSE_NegativeGBG, "Negative GBG"},
+	{CAUSE_UnknownGBG, "Unknown  GBG"},
+	{CAUSE_NoSPVknown, "No SPV known"},
+	{CAUSE_DestNotObtain, "Destination not obtainable"},
+	{CAUSE_NumberChanged, "Number changed"},
+	{CAUSE_OutOfOrder, "Out Of Order"},
+	{CAUSE_NoUserResponse, "No User Response"},
+	{CAUSE_UserBusy, "User Busy"},
+	{CAUSE_IncomingBarred, "Incoming Barred"},
+	{CAUSE_CallRejected, "Call Rejected"},
+	{CAUSE_NetworkCongestion, "Network Congestion"},
+	{CAUSE_RemoteUser, "Remote User initiated"},
+	{CAUSE_LocalProcErr, "Local Procedure Error"},
+	{CAUSE_RemoteProcErr, "Remote Procedure Error"},
+	{CAUSE_RemoteUserSuspend, "Remote User Suspend"},
+	{CAUSE_RemoteUserResumed, "Remote User Resumed"},
+	{CAUSE_UserInfoDiscarded, "User Info Discarded"}
+};
+
+int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
+
+static int
+prcause_1tr6(char *dest, byte * p) 
 {
 	char           *dp = dest;
+	int i, cause;
+
+	p++;
+	if (0 == *p) {
+		dp += sprintf(dp, "   OK (cause length=0)\n");
+		return (dp - dest);
+	} else if (*p > 1) {
+		dp += sprintf(dp, "    coding ");
+		dp += prbits(dp, p[2], 7, 2);
+		dp += sprintf(dp, " location ");
+		dp += prbits(dp, p[2], 4, 4);
+		*dp++ = '\n';
+	}
+	p++;
+	cause = 0x7f & *p;
+
+	/* locate cause value */
+	for (i = 0; i < cause_1tr6_len; i++)
+		if (cause_1tr6[i].nr == cause)
+			break;
+
+	/* display cause value if it exists */
+	if (i == cause_1tr6_len)
+		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
+	else
+		dp += sprintf(dp, "  cause value %x : %s \n", cause, cause_1tr6[i].descr);
+
+	return (dp - dest);
+
+}
+
+static int
+prchident(char *dest, byte * p) {
+	char *dp = dest;
 
 	p += 2;
 	dp += sprintf(dp, "    octet 3 ");
@@ -482,10 +630,9 @@
 	*dp++ = '\n';
 	return (dp - dest);
 }
-static
-int
-prcalled(char *dest, byte * p)
-{
+
+static int
+prcalled(char *dest, byte * p) {
 	int             l;
 	char           *dp = dest;
 
@@ -500,10 +647,8 @@
 	*dp++ = '\n';
 	return (dp - dest);
 }
-static
-int
-prcalling(char *dest, byte * p)
-{
+static int
+prcalling(char *dest, byte * p) {
 	int             l;
 	char           *dp = dest;
 
@@ -518,7 +663,6 @@
 		*dp++ = '\n';
 		l--;
 	};
-
 	p++;
 
 	dp += sprintf(dp, "    number digits ");
@@ -575,10 +719,8 @@
 	return (dp - dest);
 }
 
-static
-int
-general(char *dest, byte * p)
-{
+static int
+general(char *dest, byte * p) {
 	char           *dp = dest;
 	char            ch = ' ';
 	int             l, octet = 3;
@@ -597,17 +739,44 @@
 			ch = ' ';
 		} else if (ch == ' ')
 			ch = 'a';
-
 		else
 			ch++;
 	}
 	return (dp - dest);
 }
 
-static
-int
-display(char *dest, byte * p)
-{
+static int
+prcharge(char *dest, byte * p) {
+	char *dp = dest;
+	int l;
+
+	p++;
+	l = *p++ - 1;
+	dp += sprintf(dp, "    GEA ");
+	dp += prbits(dp, *p++, 8, 8);
+	dp += sprintf(dp, "  Anzahl: ");
+	/* Iterate over all octets in the * information element */
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+} 
+static int
+prtext(char *dest, byte * p) {
+	char *dp = dest;
+	int l;
+
+	p++;
+	l = *p++;
+	dp += sprintf(dp, "    ");
+	/* Iterate over all octets in the * information element */
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+}
+static int
+display(char *dest, byte * p) {
 	char           *dp = dest;
 	char            ch = ' ';
 	int             l, octet = 3;
@@ -772,107 +941,206 @@
 	},
 };
 
+
 #define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
 
-#ifdef FRITZDEBUG
-void
-hexdump(byte * buf, int len, char *comment)
+static struct InformationElement we_0[] =
 {
-	static char     dbuf[1024];
-	char           *p = dbuf;
+	{WE0_cause, "Cause", prcause_1tr6},
+	{WE0_connAddr, "Connecting Address", prcalled},
+	{WE0_callID, "Call IDentity", general},
+	{WE0_chanID, "Channel IDentity", general},
+	{WE0_netSpecFac, "Network Specific Facility", general},
+	{WE0_display, "Display", general},
+	{WE0_keypad, "Keypad", general},
+	{WE0_origAddr, "Origination Address", prcalled},
+	{WE0_destAddr, "Destination Address", prcalled},
+	{WE0_userInfo, "User Info", general}
+};
 
-	p += sprintf(p, "%s: ", comment);
-	while (len) {
-		p += sprintf(p, "%02x ", *p++);
-		len--;
-	}
-	p += sprintf(p, "\n");
+static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
 
-	teles_putstatus(dbuf);
-}
-#endif
+static struct InformationElement we_6[] =
+{
+	{WE6_serviceInd, "Service Indicator", general},
+	{WE6_chargingInfo, "Charging Information", prcharge},
+	{WE6_date, "Date", prtext},
+	{WE6_facSelect, "Facility Select", general},
+	{WE6_facStatus, "Facility Status", general},
+	{WE6_statusCalled, "Status Called", general},
+	{WE6_addTransAttr, "Additional Transmission Attributes", general}
+};
+static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
 
 void
-dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment)
-{
+dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) {
 	byte           *bend = buf + size;
 	char           *dp;
-	int             i;
+	int i, cs = 0, cs_old = 0, cs_fest = 0;
 
 	/* display header */
 	dp = sp->dlogspace;
 	dp += sprintf(dp, "%s\n", comment);
 
 	{
-		byte           *p = buf;
-
+		byte *p = buf;
 		dp += sprintf(dp, "hex: ");
 		while (p < bend)
-			dp += sprintf(dp, "%02x ", *p++);
+		dp += sprintf(dp, "%02x ", *p++);
 		dp += sprintf(dp, "\n");
 		teles_putstatus(sp->dlogspace);
 		dp = sp->dlogspace;
-	}
-	/* locate message type */
-	for (i = 0; i < MTSIZE; i++)
-		if (mtlist[i].nr == buf[3])
-			break;
-
-	/* display message type iff it exists */
-	if (i == MTSIZE)
-		dp += sprintf(dp, "Unknown message type %x!\n", buf[3]);
-	else
-		dp += sprintf(dp, "call reference %d size %d message type %s\n",
-			      buf[2], size, mtlist[i].descr);
+	} 
+	if ((0xfe & buf[0]) == PROTO_DIS_N0) {	/* 1TR6 */
+		/* locate message type */
+		if (buf[0] == PROTO_DIS_N0) {	/* N0 */
+			for (i = 0; i < mt_n0_len; i++)
+				if (mt_n0[i].nr == buf[3])
+					break;
+			/* display message type iff it exists */
+			if (i == mt_n0_len)
+				dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]);
+			else
+				dp += sprintf(dp, "call reference %d size %d message type %s\n",
+					      buf[2], size, mt_n0[i].descr);
+		} else {	/* N1 */
+			for (i = 0; i < mt_n1_len; i++)
+				if (mt_n1[i].nr == buf[3])
+					break;
+			/* display message type iff it exists */
+			if (i == mt_n1_len)
+				dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]);
+			else
+				dp += sprintf(dp, "call reference %d size %d message type %s\n",
+					      buf[2], size, mt_n1[i].descr);
+		}
 
-	/* display each information element */
-	buf += 4;
-	while (buf < bend) {
-		/* Is it a single octet information element? */
-		if (*buf & 0x80) {
-			switch ((*buf >> 4) & 7) {
-			  case 1:
-				  dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
-				  break;
-			  case 3:
-				  dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
-				  break;
-			  case 5:
-				  dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
-				  break;
-			  case 2:
-				  if (*buf == 0xa0) {
-					  dp += sprintf(dp, "  More data\n");
-					  break;
-				  }
-				  if (*buf == 0xa1) {
-					  dp += sprintf(dp, "  Sending complete\n");
-				  }
-				  break;
+		/* display each information element */
+		buf += 4;
+		while (buf < bend) {
+			/* Is it a single octet information element? */
+			if (*buf & 0x80) {
+				switch ((*buf >> 4) & 7) {
+				  case 1:
+					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
+					cs_old = cs;
+					cs = *buf & 7;
+					cs_fest = *buf & 8;
+					break;
+				  case 3:
+					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
+					break;
+				  case 2:
+					if (*buf == 0xa0) {
+						dp += sprintf(dp, "  More data\n");
+						break;
+					}
+					if (*buf == 0xa1) {
+						dp += sprintf(dp, "  Sending complete\n");
+					}
+					break;
 				  /* fall through */
-			  default:
-				  dp += sprintf(dp, "  Reserved %x\n", *buf);
-				  break;
+				  default:
+					dp += sprintf(dp, "  Reserved %x\n", *buf);
+					break;
+				}
+				buf++;
+				continue;
+			}
+			/* No, locate it in the table */
+			if (cs == 0) {
+				for (i = 0; i < we_0_len; i++)
+					if (*buf == we_0[i].nr)
+						break;
+
+				/* When found, give appropriate msg */
+				if (i != we_0_len) {
+					dp += sprintf(dp, "  %s\n", we_0[i].descr);
+					dp += we_0[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			} else if (cs == 6) {
+				for (i = 0; i < we_6_len; i++)
+					if (*buf == we_6[i].nr)
+						break;
+
+				/* When found, give appropriate msg */
+				if (i != we_6_len) {
+					dp += sprintf(dp, "  %s\n", we_6[i].descr);
+					dp += we_6[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			} else
+				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			/* Skip to next element */
+			if (cs_fest == 8) {
+				cs = cs_old;
+				cs_old = 0;
+				cs_fest = 0;
 			}
-			buf++;
-			continue;
+			buf += buf[1] + 2;
 		}
-		/* No, locate it in the table */
-		for (i = 0; i < IESIZE; i++)
-			if (*buf == ielist[i].nr)
+	} else {	/* EURO */
+		/* locate message type */
+		for (i = 0; i < MTSIZE; i++)
+			if (mtlist[i].nr == buf[3])
 				break;
 
-		/* When not found, give appropriate msg */
-		if (i != IESIZE) {
-			dp += sprintf(dp, "  %s\n", ielist[i].descr);
-			dp += ielist[i].f(dp, buf);
-		} else
-			dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
+		/* display message type iff it exists */
+		if (i == MTSIZE)
+			dp += sprintf(dp, "Unknown message type %x!\n", buf[3]);
+		else
+			dp += sprintf(dp, "call reference %d size %d message type %s\n",
+		buf[2], size, mtlist[i].descr);
 
-		/* Skip to next element */
-		buf += buf[1] + 2;
-	}
+		/* display each information element */
+		buf += 4;
+		while (buf < bend) {
+			/* Is it a single octet information element? */
+			if (*buf & 0x80) {
+				switch ((*buf >> 4) & 7) {
+				  case 1:
+					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
+					break;
+				  case 3:
+					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
+					break;
+				  case 5:
+					dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
+					break;
+				  case 2:
+					if (*buf == 0xa0) {
+						dp += sprintf(dp, "  More data\n");
+						break;
+					}
+					if (*buf == 0xa1) {
+						dp += sprintf(dp, "  Sending complete\n");
+					}
+					break;
+				  /* fall through */
+				  default:
+					dp += sprintf(dp, "  Reserved %x\n", *buf);
+					break;
+				}
+				buf++;
+				continue;
+			}
+			/* No, locate it in the table */
+			for (i = 0; i < IESIZE; i++)
+				if (*buf == ielist[i].nr)
+					break;
+
+			/* When not found, give appropriate msg */
+			if (i != IESIZE) {
+				dp += sprintf(dp, "  %s\n", ielist[i].descr);
+				dp += ielist[i].f(dp, buf);
+			} else
+				dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
 
+			/* Skip to next element */
+			buf += buf[1] + 2;
+		}
+	}
 	dp += sprintf(dp, "\n");
 	teles_putstatus(sp->dlogspace);
 }
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/teles/teles.h linux/drivers/isdn/teles/teles.h
--- pre2.0.5/linux/drivers/isdn/teles/teles.h	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/teles/teles.h	Sun May 19 15:29:31 1996
@@ -1,6 +1,9 @@
-/* $Id: teles.h,v 1.1 1996/04/13 10:29:00 fritz Exp $
+/* $Id: teles.h,v 1.2 1996/04/30 21:52:04 isdn4dev Exp $
  *
  * $Log: teles.h,v $
+ * Revision 1.2  1996/04/30 21:52:04  isdn4dev
+ * SPV for 1TR6 - Karsten
+ *
  * Revision 1.1  1996/04/13 10:29:00  fritz
  * Initial revision
  *
@@ -288,6 +291,7 @@
 	int             chargeinfo;  /* Charge Info - only for 1tr6 in
 				      * the moment 
 				      */
+	int		spv;	     /* SPV Flag */
 };
 
 struct PStack {
diff -u --recursive --new-file pre2.0.5/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- pre2.0.5/linux/drivers/net/8390.c	Fri May 17 15:32:15 1996
+++ linux/drivers/net/8390.c	Sat May 18 11:15:09 1996
@@ -617,7 +617,7 @@
     /* 
      * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
      * Early datasheets said to poll the reset bit, but now they say that
-     * it "is not a reliable indicator and subequently should be ignored."
+     * it "is not a reliable indicator and subsequently should be ignored."
      * We wait at least 10ms.
      */
     wait_start_time = jiffies;
diff -u --recursive --new-file pre2.0.5/linux/drivers/net/dummy.c linux/drivers/net/dummy.c
--- pre2.0.5/linux/drivers/net/dummy.c	Tue May  7 16:22:27 1996
+++ linux/drivers/net/dummy.c	Sat May 18 20:08:04 1996
@@ -58,7 +58,6 @@
 static struct enet_statistics *dummy_get_stats(struct device *dev);
 #endif
 
-#ifdef MODULE
 static int dummy_open(struct device *dev)
 {
 	MOD_INC_USE_COUNT;
@@ -70,7 +69,6 @@
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
-#endif
 
 
 int dummy_init(struct device *dev)
@@ -89,10 +87,9 @@
 	memset(dev->priv, 0, sizeof(struct enet_statistics));
 	dev->get_stats		= dummy_get_stats;
 #endif
-#ifdef MODULE
+
 	dev->open = &dummy_open;
 	dev->stop = &dummy_close;
-#endif
 
 	/* Fill in the fields of the device structure with ethernet-generic values. */
 	ether_setup(dev);
diff -u --recursive --new-file pre2.0.5/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- pre2.0.5/linux/drivers/net/loopback.c	Tue May  7 16:22:29 1996
+++ linux/drivers/net/loopback.c	Sat May 18 11:58:33 1996
@@ -17,6 +17,9 @@
  *		Larry McVoy	:	Tiny tweak to double performance
  *		Alan Cox	:	Backed out LMV's tweak - the linux mm
  *					can't take it...
+ *              Michael Griffith:       Don't bother computing the checksums
+ *                                      on packets received on the loopback
+ *                                      interface.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
diff -u --recursive --new-file pre2.0.5/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- pre2.0.5/linux/drivers/net/plip.c	Mon Apr  8 19:01:43 1996
+++ linux/drivers/net/plip.c	Sun May 19 14:57:51 1996
@@ -271,6 +271,7 @@
 	dev->get_stats 		= plip_get_stats;
 	dev->set_config		= plip_config;
 	dev->do_ioctl		= plip_ioctl;
+	dev->tx_queue_len	= 10;
 	dev->flags	        = IFF_POINTOPOINT|IFF_NOARP;
 
 	/* Set the private structure */
diff -u --recursive --new-file pre2.0.5/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- pre2.0.5/linux/drivers/net/ppp.c	Tue May  7 16:22:30 1996
+++ linux/drivers/net/ppp.c	Fri May 17 18:43:34 1996
@@ -400,6 +400,7 @@
 	dev->get_stats	      = ppp_dev_stats;
 	dev->do_ioctl	      = ppp_dev_ioctl;
 	dev->addr_len	      = 0;
+	dev->tx_queue_len     = 10;
 	dev->type	      = ARPHRD_PPP;
 
 	for (indx = 0; indx < DEV_NUMBUFFS; indx++)
diff -u --recursive --new-file pre2.0.5/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- pre2.0.5/linux/drivers/net/sdla.c	Fri May 17 15:32:15 1996
+++ linux/drivers/net/sdla.c	Sat May 18 11:15:09 1996
@@ -367,7 +367,7 @@
                      state = "active";
                   else
                   {
-                     sprintf(line, "uknown status: %02X", pstatus->flags);
+                     sprintf(line, "unknown status: %02X", pstatus->flags);
                      state = line;
                   }
             printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
diff -u --recursive --new-file pre2.0.5/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- pre2.0.5/linux/drivers/net/slhc.c	Tue May  7 16:22:31 1996
+++ linux/drivers/net/slhc.c	Sun May 19 13:29:22 1996
@@ -79,10 +79,7 @@
 #include <linux/mm.h>
 #include <net/checksum.h>
 #include <net/slhc_vj.h>
-
-#ifdef __alpha__
-# include <asm/unaligned.h>
-#endif
+#include <asm/unaligned.h>
 
 int last_retran;
 
@@ -619,11 +616,8 @@
 	  cp += (ip->ihl - 5) * 4;
 	}
 
-#ifdef __alpha__
-	stw_u(ip_fast_csum(icp, ip->ihl), &((struct iphdr *)icp)->check);
-#else
-	((struct iphdr *)icp)->check = ip_fast_csum(icp, ((struct iphdr*)icp)->ihl);
-#endif
+	put_unaligned(ip_fast_csum(icp, ip->ihl),
+		      &((struct iphdr *)icp)->check);
 
 	memcpy(cp, thp, 20);
 	cp += 20;
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- pre2.0.5/linux/drivers/scsi/Config.in	Sat May 11 10:42:05 1996
+++ linux/drivers/scsi/Config.in	Sat May 18 11:58:33 1996
@@ -42,7 +42,12 @@
 fi
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
-dep_tristate 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC $CONFIG_SCSI
+dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" ]; then
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+     dep_tristate 'Qlogic ISP SCSI support (EXPERIMENTAL)' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
+  fi
+fi
 dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
 dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
 dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- pre2.0.5/linux/drivers/scsi/Makefile	Sat Apr 27 15:19:56 1996
+++ linux/drivers/scsi/Makefile	Sat May 18 11:58:33 1996
@@ -124,13 +124,23 @@
   endif
 endif
 
-ifeq ($(CONFIG_SCSI_QLOGIC),y)
-L_OBJS += qlogic.o
+ifeq ($(CONFIG_SCSI_QLOGIC_FAS),y)
+L_OBJS += qlogicfas.o
 else
-  ifeq ($(CONFIG_SCSI_QLOGIC),m)
-  M_OBJS += qlogic.o
+  ifeq ($(CONFIG_SCSI_QLOGIC_FAS),m)
+  M_OBJS += qlogicfas.o
   endif
 endif
+
+
+ifeq ($(CONFIG_SCSI_QLOGIC_ISP),y)
+L_OBJS += qlogicisp.o 
+else
+  ifeq ($(CONFIG_SCSI_QLOGIC_ISP),m)
+  M_OBJS += qlogicisp.o 
+  endif
+endif
+
 
 ifeq ($(CONFIG_SCSI_AHA152X),y)
 L_OBJS += aha152x.o
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/README.qlogic linux/drivers/scsi/README.qlogic
--- pre2.0.5/linux/drivers/scsi/README.qlogic	Sat Nov 26 18:22:36 1994
+++ linux/drivers/scsi/README.qlogic	Thu Jan  1 02:00:00 1970
@@ -1,65 +0,0 @@
-
-RANDOM NOTES ON THE QLOGIC SCSI DRIVER
-
-This driver does NOT support the PCI version.  It is a different chip.
-
-It DOES support the ISA, VLB, and PCMCIA versions of the Qlogic FastSCSI!
-cards as well as any other card based on the chip (including the Control
-Concepts SCSI/IDE/SIO/PIO/FDC cards).
-
-PCMCIA SUPPORT
-
-This currently only works if the card is enabled first from DOS.  This means
-you will have to load your socket and card services, and QL41DOS.SYS and
-QL40ENBL.SYS.  These are a minimum, but loading the rest of the modules
-won't interfere with the operation.  The next thing to do is load the kernel
-without resetting the hardware, which can be a simple ctrl-alt-delete with
-a boot floppy, or by using loadlin with the kernel image accessible from
-DOS.  If you are using the Linux PCMCIA driver, you will have to adjust
-it or otherwise stop it from configuring the card.
-
-I am working with the PCMCIA group to make it more flexible, but that may
-take a while.
-
-ALL CARDS
-
-The top of the qlogic.c file has a number of defines that controls 
-configuration.  As shipped, it provides a balance between speed and
-function.  If there are any problems, try setting SLOW_CABLE to 1, and
-then try changing USE_IRQ and TURBO_PDMA to zero.  If you are familiar 
-with SCSI, there are other settings which can tune the bus.
-
-It may be a good idea to enable RESET_AT_START, especially if the devices
-may not have been just powered up, or if you are restarting after a crash,
-since they may be busy trying to complete the last command or something.
-It comes up faster if this is set to zero, and if you have reliable
-hardware and connections it may be more useful to not reset things.
-
-SOME TROUBLESHOOTING TIPS
-
-Make sure it works properly under DOS.  You should also do an initial FDISK
-on a new drive if you want partitions.
-
-Don't enable all the speedups first.  If anything is wrong, they will make
-any problem worse.
-
-IMPORTANT
-
-The best way to test if your cables, termination, etc. are good is to copy
-a very big file (e.g. a doublespace container file, or a very large executable
-or archive).  It should be at least 5 megabytes, but you can do multiple tests
-on smaller files.  Then do a COMP to verify that the file copied properly.
-(Turn off all caching when doing these tests, otherwise you will test your
-RAM and not the files).  Then do 10 COMPs, comparing the same file on the
-SCSI hard drive, i.e. "COMP realbig.doc realbig.doc".  Then do it after the
-computer gets warm.
-
-I noticed my system which seems to work 100% would fail this test if the
-computer was left on for a few hours.  It was worse with longer cables, and
-more devices on the SCSI bus.  What seems to happen is that it gets a false
-ACK causing an extra byte to be inserted into the stream (and this is not
-detected).  This can be caused by bad termination (the ACK can be reflected),
-or by noise when the chips work less well because of the heat, or when cables
-get too long for the speed.
-
-If it doesn't work under DOS, it won't work under Linux.
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/README.qlogicfas linux/drivers/scsi/README.qlogicfas
--- pre2.0.5/linux/drivers/scsi/README.qlogicfas	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README.qlogicfas	Sat May 18 11:58:33 1996
@@ -0,0 +1,73 @@
+
+RANDOM NOTES ON THE QLOGICFAS SCSI DRIVER
+
+This driver supports the Qlogic FASXXX family of chips.  This driver
+only works with the ISA, VLB, and PCMCIA versions of the Qlogic
+FastSCSI!  cards as well as any other card based on the FASXX chip
+(including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards).
+
+This driver does NOT support the PCI version.  Support for these PCI
+Qlogic boards:
+
+	IQ-PCI
+	IQ-PCI-10
+	IQ-PCI-D
+
+is provided by the qlogicisp.c driver.   Check README.qlogicisp for details.
+
+PCMCIA SUPPORT
+
+This currently only works if the card is enabled first from DOS.  This means
+you will have to load your socket and card services, and QL41DOS.SYS and
+QL40ENBL.SYS.  These are a minimum, but loading the rest of the modules
+won't interfere with the operation.  The next thing to do is load the kernel
+without resetting the hardware, which can be a simple ctrl-alt-delete with
+a boot floppy, or by using loadlin with the kernel image accessible from
+DOS.  If you are using the Linux PCMCIA driver, you will have to adjust
+it or otherwise stop it from configuring the card.
+
+I am working with the PCMCIA group to make it more flexible, but that may
+take a while.
+
+ALL CARDS
+
+The top of the qlogic.c file has a number of defines that controls 
+configuration.  As shipped, it provides a balance between speed and
+function.  If there are any problems, try setting SLOW_CABLE to 1, and
+then try changing USE_IRQ and TURBO_PDMA to zero.  If you are familiar 
+with SCSI, there are other settings which can tune the bus.
+
+It may be a good idea to enable RESET_AT_START, especially if the devices
+may not have been just powered up, or if you are restarting after a crash,
+since they may be busy trying to complete the last command or something.
+It comes up faster if this is set to zero, and if you have reliable
+hardware and connections it may be more useful to not reset things.
+
+SOME TROUBLESHOOTING TIPS
+
+Make sure it works properly under DOS.  You should also do an initial FDISK
+on a new drive if you want partitions.
+
+Don't enable all the speedups first.  If anything is wrong, they will make
+any problem worse.
+
+IMPORTANT
+
+The best way to test if your cables, termination, etc. are good is to copy
+a very big file (e.g. a doublespace container file, or a very large executable
+or archive).  It should be at least 5 megabytes, but you can do multiple tests
+on smaller files.  Then do a COMP to verify that the file copied properly.
+(Turn off all caching when doing these tests, otherwise you will test your
+RAM and not the files).  Then do 10 COMPs, comparing the same file on the
+SCSI hard drive, i.e. "COMP realbig.doc realbig.doc".  Then do it after the
+computer gets warm.
+
+I noticed my system which seems to work 100% would fail this test if the
+computer was left on for a few hours.  It was worse with longer cables, and
+more devices on the SCSI bus.  What seems to happen is that it gets a false
+ACK causing an extra byte to be inserted into the stream (and this is not
+detected).  This can be caused by bad termination (the ACK can be reflected),
+or by noise when the chips work less well because of the heat, or when cables
+get too long for the speed.
+
+Remember, if it doesn't work under DOS, it probably won't work under Linux.
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/README.qlogicisp linux/drivers/scsi/README.qlogicisp
--- pre2.0.5/linux/drivers/scsi/README.qlogicisp	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README.qlogicisp	Sat May 18 11:58:33 1996
@@ -0,0 +1,26 @@
+Notes for the QLogic ISP1020 PCI SCSI Driver revision 0.6.
+
+This software should be considered ***BETA***.
+
+Be sure to include PCI BIOS support when rebuilding the kernel.
+
+The QLogic Corporation produces several PCI SCSI adapters:
+
+	PCI-basic
+	IQ-PCI
+	IQ-PCI-10
+	IQ-PCI-D
+
+This driver should work for all these adpaters, except for the PCI-basic which
+does not use the ISP1020 chip.  If you have the QLogic PCI-basic there is a
+an am53c974 driver that supports your adapter.
+
+Much thanks to QLogic's tech support for providing the latest ISP1020 firmware,
+and for taking the time to review my code.
+
+Erik Moe
+ehm@cris.com
+
+Revised:
+Michael A. Griffith
+grif@cs.ucr.edu
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c
--- pre2.0.5/linux/drivers/scsi/atari_NCR5380.c	Fri May 17 15:32:16 1996
+++ linux/drivers/scsi/atari_NCR5380.c	Sat May 18 11:15:09 1996
@@ -631,7 +631,7 @@
 
 #else /* !NDEBUG */
 
-/* dummys... */
+/* dummies... */
 __inline__ void NCR5380_print(struct Scsi_Host *instance) { };
 __inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
 
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/atari_scsi.h linux/drivers/scsi/atari_scsi.h
--- pre2.0.5/linux/drivers/scsi/atari_scsi.h	Fri May 17 15:32:16 1996
+++ linux/drivers/scsi/atari_scsi.h	Sat May 18 11:15:09 1996
@@ -107,7 +107,7 @@
  *  MAIN -> NCR5380_main() control flow
  *  NDAT -> no data-out phase
  *  NWR  -> no write commands
- *  PIO  -> PIO tansfers
+ *  PIO  -> PIO transfers
  *  PDMA -> pseudo DMA (unused on Atari)
  *  QU   -> queues
  *  RSL  -> reselections
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c
--- pre2.0.5/linux/drivers/scsi/constants.c	Thu Dec 14 06:44:58 1995
+++ linux/drivers/scsi/constants.c	Sat May 18 22:18:56 1996
@@ -365,13 +365,29 @@
 
 #if (CONSTANTS & CONST_SENSE)
 static const char *snstext[] = {
-    "None","Recovered Error","Not Ready","Medium Error","Hardware Error",
-    "Illegal Request","Unit Attention","Data Protect","Blank Check",
-    "Key=9","Copy Aborted","Aborted Command","End-Of-Medium",
-    "Volume Overflow", "Miscompare", "Key=15"};
+    "None",                     /* There is no sense information */
+    "Recovered Error",          /* The last command completed successfully
+                                   but used error correction */
+    "Not Ready",                /* The addressed target is not ready */
+    "Medium Error",             /* Data error detected on the medium */
+    "Hardware Error",           /* Controller or device failure */
+    "Illegal Request",
+    "Unit Attention",           /* Removable medium was changed, or
+                                   the target has been reset */
+    "Data Protect",             /* Access to the data is blocked */
+    "Blank Check",              /* Reached unexpected written or unwritten
+                                   region of the medium */
+    "Key=9",                    /* Vendor specific */
+    "Copy Aborted",             /* COPY or COMPARE was aborted */
+    "Aborted Command",          /* The target aborted the command */
+    "Equal",                    /* A SEARCH DATA command found data equal */
+    "Volume Overflow",          /* Medium full with still data to be written */
+    "Miscompare",               /* Source data and data on the medium
+                                   do not agree */
+    "Key=15"                    /* Reserved */
+};
 #endif
 
-
 /* Print sense information */
 void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
 {
@@ -384,23 +400,29 @@
     code = sense_buffer[0] & 0xf;
     valid = sense_buffer[0] & 0x80;
     
-    if (sense_class == 7) { 
+    if (sense_class == 7) {	/* extended sense data */
 	s = sense_buffer[7] + 8;
-	if(s > sizeof(SCpnt->sense_buffer)) s = sizeof(SCpnt->sense_buffer);
+	if(s > sizeof(SCpnt->sense_buffer))
+           s = sizeof(SCpnt->sense_buffer);
 	
 	if (!valid)
 	    printk("extra data not valid ");
 	
-	if (sense_buffer[2] & 0x80) printk( "FMK ");
-	if (sense_buffer[2] & 0x40) printk( "EOM ");
-	if (sense_buffer[2] & 0x20) printk( "ILI ");
+	if (sense_buffer[2] & 0x80)
+           printk( "FMK ");	/* current command has read a filemark */
+	if (sense_buffer[2] & 0x40)
+           printk( "EOM ");	/* end-of-medium condition exists */
+	if (sense_buffer[2] & 0x20)
+           printk( "ILI ");	/* incorrect block length requested */
 	
 	switch (code) {
 	case 0x0:
-	    error = "Current";
+	    error = "Current";	/* error concerns current command */
 	    break;
 	case 0x1:
-	    error = "Deferred";
+	    error = "Deferred";	/* error concerns some earlier command */
+            	/* e.g., an earlier write to disk cache succeeded, but
+                   now the disk discovers that it cannot write the data */
 	    break;
 	default:
 	    error = "Invalid";
@@ -437,7 +459,15 @@
 #else
 	printk("ASC=%2x ASCQ=%2x\n", sense_buffer[12], sense_buffer[13]);
 #endif
-    } else { 
+    } else {	/* non-extended sense data */
+
+         /*
+          * Standard says:
+          *    sense_buffer[0] & 0200 : address valid
+          *    sense_buffer[0] & 0177 : vendor-specific error code
+          *    sense_buffer[1] & 0340 : vendor-specific
+          *    sense_buffer[1..3] : 21-bit logical block address
+          */
 	
 #if (CONSTANTS & CONST_SENSE)
 	if (sense_buffer[0] < 15)
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- pre2.0.5/linux/drivers/scsi/hosts.c	Tue May  7 16:22:34 1996
+++ linux/drivers/scsi/hosts.c	Sat May 18 11:58:34 1996
@@ -109,8 +109,12 @@
 #include "pas16.h"
 #endif
 
-#ifdef CONFIG_SCSI_QLOGIC
-#include "qlogic.h"
+#ifdef CONFIG_SCSI_QLOGIC_FAS
+#include "qlogicfas.h"
+#endif
+
+#ifdef CONFIG_SCSI_QLOGIC_ISP
+#include "qlogicisp.h"
 #endif
 
 #ifdef CONFIG_SCSI_SEAGATE
@@ -250,8 +254,11 @@
 #ifdef CONFIG_SCSI_NCR53C406A	/* 53C406A should come before QLOGIC */
     NCR53c406a,
 #endif
-#ifdef CONFIG_SCSI_QLOGIC
-    QLOGIC,
+#ifdef CONFIG_SCSI_QLOGIC_FAS
+    QLOGICFAS,
+#endif
+#ifdef CONFIG_SCSI_QLOGIC_ISP
+    QLOGICISP,
 #endif
 #ifdef CONFIG_SCSI_PAS16
     MV_PAS16,
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- pre2.0.5/linux/drivers/scsi/hosts.h	Mon Apr 15 12:20:19 1996
+++ linux/drivers/scsi/hosts.h	Sat May 18 22:19:00 1996
@@ -235,7 +235,7 @@
  * Scsi_Host_Template, except that we have one entry for each
  * actual physical host adapter on the system, stored as a linked
  * list.  Note that if there are 2 aha1542 boards, then there will
- * be two Scsi_Host entries, but only 1 Scsi_Host_Template entries.
+ * be two Scsi_Host entries, but only 1 Scsi_Host_Template entry.
  */
 
 struct Scsi_Host
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/qlogic.c linux/drivers/scsi/qlogic.c
--- pre2.0.5/linux/drivers/scsi/qlogic.c	Fri Mar  1 07:50:53 1996
+++ linux/drivers/scsi/qlogic.c	Thu Jan  1 02:00:00 1970
@@ -1,678 +0,0 @@
-/*----------------------------------------------------------------*/
-/*
-   Qlogic linux driver - work in progress. No Warranty express or implied.
-   Use at your own risk.  Support Tort Reform so you won't have to read all
-   these silly disclaimers.
-
-   Copyright 1994, Tom Zerucha.   
-   zerucha@shell.portal.com
-
-   Additional Code, and much appreciated help by
-   Michael A. Griffith
-   grif@cs.ucr.edu
-
-   Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
-   help respectively, and for suffering through my foolishness during the
-   debugging process.
-
-   Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
-   (you can reference it, but it is incomplete and inaccurate in places)
-
-   Version 0.43 4/6/95 - kernel 1.2.0+, pcmcia 2.5.4+
-
-   Functions as standalone, loadable, and PCMCIA driver, the latter from
-   Dave Hind's PCMCIA package.
-
-   Redistributable under terms of the GNU Public License
-
-*/
-/*----------------------------------------------------------------*/
-/* Configuration */
-
-/* Set the following to 2 to use normal interrupt (active high/totempole-
-   tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
-   drain */
-#define QL_INT_ACTIVE_HIGH 2
-
-/* Set the following to 1 to enable the use of interrupts.  Note that 0 tends
-   to be more stable, but slower (or ties up the system more) */
-#define QL_USE_IRQ 1
-
-/* Set the following to max out the speed of the PIO PseudoDMA transfers,
-   again, 0 tends to be slower, but more stable.  */
-#define QL_TURBO_PDMA 1
-
-/* This should be 1 to enable parity detection */
-#define QL_ENABLE_PARITY 1
-
-/* This will reset all devices when the driver is initialized (during bootup).
-   The other linux drivers don't do this, but the DOS drivers do, and after
-   using DOS or some kind of crash or lockup this will bring things back
-   without requiring a cold boot.  It does take some time to recover from a
-   reset, so it is slower, and I have seen timeouts so that devices weren't
-   recognized when this was set. */
-#define QL_RESET_AT_START 0
-
-/* crystal frequency in megahertz (for offset 5 and 9)
-   Please set this for your card.  Most Qlogic cards are 40 Mhz.  The
-   Control Concepts ISA (not VLB) is 24 Mhz */
-#define XTALFREQ	40
-
-/**********/
-/* DANGER! modify these at your own risk */
-/* SLOWCABLE can usually be reset to zero if you have a clean setup and
-   proper termination.  The rest are for synchronous transfers and other
-   advanced features if your device can transfer faster than 5Mb/sec.
-   If you are really curious, email me for a quick howto until I have
-   something official */
-/**********/
-
-/*****/
-/* config register 1 (offset 8) options */
-/* This needs to be set to 1 if your cabling is long or noisy */
-#define SLOWCABLE 1
-
-/*****/
-/* offset 0xc */
-/* This will set fast (10Mhz) synchronous timing when set to 1
-   For this to have an effect, FASTCLK must also be 1 */
-#define FASTSCSI 0
-
-/* This when set to 1 will set a faster sync transfer rate */
-#define FASTCLK 0
-/*(XTALFREQ>25?1:0)*/
-
-/*****/
-/* offset 6 */
-/* This is the sync transfer divisor, XTALFREQ/X will be the maximum
-   achievable data rate (assuming the rest of the system is capable
-   and set properly) */
-#define SYNCXFRPD 5
-/*(XTALFREQ/5)*/
-
-/*****/
-/* offset 7 */
-/* This is the count of how many synchronous transfers can take place
-	i.e. how many reqs can occur before an ack is given.
-	The maximum value for this is 15, the upper bits can modify
-	REQ/ACK assertion and deassertion during synchronous transfers
-	If this is 0, the bus will only transfer asynchronously */
-#define SYNCOFFST 0
-/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
-	of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
-	cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
-	the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
-
-/*----------------------------------------------------------------*/
-#ifdef PCMCIA
-#undef QL_INT_ACTIVE_HIGH
-#define QL_INT_ACTIVE_HIGH 0
-#define MODULE
-#endif 
-
-#include <linux/module.h>
-
-#ifdef PCMCIA
-#undef MODULE
-#endif 
-
-#include <linux/blk.h>	/* to get disk capacity */
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/unistd.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include "sd.h"
-#include "hosts.h"
-#include "qlogic.h"
-#include<linux/stat.h>
-
-struct proc_dir_entry proc_scsi_qlogic = {
-    PROC_SCSI_QLOGIC, 6, "qlogic",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
-};
-
-/*----------------------------------------------------------------*/
-/* driver state info, local to driver */
-static int	    qbase = 0;	/* Port */
-static int	    qinitid;	/* initiator ID */
-static int	    qabort;	/* Flag to cause an abort */
-static int	    qlirq = -1;	/* IRQ being used */
-static char	    qinfo[80];	/* description */
-static Scsi_Cmnd   *qlcmd;	/* current command being processed */
-
-static int	    qlcfg5 = ( XTALFREQ << 5 );	/* 15625/512 */
-static int	    qlcfg6 = SYNCXFRPD;
-static int	    qlcfg7 = SYNCOFFST;
-static int	    qlcfg8 = ( SLOWCABLE << 7 ) | ( QL_ENABLE_PARITY << 4 );
-static int	    qlcfg9 = ( ( XTALFREQ + 4 ) / 5 );
-static int	    qlcfgc = ( FASTCLK << 3 ) | ( FASTSCSI << 4 );
-
-/*----------------------------------------------------------------*/
-/* The qlogic card uses two register maps - These macros select which one */
-#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
-#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
-
-/* following is watchdog timeout in microseconds */
-#define WATCHDOG 5000000
-
-/*----------------------------------------------------------------*/
-/* the following will set the monitor border color (useful to find
-   where something crashed or gets stuck at and as a simple profiler) */
-
-#if 0
-#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
-#else
-#define rtrc(i) {}
-#endif
-
-/*----------------------------------------------------------------*/
-/* local functions */
-/*----------------------------------------------------------------*/
-static void	ql_zap(void);
-/* error recovery - reset everything */
-void	ql_zap()
-{
-int	x;
-unsigned long	flags;
-	save_flags( flags );
-	cli();
-	x = inb(qbase + 0xd);
-	REG0;
-	outb(3, qbase + 3);				/* reset SCSI */
-	outb(2, qbase + 3);				/* reset chip */
-	if (x & 0x80)
-		REG1;
-	restore_flags( flags );
-}
-
-/*----------------------------------------------------------------*/
-/* do pseudo-dma */
-static int	ql_pdma(int phase, char *request, int reqlen)
-{
-int	j;
-	j = 0;
-	if (phase & 1) {	/* in */
-#if QL_TURBO_PDMA
-rtrc(4)
-		/* empty fifo in large chunks */
-		if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */
-			insl( qbase + 4, request, 32 );
-			reqlen -= 128;
-			request += 128;
-		}
-		while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */
-			if( (j=inb( qbase + 8 )) & 4 ) {
-				insl( qbase + 4, request, 21 );
-				reqlen -= 84;
-				request += 84;
-			}
-		if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) {	/* 1/3 */
-			insl( qbase + 4, request, 11 );
-			reqlen -= 44;
-			request += 44;
-		}
-#endif
-		/* until both empty and int (or until reclen is 0) */
-rtrc(7)
-		j = 0;
-		while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) {
-			/* while bytes to receive and not empty */
-			j &= 0xc0;
-			while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) {
-				*request++ = inb(qbase + 4);
-				reqlen--;
-			}
-			if( j & 0x10 )
-				j = inb(qbase+8);
-
-		}
-	}
-	else {	/* out */
-#if QL_TURBO_PDMA
-rtrc(4)
-		if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */
-			outsl(qbase + 4, request, 32 );
-			reqlen -= 128;
-			request += 128;
-		}
-		while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */
-			if( !((j=inb( qbase + 8 )) & 8) ) {
-				outsl( qbase + 4, request, 21 );
-				reqlen -= 84;
-				request += 84;
-			}
-		if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */
-			outsl( qbase + 4, request, 10 );
-			reqlen -= 40;
-			request += 40;
-		}
-#endif
-		/* until full and int (or until reclen is 0) */
-rtrc(7)
-		j = 0;
-		while( reqlen && !( (j & 2) && (j & 0xc0) ) ) {
-			/* while bytes to send and not full */
-			while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) {
-				outb(*request++, qbase + 4);
-				reqlen--;
-			}
-			if( j & 2 )
-				j = inb(qbase+8);
-		}
-	}
-/* maybe return reqlen */
-	return inb( qbase + 8 ) & 0xc0;
-}
-
-/*----------------------------------------------------------------*/
-/* wait for interrupt flag (polled - not real hardware interrupt) */
-static int	ql_wai(void)
-{
-int	i,k;
-	k = 0;
-	i = jiffies + WATCHDOG;
-	while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0))
-		barrier();
-	if (i <= jiffies)
-		return (DID_TIME_OUT);
-	if (qabort)
-		return (qabort == 1 ? DID_ABORT : DID_RESET);
-	if (k & 0x60)
-		ql_zap();
-	if (k & 0x20)
-		return (DID_PARITY);
-	if (k & 0x40)
-		return (DID_ERROR);
-	return 0;
-}
-
-/*----------------------------------------------------------------*/
-/* initiate scsi command - queueing handler */
-static void	ql_icmd(Scsi_Cmnd * cmd)
-{
-unsigned int	    i;
-unsigned long	flags;
-
-	qabort = 0;
-
-	save_flags( flags );
-	cli();
-	REG0;
-/* clearing of interrupts and the fifo is needed */
-	inb(qbase + 5); 			/* clear interrupts */
-	if (inb(qbase + 5))			/* if still interrupting */
-		outb(2, qbase + 3);		/* reset chip */
-	else if (inb(qbase + 7) & 0x1f)
-		outb(1, qbase + 3);		/* clear fifo */
-	while (inb(qbase + 5)); 		/* clear ints */
-	REG1;
-	outb(1, qbase + 8);			/* set for PIO pseudo DMA */
-	outb(0, qbase + 0xb);			/* disable ints */
-	inb(qbase + 8); 			/* clear int bits */
-	REG0;
-	outb(0x40, qbase + 0xb);		/* enable features */
-
-/* configurables */
-	outb( qlcfgc , qbase + 0xc);
-/* config: no reset interrupt, (initiator) bus id */
-	outb( 0x40 | qlcfg8 | qinitid, qbase + 8);
-	outb( qlcfg7 , qbase + 7 );
-	outb( qlcfg6 , qbase + 6 );
-/**/
-	outb(qlcfg5, qbase + 5);		/* select timer */
-	outb(qlcfg9 & 7, qbase + 9);			/* prescaler */
-/*	outb(0x99, qbase + 5);	*/
-	outb(cmd->target, qbase + 4);
-
-	for (i = 0; i < cmd->cmd_len; i++)
-		outb(cmd->cmnd[i], qbase + 2);
-	qlcmd = cmd;
-	outb(0x41, qbase + 3);	/* select and send command */
-	restore_flags( flags );
-}
-/*----------------------------------------------------------------*/
-/* process scsi command - usually after interrupt */
-static unsigned int	ql_pcmd(Scsi_Cmnd * cmd)
-{
-unsigned int	i, j, k;
-unsigned int	result; 		/* ultimate return result */
-unsigned int	status; 		/* scsi returned status */
-unsigned int	message;		/* scsi returned message */
-unsigned int	phase;			/* recorded scsi phase */
-unsigned int	reqlen; 		/* total length of transfer */
-struct scatterlist	*sglist;	/* scatter-gather list pointer */
-unsigned int	sgcount;		/* sg counter */
-
-rtrc(1)
-	j = inb(qbase + 6);
-	i = inb(qbase + 5);
-	if (i == 0x20) {
-		return (DID_NO_CONNECT << 16);
-	}
-	i |= inb(qbase + 5);	/* the 0x10 bit can be set after the 0x08 */
-	if (i != 0x18) {
-		printk("Ql:Bad Interrupt status:%02x\n", i);
-		ql_zap();
-		return (DID_BAD_INTR << 16);
-	}
-	j &= 7; /* j = inb( qbase + 7 ) >> 5; */
-/* correct status is supposed to be step 4 */
-/* it sometimes returns step 3 but with 0 bytes left to send */
-/* We can try stuffing the FIFO with the max each time, but we will get a
-   sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
-	if(j != 3 && j != 4) {
-		printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );
-		ql_zap();
-		return (DID_ERROR << 16);
-	}
-	result = DID_OK;
-	if (inb(qbase + 7) & 0x1f)	/* if some bytes in fifo */
-		outb(1, qbase + 3);		/* clear fifo */
-/* note that request_bufflen is the total xfer size when sg is used */
-	reqlen = cmd->request_bufflen;
-/* note that it won't work if transfers > 16M are requested */
-	if (reqlen && !((phase = inb(qbase + 4)) & 6)) {	/* data phase */
-rtrc(2)
-		outb(reqlen, qbase);			/* low-mid xfer cnt */
-		outb(reqlen >> 8, qbase+1);			/* low-mid xfer cnt */
-		outb(reqlen >> 16, qbase + 0xe);	/* high xfer cnt */
-		outb(0x90, qbase + 3);			/* command do xfer */
-/* PIO pseudo DMA to buffer or sglist */
-		REG1;
-		if (!cmd->use_sg)
-			ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);
-		else {
-			sgcount = cmd->use_sg;
-			sglist = cmd->request_buffer;
-			while (sgcount--) {
-				if (qabort) {
-					REG0;
-					return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
-				}
-				if (ql_pdma(phase, sglist->address, sglist->length))
-					break;
-				sglist++;
-			}
-		}
-		REG0;
-rtrc(2)
-/* wait for irq (split into second state of irq handler if this can take time) */
-		if ((k = ql_wai()))
-			return (k << 16);
-		k = inb(qbase + 5);	/* should be 0x10, bus service */
-	}
-/*** Enter Status (and Message In) Phase ***/
-	k = jiffies + WATCHDOG;
-	while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6));	/* wait for status phase */
-	if ( k <= jiffies ) {
-		ql_zap();
-		return (DID_TIME_OUT << 16);
-	}
-	while (inb(qbase + 5)); 				/* clear pending ints */
-	if (qabort)
-		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
-	outb(0x11, qbase + 3);					/* get status and message */
-	if ((k = ql_wai()))
-		return (k << 16);
-	i = inb(qbase + 5);					/* get chip irq stat */
-	j = inb(qbase + 7) & 0x1f;				/* and bytes rec'd */
-	status = inb(qbase + 2);
-	message = inb(qbase + 2);
-/* should get function complete int if Status and message, else bus serv if only status */
-	if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
-		printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
-		result = DID_ERROR;
-	}
-	outb(0x12, qbase + 3);	/* done, disconnect */
-rtrc(1)
-	if ((k = ql_wai()))
-		return (k << 16);
-/* should get bus service interrupt and disconnect interrupt */
-	i = inb(qbase + 5);	/* should be bus service */
-	while (!qabort && ((i & 0x20) != 0x20)) {
-		barrier();
-		i |= inb(qbase + 5);
-	}
-rtrc(0)
-	if (qabort)
-		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
-	return (result << 16) | (message << 8) | (status & STATUS_MASK);
-}
-
-#if QL_USE_IRQ
-/*----------------------------------------------------------------*/
-/* interrupt handler */
-static void	       ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
-{
-Scsi_Cmnd	   *icmd;
-	REG0;
-	if (!(inb(qbase + 4) & 0x80))	/* false alarm? */
-		return;
-	if (qlcmd == NULL) {		/* no command to process? */
-		int	i;
-		i = 16;
-		while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */
-		return;
-	}
-	icmd = qlcmd;
-	icmd->result = ql_pcmd(icmd);
-	qlcmd = NULL;
-/* if result is CHECK CONDITION done calls qcommand to request sense */
-	(icmd->scsi_done) (icmd);
-}
-#endif
-
-/*----------------------------------------------------------------*/
-/* global functions */
-/*----------------------------------------------------------------*/
-/* non queued command */
-#if QL_USE_IRQ
-static void	qlidone(Scsi_Cmnd * cmd) {};		/* null function */
-#endif
-
-/* command process */
-int	qlogic_command(Scsi_Cmnd * cmd)
-{
-int	k;
-#if QL_USE_IRQ
-	if (qlirq >= 0) {
-		qlogic_queuecommand(cmd, qlidone);
-		while (qlcmd != NULL);
-		return cmd->result;
-	}
-#endif
-/* non-irq version */
-	if (cmd->target == qinitid)
-		return (DID_BAD_TARGET << 16);
-	ql_icmd(cmd);
-	if ((k = ql_wai()))
-		return (k << 16);
-	return ql_pcmd(cmd);
-
-}
-
-#if QL_USE_IRQ
-/*----------------------------------------------------------------*/
-/* queued command */
-int	qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-{
-	if(cmd->target == qinitid) {
-		cmd->result = DID_BAD_TARGET << 16;
-		done(cmd);
-		return 0;
-	}
-
-	cmd->scsi_done = done;
-/* wait for the last command's interrupt to finish */
-	while (qlcmd != NULL)
-		barrier();
-	ql_icmd(cmd);
-	return 0;
-}
-#else
-int	qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-{
-	return 1;
-}
-#endif
-
-#ifdef PCMCIA
-/*----------------------------------------------------------------*/
-/* allow PCMCIA code to preset the port */
-/* port should be 0 and irq to -1 respectively for autoprobing */
-void	qlogic_preset(int port, int irq)
-{
-	qbase=port;
-	qlirq=irq;
-}
-#endif
-
-/*----------------------------------------------------------------*/
-/* look for qlogic card and init if found */
-int	qlogic_detect(Scsi_Host_Template * host)
-{
-int	i, j;			/* these are only used by IRQ detect */
-int	qltyp;			/* type of chip */
-struct	Scsi_Host	*hreg;	/* registered host structure */
-unsigned long	flags;
-
-host->proc_dir =  &proc_scsi_qlogic;
-
-/* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
-   address - I check 230 first since MIDI cards are typically at 330
-
-   Theoretically, two Qlogic cards can coexist in the same system.  This
-   should work by simply using this as a loadable module for the second
-   card, but I haven't tested this.
-*/
-
-	if( !qbase ) {
-		for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
-			if( check_region( qbase , 0x10 ) )
-				continue;
-			REG1;
-			if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
-			  && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
-				break;
-		}
-		if (qbase == 0x430)
-			return 0;
-	}
-	else
-		printk( "Ql: Using preset base address of %03x\n", qbase );
-
-	qltyp = inb(qbase + 0xe) & 0xf8;
-	qinitid = host->this_id;
-	if (qinitid < 0)
-		qinitid = 7;			/* if no ID, use 7 */
-	outb(1, qbase + 8);			/* set for PIO pseudo DMA */
-	REG0;
-	outb(0x40 | qlcfg8 | qinitid, qbase + 8);	/* (ini) bus id, disable scsi rst */
-	outb(qlcfg5, qbase + 5);		/* select timer */
-	outb(qlcfg9, qbase + 9);			/* prescaler */
-#if QL_RESET_AT_START
-	outb( 3 , qbase + 3 );
-	REG1;
-	while( inb( qbase + 0xf ) & 4 );
-	REG0;
-#endif
-#if QL_USE_IRQ
-/* IRQ probe - toggle pin and check request pending */
-
-	if( qlirq == -1 ) {
-		save_flags( flags );
-		cli();
-		i = 0xffff;
-		j = 3;
-		outb(0x90, qbase + 3);	/* illegal command - cause interrupt */
-		REG1;
-		outb(10, 0x20); /* access pending interrupt map */
-		outb(10, 0xa0);
-		while (j--) {
-			outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd);	/* int pin off */
-			i &= ~(inb(0x20) | (inb(0xa0) << 8));	/* find IRQ off */
-			outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd);	/* int pin on */
-			i &= inb(0x20) | (inb(0xa0) << 8);	/* find IRQ on */
-		}
-		REG0;
-		while (inb(qbase + 5)); 			/* purge int */
-		j = -1;
-		while (i)					/* find on bit */
-			i >>= 1, j++;	/* should check for exactly 1 on */
-		qlirq = j;
-		restore_flags( flags );
-	}
-	else
-		printk( "Ql: Using preset IRQ %d\n", qlirq );
-
-	if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic", NULL))
-		host->can_queue = 1;
-#endif
-	request_region( qbase , 0x10 ,"qlogic");
-	hreg = scsi_register( host , 0 );	/* no host data */
-	hreg->io_port = qbase;
-	hreg->n_io_port = 16;
-	hreg->dma_channel = -1;
-	if( qlirq != -1 )
-		hreg->irq = qlirq;
-
-	sprintf(qinfo, "Qlogic Driver version 0.43, chip %02X at %03X, IRQ %d, TPdma:%d",
-	    qltyp, qbase, qlirq, QL_TURBO_PDMA );
-	host->name = qinfo;
-
-	return 1;
-}
-
-/*----------------------------------------------------------------*/
-/* return bios parameters */
-int	qlogic_biosparam(Disk * disk, kdev_t dev, int ip[])
-{
-/* This should mimic the DOS Qlogic driver's behavior exactly */
-	ip[0] = 0x40;
-	ip[1] = 0x20;
-	ip[2] = disk->capacity / (ip[0] * ip[1]);
-	if (ip[2] > 1024) {
-		ip[0] = 0xff;
-		ip[1] = 0x3f;
-		ip[2] = disk->capacity / (ip[0] * ip[1]);
-		if (ip[2] > 1023)
-			ip[2] = 1023;
-	}
-	return 0;
-}
-
-/*----------------------------------------------------------------*/
-/* abort command in progress */
-int	qlogic_abort(Scsi_Cmnd * cmd)
-{
-	qabort = 1;
-	ql_zap();
-	return 0;
-}
-
-/*----------------------------------------------------------------*/
-/* reset SCSI bus */
-int	qlogic_reset(Scsi_Cmnd * cmd)
-{
-	qabort = 2;
-	ql_zap();
-	return 1;
-}
-
-/*----------------------------------------------------------------*/
-/* return info string */
-const char	*qlogic_info(struct Scsi_Host * host)
-{
-	return qinfo;
-}
-
-#ifdef MODULE
-/* Eventually this will go into an include file, but this will be later */
-Scsi_Host_Template driver_template = QLOGIC;
-
-#include "scsi_module.c"
-#endif
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/qlogic.h linux/drivers/scsi/qlogic.h
--- pre2.0.5/linux/drivers/scsi/qlogic.h	Mon Sep 18 08:54:09 1995
+++ linux/drivers/scsi/qlogic.h	Thu Jan  1 02:00:00 1970
@@ -1,40 +0,0 @@
-#ifndef _QLOGIC_H
-#define _QLOGIC_H
-
-int qlogic_detect(Scsi_Host_Template * );
-const char * qlogic_info(struct Scsi_Host *);
-int qlogic_command(Scsi_Cmnd *);
-int qlogic_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-int qlogic_abort(Scsi_Cmnd *);
-int qlogic_reset(Scsi_Cmnd *);
-int qlogic_biosparam(Disk *, kdev_t, int[]);
-
-#ifndef NULL
-#define NULL (0)
-#endif
-
-#define QLOGIC {		\
-	NULL,			\
-	NULL,			\
-	NULL,			\
-	NULL,		        \
-	NULL,			\
-	qlogic_detect,		\
-	NULL,			\
-	qlogic_info,		\
-	qlogic_command, 	\
-	qlogic_queuecommand,	\
-	qlogic_abort,		\
-	qlogic_reset,		\
-	NULL,			\
-	qlogic_biosparam,	\
-	0,			\
-	-1,			\
-	SG_ALL,			\
-	1,			\
-	0,			\
-	0,			\
-	DISABLE_CLUSTERING	\
-}
-
-#endif /* _QLOGIC_H */
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c
--- pre2.0.5/linux/drivers/scsi/qlogicfas.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogicfas.c	Sat May 18 11:58:34 1996
@@ -0,0 +1,679 @@
+/*----------------------------------------------------------------*/
+/*
+   Qlogic linux driver - work in progress. No Warranty express or implied.
+   Use at your own risk.  Support Tort Reform so you won't have to read all
+   these silly disclaimers.
+
+   Copyright 1994, Tom Zerucha.   
+   zerucha@shell.portal.com
+
+   Additional Code, and much appreciated help by
+   Michael A. Griffith
+   grif@cs.ucr.edu
+
+   Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
+   help respectively, and for suffering through my foolishness during the
+   debugging process.
+
+   Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
+   (you can reference it, but it is incomplete and inaccurate in places)
+
+   Version 0.44 5/7/96 - kernel 1.2.0+, pcmcia 2.5.4+
+
+   Functions as standalone, loadable, and PCMCIA driver, the latter from
+   Dave Hind's PCMCIA package.
+
+   Redistributable under terms of the GNU Public License
+
+*/
+/*----------------------------------------------------------------*/
+/* Configuration */
+
+/* Set the following to 2 to use normal interrupt (active high/totempole-
+   tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
+   drain */
+#define QL_INT_ACTIVE_HIGH 2
+
+/* Set the following to 1 to enable the use of interrupts.  Note that 0 tends
+   to be more stable, but slower (or ties up the system more) */
+#define QL_USE_IRQ 1
+
+/* Set the following to max out the speed of the PIO PseudoDMA transfers,
+   again, 0 tends to be slower, but more stable.  */
+#define QL_TURBO_PDMA 1
+
+/* This should be 1 to enable parity detection */
+#define QL_ENABLE_PARITY 1
+
+/* This will reset all devices when the driver is initialized (during bootup).
+   The other linux drivers don't do this, but the DOS drivers do, and after
+   using DOS or some kind of crash or lockup this will bring things back
+   without requiring a cold boot.  It does take some time to recover from a
+   reset, so it is slower, and I have seen timeouts so that devices weren't
+   recognized when this was set. */
+#define QL_RESET_AT_START 0
+
+/* crystal frequency in megahertz (for offset 5 and 9)
+   Please set this for your card.  Most Qlogic cards are 40 Mhz.  The
+   Control Concepts ISA (not VLB) is 24 Mhz */
+#define XTALFREQ	40
+
+/**********/
+/* DANGER! modify these at your own risk */
+/* SLOWCABLE can usually be reset to zero if you have a clean setup and
+   proper termination.  The rest are for synchronous transfers and other
+   advanced features if your device can transfer faster than 5Mb/sec.
+   If you are really curious, email me for a quick howto until I have
+   something official */
+/**********/
+
+/*****/
+/* config register 1 (offset 8) options */
+/* This needs to be set to 1 if your cabling is long or noisy */
+#define SLOWCABLE 1
+
+/*****/
+/* offset 0xc */
+/* This will set fast (10Mhz) synchronous timing when set to 1
+   For this to have an effect, FASTCLK must also be 1 */
+#define FASTSCSI 0
+
+/* This when set to 1 will set a faster sync transfer rate */
+#define FASTCLK 0
+/*(XTALFREQ>25?1:0)*/
+
+/*****/
+/* offset 6 */
+/* This is the sync transfer divisor, XTALFREQ/X will be the maximum
+   achievable data rate (assuming the rest of the system is capable
+   and set properly) */
+#define SYNCXFRPD 5
+/*(XTALFREQ/5)*/
+
+/*****/
+/* offset 7 */
+/* This is the count of how many synchronous transfers can take place
+	i.e. how many reqs can occur before an ack is given.
+	The maximum value for this is 15, the upper bits can modify
+	REQ/ACK assertion and deassertion during synchronous transfers
+	If this is 0, the bus will only transfer asynchronously */
+#define SYNCOFFST 0
+/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
+	of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
+	cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
+	the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
+
+/*----------------------------------------------------------------*/
+#ifdef PCMCIA
+#undef QL_INT_ACTIVE_HIGH
+#define QL_INT_ACTIVE_HIGH 0
+#define MODULE
+#endif 
+
+#include <linux/module.h>
+
+#ifdef PCMCIA
+#undef MODULE
+#endif 
+
+#include <linux/blk.h>	/* to get disk capacity */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/unistd.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include "sd.h"
+#include "hosts.h"
+#include "qlogicfas.h"
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_qlogicfas = {
+    PROC_SCSI_QLOGICFAS, 6, "qlogicfas",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+/*----------------------------------------------------------------*/
+/* driver state info, local to driver */
+static int	    qbase = 0;	/* Port */
+static int	    qinitid;	/* initiator ID */
+static int	    qabort;	/* Flag to cause an abort */
+static int	    qlirq = -1;	/* IRQ being used */
+static char	    qinfo[80];	/* description */
+static Scsi_Cmnd   *qlcmd;	/* current command being processed */
+
+static int	    qlcfg5 = ( XTALFREQ << 5 );	/* 15625/512 */
+static int	    qlcfg6 = SYNCXFRPD;
+static int	    qlcfg7 = SYNCOFFST;
+static int	    qlcfg8 = ( SLOWCABLE << 7 ) | ( QL_ENABLE_PARITY << 4 );
+static int	    qlcfg9 = ( ( XTALFREQ + 4 ) / 5 );
+static int	    qlcfgc = ( FASTCLK << 3 ) | ( FASTSCSI << 4 );
+
+/*----------------------------------------------------------------*/
+/* The qlogic card uses two register maps - These macros select which one */
+#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
+#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
+
+/* following is watchdog timeout in microseconds */
+#define WATCHDOG 5000000
+
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+   where something crashed or gets stuck at and as a simple profiler) */
+
+#if 0
+#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
+
+/*----------------------------------------------------------------*/
+/* local functions */
+/*----------------------------------------------------------------*/
+static void	ql_zap(void);
+/* error recovery - reset everything */
+void	ql_zap()
+{
+int	x;
+unsigned long	flags;
+	save_flags( flags );
+	cli();
+	x = inb(qbase + 0xd);
+	REG0;
+	outb(3, qbase + 3);				/* reset SCSI */
+	outb(2, qbase + 3);				/* reset chip */
+	if (x & 0x80)
+		REG1;
+	restore_flags( flags );
+}
+
+/*----------------------------------------------------------------*/
+/* do pseudo-dma */
+static int	ql_pdma(int phase, char *request, int reqlen)
+{
+int	j;
+	j = 0;
+	if (phase & 1) {	/* in */
+#if QL_TURBO_PDMA
+rtrc(4)
+		/* empty fifo in large chunks */
+		if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */
+			insl( qbase + 4, request, 32 );
+			reqlen -= 128;
+			request += 128;
+		}
+		while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */
+			if( (j=inb( qbase + 8 )) & 4 ) {
+				insl( qbase + 4, request, 21 );
+				reqlen -= 84;
+				request += 84;
+			}
+		if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) {	/* 1/3 */
+			insl( qbase + 4, request, 11 );
+			reqlen -= 44;
+			request += 44;
+		}
+#endif
+		/* until both empty and int (or until reclen is 0) */
+rtrc(7)
+		j = 0;
+		while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) {
+			/* while bytes to receive and not empty */
+			j &= 0xc0;
+			while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) {
+				*request++ = inb(qbase + 4);
+				reqlen--;
+			}
+			if( j & 0x10 )
+				j = inb(qbase+8);
+
+		}
+	}
+	else {	/* out */
+#if QL_TURBO_PDMA
+rtrc(4)
+		if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */
+			outsl(qbase + 4, request, 32 );
+			reqlen -= 128;
+			request += 128;
+		}
+		while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */
+			if( !((j=inb( qbase + 8 )) & 8) ) {
+				outsl( qbase + 4, request, 21 );
+				reqlen -= 84;
+				request += 84;
+			}
+		if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */
+			outsl( qbase + 4, request, 10 );
+			reqlen -= 40;
+			request += 40;
+		}
+#endif
+		/* until full and int (or until reclen is 0) */
+rtrc(7)
+		j = 0;
+		while( reqlen && !( (j & 2) && (j & 0xc0) ) ) {
+			/* while bytes to send and not full */
+			while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) {
+				outb(*request++, qbase + 4);
+				reqlen--;
+			}
+			if( j & 2 )
+				j = inb(qbase+8);
+		}
+	}
+/* maybe return reqlen */
+	return inb( qbase + 8 ) & 0xc0;
+}
+
+/*----------------------------------------------------------------*/
+/* wait for interrupt flag (polled - not real hardware interrupt) */
+static int	ql_wai(void)
+{
+int	i,k;
+	k = 0;
+	i = jiffies + WATCHDOG;
+	while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0))
+		barrier();
+	if (i <= jiffies)
+		return (DID_TIME_OUT);
+	if (qabort)
+		return (qabort == 1 ? DID_ABORT : DID_RESET);
+	if (k & 0x60)
+		ql_zap();
+	if (k & 0x20)
+		return (DID_PARITY);
+	if (k & 0x40)
+		return (DID_ERROR);
+	return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* initiate scsi command - queueing handler */
+static void	ql_icmd(Scsi_Cmnd * cmd)
+{
+unsigned int	    i;
+unsigned long	flags;
+
+	qabort = 0;
+
+	save_flags( flags );
+	cli();
+	REG0;
+/* clearing of interrupts and the fifo is needed */
+	inb(qbase + 5); 			/* clear interrupts */
+	if (inb(qbase + 5))			/* if still interrupting */
+		outb(2, qbase + 3);		/* reset chip */
+	else if (inb(qbase + 7) & 0x1f)
+		outb(1, qbase + 3);		/* clear fifo */
+	while (inb(qbase + 5)); 		/* clear ints */
+	REG1;
+	outb(1, qbase + 8);			/* set for PIO pseudo DMA */
+	outb(0, qbase + 0xb);			/* disable ints */
+	inb(qbase + 8); 			/* clear int bits */
+	REG0;
+	outb(0x40, qbase + 0xb);		/* enable features */
+
+/* configurables */
+	outb( qlcfgc , qbase + 0xc);
+/* config: no reset interrupt, (initiator) bus id */
+	outb( 0x40 | qlcfg8 | qinitid, qbase + 8);
+	outb( qlcfg7 , qbase + 7 );
+	outb( qlcfg6 , qbase + 6 );
+/**/
+	outb(qlcfg5, qbase + 5);		/* select timer */
+	outb(qlcfg9 & 7, qbase + 9);			/* prescaler */
+/*	outb(0x99, qbase + 5);	*/
+	outb(cmd->target, qbase + 4);
+
+	for (i = 0; i < cmd->cmd_len; i++)
+		outb(cmd->cmnd[i], qbase + 2);
+	qlcmd = cmd;
+	outb(0x41, qbase + 3);	/* select and send command */
+	restore_flags( flags );
+}
+/*----------------------------------------------------------------*/
+/* process scsi command - usually after interrupt */
+static unsigned int	ql_pcmd(Scsi_Cmnd * cmd)
+{
+unsigned int	i, j, k;
+unsigned int	result; 		/* ultimate return result */
+unsigned int	status; 		/* scsi returned status */
+unsigned int	message;		/* scsi returned message */
+unsigned int	phase;			/* recorded scsi phase */
+unsigned int	reqlen; 		/* total length of transfer */
+struct scatterlist	*sglist;	/* scatter-gather list pointer */
+unsigned int	sgcount;		/* sg counter */
+
+rtrc(1)
+	j = inb(qbase + 6);
+	i = inb(qbase + 5);
+	if (i == 0x20) {
+		return (DID_NO_CONNECT << 16);
+	}
+	i |= inb(qbase + 5);	/* the 0x10 bit can be set after the 0x08 */
+	if (i != 0x18) {
+		printk("Ql:Bad Interrupt status:%02x\n", i);
+		ql_zap();
+		return (DID_BAD_INTR << 16);
+	}
+	j &= 7; /* j = inb( qbase + 7 ) >> 5; */
+/* correct status is supposed to be step 4 */
+/* it sometimes returns step 3 but with 0 bytes left to send */
+/* We can try stuffing the FIFO with the max each time, but we will get a
+   sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
+	if(j != 3 && j != 4) {
+		printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );
+		ql_zap();
+		return (DID_ERROR << 16);
+	}
+	result = DID_OK;
+	if (inb(qbase + 7) & 0x1f)	/* if some bytes in fifo */
+		outb(1, qbase + 3);		/* clear fifo */
+/* note that request_bufflen is the total xfer size when sg is used */
+	reqlen = cmd->request_bufflen;
+/* note that it won't work if transfers > 16M are requested */
+	if (reqlen && !((phase = inb(qbase + 4)) & 6)) {	/* data phase */
+rtrc(2)
+		outb(reqlen, qbase);			/* low-mid xfer cnt */
+		outb(reqlen >> 8, qbase+1);			/* low-mid xfer cnt */
+		outb(reqlen >> 16, qbase + 0xe);	/* high xfer cnt */
+		outb(0x90, qbase + 3);			/* command do xfer */
+/* PIO pseudo DMA to buffer or sglist */
+		REG1;
+		if (!cmd->use_sg)
+			ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);
+		else {
+			sgcount = cmd->use_sg;
+			sglist = cmd->request_buffer;
+			while (sgcount--) {
+				if (qabort) {
+					REG0;
+					return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+				}
+				if (ql_pdma(phase, sglist->address, sglist->length))
+					break;
+				sglist++;
+			}
+		}
+		REG0;
+rtrc(2)
+/* wait for irq (split into second state of irq handler if this can take time) */
+		if ((k = ql_wai()))
+			return (k << 16);
+		k = inb(qbase + 5);	/* should be 0x10, bus service */
+	}
+/*** Enter Status (and Message In) Phase ***/
+	k = jiffies + WATCHDOG;
+	while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6));	/* wait for status phase */
+	if ( k <= jiffies ) {
+		ql_zap();
+		return (DID_TIME_OUT << 16);
+	}
+	while (inb(qbase + 5)); 				/* clear pending ints */
+	if (qabort)
+		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+	outb(0x11, qbase + 3);					/* get status and message */
+	if ((k = ql_wai()))
+		return (k << 16);
+	i = inb(qbase + 5);					/* get chip irq stat */
+	j = inb(qbase + 7) & 0x1f;				/* and bytes rec'd */
+	status = inb(qbase + 2);
+	message = inb(qbase + 2);
+/* should get function complete int if Status and message, else bus serv if only status */
+	if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
+		printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
+		result = DID_ERROR;
+	}
+	outb(0x12, qbase + 3);	/* done, disconnect */
+rtrc(1)
+	if ((k = ql_wai()))
+		return (k << 16);
+/* should get bus service interrupt and disconnect interrupt */
+	i = inb(qbase + 5);	/* should be bus service */
+	while (!qabort && ((i & 0x20) != 0x20)) {
+		barrier();
+		i |= inb(qbase + 5);
+	}
+rtrc(0)
+	if (qabort)
+		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+	return (result << 16) | (message << 8) | (status & STATUS_MASK);
+}
+
+#if QL_USE_IRQ
+/*----------------------------------------------------------------*/
+/* interrupt handler */
+static void	       ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
+{
+Scsi_Cmnd	   *icmd;
+	REG0;
+	if (!(inb(qbase + 4) & 0x80))	/* false alarm? */
+		return;
+	if (qlcmd == NULL) {		/* no command to process? */
+		int	i;
+		i = 16;
+		while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */
+		return;
+	}
+	icmd = qlcmd;
+	icmd->result = ql_pcmd(icmd);
+	qlcmd = NULL;
+/* if result is CHECK CONDITION done calls qcommand to request sense */
+	(icmd->scsi_done) (icmd);
+}
+#endif
+
+/*----------------------------------------------------------------*/
+/* global functions */
+/*----------------------------------------------------------------*/
+/* non queued command */
+#if QL_USE_IRQ
+static void	qlidone(Scsi_Cmnd * cmd) {};		/* null function */
+#endif
+
+/* command process */
+int	qlogicfas_command(Scsi_Cmnd * cmd)
+{
+int	k;
+#if QL_USE_IRQ
+	if (qlirq >= 0) {
+		qlogicfas_queuecommand(cmd, qlidone);
+		while (qlcmd != NULL);
+		return cmd->result;
+	}
+#endif
+/* non-irq version */
+	if (cmd->target == qinitid)
+		return (DID_BAD_TARGET << 16);
+	ql_icmd(cmd);
+	if ((k = ql_wai()))
+		return (k << 16);
+	return ql_pcmd(cmd);
+
+}
+
+#if QL_USE_IRQ
+/*----------------------------------------------------------------*/
+/* queued command */
+int	qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+	if(cmd->target == qinitid) {
+		cmd->result = DID_BAD_TARGET << 16;
+		done(cmd);
+		return 0;
+	}
+
+	cmd->scsi_done = done;
+/* wait for the last command's interrupt to finish */
+	while (qlcmd != NULL)
+		barrier();
+	ql_icmd(cmd);
+	return 0;
+}
+#else
+int	qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+	return 1;
+}
+#endif
+
+#ifdef PCMCIA
+/*----------------------------------------------------------------*/
+/* allow PCMCIA code to preset the port */
+/* port should be 0 and irq to -1 respectively for autoprobing */
+void	qlogicfas_preset(int port, int irq)
+{
+	qbase=port;
+	qlirq=irq;
+}
+#endif
+
+/*----------------------------------------------------------------*/
+/* look for qlogic card and init if found */
+int	qlogicfas_detect(Scsi_Host_Template * host)
+{
+int	i, j;			/* these are only used by IRQ detect */
+int	qltyp;			/* type of chip */
+struct	Scsi_Host	*hreg;	/* registered host structure */
+unsigned long	flags;
+
+host->proc_dir =  &proc_scsi_qlogicfas;
+
+/* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
+   address - I check 230 first since MIDI cards are typically at 330
+
+   Theoretically, two Qlogic cards can coexist in the same system.  This
+   should work by simply using this as a loadable module for the second
+   card, but I haven't tested this.
+*/
+
+	if( !qbase ) {
+		for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
+			if( check_region( qbase , 0x10 ) )
+				continue;
+			REG1;
+			if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
+			  && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
+				break;
+		}
+		if (qbase == 0x430)
+			return 0;
+	}
+	else
+		printk( "Ql: Using preset base address of %03x\n", qbase );
+
+	qltyp = inb(qbase + 0xe) & 0xf8;
+	qinitid = host->this_id;
+	if (qinitid < 0)
+		qinitid = 7;			/* if no ID, use 7 */
+	outb(1, qbase + 8);			/* set for PIO pseudo DMA */
+	REG0;
+	outb(0x40 | qlcfg8 | qinitid, qbase + 8);	/* (ini) bus id, disable scsi rst */
+	outb(qlcfg5, qbase + 5);		/* select timer */
+	outb(qlcfg9, qbase + 9);			/* prescaler */
+#if QL_RESET_AT_START
+	outb( 3 , qbase + 3 );
+	REG1;
+	while( inb( qbase + 0xf ) & 4 );
+	REG0;
+#endif
+#if QL_USE_IRQ
+/* IRQ probe - toggle pin and check request pending */
+
+	if( qlirq == -1 ) {
+		save_flags( flags );
+		cli();
+		i = 0xffff;
+		j = 3;
+		outb(0x90, qbase + 3);	/* illegal command - cause interrupt */
+		REG1;
+		outb(10, 0x20); /* access pending interrupt map */
+		outb(10, 0xa0);
+		while (j--) {
+			outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd);	/* int pin off */
+			i &= ~(inb(0x20) | (inb(0xa0) << 8));	/* find IRQ off */
+			outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd);	/* int pin on */
+			i &= inb(0x20) | (inb(0xa0) << 8);	/* find IRQ on */
+		}
+		REG0;
+		while (inb(qbase + 5)); 			/* purge int */
+		j = -1;
+		while (i)					/* find on bit */
+			i >>= 1, j++;	/* should check for exactly 1 on */
+		qlirq = j;
+		restore_flags( flags );
+	}
+	else
+		printk( "Ql: Using preset IRQ %d\n", qlirq );
+
+	if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL))
+		host->can_queue = 1;
+#endif
+	request_region( qbase , 0x10 ,"qlogic");
+	hreg = scsi_register( host , 0 );	/* no host data */
+	hreg->io_port = qbase;
+	hreg->n_io_port = 16;
+	hreg->dma_channel = -1;
+	if( qlirq != -1 )
+		hreg->irq = qlirq;
+
+	sprintf(qinfo, "Qlogicfas Driver version 0.44, chip %02X at %03X, IRQ %d, TPdma:%d",
+	    qltyp, qbase, qlirq, QL_TURBO_PDMA );
+	host->name = qinfo;
+
+	return 1;
+}
+
+/*----------------------------------------------------------------*/
+/* return bios parameters */
+int	qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[])
+{
+/* This should mimic the DOS Qlogic driver's behavior exactly */
+	ip[0] = 0x40;
+	ip[1] = 0x20;
+	ip[2] = disk->capacity / (ip[0] * ip[1]);
+	if (ip[2] > 1024) {
+		ip[0] = 0xff;
+		ip[1] = 0x3f;
+		ip[2] = disk->capacity / (ip[0] * ip[1]);
+		if (ip[2] > 1023)
+			ip[2] = 1023;
+	}
+	return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* abort command in progress */
+int	qlogicfas_abort(Scsi_Cmnd * cmd)
+{
+	qabort = 1;
+	ql_zap();
+	return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* reset SCSI bus */
+int	qlogicfas_reset(Scsi_Cmnd * cmd)
+{
+	qabort = 2;
+	ql_zap();
+	return 1;
+}
+
+/*----------------------------------------------------------------*/
+/* return info string */
+const char	*qlogicfas_info(struct Scsi_Host * host)
+{
+	return qinfo;
+}
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = QLOGICFAS;
+
+#include "scsi_module.c"
+#endif
+
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/qlogicfas.h linux/drivers/scsi/qlogicfas.h
--- pre2.0.5/linux/drivers/scsi/qlogicfas.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogicfas.h	Sat May 18 11:58:34 1996
@@ -0,0 +1,43 @@
+#ifndef _QLOGICFAS_H
+#define _QLOGICFAS_H
+
+int qlogicfas_detect(Scsi_Host_Template * );
+const char * qlogicfas_info(struct Scsi_Host *);
+int qlogicfas_command(Scsi_Cmnd *);
+int qlogicfas_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+int qlogicfas_abort(Scsi_Cmnd *);
+int qlogicfas_reset(Scsi_Cmnd *);
+int qlogicfas_biosparam(Disk *, kdev_t, int[]);
+
+#ifndef NULL
+#define NULL (0)
+#endif
+
+#define QLOGICFAS {		\
+	NULL,			\
+	NULL,			\
+	NULL,			\
+	NULL,		        \
+	NULL,			\
+	qlogicfas_detect,		\
+	NULL,			\
+	qlogicfas_info,		\
+	qlogicfas_command, 	\
+	qlogicfas_queuecommand,	\
+	qlogicfas_abort,		\
+	qlogicfas_reset,		\
+	NULL,			\
+	qlogicfas_biosparam,	\
+	0,			\
+	-1,			\
+	SG_ALL,			\
+	1,			\
+	0,			\
+	0,			\
+	DISABLE_CLUSTERING	\
+}
+
+#endif /* _QLOGICFAS_H */
+
+
+
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- pre2.0.5/linux/drivers/scsi/qlogicisp.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogicisp.c	Sun May 19 15:45:19 1996
@@ -0,0 +1,1599 @@
+/*
+ * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
+ * Written by Erik H. Moe, ehm@cris.com
+ * Copyright 1995, Erik H. Moe
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+/* Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> */
+
+/*
+ * $Date: 1995/09/22 02:23:15 $
+ * $Revision: 0.5 $
+ *
+ * $Log: isp1020.c,v $
+ * Revision 0.5  1995/09/22  02:23:15  root
+ * do auto request sense
+ *
+ * Revision 0.4  1995/08/07  04:44:33  root
+ * supply firmware with driver.
+ * numerous bug fixes/general cleanup of code.
+ *
+ * Revision 0.3  1995/07/16  16:15:39  root
+ * added reset/abort code.
+ *
+ * Revision 0.2  1995/06/29  03:14:19  root
+ * fixed biosparam.
+ * added queue protocol.
+ *
+ * Revision 0.1  1995/06/25  01:55:45  root
+ * Initial release.
+ *
+ */
+
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <unistd.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "sd.h"
+#include "hosts.h"
+#include "qlogicisp.h"
+
+/* Configuration section *****************************************************/
+
+/* Set the following macro to 1 to reload the ISP1020's firmware.  This is
+   the latest firmware provided by QLogic.  This may be an earlier/later
+   revision than supplied by your board. */
+
+#define RELOAD_FIRMWARE		1
+
+/* Set the following macro to 1 to reload the ISP1020's defaults from nvram.
+   If you are not sure of your settings, leave this alone, the driver will
+   use a set of 'safe' defaults */
+
+#define USE_NVRAM_DEFAULTS	0
+
+/*  Set this macro to 1 if you want to create a scsi loadable module. */
+
+#define MODULE			0
+
+/*  Macros used for debuging */
+
+#define DEBUG_ISP1020		0
+#define DEBUG_ISP1020_INT	0
+#define DEBUG_ISP1020_SETUP	0
+
+/* End Configuration section *************************************************/
+
+#include <linux/module.h>
+
+#if DEBUG_ISP1020
+#define ENTER(x)	printk("isp1020 : entering %s()\n", x);
+#define LEAVE(x)	printk("isp1020 : leaving %s()\n", x);
+#define DEBUG(x)	x
+#else
+#define ENTER(x)
+#define LEAVE(x)
+#define DEBUG(x)
+#endif /* DEBUG_ISP1020 */
+
+#if DEBUG_ISP1020_INTR
+#define ENTER_INTR(x)	printk("isp1020 : entering %s()\n", x);
+#define LEAVE_INTR(x)	printk("isp1020 : leaving %s()\n", x);
+#define DEBUG_INTR(x)	x
+#else
+#define ENTER_INTR(x)
+#define LEAVE_INTR(x)
+#define DEBUG_INTR(x)
+#endif /* DEBUG ISP1020_INTR */
+
+#define ISP1020_REV_ID	1
+
+/* host configuration and control registers */
+#define HOST_HCCR	0xc0	/* host command and control */
+
+/* pci bus interface registers */
+#define PCI_ID_LOW	0x00	/* vendor id */
+#define PCI_ID_HIGH	0x02	/* device id */
+#define ISP_CFG0	0x04	/* configuration register #0 */
+#define ISP_CFG1	0x08	/* configuration register #1 */
+#define PCI_INTF_CTL	0x08	/* pci interface control */
+#define PCI_INTF_STS	0x0a	/* pci interface status */
+#define PCI_SEMAPHORE	0x0c	/* pci semaphore */
+#define PCI_NVRAM	0x0e	/* pci nvram interface */
+
+/* mailbox registers */
+#define MBOX0		0x70	/* mailbox 0 */
+#define MBOX1		0x72	/* mailbox 1 */
+#define MBOX2		0x74	/* mailbox 2 */
+#define MBOX3		0x76	/* mailbox 3 */
+#define MBOX4		0x78	/* mailbox 4 */
+#define MBOX5		0x7a	/* mailbox 5 */
+
+/* mailbox command complete status codes */
+#define MBOX_COMMAND_COMPLETE		0x4000
+#define INVALID_COMMAND			0x4001
+#define HOST_INTERFACE_ERROR		0x4002
+#define TEST_FAILED			0x4003
+#define COMMAND_ERROR			0x4005
+#define COMMAND_PARAM_ERROR		0x4006
+
+/* async event status codes */
+#define ASYNC_SCSI_BUS_RESET		0x8001
+#define SYSTEM_ERROR			0x8002
+#define REQUEST_TRANSFER ERROR		0x8003
+#define RESPONSE_TRANSFER_ERROR		0x8004
+#define REQUEST_QUEUE_WAKEUP		0x8005
+#define EXECUTION_TIMEOUT_RESET		0x8006
+
+struct Entry_header {
+    u_char    entry_type;
+    u_char    entry_cnt;
+    u_char    sys_def_1;
+    u_char    flags;
+};
+
+/* entry header type commands */
+#define ENTRY_COMMAND		1
+#define ENTRY_CONTINUATION	2
+#define ENTRY_STATUS		3
+#define ENTRY_MARKER		4
+#define ENTRY_EXTENDED_COMMAND	5
+
+/* entry header flag definitions */
+#define EFLAG_CONTINUATION	1
+#define EFLAG_BUSY		2
+#define EFLAG_BAD_HEADER	4
+#define EFLAG_BAD_PAYLOAD	8
+
+struct dataseg {
+    caddr_t   d_base;
+    u_long    d_count;
+};
+
+struct Command_Entry {
+    struct    Entry_header    hdr;
+    caddr_t   handle;
+    u_char    target_lun;
+    u_char    target_id;
+    u_short   cdb_length;
+    u_short   control_flags;
+    u_short   rsvd;
+    u_short   time_out;
+    u_short   segment_cnt;
+    u_char    cdb[12];
+    struct    dataseg    dataseg0;
+    struct    dataseg    dataseg1;
+    struct    dataseg    dataseg2;
+    struct    dataseg    dataseg3;
+};
+
+/* command entry control flag definitions */
+#define CFLAG_NODISC		0x01
+#define CFLAG_HEAD_TAG		0x02
+#define CFLAG_ORDERED_TAG	0x04
+#define CFLAG_SIMPLE_TAG	0x08
+#define CFLAG_TAR_RTN		0x10
+#define CFLAG_READ		0x20
+#define CFLAG_WRITE		0x40
+
+struct Ext_Command_Entry {
+    struct    Entry_header    hdr;
+    caddr_t   handle;
+    u_char    target_lun;
+    u_char    target_id;
+    u_short   cdb_length;
+    u_short   control_flags;
+    u_short   rsvd;
+    u_short   time_out;
+    u_short   segment_cnt;
+    u_char    cdb[44];
+};
+
+struct Continuation_Entry {
+    struct    Entry_header    hdr;
+    u_long    reserved;
+    struct    dataseg    dataseg0;
+    struct    dataseg    dataseg1;
+    struct    dataseg    dataseg2;
+    struct    dataseg    dataseg3;
+    struct    dataseg    dataseg4;
+    struct    dataseg    dataseg5;
+    struct    dataseg    dataseg6;
+};
+
+struct Marker_Entry {
+    struct    Entry_header    hdr;
+    caddr_t   reserved;
+    u_char    target_lun;
+    u_char    target_id;
+    u_char    modifier;
+    u_char    rsvd;
+    u_char    rsvds[52];
+};
+
+/* marker entry modifier definitions */
+#define SYNC_DEVICE	0
+#define SYNC_TARGET	1
+#define SYNC_ALL	2
+
+struct Status_Entry {
+    struct    Entry_header    hdr;
+    caddr_t   handle;
+    u_short   scsi_status;
+    u_short   completion_status;
+    u_short   state_flags;
+    u_short   status_flags;
+    u_short   time;
+    u_short   req_sense_len;
+    u_long    residual;
+    u_char    rsvd[8];
+    u_char    req_sense_data[32];
+};
+
+/* status entry completion status definitions */
+#define CS_COMPLETE			0x0000
+#define CS_INCOMPLETE			0x0001
+#define CS_DMA_ERROR			0x0002
+#define CS_TRANSPORT_ERROR		0x0003
+#define CS_RESET_OCCURRED		0x0004
+#define CS_ABORTED			0x0005
+#define CS_TIMEOUT			0x0006
+#define CS_DATA_OVERRUN			0x0007
+#define CS_COMMAND_OVERRUN		0x0008
+#define CS_STATUS_OVERRUN		0x0009
+#define CS_BAD_MESSAGE			0x000a
+#define CS_NO_MESSAGE_OUT		0x000b
+#define CS_EXT_ID_FAILED		0x000c
+#define CS_IDE_MSG_FAILED		0x000d
+#define CS_ABORT_MSG_FAILED		0x000e
+#define CS_REJECT_MSG_FAILED		0x000f
+#define CS_NOP_MSG_FAILED		0x0010
+#define CS_PARITY_ERROR_MSG_FAILED	0x0011
+#define CS_DEVICE_RESET_MSG_FAILED	0x0012
+#define CS_ID_MSG_FAILED		0x0013
+#define CS_UNEXP_BUS_FREE		0x0014
+#define CS_DATA_UNDERRUN		0x0015
+
+/* status entry state flag definitions */
+#define SF_GOT_BUS			0x0100
+#define SF_GOT_TARGET			0x0200
+#define SF_SENT_CDB			0x0400
+#define SF_TRANSFERRED_DATA		0x0800
+#define SF_GOT_STATUS			0x1000
+#define SF_GOT_SENSE			0x2000
+
+/* status entry status flag definitions */
+#define STF_DISCONNECT			0x0001
+#define STF_SYNCHRONOUS			0x0002
+#define STF_PARITY_ERROR		0x0004
+#define STF_BUS_RESET			0x0008
+#define STF_DEVICE_RESET		0x0010
+#define STF_ABORTED			0x0020
+#define STF_TIMEOUT			0x0040
+#define STF_NEGOTIATION			0x0080
+
+/* host control commands */
+#define HCCR_NOP			0x0000
+#define HCCR_RESET			0x1000
+#define HCCR_PAUSE			0x2000
+#define HCCR_RELEASE			0x3000
+#define HCCR_SINGLE_STEP		0x4000
+#define HCCR_SET_HOST_INTR		0x5000
+#define HCCR_CLEAR_HOST_INTR		0x6000
+#define HCCR_CLEAR_RISC_INTR		0x7000
+#define HCCR_BP_ENABLE			0x8000
+#define HCCR_BIOS_ENABLE		0x9000
+#define HCCR_TEST_MODE			0xf000
+
+/* mailbox commands */
+#define MBOX_NO_OP			0x0000
+#define MBOX_LOAD_RAM			0x0001
+#define MBOX_EXEC_FIRMWARE		0x0002
+#define MBOX_DUMP_RAM			0x0003
+#define MBOX_WRITE_RAM_WORD		0x0004
+#define MBOX_READ_RAM_WORD		0x0005
+#define MBOX_MAILBOX_REG_TEST		0x0006
+#define MBOX_VERIFY_CHECKSUM		0x0007
+#define MBOX_ABOUT_FIRMWARE		0x0008
+#define MBOX_CHECK_FIRMWARE		0x000e
+#define MBOX_INIT_REQ_QUEUE		0x0010
+#define MBOX_INIT_RES_QUEUE		0x0011
+#define MBOX_EXECUTE_IOCB		0x0012
+#define MBOX_WAKE_UP			0x0013
+#define MBOX_STOP_FIRMWARE		0x0014
+#define MBOX_ABORT			0x0015
+#define MBOX_ABORT_DEVICE		0x0016
+#define MBOX_ABORT_TARGET		0x0017
+#define MBOX_BUS_RESET			0x0018
+#define MBOX_STOP_QUEUE			0x0019
+#define MBOX_START_QUEUE		0x001a
+#define MBOX_SINGLE_STEP_QUEUE		0x001b
+#define MBOX_ABORT_QUEUE		0x001c
+#define MBOX_GET_DEV_QUEUE_STATUS	0x001d
+#define MBOX_GET_FIRMWARE_STATUS	0x001f
+#define MBOX_GET_INIT_SCSI_ID		0x0020
+#define MBOX_GET_SELECT_TIMEOUT		0x0021
+#define MBOX_GET_RETRY_COUNT		0x0022
+#define MBOX_GET_TAG_AGE_LIMIT		0x0023
+#define MBOX_GET_CLOCK_RATE		0x0024
+#define MBOX_GET_ACT_NEG_STATE		0x0025
+#define MBOX_GET_ASYNC_DATA_SETUP_TIME	0x0026
+#define MBOX_GET_PCI_PARAMS		0x0027
+#define MBOX_GET_TARGET_PARAMS		0x0028
+#define MBOX_GET_DEV_QUEUE_PARAMS	0x0029
+#define MBOX_SET_INIT_SCSI_ID		0x0030
+#define MBOX_SET_SELECT_TIMEOUT		0x0031
+#define MBOX_SET_RETRY_COUNT		0x0032
+#define MBOX_SET_TAG_AGE_LIMIT		0x0033
+#define MBOX_SET_CLOCK_RATE		0x0034
+#define MBOX_SET_ACTIVE_NEG_STATE	0x0035
+#define MBOX_SET_ASYNC_DATA_SETUP_TIME	0x0036
+#define MBOX_SET_PCI_CONTROL_PARAMS	0x0037
+#define MBOX_SET_TARGET_PARAMS		0x0038
+#define MBOX_SET_DEV_QUEUE_PARAMS	0x0039
+#define MBOX_RETURN_BIOS_BLOCK_ADDR	0x0040
+#define MBOX_WRITE_FOUR_RAM_WORDS	0x0041
+#define MBOX_EXEC_BIOS_IOCB		0x0042
+
+#include "qlogicisp_asm.c"
+
+#define PACKB(a, b)			(((a)<<4)|(b))
+
+u_char mbox_param[] = {
+    PACKB(1, 1),	/* MBOX_NO_OP */
+    PACKB(5, 5),	/* MBOX_LOAD_RAM */
+    PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
+    PACKB(5, 5),	/* MBOX_DUMP_RAM */
+    PACKB(3, 3),	/* MBOX_WRITE_RAM_WORD */
+    PACKB(2, 3),	/* MBOX_READ_RAM_WORD */
+    PACKB(6, 6),	/* MBOX_MAILBOX_REG_TEST */
+    PACKB(2, 3),	/* MBOX_VERIFY_CHECKSUM	*/
+    PACKB(1, 3),	/* MBOX_ABOUT_FIRMWARE */
+    PACKB(0, 0),	/* 0x0009 */
+    PACKB(0, 0),	/* 0x000a */
+    PACKB(0, 0),	/* 0x000b */
+    PACKB(0, 0),	/* 0x000c */
+    PACKB(0, 0),	/* 0x000d */
+    PACKB(1, 2),	/* MBOX_CHECK_FIRMWARE */
+    PACKB(0, 0),	/* 0x000f */
+    PACKB(5, 5),	/* MBOX_INIT_REQ_QUEUE */
+    PACKB(6, 6),	/* MBOX_INIT_RES_QUEUE */
+    PACKB(4, 4),	/* MBOX_EXECUTE_IOCB */
+    PACKB(2, 2),	/* MBOX_WAKE_UP	*/
+    PACKB(1, 6),	/* MBOX_STOP_FIRMWARE */
+    PACKB(4, 4),	/* MBOX_ABORT */
+    PACKB(2, 2),	/* MBOX_ABORT_DEVICE */
+    PACKB(3, 3),	/* MBOX_ABORT_TARGET */
+    PACKB(2, 2),	/* MBOX_BUS_RESET */
+    PACKB(2, 3),	/* MBOX_STOP_QUEUE */
+    PACKB(2, 3),	/* MBOX_START_QUEUE */
+    PACKB(2, 3),	/* MBOX_SINGLE_STEP_QUEUE */
+    PACKB(2, 3),	/* MBOX_ABORT_QUEUE */
+    PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_STATUS */
+    PACKB(0, 0),	/* 0x001e */
+    PACKB(1, 3),	/* MBOX_GET_FIRMWARE_STATUS */
+    PACKB(1, 2),	/* MBOX_GET_INIT_SCSI_ID */
+    PACKB(1, 2),	/* MBOX_GET_SELECT_TIMEOUT */
+    PACKB(1, 3),	/* MBOX_GET_RETRY_COUNT	*/
+    PACKB(1, 2),	/* MBOX_GET_TAG_AGE_LIMIT */
+    PACKB(1, 2),	/* MBOX_GET_CLOCK_RATE */
+    PACKB(1, 2),	/* MBOX_GET_ACT_NEG_STATE */
+    PACKB(1, 2),	/* MBOX_GET_ASYNC_DATA_SETUP_TIME */
+    PACKB(1, 3),	/* MBOX_GET_PCI_PARAMS */
+    PACKB(2, 4),	/* MBOX_GET_TARGET_PARAMS */
+    PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_PARAMS */
+    PACKB(0, 0),	/* 0x002a */
+    PACKB(0, 0),	/* 0x002b */
+    PACKB(0, 0),	/* 0x002c */
+    PACKB(0, 0),	/* 0x002d */
+    PACKB(0, 0),	/* 0x002e */
+    PACKB(0, 0),	/* 0x002f */
+    PACKB(2, 2),	/* MBOX_SET_INIT_SCSI_ID */
+    PACKB(2, 2),	/* MBOX_SET_SELECT_TIMEOUT */
+    PACKB(3, 3),	/* MBOX_SET_RETRY_COUNT	*/
+    PACKB(2, 2),	/* MBOX_SET_TAG_AGE_LIMIT */
+    PACKB(2, 2),	/* MBOX_SET_CLOCK_RATE */
+    PACKB(2, 2),	/* MBOX_SET_ACTIVE_NEG_STATE */
+    PACKB(2, 2),	/* MBOX_SET_ASYNC_DATA_SETUP_TIME */
+    PACKB(3, 3),	/* MBOX_SET_PCI_CONTROL_PARAMS */
+    PACKB(4, 4),	/* MBOX_SET_TARGET_PARAMS */
+    PACKB(4, 4),	/* MBOX_SET_DEV_QUEUE_PARAMS */
+    PACKB(0, 0),	/* 0x003a */
+    PACKB(0, 0),	/* 0x003b */
+    PACKB(0, 0),	/* 0x003c */
+    PACKB(0, 0),	/* 0x003d */
+    PACKB(0, 0),	/* 0x003e */
+    PACKB(0, 0),	/* 0x003f */
+    PACKB(1, 2),	/* MBOX_RETURN_BIOS_BLOCK_ADDR */
+    PACKB(6, 1),	/* MBOX_WRITE_FOUR_RAM_WORDS */
+    PACKB(2, 3)		/* MBOX_EXEC_BIOS_IOCB */
+};
+
+#define MAX_MBOX_COMMAND	(sizeof(mbox_param)/sizeof(u_short))
+
+struct host_param {
+    u_short    fifo_threshold;
+    u_short    host_adapter_enable;
+    u_short    initiator_scsi_id;
+    u_short    bus_reset_delay;
+    u_short    retry_count;
+    u_short    retry_delay;
+    u_short    async_data_setup_time;
+    u_short    req_ack_active_negation;
+    u_short    data_line_active_negation;
+    u_short    data_dma_burst_enable;
+    u_short    command_dma_burst_enable;
+    u_short    tag_aging;
+    u_short    selection_timeout;
+    u_short    max_queue_depth;
+};
+
+/*
+ * Device Flags:
+ *
+ * Bit  Name
+ * ---------
+ *  7   Disconnect Privilege
+ *  6   Parity Checking
+ *  5   Wide Data Transfers
+ *  4   Syncronous Data Transfers
+ *  3   Tagged Queuing
+ *  2   Automatic Request Sense
+ *  1   Stop Queue on Check Condition
+ *  0   Renegotiate on Error
+ */
+
+struct dev_param {
+    u_short    device_flags;
+    u_short    execution_throttle;
+    u_short    synchronous_period;
+    u_short    synchronous_offset;
+    u_short    device_enable;
+};
+
+#define REQ_QUEUE_LEN		32
+#define RES_QUEUE_LEN		32
+#define QUEUE_ENTRY_LEN		64
+
+struct isp1020_hostdata {
+    u_char    irq;
+    u_char    bus;
+    u_long    io_base;
+    u_char    revision;
+    u_char    device_fn;
+    u_short   res_queue_in_ptr;
+    u_short   res_queue_out_ptr;
+    u_short   req_queue_in_ptr;
+    u_short   req_queue_out_ptr;
+    struct    host_param host_param;
+    struct    dev_param dev_param[16];
+    char      res_queue[RES_QUEUE_LEN][QUEUE_ENTRY_LEN];
+    char      req_queue[REQ_QUEUE_LEN][QUEUE_ENTRY_LEN];
+};
+
+struct isp1020_hostdata *irq2host[16];
+
+void isp1020_enable_irqs(struct isp1020_hostdata *);
+void isp1020_disable_irqs(struct isp1020_hostdata *);
+int isp1020_init(struct Scsi_Host *);
+int isp1020_reset_hardware(struct isp1020_hostdata *);
+int isp1020_get_defaults(struct isp1020_hostdata *);
+int isp1020_set_defaults(struct isp1020_hostdata *);
+int isp1020_load_parameters(struct isp1020_hostdata *);
+int isp1020_mbox_command(struct isp1020_hostdata *, u_short []); 
+u_short isp1020_read_nvram_word(struct isp1020_hostdata *, u_short);
+int isp1020_verify_nvram(struct isp1020_hostdata *);
+void isp1020_print_status_entry(struct Status_Entry *);
+void isp1020_print_scsi_cmd(Scsi_Cmnd *);
+void isp1020_scsi_done(Scsi_Cmnd *);
+int isp1020_return_status(struct Status_Entry *);
+void isp1020_intr_handler(int, struct pt_regs *);
+
+
+int isp1020_detect(Scsi_Host_Template *tmpt)
+{
+    int hosts = 0;
+    u_short index;
+    u_char bus, device_fn;
+    struct Scsi_Host *scsihost;
+    struct isp1020_hostdata *hostdata;
+
+    ENTER("isp1020_detect");
+
+    if (pcibios_present() == 0) {
+        printk("qlogicisp : PCI bios not present\n");
+        return 0;
+    }
+
+    memset(irq2host, 0, sizeof(irq2host));
+
+    for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC,
+            PCI_DEVICE_ID_QLOGIC_ISP1020, index, &bus, &device_fn) == 0;
+                index++) {
+
+        scsihost = scsi_register(tmpt, sizeof(struct isp1020_hostdata));
+        hostdata = (struct isp1020_hostdata *) scsihost->hostdata;
+
+        memset(hostdata, 0, sizeof(struct isp1020_hostdata));
+        hostdata->bus = bus;
+        hostdata->device_fn = device_fn;
+
+        if (isp1020_init(scsihost) || isp1020_reset_hardware(hostdata)
+#if USE_NVRAM_DEFAULTS
+                || isp1020_get_defaults(hostdata)
+#else
+                || isp1020_set_defaults(hostdata)
+#endif /* USE_NVRAM_DEFAULTS */
+                || isp1020_load_parameters(hostdata)) {
+            scsi_unregister(scsihost);
+            continue;
+        }
+
+        scsihost->this_id = hostdata->host_param.initiator_scsi_id;
+
+        if (request_irq(hostdata->irq, isp1020_intr_handler, 0,
+                "qlogicisp", NULL)) {
+            printk("qlogicisp : interrupt %d already in use\n", hostdata->irq);
+            scsi_unregister(scsihost);
+            continue;
+        }
+
+        if (check_region(hostdata->io_base, 0xff)) {
+            printk("qlogicisp : i/o region 0x%04lx-0x%04lx already in use\n",
+                hostdata->io_base, hostdata->io_base + 0xff);
+            free_irq(hostdata->irq, NULL);
+            scsi_unregister(scsihost);
+            continue;
+        }
+
+        request_region(hostdata->io_base, 0xff, "qlogicisp");
+        irq2host[hostdata->irq] = hostdata;
+
+        isp1020_enable_irqs(hostdata);
+
+        hosts++;
+    }
+
+    LEAVE("isp1020_detect");
+
+    return hosts;
+}
+
+
+int isp1020_release(struct Scsi_Host *host)
+{
+    struct isp1020_hostdata *hostdata;
+
+    ENTER("isp1020_release");
+
+    hostdata = (struct isp1020_hostdata *) host->hostdata;
+
+    outw(0x0, hostdata->io_base + PCI_INTF_CTL);
+    free_irq(hostdata->irq, NULL);
+
+    release_region(hostdata->io_base, 0xff);
+
+    LEAVE("isp1020_release");
+
+    return 0;
+}
+
+
+const char *isp1020_info(struct Scsi_Host *host)
+{
+    static char buf[80];
+    struct isp1020_hostdata *hostdata;
+
+    ENTER("isp1020_info");
+
+    hostdata = (struct isp1020_hostdata *) host->hostdata;
+    sprintf(buf, "QLogic ISP1020 SCSI on PCI bus %d, device %d, irq %d",
+        hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, hostdata->irq);
+
+    LEAVE("isp1020_info");
+
+    return buf;
+}
+
+
+#define REQ_QUEUE_DEPTH() \
+    (hostdata->req_queue_in_ptr >= hostdata->req_queue_out_ptr \
+        ? hostdata->req_queue_in_ptr - hostdata->req_queue_out_ptr \
+        : (REQ_QUEUE_LEN - hostdata->req_queue_out_ptr) \
+        + hostdata->req_queue_in_ptr)
+    
+
+int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
+{
+    int i, *iptr, sg_count;
+    struct scatterlist *sg;
+    struct Command_Entry *cmd;
+    struct isp1020_hostdata *hostdata;
+
+    ENTER("isp1020_queuecommand");
+
+    hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata;
+    Cmnd->scsi_done = done;
+
+    DEBUG(isp1020_print_scsi_cmd(Cmnd);)
+
+    hostdata->req_queue_out_ptr = inw(hostdata->io_base + MBOX4);
+
+    if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN ==
+            hostdata->req_queue_out_ptr) {
+        printk("qlogicisp : request queue overflow\n");
+        return 1;
+    }
+
+    DEBUG(printk("qlogicisp : request queue depth %d\n", REQ_QUEUE_DEPTH()));
+
+    cmd = (struct Command_Entry *)
+        &hostdata->req_queue[hostdata->req_queue_in_ptr][0];
+
+    memset(cmd, 0, sizeof(struct Command_Entry));
+
+    cmd->hdr.entry_type = ENTRY_COMMAND;
+    cmd->hdr.entry_cnt = 1;
+
+    cmd->handle = (caddr_t) Cmnd;
+    cmd->target_lun = Cmnd->lun;
+    cmd->target_id = Cmnd->target;
+    cmd->cdb_length = Cmnd->cmd_len;
+    cmd->control_flags = CFLAG_READ | CFLAG_WRITE;
+
+    for (i = 0; i < Cmnd->cmd_len; i++)
+        cmd->cdb[i] = Cmnd->cmnd[i];
+
+    if (Cmnd->use_sg) {
+        cmd->segment_cnt = sg_count = Cmnd->use_sg;
+        sg = (struct scatterlist *) Cmnd->request_buffer;
+        iptr = (int *) &cmd->dataseg0.d_base;
+
+        for (i = 0; sg_count > 0; sg_count--, i++) {
+            *iptr++ = (int) sg[i].address;
+            *iptr++ = sg[i].length;
+        }
+    }
+    else {
+        cmd->dataseg0.d_base = (caddr_t) Cmnd->request_buffer;
+        cmd->dataseg0.d_count = (u_long) Cmnd->request_bufflen;
+        cmd->segment_cnt = 1;
+    }
+
+    hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1)
+        % REQ_QUEUE_LEN;
+
+    outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4);
+
+    LEAVE("isp1020_queuecommand");
+
+    return 0;
+}
+
+
+#define RES_QUEUE_DEPTH() \
+    (hostdata->res_queue_in_ptr >= hostdata->res_queue_out_ptr \
+        ? hostdata->res_queue_in_ptr - hostdata->res_queue_out_ptr \
+        : (RES_QUEUE_LEN - hostdata->res_queue_out_ptr) \
+        + hostdata->res_queue_in_ptr)
+ 
+
+int isp1020_abort(Scsi_Cmnd *Cmnd)
+{
+    u_short param[6];
+    struct isp1020_hostdata *hostdata;
+    int return_status = SCSI_ABORT_SUCCESS;
+
+    ENTER("isp1020_abort");
+
+    hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata;
+
+    isp1020_disable_irqs(hostdata);
+
+    DEBUG(printk("qlogicisp : response queue depth %d\n", RES_QUEUE_DEPTH()));
+
+    param[0] = MBOX_ABORT;
+    param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;
+    param[2] = (u_long) Cmnd >> 16;
+    param[3] = (u_long) Cmnd & 0xffff;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : scsi abort failure: %x\n", param[0]);
+        return_status = SCSI_ABORT_ERROR;
+    }
+
+    isp1020_enable_irqs(hostdata);
+
+    LEAVE("isp1020_abort");
+
+    return return_status;
+}
+
+
+int isp1020_reset(Scsi_Cmnd *Cmnd)
+{
+    u_short param[6];
+    struct isp1020_hostdata *hostdata;
+    int return_status = SCSI_RESET_SUCCESS;
+
+    ENTER("isp1020_reset");
+
+    hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata;
+
+    param[0] = MBOX_BUS_RESET;
+    param[1] = hostdata->host_param.bus_reset_delay;
+
+    isp1020_disable_irqs(hostdata);
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : scsi bus reset failure: %x\n", param[0]);
+        return_status = SCSI_RESET_ERROR;
+    }
+	
+    isp1020_enable_irqs(hostdata);
+
+    LEAVE("isp1020_reset");
+
+    return SCSI_RESET_SUCCESS;
+}
+
+
+int isp1020_biosparam(Disk *disk, int n, int ip[])
+{
+    int size = disk->capacity;
+
+    ENTER("isp1020_biosparam");
+
+    ip[0] = 64;
+    ip[1] = 32;
+    ip[2] = size >> 11;
+    if (ip[2] > 1024) {
+        ip[0] = 255;
+        ip[1] = 63;
+        ip[2] = size / (ip[0] * ip[1]);
+        if (ip[2] > 1023)
+            ip[2] = 1023;
+    }
+
+    LEAVE("isp1020_biosparam");
+
+    return 0;
+}
+
+
+int isp1020_reset_hardware(struct isp1020_hostdata *hostdata)
+{
+    u_short param[6];
+
+    ENTER("isp1020_reset_hardware");
+
+    outw(0x0001, hostdata->io_base + PCI_INTF_CTL);
+    outw(HCCR_RESET, hostdata->io_base + HOST_HCCR);
+    outw(HCCR_RELEASE, hostdata->io_base + HOST_HCCR);
+    outw(HCCR_BIOS_ENABLE, hostdata->io_base + HOST_HCCR);
+
+    while (inw(hostdata->io_base + MBOX0))
+        barrier();
+
+#if DEBUG_ISP1020
+    printk("qlogicisp : mbox 0 0x%04x \n", inw(hostdata->io_base + MBOX0));
+    printk("qlogicisp : mbox 1 0x%04x \n", inw(hostdata->io_base + MBOX1));
+    printk("qlogicisp : mbox 2 0x%04x \n", inw(hostdata->io_base + MBOX2));
+    printk("qlogicisp : mbox 3 0x%04x \n", inw(hostdata->io_base + MBOX3));
+    printk("qlogicisp : mbox 4 0x%04x \n", inw(hostdata->io_base + MBOX4));
+    printk("qlogicisp : mbox 5 0x%04x \n", inw(hostdata->io_base + MBOX5));
+#endif /* DEBUG_ISP1020 */
+
+    DEBUG(printk("qlogicisp : loading risc ram\n");)
+
+#if RELOAD_FIRMWARE
+    { int i;
+        for (i = 0; i < risc_code_length01; i++) {
+            param[0] = MBOX_WRITE_RAM_WORD;
+            param[1] = risc_code_addr01 + i;
+            param[2] = risc_code01[i];
+
+            isp1020_mbox_command(hostdata, param);
+
+            if (param[0] != MBOX_COMMAND_COMPLETE) {
+                printk("qlogicisp : firmware load failure\n");
+                return 1;
+            }
+        }
+    }
+#endif /* RELOAD_FIRMEARE */
+
+    DEBUG(printk("qlogicisp : verifing checksum\n");)
+
+    param[0] = MBOX_VERIFY_CHECKSUM;
+    param[1] = risc_code_addr01;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : ram checksum failure\n");
+        return 1;
+    }
+
+    DEBUG(printk("qlogicisp : executing firmware\n");)
+
+    param[0] = MBOX_EXEC_FIRMWARE;
+    param[1] = risc_code_addr01;
+
+    isp1020_mbox_command(hostdata, param);
+
+    param[0] = MBOX_ABOUT_FIRMWARE;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : about firmware failure\n");
+        return 1;
+    }
+
+    DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1]);)
+    DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2]);)
+
+    LEAVE("isp1020_reset_hardware");
+
+    return 0;
+}
+
+
+int isp1020_init(struct Scsi_Host *sh)
+{
+    u_long io_base;
+    struct isp1020_hostdata *hostdata;
+    u_char bus, device_fn, revision, irq;
+    u_short vendor_id, device_id, command;
+
+    ENTER("isp1020_init");
+
+    hostdata = (struct isp1020_hostdata *) sh->hostdata;
+    bus = hostdata->bus;
+    device_fn = hostdata->device_fn;
+
+    if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id)
+            || pcibios_read_config_word(bus, device_fn,
+                PCI_DEVICE_ID, &device_id)
+            || pcibios_read_config_word(bus, device_fn,
+                PCI_COMMAND, &command)
+            || pcibios_read_config_dword(bus, device_fn,
+                PCI_BASE_ADDRESS_0, &io_base)
+	    || pcibios_read_config_byte(bus, device_fn,
+                PCI_CLASS_REVISION, &revision)
+            || pcibios_read_config_byte(bus, device_fn,
+                PCI_INTERRUPT_LINE, &irq)) {
+        printk("qlogicisp : error reading PCI configuration\n");
+        return 1;
+    }
+
+    if (vendor_id != PCI_VENDOR_ID_QLOGIC) {
+        printk("qlogicisp : 0x%04x is not QLogic vendor ID\n", vendor_id);
+        return 1;
+    }
+
+    if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) {
+        printk("qlogicisp : 0x%04x does not match ISP1020 device id\n",
+            device_id);
+        return 1;
+    }
+
+    if (command & PCI_COMMAND_IO && (io_base & 3) == 1)
+        io_base &= PCI_BASE_ADDRESS_IO_MASK;
+    else {
+        printk("qlogicisp : i/o mapping is disabled\n");
+        return 1;
+    }
+
+    if (!(command & PCI_COMMAND_MASTER)) {
+        printk("qlogicisp : bus mastering is disabled\n");
+        return 1;
+    }
+
+    if (revision != ISP1020_REV_ID)
+       printk("qlogicisp : warning : new isp1020 revision id\n");
+
+    if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
+            || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) {
+        printk("qlogicisp : can't decode i/o address space\n");
+        return 1;
+    }
+
+    hostdata->io_base = io_base;
+    hostdata->revision = revision;
+    hostdata->irq = irq;
+
+    LEAVE("isp1020_init");
+
+    return 0;
+}
+
+
+int isp1020_get_defaults(struct isp1020_hostdata *hostdata)
+{
+    int i;
+    u_short value;
+
+    ENTER("isp1020_get_defaults");
+
+    if (!isp1020_verify_nvram(hostdata)) {
+        printk("qlogicisp : nvram checksum failure\n");
+        return 1;
+    }
+
+    value = isp1020_read_nvram_word(hostdata, 2);
+    hostdata->host_param.fifo_threshold = (value >> 8) & 0x03;
+    hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01;
+    hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f;
+
+    value = isp1020_read_nvram_word(hostdata, 3);
+    hostdata->host_param.bus_reset_delay = value & 0xff;
+    hostdata->host_param.retry_count = value >> 8;
+
+    value = isp1020_read_nvram_word(hostdata, 4);
+    hostdata->host_param.retry_delay = value & 0xff;
+    hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f;
+    hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01;
+    hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01;
+    hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01;
+    hostdata->host_param.command_dma_burst_enable = (value >> 15);
+
+    value = isp1020_read_nvram_word(hostdata, 5);
+    hostdata->host_param.tag_aging = value & 0xff;
+
+    value = isp1020_read_nvram_word(hostdata, 6);
+    hostdata->host_param.selection_timeout = value & 0xffff;
+
+    value = isp1020_read_nvram_word(hostdata, 7);
+    hostdata->host_param.max_queue_depth = value & 0xffff;
+
+#if DEBUG_ISP1020_SETUP
+    printk("qlogicisp : fifo threshold=%d\n",
+        hostdata->host_param.fifo_threshold);
+    printk("qlogicisp : initiator scsi id=%d\n",
+        hostdata->host_param.initiator_scsi_id);
+    printk("qlogicisp : bus reset delay=%d\n",
+        hostdata->host_param.bus_reset_delay);
+    printk("qlogicisp : retry count=%d\n",
+	hostdata->host_param.retry_count);
+    printk("qlogicisp : retry delay=%d\n",
+        hostdata->host_param.retry_delay);
+    printk("qlogicisp : async data setup time=%d\n",
+        hostdata->host_param.async_data_setup_time);
+    printk("qlogicisp : req/ack active negation=%d\n",
+        hostdata->host_param.req_ack_active_negation);
+    printk("qlogicisp : data line active negation=%d\n",
+        hostdata->host_param.data_line_active_negation);
+    printk("qlogicisp : data DMA burst enable=%d\n",
+        hostdata->host_param.data_dma_burst_enable);
+    printk("qlogicisp : command DMA burst enable=%d\n",
+        hostdata->host_param.command_dma_burst_enable);
+    printk("qlogicisp : tag age limit=%d\n",
+        hostdata->host_param.tag_aging);
+    printk("qlogicisp : selection timeout limit=%d\n",
+        hostdata->host_param.selection_timeout);
+    printk("qlogicisp : max queue depth=%d\n",
+        hostdata->host_param.max_queue_depth);
+#endif /* DEBUG_ISP1020_SETUP */
+
+    for (i = 0; i < 16; i++) {
+
+        value = isp1020_read_nvram_word(hostdata, 14 + i * 3);
+        hostdata->dev_param[i].device_flags = value & 0xff;
+        hostdata->dev_param[i].execution_throttle = value >> 8;
+
+        value = isp1020_read_nvram_word(hostdata, 15 + i * 3);
+        hostdata->dev_param[i].synchronous_period = value & 0xff;
+        hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f;
+        hostdata->dev_param[i].device_enable = (value >> 12) & 0x01;
+
+#if DEBUG_ISP1020_SETUP
+        printk("qlogicisp : target 0x%02x\n", i);
+        printk("qlogicisp :     device flags=0x%02x\n",
+            hostdata->dev_param[i].device_flags);
+        printk("qlogicisp :     execution throttle=%d\n",
+            hostdata->dev_param[i].execution_throttle);
+        printk("qlogicisp :     synchronous period=%d\n",
+            hostdata->dev_param[i].synchronous_period);
+        printk("qlogicisp :     synchronous offset=%d\n",
+            hostdata->dev_param[i].synchronous_offset);
+        printk("qlogicisp :     device enable=%d\n",
+            hostdata->dev_param[i].device_enable);
+#endif /* DEBUG_ISP1020_SETUP */
+    }
+
+    LEAVE("isp1020_get_defaults");
+
+    return 0;
+}
+
+
+int isp1020_set_defaults(struct isp1020_hostdata *hostdata)
+{
+    int i;
+
+    ENTER("isp1020_set_defaults");
+
+    hostdata->host_param.fifo_threshold = 2;
+    hostdata->host_param.host_adapter_enable = 1;
+    hostdata->host_param.initiator_scsi_id = 7;
+    hostdata->host_param.bus_reset_delay = 3;
+    hostdata->host_param.retry_count = 0;
+    hostdata->host_param.retry_delay = 0;
+    hostdata->host_param.async_data_setup_time = 6;
+    hostdata->host_param.req_ack_active_negation = 1;
+    hostdata->host_param.data_line_active_negation = 1;
+    hostdata->host_param.data_dma_burst_enable = 1;
+    hostdata->host_param.command_dma_burst_enable = 1;
+    hostdata->host_param.tag_aging = 8;
+    hostdata->host_param.selection_timeout = 250;
+    hostdata->host_param.max_queue_depth = 256;
+
+    for (i = 0; i < 16; i++) {
+        hostdata->dev_param[i].device_flags = 0xc4;
+        hostdata->dev_param[i].execution_throttle = 16;
+        hostdata->dev_param[i].synchronous_period = 25;
+        hostdata->dev_param[i].synchronous_offset = 12;
+        hostdata->dev_param[i].device_enable = 1;
+    }
+
+    LEAVE("isp1020_set_defaults");
+
+    return 0;
+}
+
+
+int isp1020_load_parameters(struct isp1020_hostdata *hostdata)
+{
+    int i, k;
+    u_long queue_addr;
+    u_short param[6];
+    u_short isp_cfg1;
+
+    ENTER("isp1020_load_parameters");
+
+    outw(hostdata->host_param.fifo_threshold, hostdata->io_base + ISP_CFG1);
+
+    param[0] = MBOX_SET_INIT_SCSI_ID;
+    param[1] = hostdata->host_param.initiator_scsi_id;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : set initiator id failure\n");
+        return 1;
+    }
+
+    param[0] = MBOX_SET_RETRY_COUNT;
+    param[1] = hostdata->host_param.retry_count;
+    param[2] = hostdata->host_param.retry_delay;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : set retry count failure\n");
+        return 1;
+    }
+
+    param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME;
+    param[1] = hostdata->host_param.async_data_setup_time;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : async data setup time failure\n");
+        return 1;
+    }
+
+    param[0] = MBOX_SET_ACTIVE_NEG_STATE;
+    param[1] = (hostdata->host_param.req_ack_active_negation << 4)
+        | (hostdata->host_param.data_line_active_negation << 5);
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : set active negation state failure\n");
+        return 1;
+    }
+
+    param[0] = MBOX_SET_PCI_CONTROL_PARAMS;
+    param[1] = hostdata->host_param.data_dma_burst_enable << 1;
+    param[2] = hostdata->host_param.command_dma_burst_enable << 1;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : set pci control parameter failure\n");
+        return 1;
+    }
+
+    isp_cfg1 = inw(hostdata->io_base + ISP_CFG1);
+
+    if (hostdata->host_param.data_dma_burst_enable 
+            || hostdata->host_param.command_dma_burst_enable)
+        isp_cfg1 |= 0x0004;
+    else
+        isp_cfg1 &= 0xfffb;
+
+    outw(isp_cfg1, hostdata->io_base + ISP_CFG1);
+			
+    param[0] = MBOX_SET_TAG_AGE_LIMIT;
+    param[1] = hostdata->host_param.tag_aging;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : set tag age limit failure\n");
+        return 1;
+    }
+
+    param[0] = MBOX_SET_SELECT_TIMEOUT;
+    param[1] = hostdata->host_param.selection_timeout;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : set selection timeout failure\n");
+        return 1;
+    }
+
+    for (i = 0; i < 16; i++) {
+
+        if (!hostdata->dev_param[i].device_enable)
+            continue;
+
+        param[0] = MBOX_SET_TARGET_PARAMS;
+        param[1] = i << 8;
+        param[2] = hostdata->dev_param[i].device_flags << 8;
+        param[3] = (hostdata->dev_param[i].synchronous_offset << 8)
+            | hostdata->dev_param[i].synchronous_period;
+
+        isp1020_mbox_command(hostdata, param);
+
+        if (param[0] != MBOX_COMMAND_COMPLETE) {
+            printk("qlogicisp : set target parameter failure\n");
+            return 1;
+        }
+
+        for (k = 0; k < 8; k++) {
+
+            param[0] = MBOX_SET_DEV_QUEUE_PARAMS;
+            param[1] = (i << 8) | k;
+            param[2] = hostdata->host_param.max_queue_depth;
+            param[3] = hostdata->dev_param[i].execution_throttle;
+
+            isp1020_mbox_command(hostdata, param);
+
+            if (param[0] != MBOX_COMMAND_COMPLETE) {
+                printk("qlogicisp : set device queue parameter failure\n");
+                return 1;
+            }
+        }
+    }
+
+    queue_addr = (u_long) &hostdata->res_queue[0][0];
+
+    param[0] = MBOX_INIT_RES_QUEUE;
+    param[1] = RES_QUEUE_LEN;
+    param[2] = (u_short) (queue_addr >> 16);
+    param[3] = (u_short) (queue_addr & 0xffff);
+    param[4] = 0;
+    param[5] = 0;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : set response queue failure\n");
+        return 1;
+    }
+
+    queue_addr = (u_long) &hostdata->req_queue[0][0];
+
+    param[0] = MBOX_INIT_REQ_QUEUE;
+    param[1] = REQ_QUEUE_LEN;
+    param[2] = (u_short) (queue_addr >> 16);
+    param[3] = (u_short) (queue_addr & 0xffff);
+    param[4] = 0;
+
+    isp1020_mbox_command(hostdata, param);
+
+    if (param[0] != MBOX_COMMAND_COMPLETE) {
+        printk("qlogicisp : set request queue failure\n");
+        return 1;
+    }
+
+    LEAVE("isp1020_load_parameters");
+
+    return 0;
+}
+
+
+int isp1020_mbox_command(struct isp1020_hostdata *hostdata, u_short param[])
+{
+    if (mbox_param[param[0]] == 0)
+        return 1;
+
+    while (inw(hostdata->io_base + HOST_HCCR) & 0x0080)
+        barrier();
+
+    switch(mbox_param[param[0]] >> 4) {
+        case 6: outw(param[5], hostdata->io_base + MBOX5);
+        case 5: outw(param[4], hostdata->io_base + MBOX4);
+        case 4: outw(param[3], hostdata->io_base + MBOX3);
+        case 3: outw(param[2], hostdata->io_base + MBOX2);
+        case 2: outw(param[1], hostdata->io_base + MBOX1);
+        case 1: outw(param[0], hostdata->io_base + MBOX0);
+    }
+
+    outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR);
+    outw(0x0, hostdata->io_base + PCI_SEMAPHORE);
+
+    outw(HCCR_SET_HOST_INTR, hostdata->io_base + HOST_HCCR);
+
+    while (!(inw(hostdata->io_base + PCI_INTF_STS) & 0x04))
+        barrier();
+
+    while (inw(hostdata->io_base + MBOX0) == 0x04)
+        barrier();
+
+    outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR);
+    outw(0x0, hostdata->io_base + PCI_SEMAPHORE);
+
+    switch(mbox_param[param[0]] & 0xf) {
+        case 6: param[5] = inw(hostdata->io_base + MBOX5);
+        case 5: param[4] = inw(hostdata->io_base + MBOX4);
+        case 4: param[3] = inw(hostdata->io_base + MBOX3);
+        case 3: param[2] = inw(hostdata->io_base + MBOX2);
+        case 2: param[1] = inw(hostdata->io_base + MBOX1);
+        case 1: param[0] = inw(hostdata->io_base + MBOX0);
+    }
+
+    return 0;
+}
+
+
+#define RESPONSE_QUEUE_UPDATE	0x01
+
+void isp1020_intr_handler(int irq, struct pt_regs *regs)
+{
+    Scsi_Cmnd *Cmnd;
+    struct Status_Entry *sts;
+    struct Marker_Entry *marker;
+    u_short status, add_marker = 0;
+    struct isp1020_hostdata *hostdata;
+
+    ENTER_INTR("isp1020_intr_handler");
+
+    if ((hostdata = irq2host[irq]) == NULL) {
+        printk("qlogicisp : unexpected interrupt on line %d\n", irq);
+        return;
+    }
+
+    DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq);)
+
+    while (!(inw(hostdata->io_base + PCI_INTF_STS) & 0x04))
+        barrier();
+
+    hostdata->res_queue_in_ptr = inw(hostdata->io_base + MBOX5);
+    outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR);
+    status = inw(hostdata->io_base + PCI_SEMAPHORE);
+
+    if ((status & RESPONSE_QUEUE_UPDATE) == 0) {
+
+        DEBUG_INTR(printk("qlogicisp : response queue update\n");)
+        DEBUG_INTR(printk("qlogicisp : response queue depth %d\n",
+            RES_QUEUE_DEPTH());)
+
+        while (hostdata->res_queue_out_ptr != hostdata->res_queue_in_ptr) {
+
+            sts = (struct Status_Entry *)
+                &hostdata->res_queue[hostdata->res_queue_out_ptr][0];
+
+            Cmnd = (Scsi_Cmnd *) sts->handle;
+
+            if (sts->completion_status == CS_RESET_OCCURRED
+                    || sts->completion_status == CS_ABORTED
+                    || (sts->status_flags & STF_BUS_RESET))
+                add_marker++;
+
+            if (sts->state_flags & SF_GOT_SENSE)
+                memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+                    sizeof(Cmnd->sense_buffer));
+
+            DEBUG_INTR(isp1020_print_status_entry(sts);)
+
+            if (sts->hdr.entry_type == ENTRY_STATUS)
+                Cmnd->result = isp1020_return_status(sts);
+            else
+                Cmnd->result = DID_ERROR << 16;
+
+            hostdata->res_queue_out_ptr = (hostdata->res_queue_out_ptr + 1)
+                % RES_QUEUE_LEN;
+
+            outw(hostdata->res_queue_out_ptr, hostdata->io_base + MBOX5);
+
+            (Cmnd->scsi_done)(Cmnd);
+        }
+    }
+    else {
+
+        DEBUG_INTR(printk("qlogicisp : mbox completion\n");)
+
+        status = inw(hostdata->io_base + MBOX0);
+        outw(0x0, hostdata->io_base + PCI_SEMAPHORE);
+
+        DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n", status);)
+
+        switch (status) {
+            case ASYNC_SCSI_BUS_RESET:
+            case EXECUTION_TIMEOUT_RESET:
+                add_marker++;
+                break;
+            case INVALID_COMMAND:
+            case HOST_INTERFACE_ERROR:
+            case COMMAND_ERROR:
+            case COMMAND_PARAM_ERROR:
+                printk("qlogicisp : bad mailbox return status\n");
+                break;
+        }
+    }
+
+    if (add_marker) {
+
+        DEBUG_INTR(printk("qlogicisp : adding marker entry\n");)
+
+        if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN
+                == hostdata->req_queue_out_ptr) {
+            printk("qlogicisp : request queue overflow\n");
+            return;
+        }
+
+        marker = (struct Marker_Entry *)
+            &hostdata->req_queue[hostdata->req_queue_in_ptr][0];
+
+        memset(marker, 0, sizeof(struct Marker_Entry));
+
+        marker->hdr.entry_type = ENTRY_MARKER;
+        marker->hdr.entry_cnt = 1;
+        marker->modifier = SYNC_ALL;
+
+        hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1)
+            % REQ_QUEUE_LEN;
+
+        outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4);
+    }
+
+    LEAVE_INTR("isp1020_intr_handler");
+}
+
+
+#define NVRAM_DELAY() { \
+    int counter = 0; while (counter++ < 0xc8) barrier(); }
+
+
+u_short isp1020_read_nvram_word(struct isp1020_hostdata *hostdata, u_short byte)
+{
+    int i;
+    u_short value, output, input;
+
+    byte &= 0x3f; byte |= 0x0180;
+
+    for (i = 8; i >= 0; i--) {
+        output = ((byte >> i) & 0x1) ? 0x4 : 0x0;
+        outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
+        outw(output | 0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
+        outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
+    }
+
+    for (i = 0xf, value = 0; i >= 0; i--) {
+        value = value << 0x1;
+        outw(0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
+        input = inw(hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
+        outw(0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
+        if (input & 0x8) value |= 0x1;
+    }
+
+    outw(0x0, hostdata->io_base + PCI_NVRAM);
+
+    return(value);
+}
+
+#define ISP1020_NVRAM_LEN	0x40
+#define ISP1020_NVRAM_SIG1	0x5349
+#define ISP1020_NVRAM_SIG2	0x2050
+
+int isp1020_verify_nvram(struct isp1020_hostdata *hostdata)
+{
+    int	i;
+    u_short value;
+    u_char checksum = 0;
+
+    for (i = 0; i < ISP1020_NVRAM_LEN; i++) {
+        value = isp1020_read_nvram_word(hostdata, i);
+
+        switch (i) {
+            case 0:
+                if (value != ISP1020_NVRAM_SIG1) return 0;
+                break;
+            case 1:
+                if (value != ISP1020_NVRAM_SIG2) return 0;
+                break;
+            case 2:
+                if ((value & 0xff) != 0x02) return 0;
+                break;
+        }
+        checksum += value & 0xff;
+        checksum += value >> 8;
+    }
+
+    return (checksum == 0);
+}
+
+
+void isp1020_enable_irqs(struct isp1020_hostdata *hostdata)
+{
+    outw(0x6, hostdata->io_base + PCI_INTF_CTL);
+}
+
+
+void isp1020_disable_irqs(struct isp1020_hostdata *hostdata)
+{
+    outw(0x0, hostdata->io_base + PCI_INTF_CTL);
+}
+
+
+#if DEBUG_ISP1020_INTR
+
+void isp1020_print_status_entry(struct Status_Entry *status)
+{
+    int i;
+
+    printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n",
+        status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
+    printk("qlogicisp : scsi status = 0x%04x, compeltion status = 0x%04x\n",
+        status->scsi_status, status->completion_status);
+    printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n",
+        status->state_flags, status->status_flags);
+    printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n",
+        status->time, status->req_sense_len);
+    printk("qlogicisp : residual transfer length = 0x%08lx\n", status->residual);
+
+    for (i = 0; i < status->req_sense_len; i++)
+        printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]);
+}
+
+#endif /* DEBUG_ISP1020_INTR */
+
+
+#if DEBUG_ISP1020
+
+void isp1020_print_scsi_cmd(Scsi_Cmnd *cmd)
+{
+    int i;
+
+    printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
+	cmd->target, cmd->lun, cmd->cmd_len);
+    printk("qlogicisp : command = ");
+    for (i = 0; i < cmd->cmd_len; i++)
+        printk("0x%02x ", cmd->cmnd[i]);
+    printk("\n");
+}
+
+#endif /* DEBUG_ISP1020 */
+
+
+int isp1020_return_status(struct Status_Entry *sts)
+{
+    int host_status = DID_ERROR;
+#if DEBUG_ISP1020_INTR
+    static char *reason[] = {
+        "DID_OK",
+        "DID_NO_CONNECT",
+        "DID_BUS_BUSY",
+        "DID_TIME_OUT",
+        "DID_BAD_TARGET",
+        "DID_ABORT",
+        "DID_PARITY",
+        "DID_ERROR",
+        "DID_RESET",
+        "DID_BAD_INTR"
+    };
+#endif /* DEBUG_ISP1020_INTR */
+
+    ENTER("isp1020_return_status");
+
+    DEBUG(printk("qlogicisp : completion status = 0x%04x\n",
+        sts->completion_status);)
+
+    switch(sts->completion_status) {
+        case CS_COMPLETE:
+            host_status = DID_OK;
+            break;
+        case CS_INCOMPLETE:
+            if (!(sts->state_flags & SF_GOT_BUS))
+                host_status = DID_NO_CONNECT;
+            else if (!(sts->state_flags & SF_GOT_TARGET))
+                host_status = DID_BAD_TARGET;
+            else if (!(sts->state_flags & SF_SENT_CDB))
+                host_status = DID_ERROR;
+            else if (!(sts->state_flags & SF_TRANSFERRED_DATA))
+                host_status = DID_ERROR;
+            else if (!(sts->state_flags & SF_GOT_STATUS))
+                host_status = DID_ERROR;
+            else if (!(sts->state_flags & SF_GOT_SENSE))
+                host_status = DID_ERROR;
+                break;
+        case CS_DMA_ERROR:
+        case CS_TRANSPORT_ERROR:
+            host_status = DID_ERROR;
+            break;
+        case CS_RESET_OCCURRED:
+            host_status = DID_RESET;
+            break;
+        case CS_ABORTED:
+            host_status = DID_ABORT;
+            break;
+        case CS_TIMEOUT:
+            host_status = DID_TIME_OUT;
+            break;
+        case CS_DATA_OVERRUN:
+        case CS_COMMAND_OVERRUN:
+        case CS_STATUS_OVERRUN:
+        case CS_BAD_MESSAGE:
+        case CS_NO_MESSAGE_OUT:
+        case CS_EXT_ID_FAILED:
+        case CS_IDE_MSG_FAILED:
+        case CS_ABORT_MSG_FAILED:
+        case CS_NOP_MSG_FAILED:
+        case CS_PARITY_ERROR_MSG_FAILED:
+        case CS_DEVICE_RESET_MSG_FAILED:
+        case CS_ID_MSG_FAILED:
+        case CS_UNEXP_BUS_FREE:
+            host_status = DID_ERROR;
+            break;
+        case CS_DATA_UNDERRUN:
+            host_status = DID_OK;
+            break;
+        default:
+            printk("qlogicisp : unknown completion status 0x%04x\n",
+                sts->completion_status);
+            host_status = DID_ERROR;
+            break;
+    }
+
+    DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n",
+        reason[host_status], sts->scsi_status);)
+
+    LEAVE("isp1020_return_status");
+
+    return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
+}
+
+#if MODULE
+Scsi_Host_Template driver_template = ISP1020;
+
+#include "scsi_module.c"
+#endif /* MODULE */
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/qlogicisp.h linux/drivers/scsi/qlogicisp.h
--- pre2.0.5/linux/drivers/scsi/qlogicisp.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogicisp.h	Sat May 18 11:58:34 1996
@@ -0,0 +1,82 @@
+/*
+ * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
+ * Written by Erik H. Moe, ehm@cris.com
+ * Copyright 1995, Erik H. Moe
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+/* Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> */
+
+/*
+ * $Date: 1995/09/22 02:32:56 $
+ * $Revision: 0.5 $
+ *
+ * $Log: isp1020.h,v $
+ * Revision 0.5  1995/09/22  02:32:56  root
+ * do auto request sense
+ *
+ * Revision 0.4  1995/08/07  04:48:28  root
+ * supply firmware with driver.
+ * numerous bug fixes/general cleanup of code.
+ *
+ * Revision 0.3  1995/07/16  16:17:16  root
+ * added reset/abort code.
+ *
+ * Revision 0.2  1995/06/29  03:19:43  root
+ * fixed biosparam.
+ * added queue protocol.
+ *
+ * Revision 0.1  1995/06/25  01:56:13  root
+ * Initial release.
+ *
+ */
+
+#ifndef _QLOGICISP_H
+#define _QLOGICISP_H
+
+int isp1020_detect(Scsi_Host_Template *);
+int isp1020_release(struct Scsi_Host *);
+const char * isp1020_info(struct Scsi_Host *);
+int isp1020_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+int isp1020_abort(Scsi_Cmnd *);
+int isp1020_reset(Scsi_Cmnd *);
+int isp1020_biosparam(Disk *, int, int[]);
+
+#ifndef NULL
+#define NULL (0)
+#endif
+
+#define QLOGICISP {					\
+	/* next */		NULL,			\
+	/* usage_count */	NULL,			\
+        /* proc dir */          NULL,                   \
+        /* procfs info */       NULL,                   \
+	/* name */		NULL,			\
+	/* detect */		isp1020_detect,		\
+	/* release */		isp1020_release,	\
+	/* info */		isp1020_info,		\
+	/* command */		NULL,		 	\
+	/* queuecommand */	isp1020_queuecommand,	\
+	/* abort */		isp1020_abort,		\
+	/* reset */		isp1020_reset,		\
+	/* slave_attach */	NULL,			\
+	/* bios_param */	isp1020_biosparam,	\
+	/* can_queue */		8,			\
+	/* this_id */		-1,			\
+	/* sg_tablesize */	4,			\
+	/* cmd_per_lun */	1,			\
+	/* present */		0,			\
+	/* unchecked_isa_dma */	0,			\
+	/* use_clustering */	DISABLE_CLUSTERING	\
+}
+
+#endif /* _QLOGICISP_H */
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/qlogicisp_asm.c linux/drivers/scsi/qlogicisp_asm.c
--- pre2.0.5/linux/drivers/scsi/qlogicisp_asm.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogicisp_asm.c	Sat May 18 11:58:34 1996
@@ -0,0 +1,1273 @@
+/* 
+ *	Version 2.02 (10:42 June 16, 1995)
+ */	
+
+unsigned short risc_code_version = 2*1024+02;
+
+unsigned short risc_code_addr01 = 0x1000 ;
+
+#if RELOAD_FIRMWARE
+
+unsigned short risc_code01[] = { 
+	0x0078, 0x1041, 0x0000, 0x2744, 0x0000, 0x2043, 0x4f50, 0x5952,
+	0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31,
+	0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320,
+	0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350,
+	0x3130, 0x3230, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056,
+	0x6572, 0x7369, 0x6f6e, 0x2030, 0x322e, 0x3032, 0x2020, 0x2043,
+	0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050,
+	0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020,
+	0x2400, 0x20b9, 0x1212, 0x2071, 0x0010, 0x70c3, 0x0004, 0x20c9,
+	0x42ff, 0x2089, 0x1159, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf,
+	0x2020, 0x70d3, 0x0002, 0x3f00, 0x70d6, 0x20c1, 0x0008, 0x2019,
+	0x0000, 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff,
+	0x2d64, 0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, 0x5050,
+	0x2114, 0xa286, 0xa5a5, 0x0040, 0x10b3, 0xa386, 0x000f, 0x0040,
+	0x1079, 0x2c6a, 0x2a5a, 0x20c1, 0x0000, 0x2019, 0x000f, 0x0078,
+	0x1059, 0x2c6a, 0x2a5a, 0x20c1, 0x0008, 0x2009, 0x7fff, 0x2148,
+	0x2944, 0x204b, 0x0a0a, 0xa9bc, 0x3fff, 0x2734, 0x203b, 0x5050,
+	0x2114, 0xa286, 0x0a0a, 0x0040, 0x109d, 0x284a, 0x263a, 0x20c1,
+	0x0004, 0x2009, 0x3fff, 0x2134, 0x200b, 0x5050, 0x2114, 0xa286,
+	0x5050, 0x0040, 0x109e, 0x0078, 0x1161, 0x284a, 0x263a, 0x98c0,
+	0xa188, 0x1000, 0x212c, 0x200b, 0xa5a5, 0x2114, 0xa286, 0xa5a5,
+	0x0040, 0x10b0, 0x250a, 0xa18a, 0x1000, 0x98c1, 0x0078, 0x10b5,
+	0x250a, 0x0078, 0x10b5, 0x2c6a, 0x2a5a, 0x2130, 0xa18a, 0x0040,
+	0x2128, 0xa1a2, 0x3800, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424,
+	0x8424, 0xa192, 0x4300, 0x2009, 0x0000, 0x2001, 0x002f, 0x1078,
+	0x19ee, 0x2218, 0x2079, 0x3800, 0x2fa0, 0x2408, 0x2011, 0x0000,
+	0x20a9, 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10d0, 0x7eda, 0x7dce,
+	0x8528, 0x7dca, 0x7cd2, 0x7bd6, 0x2031, 0x0030, 0x78b3, 0x0101,
+	0x780b, 0x0002, 0x780f, 0x0002, 0x784f, 0x0003, 0x2069, 0x3840,
+	0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008,
+	0x6813, 0x0005, 0x681f, 0x0000, 0x6823, 0x0006, 0x6817, 0x0008,
+	0x6827, 0x0000, 0x2069, 0x3900, 0x2011, 0x0020, 0x2009, 0x0010,
+	0x680b, 0x0c19, 0x680f, 0x0019, 0x6803, 0xfd00, 0x6807, 0x0018,
+	0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, 0x00c0,
+	0x1100, 0x2069, 0x3980, 0x20a9, 0x0080, 0x680b, 0x0040, 0x7bd8,
+	0xa386, 0xfeff, 0x00c0, 0x1122, 0x6817, 0x0100, 0x681f, 0x0064,
+	0x0078, 0x1126, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010,
+	0x0070, 0x112c, 0x0078, 0x1115, 0x1078, 0x1c93, 0x1078, 0x3266,
+	0x1078, 0x182c, 0x1078, 0x3706, 0x3200, 0xa085, 0x000d, 0x2090,
+	0x70c3, 0x0000, 0x0090, 0x1143, 0x70c0, 0xa086, 0x0002, 0x00c0,
+	0x1143, 0x1078, 0x1272, 0x1078, 0x1184, 0x78b0, 0xa005, 0x00c0,
+	0x114f, 0x1078, 0x1a17, 0x0068, 0x1153, 0x1078, 0x1bed, 0x0068,
+	0x1153, 0x1078, 0x191f, 0x00e0, 0x1143, 0x1078, 0x35a4, 0x0078,
+	0x1143, 0x1161, 0x1163, 0x1e39, 0x1e39, 0x32c6, 0x32c6, 0x1e39,
+	0x1e39, 0x0078, 0x1161, 0x0078, 0x1163, 0x0078, 0x1165, 0x0078,
+	0x1167, 0x2009, 0x0022, 0x2104, 0xa086, 0x4000, 0x0040, 0x117f,
+	0x7008, 0x800b, 0x00c8, 0x117f, 0x7007, 0x0002, 0xa08c, 0x0060,
+	0x00c0, 0x1180, 0xa084, 0x0008, 0x0040, 0x117f, 0x087a, 0x097a,
+	0x70c3, 0x4002, 0x0078, 0x1275, 0x0068, 0x11ef, 0x2061, 0x0000,
+	0x6018, 0xa084, 0x0001, 0x00c0, 0x11ef, 0x7814, 0xa005, 0x00c0,
+	0x1195, 0x0010, 0x11f0, 0x0078, 0x11ef, 0x2009, 0x3868, 0x2104,
+	0xa005, 0x00c0, 0x11ef, 0x2009, 0x3871, 0x200b, 0x0000, 0x7914,
+	0xa186, 0x0042, 0x00c0, 0x11ba, 0x7816, 0x2009, 0x386f, 0x2164,
+	0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca, 0x611c, 0xa18c,
+	0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce, 0x1078, 0x181e,
+	0x0078, 0x11ed, 0x7814, 0xa086, 0x0018, 0x00c0, 0x11c1, 0x1078,
+	0x15ce, 0x7817, 0x0000, 0x2009, 0x386f, 0x2104, 0xa065, 0x0040,
+	0x11dd, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x187e, 0x0c7f, 0x609f,
+	0x0000, 0x1078, 0x1695, 0x2009, 0x001c, 0x6087, 0x0103, 0x1078,
+	0x17a5, 0x00c0, 0x11e9, 0x1078, 0x181e, 0x2009, 0x386f, 0x200b,
+	0x0000, 0x2009, 0x3869, 0x2104, 0x200b, 0x0000, 0xa005, 0x0040,
+	0x11ed, 0x2001, 0x4005, 0x0078, 0x1274, 0x0078, 0x1272, 0x007c,
+	0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000, 0x70cf, 0x0000,
+	0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1240, 0x2038, 0x0079, 0x1200,
+	0x1272, 0x12cd, 0x1291, 0x12cd, 0x1336, 0x1336, 0x1288, 0x16a9,
+	0x1341, 0x1280, 0x1295, 0x1297, 0x1299, 0x129b, 0x16ae, 0x1280,
+	0x1353, 0x137e, 0x15e6, 0x16a3, 0x129d, 0x1546, 0x1568, 0x157e,
+	0x159b, 0x1503, 0x1511, 0x1525, 0x1539, 0x13f1, 0x1280, 0x139f,
+	0x13a5, 0x13aa, 0x13af, 0x13b5, 0x13ba, 0x13bf, 0x13c4, 0x13c9,
+	0x13cd, 0x13e2, 0x13ee, 0x1280, 0x1280, 0x1280, 0x1280, 0x13fd,
+	0x1406, 0x1415, 0x143b, 0x1445, 0x144c, 0x1472, 0x1481, 0x1490,
+	0x14a2, 0x14e3, 0x14f3, 0x1280, 0x1280, 0x1280, 0x1280, 0x14f8,
+	0xa0bc, 0xffa0, 0x00c0, 0x1280, 0x2038, 0xa084, 0x001f, 0x0079,
+	0x1249, 0x16c5, 0x16c8, 0x16d8, 0x1754, 0x178d, 0x1280, 0x1280,
+	0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280,
+	0x1280, 0x12c3, 0x132c, 0x1349, 0x1374, 0x15dc, 0x1280, 0x1280,
+	0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280,
+	0x1280, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x1274, 0x73ce,
+	0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, 0x1275, 0x2061,
+	0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c,
+	0x70c3, 0x4001, 0x0078, 0x1275, 0x70c3, 0x4006, 0x0078, 0x1275,
+	0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078,
+	0x1272, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x1272, 0x0078,
+	0x1272, 0x0078, 0x1272, 0x0078, 0x1272, 0x2091, 0x8000, 0x70c3,
+	0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
+	0x0002, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031,
+	0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061,
+	0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x0078, 0x0455, 0x1078, 0x198c, 0x00c0, 0x1284, 0x75d8,
+	0x74dc, 0x75da, 0x74de, 0x0078, 0x12d0, 0x2029, 0x0000, 0x2520,
+	0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, 0x2098, 0x2031, 0x0030,
+	0x81ff, 0x0040, 0x1272, 0x7007, 0x0004, 0x731a, 0x721e, 0x7422,
+	0x7526, 0x2051, 0x0012, 0x2049, 0x130b, 0x2041, 0x1272, 0x7003,
+	0x0002, 0xa786, 0x0001, 0x0040, 0x12f3, 0xa786, 0x0050, 0x0040,
+	0x12f3, 0x0078, 0x12f9, 0x2049, 0x1318, 0x2041, 0x1324, 0x7003,
+	0x0003, 0x7017, 0x0000, 0x810b, 0x7112, 0x00c8, 0x1301, 0x7017,
+	0x0001, 0x7007, 0x0001, 0xa786, 0x0001, 0x0040, 0x1318, 0xa786,
+	0x0050, 0x0040, 0x1318, 0x700c, 0xa084, 0x007f, 0x2009, 0x0040,
+	0xa102, 0x8004, 0x094a, 0x20a8, 0x26a0, 0x53a6, 0x0078, 0x1169,
+	0x700c, 0xa084, 0x007f, 0x0040, 0x1318, 0x80ac, 0x0048, 0x1318,
+	0x2698, 0x53a5, 0x0078, 0x1169, 0x700c, 0xa084, 0x007f, 0x80ac,
+	0x2698, 0x53a5, 0x0078, 0x1272, 0x1078, 0x198c, 0x00c0, 0x1284,
+	0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x12d0, 0x71c4, 0x70c8,
+	0x2114, 0xa79e, 0x0004, 0x00c0, 0x133e, 0x200a, 0x72ca, 0x0078,
+	0x1271, 0x70c7, 0x0002, 0x70cb, 0x0002, 0x70cf, 0x0000, 0x0078,
+	0x1272, 0x1078, 0x198c, 0x00c0, 0x1284, 0x75d8, 0x76dc, 0x75da,
+	0x76de, 0x0078, 0x1356, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8,
+	0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040,
+	0x136e, 0x8001, 0x787a, 0x7a82, 0x7b86, 0x7d8a, 0x7e8e, 0x7c7e,
+	0x78b0, 0xa084, 0xfffc, 0x78b2, 0x0078, 0x1372, 0x78b0, 0xa085,
+	0x0001, 0x78b2, 0x0078, 0x1272, 0x1078, 0x198c, 0x00c0, 0x1284,
+	0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1381, 0x2029, 0x0000,
+	0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce,
+	0x74d6, 0xa005, 0x0040, 0x1399, 0x8001, 0x7896, 0x7a9e, 0x7ba2,
+	0x7da6, 0x7eaa, 0x7c9a, 0x78b0, 0xa084, 0xfcff, 0x78b2, 0x0078,
+	0x139d, 0x78b0, 0xa085, 0x0100, 0x78b2, 0x0078, 0x1272, 0x2009,
+	0x385b, 0x210c, 0x7ad4, 0x0078, 0x1270, 0x2009, 0x3841, 0x210c,
+	0x0078, 0x1271, 0x2009, 0x3842, 0x210c, 0x0078, 0x1271, 0x2061,
+	0x3840, 0x610c, 0x6210, 0x0078, 0x1270, 0x2009, 0x3845, 0x210c,
+	0x0078, 0x1271, 0x2009, 0x3846, 0x210c, 0x0078, 0x1271, 0x2009,
+	0x3847, 0x210c, 0x0078, 0x1271, 0x2009, 0x3848, 0x210c, 0x0078,
+	0x1271, 0x7908, 0x7a0c, 0x0078, 0x1270, 0x71c4, 0x8107, 0xa084,
+	0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x3900, 0x6a00, 0x6804,
+	0xa084, 0x0008, 0x0040, 0x13df, 0x6b08, 0x0078, 0x13e0, 0x6b0c,
+	0x0078, 0x126f, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000, 0x6b1c,
+	0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x126f, 0x794c, 0x0078,
+	0x1271, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000, 0x6908, 0x6a18,
+	0x6b10, 0x2091, 0x8001, 0x0078, 0x126f, 0x71c4, 0xa182, 0x0010,
+	0x00c8, 0x126a, 0x1078, 0x1d19, 0x0078, 0x126f, 0x71c4, 0xa182,
+	0x0010, 0x00c8, 0x126a, 0x2011, 0x3841, 0x2204, 0x007e, 0x2112,
+	0x1078, 0x1cd2, 0x017f, 0x0078, 0x1271, 0x71c4, 0x2011, 0x1433,
+	0x20a9, 0x0008, 0x2204, 0xa106, 0x0040, 0x1425, 0x8210, 0x0070,
+	0x1423, 0x0078, 0x141a, 0x0078, 0x126a, 0xa292, 0x1433, 0x027e,
+	0x2011, 0x3842, 0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x1cde,
+	0x017f, 0x0078, 0x1271, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064,
+	0x0019, 0x0032, 0x004b, 0x2061, 0x3840, 0x610c, 0x6210, 0x70c4,
+	0x600e, 0x70c8, 0x6012, 0x0078, 0x1270, 0x2061, 0x3840, 0x6114,
+	0x70c4, 0x6016, 0x0078, 0x1271, 0x71c4, 0x2011, 0x0004, 0x2019,
+	0x1212, 0xa186, 0x0028, 0x0040, 0x1465, 0x2011, 0x0005, 0x2019,
+	0x1212, 0xa186, 0x0032, 0x0040, 0x1465, 0x2011, 0x0006, 0x2019,
+	0x2323, 0xa186, 0x003c, 0x00c0, 0x126a, 0x2061, 0x3840, 0x6018,
+	0x007e, 0x611a, 0x23b8, 0x1078, 0x1cef, 0x1078, 0x3706, 0x017f,
+	0x0078, 0x1271, 0x71c4, 0xa184, 0xffcf, 0x00c0, 0x126a, 0x2011,
+	0x3847, 0x2204, 0x2112, 0x007e, 0x1078, 0x1d11, 0x017f, 0x0078,
+	0x1271, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x126a, 0x2011, 0x3848,
+	0x2204, 0x007e, 0x2112, 0x1078, 0x1d00, 0x017f, 0x0078, 0x1271,
+	0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x1269, 0xa284, 0xfffd,
+	0x00c0, 0x1269, 0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e,
+	0x0078, 0x1270, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003,
+	0x8003, 0xa0e8, 0x3900, 0x2019, 0x0000, 0x72c8, 0x6800, 0x007e,
+	0xa226, 0x0040, 0x14d1, 0x6a02, 0xa484, 0x2000, 0x0040, 0x14ba,
+	0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x14c0, 0xa39d, 0x0008,
+	0xa484, 0x4000, 0x0040, 0x14d1, 0x810f, 0xa284, 0x4000, 0x0040,
+	0x14cd, 0x1078, 0x1d33, 0x0078, 0x14d1, 0x1078, 0x1d25, 0x0078,
+	0x14d1, 0x72cc, 0x82ff, 0x0040, 0x14dc, 0x6808, 0xa206, 0x0040,
+	0x14dc, 0x6a0a, 0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f,
+	0x6b0c, 0x0078, 0x126f, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000,
+	0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e,
+	0x2708, 0x0078, 0x126f, 0x70c4, 0x794c, 0x784e, 0x0078, 0x1271,
+	0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x126a, 0x1078,
+	0x1d41, 0x0078, 0x126f, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000,
+	0x6a08, 0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078,
+	0x1270, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000, 0x6a08, 0xa294,
+	0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1520, 0x1078, 0x1c74,
+	0x2091, 0x8001, 0x2708, 0x0078, 0x1270, 0x77c4, 0x1078, 0x183c,
+	0x2091, 0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005,
+	0x0040, 0x1534, 0x1078, 0x1c74, 0x2091, 0x8001, 0x2708, 0x0078,
+	0x1270, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020,
+	0x1078, 0x1849, 0x2708, 0x6a08, 0x0078, 0x1270, 0x77c4, 0x73c8,
+	0x72cc, 0x77c6, 0x73ca, 0x72ce, 0x1078, 0x18c4, 0x00c0, 0x1564,
+	0x6818, 0xa005, 0x0040, 0x155e, 0x2708, 0x1078, 0x1d51, 0x00c0,
+	0x155e, 0x7817, 0x0015, 0x2091, 0x8001, 0x007c, 0x2091, 0x8001,
+	0x2001, 0x4005, 0x0078, 0x1274, 0x2091, 0x8001, 0x0078, 0x1272,
+	0x77c4, 0x77c6, 0x2061, 0x3840, 0x60a3, 0x0003, 0x67b6, 0x60c7,
+	0x0005, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x1078,
+	0x1849, 0x7817, 0x0016, 0x1078, 0x1c74, 0x007c, 0x77c4, 0x77c6,
+	0xa7bc, 0xff00, 0x2061, 0x3840, 0x60a3, 0x0002, 0x67b6, 0x60c7,
+	0x0005, 0x7817, 0x0017, 0x1078, 0x1c74, 0x2041, 0x0021, 0x2049,
+	0x0004, 0x2051, 0x0010, 0x1078, 0x1849, 0x8738, 0xa784, 0x0007,
+	0x00c0, 0x1593, 0x007c, 0x78b0, 0xa084, 0x0003, 0x00c0, 0x15bf,
+	0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008,
+	0x1078, 0x183c, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a, 0x2091,
+	0x8001, 0x8738, 0xa784, 0x0007, 0x00c0, 0x15a8, 0xa7bc, 0xff00,
+	0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x15a8, 0x7817,
+	0x0018, 0x2061, 0x3840, 0x60a3, 0x0001, 0x60c7, 0x0005, 0x1078,
+	0x1c74, 0x78b0, 0xa085, 0x0002, 0x78b2, 0x007c, 0x78b0, 0xa084,
+	0xfffd, 0x78b2, 0xa084, 0x0001, 0x00c0, 0x15d8, 0x1078, 0x1906,
+	0x71c4, 0x71c6, 0x794a, 0x007c, 0x1078, 0x198c, 0x00c0, 0x1284,
+	0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x15e9, 0x2029, 0x0000,
+	0x2520, 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079,
+	0x3800, 0x1078, 0x1815, 0x0040, 0x1691, 0x20a9, 0x0005, 0x20a1,
+	0x3816, 0x41a1, 0x2009, 0x0040, 0x1078, 0x17df, 0x0040, 0x1604,
+	0x1078, 0x181e, 0x0078, 0x1691, 0x6004, 0xa084, 0xff00, 0x8007,
+	0x8009, 0x0040, 0x1665, 0x0c7e, 0x2c68, 0x1078, 0x1815, 0x0040,
+	0x1634, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x160c, 0x609f, 0x0000,
+	0x0c7f, 0x0c7e, 0x7218, 0x731c, 0x7420, 0x7524, 0x2c68, 0x689c,
+	0xa065, 0x0040, 0x1664, 0x2009, 0x0040, 0x1078, 0x17df, 0x00c0,
+	0x164d, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x00c0, 0x1634,
+	0x2d00, 0x6002, 0x0078, 0x161a, 0x0c7f, 0x0c7e, 0x609c, 0x2060,
+	0x1078, 0x187e, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1695, 0x2009,
+	0x001c, 0x6008, 0xa085, 0x0200, 0x600a, 0x6004, 0x6086, 0x1078,
+	0x17a5, 0x1078, 0x181e, 0x0078, 0x1691, 0x0c7f, 0x0c7e, 0x609c,
+	0x2060, 0x1078, 0x187e, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1695,
+	0x2009, 0x001c, 0x6087, 0x0103, 0x601b, 0x0003, 0x1078, 0x17a5,
+	0x1078, 0x181e, 0x0078, 0x1691, 0x0c7f, 0x74c4, 0x73c8, 0x72cc,
+	0x6014, 0x7817, 0x0012, 0x0e7e, 0x2071, 0x3840, 0x70a3, 0x0005,
+	0x70a7, 0x0000, 0x73aa, 0x72ae, 0x74b2, 0x70b6, 0x70bb, 0x0000,
+	0x2c00, 0x70be, 0x70c3, 0x0000, 0xa02e, 0x2530, 0x611c, 0xa184,
+	0x0060, 0x0040, 0x1685, 0x1078, 0x320a, 0x0e7f, 0x6596, 0x65a6,
+	0x669a, 0x669a, 0x60af, 0x0000, 0x60b3, 0x0000, 0x1078, 0x1c74,
+	0x007c, 0x70c3, 0x4005, 0x0078, 0x1275, 0x20a9, 0x0005, 0x2099,
+	0x3816, 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000,
+	0xa5a9, 0x0000, 0x007c, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078,
+	0x1272, 0x71c4, 0x71c6, 0x2168, 0x0078, 0x16b0, 0x2069, 0x1000,
+	0x690c, 0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x16b2,
+	0xa285, 0x0000, 0x00c0, 0x16c0, 0x70c3, 0x4000, 0x0078, 0x16c2,
+	0x70c3, 0x4003, 0x70ca, 0x0078, 0x1275, 0x79c8, 0x0078, 0x1271,
+	0x71c4, 0x71c6, 0x2198, 0x20a1, 0x0042, 0x20a9, 0x0004, 0x53a3,
+	0x21a0, 0x2099, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x0078, 0x1272,
+	0x70c4, 0x2068, 0x2079, 0x3800, 0x1078, 0x1815, 0x0040, 0x1750,
+	0x6007, 0x0001, 0x600b, 0x0000, 0x602b, 0x0000, 0x601b, 0x0006,
+	0x6a10, 0xa28c, 0x0007, 0xa284, 0x00f0, 0x8003, 0x8003, 0x8003,
+	0x8003, 0xa105, 0x6016, 0xa284, 0x0800, 0x0040, 0x16fb, 0x601b,
+	0x000a, 0x0078, 0x1701, 0xa284, 0x1000, 0x0040, 0x1701, 0x601b,
+	0x000c, 0xa284, 0x0300, 0x0040, 0x170a, 0x602b, 0x0001, 0x8004,
+	0x8004, 0x8004, 0xa085, 0x0001, 0x601e, 0x6023, 0x0000, 0x6027,
+	0x000a, 0xa284, 0x0400, 0x0040, 0x1717, 0x602b, 0x0000, 0x20a9,
+	0x0006, 0xac80, 0x000b, 0x20a0, 0xad80, 0x0005, 0x2098, 0x53a3,
+	0xa284, 0x0300, 0x00c0, 0x172c, 0x6046, 0x604a, 0x604e, 0x6052,
+	0x6096, 0x609a, 0x0078, 0x1736, 0x6800, 0x6046, 0x6804, 0x604a,
+	0x6e08, 0x664e, 0x6d0c, 0x6552, 0x6596, 0x669a, 0x6014, 0x7817,
+	0x0042, 0x2c08, 0x2061, 0x3840, 0x60a3, 0x0005, 0x60a7, 0x0000,
+	0x60ab, 0x0000, 0x60af, 0x0000, 0x60b3, 0x0000, 0x60b6, 0x61be,
+	0xa284, 0x0400, 0x60c2, 0x1078, 0x31f5, 0x1078, 0x1c74, 0x007c,
+	0x70c3, 0x4005, 0x0078, 0x1275, 0x78e0, 0xa005, 0x0040, 0x1280,
+	0x2091, 0x8000, 0x70c4, 0x800a, 0x2011, 0x0010, 0x810c, 0x0048,
+	0x1766, 0x3a00, 0xa084, 0xfff7, 0x0078, 0x1769, 0x3a00, 0xa085,
+	0x0008, 0x20d0, 0x0005, 0x0005, 0xa084, 0xfffb, 0x20d0, 0x0005,
+	0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0xa085,
+	0x0004, 0x20d0, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005,
+	0x0005, 0x0005, 0x8211, 0x00c0, 0x175e, 0x3a00, 0xa085, 0x0008,
+	0x20d0, 0x2091, 0x8001, 0x0078, 0x1272, 0x2011, 0x04fd, 0x2204,
+	0xa082, 0x0004, 0x0048, 0x17a1, 0x78e3, 0x0001, 0x2009, 0xff01,
+	0x200a, 0x2001, 0x000c, 0x20d8, 0x2001, 0x000c, 0x20d0, 0x0078,
+	0x1272, 0x2001, 0x4005, 0x0078, 0x1274, 0x700c, 0xa084, 0x00ff,
+	0x0040, 0x17b1, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+	0x17ac, 0x7017, 0x0000, 0x7112, 0x721a, 0x731e, 0x7422, 0x7526,
+	0xac80, 0x0001, 0x8108, 0x810c, 0x81a9, 0x8098, 0x20a1, 0x0030,
+	0x6084, 0x20a2, 0x53a6, 0x780c, 0xa085, 0x0000, 0x7002, 0x7007,
+	0x0001, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x17c9,
+	0x7108, 0x8103, 0x00c8, 0x17c9, 0x7014, 0xa005, 0x0040, 0x17c9,
+	0x7007, 0x0002, 0xa184, 0x0060, 0x7003, 0x0000, 0x007c, 0x700c,
+	0xa084, 0x00ff, 0x0040, 0x17eb, 0x7007, 0x0004, 0x7004, 0xa084,
+	0x0004, 0x00c0, 0x17e6, 0x7017, 0x0000, 0x7112, 0x721a, 0x7422,
+	0x7526, 0x731e, 0x2099, 0x0030, 0x8108, 0x81ac, 0x780c, 0xa085,
+	0x0001, 0x7002, 0x7007, 0x0001, 0x2009, 0x0022, 0x2104, 0xa084,
+	0x4000, 0x00c0, 0x17fc, 0x7008, 0x800b, 0x00c8, 0x17fc, 0x7007,
+	0x0002, 0xa08c, 0x0060, 0x00c0, 0x1812, 0xac80, 0x0001, 0x20a0,
+	0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x7850, 0xa065, 0x0040,
+	0x181d, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079,
+	0x3800, 0x7850, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1829, 0x1078,
+	0x1e2a, 0x7852, 0x0f7f, 0x007c, 0x2011, 0x4300, 0x7a52, 0x7bd4,
+	0x8319, 0x0040, 0x1839, 0xa280, 0x002f, 0x2012, 0x2010, 0x0078,
+	0x1830, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784,
+	0x0007, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, 0x3980,
+	0x007c, 0x1078, 0x183c, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808,
+	0xa084, 0xffef, 0xa80d, 0x690a, 0x2091, 0x8000, 0x2009, 0x384f,
+	0x210c, 0x6804, 0xa005, 0x0040, 0x1866, 0xa116, 0x00c0, 0x1866,
+	0x2060, 0x6000, 0x6806, 0x017e, 0x0078, 0x1869, 0x2009, 0x0000,
+	0x017e, 0x6804, 0xa065, 0x0040, 0x1878, 0x6000, 0x6806, 0x1078,
+	0x188b, 0x1078, 0x1992, 0x6810, 0x8001, 0x6812, 0x00c0, 0x1869,
+	0x017f, 0x6902, 0x6906, 0x2091, 0x8001, 0x007c, 0xa065, 0x0040,
+	0x188a, 0x609c, 0x609f, 0x0000, 0x2008, 0x1078, 0x181e, 0x2100,
+	0x0078, 0x187e, 0x007c, 0x6007, 0x0103, 0x20a9, 0x001c, 0xac80,
+	0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c,
+	0x6022, 0x007c, 0x0e7e, 0x2071, 0x3840, 0x7040, 0xa08c, 0x0080,
+	0x00c0, 0x18a8, 0xa088, 0x3880, 0x2d0a, 0x8000, 0x7042, 0xa006,
+	0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x3840, 0x2009, 0x3880, 0x7240,
+	0x8221, 0x8211, 0x0048, 0x18c2, 0x2104, 0x8108, 0xad06, 0x00c0,
+	0x18b1, 0x8119, 0x211e, 0x8108, 0x8318, 0x8211, 0x00c8, 0x18ba,
+	0x7442, 0xa006, 0x0e7f, 0x007c, 0x1078, 0x183c, 0x2091, 0x8000,
+	0x6804, 0x781e, 0xa065, 0x0040, 0x1905, 0x0078, 0x18d5, 0x2c00,
+	0x781e, 0x6000, 0xa065, 0x0040, 0x1905, 0x6010, 0xa306, 0x00c0,
+	0x18cf, 0x600c, 0xa206, 0x00c0, 0x18cf, 0x2c28, 0x6804, 0xac06,
+	0x00c0, 0x18ec, 0x6000, 0x2060, 0x6806, 0xa005, 0x00c0, 0x18ec,
+	0x6803, 0x0000, 0x0078, 0x18f6, 0x6400, 0x781c, 0x2060, 0x6402,
+	0xa486, 0x0000, 0x00c0, 0x18f6, 0x2c00, 0x6802, 0x2560, 0x1078,
+	0x188b, 0x601b, 0x0005, 0x6023, 0x0020, 0x1078, 0x1992, 0x6810,
+	0x8001, 0x6812, 0x2001, 0xffff, 0xa005, 0x007c, 0x2039, 0x0000,
+	0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, 0x1849,
+	0x8738, 0xa784, 0x0007, 0x00c0, 0x190e, 0xa7bc, 0xff00, 0x873f,
+	0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x190e, 0x007c, 0x2061,
+	0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1930, 0x2091, 0x8000,
+	0x78c4, 0x78c7, 0x0000, 0x2091, 0x8001, 0xa005, 0x00c0, 0x1931,
+	0x007c, 0xa08c, 0xfff0, 0x0040, 0x1937, 0x1078, 0x1e2a, 0x0079,
+	0x1939, 0x1949, 0x194b, 0x1951, 0x1955, 0x1949, 0x1959, 0x1949,
+	0x1960, 0x1964, 0x1968, 0x1949, 0x1949, 0x1949, 0x1949, 0x1949,
+	0x1949, 0x1078, 0x1e2a, 0x1078, 0x1906, 0x2001, 0x8001, 0x0078,
+	0x1274, 0x2001, 0x8003, 0x0078, 0x1274, 0x2001, 0x8004, 0x0078,
+	0x1274, 0x1078, 0x1906, 0x2001, 0x8006, 0x007c, 0x0078, 0x1274,
+	0x2001, 0x8008, 0x0078, 0x1274, 0x2001, 0x8009, 0x0078, 0x1274,
+	0x2091, 0x8000, 0x2069, 0x3840, 0x6800, 0xa086, 0x0000, 0x0040,
+	0x1976, 0x2091, 0x8001, 0x78c7, 0x0009, 0x007c, 0x68b4, 0xa0bc,
+	0xff00, 0x2091, 0x8000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051,
+	0x0010, 0x1078, 0x1849, 0x8738, 0xa784, 0x0007, 0x00c0, 0x1981,
+	0x2001, 0x800a, 0x0078, 0x1274, 0x2001, 0x04fd, 0x2004, 0xa086,
+	0x0004, 0x007c, 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, 0x786c,
+	0x8000, 0x786e, 0x7870, 0xa005, 0x7972, 0x0040, 0x19a2, 0x2c02,
+	0x0078, 0x19a3, 0x7976, 0x007c, 0x0c7e, 0x2061, 0x3800, 0x6887,
+	0x0103, 0x2d08, 0x206b, 0x0000, 0x606c, 0x8000, 0x606e, 0x6070,
+	0xa005, 0x6172, 0x0040, 0x19b7, 0x2d02, 0x0078, 0x19b8, 0x6176,
+	0x0c7f, 0x007c, 0x1078, 0x19cb, 0x0040, 0x19ca, 0x0c7e, 0x609c,
+	0xa065, 0x0040, 0x19c5, 0x1078, 0x187e, 0x0c7f, 0x609f, 0x0000,
+	0x1078, 0x181e, 0x007c, 0x7874, 0xa065, 0x0040, 0x19dd, 0x2091,
+	0x8000, 0x786c, 0x8001, 0x786e, 0x2c04, 0x7876, 0xa005, 0x00c0,
+	0x19db, 0x7872, 0x8000, 0x2091, 0x8001, 0x007c, 0x20a9, 0x0010,
+	0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x19e7, 0xa200, 0x0070,
+	0x19eb, 0x0078, 0x19e2, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9,
+	0x0010, 0xa005, 0x0040, 0x1a11, 0xa11a, 0x00c8, 0x1a11, 0x8213,
+	0x818d, 0x0048, 0x1a02, 0xa11a, 0x00c8, 0x1a03, 0x0070, 0x1a09,
+	0x0078, 0x19f7, 0xa11a, 0x2308, 0x8210, 0x0070, 0x1a09, 0x0078,
+	0x19f7, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f,
+	0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x1a0d, 0x797c,
+	0x70d0, 0x007e, 0x007f, 0xa106, 0x0040, 0x1a67, 0x2091, 0x8000,
+	0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1a67, 0x7008, 0x7208,
+	0xa206, 0x00c0, 0x1a67, 0xa286, 0x0008, 0x00c0, 0x1a67, 0x2071,
+	0x0010, 0x1078, 0x1815, 0x0040, 0x1a67, 0x7a84, 0x7b80, 0x7c8c,
+	0x7d88, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000, 0x2009,
+	0x0040, 0x1078, 0x17df, 0x2091, 0x8001, 0x0040, 0x1a5e, 0x1078,
+	0x181e, 0x7890, 0x8000, 0x7892, 0xa086, 0x0002, 0x00c0, 0x1a67,
+	0x2091, 0x8000, 0x78c7, 0x0002, 0x7893, 0x0000, 0x78b0, 0xa085,
+	0x0003, 0x78b2, 0x2091, 0x8001, 0x0078, 0x1a67, 0x7893, 0x0000,
+	0x1078, 0x1bb6, 0x6004, 0xa084, 0x000f, 0x0079, 0x1a6c, 0x2071,
+	0x0010, 0x2091, 0x8001, 0x007c, 0x1a7c, 0x1a9e, 0x1ac4, 0x1a7c,
+	0x1ad6, 0x1a8b, 0x1a7c, 0x1a7c, 0x1a7c, 0x1a98, 0x1abe, 0x1a7c,
+	0x1a7c, 0x1a7c, 0x1a7c, 0x1a7c, 0x2039, 0x0400, 0x78c0, 0xa705,
+	0x78c2, 0x6008, 0xa705, 0x600a, 0x1078, 0x1b14, 0x609c, 0x78be,
+	0x1078, 0x1b9e, 0x007c, 0x78c0, 0xa084, 0x0100, 0x0040, 0x1a92,
+	0x0078, 0x1a7c, 0x601c, 0xa085, 0x0080, 0x601e, 0x0078, 0x1aa5,
+	0x1078, 0x198c, 0x00c0, 0x1a7c, 0x1078, 0x1bd0, 0x78c0, 0xa084,
+	0x0100, 0x0040, 0x1aa5, 0x0078, 0x1a7c, 0x78c3, 0x0000, 0x6004,
+	0x8007, 0xa084, 0x00ff, 0x78b6, 0x8001, 0x609f, 0x0000, 0x0040,
+	0x1abb, 0x1078, 0x1b14, 0x0040, 0x1abb, 0x78c0, 0xa085, 0x0100,
+	0x78c2, 0x0078, 0x1abd, 0x1078, 0x1b38, 0x007c, 0x1078, 0x198c,
+	0x00c0, 0x1a7c, 0x1078, 0x1bcc, 0x78c0, 0xa08c, 0x0e00, 0x00c0,
+	0x1acd, 0xa084, 0x0100, 0x00c0, 0x1acf, 0x0078, 0x1a7c, 0x1078,
+	0x1b14, 0x00c0, 0x1ad5, 0x1078, 0x1b38, 0x007c, 0x78c0, 0xa084,
+	0x0100, 0x0040, 0x1add, 0x0078, 0x1a7c, 0x78c3, 0x0000, 0x6714,
+	0x20a9, 0x0001, 0x6018, 0xa005, 0x0040, 0x1af8, 0xa7bc, 0xff00,
+	0x20a9, 0x0008, 0xa08e, 0x0001, 0x0040, 0x1af8, 0x2039, 0x0000,
+	0x20a9, 0x0080, 0xa08e, 0x0002, 0x0040, 0x1af8, 0x0078, 0x1b11,
+	0x1078, 0x183c, 0x2d00, 0xa088, 0x0002, 0x2091, 0x8000, 0x2168,
+	0x682b, 0x0000, 0x682f, 0x0000, 0x2104, 0xa084, 0xffde, 0x200a,
+	0x2100, 0xa088, 0x0010, 0x2091, 0x8001, 0x0070, 0x1b11, 0x0078,
+	0x1afd, 0x1078, 0x181e, 0x007c, 0x78b8, 0xa06d, 0x00c0, 0x1b1f,
+	0x2c00, 0x78ba, 0x78be, 0x609f, 0x0000, 0x0078, 0x1b2b, 0x2c00,
+	0x689e, 0x609f, 0x0000, 0x78ba, 0x2d00, 0x6002, 0x78bc, 0xad06,
+	0x00c0, 0x1b2b, 0x6002, 0x78b4, 0x8001, 0x78b6, 0x00c0, 0x1b37,
+	0x78c0, 0xa084, 0x0000, 0x78c2, 0x78bc, 0x2060, 0xa006, 0x007c,
+	0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0xc1ff, 0x601e, 0xa184,
+	0x0060, 0x0040, 0x1b47, 0x0e7e, 0x1078, 0x320a, 0x0e7f, 0x6596,
+	0x669a, 0x6714, 0x1078, 0x183c, 0x2091, 0x8000, 0x6808, 0xa084,
+	0x0001, 0x0040, 0x1b63, 0x2091, 0x8001, 0x1078, 0x188b, 0x2091,
+	0x8000, 0x1078, 0x1992, 0x2091, 0x8001, 0x78bb, 0x0000, 0x78bf,
+	0x0000, 0x0078, 0x1b9d, 0x6024, 0xa096, 0x0001, 0x00c0, 0x1b6a,
+	0x8000, 0x6026, 0x6a10, 0x6814, 0x2091, 0x8001, 0xa202, 0x0048,
+	0x1b79, 0x0040, 0x1b79, 0x2039, 0x0200, 0x1078, 0x1b9e, 0x0078,
+	0x1b9d, 0x2c08, 0x2091, 0x8000, 0x6800, 0xa065, 0x0040, 0x1b81,
+	0x6102, 0x6902, 0x00c0, 0x1b85, 0x6906, 0x2160, 0x6003, 0x0000,
+	0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808, 0xa08c, 0x0040,
+	0x0040, 0x1b97, 0xa086, 0x0040, 0x680a, 0x1078, 0x189a, 0x1078,
+	0x1c74, 0x78bf, 0x0000, 0x78bb, 0x0000, 0x007c, 0x6008, 0xa705,
+	0x600a, 0x2091, 0x8000, 0x1078, 0x1992, 0x2091, 0x8001, 0x78bc,
+	0xa065, 0x0040, 0x1bb1, 0x609c, 0x78be, 0x609f, 0x0000, 0x0078,
+	0x1ba1, 0x78bb, 0x0000, 0x78bf, 0x0000, 0x007c, 0x7978, 0x787c,
+	0x8000, 0xa10a, 0x00c8, 0x1bbd, 0xa006, 0x787e, 0x70d2, 0x7804,
+	0xa005, 0x0040, 0x1bcb, 0x8001, 0x7806, 0x00c0, 0x1bcb, 0x0068,
+	0x1bcb, 0x2091, 0x4080, 0x007c, 0x2039, 0x1be4, 0x0078, 0x1bd2,
+	0x2039, 0x1bea, 0x2704, 0xa005, 0x0040, 0x1be3, 0xac00, 0x2068,
+	0x6b08, 0x6c0c, 0x6910, 0x6a14, 0x690a, 0x6a0e, 0x6b12, 0x6c16,
+	0x8738, 0x0078, 0x1bd2, 0x007c, 0x0003, 0x0009, 0x000f, 0x0015,
+	0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x0068, 0x1c05, 0x2029,
+	0x0000, 0x7874, 0xa065, 0x0040, 0x1c00, 0x1078, 0x1c06, 0x0040,
+	0x1c00, 0x1078, 0x1c17, 0x00c0, 0x1c00, 0x8528, 0x0078, 0x1bf1,
+	0x85ff, 0x0040, 0x1c05, 0x2091, 0x4080, 0x007c, 0x7b94, 0x7998,
+	0x70d4, 0x007e, 0x007f, 0xa102, 0x00c0, 0x1c11, 0x2300, 0xa005,
+	0x007c, 0x0048, 0x1c15, 0xa302, 0x007c, 0x8002, 0x007c, 0x2091,
+	0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1c5b, 0x7008,
+	0x7208, 0xa206, 0x00c0, 0x1c5b, 0xa286, 0x0008, 0x00c0, 0x1c5b,
+	0x2071, 0x0010, 0x1078, 0x1c60, 0x2009, 0x001c, 0x6028, 0xa005,
+	0x0040, 0x1c34, 0x2009, 0x0040, 0x1078, 0x17a5, 0x0040, 0x1c4d,
+	0x78ac, 0x8000, 0x78ae, 0xa086, 0x0002, 0x00c0, 0x1c5b, 0x2091,
+	0x8000, 0x78c7, 0x0003, 0x78af, 0x0000, 0x78b0, 0xa085, 0x0300,
+	0x78b2, 0x2091, 0x8001, 0x0078, 0x1c5b, 0x78af, 0x0000, 0x1078,
+	0x19ba, 0x7994, 0x7898, 0x8000, 0xa10a, 0x00c8, 0x1c58, 0xa006,
+	0x789a, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c,
+	0x8107, 0x8004, 0x8004, 0x7aa0, 0x7b9c, 0x7ca8, 0x7da4, 0xa210,
+	0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x2009,
+	0x3868, 0x2091, 0x8000, 0x200a, 0x0f7e, 0x2079, 0x0100, 0x2009,
+	0x3840, 0x2091, 0x8000, 0x2104, 0xa086, 0x0000, 0x00c0, 0x1c8f,
+	0x2009, 0x3812, 0x2104, 0xa005, 0x00c0, 0x1c8f, 0x7830, 0xa084,
+	0x00c0, 0x00c0, 0x1c8f, 0x0018, 0x1c8f, 0x781b, 0x0045, 0x2091,
+	0x8001, 0x0f7f, 0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x3840,
+	0x2079, 0x0100, 0x784b, 0x000f, 0x2019, 0x3105, 0x20a1, 0x012b,
+	0x2304, 0xa005, 0x0040, 0x1cad, 0x789a, 0x8318, 0x23ac, 0x8318,
+	0x2398, 0x53a6, 0x3318, 0x0078, 0x1ca0, 0x789b, 0x0020, 0x20a9,
+	0x0010, 0x78af, 0x0000, 0x78af, 0x0020, 0x0070, 0x1cb9, 0x0078,
+	0x1cb1, 0x7003, 0x0000, 0x1078, 0x1dbe, 0x7004, 0xa084, 0x000f,
+	0xa085, 0x6280, 0x7806, 0x780f, 0x9200, 0x7843, 0x00d8, 0x7853,
+	0x0080, 0x780b, 0x0008, 0x7047, 0x387f, 0x7043, 0x0000, 0x127f,
+	0x2000, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204, 0xa084,
+	0xfff0, 0xa105, 0x2012, 0x1078, 0x1dbe, 0x007c, 0x2011, 0x0101,
+	0x20a9, 0x0009, 0x810b, 0x0070, 0x1ce7, 0x0078, 0x1ce2, 0xa18c,
+	0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009,
+	0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x1cf8, 0x0078, 0x1cf3,
+	0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c,
+	0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, 0x1d09, 0x0078,
+	0x1d04, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012,
+	0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012,
+	0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100,
+	0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080,
+	0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf,
+	0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e,
+	0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f,
+	0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100,
+	0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f,
+	0x007c, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, 0x1d9a, 0x2061,
+	0x4280, 0x1078, 0x1da0, 0x0040, 0x1d84, 0x20a9, 0x0000, 0x2061,
+	0x4180, 0x0c7e, 0x1078, 0x1da0, 0x0040, 0x1d6e, 0x0c7f, 0x8c60,
+	0x0070, 0x1d6c, 0x0078, 0x1d61, 0x0078, 0x1d9a, 0x007f, 0xa082,
+	0x4180, 0x2071, 0x3840, 0x70ba, 0x6020, 0xa085, 0x0800, 0x6022,
+	0x2091, 0x8001, 0x71b6, 0x2001, 0x0004, 0x70a2, 0x70c7, 0x0005,
+	0x1078, 0x1c6f, 0x0078, 0x1d96, 0x2071, 0x3840, 0x6020, 0xa085,
+	0x0800, 0x6022, 0x2091, 0x8001, 0x71b6, 0x2c00, 0x70be, 0x2001,
+	0x0006, 0x70a2, 0x70c7, 0x0005, 0x1078, 0x1c6f, 0x2001, 0x0000,
+	0x0078, 0x1d9c, 0x2001, 0x0001, 0xa005, 0x0e7f, 0x0c7f, 0x007c,
+	0x2091, 0x8000, 0x2c04, 0xa005, 0x0040, 0x1db9, 0x2060, 0x6010,
+	0xa306, 0x00c0, 0x1db6, 0x600c, 0xa206, 0x00c0, 0x1db6, 0x6014,
+	0xa106, 0x00c0, 0x1db6, 0xa006, 0x0078, 0x1dbd, 0x6000, 0x0078,
+	0x1da3, 0xa085, 0x0001, 0x2091, 0x8001, 0x007c, 0x2011, 0x3841,
+	0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084, 0x0100,
+	0x0040, 0x1dd4, 0x2021, 0xff04, 0x2122, 0x810b, 0x810b, 0x810b,
+	0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, 0x68e4, 0xa08c,
+	0x0020, 0x0040, 0x1e28, 0xa084, 0x0006, 0x00c0, 0x1e28, 0x6014,
+	0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0, 0x3900,
+	0x7004, 0xa084, 0x000a, 0x00c0, 0x1e28, 0x7108, 0xa194, 0xff00,
+	0x0040, 0x1e28, 0xa18c, 0x00ff, 0x2001, 0x000c, 0xa106, 0x0040,
+	0x1e0f, 0x2001, 0x0012, 0xa106, 0x0040, 0x1e13, 0x2001, 0x0014,
+	0xa106, 0x0040, 0x1e17, 0x2001, 0x0019, 0xa106, 0x0040, 0x1e1b,
+	0x2001, 0x0032, 0xa106, 0x0040, 0x1e1f, 0x0078, 0x1e23, 0x2009,
+	0x0012, 0x0078, 0x1e25, 0x2009, 0x0014, 0x0078, 0x1e25, 0x2009,
+	0x0019, 0x0078, 0x1e25, 0x2009, 0x0020, 0x0078, 0x1e25, 0x2009,
+	0x003f, 0x0078, 0x1e25, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a,
+	0x0e7f, 0x007c, 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3,
+	0x8002, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078,
+	0x1e37, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300, 0x7f3c, 0x7e58,
+	0x7c30, 0x7d38, 0x2009, 0x3874, 0x78a0, 0x200a, 0x8108, 0x250a,
+	0x8108, 0x240a, 0x8108, 0x260a, 0x8108, 0x270a, 0xa594, 0x003f,
+	0xa484, 0x4000, 0x0040, 0x1e5a, 0xa784, 0x007c, 0x00c0, 0x308f,
+	0x1078, 0x1e2a, 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x1e62,
+	0x1078, 0x1e2a, 0x8507, 0xa084, 0x000f, 0x0079, 0x1e67, 0x22d0,
+	0x236f, 0x238c, 0x25f7, 0x283b, 0x287e, 0x28c7, 0x2925, 0x29bc,
+	0x2a49, 0x1e8f, 0x1e77, 0x2139, 0x21fe, 0x281a, 0x1e77, 0x1078,
+	0x1e2a, 0x0018, 0x1e3e, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f,
+	0x007c, 0x7003, 0x0000, 0x703f, 0x0000, 0x7030, 0xa005, 0x0040,
+	0x1e8b, 0x7033, 0x0000, 0x1078, 0x306a, 0x0018, 0x1e3e, 0x2009,
+	0x380f, 0x200b, 0x0000, 0x705c, 0xa005, 0x00c0, 0x1f58, 0x70a0,
+	0xa084, 0x0007, 0x0079, 0x1e9c, 0x1f7b, 0x1ea4, 0x1eb2, 0x1ecd,
+	0x1eed, 0x1f36, 0x1f11, 0x1ea4, 0x7808, 0xa084, 0xfffd, 0x780a,
+	0x2009, 0x0047, 0x1078, 0x271f, 0x00c0, 0x1eb0, 0x7003, 0x0004,
+	0x0078, 0x1e79, 0x1078, 0x3051, 0x00c0, 0x1ecb, 0x70b4, 0x8007,
+	0x7882, 0x789b, 0x0010, 0x78ab, 0x000c, 0x789b, 0x0060, 0x78ab,
+	0x0001, 0x785b, 0x0004, 0x2009, 0x00fb, 0x1078, 0x271d, 0x00c0,
+	0x1ecb, 0x7003, 0x0004, 0x0078, 0x1e79, 0x1078, 0x3051, 0x00c0,
+	0x1eeb, 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007,
+	0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab,
+	0x0002, 0x785b, 0x0004, 0x2009, 0x00fb, 0x1078, 0x271d, 0x00c0,
+	0x1eeb, 0x7003, 0x0004, 0x0078, 0x1e79, 0x1078, 0x3051, 0x00c0,
+	0x1f0f, 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007,
+	0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x71b8, 0x79aa, 0x78ab,
+	0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009,
+	0x00fb, 0x1078, 0x271d, 0x00c0, 0x1f0f, 0x7003, 0x0004, 0x0078,
+	0x1e79, 0x1078, 0x3051, 0x00c0, 0x1f34, 0x71b4, 0x8107, 0x7882,
+	0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab,
+	0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b, 0x0004, 0x2009,
+	0x00fb, 0x1078, 0x271d, 0x00c0, 0x1f34, 0x70bc, 0x70bf, 0x0000,
+	0x2068, 0x703e, 0x7003, 0x0002, 0x0078, 0x1e79, 0x1078, 0x3051,
+	0x00c0, 0x1e79, 0x70bc, 0x2068, 0x1078, 0x30f3, 0x789b, 0x0010,
+	0x6814, 0xa084, 0x0007, 0xa085, 0x0080, 0x007e, 0x007f, 0x78aa,
+	0x6e1c, 0x067e, 0x067f, 0x2041, 0x0001, 0x70c0, 0xa084, 0x0400,
+	0x2001, 0x0004, 0x0040, 0x1f56, 0x2001, 0x0006, 0x0078, 0x2057,
+	0x1078, 0x3051, 0x00c0, 0x1e79, 0x789b, 0x0010, 0x705c, 0x2068,
+	0x1078, 0x30f3, 0x6f14, 0x1078, 0x2f99, 0x6008, 0xa085, 0x0010,
+	0x600a, 0xad80, 0x0009, 0x2003, 0x0005, 0x6814, 0xa084, 0x0007,
+	0xa085, 0x0080, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001,
+	0x0003, 0x0078, 0x2057, 0x0018, 0x1e3e, 0x7440, 0xa485, 0x0000,
+	0x0040, 0x1f95, 0xa080, 0x3880, 0x2030, 0x7144, 0x8108, 0xa12a,
+	0x0048, 0x1f8c, 0x2009, 0x3880, 0x2164, 0x6504, 0x85ff, 0x00c0,
+	0x1fa2, 0x8421, 0x00c0, 0x1f86, 0x7146, 0x7003, 0x0000, 0x703f,
+	0x0000, 0x0078, 0x1e79, 0x7640, 0xa6b0, 0x3880, 0x7144, 0x2600,
+	0x0078, 0x1f91, 0x7146, 0x2568, 0x2558, 0x753e, 0x2c50, 0x6708,
+	0x7736, 0xa784, 0x013f, 0x0040, 0x1fcf, 0xa784, 0x0021, 0x00c0,
+	0x1f9f, 0xa784, 0x0002, 0x0040, 0x1fbc, 0xa784, 0x0004, 0x0040,
+	0x1f9f, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0, 0x1f9f,
+	0xa784, 0x0010, 0x00c0, 0x1f9f, 0xa784, 0x0100, 0x0040, 0x1fcf,
+	0x6018, 0xa005, 0x00c0, 0x1f9f, 0xa7bc, 0xfeff, 0x670a, 0x6823,
+	0x0000, 0x6e1c, 0xa684, 0x000e, 0x6118, 0x0040, 0x1fdf, 0x601c,
+	0xa102, 0x0048, 0x1fe2, 0x0040, 0x1fe2, 0x0078, 0x1f9b, 0x81ff,
+	0x00c0, 0x1f9b, 0xa784, 0x0080, 0x00c0, 0x1fe8, 0x700c, 0x6022,
+	0x1078, 0x30f3, 0x0018, 0x1e3e, 0x789b, 0x0010, 0xa046, 0x1078,
+	0x3051, 0x00c0, 0x1e79, 0x6b14, 0xa39c, 0x0007, 0xa39d, 0x00c0,
+	0x704c, 0xa084, 0x8000, 0x0040, 0x2001, 0xa684, 0x0001, 0x0040,
+	0x2003, 0xa39c, 0xffbf, 0xa684, 0x0010, 0x0040, 0x2009, 0xa39d,
+	0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, 0x00c0, 0x2014, 0xa7bd,
+	0x0010, 0x670a, 0x0078, 0x2055, 0x714c, 0xa18c, 0x0800, 0x0040,
+	0x2c2b, 0x2011, 0x0021, 0x8004, 0x8004, 0x0048, 0x202b, 0x2011,
+	0x0022, 0x8004, 0x0048, 0x202b, 0x2011, 0x0020, 0x8004, 0x0048,
+	0x202b, 0x0040, 0x2055, 0x7aaa, 0x8840, 0x1078, 0x306a, 0x6a14,
+	0x610c, 0x8108, 0xa18c, 0x00ff, 0xa1e0, 0x4180, 0x2c64, 0x8cff,
+	0x0040, 0x204c, 0x6014, 0xa206, 0x00c0, 0x2036, 0x60b8, 0x8001,
+	0x60ba, 0x00c0, 0x2031, 0x0c7e, 0x2a60, 0x6008, 0xa085, 0x0100,
+	0x600a, 0x0c7f, 0x0078, 0x1f7b, 0x1078, 0x3051, 0x00c0, 0x1e79,
+	0x2a60, 0x610e, 0x79aa, 0x8840, 0x712e, 0x2001, 0x0001, 0x007e,
+	0x7150, 0xa184, 0x0018, 0x0040, 0x2072, 0xa184, 0x0010, 0x0040,
+	0x2065, 0x1078, 0x2de3, 0x00c0, 0x2095, 0xa184, 0x0008, 0x0040,
+	0x2072, 0x69a0, 0xa184, 0x0600, 0x00c0, 0x2072, 0x1078, 0x2cdf,
+	0x0078, 0x2095, 0x69a0, 0xa184, 0x0800, 0x0040, 0x2089, 0x0c7e,
+	0x027e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d,
+	0x0010, 0x6106, 0x027f, 0x0c7f, 0x1078, 0x2de3, 0x00c0, 0x2095,
+	0x69a0, 0xa184, 0x0200, 0x0040, 0x2091, 0x1078, 0x2d2e, 0x0078,
+	0x2095, 0xa184, 0x0400, 0x00c0, 0x206e, 0x69a0, 0xa184, 0x1000,
+	0x0040, 0x20a0, 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x1d25,
+	0x007f, 0x7002, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x20ae,
+	0xa086, 0x0060, 0x00c0, 0x20ae, 0xa18d, 0x4000, 0x88ff, 0x0040,
+	0x20b3, 0xa18d, 0x0004, 0x795a, 0x69b6, 0x789b, 0x0060, 0x2800,
+	0x78aa, 0x789b, 0x0061, 0x6818, 0xa08d, 0x8000, 0xa084, 0x7fff,
+	0x691a, 0xa68c, 0x0080, 0x0040, 0x20d2, 0x70cb, 0x0000, 0xa08a,
+	0x000d, 0x0050, 0x20d0, 0xa08a, 0x000c, 0x71ca, 0x2001, 0x000c,
+	0x800c, 0x71ce, 0x78aa, 0x8008, 0x810c, 0x0040, 0x2c36, 0xa18c,
+	0x00f8, 0x00c0, 0x2c36, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b,
+	0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6,
+	0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, 0x6d94, 0x7dd6,
+	0x7dde, 0x6e98, 0x7ed2, 0x7eda, 0x7830, 0xa084, 0x00c0, 0x00c0,
+	0x20fb, 0x0098, 0x2103, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078,
+	0x306a, 0x0078, 0x1e81, 0x7200, 0xa284, 0x0007, 0xa086, 0x0001,
+	0x00c0, 0x2110, 0x781b, 0x004a, 0x1078, 0x306a, 0x0078, 0x2121,
+	0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x004a, 0x1078, 0x306a,
+	0x7200, 0x2500, 0xa605, 0x0040, 0x2121, 0xa284, 0x0007, 0x1079,
+	0x212f, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, 0x1e79, 0x6018,
+	0x8000, 0x601a, 0xad80, 0x0009, 0x7032, 0x0078, 0x1e79, 0x2137,
+	0x347d, 0x347d, 0x346c, 0x347d, 0x2137, 0x346c, 0x2137, 0x1078,
+	0x1e2a, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, 0x2079, 0x3800,
+	0x78b0, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x215f, 0x70a0, 0xa086,
+	0x0001, 0x00c0, 0x214e, 0x70a2, 0x0078, 0x21e2, 0x70a0, 0xa086,
+	0x0005, 0x00c0, 0x215d, 0x70bc, 0x2068, 0x681b, 0x0004, 0x6817,
+	0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x70a3, 0x0000, 0x157e,
+	0x2011, 0x0004, 0x71a0, 0xa186, 0x0001, 0x0040, 0x217d, 0xa186,
+	0x0007, 0x00c0, 0x2171, 0x2009, 0x3831, 0x200b, 0x0005, 0x0078,
+	0x217d, 0x2009, 0x3813, 0x2104, 0x2009, 0x3812, 0x200a, 0x2009,
+	0x3831, 0x200b, 0x0001, 0x0078, 0x217f, 0x70a3, 0x0000, 0x1078,
+	0x31f5, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078, 0x2e9a, 0xa7b8,
+	0x0100, 0x0070, 0x218d, 0x0078, 0x2185, 0x7000, 0x0079, 0x2190,
+	0x21be, 0x21a7, 0x21a7, 0x219a, 0x21be, 0x21be, 0x21be, 0x2198,
+	0x1078, 0x1e2a, 0x2021, 0x3857, 0x2404, 0xa005, 0x0040, 0x21be,
+	0xad06, 0x00c0, 0x21a7, 0x6800, 0x2022, 0x0078, 0x21b7, 0x6820,
+	0xa084, 0x0001, 0x00c0, 0x21b3, 0x6f14, 0x1078, 0x2f99, 0x1078,
+	0x2bf8, 0x0078, 0x21b7, 0x7054, 0x2060, 0x6800, 0x6002, 0x6a1a,
+	0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x19a4, 0x2021, 0x4280,
+	0x1078, 0x21e8, 0x2021, 0x3857, 0x1078, 0x21e8, 0x20a9, 0x0000,
+	0x2021, 0x4180, 0x1078, 0x21e8, 0x8420, 0x0070, 0x21d1, 0x0078,
+	0x21ca, 0x20a9, 0x0080, 0x2061, 0x3980, 0x6018, 0x6110, 0xa102,
+	0x6012, 0x601b, 0x0000, 0xace0, 0x0010, 0x0070, 0x21e1, 0x0078,
+	0x21d5, 0x157f, 0x7003, 0x0000, 0x703f, 0x0000, 0x0078, 0x1e79,
+	0x047e, 0x2404, 0xa005, 0x0040, 0x21fa, 0x2068, 0x6800, 0x007e,
+	0x6a1a, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x19a4, 0x007f,
+	0x0078, 0x21ea, 0x047f, 0x2023, 0x0000, 0x007c, 0xa282, 0x0003,
+	0x0050, 0x2204, 0x1078, 0x1e2a, 0x2300, 0x0079, 0x2207, 0x220a,
+	0x2271, 0x228e, 0xa282, 0x0002, 0x0040, 0x2210, 0x1078, 0x1e2a,
+	0x70a0, 0x70a3, 0x0000, 0x0079, 0x2215, 0x221d, 0x221d, 0x221f,
+	0x2251, 0x224f, 0x221d, 0x2251, 0x221d, 0x1078, 0x1e2a, 0x77b4,
+	0x1078, 0x2e9a, 0x77b4, 0xa7bc, 0x0f00, 0x1078, 0x2f99, 0x6018,
+	0xa005, 0x0040, 0x2248, 0x2021, 0x4280, 0x1078, 0x22a9, 0x0040,
+	0x2248, 0x157e, 0x20a9, 0x0000, 0x2021, 0x4180, 0x047e, 0x1078,
+	0x22a9, 0x047f, 0x0040, 0x2241, 0x8420, 0x0070, 0x2241, 0x0078,
+	0x2236, 0x157f, 0x2021, 0x3857, 0x1078, 0x22a9, 0x0040, 0x2248,
+	0x8738, 0xa784, 0x0007, 0x00c0, 0x2225, 0x0078, 0x1e81, 0x0078,
+	0x1e81, 0x77b4, 0x1078, 0x2f99, 0x6018, 0xa005, 0x0040, 0x226f,
+	0x2021, 0x4280, 0x1078, 0x22a9, 0x0040, 0x226f, 0x157e, 0x20a9,
+	0x0000, 0x2021, 0x4180, 0x047e, 0x1078, 0x22a9, 0x047f, 0x0040,
+	0x226e, 0x8420, 0x0070, 0x226e, 0x0078, 0x2263, 0x157f, 0x0078,
+	0x1e81, 0x2200, 0x0079, 0x2274, 0x2277, 0x2279, 0x2279, 0x1078,
+	0x1e2a, 0x2009, 0x0012, 0x70a0, 0xa086, 0x0002, 0x0040, 0x2282,
+	0x2009, 0x000e, 0x6818, 0xa084, 0x8000, 0x0040, 0x2288, 0x691a,
+	0x70a3, 0x0000, 0x70a7, 0x0001, 0x0078, 0x301c, 0x2200, 0x0079,
+	0x2291, 0x2296, 0x2279, 0x2294, 0x1078, 0x1e2a, 0x1078, 0x272c,
+	0x7000, 0xa086, 0x0001, 0x00c0, 0x2bce, 0x1078, 0x2c0e, 0x6008,
+	0xa084, 0xffef, 0x600a, 0x1078, 0x2bc1, 0x0040, 0x2bce, 0x0078,
+	0x1f7b, 0x2404, 0xa005, 0x0040, 0x22cc, 0x2068, 0x2d04, 0x007e,
+	0x6814, 0xa706, 0x0040, 0x22b8, 0x2d20, 0x007f, 0x0078, 0x22aa,
+	0x007f, 0x2022, 0x681b, 0x0004, 0x6820, 0xa085, 0x0010, 0x6822,
+	0x1078, 0x19a4, 0x6010, 0x8001, 0x6012, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x1078, 0x2c0e, 0x007c, 0xa085, 0x0001, 0x0078, 0x22cb,
+	0x2300, 0x0079, 0x22d3, 0x22d8, 0x22d6, 0x2324, 0x1078, 0x1e2a,
+	0x78e4, 0xa005, 0x00d0, 0x22ec, 0x0018, 0x22ec, 0xa084, 0x0007,
+	0x0079, 0x22e2, 0x22fd, 0x230a, 0x22f0, 0x22ea, 0x3044, 0x3044,
+	0x22ea, 0x2317, 0x1078, 0x1e2a, 0x2001, 0x0003, 0x0078, 0x260b,
+	0x6818, 0xa084, 0x8000, 0x0040, 0x22f7, 0x681b, 0x001d, 0x1078,
+	0x2e7d, 0x781b, 0x0053, 0x0078, 0x1e79, 0x6818, 0xa084, 0x8000,
+	0x0040, 0x2304, 0x681b, 0x001d, 0x1078, 0x2e7d, 0x781b, 0x00de,
+	0x0078, 0x1e79, 0x6818, 0xa084, 0x8000, 0x0040, 0x2311, 0x681b,
+	0x001d, 0x1078, 0x2e7d, 0x781b, 0x00e5, 0x0078, 0x1e79, 0x6818,
+	0xa084, 0x8000, 0x0040, 0x231e, 0x681b, 0x001d, 0x1078, 0x2e7d,
+	0x781b, 0x009c, 0x0078, 0x1e79, 0xa584, 0x000f, 0x00c0, 0x2343,
+	0x1078, 0x272c, 0x7000, 0x0079, 0x232d, 0x2335, 0x2337, 0x2335,
+	0x2bce, 0x2bce, 0x2bce, 0x2bce, 0x2335, 0x1078, 0x1e2a, 0x1078,
+	0x2c0e, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2bc1, 0x0040,
+	0x2bce, 0x0078, 0x1f7b, 0x79e4, 0xa005, 0x00d0, 0x22ec, 0x0018,
+	0x22ec, 0xa184, 0x0007, 0x0079, 0x234d, 0x235d, 0x2363, 0x2357,
+	0x2355, 0x3044, 0x3044, 0x2355, 0x303c, 0x1078, 0x1e2a, 0x1078,
+	0x2e85, 0x781b, 0x0053, 0x0078, 0x1e79, 0x1078, 0x2e85, 0x781b,
+	0x00de, 0x0078, 0x1e79, 0x1078, 0x2e85, 0x781b, 0x00e5, 0x0078,
+	0x1e79, 0x1078, 0x2e85, 0x781b, 0x009c, 0x0078, 0x1e79, 0x2300,
+	0x0079, 0x2372, 0x2377, 0x2375, 0x2379, 0x1078, 0x1e2a, 0x0078,
+	0x2925, 0x681b, 0x0008, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0007,
+	0x0079, 0x2382, 0x238a, 0x2363, 0x22f0, 0x301c, 0x3044, 0x3044,
+	0x238a, 0x303c, 0x1078, 0x1e2a, 0xa282, 0x0005, 0x0050, 0x2392,
+	0x1078, 0x1e2a, 0x2300, 0x0079, 0x2395, 0x2398, 0x25bc, 0x25c8,
+	0x2200, 0x0079, 0x239b, 0x23b5, 0x23a2, 0x23b5, 0x23a0, 0x25a1,
+	0x1078, 0x1e2a, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082,
+	0x0020, 0x0048, 0x2e69, 0xa08a, 0x0004, 0x00c8, 0x2e69, 0x0079,
+	0x23b1, 0x2e69, 0x2e69, 0x2e69, 0x2e23, 0x789b, 0x0018, 0x79a8,
+	0xa184, 0x0080, 0x0040, 0x23ca, 0xa184, 0x0018, 0x0040, 0x23c6,
+	0x0078, 0x2e69, 0x7000, 0xa005, 0x00c0, 0x23c0, 0x2011, 0x0004,
+	0x0078, 0x2a57, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x2e69,
+	0x0079, 0x23d2, 0x23e4, 0x23e2, 0x23fc, 0x2400, 0x24b8, 0x2e69,
+	0x2e69, 0x24ba, 0x2e69, 0x2e69, 0x259d, 0x259d, 0x2e69, 0x2e69,
+	0x2e69, 0x259f, 0x1078, 0x1e2a, 0xa684, 0x1000, 0x0040, 0x23f1,
+	0x2001, 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x0099, 0x0078,
+	0x1e79, 0x6818, 0xa084, 0x8000, 0x0040, 0x23fa, 0x681b, 0x001d,
+	0x0078, 0x23e8, 0x0078, 0x301c, 0x681b, 0x001d, 0x0078, 0x2e75,
+	0x6920, 0xa184, 0x8000, 0x00c0, 0x240c, 0x68af, 0x0000, 0x68b3,
+	0x0000, 0xa18d, 0x8000, 0x6922, 0xa684, 0x1800, 0x00c0, 0x244b,
+	0x6820, 0xa084, 0x0001, 0x00c0, 0x2451, 0x6818, 0xa086, 0x0008,
+	0x00c0, 0x241c, 0x681b, 0x0000, 0xa684, 0x0400, 0x0040, 0x24b4,
+	0xa684, 0x0080, 0x0040, 0x2447, 0x70cb, 0x0000, 0x6818, 0xa084,
+	0x003f, 0xa08a, 0x000d, 0x0050, 0x2447, 0xa08a, 0x000c, 0x71ca,
+	0x2001, 0x000c, 0x800c, 0x71ce, 0x789b, 0x0061, 0x78aa, 0x157e,
+	0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac,
+	0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b,
+	0x0056, 0x0078, 0x1e79, 0xa684, 0x1000, 0x0040, 0x2451, 0x0078,
+	0x1e79, 0xa684, 0x0060, 0x0040, 0x24b0, 0xa684, 0x0800, 0x0040,
+	0x24b0, 0xa684, 0x8000, 0x00c0, 0x2461, 0x69b0, 0x6aac, 0x0078,
+	0x247b, 0xa6b4, 0x7fff, 0x7e5a, 0x6eb6, 0x789b, 0x0074, 0x7aac,
+	0x79ac, 0x78ac, 0x801b, 0x00c8, 0x246e, 0x8000, 0xa084, 0x003f,
+	0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94,
+	0x2200, 0xa303, 0x68ae, 0xa684, 0x4000, 0x0040, 0x2483, 0xa6b4,
+	0xbfff, 0x7e5a, 0x6eb6, 0xa006, 0x1078, 0x353b, 0x6ab0, 0x69ac,
+	0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, 0x2492, 0x2200, 0xa422,
+	0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x6ba6, 0x7bd6, 0x2300, 0xa405,
+	0x00c0, 0x24a2, 0xa6b5, 0x4000, 0x7e5a, 0x6eb6, 0x781b, 0x0065,
+	0x0078, 0x1e79, 0x781b, 0x0065, 0x2200, 0xa115, 0x00c0, 0x24ac,
+	0x1078, 0x347d, 0x0078, 0x1e79, 0x1078, 0x34b2, 0x0078, 0x1e79,
+	0x781b, 0x0068, 0x0078, 0x1e79, 0x781b, 0x0056, 0x0078, 0x1e79,
+	0x1078, 0x1e2a, 0x0078, 0x250f, 0x6920, 0xa184, 0x0100, 0x0040,
+	0x24ce, 0xa18c, 0xfeff, 0x6922, 0x0c7e, 0x7048, 0x2060, 0x6004,
+	0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x24fe, 0xa184, 0x0200,
+	0x0040, 0x24fe, 0xa18c, 0xfdff, 0x6922, 0x0c7e, 0x7048, 0x2060,
+	0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184,
+	0x0008, 0x0040, 0x24fe, 0x1078, 0x2f95, 0x1078, 0x2cdf, 0x88ff,
+	0x0040, 0x24fe, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5,
+	0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x24fa, 0x781b, 0x0053,
+	0x0078, 0x1e79, 0x781b, 0x0067, 0x0078, 0x1e79, 0x7e58, 0xa684,
+	0x0400, 0x00c0, 0x2507, 0x781b, 0x0056, 0x0078, 0x1e79, 0x781b,
+	0x0068, 0x0078, 0x1e79, 0x0078, 0x2e6f, 0x0078, 0x2e6f, 0x2019,
+	0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x250d, 0x789b, 0x0010,
+	0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, 0x2532, 0x2300,
+	0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x252a, 0x0048, 0x252a,
+	0x0078, 0x252c, 0x0078, 0x24bc, 0x24a8, 0x7aa8, 0x00f0, 0x252c,
+	0x0078, 0x2518, 0xa284, 0x00f0, 0xa086, 0x0020, 0x00c0, 0x258e,
+	0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x2542, 0x0048, 0x2542,
+	0x0078, 0x258b, 0xa286, 0x0023, 0x0040, 0x250d, 0x681c, 0xa084,
+	0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, 0xa085, 0x0010, 0x2030,
+	0x7e5a, 0x6008, 0xa085, 0x0010, 0x600a, 0x0c7e, 0x7048, 0x2060,
+	0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0010, 0x0040, 0x2566,
+	0x1078, 0x2f95, 0x1078, 0x2de3, 0x0078, 0x2575, 0x0c7e, 0x7048,
+	0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040,
+	0x24fe, 0x1078, 0x2f95, 0x1078, 0x2cdf, 0x88ff, 0x0040, 0x24fe,
+	0x789b, 0x0060, 0x2800, 0x78aa, 0xa6b5, 0x0004, 0x7e5a, 0xa684,
+	0x0400, 0x00c0, 0x2587, 0x781b, 0x0053, 0x0078, 0x1e79, 0x781b,
+	0x0067, 0x0078, 0x1e79, 0x7aa8, 0x0078, 0x2518, 0x8318, 0x2300,
+	0xa102, 0x0040, 0x2597, 0x0048, 0x2597, 0x0078, 0x2518, 0xa284,
+	0x0080, 0x00c0, 0x2e75, 0x0078, 0x2e6f, 0x0078, 0x2e75, 0x0078,
+	0x2e69, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001,
+	0x0040, 0x25ac, 0x1078, 0x1e2a, 0x7aa8, 0xa294, 0x00ff, 0x78a8,
+	0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x2e69, 0x0079, 0x25b8,
+	0x2e69, 0x2c4f, 0x2e69, 0x2d7e, 0xa282, 0x0000, 0x00c0, 0x25c2,
+	0x1078, 0x1e2a, 0x1078, 0x2e7d, 0x781b, 0x0067, 0x0078, 0x1e79,
+	0xa282, 0x0003, 0x00c0, 0x25ce, 0x1078, 0x1e2a, 0xa484, 0x8000,
+	0x00c0, 0x25f1, 0x70a0, 0xa005, 0x0040, 0x25d8, 0x1078, 0x1e2a,
+	0x6f14, 0x77b6, 0xa7bc, 0x0f00, 0x1078, 0x2f99, 0x6008, 0xa085,
+	0x0021, 0x600a, 0x8738, 0xa784, 0x0007, 0x00c0, 0x25dc, 0x1078,
+	0x2e81, 0x70a3, 0x0002, 0x2009, 0x3831, 0x200b, 0x0009, 0x0078,
+	0x25f3, 0x1078, 0x2e8d, 0x781b, 0x0067, 0x0078, 0x1e79, 0xa282,
+	0x0004, 0x0050, 0x25fd, 0x1078, 0x1e2a, 0x2300, 0x0079, 0x2600,
+	0x2603, 0x26df, 0x2707, 0xa286, 0x0003, 0x0040, 0x2609, 0x1078,
+	0x1e2a, 0x2001, 0x0000, 0x703a, 0x7000, 0xa084, 0x0007, 0x0079,
+	0x2611, 0x2619, 0x261b, 0x261b, 0x27cf, 0x2800, 0x1e81, 0x2800,
+	0x2619, 0x1078, 0x1e2a, 0xa684, 0x1000, 0x00c0, 0x2623, 0x1078,
+	0x31f5, 0x0040, 0x26b9, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x266b,
+	0xa186, 0x0008, 0x00c0, 0x263a, 0x1078, 0x2c0e, 0x6008, 0xa084,
+	0xffef, 0x600a, 0x1078, 0x2bc1, 0x0040, 0x266b, 0x1078, 0x31f5,
+	0x0078, 0x2652, 0xa186, 0x0028, 0x00c0, 0x266b, 0x1078, 0x31f5,
+	0x6008, 0xa084, 0xffef, 0x600a, 0x6018, 0xa005, 0x0040, 0x2652,
+	0x8001, 0x601a, 0xa005, 0x0040, 0x2652, 0x8001, 0xa005, 0x0040,
+	0x2652, 0x601e, 0x6820, 0xa084, 0x0001, 0x0040, 0x1e81, 0x6820,
+	0xa084, 0xfffe, 0x6822, 0x7054, 0x0c7e, 0x2060, 0x6800, 0x6002,
+	0x0c7f, 0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, 0x2668, 0x6002,
+	0x6006, 0x0078, 0x1e81, 0x017e, 0x1078, 0x272c, 0x017f, 0xa684,
+	0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14, 0x81ff, 0x0040, 0x26b9,
+	0xa186, 0x0002, 0x00c0, 0x26b1, 0xa684, 0x0800, 0x00c0, 0x2688,
+	0xa684, 0x0060, 0x0040, 0x2688, 0x78d8, 0x7adc, 0x682e, 0x6a32,
+	0x6820, 0xa084, 0x0800, 0x00c0, 0x26b9, 0x8717, 0xa294, 0x000f,
+	0x8213, 0x8213, 0x8213, 0xa290, 0x3900, 0xa290, 0x0000, 0x221c,
+	0x8210, 0x2204, 0xa085, 0x0018, 0x2012, 0x8211, 0xa384, 0x0400,
+	0x0040, 0x26ab, 0x68a0, 0xa084, 0x0100, 0x00c0, 0x26ab, 0x1078,
+	0x278e, 0x0078, 0x1e81, 0x6008, 0xa085, 0x0002, 0x600a, 0x0078,
+	0x26b9, 0xa186, 0x0018, 0x0040, 0x26b9, 0xa186, 0x0014, 0x0040,
+	0x1e81, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, 0x26c1, 0x7038,
+	0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078, 0x2bff, 0x1078, 0x2c0e,
+	0x00c0, 0x26ce, 0x6008, 0xa084, 0xffef, 0x600a, 0x6820, 0xa084,
+	0x0001, 0x00c0, 0x26d7, 0x1078, 0x2bf8, 0x0078, 0x26db, 0x7054,
+	0x2060, 0x6800, 0x6002, 0x1078, 0x19a4, 0x0078, 0x1e81, 0xa282,
+	0x0004, 0x0048, 0x26e5, 0x1078, 0x1e2a, 0x2200, 0x0079, 0x26e8,
+	0x26e3, 0x26ec, 0x26f2, 0x26ec, 0x1078, 0x2e7d, 0x781b, 0x0067,
+	0x0078, 0x1e79, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080,
+	0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0040,
+	0x2703, 0x0078, 0x2e69, 0x781b, 0x0068, 0x0078, 0x1e79, 0x6820,
+	0xa085, 0x0004, 0x6822, 0x82ff, 0x00c0, 0x2712, 0x1078, 0x2e7d,
+	0x0078, 0x2719, 0x8211, 0x0040, 0x2717, 0x1078, 0x1e2a, 0x1078,
+	0x2e8d, 0x781b, 0x0067, 0x0078, 0x1e79, 0x1078, 0x306a, 0x7830,
+	0xa084, 0x00c0, 0x00c0, 0x2729, 0x0018, 0x2729, 0x791a, 0xa006,
+	0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060, 0x00c0, 0x2736,
+	0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x278d, 0xa684, 0x0800,
+	0x00c0, 0x2746, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7000, 0xa086,
+	0x0006, 0x0040, 0x2745, 0x1078, 0x31f5, 0x007c, 0xa684, 0x0020,
+	0x0040, 0x2760, 0xa684, 0x4000, 0x0040, 0x2754, 0x682f, 0x0000,
+	0x6833, 0x0000, 0x0078, 0x273e, 0x7038, 0xa005, 0x00c0, 0x275a,
+	0x703b, 0x0015, 0x79d8, 0x7adc, 0x692e, 0x6a32, 0x0078, 0x273e,
+	0xa684, 0x4000, 0x0040, 0x276a, 0x682f, 0x0000, 0x6833, 0x0000,
+	0x0078, 0x273e, 0x7038, 0xa005, 0x00c0, 0x2770, 0x703b, 0x0015,
+	0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8, 0x2777, 0x8000, 0xa084,
+	0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205,
+	0x00c0, 0x2784, 0x0078, 0x273e, 0x7000, 0xa086, 0x0006, 0x0040,
+	0x278d, 0x1078, 0x353b, 0x0078, 0x273e, 0x007c, 0xa384, 0x0200,
+	0x0040, 0x2796, 0x6008, 0xa085, 0x0002, 0x600a, 0x681b, 0x0006,
+	0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, 0x0000,
+	0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, 0x7000, 0x0079,
+	0x27a9, 0x27b1, 0x27b3, 0x27bc, 0x27b1, 0x27b1, 0x27b1, 0x27b1,
+	0x27b1, 0x1078, 0x1e2a, 0x6820, 0xa084, 0x0001, 0x00c0, 0x27bc,
+	0x1078, 0x2bf8, 0x0078, 0x27c2, 0x7054, 0x2c50, 0x2060, 0x6800,
+	0x6002, 0x2a60, 0x2021, 0x3857, 0x2404, 0xa005, 0x0040, 0x27cb,
+	0x2020, 0x0078, 0x27c4, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078,
+	0x2bff, 0x1078, 0x2c0e, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14,
+	0x6817, 0x0002, 0x1078, 0x3575, 0xa684, 0x0800, 0x0040, 0x27e4,
+	0x691c, 0xa18d, 0x2000, 0x691e, 0x6818, 0xa084, 0x8000, 0x0040,
+	0x27f4, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x27f2, 0x681b, 0x001e,
+	0x0078, 0x27f4, 0x681b, 0x0000, 0x2021, 0x3857, 0x6800, 0x2022,
+	0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x19a4, 0x0078, 0x1e81,
+	0x1078, 0x272c, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078,
+	0x306f, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040,
+	0x2813, 0x7038, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x70a3, 0x0000,
+	0x0078, 0x1e81, 0xa006, 0x1078, 0x31f5, 0x6817, 0x0000, 0x681b,
+	0x0001, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x7000, 0x0079,
+	0x2829, 0x2831, 0x2833, 0x2833, 0x2835, 0x2835, 0x2835, 0x2835,
+	0x2831, 0x1078, 0x1e2a, 0x1078, 0x2c0e, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x0078, 0x2bd9, 0x2300, 0x0079, 0x283e, 0x2841, 0x2843,
+	0x287c, 0x1078, 0x1e2a, 0x7000, 0x0079, 0x2846, 0x284e, 0x2850,
+	0x2850, 0x286b, 0x2850, 0x2878, 0x286b, 0x284e, 0x1078, 0x1e2a,
+	0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, 0x2867, 0xa6b4, 0xffdf,
+	0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffdf,
+	0x681e, 0x1078, 0x31f5, 0x1078, 0x347d, 0x0078, 0x301c, 0xa684,
+	0x2000, 0x0040, 0x285a, 0x6818, 0xa084, 0x8000, 0x0040, 0x2878,
+	0x681b, 0x0015, 0xa684, 0x4000, 0x0040, 0x2878, 0x681b, 0x0007,
+	0x781b, 0x00df, 0x0078, 0x1e79, 0x1078, 0x1e2a, 0x2300, 0x0079,
+	0x2881, 0x2884, 0x2886, 0x28b9, 0x1078, 0x1e2a, 0x7000, 0x0079,
+	0x2889, 0x2891, 0x2893, 0x2893, 0x28ae, 0x2893, 0x28b5, 0x28ae,
+	0x2891, 0x1078, 0x1e2a, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0,
+	0x28aa, 0xa6b4, 0xffbf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a,
+	0x681c, 0xa084, 0xffbf, 0x681e, 0x1078, 0x31f5, 0x1078, 0x347d,
+	0x0078, 0x301c, 0xa684, 0x2000, 0x0040, 0x289d, 0x6818, 0xa084,
+	0x8000, 0x0040, 0x28b5, 0x681b, 0x0007, 0x781b, 0x00e6, 0x0078,
+	0x1e79, 0x6820, 0xa085, 0x0004, 0x6822, 0x1078, 0x2fe7, 0xa6b5,
+	0x0800, 0x1078, 0x2e7d, 0x781b, 0x0067, 0x0078, 0x1e79, 0x2300,
+	0x0079, 0x28ca, 0x28cd, 0x28cf, 0x28d1, 0x1078, 0x1e2a, 0x1078,
+	0x1e2a, 0x782b, 0x3009, 0xa684, 0x0400, 0x00c0, 0x28eb, 0x789b,
+	0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xa184,
+	0x0020, 0x00c0, 0x28e7, 0x2001, 0x0014, 0x0078, 0x260b, 0xa184,
+	0x0007, 0x0079, 0x291b, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060,
+	0x79a8, 0x81ff, 0x0040, 0x2919, 0x789b, 0x0010, 0x7ba8, 0xa384,
+	0x0001, 0x00c0, 0x2912, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0,
+	0x2905, 0x2009, 0xfff7, 0x0078, 0x290b, 0xa386, 0x0003, 0x00c0,
+	0x2912, 0x2009, 0xffef, 0x0c7e, 0x7048, 0x2060, 0x6004, 0xa104,
+	0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb,
+	0x785a, 0x0078, 0x301c, 0x22fd, 0x230a, 0x3024, 0x3024, 0x2923,
+	0x2923, 0x2923, 0x3024, 0x1078, 0x1e2a, 0x79e4, 0xa184, 0x0030,
+	0x00c0, 0x293b, 0x70a0, 0xa086, 0x0002, 0x00c0, 0x2933, 0x2011,
+	0x0002, 0x0078, 0x21fe, 0x6818, 0xa085, 0x8000, 0x681a, 0x2001,
+	0x0014, 0x0078, 0x260b, 0xa18c, 0x0007, 0xa186, 0x0002, 0x00c0,
+	0x3044, 0xa684, 0x0080, 0x0040, 0x2970, 0x71c8, 0x81ff, 0x0040,
+	0x2970, 0xa182, 0x000d, 0x00d0, 0x2951, 0x70cb, 0x0000, 0x0078,
+	0x2956, 0xa182, 0x000c, 0x70ca, 0x2009, 0x000c, 0x789b, 0x0061,
+	0x79aa, 0x157e, 0x137e, 0x147e, 0x70cc, 0x8114, 0xa210, 0x72ce,
+	0xa080, 0x000b, 0xad00, 0x2098, 0x20a1, 0x012b, 0x789b, 0x0000,
+	0x8108, 0x81ac, 0x53a6, 0x147f, 0x137f, 0x157f, 0x0078, 0x3024,
+	0xa684, 0x0400, 0x00c0, 0x29b1, 0x6820, 0xa084, 0x0001, 0x0040,
+	0x3024, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, 0x2985, 0xa086,
+	0x0060, 0x00c0, 0x2985, 0xa18d, 0x4000, 0xa18c, 0xfffb, 0x795a,
+	0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818,
+	0xa085, 0x8000, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, 0x2c36,
+	0xa18c, 0x00f8, 0x00c0, 0x2c36, 0x157e, 0x137e, 0x147e, 0x20a1,
+	0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098,
+	0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, 0x0078,
+	0x3024, 0x6818, 0xa084, 0x8000, 0x0040, 0x29b8, 0x681b, 0x0008,
+	0x781b, 0x00da, 0x0078, 0x1e79, 0x2300, 0x0079, 0x29bf, 0x29c4,
+	0x2a47, 0x29c2, 0x1078, 0x1e2a, 0x7000, 0xa084, 0x0007, 0x0079,
+	0x29c9, 0x29d1, 0x29d3, 0x29ef, 0x29d1, 0x29d1, 0x1e81, 0x29d1,
+	0x29d1, 0x1078, 0x1e2a, 0x6920, 0xa18d, 0x0001, 0x6922, 0x6800,
+	0x6006, 0xa005, 0x00c0, 0x29dd, 0x6002, 0x681c, 0xa084, 0x000e,
+	0x0040, 0x29e9, 0x7014, 0x68ba, 0x712c, 0xa188, 0x4180, 0x0078,
+	0x29eb, 0x2009, 0x4280, 0x2104, 0x6802, 0x2d0a, 0x7156, 0x6920,
+	0xa184, 0x8000, 0x00c0, 0x29fb, 0x68af, 0x0000, 0x68b3, 0x0000,
+	0xa18d, 0x8000, 0x6922, 0x6eb6, 0xa684, 0x0060, 0x0040, 0x2a45,
+	0xa684, 0x0800, 0x00c0, 0x2a0c, 0x6894, 0x68a6, 0x6898, 0x68aa,
+	0x1078, 0x31f5, 0x0078, 0x2a45, 0xa684, 0x0020, 0x0040, 0x2a19,
+	0xa006, 0x1078, 0x353b, 0x79d8, 0x7adc, 0x69aa, 0x6aa6, 0x0078,
+	0x2a1f, 0x1078, 0x2fa6, 0x69aa, 0x6aa6, 0x1078, 0x353b, 0xa684,
+	0x8000, 0x0040, 0x2a45, 0xa684, 0x7fff, 0x68b6, 0x789b, 0x0074,
+	0x1078, 0x306f, 0x2010, 0x1078, 0x306f, 0x2008, 0xa684, 0x0020,
+	0x00c0, 0x2a3d, 0x1078, 0x306f, 0x801b, 0x00c8, 0x2a38, 0x8000,
+	0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302,
+	0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x0078, 0x1e81, 0x0078,
+	0x2e75, 0x7033, 0x0000, 0xa282, 0x0006, 0x0050, 0x2a51, 0x1078,
+	0x1e2a, 0x2300, 0x0079, 0x2a54, 0x2a57, 0x2a7d, 0x2aa1, 0x2200,
+	0x0079, 0x2a5a, 0x2a60, 0x2e75, 0x2a62, 0x2a60, 0x2acb, 0x2b1c,
+	0x1078, 0x1e2a, 0x7003, 0x0005, 0x2001, 0x4290, 0x2068, 0x703e,
+	0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x2a72,
+	0x0078, 0x2a6b, 0x157f, 0x6817, 0x0000, 0x68b7, 0x0700, 0x6823,
+	0x0800, 0x6827, 0x0003, 0x0078, 0x2e69, 0x7000, 0xa086, 0x0001,
+	0x00c0, 0x2a8a, 0x1078, 0x2c0e, 0x1078, 0x31f5, 0x7034, 0x600a,
+	0x0078, 0x2a8f, 0x7000, 0xa086, 0x0003, 0x0040, 0x2a84, 0x7003,
+	0x0005, 0x2001, 0x4290, 0x2068, 0x703e, 0x7032, 0x2200, 0x0079,
+	0x2a99, 0x2e75, 0x2a9f, 0x2a9f, 0x2acb, 0x2a9f, 0x2e75, 0x1078,
+	0x1e2a, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2aae, 0x1078, 0x2c0e,
+	0x1078, 0x31f5, 0x7034, 0x600a, 0x0078, 0x2ab3, 0x7000, 0xa086,
+	0x0003, 0x0040, 0x2aa8, 0x7003, 0x0005, 0x2001, 0x4290, 0x2068,
+	0x703e, 0x7032, 0x2200, 0x0079, 0x2abd, 0x2ac5, 0x2ac3, 0x2ac3,
+	0x2ac5, 0x2ac3, 0x2ac5, 0x1078, 0x1e2a, 0x1078, 0x2e8d, 0x781b,
+	0x0067, 0x0078, 0x1e79, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2ad8,
+	0x1078, 0x2c0e, 0x1078, 0x31f5, 0x7034, 0x600a, 0x0078, 0x2add,
+	0x7000, 0xa086, 0x0003, 0x0040, 0x2ad2, 0x7003, 0x0002, 0x7a80,
+	0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215,
+	0x2069, 0x4280, 0x2d04, 0x2d08, 0x7156, 0x2068, 0xa005, 0x0040,
+	0x2af8, 0x6814, 0xa206, 0x0040, 0x2b11, 0x6800, 0x0078, 0x2aeb,
+	0x7003, 0x0005, 0x2001, 0x4290, 0x2068, 0x703e, 0x7032, 0x157e,
+	0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x2b09, 0x0078,
+	0x2b02, 0x157f, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827,
+	0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x2b7a,
+	0x1078, 0x2e85, 0x0078, 0x2b7a, 0x7000, 0xa086, 0x0001, 0x00c0,
+	0x2b29, 0x1078, 0x2c0e, 0x1078, 0x31f5, 0x7034, 0x600a, 0x0078,
+	0x2b2e, 0x7000, 0xa086, 0x0003, 0x0040, 0x2b23, 0x7003, 0x0002,
+	0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007,
+	0xa215, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0xa1e8, 0x4180, 0x2d04,
+	0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, 0x2b4d, 0x6814, 0xa206,
+	0x0040, 0x2b65, 0x6800, 0x0078, 0x2b40, 0x7003, 0x0005, 0x2001,
+	0x4290, 0x2068, 0x703e, 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000,
+	0x8000, 0x0070, 0x2b5d, 0x0078, 0x2b56, 0x157f, 0x6a16, 0x68b7,
+	0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820,
+	0xa084, 0x0c00, 0x0040, 0x2b7a, 0xa084, 0x0800, 0x0040, 0x2b74,
+	0x1078, 0x2e89, 0x0078, 0x2b7a, 0x1078, 0x2e85, 0x70bf, 0x0000,
+	0x0078, 0x2b7a, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003,
+	0x8003, 0xa080, 0x3900, 0x2060, 0x704a, 0x6000, 0x704e, 0x6004,
+	0x7052, 0xa684, 0x0060, 0x0040, 0x2b93, 0x68a8, 0x78d2, 0x78da,
+	0x68a4, 0x78d6, 0x78de, 0x077f, 0x1078, 0x2f99, 0x2009, 0x0068,
+	0xa684, 0x0008, 0x0040, 0x2b9e, 0x2009, 0x0067, 0xa6b5, 0x2000,
+	0x7e5a, 0x791a, 0xa684, 0x0060, 0x0040, 0x2bb4, 0xa684, 0x0800,
+	0x00c0, 0x2bae, 0x1078, 0x347d, 0x0078, 0x2bb4, 0xa684, 0x4000,
+	0x00c0, 0x2bb4, 0x1078, 0x340e, 0x2d00, 0x703e, 0x8207, 0xa084,
+	0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3900, 0x2048, 0x0078,
+	0x1e79, 0x6020, 0xa005, 0x0040, 0x2bcd, 0x8001, 0x6022, 0x6008,
+	0xa085, 0x0008, 0x600a, 0x7010, 0x6026, 0x007c, 0xa006, 0x1078,
+	0x31f5, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040, 0x681f,
+	0x0100, 0x7000, 0xa084, 0x0007, 0x0079, 0x2bde, 0x2be6, 0x2be8,
+	0x2be8, 0x2bf4, 0x2bf0, 0x2be6, 0x2bf0, 0x2be6, 0x1078, 0x1e2a,
+	0x1078, 0x2bff, 0x1078, 0x2bf8, 0x1078, 0x19a4, 0x0078, 0x1e81,
+	0x70a3, 0x0000, 0x0078, 0x1e81, 0x681b, 0x0000, 0x0078, 0x27cf,
+	0x6800, 0xa005, 0x00c0, 0x2bfd, 0x6002, 0x6006, 0x007c, 0x6010,
+	0xa005, 0x0040, 0x2c08, 0x8001, 0x00d0, 0x2c08, 0x1078, 0x1e2a,
+	0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x007c, 0x6018, 0xa005,
+	0x0040, 0x2c14, 0x8001, 0x601a, 0x007c, 0x1078, 0x306a, 0x6818,
+	0xa084, 0x8000, 0x0040, 0x2c1e, 0x681b, 0x0018, 0x0078, 0x2c43,
+	0x1078, 0x306a, 0x6818, 0xa084, 0x8000, 0x0040, 0x2c29, 0x681b,
+	0x0019, 0x0078, 0x2c43, 0x1078, 0x306a, 0x6818, 0xa084, 0x8000,
+	0x0040, 0x2c34, 0x681b, 0x001a, 0x0078, 0x2c43, 0x1078, 0x306a,
+	0x681b, 0x0003, 0x0078, 0x2c43, 0x6818, 0xa084, 0x8000, 0x0040,
+	0x2c43, 0x681b, 0x0005, 0x681f, 0x0000, 0x6823, 0x0020, 0x1078,
+	0x2bff, 0x1078, 0x2bf8, 0x1078, 0x19a4, 0x0078, 0x1e81, 0xa282,
+	0x0003, 0x00c0, 0x2e69, 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4,
+	0x00ff, 0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0100, 0x0040,
+	0x2c92, 0xa18c, 0xfeff, 0x6922, 0xa6b4, 0x00ff, 0x0040, 0x2c7c,
+	0xa682, 0x000c, 0x0048, 0x2c70, 0x0040, 0x2c70, 0x2031, 0x000c,
+	0x852b, 0x852b, 0x1078, 0x2f18, 0x0040, 0x2c7a, 0x1078, 0x2d4a,
+	0x0078, 0x2c85, 0x1078, 0x2ed3, 0x0c7e, 0x2960, 0x6004, 0xa084,
+	0xfff5, 0x6006, 0x1078, 0x2d6e, 0x0c7f, 0x7e58, 0xa684, 0x0400,
+	0x00c0, 0x2c8e, 0x781b, 0x0056, 0x0078, 0x1e79, 0x781b, 0x0068,
+	0x0078, 0x1e79, 0x0c7e, 0x7048, 0x2060, 0x6100, 0xa18c, 0x1000,
+	0x0040, 0x2cd2, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c,
+	0x0048, 0x2ca6, 0x0040, 0x2ca6, 0x2011, 0x000c, 0x2600, 0xa202,
+	0x00c8, 0x2cab, 0x2230, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086,
+	0x0028, 0x00c0, 0x2cbb, 0xa282, 0x0019, 0x00c8, 0x2cc1, 0x2011,
+	0x0019, 0x0078, 0x2cc1, 0xa282, 0x000c, 0x00c8, 0x2cc1, 0x2011,
+	0x000c, 0x2200, 0xa502, 0x00c8, 0x2cc6, 0x2228, 0x1078, 0x2ed7,
+	0x852b, 0x852b, 0x1078, 0x2f18, 0x0040, 0x2cd2, 0x1078, 0x2d4a,
+	0x0078, 0x2cd6, 0x1078, 0x2ed3, 0x1078, 0x2d6e, 0x7858, 0xa085,
+	0x0004, 0x785a, 0x0c7f, 0x781b, 0x0067, 0x0078, 0x1e79, 0x0c7e,
+	0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x2cf7, 0x6010, 0xa084,
+	0x000f, 0x00c0, 0x2cf1, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x0c7f,
+	0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x2d1e, 0x68a0,
+	0xa084, 0x0200, 0x00c0, 0x2cf1, 0x6208, 0xa294, 0x00ff, 0x7018,
+	0xa086, 0x0028, 0x00c0, 0x2d0c, 0xa282, 0x0019, 0x00c8, 0x2d12,
+	0x2011, 0x0019, 0x0078, 0x2d12, 0xa282, 0x000c, 0x00c8, 0x2d12,
+	0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c,
+	0x0048, 0x2d1e, 0x0040, 0x2d1e, 0x2019, 0x000c, 0x78ab, 0x0001,
+	0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005,
+	0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x2960,
+	0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000,
+	0x0078, 0x2d3a, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001,
+	0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822,
+	0x0c7f, 0x007c, 0x0c7e, 0x7148, 0x2160, 0x2008, 0xa084, 0xfff0,
+	0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084,
+	0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016, 0x788a, 0xa6b4,
+	0x000f, 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605, 0x600e,
+	0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e, 0x7048,
+	0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012,
+	0x7884, 0xa084, 0xfff0, 0x7886, 0x0c7f, 0x007c, 0xa282, 0x0002,
+	0x00c0, 0x2e69, 0x7aa8, 0x6920, 0xa18d, 0x0080, 0x6922, 0xa184,
+	0x0200, 0x0040, 0x2dc3, 0xa18c, 0xfdff, 0x6922, 0xa294, 0x00ff,
+	0xa282, 0x0002, 0x00c8, 0x2e69, 0x1078, 0x2e0a, 0x1078, 0x2d6e,
+	0xa980, 0x0001, 0x200c, 0x1078, 0x2f95, 0x1078, 0x2cdf, 0x88ff,
+	0x0040, 0x2db6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5,
+	0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2db2, 0x781b, 0x0053,
+	0x0078, 0x1e79, 0x781b, 0x0067, 0x0078, 0x1e79, 0x7e58, 0xa684,
+	0x0400, 0x00c0, 0x2dbf, 0x781b, 0x0056, 0x0078, 0x1e79, 0x781b,
+	0x0068, 0x0078, 0x1e79, 0xa282, 0x0002, 0x00c8, 0x2dcb, 0xa284,
+	0x0001, 0x0040, 0x2dd5, 0x7148, 0xa188, 0x0000, 0x210c, 0xa18c,
+	0x2000, 0x00c0, 0x2dd5, 0x2011, 0x0000, 0x1078, 0x2ec5, 0x1078,
+	0x2e0a, 0x1078, 0x2d6e, 0x7858, 0xa085, 0x0004, 0x785a, 0x781b,
+	0x0067, 0x0078, 0x1e79, 0x0c7e, 0x027e, 0x2960, 0x6000, 0x2011,
+	0x0001, 0xa084, 0x2000, 0x00c0, 0x2dfa, 0x6014, 0xa084, 0x0040,
+	0x00c0, 0x2df8, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078, 0x2e07,
+	0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003,
+	0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085, 0x0200, 0x6822, 0x027f,
+	0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x82ff, 0x0040, 0x2e12,
+	0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084,
+	0xffbf, 0xa205, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, 0xffef,
+	0x6006, 0x0c7f, 0x007c, 0xa684, 0x0020, 0x0040, 0x2e65, 0x7888,
+	0xa084, 0x0040, 0x0040, 0x2e65, 0x7bb8, 0xa384, 0x003f, 0x831b,
+	0x00c8, 0x2e33, 0x8000, 0xa005, 0x0040, 0x2e4c, 0x831b, 0x00c8,
+	0x2e3c, 0x8001, 0x0040, 0x2e61, 0xa684, 0x4000, 0x0040, 0x2e4c,
+	0x78b8, 0x801b, 0x00c8, 0x2e45, 0x8000, 0xa084, 0x003f, 0x00c0,
+	0x2e61, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001,
+	0xa108, 0x00c8, 0x2e55, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6,
+	0x7ade, 0x1078, 0x353b, 0x781b, 0x0065, 0x1078, 0x340e, 0x0078,
+	0x1e79, 0x781b, 0x0065, 0x0078, 0x1e79, 0x781b, 0x0068, 0x0078,
+	0x1e79, 0x1078, 0x2e91, 0x781b, 0x0067, 0x0078, 0x1e79, 0x1078,
+	0x2e7d, 0x781b, 0x0067, 0x0078, 0x1e79, 0x6827, 0x0002, 0x1078,
+	0x2e85, 0x781b, 0x0067, 0x0078, 0x1e79, 0x2001, 0x0005, 0x0078,
+	0x2e93, 0x2001, 0x000c, 0x0078, 0x2e93, 0x2001, 0x0006, 0x0078,
+	0x2e93, 0x2001, 0x000d, 0x0078, 0x2e93, 0x2001, 0x0009, 0x0078,
+	0x2e93, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xa6b5, 0x0008,
+	0x7e5a, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b,
+	0x8703, 0xa0e0, 0x3900, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184,
+	0x000f, 0x0040, 0x2eb3, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004,
+	0xa085, 0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184,
+	0x0040, 0x0040, 0x2ec3, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004,
+	0xa085, 0x0010, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab,
+	0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060,
+	0x78ab, 0x0004, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b,
+	0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa,
+	0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007,
+	0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4,
+	0xa18c, 0xfff0, 0x2001, 0x3846, 0x2004, 0xa082, 0x0028, 0x0040,
+	0x2f01, 0x2021, 0x2f7c, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078,
+	0x2f07, 0x2021, 0x2f88, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011,
+	0x0064, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x2f16, 0x8420,
+	0x2300, 0xa210, 0x0070, 0x2f16, 0x0078, 0x2f09, 0x157f, 0x007c,
+	0x157e, 0x2011, 0x3846, 0x2214, 0xa282, 0x0032, 0x0048, 0x2f2c,
+	0x0040, 0x2f30, 0x2021, 0x2f6e, 0x2019, 0x0011, 0x20a9, 0x000e,
+	0x2011, 0x0032, 0x0078, 0x2f42, 0xa282, 0x0028, 0x0040, 0x2f3a,
+	0x2021, 0x2f7c, 0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064,
+	0x0078, 0x2f42, 0x2021, 0x2f88, 0x2019, 0x0019, 0x20a9, 0x000d,
+	0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x2f52, 0x0048, 0x2f52,
+	0x8420, 0x2300, 0xa210, 0x0070, 0x2f4f, 0x0078, 0x2f42, 0x157f,
+	0xa006, 0x007c, 0x157f, 0x7a08, 0xa582, 0x00c8, 0x00c8, 0x2f5d,
+	0xa285, 0x0040, 0x780a, 0x0078, 0x2f5d, 0x78ec, 0xa084, 0x0300,
+	0x0040, 0x2f6b, 0x2404, 0xa09e, 0x2002, 0x00c0, 0x2f6b, 0x2001,
+	0x2101, 0x0078, 0x2f6c, 0x2404, 0xa005, 0x007c, 0x2002, 0x3002,
+	0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806,
+	0x7a06, 0x0a07, 0x0c07, 0x0e07, 0x3202, 0x4202, 0x5202, 0x6202,
+	0x7202, 0x6605, 0x7605, 0x7805, 0x7a05, 0x7c05, 0x7e05, 0x7f05,
+	0x2202, 0x3202, 0x4202, 0x5202, 0x5404, 0x6404, 0x7404, 0x7604,
+	0x7804, 0x7a04, 0x7c04, 0x7e04, 0x7f04, 0x789b, 0x0010, 0xa046,
+	0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, 0x8003,
+	0x8003, 0x8003, 0xa105, 0xa0e0, 0x3980, 0x007c, 0x79d8, 0x7adc,
+	0x78d0, 0x801b, 0x00c8, 0x2fad, 0x8000, 0xa084, 0x003f, 0xa108,
+	0xa291, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3840,
+	0x2091, 0x8000, 0x2104, 0x0079, 0x2fbd, 0x2fe3, 0x2fc7, 0x2fc7,
+	0x2fc7, 0x2fc7, 0x2fc7, 0x2fc7, 0x2fc5, 0x1078, 0x1e2a, 0x784b,
+	0x0004, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858, 0xa085, 0x4000,
+	0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x2fe3, 0x0018, 0x2fe3,
+	0x681c, 0xa084, 0x0020, 0x00c0, 0x2fe1, 0x781b, 0x00df, 0x0078,
+	0x2fe3, 0x781b, 0x00e6, 0x2091, 0x8001, 0x0f7f, 0x007c, 0x0c7e,
+	0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0,
+	0x3900, 0x6004, 0xa084, 0x000a, 0x00c0, 0x301a, 0x6108, 0xa194,
+	0xff00, 0x0040, 0x301a, 0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106,
+	0x0040, 0x3009, 0x2001, 0x0032, 0xa106, 0x0040, 0x300d, 0x0078,
+	0x3011, 0x2009, 0x0020, 0x0078, 0x3013, 0x2009, 0x003f, 0x0078,
+	0x3013, 0x2011, 0x0000, 0x2100, 0xa205, 0x600a, 0x6004, 0xa085,
+	0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b, 0x0068, 0x0078, 0x1e79,
+	0x781b, 0x0067, 0x0078, 0x1e79, 0x781b, 0x0056, 0x0078, 0x1e79,
+	0x781b, 0x0053, 0x0078, 0x1e79, 0x781b, 0x00df, 0x0078, 0x1e79,
+	0x781b, 0x00de, 0x0078, 0x1e79, 0x781b, 0x00e6, 0x0078, 0x1e79,
+	0x781b, 0x00e5, 0x0078, 0x1e79, 0x781b, 0x009d, 0x0078, 0x1e79,
+	0x781b, 0x009c, 0x0078, 0x1e79, 0x6818, 0xa084, 0x8000, 0x0040,
+	0x304b, 0x681b, 0x001d, 0x70a3, 0x0001, 0x781b, 0x0047, 0x0078,
+	0x1e79, 0x007e, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3068, 0x7808,
+	0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec,
+	0xa084, 0x0021, 0x0040, 0x3068, 0x7808, 0xa085, 0x0002, 0x780a,
+	0x007f, 0x007c, 0x7808, 0xa085, 0x0002, 0x780a, 0x007c, 0x7830,
+	0xa084, 0x0040, 0x00c0, 0x306f, 0x0098, 0x3078, 0x78ac, 0x007c,
+	0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005,
+	0x78ec, 0xa084, 0x0021, 0x0040, 0x3087, 0x0098, 0x3085, 0x78ac,
+	0x007e, 0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0xa784,
+	0x0070, 0x0040, 0x309b, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x1dd5,
+	0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x30a8, 0x784b,
+	0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1e81, 0x0078, 0x301c,
+	0xa784, 0x0004, 0x0040, 0x30db, 0x78b8, 0xa084, 0x4001, 0x0040,
+	0x30db, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1e81,
+	0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x30db, 0x78c0,
+	0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00e6, 0x0078, 0x1e79,
+	0x784b, 0x0008, 0x6818, 0xa084, 0x8000, 0x0040, 0x30d7, 0x681b,
+	0x0015, 0xa684, 0x4000, 0x0040, 0x30d7, 0x681b, 0x0007, 0x781b,
+	0x00df, 0x0078, 0x1e79, 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00,
+	0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, 0x78e4,
+	0xa005, 0x00d0, 0x22ec, 0xa084, 0x0020, 0x0040, 0x22ec, 0x0018,
+	0x22ec, 0x0078, 0x2e6f, 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003,
+	0x8003, 0x8003, 0xa080, 0x3900, 0x2060, 0x2048, 0x704a, 0x6000,
+	0x704e, 0x6004, 0x7052, 0x2a60, 0x007c, 0x0020, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062,
+	0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, 0x98f9, 0x98e9,
+	0x0014, 0x0014, 0x0080, 0x00c0, 0x0100, 0x0402, 0x2008, 0xf880,
+	0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0xa200, 0x8838,
+	0x3806, 0x8839, 0x28c2, 0x9cc2, 0xa805, 0x0864, 0xa83d, 0x3008,
+	0x28c1, 0x9cc2, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000,
+	0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9c9f, 0xa8f3, 0x0864,
+	0xa82b, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9c9f, 0x280d, 0xa204,
+	0x64c0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677,
+	0xa80f, 0x786e, 0x883e, 0xa80c, 0x282b, 0xa205, 0x64a0, 0x67a0,
+	0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa801, 0x883e,
+	0x206b, 0x28c1, 0x9cc2, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8dc,
+	0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, 0x8000, 0x85a4, 0x1872,
+	0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x866f, 0x0704,
+	0x3008, 0x9c9f, 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8,
+	0x19e2, 0xf848, 0x8174, 0x86eb, 0x85eb, 0x872e, 0x87a9, 0x883f,
+	0x08e6, 0xa8f1, 0xf861, 0xa8e8, 0xf801, 0x0014, 0xf881, 0x0016,
+	0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221,
+	0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0xa206, 0x6865,
+	0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, 0x8008, 0xa8fa,
+	0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, 0x3008, 0x84a8, 0x11d6,
+	0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, 0x0016, 0x8000, 0x2848,
+	0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2802, 0x1011, 0xa8fd,
+	0xa883, 0x3008, 0x283d, 0x1011, 0xa8fd, 0xa209, 0x0017, 0x300c,
+	0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0xd301, 0x0014, 0x26e0,
+	0x873a, 0xfaa2, 0x19f2, 0x1fe2, 0x0014, 0xa20b, 0x0014, 0xa20d,
+	0x3806, 0x0210, 0x9ccc, 0x0704, 0x0000, 0x127e, 0x2091, 0x2200,
+	0x2049, 0x31f5, 0x7000, 0x7204, 0xa205, 0x720c, 0xa215, 0x7008,
+	0xa084, 0xfff7, 0xa205, 0x0040, 0x3207, 0x1078, 0x3280, 0x127f,
+	0x2000, 0x007c, 0x6428, 0x84ff, 0x0040, 0x3236, 0x2c70, 0x7004,
+	0xa0bc, 0x000f, 0xa7b8, 0x3246, 0x273c, 0x87fb, 0x00c0, 0x3224,
+	0x0048, 0x321c, 0x1078, 0x1e2a, 0x609c, 0xa075, 0x0040, 0x3236,
+	0x0078, 0x320f, 0x2039, 0x323b, 0x2704, 0xae68, 0x6808, 0xa630,
+	0x680c, 0xa529, 0x8421, 0x0040, 0x3236, 0x8738, 0x2704, 0xa005,
+	0x00c0, 0x3225, 0x709c, 0xa075, 0x00c0, 0x320f, 0x007c, 0x0000,
+	0x0005, 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000,
+	0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x323b,
+	0x3238, 0x0000, 0x0000, 0x8000, 0x0000, 0x323b, 0x0000, 0x3243,
+	0x3240, 0x0000, 0x0000, 0x0000, 0x0000, 0x3243, 0x0000, 0x323e,
+	0x323e, 0x0000, 0x0000, 0x8000, 0x0000, 0x323e, 0x0000, 0x3244,
+	0x3244, 0x0000, 0x0000, 0x0000, 0x0000, 0x3244, 0x127e, 0x2091,
+	0x2200, 0x2079, 0x3800, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007,
+	0x0002, 0x7003, 0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007,
+	0x0002, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c,
+	0x2049, 0x3280, 0x2019, 0x0000, 0x7004, 0x8004, 0x00c8, 0x32b2,
+	0x7007, 0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x328a, 0xa184,
+	0x01e0, 0x0040, 0x3295, 0x1078, 0x1e2a, 0xa184, 0x4000, 0x00c0,
+	0x328a, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x32a7, 0xa386,
+	0x0008, 0x0040, 0x32b2, 0xa386, 0x200c, 0x00c0, 0x328a, 0x7200,
+	0x8204, 0x0048, 0x32b2, 0x730c, 0xa384, 0x00ff, 0x0040, 0x32b2,
+	0x1078, 0x1e2a, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084,
+	0x0008, 0x00c0, 0x32b6, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048,
+	0x32bb, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e, 0x007e,
+	0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x32d6, 0x157f,
+	0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204, 0x7500,
+	0x730c, 0xa384, 0x0300, 0x00c0, 0x3315, 0xa184, 0x0060, 0x00c0,
+	0x334e, 0x7008, 0x7108, 0xa106, 0x00c0, 0x32e1, 0xa184, 0x01e0,
+	0x00c0, 0x334e, 0xa184, 0x4000, 0x00c0, 0x32e1, 0xa986, 0x353b,
+	0x00c0, 0x3309, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x3300,
+	0xa386, 0x0008, 0x0040, 0x3309, 0xa386, 0x200c, 0x00c0, 0x32e1,
+	0x7200, 0x8204, 0x0048, 0x3309, 0x730c, 0xa384, 0x00ff, 0x00c0,
+	0x3315, 0xa184, 0x0007, 0x0079, 0x330d, 0x3317, 0x3342, 0x3315,
+	0x3342, 0x3315, 0x339b, 0x3315, 0x3399, 0x1078, 0x1e2a, 0x7007,
+	0x0002, 0x8aff, 0x00c0, 0x3320, 0x2049, 0x0000, 0x0078, 0x3324,
+	0x1078, 0x3512, 0x00c0, 0x3320, 0x2704, 0xac00, 0xa088, 0x0002,
+	0x2104, 0x8108, 0x6892, 0x2104, 0x688e, 0x8a07, 0x077e, 0x007e,
+	0x6004, 0xa084, 0x0008, 0x0040, 0x3339, 0xa7ba, 0x3240, 0x0078,
+	0x333b, 0xa7ba, 0x3238, 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a,
+	0x077f, 0x007c, 0x7007, 0x0002, 0x8aff, 0x00c0, 0x3349, 0x0078,
+	0x334d, 0x1078, 0x3512, 0x00c0, 0x3349, 0x007c, 0x7108, 0x7008,
+	0xa106, 0x00c0, 0x334e, 0xa184, 0x4000, 0x00c0, 0x334e, 0x7007,
+	0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x3359, 0xa184, 0x4000,
+	0x00c0, 0x3359, 0x00e0, 0x3362, 0x2091, 0x6000, 0x00e0, 0x3366,
+	0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084,
+	0x0008, 0x00c0, 0x336e, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048,
+	0x3373, 0x7003, 0x0000, 0x7000, 0xa005, 0x00c0, 0x3387, 0x7004,
+	0xa005, 0x00c0, 0x3387, 0x700c, 0xa005, 0x0040, 0x3389, 0x0078,
+	0x336a, 0x2049, 0x0000, 0x1078, 0x2fb3, 0x6818, 0xa084, 0x8000,
+	0x0040, 0x3394, 0x681b, 0x0002, 0x007c, 0x1078, 0x1e2a, 0x1078,
+	0x1e2a, 0x1078, 0x33f9, 0x7210, 0x7114, 0x700c, 0xa09c, 0x00ff,
+	0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x33f9, 0x2704,
+	0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b,
+	0x2400, 0xa305, 0x0040, 0x33be, 0x00c8, 0x33be, 0x8412, 0x8210,
+	0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x33a5, 0x2b60, 0x8a07,
+	0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x33ca, 0xa7ba, 0x3240,
+	0x0078, 0x33cc, 0xa7ba, 0x3238, 0x007f, 0xa73d, 0x2c00, 0x6886,
+	0x6f8a, 0x6c92, 0x6b8e, 0x1078, 0x3280, 0x007c, 0x8738, 0x2704,
+	0xa005, 0x00c0, 0x33e9, 0x609c, 0xa005, 0x0040, 0x33f6, 0x2060,
+	0x6004, 0xa084, 0x000f, 0xa080, 0x3246, 0x203c, 0x87fb, 0x1040,
+	0x1e2a, 0x8a51, 0x0040, 0x33f5, 0x7008, 0x7508, 0xa52e, 0x00c0,
+	0x33ec, 0xa084, 0x0003, 0xa086, 0x0003, 0x007c, 0x2051, 0x0000,
+	0x007c, 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x340d, 0x6000,
+	0xa064, 0x00c0, 0x3404, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080,
+	0x3256, 0x203c, 0x87fb, 0x1040, 0x1e2a, 0x007c, 0x127e, 0x0d7e,
+	0x2091, 0x2200, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90,
+	0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, 0x6804, 0xa084,
+	0x0008, 0x007f, 0x0040, 0x3428, 0xa0b8, 0x3240, 0x0078, 0x342a,
+	0xa0b8, 0x3238, 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084, 0x0040,
+	0x0040, 0x3434, 0xa6b5, 0x0001, 0x7007, 0x0004, 0x7004, 0xa084,
+	0x0004, 0x00c0, 0x3436, 0x2400, 0xa305, 0x00c0, 0x3441, 0x0078,
+	0x3465, 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a,
+	0x6004, 0xa301, 0x701e, 0xa184, 0x0008, 0x0040, 0x3455, 0x6010,
+	0xa001, 0x7022, 0x6014, 0xa001, 0x7026, 0x6208, 0x2400, 0xa202,
+	0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001,
+	0x2b60, 0x1078, 0x33d6, 0x0078, 0x3467, 0x1078, 0x3512, 0x00c0,
+	0x3465, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200,
+	0x0d7f, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x3473,
+	0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091,
+	0x2200, 0x0d7f, 0x2049, 0x347d, 0x7007, 0x0004, 0x7004, 0xa084,
+	0x0004, 0x00c0, 0x3486, 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084,
+	0x0020, 0x00c0, 0x3495, 0xa6b5, 0x0001, 0x6828, 0x2050, 0x2d60,
+	0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x3246, 0x273c, 0x87fb, 0x00c0,
+	0x34ab, 0x0048, 0x34a5, 0x1078, 0x1e2a, 0x689c, 0xa065, 0x0040,
+	0x34af, 0x0078, 0x3498, 0x1078, 0x3512, 0x00c0, 0x34ab, 0x127f,
+	0x2000, 0x007c, 0x127e, 0x007e, 0x017e, 0x0d7e, 0x2091, 0x2200,
+	0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084,
+	0x0040, 0x0040, 0x34c5, 0xa6b5, 0x0001, 0x2049, 0x34b2, 0x6828,
+	0xa055, 0x0040, 0x350f, 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f,
+	0xa7b8, 0x3246, 0x273c, 0x87fb, 0x00c0, 0x34e1, 0x0048, 0x34da,
+	0x1078, 0x1e2a, 0x709c, 0xa075, 0x2060, 0x0040, 0x350f, 0x0078,
+	0x34cd, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048,
+	0x34fc, 0x8a51, 0x00c0, 0x34ee, 0x1078, 0x1e2a, 0x8738, 0x2704,
+	0xa005, 0x00c0, 0x34e2, 0x709c, 0xa075, 0x2060, 0x0040, 0x350f,
+	0x2039, 0x3238, 0x0078, 0x34cd, 0x8422, 0x8420, 0x831a, 0xa399,
+	0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8,
+	0x350b, 0x1078, 0x1e2a, 0x2071, 0x0020, 0x0078, 0x3434, 0x127f,
+	0x2000, 0x007c, 0x7008, 0x7508, 0xa52e, 0x00c0, 0x3512, 0xa084,
+	0x0003, 0xa086, 0x0003, 0x0040, 0x353a, 0x2704, 0xac08, 0x2104,
+	0x701a, 0x8108, 0x2104, 0x701e, 0x8108, 0x2104, 0x7012, 0x8108,
+	0x2104, 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, 0x3535, 0x8108,
+	0x2104, 0x7022, 0x8108, 0x2104, 0x7026, 0x7602, 0x7007, 0x0001,
+	0x1078, 0x33d6, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200,
+	0x2049, 0x353b, 0x0d7f, 0x087f, 0x7108, 0x7008, 0xa106, 0x00c0,
+	0x3544, 0xa184, 0x4000, 0x00c0, 0x3544, 0xa184, 0x0003, 0x00c0,
+	0x355b, 0x6828, 0xa005, 0x0040, 0x3569, 0x0020, 0x355b, 0x1078,
+	0x339b, 0x0078, 0x3569, 0x00a0, 0x3562, 0x7108, 0x1078, 0x32d6,
+	0x0078, 0x3544, 0x7007, 0x0010, 0x00a0, 0x3564, 0x7108, 0x1078,
+	0x32d6, 0x7008, 0xa086, 0x0008, 0x00c0, 0x3544, 0x7003, 0x0000,
+	0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e,
+	0x157e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x3575, 0xad80,
+	0x0011, 0x20a0, 0x2099, 0x0031, 0x700c, 0xa084, 0x00ff, 0x682a,
+	0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, 0x3593,
+	0x8000, 0x80ac, 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004,
+	0x00c0, 0x3595, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f,
+	0x147f, 0x127f, 0x2000, 0x007c, 0x2091, 0x6000, 0x78b0, 0xa005,
+	0x0040, 0x35b9, 0x797c, 0x70d0, 0xa106, 0x00c0, 0x35b9, 0x7804,
+	0xa005, 0x0040, 0x35b9, 0x7807, 0x0000, 0x0068, 0x35b9, 0x2091,
+	0x4080, 0x7820, 0x8001, 0x7822, 0x00c0, 0x3619, 0x7824, 0x7822,
+	0x2091, 0x8000, 0x78e0, 0xa005, 0x0040, 0x35e6, 0x78c4, 0xa005,
+	0x00c0, 0x35e6, 0x3a10, 0xa284, 0x0002, 0x00c0, 0x35d6, 0x78c7,
+	0x0007, 0x2009, 0xff01, 0x200a, 0x0078, 0x35e6, 0xa284, 0x0001,
+	0x00c0, 0x35de, 0x78df, 0x0000, 0x0078, 0x35e6, 0x78dc, 0xa005,
+	0x00c0, 0x35e6, 0x78c7, 0x0008, 0x78df, 0x0001, 0x2069, 0x3840,
+	0x6800, 0xa084, 0x0007, 0x0040, 0x35fd, 0xa086, 0x0002, 0x0040,
+	0x35fd, 0x6830, 0xa00d, 0x0040, 0x35fd, 0x2104, 0xa005, 0x0040,
+	0x35fd, 0x8001, 0x200a, 0x0040, 0x36bb, 0x7848, 0xa005, 0x0040,
+	0x3619, 0x8001, 0x784a, 0x00c0, 0x3619, 0x0f7e, 0x2079, 0x0100,
+	0x1078, 0x306a, 0x0f7f, 0x1078, 0x1c74, 0x68c4, 0xa005, 0x0040,
+	0x3619, 0x8001, 0x68c6, 0x00c0, 0x3619, 0x68a3, 0x0000, 0x68a7,
+	0x0001, 0x1078, 0x3620, 0x1078, 0x3645, 0x2091, 0x8001, 0x007c,
+	0x7834, 0x8001, 0x7836, 0x00c0, 0x3644, 0x7838, 0x7836, 0x2091,
+	0x8000, 0x7844, 0xa005, 0x00c0, 0x362f, 0x2001, 0x0101, 0x8001,
+	0x7846, 0xa080, 0x4180, 0x2040, 0x2004, 0xa065, 0x0040, 0x3644,
+	0x6024, 0xa005, 0x0040, 0x3640, 0x8001, 0x6026, 0x0040, 0x3674,
+	0x6000, 0x2c40, 0x0078, 0x3635, 0x007c, 0x7828, 0x8001, 0x782a,
+	0x00c0, 0x3673, 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, 0x3652,
+	0x2001, 0x0080, 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, 0x8003,
+	0xa090, 0x3980, 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, 0x0040,
+	0x3673, 0xa290, 0x0009, 0x2204, 0xa005, 0x0040, 0x366b, 0x8001,
+	0x2012, 0x00c0, 0x3673, 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080,
+	0x201a, 0x1078, 0x1c74, 0x007c, 0x2069, 0x3840, 0x6800, 0xa005,
+	0x0040, 0x367e, 0x683c, 0xac06, 0x0040, 0x36bb, 0x601b, 0x0006,
+	0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085,
+	0x0060, 0x6022, 0x6000, 0x2042, 0x6714, 0x6fb6, 0x1078, 0x183c,
+	0x6818, 0xa005, 0x0040, 0x3696, 0x8001, 0x681a, 0x6808, 0xa084,
+	0xffef, 0x680a, 0x6810, 0x8001, 0x00d0, 0x36a0, 0x1078, 0x1e2a,
+	0x6812, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x19a4,
+	0x2069, 0x3840, 0x2001, 0x0006, 0x68a2, 0x7944, 0xa184, 0x0100,
+	0x00c0, 0x36b6, 0x69ba, 0x2001, 0x0004, 0x68a2, 0x1078, 0x1c6f,
+	0x2091, 0x8001, 0x007c, 0x2009, 0x384f, 0x2164, 0x2069, 0x0100,
+	0x1078, 0x1dd5, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e,
+	0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, 0x0000,
+	0x6033, 0x0000, 0x6830, 0xa084, 0x0040, 0x0040, 0x36f7, 0x684b,
+	0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, 0x0040, 0x36e4,
+	0x0070, 0x36e4, 0x0078, 0x36db, 0x684b, 0x0009, 0x20a9, 0x0014,
+	0x6848, 0xa084, 0x0001, 0x0040, 0x36f1, 0x0070, 0x36f1, 0x0078,
+	0x36e8, 0x20a9, 0x00fa, 0x0070, 0x36f7, 0x0078, 0x36f3, 0x6808,
+	0xa084, 0xfffd, 0x680a, 0x681b, 0x0047, 0x2009, 0x3868, 0x200b,
+	0x0007, 0x784c, 0x784a, 0x2091, 0x8001, 0x007c, 0x2079, 0x3800,
+	0x1078, 0x3731, 0x1078, 0x3715, 0x1078, 0x3723, 0x7833, 0x0000,
+	0x7847, 0x0000, 0x784b, 0x0000, 0x007c, 0x2019, 0x000c, 0x2011,
+	0x3846, 0x2204, 0xa086, 0x003c, 0x0040, 0x3720, 0x2019, 0x0008,
+	0x7b2a, 0x7b2e, 0x007c, 0x2019, 0x0039, 0x2011, 0x3846, 0x2204,
+	0xa086, 0x003c, 0x0040, 0x372e, 0x2019, 0x0027, 0x7b36, 0x7b3a,
+	0x007c, 0x2019, 0x3971, 0x2011, 0x3846, 0x2204, 0xa086, 0x003c,
+	0x0040, 0x373c, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x783f, 0x0000,
+	0x7843, 0x000a, 0x007c, 0xe0c5
+};
+
+#endif /* RELOAD_FIRMWARE */
+
+unsigned short risc_code_length01 = 0x2744;
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- pre2.0.5/linux/drivers/scsi/scsi.h	Sun May  5 08:52:02 1996
+++ linux/drivers/scsi/scsi.h	Sat May 18 22:19:04 1996
@@ -521,7 +521,7 @@
     if (req->bh){
 	req->buffer = bh->b_data;
 	return SCpnt;
-    };
+    }
     DEVICE_OFF(req->rq_dev);
     if (req->sem != NULL) {
 	up(req->sem);
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- pre2.0.5/linux/drivers/scsi/scsi_ioctl.c	Sun May  5 08:52:02 1996
+++ linux/drivers/scsi/scsi_ioctl.c	Sat May 18 22:19:09 1996
@@ -298,7 +298,7 @@
 
 /*
  * the scsi_ioctl() function differs from most ioctls in that it does
- * not take a major/minor number as the dev filed.  Rather, it takes
+ * not take a major/minor number as the dev field.  Rather, it takes
  * a pointer to a scsi_devices[] element, a structure. 
  */
 int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- pre2.0.5/linux/drivers/scsi/sd.c	Tue May  7 16:22:34 1996
+++ linux/drivers/scsi/sd.c	Sat May 18 22:19:14 1996
@@ -106,28 +106,23 @@
      */
     
     while (rscsi_disks[target].device->busy)
-    barrier();   
+        barrier();   
     if(rscsi_disks[target].device->removable) {
 	check_disk_change(inode->i_rdev);
 	
 	/*
 	 * If the drive is empty, just let the open fail.
 	 */
-	if ( !rscsi_disks[target].ready ) {
+	if ( !rscsi_disks[target].ready )
 	    return -ENXIO;
-	}
 
 	/*
 	 * Similarly, if the device has the write protect tab set,
 	 * have the open fail if the user expects to be able to write
 	 * to the thing.
 	 */
-	if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) ) { 
+	if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) )
 	    return -EROFS;
-	}
-
-	if(!rscsi_disks[target].device->access_count)
-	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
     }
 
     /*
@@ -137,6 +132,10 @@
     if(sd_sizes[MINOR(inode->i_rdev)] == 0)
 	return -ENXIO;
     
+    if(rscsi_disks[target].device->removable)
+	if(!rscsi_disks[target].device->access_count)
+	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
+
     rscsi_disks[target].device->access_count++;
     if (rscsi_disks[target].device->host->hostt->usage_count)
 	(*rscsi_disks[target].device->host->hostt->usage_count)++;
@@ -208,9 +207,9 @@
 }
 
 /*
- * rw_intr is the interrupt routine for the device driver.  It will
- * be notified on the end of a SCSI read / write, and
- * will take on of several actions based on success or failure.
+ * rw_intr is the interrupt routine for the device driver.
+ * It will be notified on the end of a SCSI read / write, and
+ * will take one of several actions based on success or failure.
  */
 
 static void rw_intr (Scsi_Cmnd *SCpnt)
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- pre2.0.5/linux/drivers/scsi/sr_ioctl.c	Sun May  5 08:52:02 1996
+++ linux/drivers/scsi/sr_ioctl.c	Sat May 18 22:19:19 1996
@@ -554,21 +554,30 @@
 	return (0);
     }
 	
+    case BLKRAGET:
+	if (!arg)
+		return -EINVAL;
+	err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int));
+	if (err)
+		return err;
+	put_user(read_ahead[MAJOR(inode->i_rdev)], (int *) arg);
+	return 0;
+
     case BLKRASET:
-    {
-	if(!suser())  return -EACCES;
-	if(!(inode->i_rdev)) return -EINVAL;
-	if(arg > 0xff) return -EINVAL;
+	if(!suser())
+        	return -EACCES;
+	if(!(inode->i_rdev))
+        	return -EINVAL;
+	if(arg > 0xff)
+        	return -EINVAL;
 	read_ahead[MAJOR(inode->i_rdev)] = arg;
 	return 0;
-	RO_IOCTLS(dev,arg);
-    }
+
+    RO_IOCTLS(dev,arg);
 
     case CDROMRESET:
-    {
-	invalidate_buffers(MKDEV(MAJOR(inode->i_rdev),MINOR(inode->i_rdev)));
+	invalidate_buffers(inode->i_rdev);
 	return 0;
-    }
 
     default:
 	return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
diff -u --recursive --new-file pre2.0.5/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- pre2.0.5/linux/drivers/scsi/st.c	Sun May  5 08:52:02 1996
+++ linux/drivers/scsi/st.c	Sat May 18 13:25:09 1996
@@ -11,7 +11,7 @@
   Copyright 1992 - 1996 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Thu May  2 19:41:34 1996 by makisara@kai.makisara.fi
+  Last modified: Tue May 14 17:58:12 1996 by makisara@kai.makisara.fi
   Some small formal changes - aeb, 950809
 */
 
@@ -530,8 +530,6 @@
 	printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
 	       dev, STp->current_mode, mode);
 #endif
-      /*      if (!STp->modes[mode].defined)
-	return (-ENXIO); */
       new_session = TRUE;
       STp->current_mode = mode;
     }
@@ -570,12 +568,20 @@
     STp->nbr_waits = STp->nbr_finished = 0;
 #endif
 
+    if (scsi_tapes[dev].device->host->hostt->usage_count)
+	(*scsi_tapes[dev].device->host->hostt->usage_count)++;
+    if(st_template.usage_count) (*st_template.usage_count)++;
+
     memset ((void *) &cmd[0], 0, 10);
     cmd[0] = TEST_UNIT_READY;
 
     SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_LONG_TIMEOUT, MAX_READY_RETRIES);
-    if (!SCpnt)
+    if (!SCpnt) {
+      if (scsi_tapes[dev].device->host->hostt->usage_count)
+	  (*scsi_tapes[dev].device->host->hostt->usage_count)--;
+      if(st_template.usage_count) (*st_template.usage_count)--;
       return (-EBUSY);
+    }
 
     if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 	(SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
@@ -619,9 +625,6 @@
       STp->partition = STp->new_partition = 0;
       STp->door_locked = ST_UNLOCKED;
       STp->in_use = 1;
-      if (scsi_tapes[dev].device->host->hostt->usage_count)
-	(*scsi_tapes[dev].device->host->hostt->usage_count)++;
-      if(st_template.usage_count) (*st_template.usage_count)++;
       return 0;
     }
 
@@ -698,6 +701,9 @@
 	       STp->block_size);
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
+	if (scsi_tapes[dev].device->host->hostt->usage_count)
+	    (*scsi_tapes[dev].device->host->hostt->usage_count)--;
+	if(st_template.usage_count) (*st_template.usage_count)--;
 	return (-EIO);
       }
       STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
@@ -726,6 +732,9 @@
       if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
+	if (scsi_tapes[dev].device->host->hostt->usage_count)
+	    (*scsi_tapes[dev].device->host->hostt->usage_count)--;
+	if(st_template.usage_count) (*st_template.usage_count)--;
 	return (-EROFS);
       }
     }
@@ -741,6 +750,9 @@
       if ((STp->partition = find_partition(inode)) < 0) {
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
+	if (scsi_tapes[dev].device->host->hostt->usage_count)
+	    (*scsi_tapes[dev].device->host->hostt->usage_count)--;
+	if(st_template.usage_count) (*st_template.usage_count)--;
 	return STp->partition;
       }
       STp->new_partition = STp->partition;
@@ -754,6 +766,9 @@
 	  (i = set_mode_densblk(inode, STp, STm)) < 0) {
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
+	if (scsi_tapes[dev].device->host->hostt->usage_count)
+	    (*scsi_tapes[dev].device->host->hostt->usage_count)--;
+	if(st_template.usage_count) (*st_template.usage_count)--;
 	return i;
       }
       if (STp->default_drvbuffer != 0xff) {
@@ -764,9 +779,6 @@
     }
 
     STp->in_use = 1;
-    if (scsi_tapes[dev].device->host->hostt->usage_count)
-      (*scsi_tapes[dev].device->host->hostt->usage_count)++;
-    if(st_template.usage_count) (*st_template.usage_count)++;
 
     return 0;
 }
@@ -3050,5 +3062,6 @@
     }
   }
   st_template.dev_max = 0;
+  printk(KERN_INFO "st: Unloaded.\n");
 }
 #endif /* MODULE */
diff -u --recursive --new-file pre2.0.5/linux/fs/Config.in linux/fs/Config.in
--- pre2.0.5/linux/fs/Config.in	Fri May 17 15:32:17 1996
+++ linux/fs/Config.in	Sun May 19 15:22:19 1996
@@ -35,11 +35,10 @@
 tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-# AFFS disabled until they can get that BYTE/WORD/LONG crap sorted out
-#tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS
-#if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then
-#  define_bool CONFIG_AMIGA_PARTITION y
-#fi
+tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS
+if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then
+  define_bool CONFIG_AMIGA_PARTITION y
+fi
 tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
 if [ "$CONFIG_UFS_FS" != "n" ]; then
   bool "BSD disklabel (FreeBSD partition tables) support" CONFIG_BSD_DISKLABEL
diff -u --recursive --new-file pre2.0.5/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- pre2.0.5/linux/fs/affs/amigaffs.c	Fri May 17 15:32:17 1996
+++ linux/fs/affs/amigaffs.c	Sun May 19 15:22:19 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/amigaffs.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - rewritten
+ *  (c) 1996  Hans-Joachim Widmaier - Rewritten
  *
  *  (C) 1993  Ray Burr - Amiga FFS filesystem.
  *
@@ -29,10 +29,10 @@
    is returned. */
 
 int
-affs_find_next_hash_entry(int hsize, void *dir_data, ULONG *hash_pos)
+affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos)
 {
 	struct dir_front *dir_front = dir_data;
-	ULONG i;
+	int i;
 
 	for (i = *hash_pos; i < hsize; i++)
 		if (dir_front->hashtable[i] != 0)
@@ -67,11 +67,11 @@
 /* Find the predecessor in the hash chain */
 
 int
-affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newkey)
+affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey)
 {
 	struct buffer_head	*bh = NULL;
-	ULONG			 nextkey;
-	LONG			 ptype, stype;
+	int			 nextkey;
+	int			 ptype, stype;
 	int			 retval;
 
 	nextkey = startino->i_ino;
@@ -92,9 +92,9 @@
 			affs_brelse(bh);
 			break;
 		}
-		nextkey = htonl(((ULONG *)bh->b_data)[startoffset]);
+		nextkey = htonl(((__u32 *)bh->b_data)[startoffset]);
 		if (nextkey == key) {
-			((ULONG *)bh->b_data)[startoffset] = newkey;
+			((__u32 *)bh->b_data)[startoffset] = newkey;
 			affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
 			mark_buffer_dirty(bh,1);
 			affs_brelse(bh);
@@ -112,13 +112,13 @@
 /* Remove inode from link chain */
 
 int
-affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey)
+affs_fix_link_pred(struct inode *startino, int key, int newkey)
 {
 	struct buffer_head	*bh = NULL;
-	ULONG			 nextkey;
-	ULONG			 offset;
-	LONG			 etype = 0;
-	LONG			 ptype, stype;
+	int			 nextkey;
+	int			 offset;
+	int			 etype = 0;
+	int			 ptype, stype;
 	int			 retval;
 
 	offset  = AFFS_I2BSIZE(startino) / 4 - 10;
@@ -150,7 +150,7 @@
 			retval = -EPERM;
 			break;
 		}
-		nextkey = htonl(((ULONG *)bh->b_data)[offset]);
+		nextkey = htonl(((__u32 *)bh->b_data)[offset]);
 		if (nextkey == key) {
 			FILE_END(bh->b_data,startino)->link_chain = newkey;
 			affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
@@ -172,17 +172,17 @@
    (which lets us calculate the block size).
    Returns non-zero if the block is not consistent. */
 
-ULONG
-affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype)
+__u32
+affs_checksum_block(int bsize, void *data, int *ptype, int *stype)
 {
-	ULONG sum;
-	ULONG *p;
+	__u32	 sum;
+	__u32	*p;
 
 	bsize /= 4;
 	if (ptype)
-		*ptype = htonl(((LONG *)data)[0]);
+		*ptype = htonl(((__s32 *)data)[0]);
 	if (stype)
-		*stype = htonl(((LONG *)data)[bsize - 1]);
+		*stype = htonl(((__s32 *)data)[bsize - 1]);
 
 	sum    = 0;
 	p      = data;
@@ -194,20 +194,20 @@
 void
 affs_fix_checksum(int bsize, void *data, int cspos)
 {
-	ULONG	 ocs;
-	ULONG	 cs;
+	__u32	 ocs;
+	__u32	 cs;
 
 	cs   = affs_checksum_block(bsize,data,NULL,NULL);
-	ocs  = htonl (((ULONG *)data)[cspos]);
+	ocs  = htonl (((__u32 *)data)[cspos]);
 	ocs -= cs;
-	((ULONG *)data)[cspos] = htonl(ocs);
+	((__u32 *)data)[cspos] = htonl(ocs);
 }
 
 void
 secs_to_datestamp(int secs, struct DateStamp *ds)
 {
-	ULONG	 days;
-	ULONG	 minute;
+	__u32	 days;
+	__u32	 minute;
 
 	secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60);
 	if (secs < 0)
@@ -223,7 +223,7 @@
 }
 
 int
-prot_to_mode(ULONG prot)
+prot_to_mode(__u32 prot)
 {
 	int	 mode = 0;
 
@@ -249,10 +249,10 @@
 	return mode;
 }
 
-ULONG
+unsigned int
 mode_to_prot(int mode)
 {
-	ULONG	 prot = 0;
+	unsigned int	 prot = 0;
 
 	if (mode & S_IXUSR)
 		prot |= FIBF_SCRIPT;
diff -u --recursive --new-file pre2.0.5/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c
--- pre2.0.5/linux/fs/affs/bitmap.c	Fri May 17 15:32:17 1996
+++ linux/fs/affs/bitmap.c	Sun May 19 15:22:19 1996
@@ -2,24 +2,28 @@
  *  linux/fs/affs/bitmap.c
  *
  *  (c) 1996 Hans-Joachim Widmaier
+ *
+ *
+ *  bitmap.c contains the code that handles all bitmap related stuff -
+ *  block allocation, deallocation, calculation of free space.
  */
 
-/* bitmap.c contains the code that handles the inode and block bitmaps */
-
 #include <linux/sched.h>
 #include <linux/affs_fs.h>
 #include <linux/stat.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/amigaffs.h>
 #include <linux/locks.h>
+#include <linux/amigaffs.h>
 
 #include <asm/bitops.h>
 
+/* This is, of course, shamelessly stolen from fs/minix */
+
 static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
 
 int
-affs_count_free_bits(int blocksize, const UBYTE *data)
+affs_count_free_bits(int blocksize, const char *data)
 {
   int	 free;
   int	 i;
@@ -42,94 +46,111 @@
 
 	free = 0;
 	if (s->u.affs_sb.s_flags & SF_BM_VALID) {
-		for (i = 0; i < s->u.affs_sb.s_bm_count; i++) {
-			free += s->u.affs_sb.s_bitmap[i].bm_free;
+		for (i = 0; i < s->u.affs_sb.s_num_az; i++) {
+			free += s->u.affs_sb.s_alloc[i].az_free;
 		}
 	}
 	return free;
 }
 
 void
-affs_free_block(struct super_block *sb, LONG block)
+affs_free_block(struct super_block *sb, int block)
 {
 	int			 bmap;
 	int			 bit;
-	ULONG			 blk;
+	int			 blk;
+	int			 zone_no;
 	struct affs_bm_info	*bm;
 
 	pr_debug("AFFS: free_block(%d)\n",block);
 
-	blk    = block - sb->u.affs_sb.s_reserved;
-	bmap   = blk / (sb->s_blocksize * 8 - 32);
-	bit    = blk % (sb->s_blocksize * 8 - 32);
-	bm     = &sb->u.affs_sb.s_bitmap[bmap];
-	if (bmap >= sb->u.affs_sb.s_bm_count || bit >= bm->bm_size) {
+	blk     = block - sb->u.affs_sb.s_reserved;
+	bmap    = blk / (sb->s_blocksize * 8 - 32);
+	bit     = blk % (sb->s_blocksize * 8 - 32);
+	zone_no = (bmap << (sb->s_blocksize_bits - 7)) + bit / 1024;
+	bm      = &sb->u.affs_sb.s_bitmap[bmap];
+	if (bmap >= sb->u.affs_sb.s_bm_count) {
 		printk("AFFS: free_block(): block %d outside partition.\n",block);
 		return;
 	}
-	blk  = 0;
+	blk = 0;
 	set_bit(bit & 31,&blk);
 
 	lock_super(sb);
+	bm->bm_count++;
+	if (!bm->bm_bh) {
+		bm->bm_bh = affs_bread(sb->s_dev,bm->bm_key,sb->s_blocksize);
+		if (!bm->bm_bh) {
+			bm->bm_count--;
+			unlock_super(sb);
+			printk("AFFS: free_block(): Cannot read bitmap block %d\n",bm->bm_key);
+			return;
+		}
+	}
 	if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
 		printk("AFFS: free_block(): block %d is already free.\n",block);
 	else {
-		bm->bm_free++;
-		((ULONG *)bm->bm_bh->b_data)[0] = ntohl(htonl(((ULONG *)bm->bm_bh->b_data)[0]) - blk);
+		sb->u.affs_sb.s_alloc[zone_no].az_free++;
+		((__u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((__u32 *)bm->bm_bh->b_data)[0]) - blk);
 		mark_buffer_dirty(bm->bm_bh,1);
 		sb->s_dirt = 1;
 	}
+	if (--bm->bm_count == 0) {
+		affs_brelse(bm->bm_bh);
+		bm->bm_bh = NULL;
+	}
 	unlock_super(sb);
 }
 
-static ULONG
+static int
 affs_balloc(struct inode *inode, int zone_no)
 {
-	ULONG			 w;
-	ULONG			*bm;
+	__u32			 w;
+	__u32			*bm;
 	int			 fb;
 	int			 i;
 	int			 fwb;
-	ULONG			 block;
+	int			 block;
 	struct affs_zone	*zone;
+	struct affs_alloc_zone	*az;
 	struct super_block	*sb;
 
 	sb   = inode->i_sb;
 	zone = &sb->u.affs_sb.s_zones[zone_no];
 
-	if (!zone || !zone->z_bm || !zone->z_bm->bm_bh)
-		return 0;
-	
+	if (!zone->z_bm || !zone->z_bm->bm_bh)
+		return 0;	
+
 	pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no);
 
-	bm = (ULONG *)zone->z_bm->bm_bh->b_data;
+	az = &sb->u.affs_sb.s_alloc[zone->z_az_no];
+	bm = (__u32 *)zone->z_bm->bm_bh->b_data;
 repeat:
-	fb = (zone->z_bm->bm_size + 31) >> 5;
-	for (i = zone->z_start; i <= fb; i++) {
+	for (i = zone->z_start; i < zone->z_end; i++) {
 		if (bm[i])
 			goto found;
 	}
-	return 0;
+	return 0;	
 
 found:
 	fwb = zone->z_bm->bm_firstblk + (i - 1) * 32;
 	lock_super(sb);
 	zone->z_start = i;
-	w   = htonl(bm[i]);
-	fb  = find_first_one_bit(&w,32);
+	w   = ~htonl(bm[i]);
+	fb  = find_first_zero_bit(&w,32);
 	if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) {
 		unlock_super(sb);
 		printk("AFFS: balloc(): empty block disappeared somehow\n");
 		goto repeat;
 	}
 	block = fwb + fb;
-	zone->z_bm->bm_free--;
+	az->az_free--;
 
-	/* prealloc as much as possible within this word, but not for headers */
+	/* prealloc as much as possible within this word, but not in header zone */
 
 	if (zone_no) {
 		while (inode->u.affs_i.i_pa_cnt < MAX_PREALLOC && ++fb < 32) {
-			fb = find_next_one_bit(&w,32,fb);
+			fb = find_next_zero_bit(&w,32,fb);
 			if (fb > 31)
 				break;
 			if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) {
@@ -139,102 +160,129 @@
 			inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb;
 			inode->u.affs_i.i_pa_last &= MAX_PREALLOC - 1;
 			inode->u.affs_i.i_pa_cnt++;
-			zone->z_bm->bm_free--;
+			az->az_free--;
 		}
 	}
-	w    -= htonl(bm[i]);
+	w     = ~w - htonl(bm[i]);
 	bm[0] = ntohl(htonl(bm[0]) + w);
 	unlock_super(sb);
 	mark_buffer_dirty(zone->z_bm->bm_bh,1);
+	zone->z_lru_time = jiffies;
 
 	return block;
 }
 
-static void
-affs_find_new_zone(struct super_block *sb,struct affs_zone *z, int minfree, int start)
+static int
+affs_find_new_zone(struct super_block *sb, int zone_no)
 {
 	struct affs_bm_info	*bm;
-	int			 offs;
-	int			 zone;
-	int			 free;
-	int			 len;
+	struct affs_zone	*zone;
+	struct affs_alloc_zone	*az;
+	int			 bestfree;
+	int			 bestno;
+	int			 bestused;
+	int			 lusers;
+	int			 i;
+	int			 min;
 
-	pr_debug("AFFS: find_new_zone()\n");
+	pr_debug("AFFS: find_new_zone(zone_no=%d)\n",zone_no);
 
+	bestfree = 0;
+	bestused = -1;
+	bestno   = -1;
+	lusers   = MAX_ZONES;
+	min      = zone_no ? AFFS_DATA_MIN_FREE : AFFS_HDR_MIN_FREE;
 	lock_super(sb);
-
-	zone    = start;
-	z->z_bm = NULL;
-	while (1) {
-		if (zone >= sb->u.affs_sb.s_num_zones) {
-			zone = 0;
-			continue;
+	zone = &sb->u.affs_sb.s_zones[zone_no];
+	i    = zone->z_az_no;
+	az   = &sb->u.affs_sb.s_alloc[i];
+	if (zone->z_bm && zone->z_bm->bm_count) {
+		if (--zone->z_bm->bm_count == 0) {
+			affs_brelse(zone->z_bm->bm_bh);
+			zone->z_bm->bm_bh = NULL;
 		}
+		if (az->az_count)
+			az->az_count--;
+		else
+			printk("AFFS: find_new_zone(): az_count=0, but bm used\n");
 
-		if (!set_bit(zone,sb->u.affs_sb.s_zonemap)) {
-			bm   = &sb->u.affs_sb.s_bitmap[zone >> (sb->s_blocksize_bits - 8)];
-			offs = zone * 256 & (sb->s_blocksize - 1);
-			len  = bm->bm_size / 8 - offs;
-			if (len > 256)
-				len = 256;
-			offs += 4;
-			free  = affs_count_free_bits(len,(char *)bm->bm_bh->b_data + offs);
-			if (free && (100 * free) / (len * 8) > minfree) {
-				z->z_bm       = bm;
-				z->z_start    = offs / 4;
-				z->z_ino      = 0;
-				z->z_zone_no  = zone;
-				pr_debug("  ++ found zone (%d) in bh %d at offset %d with %d free blocks\n",
-					zone,(zone >> (sb->s_blocksize_bits - 8)),offs,free);
+	}
+	while (1) {
+		if (i >= sb->u.affs_sb.s_num_az)
+			i = 0;
+		az = &sb->u.affs_sb.s_alloc[i];
+		if (!az->az_count) {
+			if (az->az_free > min) {
 				break;
 			}
-			clear_bit(zone,sb->u.affs_sb.s_zonemap);
+			if (az->az_free > bestfree) {
+				bestfree = az->az_free;
+				bestno   = i;
+			}
+		} else if (az->az_free && az->az_count < lusers) {
+			lusers   = az->az_count;
+			bestused = i;
 		}
-
-		/* Skip to next possible zone */
-
-		pr_debug("  ++ Skipping to next zone\n");
-		if (++zone == start)
+		if (++i == zone->z_az_no) {		/* Seen all */
+			if (bestno >= 0) {
+				i = bestno;
+			} else {
+				i = bestused;
+			}
 			break;
+		}
+	}
+	if (i < 0) {
+		/* Didn't find a single free block anywhere. */
+		unlock_super(sb);
+		return 0;
+	}
+	az = &sb->u.affs_sb.s_alloc[i];
+	az->az_count++;
+	bm = &sb->u.affs_sb.s_bitmap[i >> (sb->s_blocksize_bits - 7)];
+	bm->bm_count++;
+	if (!bm->bm_bh)
+		bm->bm_bh = affs_bread(sb->s_dev,bm->bm_key,sb->s_blocksize);
+	if (!bm->bm_bh) {
+		bm->bm_count--;
+		az->az_count--;
+		unlock_super(sb);
+		printk("AFFS: find_new_zone(): Cannot read bitmap\n");
+		return 0;
 	}
+	zone->z_bm    = bm;
+	zone->z_start = (i & ((sb->s_blocksize / 128) - 1)) * 32 + 1;
+	zone->z_end   = zone->z_start + az->az_size;
+	zone->z_az_no = i;
+	zone->z_lru_time = jiffies;
+	pr_debug("  ++ found zone (%d) in bm %d at lw offset %d with %d free blocks\n",
+		 i,(i >> (sb->s_blocksize_bits - 7)),zone->z_start,az->az_free);
 	unlock_super(sb);
-	return;
+	return az->az_free;
 }
 
-LONG
+int
 affs_new_header(struct inode *inode)
 {
-	struct affs_zone	*zone;
-	LONG			 block;
-	struct super_block	*sb;
+	int			 block;
 	struct buffer_head	*bh;
 
-	sb   = inode->i_sb;
-	zone = &sb->u.affs_sb.s_zones[0];
-
-	/* We try up to 3 times to find a free block:
-	 * If there is no more room in the current header zone,
-	 * we try to get a new one and allocate the block there.
-	 * If there is no zone with at least AFFS_HDR_MIN_FREE
-	 * percent of free blocks, we try to find a zone with
-	 * at least one free block.
-	 */
+	pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino);
 
 	if (!(block = affs_balloc(inode,0))) {
-		clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
-		affs_find_new_zone(sb,zone,AFFS_HDR_MIN_FREE,(sb->u.affs_sb.s_num_zones + 1) / 2);
-		if (!(block = affs_balloc(inode,0))) {
-			clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
-			affs_find_new_zone(sb,zone,0,(sb->u.affs_sb.s_num_zones + 1) / 2);
-			if (!(block = affs_balloc(inode,0)))
-				return 0;
+		while(affs_find_new_zone(inode->i_sb,0)) {
+			if ((block = affs_balloc(inode,0)))
+				goto init_block;
+			schedule();
 		}
+		return 0;
 	}
-	if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
+init_block:
+	if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
 		printk("AFFS: balloc(): cannot read block %d\n",block);
 		return 0;
 	}
-	memset(bh->b_data,0,sb->s_blocksize);
+	memset(bh->b_data,0,AFFS_I2BSIZE(inode));
 	mark_buffer_uptodate(bh,1);
 	mark_buffer_dirty(bh,1);
 	affs_brelse(bh);
@@ -242,7 +290,7 @@
 	return block;
 }
 
-LONG
+int
 affs_new_data(struct inode *inode)
 {
 	int			 empty, old;
@@ -251,7 +299,7 @@
 	struct super_block	*sb;
 	struct buffer_head	*bh;
 	int			 i = 0;
-	LONG			 block;
+	int			 block;
 
 	pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino);
 
@@ -265,7 +313,6 @@
 		goto init_block;
 	}
 	unlock_super(sb);
-repeat:
 	oldest = jiffies;
 	old    = 0;
 	empty  = 0;
@@ -287,19 +334,25 @@
 		i = empty;
 	else if (old)
 		i = old;
-	else
+	else {
+		inode->u.affs_i.i_zone = 0;
 		return affs_new_header(inode);
+	}
 
 	inode->u.affs_i.i_zone = i;
 	zone->z_ino            = inode->i_ino;
 
 found:
 	zone = &sb->u.affs_sb.s_zones[i];
-	if (!(block = affs_balloc(inode,i))) {				/* Zone is full */
-		clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
-		affs_find_new_zone(sb,zone,AFFS_DATA_MIN_FREE,sb->u.affs_sb.s_nextzone);
-		sb->u.affs_sb.s_nextzone = zone->z_zone_no + 1;
-		goto repeat;
+	if (!(block = affs_balloc(inode,i))) {		/* No data zones left */
+		while(affs_find_new_zone(sb,i)) {
+			if ((block = affs_balloc(inode,i)))
+				goto init_block;
+			schedule();
+		}
+		inode->u.affs_i.i_zone = 0;
+		zone->z_ino            = -1;
+		return 0;
 	}
 
 init_block:
@@ -318,15 +371,15 @@
 void
 affs_make_zones(struct super_block *sb)
 {
-	int	 i, j;
-
-	pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_zones);
+	int	 i, mid;
 
-	j = (sb->u.affs_sb.s_num_zones + 1) / 2;
+	pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_az);
 
-	affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[0],AFFS_HDR_MIN_FREE,j);
+	mid = (sb->u.affs_sb.s_num_az + 1) / 2;
+	sb->u.affs_sb.s_zones[0].z_az_no = mid;
+	affs_find_new_zone(sb,0);
 	for (i = 1; i < MAX_ZONES; i++) {
-		affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[i],AFFS_DATA_MIN_FREE,j);
-		j = sb->u.affs_sb.s_zones[i].z_zone_no + 1;
+		sb->u.affs_sb.s_zones[i].z_az_no = mid;
+		affs_find_new_zone(sb,i);
 	}
 }
diff -u --recursive --new-file pre2.0.5/linux/fs/affs/dir.c linux/fs/affs/dir.c
--- pre2.0.5/linux/fs/affs/dir.c	Fri May 17 15:32:17 1996
+++ linux/fs/affs/dir.c	Sun May 19 15:22:19 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/dir.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - rewritten
+ *  (c) 1996  Hans-Joachim Widmaier - Rewritten
  *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  *
@@ -58,7 +58,7 @@
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
-	affs_dir_truncate,	/* truncate */
+	NULL,			/* truncate */
 	NULL			/* permissions */
 };
 
@@ -72,11 +72,11 @@
 affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir)
 {
 	int			 j, namelen;
-	LONG			 i;
-	ULONG			 hash_pos;
-	ULONG			 chain_pos;
+	int			 i;
+	int			 hash_pos;
+	int			 chain_pos;
 	unsigned long		 ino;
-	unsigned long			 old;
+	unsigned long		 old;
 	int stored;
 	char *name;
 	struct buffer_head *dir_bh;
@@ -142,9 +142,9 @@
 		 * we can jump directly to where we left off.
 		 */
 		if (filp->private_data && filp->f_version == dir->i_version) {
-			i = (ULONG)filp->private_data;
+			i = (int)filp->private_data;
 			j = 0;
-			pr_debug("AFFS: readdir() left off=%lu\n",i);
+			pr_debug("AFFS: readdir() left off=%d\n",i);
 		}
 		filp->f_version = dir->i_version;
 		pr_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos);
@@ -163,7 +163,8 @@
 		}
 		if (fh_bh) {
 			namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
-			pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",namelen,name,ino,i);
+			pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",
+				 namelen,name,ino,i);
 			filp->private_data = (void *)ino;
 			if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
 				goto readdir_done;
@@ -187,10 +188,4 @@
 	iput(dir);
 	pr_debug("AFFS: readdir()=%d\n",stored);
 	return stored;
-}
-
-void
-affs_dir_truncate(struct inode *inode)
-{
-	printk("AFFS: dir_truncate()\n");
 }
diff -u --recursive --new-file pre2.0.5/linux/fs/affs/file.c linux/fs/affs/file.c
--- pre2.0.5/linux/fs/affs/file.c	Fri May 17 15:32:17 1996
+++ linux/fs/affs/file.c	Sun May 19 15:22:19 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/file.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - rewritten
+ *  (c) 1996  Hans-Joachim Widmaier - Rewritten
  *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  *
@@ -104,11 +104,11 @@
 };
 
 int
-affs_bmap(struct inode *inode, LONG block)
+affs_bmap(struct inode *inode, int block)
 {
 	struct buffer_head	*bh;
-	LONG			 ext, key;
-	LONG			 ptype, stype;
+	int			 ext, key;
+	int			 ptype, stype;
 
 	pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
 
@@ -155,13 +155,13 @@
 }
 
 struct buffer_head *
-affs_getblock(struct inode *inode, LONG block)
+affs_getblock(struct inode *inode, int block)
 {
 	struct buffer_head	*bh;
 	struct buffer_head	*ebh;
-	LONG			 key;
-	LONG			 ext;
-	LONG			 cnt, j, pt;
+	int			 key;
+	int			 ext;
+	int			 cnt, j, pt;
 
 	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
 
@@ -258,28 +258,28 @@
 	affs_brelse(bh);
 	if (!key)
 		return NULL;
-
+	
 	return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
 }
 
 struct buffer_head *
-affs_getblock_ofs(struct inode *inode, LONG block, LONG *blk_key)
+affs_getblock_ofs(struct inode *inode, int block, int *blk_key)
 {
 	struct buffer_head	*bh;
 	struct buffer_head	*pbh;
 	struct buffer_head	*ebh;
-	LONG			 key;
-	LONG			 ext;
-	LONG			 cnt, j, pt;
+	int			 key;
+	int			 ext;
+	int			 cnt, j, pt;
 
-	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
+	pr_debug("AFFS: getblock_ofs(%lu,%d)\n",inode->i_ino,block);
 
 	if (block < 0)
 		return NULL;
 	key = inode->i_ino;
 	pt  = T_SHORT;
 
-	ext = block / (AFFS_I2HSIZE(inode) - 24);
+	ext = block / AFFS_I2HSIZE(inode);
 	if (ext) {
 		if (ext > inode->u.affs_i.i_max_ext)
 			ext = inode->u.affs_i.i_max_ext;
@@ -305,7 +305,11 @@
 		j = htonl(((struct file_front *)bh->b_data)->block_count);
 		while (j < AFFS_I2HSIZE(inode) && j <= block) {
 			if (!pbh && inode->u.affs_i.i_lastblock >= 0) {
-				pbh = affs_getblock_ofs(inode,inode->u.affs_i.i_lastblock,&key);
+				if (j > 0)
+					pbh = affs_bread(inode->i_dev,ntohl(AFFS_BLOCK(bh->b_data,inode,j - 1)),
+							 AFFS_I2BSIZE(inode));
+				else
+					pbh = affs_getblock_ofs(inode,inode->u.affs_i.i_lastblock,&key);
 				if (!pbh) {
 					printk("AFFS: getblock(): cannot get last block in file\n");
 					break;
@@ -335,12 +339,14 @@
 			DATA_FRONT(ebh)->primary_type    = ntohl(T_DATA);
 			DATA_FRONT(ebh)->header_key      = ntohl(inode->i_ino);
 			DATA_FRONT(ebh)->sequence_number = ntohl(inode->u.affs_i.i_lastblock + 1);
-			DATA_FRONT(pbh)->data_size       = ntohl(AFFS_I2HSIZE(inode) - 24);
-			DATA_FRONT(pbh)->next_data       = ntohl(key);
-			affs_fix_checksum(AFFS_I2HSIZE(inode),pbh->b_data,5);
-			mark_buffer_dirty(pbh,0);
-			mark_buffer_dirty(ebh,0);
-			affs_brelse(pbh);
+			if (pbh) {
+				DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2BSIZE(inode) - 24);
+				DATA_FRONT(pbh)->next_data = ntohl(key);
+				affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
+				mark_buffer_dirty(pbh,0);
+				mark_buffer_dirty(ebh,0);
+				affs_brelse(pbh);
+			}
 			pbh = ebh;
 			j++;
 		}
@@ -433,10 +439,10 @@
 		left = MIN (inode->i_size - filp->f_pos,count - (buf - start));
 		if (!left)
 			break;
-		sector = affs_bmap(inode,(ULONG)filp->f_pos / blocksize);
+		sector = affs_bmap(inode,(__u32)filp->f_pos / blocksize);
 		if (!sector)
 			break;
-		offset = (ULONG)filp->f_pos % blocksize;
+		offset = (__u32)filp->f_pos % blocksize;
 		bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
 		if (!bh)
 			break;
@@ -537,6 +543,7 @@
 	off_t			 pos;
 	int			 written;
 	int			 c;
+	int			 key;
 	int			 blocksize;
 	struct buffer_head	*bh;
 	struct inode		*ino;
@@ -546,7 +553,7 @@
 		(unsigned long)filp->f_pos,count);
 
 	if (!inode) {
-		printk("AFFS: file_write(): inode=NULL\n");
+		printk("AFFS: file_write_ofs(): inode=NULL\n");
 		return -EINVAL;
 	}
 	ino = NULL;
@@ -560,7 +567,7 @@
 		inode = ino;
 	}
 	if (!S_ISREG(inode->i_mode)) {
-		printk("AFFS: file_write(): mode=%07o\n",inode->i_mode);
+		printk("AFFS: file_write_ofs(): mode=%07o\n",inode->i_mode);
 		iput(inode);
 		return -EINVAL;
 	}
@@ -573,7 +580,7 @@
 	blocksize = AFFS_I2BSIZE(inode) - 24;
 	written   = 0;
 	while (written < count) {
-		bh = affs_getblock(inode,pos / blocksize);
+		bh = affs_getblock_ofs(inode,pos / blocksize,&key);
 		if (!bh) {
 			if (!written)
 				written = -ENOSPC;
@@ -620,12 +627,13 @@
 	struct buffer_head	*bh;
 	struct buffer_head	*ebh;
 	struct inode		*ino;
-	LONG	 first;
-	LONG	 block;
-	LONG	 key;
-	LONG	*keyp;
-	LONG	 ekey;
-	LONG	 ptype, stype;
+	struct affs_zone	*zone;
+	int	 first;
+	int	 block;
+	int	 key;
+	int	*keyp;
+	int	 ekey;
+	int	 ptype, stype;
 	int	 freethis;
 	int	 blocksize;
 	int	 rem;
@@ -646,7 +654,24 @@
 	blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
 	first = (inode->i_size + blocksize - 1) / blocksize;
 	if (inode->u.affs_i.i_lastblock < first - 1) {
-		bh = affs_getblock(inode,first - 1);
+		if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
+			bh = affs_getblock_ofs(inode,first - 1,&ekey);
+		else
+			bh = affs_getblock(inode,first - 1);
+
+		while (inode->u.affs_i.i_pa_cnt) {		/* Free any preallocated blocks */
+			affs_free_block(inode->i_sb,
+					inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
+			inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
+			inode->u.affs_i.i_pa_cnt--;
+		}
+		if (inode->u.affs_i.i_zone) {
+			lock_super(inode->i_sb);
+			zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
+			if (zone->z_ino == inode->i_ino)
+				zone->z_ino = 0;
+			unlock_super(inode->i_sb);
+		}
 		if (!bh) {
 			printk("AFFS: truncate(): Cannot extend file\n");
 			inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1);
diff -u --recursive --new-file pre2.0.5/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- pre2.0.5/linux/fs/affs/inode.c	Fri May 17 15:32:17 1996
+++ linux/fs/affs/inode.c	Sun May 19 16:15:32 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/inode.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - rewritten
+ *  (c) 1996  Hans-Joachim Widmaier - Rewritten
  *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  * 
@@ -25,12 +25,15 @@
 #include <linux/genhd.h>
 #include <linux/amigaffs.h>
 #include <linux/major.h>
+#include <linux/blkdev.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 
 extern int *blk_size[];
 extern struct timezone sys_tz;
 
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
 void
 affs_put_super(struct super_block *sb)
 {
@@ -39,15 +42,13 @@
 	pr_debug("affs_put_super()\n");
 
 	lock_super(sb);
-	if (!(sb->s_flags & MS_RDONLY)) {
-		for (i = 0; i < sb->u.affs_sb.s_bm_count; i++)
-			affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh);
-		ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1);
-		secs_to_datestamp(CURRENT_TIME,
-				  &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
-		affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
-		mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1);
-	}
+	for (i = 0; i < sb->u.affs_sb.s_bm_count; i++)
+		affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh);
+	ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1);
+	secs_to_datestamp(CURRENT_TIME,&ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
+	affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
+	mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1);
+
 	if (sb->u.affs_sb.s_flags & SF_PREFIX)
 		kfree(sb->u.affs_sb.s_prefix);
 	kfree(sb->u.affs_sb.s_bitmap);
@@ -62,15 +63,24 @@
 static void
 affs_write_super(struct super_block *sb)
 {
-	int	 i, clean = 2;
+	int			 i, clean = 2;
 
+	if ((sb->u.affs_sb.s_flags & SF_USE_MP) && !sb->u.affs_sb.s_uid && sb->s_covered) {
+		sb->s_mounted->i_uid = sb->u.affs_sb.s_uid = sb->s_covered->i_uid;
+		sb->s_mounted->i_gid = sb->u.affs_sb.s_gid = sb->s_covered->i_gid;
+		sb->u.affs_sb.s_flags &= ~SF_USE_MP;
+	}
 	if (!(sb->s_flags & MS_RDONLY)) {
+		lock_super(sb);
 		for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) {
-			if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) {
-				clean = 0;
-				break;
+			if (sb->u.affs_sb.s_bitmap[i].bm_bh) {
+				if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) {
+					clean = 0;
+					break;
+				}
 			}
 		}
+		unlock_super(sb);
 		ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(clean);
 		secs_to_datestamp(CURRENT_TIME,
 				  &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
@@ -108,7 +118,6 @@
 	return dir->u.affs_i.i_parent;
 }
 
-
 static int
 parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, int *root,
 		int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
@@ -140,6 +149,13 @@
 			}
 			*mount_opts |= SF_IMMUTABLE;
 		}
+		if (!strcmp(this_char,"usemp")) {
+			if (value) {
+				printk("AFFS: option usemp does not take an argument\n");
+				return 0;
+			}
+			*mount_opts |= SF_USE_MP;
+		}
 		else if (!strcmp(this_char,"verbose")) {
 			if (value) {
 				printk("AFFS: option verbose does not take an argument\n");
@@ -251,6 +267,10 @@
 	return 1;
 }
 
+/* This function definately needs to be split up. Some fine day I'll
+ * hopefully have the guts to do so. Until then: sorry for the mess.
+ */
+
 struct super_block *
 affs_read_super(struct super_block *s,void *data, int silent)
 {
@@ -259,26 +279,26 @@
 	kdev_t			 dev = s->s_dev;
 	int			 root_block;
 	int			 size;
-	ULONG			 chksum;
-	ULONG			*bm;
-	LONG			 ptype, stype;
-	int			 mapidx = 0;
+	__u32			 chksum;
+	__u32			*bm;
+	int			 ptype, stype;
+	int			 mapidx;
 	int			 num_bm;
-	int			 i;
+	int			 i, j;
 	int			 key;
 	int			 blocksize;
 	uid_t			 uid;
 	gid_t			 gid;
-	int			 mode, reserved;
-	int			 zm_size;
+	int			 reserved;
+	int			 az_no;
 	unsigned long		 mount_flags;
-	ULONG			 offset;
+	unsigned long		 offset;
 
-	pr_debug("affs_read_super(%s)\n",(const char *)data);
+	pr_debug("affs_read_super(%s)\n",data ? (const char *)data : "no options");
 
 	MOD_INC_USE_COUNT;
 
-	if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block,
+	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
 	    &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) {
 		s->s_dev = 0;
 		printk("AFFS: error parsing options.\n");
@@ -292,13 +312,15 @@
 	 * blocks, we will have to change it.
 	 */
 
-	size                      = 2 * blk_size[MAJOR(dev)][MINOR(dev)];
-	s->u.affs_sb.s_bitmap     = NULL;
-	s->u.affs_sb.s_root_bh    = NULL;
-	s->u.affs_sb.s_flags      = mount_flags;
-	s->u.affs_sb.s_mode       = mode;
-	s->u.affs_sb.s_uid        = uid;
-	s->u.affs_sb.s_gid        = gid;
+	size = blksize_size[MAJOR(dev)][MINOR(dev)];
+	size = (size ? size : BLOCK_SIZE) / 512 * blk_size[MAJOR(dev)][MINOR(dev)];
+
+	s->u.affs_sb.s_bitmap  = NULL;
+	s->u.affs_sb.s_root_bh = NULL;
+	s->u.affs_sb.s_flags   = mount_flags;
+	s->u.affs_sb.s_mode    = i;
+	s->u.affs_sb.s_uid     = uid;
+	s->u.affs_sb.s_gid     = gid;
 
 	if (size == 0) {
 		s->s_dev = 0;
@@ -320,15 +342,12 @@
 		num_bm = 4096;
 	}
 	for (blocksize = chksum; blocksize <= num_bm; blocksize <<= 1, size >>= 1) {
-	        if (root_block < 0){
-		    if (MAJOR(dev) == FLOPPY_MAJOR)
-		        s->u.affs_sb.s_root_block = size/4;
-		    else
+		if (root_block < 0)
 			s->u.affs_sb.s_root_block = (reserved + size - 1) / 2;
-		}else
+		else
 			s->u.affs_sb.s_root_block = root_block;
 		pr_debug("Trying bs=%d bytes, root at %d, size=%d blocks (%d reserved)\n",
-			blocksize,s->u.affs_sb.s_root_block,size,reserved);
+			 blocksize,s->u.affs_sb.s_root_block,size,reserved);
 		set_blocksize(dev,blocksize);
 		bh = affs_bread(dev,s->u.affs_sb.s_root_block,blocksize);
 		if (!bh) {
@@ -360,7 +379,7 @@
 	/* Find out which kind of FS we have */
 	bb = affs_bread(dev,0,s->s_blocksize);
 	if (bb) {
-		chksum = htonl(*(ULONG *)bb->b_data);
+		chksum = htonl(*(__u32 *)bb->b_data);
 		switch (chksum) {
 			case MUFS_FS:
 			case MUFS_INTLFFS:
@@ -422,20 +441,28 @@
 		goto out;
 	}
 
-	/* Allocate space for bitmap pointers and read the bitmap */
+	/* Allocate space for bitmaps, zones and others */
 
-	size    = s->u.affs_sb.s_partition_size - reserved;
-	num_bm  = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32);
-	zm_size = (num_bm *  (1 << (s->s_blocksize_bits - 8)) + 7) / 8;
-	ptype   = num_bm * sizeof(struct affs_bm_info) + zm_size +
-		  MAX_ZONES * sizeof(struct affs_zone);
+	size   = s->u.affs_sb.s_partition_size - reserved;
+	num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32);
+	az_no  = (size + AFFS_ZONE_SIZE - 1) / (AFFS_ZONE_SIZE - 32);
+	ptype  = num_bm * sizeof(struct affs_bm_info) + 
+		 az_no * sizeof(struct affs_alloc_zone) +
+		 MAX_ZONES * sizeof(struct affs_zone);
+	pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype);
 	if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) {
-		printk("AFFS: Can't get memory for bitmap info.\n");
+		printk("AFFS: Not enough memory.\n");
 		goto out;
 	}
 	memset(s->u.affs_sb.s_bitmap,0,ptype);
 
-	if( (ULONG)((UBYTE *)bh->b_data + s->s_blocksize - 200) == 0 ) {
+	s->u.affs_sb.s_zones   = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm];
+	s->u.affs_sb.s_alloc   = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES];
+	s->u.affs_sb.s_num_az  = az_no;
+
+	mapidx = 0;
+
+	if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) {
 		if (!(s->s_flags & MS_RDONLY)) {
 			printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev));
 			s->s_flags |= MS_RDONLY;
@@ -445,14 +472,17 @@
 		goto nobitmap;
 	}
 
-	pr_debug("AFFS: %d bitmap blocks\n",num_bm);
+	/* The following section is ugly, I know. Especially because of the
+	 * reuse of some variables that are not named properly.
+	 */
 
 	key    = root_block;
 	ptype  = s->s_blocksize / 4 - 49;
 	stype  = ptype + 25;
 	offset = s->u.affs_sb.s_reserved;
+	az_no  = 0;
 	while (bh) {
-		bm = (ULONG *)bh->b_data;
+		bm = (__u32 *)bh->b_data;
 		for (i = ptype; i < stype && bm[i]; i++, mapidx++) {
 			if (mapidx >= num_bm) {
 				printk("AFFS: Not enough bitmap space!?\n");
@@ -460,21 +490,22 @@
 			}
 			bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize);
 			if (bb) {
-				if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) /*&&
-				    !(s->s_flags & MS_RDONLY)*/) {
+				if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) &&
+				    !(s->s_flags & MS_RDONLY)) {
 					printk("AFFS: Bitmap (%d,key=%lu) invalid - "
 					       "mounting %s read only.\n",mapidx,htonl(bm[i]),
 						kdevname(dev));
 					s->s_flags |= MS_RDONLY;
 				}
+				/* Mark unused bits in the last word as allocated */
 				if (size <= s->s_blocksize * 8 - 32) {	/* last bitmap */
 					ptype = size / 32 + 1;		/* word number */
 					key   = size & 0x1F;		/* used bits */
 					if (key) {
 						chksum = ntohl(0x7FFFFFFF >> (31 - key));
-						((ULONG *)bb->b_data)[ptype] &= chksum;
+						((__u32 *)bb->b_data)[ptype] &= chksum;
 						affs_fix_checksum(s->s_blocksize,bb->b_data,0);
-						/* no need to mark buffer as dirty */
+						mark_buffer_dirty(bb,1);
 					}
 					ptype = (size + 31) & ~0x1F;
 					size  = 0;
@@ -485,11 +516,19 @@
 					size -= ptype;
 				}
 				s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset;
-				s->u.affs_sb.s_bitmap[mapidx].bm_size     = ptype;
-				s->u.affs_sb.s_bitmap[mapidx].bm_bh       = bb;
-				s->u.affs_sb.s_bitmap[mapidx].bm_free     =
-						affs_count_free_bits(ptype / 8,bb->b_data + 4);
+				s->u.affs_sb.s_bitmap[mapidx].bm_bh       = NULL;
+				s->u.affs_sb.s_bitmap[mapidx].bm_key      = htonl(bm[i]);
+				s->u.affs_sb.s_bitmap[mapidx].bm_count    = 0;
 				offset += ptype;
+
+				for (j = 0; ptype > 0; j++, az_no++, ptype -= key) {
+					key = MIN(ptype,AFFS_ZONE_SIZE);	/* size in bits */
+					s->u.affs_sb.s_alloc[az_no].az_size = key / 32;
+					s->u.affs_sb.s_alloc[az_no].az_free =
+						affs_count_free_bits(key / 8,bb->b_data +
+								     j * (AFFS_ZONE_SIZE / 8) + 4);
+				}
+				affs_brelse(bb);
 			} else {
 				printk("AFFS: Can't read bitmap.\n");
 				goto out;
@@ -511,18 +550,15 @@
 		printk("AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm);
 		goto out;
 	}
-	s->u.affs_sb.s_num_zones = ((num_bm - 1) << (s->s_blocksize_bits - 8)) +
-				   (s->u.affs_sb.s_bitmap[num_bm - 1].bm_size + 2047) / 2048;
 nobitmap:
 	s->u.affs_sb.s_bm_count  = mapidx;
-	s->u.affs_sb.s_zones     = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm];
-	s->u.affs_sb.s_zonemap   = (char *)&s->u.affs_sb.s_zones[MAX_ZONES];
 
 	/* set up enough so that it can read an inode */
 
 	s->s_dev       = dev;
 	s->s_op        = &affs_sops;
 	s->s_mounted   = iget(s,root_block);
+	s->s_dirt      = 1;
 	unlock_super(s);
 
 	if (!(s->s_mounted)) {
@@ -532,7 +568,7 @@
 		return NULL;
 	}
 
-	/* If the fs is mounted r/w, create data zones, else free bitmaps. */
+	/* create data zones if the fs is mounted r/w */
 
 	if (!(s->s_flags & MS_RDONLY)) {
 		ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_mounted)->bm_flag = 0;
@@ -541,13 +577,7 @@
 		affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
 		mark_buffer_dirty(s->u.affs_sb.s_root_bh,1);
 		affs_make_zones(s);
-	} else {
-		for (i = 0; i < s->u.affs_sb.s_bm_count; i++) {
-			affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh);
-			s->u.affs_sb.s_bitmap[i].bm_bh = NULL;
-		}
 	}
-		
 
 	pr_debug("AFFS: s_flags=%lX\n",s->s_flags);
 	return s;
@@ -555,11 +585,8 @@
  out: /* Kick out for various error conditions */
 	affs_brelse (bh);
 	affs_brelse(s->u.affs_sb.s_root_bh);
-	if (s->u.affs_sb.s_bitmap) {
-		for (i = 0; i < mapidx; i++)
-			affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh);
+	if (s->u.affs_sb.s_bitmap)
 		kfree(s->u.affs_sb.s_bitmap);
-	}
 	s->s_dev = 0;
 	unlock_super(s);
 	MOD_DEC_USE_COUNT;
@@ -569,7 +596,7 @@
 void
 affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
-	ULONG		 free;
+	int		 free;
 	struct statfs	 tmp;
 
 	pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size,
@@ -592,9 +619,9 @@
 	struct buffer_head	*bh, *lbh;
 	struct file_front	*file_front;
 	struct file_end		*file_end;
-	LONG			 block;
-	ULONG			 prot;
-	LONG			 ptype, stype;
+	int			 block;
+	unsigned long		 prot;
+	int			 ptype, stype;
 	unsigned short		 id;
 
 	pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
@@ -817,7 +844,7 @@
 {
 	struct inode		*inode;
 	struct super_block	*sb;
-	ULONG			 block;
+	int			 block;
 
 	if (!dir || !(inode = get_empty_inode()))
 		return NULL;
@@ -863,15 +890,15 @@
 
 int
 affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
-	       const char *name, int len, LONG type)
+	       const char *name, int len, int type)
 {
 	struct buffer_head	*dir_bh;
 	struct buffer_head	*inode_bh;
 	struct buffer_head	*link_bh;
-	ULONG			 hash;
+	int			 hash;
 
-	pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%ld\n",dir->i_ino,inode->i_ino,
-		len,name,type);
+	pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d\n",dir->i_ino,inode->i_ino,
+		 len,name,type);
 
 	dir_bh      = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
 	inode_bh    = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
diff -u --recursive --new-file pre2.0.5/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- pre2.0.5/linux/fs/affs/namei.c	Fri May 17 15:32:17 1996
+++ linux/fs/affs/namei.c	Sun May 19 15:22:20 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/namei.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - rewritten
+ *  (c) 1996  Hans-Joachim Widmaier - Rewritten
  *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  *
@@ -10,12 +10,12 @@
 
 #include <linux/sched.h>
 #include <linux/affs_fs.h>
-#include <linux/amigaffs.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 #include <linux/locks.h>
+#include <linux/amigaffs.h>
 #include <asm/segment.h>
 
 #include <linux/errno.h>
@@ -100,7 +100,7 @@
 {
 	struct buffer_head *bh;
 	int	 intl;
-	ULONG	 key;
+	int	 key;
 
 	pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
 
@@ -137,7 +137,6 @@
 			break;
 		key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
 	}
-	pr_debug("%lu\n",key);
 	*ino = key;
 	return bh;
 }
@@ -379,7 +378,6 @@
 	char			 c, lc;
 
 	pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
-	printk("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
 	
 	maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
 	inode  = affs_new_inode(dir);
@@ -548,7 +546,7 @@
 	int			 retval;
 
 	pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name,
-		new_dir->i_ino,new_len,new_name);
+		 new_dir->i_ino,new_len,new_name);
 	
 	if (new_len > 30)
 		new_len = 30;
@@ -607,7 +605,7 @@
 		if (affs_parent_ino(old_inode) != old_dir->i_ino)
 			goto end_rename;
 	}
-	/* Unlink destination if existant */
+	/* Unlink destination if existent */
 	if (new_inode) {
 		if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
 		                                 AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
@@ -652,8 +650,8 @@
 int
 affs_fixup(struct buffer_head *bh, struct inode *inode)
 {
-	ULONG			 key, link_key;
-	LONG			 type;
+	int			 key, link_key;
+	int			 type;
 	struct buffer_head	*nbh;
 	struct inode		*ofinode;
 
diff -u --recursive --new-file pre2.0.5/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
--- pre2.0.5/linux/fs/affs/symlink.c	Fri May 17 15:32:17 1996
+++ linux/fs/affs/symlink.c	Sun May 19 15:22:20 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/symlink.c
  *
- *  1995  Hans-Joachim Widmaier - modified for affs.
+ *  1995  Hans-Joachim Widmaier - Modified for affs.
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
diff -u --recursive --new-file pre2.0.5/linux/fs/buffer.c linux/fs/buffer.c
--- pre2.0.5/linux/fs/buffer.c	Tue May  7 16:22:36 1996
+++ linux/fs/buffer.c	Fri May 17 18:30:40 1996
@@ -1270,6 +1270,8 @@
            deemed complete once all buffers have been visited
            (b_count==0) and are now unlocked. */
 	bh->b_count--;
+	if (!test_bit(BH_Uptodate, &bh->b_state))
+		set_bit(PG_error, &page->flags);
 	for (tmp = bh; tmp=tmp->b_this_page, tmp!=bh; ) {
 		if (test_bit(BH_Lock, &tmp->b_state) || tmp->b_count)
 			return;
diff -u --recursive --new-file pre2.0.5/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- pre2.0.5/linux/fs/isofs/rock.c	Wed May 15 11:01:15 1996
+++ linux/fs/isofs/rock.c	Sat May 18 11:15:09 1996
@@ -367,7 +367,7 @@
 	   }
 
 	   /*
-	    * If this component record isnt continued, then append a '/'.
+	    * If this component record isn't continued, then append a '/'.
 	    */
 	   if(   (!rootflag)
 		 && ((oldslp->flags & 1) == 0) ) inode->i_size += 1;
@@ -529,7 +529,7 @@
 	 }
 
 	 /*
-	  * If this component record isnt continued, then append a '/'.
+	  * If this component record isn't continued, then append a '/'.
 	  */
 	 if(   (!rootflag)
 	    && ((oldslp->flags & 1) == 0) ) strcat(rpnt,"/");
diff -u --recursive --new-file pre2.0.5/linux/include/asm-alpha/unaligned.h linux/include/asm-alpha/unaligned.h
--- pre2.0.5/linux/include/asm-alpha/unaligned.h	Fri Jun  2 13:51:17 1995
+++ linux/include/asm-alpha/unaligned.h	Sun May 19 13:29:22 1996
@@ -1,10 +1,26 @@
 #ifndef __ALPHA_UNALIGNED_H
 #define __ALPHA_UNALIGNED_H
 
+/* 
+ * The main single-value unaligned transfer routines.
+ */
+#define get_unaligned(ptr) \
+	((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))
+#define put_unaligned(x,ptr) \
+	__put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr)))
+
+/*
+ * This is a silly but good way to make sure that
+ * the get/put functions are indeed always optimized,
+ * and that we use the correct sizes.
+ */
+extern void bad_unaligned_access_length(void);
+
 /*
- * inline functions to do unaligned accesses.. See entUna in traps.c
+ * Elemental unaligned loads 
  */
-extern inline unsigned long ldq_u(unsigned long * r11)
+
+extern inline unsigned long __uldq(const unsigned long * r11)
 {
 	unsigned long r1,r2;
 	__asm__("ldq_u %0,%3\n\t"
@@ -15,11 +31,11 @@
 		:"=&r" (r1), "=&r" (r2)
 		:"r" (r11),
 		 "m" (*r11),
-		 "m" (*(unsigned long *)(7+(char *) r11)));
+		 "m" (*(const unsigned long *)(7+(char *) r11)));
 	return r1;
 }
 
-extern inline unsigned long ldl_u(unsigned int * r11)
+extern inline unsigned long __uldl(const unsigned int * r11)
 {
 	unsigned long r1,r2;
 	__asm__("ldq_u %0,%3\n\t"
@@ -30,11 +46,11 @@
 		:"=&r" (r1), "=&r" (r2)
 		:"r" (r11),
 		 "m" (*r11),
-		 "m" (*(unsigned long *)(3+(char *) r11)));
+		 "m" (*(const unsigned long *)(3+(char *) r11)));
 	return r1;
 }
 
-extern inline unsigned long ldw_u(unsigned short * r11)
+extern inline unsigned long __uldw(const unsigned short * r11)
 {
 	unsigned long r1,r2;
 	__asm__("ldq_u %0,%3\n\t"
@@ -45,11 +61,15 @@
 		:"=&r" (r1), "=&r" (r2)
 		:"r" (r11),
 		 "m" (*r11),
-		 "m" (*(unsigned long *)(1+(char *) r11)));
+		 "m" (*(const unsigned long *)(1+(char *) r11)));
 	return r1;
 }
 
-extern inline void stq_u(unsigned long r5, unsigned long * r11)
+/*
+ * Elemental unaligned stores 
+ */
+
+extern inline void __ustq(unsigned long r5, unsigned long * r11)
 {
 	unsigned long r1,r2,r3,r4;
 
@@ -69,7 +89,7 @@
 		:"r" (r5), "r" (r11));
 }
 
-extern inline void stl_u(unsigned long r5, unsigned int * r11)
+extern inline void __ustl(unsigned long r5, unsigned int * r11)
 {
 	unsigned long r1,r2,r3,r4;
 
@@ -89,7 +109,7 @@
 		:"r" (r5), "r" (r11));
 }
 
-extern inline void stw_u(unsigned long r5, unsigned short * r11)
+extern inline void __ustw(unsigned long r5, unsigned short * r11)
 {
 	unsigned long r1,r2,r3,r4;
 
@@ -107,6 +127,48 @@
 		 "=m" (*(unsigned long *)(1+(char *) r11)),
 		 "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
 		:"r" (r5), "r" (r11));
+}
+
+extern inline unsigned long __get_unaligned(const void *ptr, size_t size)
+{
+	unsigned long val;
+	switch (size) {
+	      case 1:
+		val = *(const unsigned char *)ptr;
+		break;
+	      case 2:
+		val = __uldw((const unsigned short *)ptr);
+		break;
+	      case 4:
+		val = __uldl((const unsigned int *)ptr);
+		break;
+	      case 8:
+		val = __uldq((const unsigned long *)ptr);
+		break;
+	      default:
+		bad_unaligned_access_length();
+	}
+	return val;
+}
+
+extern inline void __put_unaligned(unsigned long val, void *ptr, size_t size)
+{
+	switch (size) {
+	      case 1:
+		*(unsigned char *)ptr = (val);
+	        break;
+	      case 2:
+		__ustw(val, (unsigned short *)ptr);
+		break;
+	      case 4:
+		__ustl(val, (unsigned int *)ptr);
+		break;
+	      case 8:
+		__ustq(val, (unsigned long *)ptr);
+		break;
+	      default:
+	    	bad_unaligned_access_length();
+	}
 }
 
 #endif
diff -u --recursive --new-file pre2.0.5/linux/include/asm-generic/unaligned.h linux/include/asm-generic/unaligned.h
--- pre2.0.5/linux/include/asm-generic/unaligned.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-generic/unaligned.h	Sun May 19 13:29:22 1996
@@ -0,0 +1,20 @@
+#ifndef _ASM_GENERIC_UNALIGNED_H_
+#define _ASM_GENERIC_UNALIGNED_H_
+
+/*
+ * For the benefit of those who are trying to port Linux to another
+ * architecture, here are some C-language equivalents. 
+ */
+
+#include <asm/string.h>
+
+
+#define get_unaligned(ptr) \
+  ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+
+#define put_unaligned(val, ptr)				\
+  ({ __typeof__(*(ptr)) __tmp = (val);			\
+     memcpy((ptr), &__tmp, sizeof(*(ptr)));		\
+     (void)0; })
+
+#endif /* _ASM_GENERIC_UNALIGNED_H */
diff -u --recursive --new-file pre2.0.5/linux/include/asm-i386/unaligned.h linux/include/asm-i386/unaligned.h
--- pre2.0.5/linux/include/asm-i386/unaligned.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/unaligned.h	Sun May 19 15:47:57 1996
@@ -0,0 +1,16 @@
+#ifndef __I386_UNALIGNED_H
+#define __I386_UNALIGNED_H
+
+/*
+ * The i386 can do unaligned accesses itself. 
+ *
+ * The strange macros are there to make sure these can't
+ * be misused in a way that makes them not work on other
+ * architectures where unaligned accesses aren't as simple.
+ */
+
+#define get_unaligned(ptr) (*(ptr))
+
+#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+
+#endif
diff -u --recursive --new-file pre2.0.5/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- pre2.0.5/linux/include/linux/affs_fs.h	Fri May 17 15:32:18 1996
+++ linux/include/linux/affs_fs.h	Sun May 19 15:22:20 1996
@@ -5,7 +5,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/amigaffs.h>
 
 #define AFFS_SUPER_MAGIC 0xadff
 
@@ -21,29 +20,37 @@
 /* Get the fs type given an inode */
 #define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_flags & SF_INTL)
 
+struct DateStamp
+{
+  __u32 ds_Days;
+  __u32 ds_Minute;
+  __u32 ds_Tick;
+};
+
+
 /* --- Prototypes -----------------------------------------------------------------------------	*/
 
 /* amigaffs.c */
 
 extern int		   affs_get_key_entry(int bsize, void *data, int entry_pos);
-extern int		   affs_find_next_hash_entry(int bsize, void *dir_data, __u32 *hash_pos);
+extern int		   affs_find_next_hash_entry(int bsize, void *dir_data, int *hash_pos);
 extern int		   affs_get_file_name(int bsize, void *fh_data, char **name);
-extern __u32		   affs_checksum_block(int bsize, void *data, __s32 *ptype, __s32 *stype);
+extern unsigned int	   affs_checksum_block(int bsize, void *data, int *ptype, int *stype);
 extern void		   affs_fix_checksum(int bsize, void *data, int cspos);
 extern void		   secs_to_datestamp(int secs, struct DateStamp *ds);
-extern int		   prot_to_mode(__u32 prot);
-extern __u32		   mode_to_prot(int mode);
+extern int		   prot_to_mode(unsigned int prot);
+extern unsigned int	   mode_to_prot(int mode);
 extern int		   affs_fix_hash_pred(struct inode *startino, int startoffset,
-		 			      __s32 key, __s32 newkey);
-extern int		   affs_fix_link_pred(struct inode *startino, __s32 key, __s32 newkey);
+		 			      int key, int newkey);
+extern int		   affs_fix_link_pred(struct inode *startino, int key, int newkey);
 
 /* bitmap. c */
 
 extern int		   affs_count_free_blocks(struct super_block *s);
-extern int		   affs_count_free_bits(int blocksize, const __u8 *data);
-extern void		   affs_free_block(struct super_block *sb, __s32 block);
-extern __s32		   affs_new_header(struct inode *inode);
-extern __s32		   affs_new_data(struct inode *inode);
+extern int		   affs_count_free_bits(int blocksize, const char *data);
+extern void		   affs_free_block(struct super_block *sb, int block);
+extern int		   affs_new_header(struct inode *inode);
+extern int		   affs_new_data(struct inode *inode);
 extern void		   affs_make_zones(struct super_block *sb);
 
 /* namei.c */
@@ -78,7 +85,7 @@
 extern void		   affs_put_inode(struct inode *);
 extern struct inode	  *affs_new_inode(const struct inode *dir);
 extern int		   affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
-					  const char *name, int len, __s32 type);
+					  const char *name, int len, int type);
 
 /* file.c */
 
@@ -101,5 +108,4 @@
 extern struct inode_operations	 affs_blkdev_inode_operations;
 
 extern int init_affs_fs(void);
-
 #endif
diff -u --recursive --new-file pre2.0.5/linux/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h
--- pre2.0.5/linux/include/linux/affs_fs_i.h	Tue May  7 16:22:38 1996
+++ linux/include/linux/affs_fs_i.h	Sun May 19 15:22:20 1996
@@ -1,24 +1,25 @@
 #ifndef _AFFS_FS_I
 #define _AFFS_FS_I
 
-#define EXT_CACHE_SIZE	16
+#define EXT_CACHE_SIZE	12
 #define MAX_PREALLOC	8	/* MUST be a power of 2 */
 
 /*
  * affs fs inode data in memory
  */
 struct affs_inode_info {
-	int i_protect;	/* unused attribute bits */
-	int i_parent;   /* parent ino */
-	int i_original;	/* if != 0, this is the key of the original */
-	__u32 i_ext[EXT_CACHE_SIZE]; /* extension block numbers */
-	__u32 i_data[MAX_PREALLOC]; /* preallocated blocks */
-	short i_max_ext; /* last known extension block */
-	short i_pa_cnt;	/* number of preallocated blocks */
-	short i_pa_next;  /* Index of next block in i_data[] */
-	short i_pa_last;  /* Index of next free slot in i_data[] */
-	short i_zone;	/* write zone */
-	unsigned char i_hlink;	/* This is a fake */
+	__u32	i_protect;		/* unused attribute bits */
+	__s32	i_parent;		/* parent ino */
+	__s32	i_original;		/* if != 0, this is the key of the original */
+	__s32	i_ext[EXT_CACHE_SIZE];	/* extension block numbers */
+	__s32	i_data[MAX_PREALLOC];	/* preallocated blocks */
+	int	i_lastblock;		/* last allocated block */
+	short	i_max_ext;		/* last known extension block */
+	short	i_pa_cnt;		/* number of preallocated blocks */
+	short	i_pa_next;		/* Index of next block in i_data[] */
+	short	i_pa_last;		/* Index of next free slot in i_data[] */
+	short	i_zone;			/* write zone */
+	unsigned char i_hlink;		/* This is a fake */
 	unsigned char i_pad;
 };
 
diff -u --recursive --new-file pre2.0.5/linux/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h
--- pre2.0.5/linux/include/linux/affs_fs_sb.h	Sat May 11 10:42:07 1996
+++ linux/include/linux/affs_fs_sb.h	Sun May 19 15:22:20 1996
@@ -8,24 +8,30 @@
  *
  */
 
-#include <linux/amigaffs.h>
-
 #define MAX_ZONES		8
-#define AFFS_DATA_MIN_FREE	30	/* Percentage of free blocks needed for a data zone */
-#define AFFS_HDR_MIN_FREE	10	/* Same for header blocks */
+#define AFFS_DATA_MIN_FREE	512	/* Number of free blocks in zone for data blocks */
+#define AFFS_HDR_MIN_FREE	128	/* Same for header blocks */
+#define AFFS_ZONE_SIZE		1024	/* Blocks per alloc zone, must be multiple of 32 */
 
 struct affs_bm_info {
-	struct buffer_head *bm_bh;	/* Buffer for bitmap. */
-	int bm_free;			/* Free blocks. */
-	int bm_size;			/* Size in bits, rounded to multiple of 32. */
+	struct buffer_head *bm_bh;	/* Buffer head if loaded (bm_count > 0) */
 	int bm_firstblk;		/* Block number of first bit in this map */
+	int bm_key;			/* Disk block number */
+	int bm_count;			/* Usage counter */
+};
+
+struct affs_alloc_zone {
+	short az_size;			/* Size of this allocation zone in double words */
+	short az_count;			/* Number of users */
+	int az_free;			/* Free blocks in here (no. of bits) */
 };
 
 struct affs_zone {
 	unsigned long z_ino;		/* Associated inode number */
 	struct affs_bm_info *z_bm;	/* Zone lies in this bitmap */
 	int z_start;			/* Index of first word in bitmap */
-	int z_zone_no;			/* Zone number */
+	int z_end;			/* Index of last word in zone + 1 */
+	int z_az_no;			/* Zone number */
 	unsigned long z_lru_time;	/* Time of last usage */
 };
 
@@ -42,10 +48,11 @@
 	struct affs_bm_info *s_bitmap;	/* Bitmap infos. */
 	int s_bm_count;			/* Number of bitmap blocks. */
 	int s_nextzone;			/* Next zone to look for free blocks. */
-	int s_num_zones;		/* Total number of zones. */
-	struct affs_zone *s_zones;	/* The zones themselves. */
-	char *s_zonemap;		/* Bitmap for zones. */
-	char *s_prefix;			/* Prefix for volumes and assigns. */
+	int s_num_az;			/* Total number of alloc zones. */
+	struct affs_zone *s_zones;	/* The zones themselfes. */
+	struct affs_alloc_zone *s_alloc;/* The allocation zones. */
+	char *s_zonemap;		/* Bitmap for allocation zones. */
+	char *s_prefix;			/* Prefix for volumes and assignes. */
 	int s_prefix_len;		/* Length of prefix. */
 	char s_volume[32];		/* Volume prefix for absolute symlinks. */
 };
diff -u --recursive --new-file pre2.0.5/linux/include/linux/affs_hardblocks.h linux/include/linux/affs_hardblocks.h
--- pre2.0.5/linux/include/linux/affs_hardblocks.h	Fri May 17 15:32:18 1996
+++ linux/include/linux/affs_hardblocks.h	Sun May 19 15:22:20 1996
@@ -3,10 +3,6 @@
 
 /* Just the needed definitions for the RDB of an Amiga HD. */
 
-#ifndef AMIGAFFS_H
-#include <linux/amigaffs.h>
-#endif
-
 struct RigidDiskBlock {
 	__u32	rdb_ID;
 	__u32	rdb_SummedLongs;
diff -u --recursive --new-file pre2.0.5/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- pre2.0.5/linux/include/linux/amigaffs.h	Fri May 17 15:32:18 1996
+++ linux/include/linux/amigaffs.h	Sun May 19 15:22:20 1996
@@ -8,7 +8,7 @@
 
 #define GET_END_PTR(st,p,sz)		 ((st *)((char *)(p)+((sz)-sizeof(st))))
 #define AFFS_GET_HASHENTRY(data,hashkey) htonl(((struct dir_front *)data)->hashtable[hashkey])
-#define AFFS_BLOCK(data,ino,blk)	 ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-blk]
+#define AFFS_BLOCK(data,ino,blk)	 ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-(blk)]
 
 #define FILE_END(p,i)	GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i))
 #define ROOT_END(p,i)	GET_END_PTR(struct root_end,p,AFFS_I2BSIZE(i))
@@ -29,8 +29,6 @@
 #error Endianness must be known for affs to work.
 #endif
 
-/* The following constants will be checked against the values read native */
-
 #define FS_OFS		0x444F5300
 #define FS_FFS		0x444F5301
 #define FS_INTLOFS	0x444F5302
@@ -45,13 +43,6 @@
 #define MUFS_DCOFS	0x6d754604   /* 'muF\4' */
 #define MUFS_DCFFS	0x6d754605   /* 'muF\5' */
 
-struct DateStamp
-{
-  __u32 ds_Days;
-  __u32 ds_Minute;
-  __u32 ds_Tick;
-};
-
 #define T_SHORT		2
 #define T_LIST		16
 #define T_DATA		8
@@ -66,119 +57,130 @@
 struct root_front
 {
   __s32 primary_type;
-  __u32 spare1[2];
-  __u32 hash_size;
-  __u32 spare2;
+  __s32 spare1[2];
+  __s32 hash_size;
+  __s32 spare2;
   __u32 checksum;
-  __u32 hashtable[0];
+  __s32 hashtable[0];
 };
 
 struct root_end
 {
   __s32 bm_flag;
-  __u32 bm_keys[25];
-  __u32 bm_extend;
+  __s32 bm_keys[25];
+  __s32 bm_extend;
   struct DateStamp dir_altered;
   __u8 disk_name[40];
   struct DateStamp disk_altered;
   struct DateStamp disk_made;
-  __u32 spare1[3];
+  __s32 spare1[3];
   __s32 secondary_type;
 };
 
 struct dir_front
 {
   __s32 primary_type;
-  __u32 own_key;
-  __u32 spare1[3];
+  __s32 own_key;
+  __s32 spare1[3];
   __u32 checksum;
-  __u32 hashtable[0];
+  __s32 hashtable[0];
 };
 
 struct dir_end
 {
-  __u32 spare1;
-  __u16 owner_uid;
-  __u16 owner_gid;
+  __s32 spare1;
+  __s16 owner_uid;
+  __s16 owner_gid;
   __u32 protect;
-  __u32 spare2;
+  __s32 spare2;
   __u8 comment[92];
   struct DateStamp created;
   __u8 dir_name[32];
-  __u32 spare3[2];
-  __u32 link_chain;
-  __u32 spare4[5];
-  __u32 hash_chain;
-  __u32 parent;
-  __u32 spare5;
+  __s32 spare3[2];
+  __s32 link_chain;
+  __s32 spare4[5];
+  __s32 hash_chain;
+  __s32 parent;
+  __s32 spare5;
   __s32 secondary_type;
 };
 
 struct file_front
 {
   __s32 primary_type;
-  __u32 own_key;
-  __u32 block_count;
-  __u32 unknown1;
-  __u32 first_data;
+  __s32 own_key;
+  __s32 block_count;
+  __s32 unknown1;
+  __s32 first_data;
   __u32 checksum;
-  __u32 blocks[0];
+  __s32 blocks[0];
 };
 
 struct file_end
 {
-  __u32 spare1;
-  __u16 owner_uid;
-  __u16 owner_gid;
+  __s32 spare1;
+  __s16 owner_uid;
+  __s16 owner_gid;
   __u32 protect;
-  __u32 byte_size;
+  __s32 byte_size;
   __u8 comment[92];
   struct DateStamp created;
   __u8 file_name[32];
-  __u32 spare2;
-  __u32 original;	/* not really in file_end */
-  __u32 link_chain;
-  __u32 spare3[5];
-  __u32 hash_chain;
-  __u32 parent;
-  __u32 extension;
+  __s32 spare2;
+  __s32 original;	/* not really in file_end */
+  __s32 link_chain;
+  __s32 spare3[5];
+  __s32 hash_chain;
+  __s32 parent;
+  __s32 extension;
   __s32 secondary_type;
 };
 
 struct hlink_front
 {
   __s32 primary_type;
-  __u32 own_key;
-  __u32 spare1[3];
+  __s32 own_key;
+  __s32 spare1[3];
   __u32 checksum;
 };
 
 struct hlink_end
 {
-  __u32 spare1;
-  __u16 owner_uid;
-  __u16 owner_gid;
+  __s32 spare1;
+  __s16 owner_uid;
+  __s16 owner_gid;
   __u32 protect;
   __u8 comment[92];
   struct DateStamp created;
   __u8 link_name[32];
-  __u32 spare2;
-  __u32 original;
-  __u32 link_chain;
-  __u32 spare3[5];
-  __u32 hash_chain;
-  __u32 parent;
-  __u32 spare4;
+  __s32 spare2;
+  __s32 original;
+  __s32 link_chain;
+  __s32 spare3[5];
+  __s32 hash_chain;
+  __s32 parent;
+  __s32 spare4;
   __s32 secondary_type;
 };
 
 struct slink_front
 {
   __s32 primary_type;
-  __u32 own_key;
-  __u32 spare1[3];
-  __u32 checksum;
+  __s32 own_key;
+  __s32 spare1[3];
+  __s32 checksum;
   __u8	symname[288];	/* depends on block size */
+};
+
+struct data_front
+{
+  __s32 primary_type;
+  __s32 header_key;
+  __s32 sequence_number;
+  __s32 data_size;
+  __s32 next_data;
+  __s32 checksum;
+  __u8 data[488];	/* depends on block size */
 };
 
 /* Permission bits */
diff -u --recursive --new-file pre2.0.5/linux/include/linux/aztcd.h linux/include/linux/aztcd.h
--- pre2.0.5/linux/include/linux/aztcd.h	Mon Apr 29 18:05:20 1996
+++ linux/include/linux/aztcd.h	Sun May 19 15:17:57 1996
@@ -1,4 +1,4 @@
-/* $Id: aztcd.h,v 2.30 1996/04/26 05:33:56 root Exp root $
+/* $Id: aztcd.h,v 2.50 1996/05/17 16:15:43 root Exp root $
  *
  * Definitions for a AztechCD268 CD-ROM interface
  *	Copyright (C) 1994, 1995  Werner Zimmermann
@@ -32,7 +32,7 @@
 */
 
 #ifdef AZT_SW32 
-#define AZT_SW32_BASE_ADDR       0x220  /*I/O port base address of your soundcard*/
+#define AZT_SW32_BASE_ADDR      0x220  /*I/O port base address of your soundcard*/
 #endif
 
 /* Set this to 1, if you want your tray to be locked, set to 0 to prevent tray 
@@ -74,9 +74,9 @@
 #define STATUS_PORT		azt_port+1
 #define MODE_PORT		azt_port+2
 #ifdef  AZT_SW32                
- #define AZT_SW32_INIT           (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16))
- #define AZT_SW32_CONFIG_REG     AZT_SW32_BASE_ADDR+0x16  /*Soundwave32 Config. Register*/
- #define AZT_SW32_ID_REG         AZT_SW32_BASE_ADDR+0x04  /*Soundwave32 ID Version Register*/
+ #define AZT_SW32_INIT          (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16))
+ #define AZT_SW32_CONFIG_REG    AZT_SW32_BASE_ADDR+0x16  /*Soundwave32 Config. Register*/
+ #define AZT_SW32_ID_REG        AZT_SW32_BASE_ADDR+0x04  /*Soundwave32 ID Version Register*/
 #endif
 
 /* status bits */
diff -u --recursive --new-file pre2.0.5/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- pre2.0.5/linux/include/linux/isdn.h	Tue May  7 16:22:38 1996
+++ linux/include/linux/isdn.h	Sun May 19 15:29:31 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.3 1996/04/20 16:54:58 fritz Exp $
+/* $Id: isdn.h,v 1.10 1996/05/18 01:37:18 fritz Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -21,6 +21,29 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn.h,v $
+ * Revision 1.10  1996/05/18 01:37:18  fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.9  1996/05/17 03:58:20  fritz
+ * Added flags for DLE handling.
+ *
+ * Revision 1.8  1996/05/11 21:49:55  fritz
+ * Removed queue mamagement variables.
+ * Changed queue management to use sk_buffs.
+ *
+ * Revision 1.7  1996/05/07 09:10:06  fritz
+ * Reorganized tty-related structs.
+ *
+ * Revision 1.6  1996/05/06 11:38:27  hipp
+ * minor change in ippp struct
+ *
+ * Revision 1.5  1996/04/30 11:03:16  fritz
+ * Added Michael's ippp-bind patch.
+ *
+ * Revision 1.4  1996/04/29 23:00:02  fritz
+ * Added variables for voice-support.
+ *
  * Revision 1.3  1996/04/20 16:54:58  fritz
  * Increased maximum number of channels.
  * Added some flags for isdn_net to handle callback more reliable.
@@ -110,7 +133,7 @@
 #define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */
 #define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing  */
 
-#define ISDN_MODEM_ANZREG    20        /* Number of Modem-Registers        */
+#define ISDN_MODEM_ANZREG    21        /* Number of Modem-Registers        */
 #define ISDN_MSNLEN          20
 
 typedef struct {
@@ -150,6 +173,7 @@
   int  secure;       /* Flag: Secure                          */
   int  callback;     /* Flag: Callback                        */
   int  cbhup;        /* Flag: Reject Call before Callback     */
+  int  pppbind;      /* ippp device for bindings              */
 } isdn_net_ioctl_cfg;
 
 #ifdef __KERNEL__
@@ -214,11 +238,14 @@
 #define ISDN_SERVICE_BTEL  1<<12
 
 /* Macros checking plain usage */
-#define USG_NONE(x)     ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NONE)
-#define USG_RAW(x)      ((x & ISDN_USAGE_MASK)==ISDN_USAGE_RAW)
-#define USG_MODEM(x)    ((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM)
-#define USG_NET(x)      ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NET)
-#define USG_OUTGOING(x) ((x & ISDN_USAGE_OUTGOING)==ISDN_USAGE_OUTGOING)
+#define USG_NONE(x)         ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NONE)
+#define USG_RAW(x)          ((x & ISDN_USAGE_MASK)==ISDN_USAGE_RAW)
+#define USG_MODEM(x)        ((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM)
+#define USG_VOICE(x)        ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE)
+#define USG_NET(x)          ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NET)
+#define USG_OUTGOING(x)     ((x & ISDN_USAGE_OUTGOING)==ISDN_USAGE_OUTGOING)
+#define USG_MODEMORVOICE(x) (((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) || \
+                             ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE)     )
 
 /* Timer-delays and scheduling-flags */
 #define ISDN_TIMER_RES       3                     /* Main Timer-Resolution  */
@@ -333,6 +360,7 @@
                                        /* Ptr to orig. header_cache_update */
   void                   (*org_hcu)(struct hh_cache *, struct device *,
                                     unsigned char *);
+  int  pppbind;                        /* ippp device for bindings         */
 } isdn_net_local;
 
 #ifdef CONFIG_ISDN_PPP
@@ -375,70 +403,74 @@
 #define ISDN_ASYNC_PGRP_LOCKOUT       0x0200 /* Lock cua opens on pgrp       */
 #define ISDN_ASYNC_CALLOUT_NOHUP      0x0400 /* No hangup for cui            */
 #define ISDN_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
-#define ISDN_PORT_16550A                   4 /* Type of faked Hardware       */
 #define ISDN_SERIAL_XMIT_SIZE           4000 /* Maximum bufsize for write    */
-#define ISDN_SERIAL_TYPE_NORMAL	           1 /* tty-type                     */
-#define ISDN_SERIAL_TYPE_CALLOUT           2 /* cua-type                     */
+#define ISDN_SERIAL_TYPE_NORMAL            1
+#define ISDN_SERIAL_TYPE_CALLOUT           2
+
+/* Private data of AT-command-interpreter */
+typedef struct atemu {
+  u_char              profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0 */
+  u_char              mdmreg[ISDN_MODEM_ANZREG];  /* Modem-Registers       */
+  char                pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0             */
+  char                msn[ISDN_MSNLEN];/* EAZ/MSN                          */
+  u_char              vpar[10];        /* Voice-parameters                 */
+  int                 mdmcmdl;         /* Length of Modem-Commandbuffer    */
+  int                 pluscount;       /* Counter for +++ sequence         */
+  int                 lastplus;        /* Timestamp of last +              */
+  int                 lastDLE;         /* Flag for voice-coding: DLE seen  */
+  char                mdmcmd[255];     /* Modem-Commandbuffer              */
+} atemu;
 
 /* Private data (similar to async_struct in <linux/serial.h>) */
-typedef struct {
+typedef struct modem_info {
   int			magic;
   int			flags;		 /* defined in tty.h               */
-  int			type;		 /* UART type                      */
-  struct tty_struct 	*tty;
   int			x_char;		 /* xon/xoff character             */
-  int			close_delay;
-  int			MCR;		 /* Modem control register         */
+  int			mcr;		 /* Modem control register         */
+  int                   msr;             /* Modem status register          */
+  int                   lsr;             /* Line status register           */
   int			line;
   int			count;		 /* # of fd on device              */
   int			blocked_open;	 /* # of blocked opens             */
   long			session;	 /* Session of opening process     */
   long			pgrp;		 /* pgrp of opening process        */
+  int                   online;          /* B-Channel is up                */
+  int                   vonline;         /* Voice-channel status           */
+  int                   dialing;         /* Dial in progress               */
+  int                   rcvsched;        /* Receive needs schedule         */
   int                   isdn_driver;	 /* Index to isdn-driver           */
   int                   isdn_channel;    /* Index to isdn-channel          */
   int                   drv_index;       /* Index to dev->usage            */
+  int                   ncarrier;        /* Flag: schedule NO CARRIER      */
+  struct timer_list     nc_timer;        /* Timer for delayed NO CARRIER   */
+#define FUTURE 1
 #if FUTURE
   int                   send_outstanding;/* # of outstanding send-requests */
 #endif
   int                   xmit_size;       /* max. # of chars in xmit_buf    */
   int                   xmit_count;      /* # of chars in xmit_buf         */
-  u_char                *xmit_buf;       /* transmit-buffer                */
-  struct termios	normal_termios;
+  struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
+  atemu                 emu;             /* AT-emulator data               */
+  void                  *adpcms;         /* state for adpcm decompression  */
+  void                  *adpcmr;         /* state for adpcm compression    */
+  struct termios	normal_termios;  /* For saving termios structs     */
   struct termios	callout_termios;
   struct wait_queue	*open_wait;
   struct wait_queue	*close_wait;
+  struct sk_buff_head   *xmit_buf;       /* transmit-buffer queue          */
 } modem_info;
 
 #define ISDN_MODEM_WINSIZE 8
 
-/* Private data of AT-command-interpreter */
-typedef struct {
-  u_char              profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0  */
-  u_char              mdmreg[ISDN_MODEM_ANZREG];  /* Modem-Registers        */
-  char                pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0             */
-  char                msn[ISDN_MSNLEN];/* EAZ/MSN                          */
-  int                 mdmcmdl;         /* Length of Modem-Commandbuffer    */
-  int                 pluscount;       /* Counter for +++ sequence         */
-  int                 lastplus;        /* Timestamp of last +              */
-  char                mdmcmd[255];     /* Modem-Commandbuffer              */
-} atemu;
-
 /* Description of one ISDN-tty */
 typedef struct {
-  int                msr[ISDN_MAX_CHANNELS];	  /* Modem-statusregister   */
-  int                mlr[ISDN_MAX_CHANNELS];	  /* Line-statusregister    */
-  int                refcount;			  /* Number of opens        */
-  int                online[ISDN_MAX_CHANNELS];	  /* B-Channel is up        */
-  int                dialing[ISDN_MAX_CHANNELS];  /* Dial in progress       */
-  int                rcvsched[ISDN_MAX_CHANNELS]; /* Receive needs schedule */
-  int                ncarrier[ISDN_MAX_CHANNELS]; /* Output NO CARRIER      */
-  struct tty_driver  tty_modem;			  /* tty-device             */
-  struct tty_driver  cua_modem;			  /* cua-device             */
+  int                refcount;			   /* Number of opens        */
+  struct tty_driver  tty_modem;			   /* tty-device             */
+  struct tty_driver  cua_modem;			   /* cua-device             */
   struct tty_struct  *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
-  struct termios     *modem_termios[ISDN_MAX_CHANNELS];
-  struct termios     *modem_termios_locked[ISDN_MAX_CHANNELS];
-  atemu              atmodem[ISDN_MAX_CHANNELS];  /* AT-Command-parser      */
-  modem_info         info[ISDN_MAX_CHANNELS];	  /* Private data           */
+  struct termios     modem_termios[ISDN_MAX_CHANNELS];
+  struct termios     modem_termios_locked[ISDN_MAX_CHANNELS];
+  modem_info         info[ISDN_MAX_CHANNELS];	   /* Private data           */
 } modem;
 
 /*======================= End of ISDN-tty stuff ============================*/
@@ -504,6 +536,7 @@
   unsigned char *cbuf;
   struct slcompress *slcomp;
 #endif
+  unsigned long debug;
 };
 
 #endif
@@ -512,15 +545,6 @@
 
 /*======================= Start of general stuff ===========================*/
 
-/* Packet-queue-element */
-typedef struct pqueue {
-  char   *next;				/* Pointer to next packet           */
-  short   length;			/* Packetlength                     */
-  short   size;                         /* Allocated size                   */
-  u_char *rptr;				/* Read-pointer for stream-reading  */
-  u_char  buffer[1];			/* The data (will be alloc'd)       */
-} pqueue;
-
 typedef struct {
   char *next;
   char *private;
@@ -540,7 +564,8 @@
   isdn_if            *interface;        /* Interface to driver              */
   int                *rcverr;           /* Error-counters for B-Ch.-receive */
   int                *rcvcount;         /* Byte-counters for B-Ch.-receive  */
-  pqueue             **rpqueue;         /* Pointers to start of Rcv-Queue   */
+  unsigned long      DLEflag;           /* Flags: Insert DLE at next read   */
+  struct sk_buff_head *rpqueue;         /* Pointers to start of Rcv-Queue   */
   struct wait_queue  **rcv_waitq;       /* Wait-Queues for B-Channel-Reads  */
   struct wait_queue  **snd_waitq;       /* Wait-Queue for B-Channel-Send's  */
   char               msn2eaz[10][ISDN_MSNLEN];  /* Mapping-Table MSN->EAZ   */
diff -u --recursive --new-file pre2.0.5/linux/include/linux/isdn_ppp.h linux/include/linux/isdn_ppp.h
--- pre2.0.5/linux/include/linux/isdn_ppp.h	Mon Feb 26 11:58:16 1996
+++ linux/include/linux/isdn_ppp.h	Sun May 19 15:29:31 1996
@@ -1,4 +1,8 @@
+#ifndef _LINUX_ISDN_PPP_H
+#define _LINUX_ISDN_PPP_H
+
 extern int isdn_ppp_dial_slave(char *);
+extern int isdn_ppp_hangup_slave(char *);
 
 struct pppinfo
 {
@@ -28,3 +32,4 @@
 #define MP_END_FRAG    0x40
 #define MP_BEGIN_FRAG  0x80
 
+#endif
diff -u --recursive --new-file pre2.0.5/linux/include/linux/isdnif.h linux/include/linux/isdnif.h
--- pre2.0.5/linux/include/linux/isdnif.h	Tue May  7 16:22:38 1996
+++ linux/include/linux/isdnif.h	Sun May 19 15:29:31 1996
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.2 1996/04/20 17:02:40 fritz Exp $
+/* $Id: isdnif.h,v 1.8 1996/05/18 01:45:37 fritz Exp $
  *
  * Linux ISDN subsystem
  *
@@ -22,6 +22,27 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.8  1996/05/18 01:45:37  fritz
+ * More spelling corrections.
+ *
+ * Revision 1.7  1996/05/18 01:37:19  fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.6  1996/05/17 03:59:28  fritz
+ * Marked rcvcallb and writebuf obsolete.
+ *
+ * Revision 1.5  1996/05/01 11:43:54  fritz
+ * Removed STANDALONE
+ *
+ * Revision 1.4  1996/05/01 11:38:40  fritz
+ * Added ISDN_FEATURE_L2_TRANS
+ *
+ * Revision 1.3  1996/04/29 22:57:54  fritz
+ * Added driverId and channel parameters to
+ * writecmd() and readstat().
+ * Added constant for voice-support.
+ *
  * Revision 1.2  1996/04/20 17:02:40  fritz
  * Changes to support skbuffs for Lowlevel-Drivers.
  * Misc. typos
@@ -34,10 +55,6 @@
 #ifndef isdnif_h
 #define isdnif_h
 
-#ifdef STANDALONE
-#include <linux/k_compat.h>
-#endif
-
 /*
  * Values for general protocol-selection
  */
@@ -52,6 +69,7 @@
 #define ISDN_PROTO_L2_X75UI  1   /* X75/LAPB with UI-Frames     */
 #define ISDN_PROTO_L2_X75BUI 2   /* X75/LAPB with UI-Frames     */
 #define ISDN_PROTO_L2_HDLC   3   /* HDLC                        */
+#define ISDN_PROTO_L2_TRANS  4   /* Transparent (Voice)         */
 
 /*
  * Values for Layer-3-protocol-selection
@@ -112,6 +130,7 @@
 #define ISDN_FEATURE_L2_X75UI   (0x0001 << ISDN_PROTO_L2_X75UI)
 #define ISDN_FEATURE_L2_X75BUI  (0x0001 << ISDN_PROTO_L2_X75BUI)
 #define ISDN_FEATURE_L2_HDLC    (0x0001 << ISDN_PROTO_L2_HDLC)
+#define ISDN_FEATURE_L2_TRANS   (0x0001 << ISDN_PROTO_L2_TRANS)
 
 /* Layer 3 */
 #define ISDN_FEATURE_L3_TRANS   (0x0100 << ISDN_PROTO_L3_TRANS)
@@ -167,6 +186,10 @@
    *             int    local channel-number (0 ...)
    *             u_char pointer to received data (in Kernel-Space, volatile)
    *             int    length of data
+   *
+   * NOTE: This callback is obsolete, and will be removed when all
+   *       current LL-drivers support rcvcall_skb. Do NOT use for new
+   *       drivers.
    */
   void (*rcvcallb)(int, int, u_char*, int);
 
@@ -207,6 +230,10 @@
    *                              no schedule allowed) 
    *                          1 = Data is in User-Space (use memcpy_fromfs,
    *                              may schedule)
+   *
+   * NOTE: This call is obsolete, and will be removed when all
+   *       current LL-drivers support writebuf_skb. Do NOT use for new
+   *       drivers.
    */
   int (*writebuf)(int, int, const u_char*, int, int);
 
@@ -227,8 +254,10 @@
    *                              no schedule allowed) 
    *                          1 = Data is in User-Space (use memcpy_fromfs,
    *                              may schedule)
+   *             int    driverId
+   *             int    local channel-number (0 ...)
    */
-  int (*writecmd)(const u_char*, int, int);
+  int (*writecmd)(const u_char*, int, int, int, int);
   /* Read raw Status replies
    *             u_char pointer data (volatile)
    *             int    length of buffer
@@ -236,8 +265,10 @@
    *                              no schedule allowed) 
    *                          1 = Data is in User-Space (use memcpy_fromfs,
    *                              may schedule)
+   *             int    driverId
+   *             int    local channel-number (0 ...)
    */
-  int (*readstat)(u_char*, int, int);
+  int (*readstat)(u_char*, int, int, int, int);
   char id[20];
 } isdn_if;
 
@@ -250,7 +281,7 @@
  *              supporting sk_buff's should set this to 0.
  * command      Address of Command-Handler.
  * features     Bitwise coded Features of this driver. (use ISDN_FEATURE_...)
- * writebuf     Address of Send-Command-Handler.
+ * writebuf     Address of Send-Command-Handler. OBSOLETE do NOT use anymore.
  * writebuf_skb Address of Skbuff-Send-Handler. (NULL if not supported)
  * writecmd        "    "  D-Channel  " which accepts raw D-Ch-Commands.
  * readstat        "    "  D-Channel  " which delivers raw Status-Data.
@@ -259,7 +290,7 @@
  *
  * channels      Driver-ID assigned to this driver. (Must be used on all
  *               subsequent callbacks.
- * rcvcallb      Address of handler for received data.
+ * rcvcallb      Address of handler for received data. OBSOLETE, do NOT use anymore.
  * rcvcallb_skb  Address of handler for received Skbuff's. (NULL if not supp.)
  * statcallb        "    "     "    for status-changes.
  *
diff -u --recursive --new-file pre2.0.5/linux/include/linux/mcdx.h linux/include/linux/mcdx.h
--- pre2.0.5/linux/include/linux/mcdx.h	Fri May 17 15:32:18 1996
+++ linux/include/linux/mcdx.h	Sat May 18 11:15:09 1996
@@ -27,7 +27,7 @@
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
- *  Andreas Kies (testing the mysterious hang up's)
+ *  Andreas Kies (testing the mysterious hangups)
  *  ... somebody forgotten?
  *  
  */
@@ -35,14 +35,14 @@
 #ifndef __MCDX_H
 #define __MCDX_H
 /*
- * 	PLEASE CONFIGURE THIS ACCORIDNG TO YOURS HARDWARE/JUMPER SETTINGS.
+ * 	PLEASE CONFIGURE THIS ACCORDING TO YOUR HARDWARE/JUMPER SETTINGS.
  *
  *      o       MCDX_NDRIVES  :  number of used entries of the following table
  *      o       MCDX_DRIVEMAP :  table of {i/o base, irq} per controller
  *
  *      NOTE: Don't even think about connecting the drive to IRQ 9(2).
  *	In the AT architecture this interrupt is used to cascade the two
- *	interrupt controllers and isn't therefore usable for enything else!
+ *	interrupt controllers and isn't therefore usable for anything else!
  */
  /* #define I_WAS_IN_MCDX_H */
 #define MCDX_NDRIVES 1
@@ -55,11 +55,11 @@
 	  	
 /* 
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!NO USER INTERVENTION NEEDED BELOW
- * If You are shure that all configuration is done, please uncomment the
+ * If You are sure that all configuration is done, please uncomment the
  * line below. 
  */
 
-#undef MCDX_DEBUG	/* This is *REALLY* only for developement! */
+#undef MCDX_DEBUG	/* This is *REALLY* only for development! */
 
 #ifdef MCDX_DEBUG
 #define MCDX_TRACE(x) printk x
diff -u --recursive --new-file pre2.0.5/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- pre2.0.5/linux/include/linux/proc_fs.h	Sun May  5 08:52:04 1996
+++ linux/include/linux/proc_fs.h	Sun May 19 16:27:21 1996
@@ -120,7 +120,8 @@
 	PROC_SCSI_GENERIC_NCR5380,
 	PROC_SCSI_IN2000,
 	PROC_SCSI_PAS16,
-	PROC_SCSI_QLOGIC,
+	PROC_SCSI_QLOGICFAS,
+	PROC_SCSI_QLOGICISP,
 	PROC_SCSI_SEAGATE,
 	PROC_SCSI_T128,
 	PROC_SCSI_NCR53C7xx,
diff -u --recursive --new-file pre2.0.5/linux/include/net/sock.h linux/include/net/sock.h
--- pre2.0.5/linux/include/net/sock.h	Fri May 17 15:32:19 1996
+++ linux/include/net/sock.h	Sun May 19 16:29:21 1996
@@ -195,8 +195,8 @@
 	struct sock		*next;
 	struct sock		*prev; /* Doubly linked chain.. */
 	struct sock		*pair;
-	struct sk_buff		* send_head;
-	struct sk_buff		* send_tail;
+	struct sk_buff		* volatile send_head;
+	struct sk_buff		* volatile send_tail;
 	struct sk_buff_head	back_log;
 	struct sk_buff		*partial;
 	struct timer_list	partial_timer;
@@ -212,33 +212,33 @@
 	unsigned short		window;
 	__u32                   lastwin_seq;    /* sequence number when we last updated the window we offer */
 	__u32			high_seq;	/* sequence number when we did current fast retransmit */
-	unsigned long		ato;            /* ack timeout */
-	unsigned long		lrcvtime;       /* jiffies at last rcv */
+	volatile unsigned long  ato;            /* ack timeout */
+	volatile unsigned long  lrcvtime;       /* jiffies at last rcv */
 	unsigned short		bytes_rcv;
 /*
  *	mss is min(mtu, max_window) 
  */
 	unsigned short		mtu;       /* mss negotiated in the syn's */
-	unsigned short		mss;       /* current eff. mss - can change */
-	unsigned short		user_mss;  /* mss requested by user in ioctl */
-	unsigned short		max_window;
+	volatile unsigned short	mss;       /* current eff. mss - can change */
+	volatile unsigned short	user_mss;  /* mss requested by user in ioctl */
+	volatile unsigned short	max_window;
 	unsigned long 		window_clamp;
 	unsigned int		ssthresh;
 	unsigned short		num;
-	unsigned short		cong_window;
-	unsigned short		cong_count;
-	unsigned short		packets_out;
-	unsigned short		shutdown;
-	unsigned long		rtt;
-	unsigned long		mdev;
-	unsigned long		rto;
+	volatile unsigned short	cong_window;
+	volatile unsigned short	cong_count;
+	volatile unsigned short	packets_out;
+	volatile unsigned short	shutdown;
+	volatile unsigned long	rtt;
+	volatile unsigned long	mdev;
+	volatile unsigned long	rto;
 
 /*
  *	currently backoff isn't used, but I'm maintaining it in case
  *	we want to go back to a backoff formula that needs it
  */
  
-	unsigned short		backoff;
+	volatile unsigned short	backoff;
 	int			err, err_soft;	/* Soft holds errors that don't
 						   cause failure but are the cause
 						   of a persistent failure not just
diff -u --recursive --new-file pre2.0.5/linux/kernel/module.c linux/kernel/module.c
--- pre2.0.5/linux/kernel/module.c	Fri May 17 15:32:19 1996
+++ linux/kernel/module.c	Fri May 17 18:34:06 1996
@@ -293,7 +293,7 @@
 	else {
 		for (mp = module_list; mp != &kernel_module; mp = mp->next) {
 			if ((mp->ref == NULL) && (mp->state == MOD_RUNNING) &&
-			    ((GET_USE_COUNT(mp) & ~(MOD_AUTOCLEAN | MOD_VISITED)) == 0)) {
+			    ((GET_USE_COUNT(mp) & ~MOD_VISITED) == MOD_AUTOCLEAN)) {
 			    	if ((GET_USE_COUNT(mp) & MOD_VISITED)) {
 					/* Don't reap until one "cycle" after last _use_ */
 			   		GET_USE_COUNT(mp) &= ~MOD_VISITED;
diff -u --recursive --new-file pre2.0.5/linux/net/core/net_alias.c linux/net/core/net_alias.c
--- pre2.0.5/linux/net/core/net_alias.c	Fri May 17 15:32:20 1996
+++ linux/net/core/net_alias.c	Sat May 18 20:16:23 1996
@@ -235,6 +235,18 @@
 }
 
 
+static int
+net_alias_open(struct device * dev)
+{
+  return 0;
+}
+
+static int
+net_alias_close(struct device * dev)
+{
+  return 0;
+}
+
 /*
  * setups a new (alias) device 
  */
@@ -264,6 +276,8 @@
   dev->my_alias = alias;	/* point to alias */
   dev->name = alias->name;
   dev->type = main_dev->type;
+  dev->open = net_alias_open;
+  dev->stop = net_alias_close;
   dev->hard_header_len = main_dev->hard_header_len;
   memcpy(dev->broadcast, main_dev->broadcast, MAX_ADDR_LEN);
   memcpy(dev->dev_addr, main_dev->dev_addr, MAX_ADDR_LEN);
diff -u --recursive --new-file pre2.0.5/linux/net/decnet/README linux/net/decnet/README
--- pre2.0.5/linux/net/decnet/README	Fri May 17 15:32:20 1996
+++ linux/net/decnet/README	Sat May 18 11:15:09 1996
@@ -1,4 +1,4 @@
-Yes.. its being worked on.
+Yes.. it's being worked on.
 
 If you want to get involved email me <Alan.Cox@linux.org> and I'll put you
 in touch with the people doing the work.
diff -u --recursive --new-file pre2.0.5/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- pre2.0.5/linux/net/ipv4/tcp_input.c	Fri May 17 15:32:20 1996
+++ linux/net/ipv4/tcp_input.c	Sat May 18 20:28:07 1996
@@ -61,15 +61,7 @@
 		if (m <= 0)
 			m = 1;
 
-		/* Yikes. This used to test if m was larger than rtt/8.
-		 * Maybe on a long delay high speed link this would be
-	         * good initial guess, but over a slow link where the
-	         * delay is dominated by transmission time this will
-	         * be very bad, since ato will almost always be something
-		 * more like rtt/2. Better to discard data points that
-		 * are larger than the rtt estimate.
-	         */
-		if (m > sk->rtt)
+		if (m > (sk->rtt >> 3))
 		{
 			sk->ato = sk->rtt >> 3;
 			/*
@@ -741,7 +733,7 @@
 	 * (2) it has the same window as the last ACK,
 	 * (3) we have outstanding data that has not been ACKed
 	 * (4) The packet was not carrying any data.
-	 * (5) [From Floyds paper on fast retransmit wars]
+	 * (5) [From Floyd's paper on fast retransmit wars]
 	 *     The packet acked data after high_seq;
 	 * I've tried to order these in occurrence of most likely to fail
 	 * to least likely to fail.
diff -u --recursive --new-file pre2.0.5/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- pre2.0.5/linux/net/ipv4/tcp_output.c	Fri May 17 15:32:21 1996
+++ linux/net/ipv4/tcp_output.c	Sat May 18 11:15:09 1996
@@ -837,7 +837,7 @@
  *	  sending every two full sized packets will never need to be
  *	  invoked, the delayed ack will be sent before the ATO timeout
  *	  every time. Of course, the relies on our having a good estimate
- *	  for packet interarrival times.
+ *	  for packet interarrival times.)
  */
 void tcp_send_delayed_ack(struct sock * sk, int max_timeout, unsigned long timeout)
 {
