]> git.neil.brown.name Git - history.git/commitdiff
Import pre2.0.6 pre2.0.6
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:11:01 +0000 (15:11 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:11:01 +0000 (15:11 -0500)
109 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/cdrom/aztcd
Documentation/cdrom/cdrom-standard.tex
Documentation/cdrom/ide-cd
Documentation/filesystems/affs.txt
Documentation/isdn/INTERFACE
Documentation/isdn/README
Documentation/isdn/README.icn
Documentation/isdn/README.syncppp
Documentation/isdn/syncPPP.FAQ
Makefile
arch/alpha/defconfig
arch/alpha/kernel/traps.c
arch/i386/boot/video.S
arch/i386/defconfig
arch/m68k/kernel/head.S
drivers/block/genhd.c
drivers/block/ide-cd.c
drivers/block/ll_rw_blk.c
drivers/cdrom/aztcd.c
drivers/cdrom/mcdx.c
drivers/char/README.baycom
drivers/char/pcxx.c
drivers/isdn/Config.in
drivers/isdn/Makefile
drivers/isdn/icn/icn.c
drivers/isdn/icn/icn.h
drivers/isdn/isdn_audio.c [new file with mode: 0644]
drivers/isdn/isdn_audio.h [new file with mode: 0644]
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_net.c
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_ppp.h
drivers/isdn/isdn_tty.c
drivers/isdn/isdn_tty.h
drivers/isdn/pcbit/drv.c
drivers/isdn/teles/buffers.c
drivers/isdn/teles/callc.c
drivers/isdn/teles/card.c
drivers/isdn/teles/fsm.c
drivers/isdn/teles/isdnl2.c
drivers/isdn/teles/isdnl3.c
drivers/isdn/teles/l3_1TR6.c
drivers/isdn/teles/l3_1TR6.h
drivers/isdn/teles/llglue.c
drivers/isdn/teles/q931.c
drivers/isdn/teles/teles.h
drivers/net/8390.c
drivers/net/dummy.c
drivers/net/loopback.c
drivers/net/plip.c
drivers/net/ppp.c
drivers/net/sdla.c
drivers/net/slhc.c
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/README.qlogic [deleted file]
drivers/scsi/README.qlogicfas [new file with mode: 0644]
drivers/scsi/README.qlogicisp [new file with mode: 0644]
drivers/scsi/atari_NCR5380.c
drivers/scsi/atari_scsi.h
drivers/scsi/constants.c
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/qlogic.c [deleted file]
drivers/scsi/qlogic.h [deleted file]
drivers/scsi/qlogicfas.c [new file with mode: 0644]
drivers/scsi/qlogicfas.h [new file with mode: 0644]
drivers/scsi/qlogicisp.c [new file with mode: 0644]
drivers/scsi/qlogicisp.h [new file with mode: 0644]
drivers/scsi/qlogicisp_asm.c [new file with mode: 0644]
drivers/scsi/scsi.h
drivers/scsi/scsi_ioctl.c
drivers/scsi/sd.c
drivers/scsi/sr_ioctl.c
drivers/scsi/st.c
fs/Config.in
fs/affs/amigaffs.c
fs/affs/bitmap.c
fs/affs/dir.c
fs/affs/file.c
fs/affs/inode.c
fs/affs/namei.c
fs/affs/symlink.c
fs/buffer.c
fs/isofs/rock.c
include/asm-alpha/unaligned.h
include/asm-generic/unaligned.h [new file with mode: 0644]
include/asm-i386/unaligned.h [new file with mode: 0644]
include/linux/affs_fs.h
include/linux/affs_fs_i.h
include/linux/affs_fs_sb.h
include/linux/affs_hardblocks.h
include/linux/amigaffs.h
include/linux/aztcd.h
include/linux/isdn.h
include/linux/isdn_ppp.h
include/linux/isdnif.h
include/linux/mcdx.h
include/linux/proc_fs.h
include/net/sock.h
kernel/module.c
net/core/net_alias.c
net/decnet/README
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c

diff --git a/CREDITS b/CREDITS
index 6244be2ea7ae0f92cf998dd7ab75d5082bd4c75a..ca74bb5abbb8aa5d60dce90711a373ddc466544e 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -434,6 +434,15 @@ N: Philip Gladstone
 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 @@ S: USA
 
 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
@@ -1350,6 +1361,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
 D: Author of acct and quota
index b4c8a0933e7a1fbac7c2b4ebc73208ce18722498..0b6775088b8aeaac37a0b08d95caca6b5253c262 100644 (file)
@@ -324,8 +324,8 @@ throughout 1.3.x. A warning will be printed in 2.0.x when the old
 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
@@ -337,6 +337,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.
 
index 93ceacaecb0efe53cbab198cb59e9beb0d27ddf1..f3650f7fab346910e21336f9aa3ed2e0cc9dc9e8 100644 (file)
@@ -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 @@ CONFIG_EXPERIMENTAL
   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 @@ CONFIG_BLK_DEV_IDE
   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 @@ CONFIG_BLK_DEV_HD_IDE
   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 @@ CONFIG_BLK_DEV_IDECD
   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 @@ CONFIG_BLK_DEV_IDETAPE
   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 @@ CONFIG_BLK_DEV_PROMISE
 
 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 @@ CONFIG_NET
 
 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 @@ CONFIG_FIREWALL
   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 @@ CONFIG_PCI
   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 @@ CONFIG_BINFMT_AOUT
 
 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 @@ CONFIG_KERNELD
   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 @@ IP: multicasting
 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 @@ CONFIG_IP_ROUTER
 
 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 @@ CONFIG_IP_ALIAS
   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 @@ CONFIG_AX25
   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 @@ CONFIG_BPQETHER
 
 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 @@ CONFIG_NETLINK
   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 @@ CONFIG_SCSI_NCR53C7xx_FAST
  
 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 @@ CONFIG_NETDEVICES
   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 @@ CONFIG_SLIP_SMART
 
 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 @@ CONFIG_STRIP
 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 @@ CONFIG_PLIP
   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 @@ CONFIG_SDLA
   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 @@ CONFIG_QUOTA
   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 @@ CONFIG_NCP_FS
   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 @@ CONFIG_WATCHDOG
   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 @@ Software Watchdog
 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 @@ CONFIG_PROFILE_SHIFT
 
 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 @@ Use VJ-compression with synchronous PPP
 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 @@ CONFIG_AP1000
 # 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
index ea7de765f64e3fc932e9cb37cac88dfd4183b4cb..7ad9cc2050b69c18425ae20e0b8eed68481673f6 100644 (file)
@@ -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
index 43bbfb8551018563f175c5608b56091dccffb00e..78d887fab3ed20b63e68bd46e8cc55695027890d 100644 (file)
@@ -77,7 +77,7 @@ let the juke box work on even if a disk has fallen upon the floor and
 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\ 
index b543a257496025decc971e707d64957b8db29595..632940cfea6afde41ed1533301e2bc6cfbb11bac 100644 (file)
@@ -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 @@ This driver provides the following features:
 ---------------
 
 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 @@ This driver provides the following features:
 
    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 @@ This driver provides the following features:
    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 @@ This driver provides the following features:
    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 @@ TEST
 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 @@ from the driver.
 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 @@ a. Drive is not detected during booting.
 
    - 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 @@ a. Drive is not detected during booting.
      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 @@ c. System hangups.
     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 @@ d. Can't mount a cdrom.
 
     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
index 4e47d29e5de93e96e4ddd5fbc6d432ab52fcb77d..f561b5c8724025d666e6486e807150e00c34d163 100644 (file)
@@ -6,14 +6,12 @@ currently knows 6 different filesystems:
 
 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 @@ Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks
 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 @@ bs=blksize    Sets the blocksize to blksize. Valid block sizes are 512,
 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 @@ The Linux rwxrwxrwx file mode is handled as follows:
     
 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.
index 26e9e329599981d16d5b7a8047fb1d7bdd09ded5..295d1d71e362343680b6ac508a6740e2d7e1313c 100644 (file)
@@ -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 @@ Description of the Interface between Linklevel and Hardwarelevel
   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 @@ Description of the Interface between Linklevel and Hardwarelevel
 
   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 @@ Description of the Interface between Linklevel and Hardwarelevel
 
   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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ NOTE on writebuf and writebuf_skb:
                         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 @@ NOTE on writebuf and writebuf_skb:
                         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.)
index 5d5e339ddb2184f84c84ef7c6b0fe293b4060af9..a003cd79dc4940ea5ecb412c95428dde2687911d 100644 (file)
@@ -119,6 +119,8 @@ README for the ISDN-subsystem
                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 @@ README for the ISDN-subsystem
                                       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 @@ README for the ISDN-subsystem
        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 @@ README for the ISDN-subsystem
        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 @@ README for the ISDN-subsystem
        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,13 +379,16 @@ README for the ISDN-subsystem
      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.
 
    c) If you want to have really permanent "Modem"-settings on disk, you
index 66327c35c822a0ec420593513189c6c3e355fbad..3cd5171ff140357b52c3cdc7a8f6d3886b95e175 100644 (file)
@@ -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 @@ The card communicates with the PC by two interfaces:
   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:
 
index 5bdc48fdfe6a4622e012065dc4cc73a8c4dca2d8..27d260095cce35cd2967764b8b9ad492a1acf95c 100644 (file)
@@ -12,7 +12,7 @@ To compile isdn4linux with the sync PPP part, you have
 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 @@ Using isdn4linux with sync PPP:
 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 @@ for an example setup script.
 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
index 5743f6a42253dbeeee880a61c30c554e7a4ebe96..ab8a1ee217e7bb363a84d22b5f3aa1737abc6a88 100644 (file)
@@ -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.
-
-Q: when I start the ipppd .. I only get the
+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.
+
+--
+
+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 @@ A: Maybe you have compiled the ipppd with another
    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).
 
 
 
index 1e0937b7af192da782841239778e74412d3b5288..cf960dc84f6f34c624c264dde31f017d22684d0e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 99
-SUBLEVEL = 5
+SUBLEVEL = 6
 
 ARCH = i386
 
index 174ecb0349d674e7cac8c5ec1d60e589ff649071..ae3db1ea8ee87c72e31131f431478efc3e8ab955 100644 (file)
@@ -24,6 +24,7 @@ CONFIG_NATIVE=y
 # 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 @@ CONFIG_BLK_DEV_FD=y
 # 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_FAST=y
 # 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
index fd4575af7a0ea3bc6070ac6aa1f6bf665ae4ab3b..24145c4af0af57547b62c9324d506baf4ce6c05d 100644 (file)
@@ -70,9 +70,9 @@ asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
        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 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
        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 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
        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 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
  * 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;
 }
 
index 3db2f7c9517af77462bef3462c3d72fb09320f5d..994b5c195470dc2b8ea1b6a3096c34ab4b2ebf7b 100644 (file)
@@ -880,7 +880,7 @@ vesa1:      seg     gs              ! Get next mode in the list
        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
index 252db60ca1e16f4ec8b70828b4953995fcb71c3c..f0526b08318899c5c5f7513f87f4ab1403a3e82c 100644 (file)
@@ -44,13 +44,17 @@ CONFIG_BLK_DEV_IDECD=y
 # 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
index 4a55b16241966c5c8f1334f346cb78f682d5fdc2..795d7466e8acd296354045f68587b9bc2d7a8f73 100644 (file)
@@ -375,7 +375,7 @@ ENTRY(_start)
        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:
index 7a86984ec2e99ddc48f23419e20fd56934e8ae5e..d663335f16609498994c6e35ea0a49954171064e 100644 (file)
 
 #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;
 
index 50b7a7fd71e5eebb07b317f0d7381be0f4b456a7..9088f75eee6fadb20ba06366c08a2435195ee921 100644 (file)
@@ -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.
  * 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
 #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 @@ static void cdrom_start_read_continuation (ide_drive_t *drive)
        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 @@ cdrom_read_block (ide_drive_t *drive, int format, int lba,
                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 @@ cdrom_read_block (ide_drive_t *drive, int format, int lba,
 
 /* 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 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
                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 @@ void ide_cdrom_setup (ide_drive_t *drive)
  *  Establish interfaces for an IDE port driver, and break out the cdrom
  *   code into a loadable module.
  *  Support changers better.
- *  Write some real documentation.
  */
 
 
index 11410f4ca7d7e289a634800f5604eb2cd78b0263..6933b815339162a5c29a5eff9cdeae9436d7fa43 100644 (file)
@@ -286,9 +286,17 @@ static void make_request(int major,int rw, struct buffer_head * bh)
 
        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 @@ static void make_request(int major,int rw, struct buffer_head * bh)
                                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) {
index 18e4f2319aeeb35ab6628363da2fd157e22715e1..637739c1ef0a27732615f281db20225b84200d32 100644 (file)
@@ -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)
         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 @@ void aztcd_setup(char *str, int *ints)
 }
 
 /* 
- * 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 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsi
 #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 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsi
                  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 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
                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 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
                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 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
 #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 */
index f2b2094e949d2a05fd7c75a6e3c677a68103bc65..4c38cd6f73e25764a58c945b952ef56079496a93 100644 (file)
@@ -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 @@ static inline int irq(int *ip)
  * 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 @@ int read_toc(struct s_drive_stuff *stuffp)
                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 @@ static int mcdx_ioctl(struct inode *ip, struct file *fp,
        /*
         * 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 @@ static int mcdx_ioctl(struct inode *ip, struct file *fp,
                        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 @@ static int mcdx_ioctl(struct inode *ip, struct file *fp,
  * 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 @@ static int mcdx_media_change(kdev_t full_dev)
        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 @@ static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
        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 @@ static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
 
 /*
  * 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)
index 469b337d45f4d77c6c91f2fa3fa492d4ac3ed991..25f2f5846ed0edb7079b7e73b5a60ec5f8dce6a2 100644 (file)
@@ -79,7 +79,7 @@ or leave this task to kerneld (if installed). Add the following line to
 
 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
index 5666b2a406f90629d5ee31c5028a357960d48a5b..be1490a8bc32b7a885408ec3faf1a18cefea6ffa 100644 (file)
@@ -1868,6 +1868,9 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
                        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 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
                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;
index 5fd9edb62814c092f1346b1d21b9b04a87629643..96f7e5a43b8eef41ddee598e28cb277cc960ed19 100644 (file)
@@ -8,6 +8,7 @@ if [ "$CONFIG_INET" != "n" ]; then
     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
index 65f670558ffbabce48894b6219470d6b5b889455..3b441835e722f94bf11b3871aa5162bd107fb904 100644 (file)
@@ -18,6 +18,9 @@ ifeq ($(CONFIG_ISDN),y)
   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
@@ -27,6 +30,9 @@ else
     ifdef CONFIG_ISDN_PPP
       O_OBJS += isdn_ppp.o
     endif
+    ifdef CONFIG_ISDN_AUDIO
+      O_OBJS += isdn_audio.o
+    endif
   endif
 endif
 
index 9c8e068d81396a267d040e9a69943711300ac92e..6f5d4c8bbad24fa4b09128770fcd35d4c30ac4a5 100644 (file)
@@ -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.
  *
  * 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
 
 #include "icn.h"
 
-
-
 /*
  * Verbose bootcode- and protocol-downloading.
  */
  */
 #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 $";
-
-static void icn_pollcard(unsigned long dummy);
+*revision = "$Revision: 1.22 $";
 
-/* 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;
-       }
-}
+static int icn_addcard(int, char *, char *);
 
-#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 @@ static void icn_free_queue(pqueue ** queue)
  *            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)
+static void icn_pollbchan_receive(int channel, icn_card *card)
 {
-       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);
-       }
+        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 @@ static void icn_pollbchan_send(int channel, icn_dev * dev)
  * 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;
-
-       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;
-       }
+        icn_card *card = (icn_card *)data;
+        unsigned long 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;
 }
 
-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);
-               }
-}
+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 @@ static void icn_pollit(icn_dev * dev)
  * 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)
+{
+        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)
 {
-       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_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;
-
-       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;
+        int len = skb->len;
+        unsigned long flags;
+
+        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 @@ int slsec = sec; \
 #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));
+        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_dev * ldev)
+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;
+        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;
-
-       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);
+        unsigned long flags;
+        isdn_ctrl cmd;
+
+        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 int my_atoi(char *s)
+static void icn_stopallcards(void)
 {
-       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;
+        icn_card *p = cards;
+
+        while (p) {
+                icn_stopcard(p);
+                p = p->next;
+        }
 }
 
-static int icn_command(isdn_ctrl * c, icn_dev * ldev)
+static int icn_command(isdn_ctrl * c, icn_card * card)
 {
-       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;
+        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;
+
+        while (p) {
+                if (p->myid == driverid)
+                        return p;
+                p = p->next;
+        }
+        return (icn_card *)0;
 }
 
-static int if_command2(isdn_ctrl * c)
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int if_command(isdn_ctrl * c)
 {
-       return (icn_command(c, dev2));
-}
+        icn_card *card = icn_findcard(c->driver);
 
-static int if_writecmd1(const u_char * buf, int len, int user)
-{
-       return (icn_writecmd(buf, len, user, dev, 0));
+        if (card)
+                return (icn_command(c, card));
+        printk(KERN_ERR
+               "icn: if_command called with invalid driverId!\n");
+        return -ENODEV;
 }
 
-static int if_writecmd2(const 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_writecmd(buf, len, user, dev2, 0));
+        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_readstatus1(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, dev));
+        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_readstatus2(u_char * buf, int len, int user)
+static int if_sendbuf(int id, int channel, struct sk_buff *skb)
 {
-       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_sendbuf(channel, skb, 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)
-{
-       return (icn_sendbuf(channel, buffer, len, user, dev));
+/*
+ * 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 if_sendbuf2(int id, int channel, const u_char * buffer, int len,
-                      int user)
+static int icn_addcard(int port, char *id1, char *id2)
 {
-       return (icn_sendbuf(channel, buffer, len, user, dev2));
+        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 @@ static int if_sendbuf2(int id, int channel, const u_char * buffer, int len,
 #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
index 7e690a297c81f2d62c1c0b82d3c60f74a8e1bf99..86d44b329bf7e64721d99a0c786db29e7ea79fae 100644 (file)
@@ -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.
  *
  * 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
 #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__)
 
 #include <linux/wait.h>
 #include <linux/isdnif.h>
 
-#endif                         /* __KERNEL__ */
+#endif /* __KERNEL__ */
 
 /* some useful macros for debugging */
 #ifdef ICN_DEBUG_PORT
 #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_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_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_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_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_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;
-
-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
+/*
+ * 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;
+
+/*
+ * 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 @@ static char regname[35];    /* Name used for port/mem-registration */
 #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 --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c
new file mode 100644 (file)
index 0000000..b53149a
--- /dev/null
@@ -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 --git a/drivers/isdn/isdn_audio.h b/drivers/isdn/isdn_audio.h
new file mode 100644 (file)
index 0000000..fa7bd1b
--- /dev/null
@@ -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);
index 99600a679a6760d652d662d6e389f51a64498b56..6cf1d2a2db2b8e3810fc0bcc5adc00ca7c3d30c9 100644 (file)
@@ -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).
  *
  * 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 */
 #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 @@ extern char *isdn_ppp_revision;
 #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 @@ void isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
 }
 #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;
-
-       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();
+        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 @@ void isdn_timer_ctrl(int tf, int onoff)
        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 @@ static int isdn_status_callback(isdn_ctrl * c)
        ulong flags;
        int i;
        int r;
+        modem_info *info;
        isdn_ctrl cmd;
 
        di = c->driver;
@@ -323,9 +371,7 @@ static int isdn_status_callback(isdn_ctrl * c)
                                 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 @@ static int isdn_status_callback(isdn_ctrl * c)
                                          * 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 @@ static int isdn_status_callback(isdn_ctrl * c)
                         /* 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 @@ static int isdn_status_callback(isdn_ctrl * c)
                                                return 0;
                                        }
                                }
+                        }
                         break;
                 case ISDN_STAT_DHUP:
                        if (i<0)
@@ -457,19 +507,19 @@ static int isdn_status_callback(isdn_ctrl * c)
                                 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 @@ static int isdn_status_callback(isdn_ctrl * c)
                                /* 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 @@ static int isdn_status_callback(isdn_ctrl * c)
                         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 @@ static int isdn_status_callback(isdn_ctrl * c)
                         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 @@ static int isdn_status_callback(isdn_ctrl * c)
                         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 @@ int isdn_getnum(char **p)
        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 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun
                                 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 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun
                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 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun
                 }
                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 @@ static int isdn_write(struct inode *inode, struct file *file, const char *buf, i
                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 @@ static int isdn_write(struct inode *inode, struct file *file, const char *buf, i
                 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_write(struct inode *inode, struct file *file, const char *buf, i
 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 @@ static int isdn_select(struct inode *inode, struct file *file, int type, select_
                        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 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
                                 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 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
                                         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 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
                                                 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 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
                                                 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 @@ static int isdn_open(struct inode *ino, struct file *filep)
 
        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 @@ void isdn_free_channel(int di, int ch, int usage)
                         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 @@ void isdn_unexclusive_channel(int di, int ch)
 }
 
 /*
- *  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 @@ int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
                      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 @@ int register_isdn(isdn_if * i)
                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 @@ int register_isdn(isdn_if * i)
                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 @@ int isdn_init(void)
                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 @@ int isdn_init(void)
         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 @@ void cleanup_module(void)
                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 {
index 87b3b849614e6367a7db9fcb52e5405334d27bc8..cae4567cb6b9c733fa16d3e5d537b8f4aca3680e 100644 (file)
@@ -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 */
index ba93884f60846547728af70b2b18d8485ec5d677..1e62f62f207d09d9a481c4ad5dd6b62afea574d2 100644 (file)
@@ -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).
  *
  * 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_wildmat(char *s, char *p);
 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
@@ -142,6 +161,32 @@ isdn_net_bind_channel(isdn_net_local * lp, int idx)
         restore_flags(flags);
 }
 
+/*
+ * 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.
  *
@@ -232,6 +277,8 @@ isdn_net_stat_callback(int idx, int cmd)
                                /* 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 @@ isdn_net_hangup(struct device *d)
                 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 @@ isdn_net_xmit(struct device *ndev, isdn_net_local *lp, struct sk_buff *skb)
 
        /* 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_start_xmit(struct sk_buff *skb, struct device *ndev)
 {
        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(struct sk_buff *skb, struct device *ndev)
                                                "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 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                /* 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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
 #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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                } 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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                        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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
 #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 @@ int isdn_net_force_dial_lp(isdn_net_local * lp)
 #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 @@ isdn_net_new(char *name, struct device *master)
        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 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                 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 @@ int isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
                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 @@ static int isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
        restore_flags(flags);
 
 #ifdef CONFIG_ISDN_PPP
-       isdn_ppp_free_mpqueue(p);
+       isdn_ppp_free_mpqueue(p);       /* still necessary? */
 #endif
        kfree(p);
 
@@ -2342,6 +2388,26 @@ int isdn_net_rmall(void)
        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);
+        }
+       
+}
+
+
+
+
+
 
 
 
index eab7e4612719c91f61c402ceff80abe56c87c7fd..ad77c57159a6c0b1d3a8abe3b5d83b8df97f0070 100644 (file)
@@ -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).
  *
  * 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 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
                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,17 +143,32 @@ int isdn_ppp_bind(isdn_net_local * lp)
        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) {
                restore_flags(flags);
@@ -163,7 +195,12 @@ int isdn_ppp_bind(isdn_net_local * lp)
        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 @@ static int isdn_ppp_hangup(int minor)
 
 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 @@ int isdn_ppp_open(int minor, struct file *file)
        return 0;
 }
 
+/*
+ * release ippp device
+ */
 void isdn_ppp_release(int minor, struct file *file)
 {
        int i;
@@ -226,29 +265,24 @@ void isdn_ppp_release(int minor, struct file *file)
        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 @@ void isdn_ppp_release(int minor, struct file *file)
        ippp_table[minor]->state = 0;
 }
 
+/*
+ * get_arg .. ioctl helper
+ */
 static int get_arg(void *b, unsigned long *val)
 {
        int r;
@@ -267,6 +304,9 @@ static int get_arg(void *b, unsigned long *val)
        return 0;
 }
 
+/*
+ * set arg .. ioctl helper
+ */
 static int set_arg(void *b, unsigned long val)
 {
        int r;
@@ -276,15 +316,17 @@ static int set_arg(void *b, unsigned long val)
        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 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long
                        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 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long
                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 @@ int isdn_ppp_select(int minor, struct file *file, int type, select_table * st)
        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 @@ int isdn_ppp_select(int minor, struct file *file, int type, select_table * st)
                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 @@ int isdn_ppp_select(int minor, struct file *file, int type, select_table * st)
  *  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 @@ static int isdn_ppp_fill_rq(char *buf, int len, int minor)
                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 @@ int isdn_ppp_write(int minor, struct file *file,  const char *buf, int count)
        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 @@ int isdn_ppp_init(void)
                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_cleanup(void)
 
 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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                        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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
 
                                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 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
                }
        }
 
-#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 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
                        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 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
 #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 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
 }
 
 /*
- * 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 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 
 /* 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 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
        }
 #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 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
        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 @@ static int isdn_ppp_bundle(int minor, int unit)
        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 @@ int isdn_ppp_dial_slave(char *name)
 #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
+}
 
index 05a8036895d607ad729998916eb2e3467a6f2f96..cb01128c33ddb318da2334fbb6b8ee76575ec308 100644 (file)
@@ -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).
  *
  * 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 int  isdn_ppp_xmit(struct sk_buff *, struct device *);
 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 *);
index efa95c3562dacc097b1300b25e29e67e6fc6c2aa..f76dcaf0923a3b79573a22a29cda3960e22ed78c 100644 (file)
@@ -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).
  *
  * 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
 #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 void isdn_tty_modem_reset_regs(atemu *, int);
 
 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 @@ int isdn_tty_try_read(int i, u_char * buf, int len)
        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 @@ void isdn_tty_readmodem(void)
        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 @@ void isdn_tty_readmodem(void)
  *
  ************************************************************/
 
+/* 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 @@ static void isdn_tty_change_speed(modem_info * info)
                        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 @@ static int isdn_tty_startup(modem_info * info)
 
        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 @@ static int isdn_tty_startup(modem_info * info)
        /*
         * 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 @@ static int isdn_tty_startup(modem_info * info)
        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 @@ static void isdn_tty_shutdown(modem_info * info)
        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 @@ static void isdn_tty_shutdown(modem_info * info)
        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 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char *
        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);
+                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
-                               }
-                               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);
-                               }
-                       }
+                                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 @@ static int isdn_tty_write_room(struct tty_struct *tty)
 
        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 @@ static int isdn_tty_chars_in_buffer(struct tty_struct *tty)
 
        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 int isdn_tty_chars_in_buffer(struct tty_struct *tty)
 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 @@ static void isdn_tty_flush_chars(struct tty_struct *tty)
 
        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 @@ static void isdn_tty_throttle(struct tty_struct *tty)
                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 @@ static void isdn_tty_unthrottle(struct tty_struct *tty)
                else
                        info->x_char = START_CHAR(tty);
        }
-       info->MCR |= UART_MCR_RTS;
+       info->mcr |= UART_MCR_RTS;
 }
 
 /*
@@ -564,7 +884,7 @@ static int isdn_tty_get_lsr_info(modem_info * info, uint * value)
 
        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 @@ static int isdn_tty_get_modem_info(modem_info * info, uint * value)
        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_get_modem_info(modem_info * info, uint * value)
 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 @@ static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
        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);
+                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 TIOCSSERIAL:
-               return -ENOIOCTLCMD;
-#if 0
-               return set_serial_info(info,
-                                      (struct serial_struct *) arg);
+                        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 TIOCSERCONFIG:
-               return -ENOIOCTLCMD;
-#if 0
-               return do_autoconfig(info);
+                        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
-
-       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;
+                        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
-       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;
+                        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
-       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;
+                        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 @@ static void isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_ter
 {
        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 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m
         * 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 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m
                }
                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 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
 #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 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
        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 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
                 * 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 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
                                break;
                }
        }
+       dev->modempoll--;
        isdn_tty_shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
@@ -1039,22 +1347,10 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
                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 @@ static void isdn_tty_hangup(struct tty_struct *tty)
        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 @@ static void isdn_tty_reset_profile(atemu * m)
        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 @@ int isdn_tty_modem_init(void)
        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 @@ int isdn_tty_modem_init(void)
        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 @@ int isdn_tty_modem_init(void)
                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 @@ int isdn_tty_modem_init(void)
                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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
        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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
                                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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
 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 @@ static void isdn_tty_at_cout(char *msg, modem_info * info)
        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 @@ static void isdn_tty_on_hook(modem_info * info)
 #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 @@ static void isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pl
  */
 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 @@ void isdn_tty_modem_result(int code, modem_info * info)
                }
                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 @@ static void isdn_tty_show_profile(int ridx, modem_info * info)
 {
        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 @@ static void isdn_tty_getdial(char *p, char *q)
        *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 void isdn_tty_parse_at(modem_info * info)
  */
 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 @@ static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int use
                        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 @@ void isdn_tty_modem_escape(void)
 
        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 @@ void isdn_tty_modem_ring(void)
        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 @@ void isdn_tty_bsent(int drv, int chan)
        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 */
index e128464fb0039d9d29fd3f7ce3a6c83a02709867..f317d23ae3d27a7a00b4b607becef627e25286ec 100644 (file)
@@ -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).
  *
  * 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_xmit(void);
 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 *);
index 5e76e6301b554964b0ba99e5dffd57354e4654f8..4f4a3f8d60334f40d4e81b16a7559471421399b4 100644 (file)
@@ -52,9 +52,9 @@ static char* pcbit_devname[MAX_PCBIT_CARDS] = {
  */
 
 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_xmit(int driver, int chnum, struct sk_buff *skb)
 }
 
 
-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 @@ static int stat_end = 0;
 (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;
index c747dcb5ffd9be5f39c7406ff9b8c13e1f1b4957..30ed168348224018aecc47e680a40c2ca743498b 100644 (file)
@@ -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 @@ BufPoolAdd(struct BufPool *bp, int priority)
        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);
index 7ed0da48b3c96a97e5cf51a75d5f1bbd68f9753d..3eea3c8a8dd7faa42b6a733721d64b56ba174bbc 100644 (file)
@@ -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 @@ stat_debug(struct Channel *chanp, char *s)
        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 @@ r1(struct FsmInst *fi, int event, void *arg)
                   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 @@ r9(struct FsmInst *fi, int event, void *arg)
                   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 @@ r12(struct FsmInst *fi, int event, void *arg)
         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 @@ static struct FsmNode fnlist[] =
         {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 @@ static struct FsmNode fnlist[] =
         {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 @@ release_ds(int chan)
                   releasestack_isdnl2(st);
                   break;
           case (ISDN_PROTO_L2_HDLC):
+          case (ISDN_PROTO_L2_TRANS):
                   releasestack_transl2(st);
                   break;
         }
@@ -1121,22 +1122,13 @@ release_is(int chan)
         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 @@ init_ds(int chan, int incoming)
                   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 @@ teles_command(isdn_ctrl * ic)
                             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;
index 3eb297c4a7303700d12be6c8ea5875f9f70f63ae..d7787f32eae7e32a7a4cde245b123b34147c85ff 100644 (file)
@@ -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 @@ waitforCEC_3(int iobase, byte hscx)
 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 @@ waitforXFW_0(byte * base, byte hscx)
 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 @@ hscx_empty_fifo(struct HscxState *hsp, int count)
                 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 @@ hscx_fill_fifo(struct HscxState *hsp)
        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 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
                                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 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
                        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 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
                                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 @@ isac_new_ph(struct IsdnCardState *sp)
                          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 @@ isac_new_ph(struct IsdnCardState *sp)
 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 @@ teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 
        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 @@ teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                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 @@ checkcard(int cardnr)
                         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 @@ checkcard(int cardnr)
                 }
                 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 @@ modehscx(struct HscxState *hs, int mode,
        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 @@ get_irq(int cardnr)
 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 @@ closecard(int cardnr)
        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 @@ hscx_l2l1(struct PStack *st, int pr,
        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 @@ setstack_hscx(struct PStack *st, struct HscxState *hs)
 void
 teles_reportcard(int cardnr)
 {
-
        printk(KERN_DEBUG "teles_reportcard\n");
-
 }
index b75cd9bcf4f02e3329c03eb4f79c1b32ad7e171d..c0b2f494bf94ac06feb400fb6d7198088d7c92c8 100644 (file)
@@ -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
  *
index 6beaf2fab112a883529f9d12b64a92088c714ae7..779b7b70ac7aaaa4fd0b30d670bedb28bb7a6ee8 100644 (file)
@@ -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 @@ static void     l2m_debug(struct FsmInst *fi, char *s);
 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 @@ static char    *strL2Event[] =
        "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 @@ discard_i_queue(struct PStack *st)
                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 @@ static void
 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 @@ static void
 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 @@ setstack_isdnl2(struct PStack *st, char *debug_id)
        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
index b4088d14b60cd0722bd0832555f8b1e45e4c0439..6b93bfe71f1f1e6891f7bedfb3a3b5a8e571c1b1 100644 (file)
@@ -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 @@ l3s5(struct PStack *st, byte pr,
                  *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 @@ l3s13(struct PStack *st, byte pr, void *arg)
        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 @@ l3up(struct PStack *st,
                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 @@ l3up(struct PStack *st,
                          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 @@ l3up(struct PStack *st,
                                          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 @@ l3up(struct PStack *st,
                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 @@ l3up(struct PStack *st,
                                          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 @@ l3up(struct PStack *st,
                                          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 @@ l3down(struct PStack *st,
                              (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);
        }
index 71568e7ab43c776abe2f580848bedf3da335414d..a451eed2a42fe72a6709a0842e65810c3fca598b 100644 (file)
@@ -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.
  *
  */
 
-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 @@ l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
        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 @@ l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
        *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 @@ l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
                        *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 @@ l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
 
 }
 
-
 static void
 l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
 {
@@ -118,13 +115,7 @@ l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
        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 @@ l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
        } 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 @@ l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
        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 @@ l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
        } else
                printk(KERN_INFO "octect 3 not found\n");
 
+
        BufPoolRelease(ibh);
        newl3state(st, 2);
 }
@@ -193,10 +188,6 @@ l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg)
        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 @@ l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg)
        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 @@ static void
 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 @@ l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg)
        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 @@ l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg)
 {
        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 @@ l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg)
 {
        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 @@ l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg)
 {
        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 @@ l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg)
 {
        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 @@ l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg)
 {
        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 @@ static void
 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 @@ static void
 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 @@ l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
        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 @@ l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
 
        i_down(st, dibh);
 
-        if (rejflg)
-                newl3state(st, 0);
-        else
-                newl3state(st, 11);
+        newl3state(st, 11);
 }
 
 static void
@@ -473,8 +446,6 @@ l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
        newl3state(st, 19);
 }
 
-
-
 static struct stateentry downstatelist_1tr6t[] =
 {
        {0, CC_SETUP_REQ, l3_1tr6_setup},
index 451d7af586622e505cf2b7fdba352364389ae9c4..a3502fb36dc4d5f33d7f9ae4163b09ffc458875c 100644 (file)
@@ -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
  *
 /*
  * 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
 
 
 /*
 #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 @@ static struct MTypeDesc mtdesc_n1[] =
 #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 @@ static struct MTypeDesc mtdesc_n1[] =
 #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
index 8c164333032dbbdabdf9e183e8d5c2ed4a4efa2d..4f331504a10addafabedb742cb74bce0cc94dc82 100644 (file)
@@ -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_write = NULL;
 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 @@ ll_init(void)
        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;
index 4e740bd639c73348c5bb5c441baeeb7856cda679..ab8b7947f0268c95c769ea33723daead9e92a5ea 100644 (file)
@@ -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
  * 
  * 
  * 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 @@ struct MessageType {
 
 #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 @@ prcause(char *dest, byte * p)
        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 @@ prcause(char *dest, byte * p)
 }
 
 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 @@ prchident(char *dest, byte * p)
        *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 @@ prcalled(char *dest, byte * p)
        *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 @@ prcalling(char *dest, byte * p)
                *dp++ = '\n';
                l--;
        };
-
        p++;
 
        dp += sprintf(dp, "    number digits ");
@@ -575,10 +719,8 @@ prbearer(char *dest, byte * p)
        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 @@ general(char *dest, byte * p)
                        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 @@ struct InformationElement {
        },
 };
 
+
 #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;
+       } 
+       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 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);
-
-       /* 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);
 }
index f0007f58d8d63906d815f622f361846aa7d128e0..15ce659761d793e2a034016d1946e6febe88c11e 100644 (file)
@@ -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 @@ struct Param {
        int             chargeinfo;  /* Charge Info - only for 1tr6 in
                                      * the moment 
                                      */
+       int             spv;         /* SPV Flag */
 };
 
 struct PStack {
index 87008f8df6adc5c752d0f94849a1514f442df975..9864106bafb8a7f1c8a46b3417a95f56d31e431f 100644 (file)
@@ -617,7 +617,7 @@ static void ei_rx_overrun(struct device *dev)
     /* 
      * 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;
index 1135fbb2e963727e944672499b5f34829e98b64c..0ff16b74c815c242a36b57516af4d71c75521b41 100644 (file)
@@ -58,7 +58,6 @@ static int dummy_xmit(struct sk_buff *skb, struct device *dev);
 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 @@ static int dummy_close(struct device *dev)
        MOD_DEC_USE_COUNT;
        return 0;
 }
-#endif
 
 
 int dummy_init(struct device *dev)
@@ -89,10 +87,9 @@ int dummy_init(struct device *dev)
        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);
index 74181b54f93c720929d6251727445fab679cb5a7..4986d1fed9fe7c2f7936671f2f3f0e38c52b1c66 100644 (file)
@@ -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
index 10e574e167b4ec1408f796cabfce01528f29d59a..cd91ea15834afd4b607ee93d45d8666d97a7620e 100644 (file)
@@ -271,6 +271,7 @@ plip_init(struct device *dev)
        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 */
index 865e8bb0e9c5883a867b2053f249b05b1c7f4d0b..e918642cb8fa8eed29c04eea01f175b10771d5ab 100644 (file)
@@ -400,6 +400,7 @@ ppp_init_dev (struct device *dev)
        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++)
index 89058ab5567d5e4a8b99108efb934755377f5639..ff94f90987b70cef9f48096aea0713839c0eef1d 100644 (file)
@@ -367,7 +367,7 @@ static void sdla_errors(struct device *dev, int cmd, int dlci, int ret, int len,
                      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);
index 5b868315e8c53ec248cd6adab8cc5d6d9d6d3148..3f19301adc709ec568ba88ed713cd689336dc2ce 100644 (file)
 #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 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
          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;
index b1cd0cefcc456e2f0d24934d33a714aeb019ecf9..a8ef97990c4fa01ca3078aa6de8ce59f9f8ed189 100644 (file)
@@ -42,7 +42,12 @@ if [ "$CONFIG_PCI" = "y" ]; then
 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
index bfdbb86e9b8c546e5153865767b81f8f2cf57703..626a2ea37f8fe2ec6d8b5e8c453f88df41ed158d 100644 (file)
@@ -124,14 +124,24 @@ else
   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
 else
diff --git a/drivers/scsi/README.qlogic b/drivers/scsi/README.qlogic
deleted file mode 100644 (file)
index 2c2d840..0000000
+++ /dev/null
@@ -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 --git a/drivers/scsi/README.qlogicfas b/drivers/scsi/README.qlogicfas
new file mode 100644 (file)
index 0000000..737a03f
--- /dev/null
@@ -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 --git a/drivers/scsi/README.qlogicisp b/drivers/scsi/README.qlogicisp
new file mode 100644 (file)
index 0000000..ff2242c
--- /dev/null
@@ -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
index e16abe4a9e552cf8ba3fc5364fad2d31309a46ba..80e55aa6dceacc3507e58387414537ed99c53238 100644 (file)
@@ -631,7 +631,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
 
 #else /* !NDEBUG */
 
-/* dummys... */
+/* dummies... */
 __inline__ void NCR5380_print(struct Scsi_Host *instance) { };
 __inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
 
index b61b627c8e5b8ec324591130e90a887284ed8486..8488ea39ad1cae2f0ba11a256ffc2915d8f3da8c 100644 (file)
@@ -107,7 +107,7 @@ int atari_scsi_release (struct Scsi_Host *);
  *  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
index 07f071b21d53d232293da9fb8f6498d4b4337407..6250fefdd2eb0650b53040de48f4040f86a3e960 100644 (file)
@@ -365,13 +365,29 @@ static struct error_info additional[] =
 
 #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 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
     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 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
 #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)
index f35029d94ef90e4d9223781224ee0af1d9413265..6bf0a13f22893518d10d481c81ec7f1a3cc8c9b1 100644 (file)
 #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 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #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,
index 471f32d2cee2713216869249b1c4dbcd1d6efa73..7de6dbd7b06bad4cfe78f80a51e04a652b2149dd 100644 (file)
@@ -235,7 +235,7 @@ typedef struct      SHT
  * 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 --git a/drivers/scsi/qlogic.c b/drivers/scsi/qlogic.c
deleted file mode 100644 (file)
index e4f15f9..0000000
+++ /dev/null
@@ -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 --git a/drivers/scsi/qlogic.h b/drivers/scsi/qlogic.h
deleted file mode 100644 (file)
index 0ff119a..0000000
+++ /dev/null
@@ -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 --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
new file mode 100644 (file)
index 0000000..342d52a
--- /dev/null
@@ -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 --git a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h
new file mode 100644 (file)
index 0000000..4e0457f
--- /dev/null
@@ -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 --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
new file mode 100644 (file)
index 0000000..a400909
--- /dev/null
@@ -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 --git a/drivers/scsi/qlogicisp.h b/drivers/scsi/qlogicisp.h
new file mode 100644 (file)
index 0000000..c64d172
--- /dev/null
@@ -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 --git a/drivers/scsi/qlogicisp_asm.c b/drivers/scsi/qlogicisp_asm.c
new file mode 100644 (file)
index 0000000..7ab9189
--- /dev/null
@@ -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;
index b6acbd57aa88b8331914a299ff1d108b6c72eb0f..22c361a9ea924b353271daf4e5730e0239438488 100644 (file)
@@ -521,7 +521,7 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
     if (req->bh){
        req->buffer = bh->b_data;
        return SCpnt;
-    };
+    }
     DEVICE_OFF(req->rq_dev);
     if (req->sem != NULL) {
        up(req->sem);
index e3453d1e9ddbbf3d34c7824fdc11f27dc32c7965..42da5ecc237fcc019a1d2b9cccd6702e6206224d 100644 (file)
@@ -298,7 +298,7 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
 
 /*
  * 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)
index e68d085ee7aa9903fb6b9065246d8ad34a4e6c66..3bca2934e71fe0d126fb5b0056f8b6673a893f74 100644 (file)
@@ -106,28 +106,23 @@ static int sd_open(struct inode * inode, struct file * filp)
      */
     
     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 @@ static int sd_open(struct inode * inode, struct file * filp)
     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 @@ static void sd_geninit (struct gendisk *ignored)
 }
 
 /*
- * 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)
index 26d2b36e729d11bc1823f15a99f183243205e315..229bc908781e0257a810ab083b59d04118f93bc3 100644 (file)
@@ -554,21 +554,30 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
        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);
index b0aa76a1448da02b79a2d0669312b041687ebbde..18d2e40fe421849eb436f4f5f91131e20164aba3 100644 (file)
@@ -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 @@ scsi_tape_open(struct inode * inode, struct file * filp)
        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 @@ scsi_tape_open(struct inode * inode, struct file * filp)
     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 @@ scsi_tape_open(struct inode * inode, struct file * filp)
       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 @@ scsi_tape_open(struct inode * inode, struct file * filp)
               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 @@ scsi_tape_open(struct inode * inode, struct file * filp)
       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 @@ scsi_tape_open(struct inode * inode, struct file * filp)
       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 @@ scsi_tape_open(struct inode * inode, struct file * filp)
          (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 @@ scsi_tape_open(struct inode * inode, struct file * filp)
     }
 
     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 @@ void cleanup_module( void)
     }
   }
   st_template.dev_max = 0;
+  printk(KERN_INFO "st: Unloaded.\n");
 }
 #endif /* MODULE */
index 8ac62ab2972a44dd71cfa26b1880cbfceb459d94..208856183fe8409530f9a8224ad27dd326f1edb5 100644 (file)
@@ -35,11 +35,10 @@ fi
 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
index cc986de29cfed165cd7246fa81ac93bf1de4343c..63d76a86ee3e543e81dc7a9fd1e913081e5b9d88 100644 (file)
@@ -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 @@ extern struct timezone sys_tz;
    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 @@ affs_get_file_name(int bsize, void *fh_data, char **name)
 /* 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_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newke
                        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 @@ affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newke
 /* 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 @@ affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey)
                        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 @@ affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey)
    (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 @@ affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype)
 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 @@ secs_to_datestamp(int secs, struct DateStamp *ds)
 }
 
 int
-prot_to_mode(ULONG prot)
+prot_to_mode(__u32 prot)
 {
        int      mode = 0;
 
@@ -249,10 +249,10 @@ prot_to_mode(ULONG prot)
        return mode;
 }
 
-ULONG
+unsigned int
 mode_to_prot(int mode)
 {
-       ULONG    prot = 0;
+       unsigned int     prot = 0;
 
        if (mode & S_IXUSR)
                prot |= FIBF_SCRIPT;
index 50fbaead10b4b761635c5b10ce8fdbfaa6353e2d..00fd83eacf6658e52b300717ef01d3454891e685 100644 (file)
@@ -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 @@ affs_count_free_blocks(struct super_block *s)
 
        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 @@ found:
                        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 @@ affs_new_header(struct inode *inode)
        return block;
 }
 
-LONG
+int
 affs_new_data(struct inode *inode)
 {
        int                      empty, old;
@@ -251,7 +299,7 @@ affs_new_data(struct inode *inode)
        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 @@ affs_new_data(struct inode *inode)
                goto init_block;
        }
        unlock_super(sb);
-repeat:
        oldest = jiffies;
        old    = 0;
        empty  = 0;
@@ -287,19 +334,25 @@ repeat:
                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 @@ init_block:
 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);
        }
 }
index cf443bf8b5bbd618930543c3f62338639bfe3981..ad6a642f8e669207405410efef6e76217153ee46 100644 (file)
@@ -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 @@ struct inode_operations affs_dir_inode_operations = {
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
-       affs_dir_truncate,      /* truncate */
+       NULL,                   /* truncate */
        NULL                    /* permissions */
 };
 
@@ -72,11 +72,11 @@ static int
 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 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil
                 * 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 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil
                }
                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;
@@ -188,9 +189,3 @@ readdir_done:
        pr_debug("AFFS: readdir()=%d\n",stored);
        return stored;
 }
-
-void
-affs_dir_truncate(struct inode *inode)
-{
-       printk("AFFS: dir_truncate()\n");
-}
index 4b872ec5bd684bbe768fc637de6b9cc613956505..6cfbbf7245f1c8a352d49d858ea02a7e480cb236 100644 (file)
@@ -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 @@ struct inode_operations affs_file_inode_operations_ofs = {
 };
 
 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 @@ affs_bmap(struct inode *inode, LONG block)
 }
 
 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_getblock(struct inode *inode, LONG block)
        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 @@ affs_getblock_ofs(struct inode *inode, LONG block, LONG *blk_key)
                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 @@ affs_getblock_ofs(struct inode *inode, LONG block, LONG *blk_key)
                        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 @@ affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count)
                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 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int
        off_t                    pos;
        int                      written;
        int                      c;
+       int                      key;
        int                      blocksize;
        struct buffer_head      *bh;
        struct inode            *ino;
@@ -546,7 +553,7 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int
                (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 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int
                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 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int
        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 @@ affs_truncate(struct inode *inode)
        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 @@ affs_truncate(struct inode *inode)
        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);
index cba69f8ddf741e37c707e340fbae30cb32006c10..a1f3228f607121a575ffbb9a720b9fda8476ac7b 100644 (file)
@@ -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.
  * 
 #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 @@ affs_put_super(struct super_block *sb)
        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 @@ affs_put_super(struct super_block *sb)
 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 @@ affs_parent_ino(struct inode *dir)
        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 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i
                        }
                        *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 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i
        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 @@ affs_read_super(struct super_block *s,void *data, int silent)
        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 @@ affs_read_super(struct super_block *s,void *data, int silent)
         * 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 @@ affs_read_super(struct super_block *s,void *data, int silent)
                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 @@ affs_read_super(struct super_block *s,void *data, int silent)
        /* 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 @@ affs_read_super(struct super_block *s,void *data, int silent)
                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 @@ affs_read_super(struct super_block *s,void *data, int silent)
                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 @@ affs_read_super(struct super_block *s,void *data, int silent)
                        }
                        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 @@ affs_read_super(struct super_block *s,void *data, int silent)
                                        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 @@ affs_read_super(struct super_block *s,void *data, int silent)
                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 @@ nobitmap:
                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 @@ nobitmap:
                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 @@ nobitmap:
  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 @@ nobitmap:
 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 @@ affs_read_inode(struct inode *inode)
        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 @@ affs_new_inode(const struct inode *dir)
 {
        struct inode            *inode;
        struct super_block      *sb;
-       ULONG                    block;
+       int                      block;
 
        if (!dir || !(inode = get_empty_inode()))
                return NULL;
@@ -863,15 +890,15 @@ affs_new_inode(const struct inode *dir)
 
 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));
index b5bd1510cfe74a46fc0baee9306bb95572363cd4..f9f40b36286b0f52ebcd66f10feab3bda0b9935a 100644 (file)
@@ -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.
  *
 
 #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 @@ affs_find_entry(struct inode *dir, const char *name, int namelen,
 {
        struct buffer_head *bh;
        int      intl;
-       ULONG    key;
+       int      key;
 
        pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
 
@@ -137,7 +137,6 @@ affs_find_entry(struct inode *dir, const char *name, int namelen,
                        break;
                key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
        }
-       pr_debug("%lu\n",key);
        *ino = key;
        return bh;
 }
@@ -379,7 +378,6 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
        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 @@ affs_rename(struct inode *old_dir, const char *old_name, int old_len,
        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 @@ start_up:
                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 @@ end_rename:
 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;
 
index 2f0e98bcaeebb47a8d2ea083266d23d9dd186542..fe790ef5c04d69f5276b98d4df5ae3f4498278e3 100644 (file)
@@ -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
  *
index a6000753719cae84fb77636480711496b088bc62..a8952c87c638b87321af46549b44de72e4afae7c 100644 (file)
@@ -1270,6 +1270,8 @@ void unlock_buffer(struct buffer_head * bh)
            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;
index aef0846ba0c115b86d9344c3f76595135639452c..9f267e69dced6f510c82aaa870c98ea8865b2268 100644 (file)
@@ -367,7 +367,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
           }
 
           /*
-           * 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 @@ char * get_rock_ridge_symlink(struct inode * inode)
         }
 
         /*
-         * 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,"/");
index 071477496646cb9e0268f95d5064fba98e8885a6..69a2d54b2707173b88b5502523d3620b999da0c0 100644 (file)
@@ -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 @@ extern inline unsigned long ldq_u(unsigned long * r11)
                :"=&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 @@ extern inline unsigned long ldl_u(unsigned int * r11)
                :"=&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 @@ extern inline unsigned long ldw_u(unsigned short * r11)
                :"=&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 @@ extern inline void stq_u(unsigned long r5, unsigned long * r11)
                :"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 @@ extern inline void stl_u(unsigned long r5, unsigned int * r11)
                :"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;
 
@@ -109,4 +129,46 @@ extern inline void stw_u(unsigned long r5, unsigned short * r11)
                :"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 --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h
new file mode 100644 (file)
index 0000000..57b1402
--- /dev/null
@@ -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 --git a/include/asm-i386/unaligned.h b/include/asm-i386/unaligned.h
new file mode 100644 (file)
index 0000000..282ce19
--- /dev/null
@@ -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
index 15c4c11227ac2137ba2e54b979ba5eaef0b1622c..acc6f00940e86291b16cd0d1da24143493f84d41 100644 (file)
@@ -5,7 +5,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/amigaffs.h>
 
 #define AFFS_SUPER_MAGIC 0xadff
 
 /* 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 int               affs_notify_change(struct inode *inode, struct iattr *attr);
 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_chrdev_inode_operations;
 extern struct inode_operations  affs_blkdev_inode_operations;
 
 extern int init_affs_fs(void);
-
 #endif
index 62785ba3ea29574a5bb87271a3ce40af33afa04e..7230f0a3523aa598ac90dae243487f7cc7583ed5 100644 (file)
@@ -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;
 };
 
index 87d41c0d5ddea3112f9ec0ffacfacae3a9ddd87d..7d73710c95ed6a98972d51a6465ba7b53a256002 100644 (file)
@@ -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_sb_info {
        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. */
 };
index f7c943e9b29ec81a06e7d9607523c954ede1362b..33315488dc54d8e823fb48005993d65f1f4c9115 100644 (file)
@@ -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;
index 30d62360ed0419a71b43787377eddfe1056a7389..679f333e544258ea2a87950c4a9feda1e3b94b11 100644 (file)
@@ -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
 #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,121 +57,132 @@ struct DateStamp
 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 */
 
 #define FIBF_OTR_READ          0x8000
index 6154a992dc8eae6ce28fe4f96d4b1817a1043a85..71fe5a0df5454a30b42e398dfc46d37bf81f35e7 100644 (file)
@@ -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 */
index bc33fa1771f4b49cc4b2841910d227993ba9419b..a569192789a95084214f660e1570e401ed06b3da 100644 (file)
@@ -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).
  *
  * 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.
 #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 @@ typedef struct {
   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 @@ typedef struct {
 #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 @@ typedef struct isdn_net_local_s {
                                        /* 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 @@ typedef struct isdn_net_dev_s {
 #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 @@ struct ippp_struct {
   unsigned char *cbuf;
   struct slcompress *slcomp;
 #endif
+  unsigned long debug;
 };
 
 #endif
@@ -512,15 +545,6 @@ struct ippp_struct {
 
 /*======================= 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 @@ typedef struct {
   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   */
index b14fec0671207a4e9a4be5f05b70859ddbea26bd..5ce86f868e2781d11c179ca7db9357d2d18a0b6f 100644 (file)
@@ -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 @@ struct pppinfo
 #define MP_END_FRAG    0x40
 #define MP_BEGIN_FRAG  0x80
 
+#endif
index 875fc8148f9c119a3d563014a49ab468dbce4613..596192ba81a5b4725a9f6a68b839e15417384d78 100644 (file)
@@ -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
  *
  * 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
 #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
 #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 @@ typedef struct {
    *             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 @@ typedef struct {
    *                              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 @@ typedef struct {
    *                              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 @@ typedef struct {
    *                              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 @@ typedef struct {
  *              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 @@ typedef struct {
  *
  * 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.
  *
index 9fb518643c24c352856de1de958171cf69399cdb..cce1a7f006c616831058d8cdd8e5b39180468400 100644 (file)
@@ -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?
  *  
  */
 #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
                
 /* 
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!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
index d5a7688678edade60839961667ef82b529db1867..80776ef1743847f45189913990ab9ebef5359c47 100644 (file)
@@ -120,7 +120,8 @@ enum scsi_directory_inos {
        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,
index 6d87400e8f468d8ac375dbebf6432995f0273150..fdcd6fd81e5683f7659b5461f43b91e05b4b8424 100644 (file)
@@ -195,8 +195,8 @@ struct sock
        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 @@ struct sock
        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
index f40c40a599d97fd7c5f87ca0a345f4f4b27a57c8..d3e8a802bf2ebd9d01e17124f5c82c3abe9eed0f 100644 (file)
@@ -293,7 +293,7 @@ sys_delete_module(char *module_name)
        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;
index b0feb9ee62676601e7d20d98bf92eac0f767af76..e6f1fe3eb5917cc8923f2fe6f728b77aa6be21da 100644 (file)
@@ -235,6 +235,18 @@ net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev)
 }
 
 
+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 @@ net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat,
   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);
index 6f60472b26fedff54f798fcc2c978941d6a5531e..96816c47cc520303a6247127ddcfc108d130e6af 100644 (file)
@@ -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.
index 3a461bfe87c8580e9dd47fc7b850054e7c5d8d89..c1635c9df5641572565fa7425d1efadda6e72a86 100644 (file)
@@ -61,15 +61,7 @@ extern __inline__ void tcp_delack_estimator(struct sock *sk)
                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 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
         * (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.
index 0f2051bc2cb455354179d1015ce6cc3bb6e23b0f..e26154b7826a5bb858953749ad13ff1dd08b501d 100644 (file)
@@ -837,7 +837,7 @@ void tcp_send_synack(struct sock * newsk, struct sock * sk, struct sk_buff * skb
  *       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)
 {