]> git.neil.brown.name Git - history.git/commitdiff
Import 2.2.10pre4 2.2.10pre4
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:19:05 +0000 (15:19 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:19:05 +0000 (15:19 -0500)
121 files changed:
CREDITS
Documentation/Configure.help
Documentation/kernel-parameters.txt
Documentation/networking/ethertap.txt
Documentation/networking/ltpc.txt
Documentation/scsi-generic.txt
Documentation/video4linux/API.html
Documentation/video4linux/bttv/PROBLEMS
Documentation/video4linux/bttv/README.RADIO
Documentation/video4linux/bttv/README.WINVIEW [new file with mode: 0644]
Documentation/video4linux/bttv/THANKS
arch/alpha/defconfig
arch/alpha/kernel/head.S
arch/alpha/kernel/proto.h
arch/alpha/kernel/signal.c
arch/alpha/kernel/smp.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_takara.c
arch/alpha/kernel/time.c
arch/i386/boot/setup.S
arch/i386/kernel/mca.c
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/ppc/kernel/checks.c
drivers/block/floppy.c
drivers/char/bttv.c
drivers/char/bttv.h
drivers/char/n_hdlc.c
drivers/char/radio-cadet.c
drivers/char/synclink.c
drivers/char/tuner.c
drivers/char/tuner.h
drivers/misc/parport_share.c
drivers/net/3c515.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/cosa.c
drivers/net/cs89x0.c
drivers/net/irda/Config.in
drivers/net/irda/Makefile
drivers/net/irda/actisys.c
drivers/net/irda/esi.c
drivers/net/irda/girbil.c
drivers/net/irda/irport.c
drivers/net/irda/litelink.c
drivers/net/irda/pc87108.c
drivers/net/irda/smc-ircc.c [new file with mode: 0644]
drivers/net/irda/tekram.c
drivers/net/irda/uircc.c
drivers/net/irda/w83977af_ir.c
drivers/net/ni52.c
drivers/net/ni52.h
drivers/net/ni65.c
drivers/net/sk_mca.c [new file with mode: 0644]
drivers/net/sk_mca.h [new file with mode: 0644]
drivers/pci/oldproc.c
drivers/sbus/char/aurora.c
drivers/scsi/Config.in
drivers/scsi/README.aic7xxx
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx/aic7xxx.reg
drivers/scsi/aic7xxx/aic7xxx.seq
drivers/scsi/aic7xxx/scsi_message.h
drivers/scsi/aic7xxx_proc.c
drivers/scsi/aic7xxx_reg.h
drivers/scsi/aic7xxx_seq.c
drivers/scsi/scsi.h
drivers/scsi/scsi_proc.c
drivers/scsi/scsi_syms.c
drivers/scsi/scsicam.c
drivers/scsi/sd.c
drivers/scsi/sg.c
fs/Config.in
fs/coda/inode.c
fs/nfs/read.c
include/asm-alpha/init.h
include/asm-alpha/io.h
include/asm-alpha/mmu_context.h
include/asm-alpha/system.h
include/asm-i386/bugs.h
include/linux/pci.h
include/linux/synclink.h
include/net/irda/dongle.h
include/net/irda/ircomm_common.h
include/net/irda/irda_device.h
include/net/irda/irlan_common.h
include/net/irda/irlan_eth.h
include/net/irda/irport.h
include/net/irda/irqueue.h
include/net/irda/irvtd.h
include/net/irda/smc-ircc.h [new file with mode: 0644]
include/net/irda/smc_ircc.h [deleted file]
include/scsi/scsicam.h
include/scsi/sg.h
kernel/signal.c
kernel/sys.c
mm/memory.c
mm/swapfile.c
net/ipv4/icmp.c
net/ipv4/ip_fw.c
net/ipv4/ipmr.c
net/irda/Config.in
net/irda/af_irda.c
net/irda/discovery.c
net/irda/ircomm/ircomm_common.c
net/irda/ircomm/irvtd_driver.c
net/irda/irda_device.c
net/irda/irlan/irlan_client.c
net/irda/irlan/irlan_client_event.c
net/irda/irlan/irlan_common.c
net/irda/irlan/irlan_eth.c
net/irda/irlan/irlan_filter.c
net/irda/irlap.c
net/irda/irlap_event.c
net/irda/irlap_frame.c
net/irda/irlmp.c
net/irda/irlmp_frame.c
net/irda/irmod.c
net/irda/irttp.c
net/irda/wrapper.c

diff --git a/CREDITS b/CREDITS
index 8995afa42d00c07f29a904c77b369b3c88c61b94..407b670109baba7ffa90b4c1cdaae8a0cb7bf11c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -611,6 +611,13 @@ S: 1123 North Oak Park Avenue
 S: Oak Park, Illinois 60302
 S: USA
 
+N: Daniel J. Frasnelli
+E: dfrasnel@alphalinux.org   
+W: http://www.alphalinux.org/
+P: 1024/3EF87611 B9 F1 44 50 D3 E8 C2 80  DA E5 55 AA 56 7C 42 DA
+D: DEC Alpha hacker
+D: Miscellaneous bug squisher
+
 N: Jim Freeman
 E: jfree@sovereign.org
 W: http://www.sovereign.org/
@@ -808,7 +815,7 @@ S: 14059 Berlin
 S: Germany
 
 N: Michael Hipp
-E: mhipp@student.uni-tuebingen.de
+E: hippm@informatik.uni-tuebingen.de
 D: drivers for the racal ni5210 & ni6510 Ethernet-boards
 S: Talstr. 1
 S: D - 72072 Tuebingen
index da76a5930f3b7bad9631fee6b95fb73da88a32f0..953cd74e2501257e91bfe85b65e38b4aeedfec12 100644 (file)
@@ -3749,34 +3749,49 @@ CONFIG_SCSI_AIC7XXX
   say M here and read Documentation/modules.txt. The module will be
   called aic7xxx.o.
 
-Override driver defaults for commands per LUN
-CONFIG_OVERRIDE_CMDS
-  Say Y here if you want to override the default maximum number of
-  commands that a single device on the aic7xxx controller is allowed
-  to have active at one time. This option only affects tagged queueing
-  capable devices. The driver uses a value of 24 by default.
-  If you say Y here, you can adjust the number of commands per LUN
-  with the following configuration option.
+Enable or Disable Tagged Command Queueing by default
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+  This option causes the aic7xxx driver to attempt to use tagged command
+  queueing on any devices that claim to support it.  If this is set to yes,
+  you can still turn off TCQ on troublesome devices with the use of the
+  tag_info boot parameter.  See /usr/src/linux/drivers/scsi/README.aic7xxx
+  for more information on that and other aic7xxx setup commands.  If this
+  option is turned off, you may still enable TCQ on known good devices by
+  use of the tag_info boot parameter.
   
-  If unsure, say N.
-
-Maximum number of commands per LUN
-CONFIG_AIC7XXX_CMDS_PER_LUN
-  Specify the maximum number of commands you would like to allocate
-  per LUN (a LUN is a Logical Unit Number -- some physical SCSI
-  devices, e.g. CD jukeboxes, act logically as several separate units,
-  each of which gets its own number).
-
-  Reasonable figures are in the range of 14 to 32 commands per device,
+  If you are unsure about your devices then it is safest to say N here.
+  
+  However, TCQ can increase performance on some hard drives by as much
+  as 50% or more, so I would recommend that if you say N here, that you
+  at least read the README.aic7xxx file so you will know how to enable
+  this option manually should your drives prove to be safe in regards
+  to TCQ.
+
+  Conversely, certain drives are known to lock up or cause bus resets when
+  TCQ is enabled on them.  If you have a Western Digital Enterprise SCSI
+  drive for instance, then don't even bother to enable TCQ on it as the
+  drive will become unreliable, and it will actually reduce performance.
+
+Default number of TCQ commands per device
+CONFIG_AIC7XXX_CMDS_PER_DEVICE
+  Specify the number of commands you would like to allocate per SCSI
+  device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+  Reasonable figures are in the range of 8 to 24 commands per device,
   but depending on hardware could be increased or decreased from that
   figure. If the number is too high for any particular device, the
   driver will automatically compensate usually after only 10 minutes
-  of uptime and will issue a message to alert you to the fact that the
-  number of commands for that device has been reduced. It will not
-  hinder performance if some of your devices eventually have their
-  commands per LUN reduced, but is a waste of memory if all of your
-  devices end up reducing this number down to a more reasonable
-  figure. Default: 24
+  of uptime. It will not hinder performance if some of your devices
+  eventually have their command depth reduced, but is a waste of memory
+  if all of your devices end up reducing this number down to a more
+  reasonable figure.
+  
+  NOTE: Certain very broken drives are known to lock up when given more
+  commands than they like to deal with.  Quantum Fireball drives are the
+  most common in this category.  For the Quantum Fireball drives I would
+  suggest no more than 8 commands per device.
+
+  Default: 8
 
 Collect statistics to report in /proc
 CONFIG_AIC7XXX_PROC_STATS
@@ -6160,6 +6175,20 @@ CONFIG_NE2_MCA
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+SKnet MCA support
+CONFIG_SKMC
+  This are Micro Channel ethernet adapters.  You need to set CONFIG_MCA
+  to use this driver.  It's both available as an in-kernel driver and
+  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 as well as
+  Documentation/networking/net-modules.txt. If you plan to use more than
+  one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
+  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.  Supported
+  cards are the SKnet Junior MC2 and the SKnet MC2(+).  Distinguishing
+  both cards is done automatically.  Note that using multiple boards
+  of different type hasn't been tested with this driver.
+
 EISA, VLB, PCI and on board controllers
 CONFIG_NET_EISA
   This is another class of network cards which attach directly to the
index 9c293fbc9f45138f01274e97aa8c45f5dec8e72b..e1392c277afc0da5fe84f0e1d518553cc8914d73 100644 (file)
@@ -37,7 +37,7 @@ restrictions referred to are that the relevant option is valid if:
     SOUND      Appropriate sound system support is enabled.
     VGA        The VGA console has been enabled.
     VT         Virtual terminal support is enabled.
-    XT         IBM PC/XT support is enabled.
+    XT         IBM PC/XT MFM hard disk support is enabled.
 
 In addition, the following text indicates that the option:
 
index 27202efbaf1f64c10a9fe2ece1f1e418ce517efc..6f6214baf72d9fc29a7fd179cd58fcfdce75e2f8 100644 (file)
@@ -1,7 +1,7 @@
 Documentation on setup and use of EtherTap.
 
 Contact Jay Schulist <Jay.Schulist@spacs.k12.wi.us> if you
-have questions or need futher assistance.
+have questions or need further assistance.
 
 Introduction
 ============
@@ -49,11 +49,11 @@ get the general idea.
 
         1.2.3.4 will be the router to the outside world
         1.2.3.5 our box
-        2.0.0.1 our box (appletalk side)
-        2.0.0.* a pile of macintoys
+        2.0.0.1 our box (AppleTalk side)
+        2.0.0.* a pile of Macintoys
 
 
-[1.2.3.4]-------------1.2.3.5[Our Box]2.0.0.1---------> macs
+[1.2.3.4]-------------1.2.3.5[Our Box]2.0.0.1---------> Macs
 
 The routing on our box would be
 
index ed9983f0786b215d5aee043534a35626efd59a6d..4c1c25195724a8d6ce224bbf5d748dd1c6a2d3bd 100644 (file)
@@ -65,7 +65,7 @@ line in atalkd.conf is
 
 Card Configuration:
 
-The interrupts and so forth are configured via the dipswitch on the
+The interrupts and so forth are configured via the DIP switch on the
 board.  Set the switches so as not to conflict with other hardware.
 
        Interrupts -- set at most one.  If none are set, the driver uses
index 17822c4ad70fcf43b8eb885622782c3396e154c9..2d26dec9d2e8d5a49a9bec3d50c201ffa2636480 100644 (file)
@@ -1,34 +1,38 @@
-            Notes on Linux's SG driver version 2.1.30
+            Notes on Linux's SG driver version 2.1.34
             -----------------------------------------
-                                                        990328
+                                                        990606
 
 Introduction
 ============
+Sg is one of the four "high level" SCSI device drivers along with
+sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized
+(but lower level) than its siblings and tends to be used on SCSI devices
+that don't fit into the already serviced categories. Thus sg is used for
+scanners, cd writers and reading audio cds digitally amongst other things.
+
 These are notes on the Linux SCSI generic packet device driver (sg)
-describing version 2.1.30 . The original driver was written by Lawrence
-Foard and has remained in place with minimal changes since circa 1992.
+describing version 2.1.34 . The original driver was written by Lawrence
+Foard and remained in place with minimal changes since circa 1992.
 Version 2 of this driver remains backward compatible (binary and
 source **) with the original. It adds scatter gather, command queuing,
 per file descriptor sequencing, asynchronous notification and better
 error reporting.
 
-Sg is one of the four "high level" SCSI device drivers along with
-sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized
-(but lower level) than its sibling and tends to be used on SCSI devices
-that don't fit into the already serviced categories. Thus sg is used for
-scanners, cd writers and reading audio cds amongst other things.
+This is an abridged version of the sg documentation that is targeted
+at the linux/Documentation directory. The full document can be found
+at http://www.torque.net/sg/p/scsi-generic_long.txt .
 
-The interface and usage of the original sg driver has been documented
+The interface and usage of the original sg driver have been documented
 by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy
 of the document is version 1.5 dated 7th May 1996. It can found at
-ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/SCSI-Programming-HOWTO .
-Amongst other things it has a lot of tables from the SCSI-2 standard
-that are very useful for programming this interface.
+ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO-SCSI-Programming-HOWTO .
+A copy of this document can be found at:
+http://www.torque.net/sg/p/original/HOWTO-SCSI-Programming-HOWTO .
 
 ** It is possible to write applications that perform differently
 depending on whether they are using the original or this version of
-the sg device driver. The author is not aware of any useful applications
-that have problems with version 2 (yet).
+the sg device driver. The author is not aware of any useful 
+pre-existing applications that have problems with version 2 (yet).
 
 
 Architecture
@@ -38,9 +42,11 @@ It is one of the four high level device driver in the SCSI sub-system;
 the others are sd (for direct-access devices - disks), st (for tapes)
 and sr (for data cdroms). The other three devices are block devices.
 
-The unifying layer of the SCSI sub-system in the so-called mid-level.
-Below that are all the drivers for the various adapters supported by
-Linux.
+The unifying layer of the SCSI sub-system is the so-called mid-level.
+Below that are the "low level" drivers which are the drivers for the
+various adapters supported by Linux. Also at this level are pseudo
+adapter drivers such as ide-scsi which converts the SCSI protocol to
+ATAPI (which are similar to one another) for use by IDE devices.
 
 Since sg is a character device it supports the traditional Unix
 system calls of open(), close(), read(), write() and ioctl(). Two other
@@ -85,8 +91,9 @@ struct sg_header {
     unsigned char sense_buffer[16];
 }; /* this structure is 36 bytes long */
 
-The 'pack_len' is bizzare and ends up having the 'reply_len' put in it
-(perhaps it had a use at some stage). 
+The 'pack_len' is bizarre and ends up having the 'reply_len' put in it
+(perhaps it had a use at some stage). Even though it looks like an
+input variable, it is not read by sg internally (only written).
 
 The 'reply_len' is the length of the data the corresponding read()
 will/should request (including the sg_header). 
@@ -95,14 +102,14 @@ The 'pack_id' is not acted upon by the sg device driver but is conveyed
 back to the corresponding read() so it can be used for sequencing by an
 application. 
 
-The 'result' is also bizzare, turning certain types of host codes it 0 (no
+The 'result' is also bizarre, turning certain types of host codes to 0 (no
 error), EBUSY or EIO. With better error reporting now available, the
 'result' is best ignored.
 
-The 'twelve_byte' field overrides the internal SCSI command length "guessing"
+The 'twelve_byte' field overrides the internal SCSI command length detection
 algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces
-a command lenth of 12 bytes.
-The command length "guessing" algorithm is as follows:
+a command length of 12 bytes.
+The command length detection algorithm is as follows:
 Group:  0    1    2    3    4    5    6    7
 Length: 6   10   10   12   12   12   10   10
 
@@ -115,6 +122,7 @@ or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This
 buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately
 this is unlikely to happen in the 2.2.x series of kernels.
 
+
 The new sg_header offered in this driver is:
 #define SG_MAX_SENSE 16
 struct sg_header
@@ -122,15 +130,17 @@ struct sg_header
     int pack_len;    /* [o] reply_len (ie useless) ignored as input */
     int reply_len;   /* [i] max length of expected reply (inc. sg_header) */
     int pack_id;     /* [io] id number of packet (use ints >= 0) */
-    int result;      /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */
+    int result;      /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
     unsigned int twelve_byte:1;
         /* [i] Force 12 byte command length for group 6 & 7 commands  */
     unsigned int target_status:5;   /* [o] scsi status from target */
     unsigned int host_status:8;     /* [o] host status (see "DID" codes) */
     unsigned int driver_status:8;   /* [o] driver status+suggestion */
     unsigned int other_flags:10;    /* unused */
-    unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is
-               CHECK_CONDITION or COMMAND_TERMINATED this is output. */
+    unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
+           when target_status is CHECK_CONDITION or 
+           when target_status is COMMAND_TERMINATED or
+           when (driver_status & DRIVER_SENSE) is true. */
 };      /* This structure is 36 bytes long on i386 */
 
 Firstly the new header is binary compatible with the original. This is
@@ -146,6 +156,9 @@ EAGAIN) until a packet with that 'pack_id' becomes available. In all cases
 the value of 'pack_id' available after a read() is the value given to that
 variable in the prior, corresponding write().
 
+The SCSI command length can now be given directly using the SG_NEXT_CMD_LEN
+ioctl().
+
 The 'target_status' field is always output and is the (masked and shifted
 1 bit right) SCSI status code from the target device. The allowable
 values are (found in <scsi/scsi.h>):
@@ -162,28 +175,28 @@ values are (found in <scsi/scsi.h>):
 When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the
 'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE)
 is true then the 'sense_buffer' is also output (this seems to occur when
-the scsi ide emulation is used). When the 'sense_buffer' is output the 
+the ide-scsi emulation is used). When the 'sense_buffer' is output the 
 SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) .
 
 The 'host_status' field is always output and has the following values
-whose "defines" are not visible outside the kernel (unfortunately):
+whose "defines" are not visible outside the kernel. A copy of these
+defines can be found in sg_err.h (see the utilities section):
 #define DID_OK          0x00 /* NO error                                */
 #define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
 #define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
 #define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
-#define DID_BAD_TARGET  0x04 /* BAD target.                             */
+#define DID_BAD_TARGET  0x04 /* BAD target, device not responding?      */
 #define DID_ABORT       0x05 /* Told to abort for some other reason     */
 #define DID_PARITY      0x06 /* Parity error                            */
-#define DID_ERROR       0x07 /* Internal error                          */
+#define DID_ERROR       0x07 /* Internal error [DMA underrun on aic7xxx]*/
 #define DID_RESET       0x08 /* Reset by somebody.                      */
 #define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */
 #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
-#define DID_SOFT_ERROR  0x0b /* The low level driver just wish a retry  */
+#define DID_SOFT_ERROR  0x0b /* The low level driver wants a retry      */
 
 The 'driver_status' field is always output. When ('driver_status' &
-DRIVER_SENSE) is true the 'sense_buffer' is also output. The following
-values whose "defines" are not visible outside the kernel (unfortunately)
-can occur:
+DRIVER_SENSE) is true the 'sense_buffer' is also output. A copy of these
+defines can be found in sg_err.h (see the utilities section):
 #define DRIVER_OK           0x00 /* Typically no suggestion */
 #define DRIVER_BUSY         0x01
 #define DRIVER_SOFT         0x02
@@ -192,7 +205,7 @@ can occur:
 #define DRIVER_INVALID      0x05
 #define DRIVER_TIMEOUT      0x06
 #define DRIVER_HARD         0x07
-#define DRIVER_SENSE        0x08
+#define DRIVER_SENSE        0x08 /* Implies sense_buffer output */
 /* above status 'or'ed with one of the following suggestions */
 #define SUGGEST_RETRY       0x10
 #define SUGGEST_ABORT       0x20
@@ -200,55 +213,8 @@ can occur:
 #define SUGGEST_DIE         0x40
 #define SUGGEST_SENSE       0x80
 
-'other_flags' still remains as a 10 bit field, so code that places 0 in it
-will still be happy. It is not used.
-
-
-memory
-======
-Memory is a scarce resource in any computer. Sg needs to reserve memory
-suitable for DMA roughly equal in size to the maximum of the write and
-read data buffers for each packet. This DMA memory is obtained at the time
-of a write() and released when the corresponding read() is called (although
-if memory is tight it may be using the buffer reserved by the open() ).
-
-Linux obtaining memory a challenge for several reasons. The memory pool
-that sg uses is in common with all other device drivers and all user
-processes. In this environment the only way to 99.9% guarantee a driver
-will have memory in Linux is to build it into the kernel (ie not as a
-module) and then reserve it on initialization before user processes get
-a chance. [Of course, another driver initialized before sg could take
-all available memory ...] Another problem is the biggest contiguous
-chunk of memory that can be obtained from the kernel is 32 * PAGE_SIZE
-(which is 128KBytes on i386). As memory gets "splintered" there is a good
-chance that buffers won't be available (my machine has 64 MBytes of RAM
-and has 3 available at the moment).
-
-The original sg driver used the following technique: grab a SG_BIG_BUFF
-sized buffer at driver initialization and use it for all requests greater
-than PAGE_SIZE (4096 bytes on i386). By default SG_BIG_BUFF is set to
-32 KBytes in the origianl driver but many applications suggest that the
-user increases this number. Linux limits the biggest single buffer of
-this type to 32 * PAGE_SIZE (128KBytes on i386). Unfortunately if the
-sg driver is a module then there is a high chance a contiguous block of
-that large size will not be available at module initialization.
-
-The author has found no "silver bullet" solution but uses multiple
-techniques hoping that at least one is able provide memory at the critical
-time. Listed below are some of these techniques:
-        - use scatter gather: then instead of one large buffer needing to
-          be found, multiple smaller buffer can be used
-        - use memory above the 16MByte level: the original driver limited
-          itself to obtaining memory below the 16MByte level (on the i386)
-          due to the shortcomings of DMA on ISA adapters. Yet more and more
-          people use PCI adapters that don't have this problem. So make
-          the decision based on the capabilities of the host adpater
-          associated with the current SCSI device
-        - reserve some memory at open() for emergencies but otherwise
-          fetch and release it on a per packet basis
-        - if the kernel is short of memory then dip into the SCSI DMA
-          pool (maintained by the mid-level driver) to a limited amount
-
+'other_flags' still remains as a 10 bit field (reduced from 31 bits), so
+code that places 0 in it will still be happy. It is not used.
 
 
 System Calls
@@ -257,16 +223,16 @@ What follows are descriptions of the characteristics of the standard
 Unix operating system calls when applied to a SCSI generic device
 using this version of the device driver.
 
-open
-----
+open(const char * filename, int flags)
+--------------------------------------
 The filename should be an 'sg' device such as
 /dev/sg[a-z]
 /dev/sg[0,1,2,...]
 or a symbolic link to one of these. [Devfs has its own sub-directory for
-sg devices.] It seems as though SCSI devices are allocated to sg minor
-numbers in the same order as they appear in 'cat /proc/scsi/scsi'.
-Sg is a "character" based Linux device driver. This means it has an
-open/close/read/write/ioctl type interface.
+sg devices with entries like: /dev/sg/c1b2t3u4 .] It seems as though SCSI
+devices are allocated to sg minor numbers in the same order as they appear
+in 'cat /proc/scsi/scsi'. Sg is a "character" based Linux device driver.
+This means it has an open/close/read/write/ioctl type interface.
 
 Flags can be either O_RDONLY or O_RDWR or-ed with either
 O_EXCL          waits for other opens on sg device to be closed before
@@ -279,7 +245,7 @@ O_NONBLOCK      Sets non-blocking mode. Calls that would otherwise block
 The original version of sg did not allow the O_RDONLY (yielding a EACCES
 error). This version allows it for accessing ioctls (e.g. doing an sg
 device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be
-allowed.
+allowed. These flags are found in <fcntl.h> .
 
 By default, sequencing is per file descriptor in this version of sg. This
 means, for example that 2 processes can independently manipulate the same
@@ -290,32 +256,38 @@ on the same device at the same time probably wouldn't be a good idea. The
 previous version of sg supported only per device sequencing and this can
 still be selected with the SG_SET_MERGE_FD,1 ioctl().
 
-The driver will attempt to reserve SG_SCATTER_SZ bytes (32KBytes in the
-current sg.h) on open() for "emergency" situations. If this is unavailable
-it will halve its request and try again. It gives up if PAGE_SIZE bytes
-(4096 bytes on i386) cannot be obtained so no memory is reserved. In this
-case open() will still return successfully. The actual amount of memory
-reserved can be found with the SG_GET_RESERVED_SIZE ioctl().
+The driver will attempt to reserve SG_DEF_RESERVED_SIZE bytes (32KBytes in
+the current sg.h) on open(). The size of this reserved buffer can
+subsequently be modified with the SG_SET_RESERVED_SIZE ioctl(). In both
+cases these are requests subject to various dynamic constraints. The actual
+amount of memory obtained can be found by the SG_GET_RESERVED_SIZE ioctl().
+The reserved buffer will be used if:
+    -  it is not already in use (eg when command queuing is in use)
+    -  a write() does not call for a buffer size larger than the
+       reserved size.
 
 Returns a file descriptor if >= 0 , otherwise -1 implies an error.
 
 Error codes (value in 'errno' after -1 returned):
-ENODEV          sg not compiled into kernel or the kernel cannot find the
-                sg module (or it can't initialize itself (low memory??))
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
+EACCES          Either the user doesn't have appropriate permissions on 
+                'filename' or attempted to use both O_RDONLY and O_EXCL
 EBUSY           O_NONBLOCK set and some user of this sg device has O_EXCL
                 set while someone is already using this device
 EINTR           while waiting for an "exclusive" lock to clear, a signal
                 is received, just try again ...        
+ENODEV          sg not compiled into kernel or the kernel cannot find the
+                sg module (or it can't initialize itself (low memory??))
+ENOENT          given filename not found
 ENOMEM          An attempt to get memory to store this open's context
                 failed (this was _not_ a request to reserve DMA memory)
-EACCES          An attempt to use both O_RDONLY and O_EXCL
+ENXIO           either there is no attached device corresponding to given
+                filename or scsi sub-system is currently processing some
+                error (eg doing a device reset) or the sg driver/module
+                removed or corrupted
 
 
-write
------
+write(int sg_fd, const void * buffer, size_t count)
+---------------------------------------------------
 Even though sg is a character-based device driver it sends and receives
 packets to/from the associated scsi device. Write() is used to send a
 packet containing 2 mandatory parts and 1 optional part. The mandatory
@@ -343,32 +315,33 @@ In this sg driver a write() should return more or less immediately.
 Returns number of bytes written if > 0 , otherwise -1 implies an error.
 
 Error codes (value in 'errno' after -1 returned):
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
 EACCES          opened with RD_ONLY flag
-EIO             incoming buffer too short. It should be at least (6 +
-                sizeof(struct sg_header))==42 bytes long
-EDOM            a) command queuing off: a packet is already queued
-                b) command queuing on: too many packets queued 
-                   (SG_MAX_QUEUE exceeded)
 EAGAIN          SCSI mid-level out of command blocks (rare), try again.
                 This is more likely to happen when queuing commands,
                 so wait a bit (eg usleep(10000) ) before trying again
+EDOM            a) command queuing off: a packet is already queued
+                b) command queuing on: too many packets queued 
+                   (SG_MAX_QUEUE exceeded)
+                c) SCSI command length given in SG_NEXT_CMD_LEN too long
+EFAULT          'buffer' for 'count' bytes is an invalid memory range
+EIO             incoming buffer too short. It should be at least (6 +
+                sizeof(struct sg_header))==42 bytes long
 ENOMEM          can't get memory for DMA. Take evasive action ...
-                (see section on memory)
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
 
 
-read
-----
+read(int sg_fd, void * buffer, size_t count)
+--------------------------------------------
 Read() is used to receive a packet containing 1 mandatory part and 1 
 optional part. The mandatory part is:
   - a control block (an instance of struct sg_header)
 The optional part is:
   - incoming data (eg if a SCSI read command was sent by earlier write() )
 The buffer given to a read() and its corresponding count should be
-sufficient to accommodate this packet to avoid truncation. Truncation has
-occurred if count < sg_header::replylen .
+sufficient to accommodate this packet to avoid truncation. Truncation occurs
+if count < sg_header::replylen .
 
 By default, read() will return the oldest packet queued up. If the 
 SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to
@@ -377,7 +350,6 @@ sg_header::pack_id given to this read(). If not available it will either
 wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given
 to read() will match the oldest packet.
 
-
 Returns number of bytes read if > 0 , otherwise -1 implies an error.
 Unfortunately the return value in the non-error case is simply the
 same as the count argument. It is not the actual number of bytes
@@ -385,25 +357,26 @@ DMA-ed by the SCSI device. This driver is currently unable to provide
 such an underrun indication.
 
 Error codes (value in 'errno' after -1 returned):
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
 EAGAIN          either no waiting packet or requested packet is not
                 available while O_NONBLOCK flag was set
+EFAULT          'buffer' for 'count' bytes is an invalid memory range
 EINTR           while waiting for a packet, a signal is received, just
                 try again ...        
 EIO             if the 'count' given to read() is < sizeof(struct sg_header)
                 and the 'result' element in sg_header is non-zero. Not a
                 recommended error reporting technique
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
 
 
-close
------
+close(int sg_fd)
+----------------
 Preferably a close() should be done after all issued write()s have had
 their corresponding read() calls completed. Unfortunately this is not
 always possible. The semantics of close() in Unix are to return more
 or less immediately (ie not wait on any event) so the driver needs to
-arrange to an orderly cleanup of those packets that are still "in
+arrange for an orderly cleanup of those packets that are still "in
 flight".
 
 A process that has an open file descriptor to an sg device may be aborted
@@ -411,22 +384,22 @@ A process that has an open file descriptor to an sg device may be aborted
 (which is called 'sg_release()' in the version 2 driver) to facilitate
 the cleanup mentioned above.
 
-A problem persists in version 2.1.8 if the sg driver is a module and is
-removed while packets are still "in flight". Hopefully this will be soon
-fixed.
+A problem persists in version 2.1.34 if the sg driver is a module and is
+removed while packets are still "in flight".
 
 Returns 0 if successful, otherwise -1 implies an error.
 
 Error codes (value in 'errno' after -1 returned):
 ENXIO           sg driver/module removed or corrupted
 
-ioctl (sg specific)
--------------------
+ioctl(int sg_fd, int command, ...)  [sg specific]
+-------------------------------------------------
 Ken Thompson (or perhaps some other Unix luminary) described ioctl() as 
 the "garbage bin of Unix". This driver compounds the situation by adding
-around 18 more commands. These commands either yield state information (10
-of them), change the driver's characteristics (8 of them) or allow direct
-communication with the common SCSI mid-level driver.
+more ...
+If a ioctl command is not recognized by sg (and the various lower levels
+that it may pass the command on to) then the error EINVAL occurs. If an
+invalid address is given (in the 3rd argument) then the error EFAULT occurs.
 
 Those commands with an appended "+" are new in version 2.
 
@@ -442,15 +415,38 @@ a manifest constant HZ which is the number of "jiffies" in 1 second.
 SG_SET_TIMEOUT:
 Assumes 3rd argument points to an int containing the new timeout value
 for this file descriptor. The unit is a "jiffy". Packets that are
-already "in flight" will not be effected. The default value is set
-on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h).
+already "in flight" will not be affected. The default value is set
+on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). This default is
+currently 1 minute and may not be long enough for formats.
 
 SG_EMULATED_HOST:
 Assumes 3rd argument points to an int and outputs a flag indicating
-whether the host (adapter) is connected to a real SCSI bus or is
+whether the host (adapter) is connected to a real SCSI bus or is an
 emulated one (eg ide-scsi device driver). A value of 1 means emulated
 while 0 is not.
 
+SG_SET_TRANSFORM  W:
+Third argument is ignored. Only is meaningful when SG_EMULATED host has
+yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
+an EINVAL error occurs. The default state is to _not_ transform SCSI
+commands to the corresponding ATAPI commands but pass them straight
+through as is. [Only certain classes of SCSI commands need to be
+transformed to their ATAPI equivalents.] Making this ioctl command causes
+transforms to occur thereafter. Subsequent calls to this ioctl command
+have no additional effect. Beware, this state will affect all devices
+(and hence all related sg file descriptors) associated with this ide-scsi
+"bus".
+The author of ide-scsi has pointed out that this is not the intended
+behaviour which is a 3rd argument of 0 to disable transforms and 1 to
+enable transforms. Note the 3rd argument is an 'int' not a 'int *'.
+Perhaps the intended behaviour will be implemented soon.
+
+SG_GET_TRANSFORM:
+Third argument is ignored. Only is meaningful when SG_EMULATED host has
+yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
+an EINVAL error occurs. Returns 0 to indicate _not_ transforming SCSI
+to ATAPI commands (default). Returns 1 when it is transforming.
+
 SG_SET_FORCE_LOW_DMA +:
 Assumes 3rd argument points to an int containing 0 or 1. 0 (default)
 means sg decides whether to use memory above 16 Mbyte level (on i386)
@@ -459,10 +455,10 @@ PCI SCSI adapters will indicate they can DMA to the whole 32 bit address
 space. 
 If 1 is given then the host adapter is overridden and only memory below
 the 16MB level is used for DMA. A requirement for this should be
-extremely rare. If the "reserve" buffer allocated on open() is not in
+extremely rare. If the "reserved" buffer allocated on open() is not in
 use then it will be de-allocated and re-allocated under the 16MB level
 (and the latter operation could fail yielding ENOMEM).
-Only the current file descriptor is effected.
+Only the current file descriptor is affected.
 
 SG_GET_LOW_DMA +:
 Assumes 3rd argument points to an int and places 0 or 1 in it. 0
@@ -472,11 +468,11 @@ on this file descriptor. 1 indicates the memory below the 16MB level
 adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 .
 
 SG_GET_SCSI_ID +:
-Assumes 3rd argument is pointing to an object of type Sg_scsi_id and
-populates it. That structure contains ints for host_no, channel,
-scsi_id, lun and scsi_type. Most of this information is available from
-other sources (eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER)
-but tends to be awkward to collect.
+Assumes 3rd argument is pointing to an object of type Sg_scsi_id (see
+sg.h) and populates it. That structure contains ints for host_no, 
+channel, scsi_id, lun and scsi_type. Most of this information is 
+available from other sources (eg SCSI_IOCTL_GET_IDLUN and 
+SCSI_IOCTL_GET_BUS_NUMBER) but tends to be awkward to collect.
 
 SG_SET_FORCE_PACK_ID +:
 Assumes 3rd argument is pointing to an int. 0 (default) instructs read()
@@ -486,9 +482,9 @@ waiting to be read (when command queuing is being used).
 oldest packet matching that pack_id or wait until it arrives (or yield
 EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1
 given to read() in the mode will match the oldest packet.
-Only the current file descriptor is effected by this command.
+Only the current file descriptor is affected by this command.
 
-SG_GET_LOW_DMA +:
+SG_GET_PACK_ID +:
 Assumes 3rd argument points to an int and places the pack_id of the
 oldest (written) packet in it. If no packet is waiting to be read then
 yields -1.
@@ -503,30 +499,33 @@ scatter gather elements supported by the host adapter. 0 indicates that
 the adapter does support scatter gather.
 
 SG_SET_RESERVED_SIZE +W:
-This is not currently implemented. It is intended for reserving either a
-large buffer or scatter gather list that will be available until the
-current file descriptor is closed. The requested amount of memory may
-not be available so SG_GET_RESERVED_SIZE should be used after this call
-to see how much was reserved. (EBUSY error possible)
+Assumes 3rd argument is pointing to an int. That value will be used to
+request a new reserved buffer of that size. The previous reserved buffer
+is freed (if it is not in use; if it was in use -EBUSY is returned).
+A new reserved buffer is then allocated and its actual size can be found by
+calling the SG_GET_RESERVED_SIZE ioctl(). The reserved buffer is then used
+for DMA purposes by subsequent write() commands if it is not already in
+use and if the write() is not calling for a buffer size larger than that
+reserved. The reserved buffer may well be a series of kernel buffers if the
+adapter supports scatter-gather. Large buffers can be requested (eg 1 MB).
 
 SG_GET_RESERVED_SIZE +:
 Assumes 3rd argument points to an int and places the size in bytes of
-the DMA buffer reserved on open() for emergencies. If this is 0 then it
-is probably not wise to attempt on operation like burning a CD on this
-file descriptor.
+the reserved buffer from open() or the most recent SG_SET_RESERVED_SIZE
+ioctl() call on this fd.  The result can be 0 if memory is very tight. In
+this case it may not be wise to attempt something like burning a CD on
+this file descriptor.
 
 SG_SET_MERGE_FD +W:
 Assumes 3rd argument is pointing to an int. 0 (the default) causes all
 subsequent sequencing to be per file descriptor. 1 causes all subsequent
 sequencing to be per device. If this command tries to change the current
-state and the is one or more _other_ file descriptors using this sg
-device then an EBUSY error occurs. Also if this file descriptor was not
-open()ed with the O_RDWR flag then an EACCES error occurs.
-Per device sequencing was the original semantics and allowed, for example
-different processes to "share" the device, one perhaps write()ing with
-the other one read()ing. This command is supplied if anyone needs those
-semantics. Per file descriptor sequencing, perhaps with the usage of
-the O_EXCL flag, seems more sensible.
+state and there is one or more _other_ file descriptors using this sg
+device then an EBUSY error occurs. Per device sequencing was the original
+semantics and allowed, for example different processes to "share" the
+device, one perhaps write()ing with the other one read()ing. This command
+is supplied if anyone needs those semantics. Per file descriptor 
+sequencing, perhaps with the use of the O_EXCL flag, seems more sensible.
 
 SG_GET_MERGE_FD +:
 Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
@@ -538,14 +537,42 @@ Assumes 3rd argument is pointing to an int. 0 (current default, set by
 SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write()
 a packet while one is already queued will result in a EDOM error.
 1 turns command queuing on.
-Changing the queuing state only effects write()s done after the change.
-Only the current file descriptor is effected by this command.
+Changing the queuing state only affects write()s done after the change.
+Only the current file descriptor is affected by this command.
 
 SG_GET_COMMAND_Q +:
 Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
 that command queuing is off on this file descriptor. 1 implies command
 queuing is on.
 
+SG_SET_UNDERRUN_FLAG +:
+Assumes 3rd argument is pointing to an int. 0 (current default, set by
+SG_DEF_UNDERRUN_FLAG in sg.h) requests underruns be ignored. 1 requests
+that underruns be flagged. [The only low level driver that acts on this 
+at the moment is the aic7xxx which yields a DID_ERROR error on underrun.]
+Only the current file descriptor is affected by this command (unless
+"per device" sequencing has been selected).
+
+SG_GET_UNDERRUN_FLAG +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
+that underruns are not being reported. 1 implies that underruns are being
+reported (see SG_SET_UNDERRUN_FLAG for more details).
+
+SG_NEXT_CMD_LEN +:
+Assumes 3rd argument is pointing to an int. The value of the int (if > 0)
+will be used as the SCSI command length of the next SCSI command sent to
+a write() on this fd. After that write() the SCSI command length logic is
+reset to use automatic length detection (ie depending on SCSI command group
+and the 'twelve_byte' field). If the current SCSI command length maximum of
+12 is exceeded then the affected write() will yield an EDOM error.
+Giving this ioctl() a value of 0 will set automatic length detection for
+the next write(). N.B. Only the following write() on this fd is affected by
+this ioctl().
+
+SG_GET_VERSION_NUM +:
+Assumes 3rd argument points to an int. The version number is then placed
+in that int. A sg version such as 2.1.34 will yield "20134" from this ioctl.
+
 SG_SET_DEBUG +:
 Assumes 3rd argument is pointing to an int. 0 (default) turns debugging
 off. Values > 0 cause the SCSI sense buffer to be decoded and output
@@ -556,73 +583,53 @@ If you need a _lot_ of the SCSI sub-system debug information (mainly from
 the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of
 debug will appear in your console/log.
 
-ioctl (in common with sd, st + sr)
-----------------------------------
-The following ioctl()s can be called from any high-level scsi device
-driver (ie sd, st, sr + sg). Access permissions may differ a bit from
-one device to another, the access information given below is specific to
-the sg device driver.
-
-SCSI_IOCTL_GET_IDLUN:
-SCSI_IOCTL_GET_BUS_NUMBER:
-
-SCSI_IOCTL_SEND_COMMAND:  W
-If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto
-the SCSI mid-level driver for processing.
-Don't know much about this one but it looks pretty powerful and
-dangerous. Some comments says it is also deprecated.
 
-<any_command_not matching_above>:  W
-If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto
-the SCSI mid-level driver for processing.
-
-
-poll
-----
+poll(struct pollfd * udfds, unsigned int nfds, int timeout_ms)
+--------------------------------------------------------------
 This is a native call in Linux 2.2 but most of its capabilities are available
 through the older select() call. Given a choice poll() should probably be
 used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK
-for polling; or alternatively with asynchronous notification using the
-fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
+for polling; and optionally with asynchronous notification as well using
+the fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
 Only if something drastically is wrong (eg file handle gone stale) will
 POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set.
 POLLIN is set when there is one or more packets waiting to be read.
-When POLLIN is set it implies that a read() will not block (or yield
+When POLLIN is set it implies that a read() will not block (nor yield
 EAGAIN in non-blocking mode) but return a packet immediately.
 POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet
-(ie will _not_ yield an EDOM error). The setting of POLLOUT is effected
+(ie will _not_ yield an EDOM error). The setting of POLLOUT is affected
 by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain
 set until the number of queued packets reaches SG_MAX_QUEUE, if the
 state is off then POLLOUT is only set when no packets are queued.
 Note that a packet can be queued after write()ing but not available to be
 read(); this typically happens when a SCSI read command is issued while
-the data is being retreaved.
+the data is being retrieved.
 Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case
 it is per device.
 
 
-fcntl
------
+fcntl(int sg_fd, int cmd) or fcntl(int sg_fd, int cmd, long arg)
+----------------------------------------------------------------
 There are several uses for this system call in association with a sg
-file descriptor. The first pseudo code shows code that is useful for
+file descriptor. The following pseudo code shows code that is useful for
 scanning the sg devices, taking care not to be caught in a wait for
 an O_EXCL lock by another process, and when the appropriate device is
-found switching to normal blocked io. A working example of this logic
-is in the sg_scan.c utility program.
+found, switching to normal blocked io. A working example of this logic
+is in the sg_scan utility program.
 
 open("/dev/sga", O_RDONLY | O_NONBLOCK)
 /* check device, EBUSY means some other process has O_EXCL lock on it */
-/* one the device you want is found then ... */
+/* when the device you want is found then ... */
 flags = fcntl(sg_fd, F_GETFL)
 fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))
-/* for simple apps is is easier to use normal blocked io */
+/* since, for simple apps, it is easier to use normal blocked io */
 
 
 Some work has to be done in Linux to set up for asynchronous notification.
-This is a non-blocking mode of operation in which when the driver receives
+This is a non-blocking mode of operation in which, when the driver receives
 data back from a device so that a read() can be done, it sends a SIGPOLL
 (aka SIGIO) signal to the owning process. A working example of this logic
-is in the sg_poll.c test program.
+is in the sg_poll test program.
 
 sigemptyset(&sig_set)
 sigaddset(&sig_set, SIGPOLL)
@@ -634,3 +641,91 @@ fcntl(sg_fd, F_SETFL, flags | O_ASYNC)
 
 Utility and Test Programs
 =========================
+See the README file in the sg_utils<date>.tgz tarball. At the time of
+writing this was sg_utils990527.tgz .
+
+Briefly, that tarball contains the following utilities:
+sg_dd512        'dd' like program that assumes 512 byte blocks size
+sg_dd2048       'dd' like program that assumes 2048 byte blocks size
+sgq_dd512       like 'sg_dd512' but does command queuing on "if"
+sg_scan         outputs information (optionally Inquiry) on SCSI devices
+sg_rbuf         tests SCSI bus transfer speed (without physical IO)
+sg_whoami       outputs info (optionally capacity) of given SCSI device
+sginfo          outputs "mode" information about SCSI devices (it is a
+                  re-port of the scsiinfo program onto the sg interface)
+
+It also contains the following test programs:
+sg_debug        outputs sg driver state to console/log file
+sg_poll         tests asynchronous notification
+sg_inquiry      does a SCSI Inquiry command (from original HOWTO)
+sg_tst_med      checks presence of media (from original HOWTO)
+
+There are also 2 source files (sg_err.[hc]) for outputting and categorizing
+SCSI 2 errors and warnings. This code is used by most of the above
+utility and test programs.
+
+The following programs: sg_dd512, sg_dd2048, sg_scan, sg_rbuf, sg_tst_med, 
+sg_inquiry and sginfo, can be compiled either for this new sg driver _or_
+the original sg driver.
+
+
+Header files
+============
+User applications need to find the correct "sg.h" header file matching
+their kernel in order to write code using the sg device driver. This is 
+sometimes more difficult than it should be. The correct "sg.h" will usually
+be found at /usr/src/linux/include/scsi/sg.h . Another important header 
+file is "scsi.h" which will be in the same directory.
+
+Several distributions have taken their own copies of these files and placed
+them in /usr/include/scsi which is where "#include <scsi/sg.h>" would go
+looking. The directory /usr/include/scsi _should_ be a symbolic link to
+/usr/src/linux/include/scsi/ . It was is Redhat 5.1 and 5.2 but it is
+not is Redhat 6.0 . Some other distributions have the same problem. To
+solve this (as root) do the following:
+
+# cd /usr/include
+# mv scsi scsi_orig
+# ln -s ../src/linux/include/scsi scsi
+
+This doesn't seem to be a problem with /usr/include/linux (at least in
+Redhat where it is a symbolic link) so it is hard to understand why
+/usr/include/scsi is defined the way it is. The fact the
+/usr/include/linux is a symbolic link opens up the following solution
+proposed by the author of cdparanoia (Monty):
+#include <linux/../scsi/sg.h>
+
+
+Extra information in scsi-generic_long.txt
+==========================================
+This document is an abridged form of a more comprehensive document called
+scsi-generic_long.txt (see www.torque.net/sg/p/scsi-generic_long.txt).
+
+The longer document contains additional sections on:
+   - memory issues
+   - ioctl()s in common with sd, st + sr
+   - distinguishing the original from the new driver
+   - SG_BIG_BUFF and friends
+   - shortcomings
+   - future directions
+   - an appendix with some SCSI 2 information in it
+
+
+Conclusion
+==========
+The SCSI generic packet device driver attempts to make as few assumptions
+as possible about the device it is connected to while giving applications
+using it as much flexibility as possible on the SCSI command level. Sg
+needs to hide the "messy" kernel related details while protecting
+the integrity of the kernel against sg "abuse". Some of these aims are
+contradictory and some compromises need to be made. For example: should
+a sg based application be able to reset a SCSI bus when that could cause
+collateral damage to a disk holding the root file system? There is no
+easy answer to this and many other related questions.
+
+If you have any suggestion about sg (or improving (the accuracy of) this
+document) please contact me.
+
+
+Douglas Gilbert
+dgilbert@interlog.com
index 1af60ed4eb39de60268a2f3e5227869eca3351ce..b4b9d0dcc61ff9e184f8f150f31c00d1dbc78824 100644 (file)
@@ -1,6 +1,9 @@
 <HTML><HEAD>
-<TITLE>Video4Linux Kernel API Reference v0.1:19980516</TITLE>
+<TITLE>Video4Linux Kernel API Reference v0.1:19990430</TITLE>
 </HEAD>
+<! Revision History: >
+<!   4/30/1999 - Fred Gleason (fredg@wava.com)>
+<! Documented extensions for the Radio Data System (RDS) extensions >
 <BODY bgcolor="#ffffff">
 <H3>Devices</H3>
 Video4Linux provides the following sets of device files. These live on the
@@ -117,7 +120,7 @@ fields available to the user.
 </TABLE>
 <P>
 Merely setting the window does not enable capturing. Overlay capturing
-is activatied by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
+is activated by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
 disabled by passing it a value of 0. 
 <P>
 Some capture devices can capture a subfield of the image they actually see.
@@ -150,7 +153,7 @@ the <b>struct video_channel</b> is filled in with information about the
 nature of the channel itself.
 <P>
 The <b>VIDIOCSCHAN</b> ioctl takes an integer argument and switches the
-capture to this input. It is not defined whether paramters such as colour
+capture to this input. It is not defined whether parameters such as colour
 settings or tuning are maintained across a channel switch. The caller should
 maintain settings as desired for each channel. (This is reasonable as 
 different video inputs may have different properties).
@@ -249,6 +252,8 @@ The following flags exist
 <TR><TD><b>VIDEO_TUNER_LOW</b><TD>Frequency is in a lower range</TD>
 <TR><TD><b>VIDEO_TUNER_NORM</b><TD>The norm for this tuner is settable</TD>
 <TR><TD><b>VIDEO_TUNER_STEREO_ON</b><TD>The tuner is seeing stereo audio</TD>
+<TR><TD><b>VIDEO_TUNER_RDS_ON</b><TD>The tuner is seeing a RDS datastream</TD>
+<TR><TD><b>VIDEO_TUNER_MBS_ON</b><TD>The tuner is seeing a MBS datastream</TD>
 </TABLE>
 <P>
 The following modes are defined
@@ -349,6 +354,21 @@ devices if any exist. The video_unit structure has the following fields.
 <TR><TD><b>teletext</b><TD>Teletext device</TD>
 </TABLE>
 <P>
-
+<H3>RDS Datastreams</H3>
+For radio devices that support it, it is possible to receive Radio Data
+System (RDS) data by means of a read() on the device.  The data is packed in
+groups of three, as follows:
+<TABLE>
+<TR><TD>First Octet</TD><TD>Least Siginificant Byte of RDS Block</TD></TR>
+<TR><TD>Second Octet</TD><TD>Most Siginificant Byte of RDS Block
+<TR><TD>Third Octet</TD><TD>Bit 7:</TD><TD>Error bit.  Indicates that
+an uncorrectable error occured during reception of this block.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bit 6:</TD><TD>Corrected bit.  Indicates that  
+an error was corrected for this data block.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bits 5-3:</TD><TD>Reeived Offset.  Indicates the  
+offset received by the sync system.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bits 2-0:</TD><TD>Offset Name.  Indicates the  
+offset applied to this data.</TD></TR>
+</TABLE>
 </BODY>
 </HTML>
index 6148f859c7d189bbddcaebebceaf00c1ef3cba82..0371d2e74e75ae39dc5d14792427b0a42d53e74d 100644 (file)
@@ -17,9 +17,9 @@
   If this 64MB area overlaps the IO memory of the Bt848 you also have to
   remap this. E.g.: insmod bttv vidmem=0xfb0 remap=0xfa0
 
-  If the videomemory is found at the right place and there are no address
-  conflicts but still no picture (or the computer even crashes.),
-  try disabling features of your PCI chipset in the BIOS Setup.
+  If the video memory is found at the right place and there are no address
+  conflicts but still no picture (or the computer even crashes),
+  try disabling features of your PCI chipset in the BIOS setup.
 
   Frank Kapahnke <frank@kapahnke.prima.ruhr.de> also reported that problems
   with his S3 868 went away when he upgraded to XFree 3.2.
   
   Disable backing store by starting X with the option "-bs"
 
-- When using 32bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
+- When using 32 bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
   can sometimes lock up if you use more than 1 bt848 card at the same time.
   You will always get pixel errors when e.g. using more than 1 card in full
   screen mode. Maybe we need something faster than the PCI bus ...
 
 
-- Some S3 cards and the Matrox Mystique will produce pixel erros with
-  full resolution in 32bit mode.
+- Some S3 cards and the Matrox Mystique will produce pixel errors with
+  full resolution in 32-bit mode.
 
-- Some video cards have problems with Accelerated X 4.1
\ No newline at end of file
+- Some video cards have problems with Accelerated X 4.1
index 53d04f59b79b78eb153e0dd34faefbca3581ec78..f22f9c0cabff2134e7f6a6b1487d5f8fd74269e9 100644 (file)
@@ -6,7 +6,7 @@ Support is in now:
 
 So you should have TV with (stereo) sound now.  Radio does _not_ work.
 It probably does not work with sat receivers. I can't test this and
-therefore hav'nt added support for it yet. If someone needs this and
+therefore have not added support for it yet. If someone needs this and
 can help testing the sat stuff, drop me a note.
 
   Gerd
diff --git a/Documentation/video4linux/bttv/README.WINVIEW b/Documentation/video4linux/bttv/README.WINVIEW
new file mode 100644 (file)
index 0000000..c61cf28
--- /dev/null
@@ -0,0 +1,33 @@
+
+Support for the Leadtek WinView 601 TV/FM by Jon Tombs <jon@gte.esi.us.es>
+
+This card is basically the same as all the rest (Bt484A, Philips tuner),
+the main difference is that they have attached a programmable attenuator to 3
+GPIO lines in order to give some volume control. They have also stuck an
+infra-red remote control decoded on the board, I will add support for this
+when I get time (it simple generates an interrupt for each key press, with
+the key code is placed in the GPIO port).
+
+I don't yet have any application to test the radio support. The tuner
+frequency setting should work but it is possible that the audio multiplexer
+is wrong. If it doesn't work, send me email.
+
+
+- No Thanks to Leadtek they refused to answer any questions about their
+hardware. The driver was written by visual inspection of the card. If you
+use this driver, send an email insult to them, and tell them you won't
+continue buying their hardware unless they support Linux.
+
+- Little thanks to Princeton Technology Corp (http://www.princeton.com.tw)
+who make the audio attenuator. Their publicly available data-sheet available
+on their web site doesn't include the chip programming information! Hidden
+on their server are the full data-sheets, but don't ask how I found it.
+
+To use the driver I use the following options, the tuner and pll settings might
+be different in your country
+
+insmod videodev
+insmod i2c scan=1 i2c_debug=0 verbose=0
+insmod tuner type=1 debug=0
+insmod bttv  pll=1 radio=1 card=17
+
index 0da6d9f8e280062bfc349eb2519ea8b9225db204..2085399da7d4c3274b39c133bd253523af370ef1 100644 (file)
@@ -17,7 +17,7 @@ Many thanks to:
   components on their cards. (E.g. how the tuner type is detected)
   Without their card I could not have debugged the NTSC mode.
        
-- Hauppauge for telling how the sound input is selected and what compenents
+- Hauppauge for telling how the sound input is selected and what components
   they do and will use on their radio cards.
   Also many thanks for faxing me the FM1216 data sheet.
 
index c557d66eca964fca215d2d8675be3fea9cd3253d..29de97e597aff55a86cbf767997eec6b60eb43d4 100644 (file)
 #
 CONFIG_MODULES=y
 # CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_KMOD=y
 
 #
 # General setup
 #
-CONFIG_NATIVE=y
 CONFIG_ALPHA_GENERIC=y
 # CONFIG_ALPHA_ALCOR is not set
 # CONFIG_ALPHA_XL is not set
@@ -39,12 +38,12 @@ CONFIG_ALPHA_GENERIC=y
 # CONFIG_ALPHA_P2K is not set
 # CONFIG_ALPHA_RAWHIDE is not set
 # CONFIG_ALPHA_RUFFIAN is not set
+# CONFIG_ALPHA_RX164 is not set
 # CONFIG_ALPHA_SX164 is not set
 # CONFIG_ALPHA_SABLE is not set
 # CONFIG_ALPHA_TAKARA is not set
-# CONFIG_SMP is not set
 CONFIG_PCI=y
-CONFIG_ALPHA_NEED_ROUNDING_EMULATION=y
+# CONFIG_SMP is not set
 # CONFIG_PCI_QUIRKS is not set
 CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
@@ -88,7 +87,7 @@ CONFIG_PARIDE_PARPORT=y
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
 # CONFIG_FILTER is not set
@@ -107,7 +106,6 @@ CONFIG_INET=y
 # (it is safe to leave these untouched)
 #
 # CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 
 #
@@ -141,6 +139,7 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI low-level drivers
 #
 # CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
@@ -148,23 +147,29 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
 # CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 CONFIG_SCSI_QLOGIC_ISP=y
+# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -194,6 +199,7 @@ CONFIG_DE4X5=y
 # CONFIG_EEXPRESS_PRO100 is not set
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
@@ -202,6 +208,8 @@ CONFIG_DE4X5=y
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
 # CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
@@ -217,7 +225,7 @@ CONFIG_DE4X5=y
 # CONFIG_ISDN is not set
 
 #
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
 #
 # CONFIG_CD_NO_IDESCSI is not set
 
@@ -233,19 +241,31 @@ CONFIG_SERIAL=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 CONFIG_MOUSE=y
+
+#
+# Mice
+#
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
 # CONFIG_MS_BUSMOUSE is not set
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
-# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
 # CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+
+#
+# Joystick support
+#
 # CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
 
 #
 # Ftape, the floppy tape device driver
@@ -256,31 +276,43 @@ CONFIG_PSMOUSE=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_DEVPTS_FS=y
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_BSD_DISKLABEL is not set
 # CONFIG_MAC_PARTITION is not set
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
index 3fcbdbcda71e5a0afc6740f773819da615b7cc71..3b004b7f615e50529b82fbaf9c2e5585faee0c90 100644 (file)
@@ -54,87 +54,6 @@ __smp_callin:
        .end __smp_callin
 #endif /* __SMP__ */
 
-       .align 3
-       .globl  wrent
-       .ent    wrent
-wrent:
-       .prologue 0
-       call_pal PAL_wrent
-       ret     ($26)
-       .end wrent
-
-       .align 3
-       .globl  wrkgp
-       .ent    wrkgp
-wrkgp:
-       .prologue 0
-       call_pal PAL_wrkgp
-       ret     ($26)
-       .end wrkgp
-
-       .align 3
-       .globl  wrusp
-       .ent    wrusp
-wrusp:
-       .prologue 0
-       call_pal PAL_wrusp
-       ret     ($26)
-       .end wrusp
-
-       .align 3
-       .globl  rdusp
-       .ent    rdusp
-rdusp:
-       .prologue 0
-       call_pal PAL_rdusp
-       ret     ($26)
-       .end rdusp
-
-       .align 3
-       .globl  rdmces
-       .ent    rdmces
-rdmces:
-       .prologue 0
-       call_pal PAL_rdmces
-       ret     ($26)
-       .end rdmces
-
-       .align 3
-       .globl  wrmces
-       .ent    wrmces
-wrmces:
-       .prologue 0
-       call_pal PAL_wrmces
-       ret     ($26)
-       .end wrmces
-
-       .align 3
-       .globl  whami
-       .ent    whami
-whami:
-       .prologue 0
-       call_pal PAL_whami
-       ret     ($26)
-       .end whami
-       .align 3
-       .globl  wripir
-       .ent    wripir
-wripir:
-       .prologue 0
-       call_pal PAL_wripir
-       ret     ($26)
-       .end wripir
-
-       .align 3
-       .globl wrvptptr
-       .ent wrvptptr
-wrvptptr:
-       .prologue 0
-       call_pal PAL_wrvptptr
-       ret     ($26)
-       .end wrvptptr
-
        #
        # The following two functions are needed for supporting SRM PALcode
        # on the PC164 (at least), since that PALcode manages the interrupt
index f7e54a982c565e824ba20ee48cbc71de870fd57c..8fa1fd7ea7666910eccdf6b6472f89278c2d5926 100644 (file)
@@ -180,7 +180,7 @@ extern unsigned long alpha_read_fp_reg (unsigned long reg);
 extern void wrmces(unsigned long mces);
 extern void cserve_ena(unsigned long);
 extern void cserve_dis(unsigned long);
-extern void __smp_callin(void);
+extern void __smp_callin(unsigned long);
 
 /* entry.S */
 extern void entArith(void);
index 34ac7754ba488bcb7f170b9a747071b9926147f8..a477c2344059270b562f7c4681ee9a4a2e8fab96 100644 (file)
@@ -27,9 +27,6 @@
 #include "proto.h"
 
 
-#include "proto.h"
-
-
 #define DEBUG_SIG 0
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
index f01c0e55d632813f8b47e0633f563aac9eba318f..489274b8be9496d9038af4d859ed24a6d5cdeb4c 100644 (file)
@@ -151,8 +151,8 @@ smp_callin(void)
        while (!smp_threads_ready)
                barrier();
 
-       printk(KERN_INFO "SMP: commencing CPU %d current %p\n",
-              cpuid, current);
+       DBGS(("smp_callin: commencing CPU %d current %p\n",
+             cpuid, current));
 
        /* Do nothing.  */
        cpu_idle(NULL);
@@ -293,9 +293,9 @@ recv_secondary_console_msg(void)
                   + hwrpb->processor_offset
                   + i * hwrpb->processor_size);
 
-               printk(KERN_INFO "recv_secondary_console_msg: on %d from %d"
-                      " HALT_REASON 0x%lx FLAGS 0x%lx\n",
-                      mycpu, i, cpu->halt_reason, cpu->flags);
+               DBGS(("recv_secondary_console_msg: on %d from %d"
+                     " HALT_REASON 0x%lx FLAGS 0x%lx\n",
+                     mycpu, i, cpu->halt_reason, cpu->flags));
 
                cnt = cpu->ipc_buffer[0] >> 32;
                if (cnt <= 0 || cnt >= 80)
@@ -790,6 +790,11 @@ handle_ipi(struct pt_regs *regs)
 void
 smp_send_reschedule(int cpu)
 {
+#if DEBUG_IPI_MSG
+       if (cpu == hard_smp_processor_id())
+               printk(KERN_WARNING
+                      "smp_send_reschedule: Sending IPI to self.\n");
+#endif
        send_ipi_message(1L << cpu, IPI_RESCHEDULE);
 }
 
@@ -797,6 +802,10 @@ void
 smp_send_stop(void)
 {
        unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+#if DEBUG_IPI_MSG
+       if (hard_smp_processor_id() != boot_cpu_id)
+               printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
+#endif
        send_ipi_message(to_whom, IPI_CPU_STOP);
 }
 
@@ -862,13 +871,13 @@ ipi_flush_tlb_all(void *ignored)
 void
 flush_tlb_all(void)
 {
-       tbia();
-
        /* Although we don't have any data to pass, we do want to
           synchronize with the other processors.  */
        if (smp_call_function(ipi_flush_tlb_all, NULL, 1, 1)) {
                printk(KERN_CRIT "flush_tlb_all: timed out\n");
        }
+
+       tbia();
 }
 
 static void
@@ -948,43 +957,21 @@ smp_info(char *buffer)
 
 \f
 #if DEBUG_SPINLOCK
-
-#ifdef MANAGE_SPINLOCK_IPL
-
-static inline long 
-spinlock_raise_ipl(spinlock_t * lock)
-{
-       long min_ipl = lock->target_ipl;
-       long last_ipl = swpipl(7);
-       if (last_ipl < 7 && min_ipl < 7)
-               setipl(min_ipl < last_ipl ? last_ipl : min_ipl);
-       return last_ipl;
-}
-
-static inline void
-spinlock_restore_ipl(long prev)
-{
-       setipl(prev);
-}
-
-#else
-
-#define spinlock_raise_ipl(LOCK)       ((void)(LOCK), 0)
-#define spinlock_restore_ipl(PREV)     ((void)(PREV))
-
-#endif /* MANAGE_SPINLOCK_IPL */
-
 void
 spin_unlock(spinlock_t * lock)
 {
-       long old_ipl = lock->saved_ipl;
        mb();
        lock->lock = 0;
-       spinlock_restore_ipl(old_ipl);
+
+       lock->on_cpu = -1;
+       lock->previous = NULL;
+       lock->task = NULL;
+       lock->base_file = "none";
+       lock->line_no = 0;
 }
 
 void
-spin_lock(spinlock_t * lock)
+debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no)
 {
        long tmp;
        long stuck;
@@ -992,7 +979,6 @@ spin_lock(spinlock_t * lock)
        unsigned long started = jiffies;
        int printed = 0;
        int cpu = smp_processor_id();
-       long old_ipl = spinlock_raise_ipl(lock);
 
        stuck = 1L << 28;
  try_again:
@@ -1020,39 +1006,43 @@ spin_lock(spinlock_t * lock)
 
        if (stuck < 0) {
                printk(KERN_WARNING
-                      "spinlock stuck at %p(%d) owner %s at %p(%d) st %ld\n",
-                      inline_pc, cpu, lock->task->comm, lock->previous,
-                      lock->task->processor, lock->task->state);
+                      "%s:%d spinlock stuck in %s at %p(%d)"
+                      " owner %s at %p(%d) %s:%d\n",
+                      base_file, line_no,
+                      current->comm, inline_pc, cpu,
+                      lock->task->comm, lock->previous,
+                      lock->on_cpu, lock->base_file, lock->line_no);
                stuck = 1L << 36;
                printed = 1;
                goto try_again;
        }
 
        /* Exiting.  Got the lock.  */
-       lock->saved_ipl = old_ipl;
        lock->on_cpu = cpu;
        lock->previous = inline_pc;
        lock->task = current;
+       lock->base_file = base_file;
+       lock->line_no = line_no;
 
        if (printed) {
-               printk(KERN_WARNING "spinlock grabbed at %p(%d) %ld ticks\n",
-                      inline_pc, cpu, jiffies - started);
+               printk(KERN_WARNING
+                      "%s:%d spinlock grabbed in %s at %p(%d) %ld ticks\n",
+                      base_file, line_no, current->comm, inline_pc,
+                      cpu, jiffies - started);
        }
 }
 
 int
-spin_trylock(spinlock_t * lock)
+debug_spin_trylock(spinlock_t * lock, const char *base_file, int line_no)
 {
-       long old_ipl = spinlock_raise_ipl(lock);
        int ret;
        if ((ret = !test_and_set_bit(0, lock))) {
-               mb();
-               lock->saved_ipl = old_ipl;
                lock->on_cpu = smp_processor_id();
                lock->previous = __builtin_return_address(0);
                lock->task = current;
        } else {
-               spinlock_restore_ipl(old_ipl);
+               lock->base_file = base_file;
+               lock->line_no = line_no;
        }
        return ret;
 }
index 4b4cf656733e58befdf91cff51f782a2532b40cd..f465b3b4ef222fc36463ef2c70078a43485b69cc 100644 (file)
@@ -2,8 +2,8 @@
  *     linux/arch/alpha/kernel/sys_dp264.c
  *
  *     Copyright (C) 1995 David A Rusling
- *     Copyright (C) 1996 Jay A Estabrook
- *     Copyright (C) 1998 Richard Henderson
+ *     Copyright (C) 1996, 1999 Jay A Estabrook
+ *     Copyright (C) 1998, 1999 Richard Henderson
  *
  * Code supporting the DP264 (EV6+TSUNAMI).
  */
@@ -35,7 +35,7 @@
 #define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index)
 
 /*
- * HACK ALERT! only CPU#0 is used currently
+ * HACK ALERT! only the boot cpu is used for interrupts.
  */
 
 static void
@@ -98,29 +98,28 @@ dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
 #if 1
        printk("dp264_device_interrupt: NOT IMPLEMENTED YET!! \n");
 #else
-        unsigned long pld;
-        unsigned int i;
-
-        /* Read the interrupt summary register of TSUNAMI */
-        pld = TSUNAMI_cchip->dir0.csr;
-
-        /*
-         * Now for every possible bit set, work through them and call
-         * the appropriate interrupt handler.
-         */
-        while (pld) {
-                i = ffz(~pld);
-                pld &= pld - 1; /* clear least bit set */
-                if (i == 55) {
-                        isa_device_interrupt(vector, regs);
-               } else { /* if not timer int */
-                        handle_irq(16 + i, 16 + i, regs);
-                }
+       unsigned long pld;
+       unsigned int i;
+
+       /* Read the interrupt summary register of TSUNAMI */
+       pld = TSUNAMI_cchip->dir0.csr;
+
+       /*
+        * Now for every possible bit set, work through them and call
+        * the appropriate interrupt handler.
+        */
+       while (pld) {
+               i = ffz(~pld);
+               pld &= pld - 1; /* clear least bit set */
+               if (i == 55)
+                       isa_device_interrupt(vector, regs);
+               else
+                       handle_irq(16 + i, 16 + i, regs);
 #if 0
                TSUNAMI_cchip->dir0.csr = 1UL << i; mb();
                tmp = TSUNAMI_cchip->dir0.csr;
 #endif
-        }
+       }
 #endif
 }
 
@@ -131,20 +130,19 @@ dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 
        ack = irq = (vector - 0x800) >> 4;
 
-        /*
-         * The EV6 machines SRM console reports PCI interrupts with a vector
-        * calculated by:
+       /*
+        * The SRM console reports PCI interrupts with a vector calculated by:
         *
         *      0x900 + (0x10 * DRIR-bit)
         *
-        * So bit 16 shows up as IRQ 32, etc, etc.
+        * So bit 16 shows up as IRQ 32, etc.
         * 
         * On DP264/BRICK/MONET, we adjust it down by 16 because at least
         * that many of the low order bits of the DRIR are not used, and
         * so we don't count them.
-         */
-        if (irq >= 32)
-                ack = irq = irq - 16;
+        */
+       if (irq >= 32)
+               ack = irq = irq - 16;
 
        handle_irq(irq, ack, regs);
 }
@@ -156,19 +154,18 @@ clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 
        ack = irq = (vector - 0x800) >> 4;
 
-        /*
-         * The EV6 machines SRM console reports PCI interrupts with a vector
-        * calculated by:
+       /*
+        * The SRM console reports PCI interrupts with a vector calculated by:
         *
         *      0x900 + (0x10 * DRIR-bit)
         *
-        * So bit 16 shows up as IRQ 32, etc, etc.
+        * So bit 16 shows up as IRQ 32, etc.
         * 
         * CLIPPER uses bits 8-47 for PCI interrupts, so we do not need
         * to scale down the vector reported, we just use it.
         *
         * Eg IRQ 24 is DRIR bit 8, etc, etc
-         */
+        */
        handle_irq(irq, ack, regs);
 }
 
@@ -306,42 +303,38 @@ monet_map_irq(struct pci_dev *dev, int slot, int pin)
                {    32,    32,    33,    34,    35}, /* IdSel 13 slot 3 PCI0*/
                {    28,    28,    29,    30,    31}, /* IdSel 14 slot 4 PCI2*/
                {    24,    24,    25,    26,    27}  /* IdSel 15 slot 5 PCI2*/
-};
+       };
        const long min_idsel = 3, max_idsel = 15, irqs_per_slot = 5;
-       int irq = COMMON_TABLE_LOOKUP;
-
-       return irq;
+       return COMMON_TABLE_LOOKUP;
 }
 
 static int __init
 monet_swizzle(struct pci_dev *dev, int *pinp)
 {
-        int slot, pin = *pinp;
-
-        /* Check first for the built-in bridge on hose 1. */
-        if (dev2hose(dev) == 1 && PCI_SLOT(dev->bus->self->devfn) == 8) {
-         slot = PCI_SLOT(dev->devfn);
-        }
-        else
-        {
-                /* Must be a card-based bridge.  */
-                do {
+       int slot, pin = *pinp;
+
+       /* Check first for the built-in bridge on hose 1. */
+       if (dev2hose(dev) == 1 && PCI_SLOT(dev->bus->self->devfn) == 8) {
+               slot = PCI_SLOT(dev->devfn);
+       } else {
+               /* Must be a card-based bridge.  */
+               do {
                        /* Check for built-in bridge on hose 1. */
-                        if (dev2hose(dev) == 1 &&
+                       if (dev2hose(dev) == 1 &&
                            PCI_SLOT(dev->bus->self->devfn) == 8) {
                                slot = PCI_SLOT(dev->devfn);
                                break;
-                        }
-                        pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ;
-
-                        /* Move up the chain of bridges.  */
-                        dev = dev->bus->self;
-                        /* Slot of the next bridge.  */
-                        slot = PCI_SLOT(dev->devfn);
-                } while (dev->bus->self);
-        }
-        *pinp = pin;
-        return slot;
+                       }
+                       pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ;
+
+                       /* Move up the chain of bridges.  */
+                       dev = dev->bus->self;
+                       /* Slot of the next bridge.  */
+                       slot = PCI_SLOT(dev->devfn);
+               } while (dev->bus->self);
+       }
+       *pinp = pin;
+       return slot;
 }
 
 static int __init
@@ -360,11 +353,9 @@ webbrick_map_irq(struct pci_dev *dev, int slot, int pin)
                {    39,    39,    38,    37,    36}, /* IdSel 15 slot 1 */
                {    43,    43,    42,    41,    40}, /* IdSel 16 slot 2 */
                {    47,    47,    46,    45,    44}, /* IdSel 17 slot 3 */
-};
+       };
        const long min_idsel = 7, max_idsel = 17, irqs_per_slot = 5;
-       int irq = COMMON_TABLE_LOOKUP;
-
-       return irq;
+       return COMMON_TABLE_LOOKUP;
 }
 
 static int __init
@@ -492,6 +483,7 @@ struct alpha_machine_vector webbrick_mv __initmv = {
        pci_fixup:              webbrick_pci_fixup,
        kill_arch:              generic_kill_arch,
 };
+
 struct alpha_machine_vector clipper_mv __initmv = {
        vector_name:            "Clipper",
        DO_EV6_MMU,
@@ -513,5 +505,6 @@ struct alpha_machine_vector clipper_mv __initmv = {
        pci_fixup:              clipper_pci_fixup,
        kill_arch:              generic_kill_arch,
 };
+
 /* No alpha_mv alias for webbrick/monet/clipper, since we compile them
    in unconditionally with DP264; setup_arch knows how to cope.  */
index 95adc3b39db2995651b0ba9f030f459447eab91f..c554a9fa1a07057b738a52a5fbdc48d6081a7aad 100644 (file)
@@ -3,7 +3,7 @@
  *
  *     Copyright (C) 1995 David A Rusling
  *     Copyright (C) 1996 Jay A Estabrook
- *     Copyright (C) 1998 Richard Henderson
+ *     Copyright (C) 1998, 1999 Richard Henderson
  *
  * Code supporting the TAKARA.
  */
 #include "machvec.h"
 
 
-/*
- * WARNING WARNING WARNING
- *
- * This port is missing an update_irq_hw implementation.
- */
+static void 
+takara_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+{
+       unsigned int regaddr;
+
+       if (irq <= 15) {
+               if (irq <= 7)
+                       outb(mask, 0x21);       /* ISA PIC1 */
+               else
+                       outb(mask >> 8, 0xA1);  /* ISA PIC2 */
+       } else if (irq <= 31) {
+               regaddr = 0x510 + ((irq - 16) & 0x0c);
+               outl((mask >> ((irq - 16) & 0x0c)) & 0xf0000Ul, regaddr);
+       }
+}
 
 static void
 takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
@@ -68,28 +78,45 @@ takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
                if (intstatus & 4) handle_irq(16+2, 16+2, regs);
                if (intstatus & 2) handle_irq(16+1, 16+1, regs);
                if (intstatus & 1) handle_irq(16+0, 16+0, regs);
-       } else
+       } else {
                isa_device_interrupt (vector, regs);
+       }
+}
+
+static void 
+takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+       int irq = (vector - 0x800) >> 4;
+
+       if (irq > 15)
+               irq = ((vector - 0x800) >> 6) + 12;
+       
+       handle_irq(irq, irq, regs);
 }
 
 static void __init
 takara_init_irq(void)
 {
-       unsigned int ctlreg;
-
        STANDARD_INIT_IRQ_PROLOG;
 
-       ctlreg = inl(0x500);
-       ctlreg &= ~0x8000;     /* return to non-accelerated mode */
-       outw(ctlreg >> 16, 0x502);
-       outw(ctlreg & 0xFFFF, 0x500);
-       ctlreg = 0x05107c00;   /* enable the PCI interrupt register */
-       outw(ctlreg >> 16, 0x502);
-       outw(ctlreg & 0xFFFF, 0x500);
+       if (alpha_using_srm)
+               alpha_mv.device_interrupt = takara_srm_device_interrupt;
+
+       if (!alpha_using_srm) {
+               unsigned int ctlreg = inl(0x500);
+
+               /* Return to non-accelerated mode.  */
+               ctlreg &= ~0x8000;
+               outl(ctlreg, 0x500);
+
+               /* Enable the PCI interrupt register.  */
+               ctlreg = 0x05107c00;
+               outl(ctlreg, 0x500);
+       }
+
        enable_irq(2);
 }
 
-
 /*
  * The Takara has PCI devices 1, 2, and 3 configured to slots 20,
  * 19, and 18 respectively, in the default configuration. They can
@@ -123,12 +150,35 @@ takara_map_irq(struct pci_dev *dev, int slot, int pin)
        return COMMON_TABLE_LOOKUP;
 }
 
+static int __init
+takara_swizzle(struct pci_dev *dev, int *pinp)
+{
+       int slot = PCI_SLOT(dev->devfn);
+       int pin = *pinp;
+       unsigned int ctlreg = inl(0x500);
+       unsigned int busslot = PCI_SLOT(dev->bus->self->devfn);
+
+       /* Check first for built-in bridges.  */
+       if (busslot > 16 && ((1<<(36-busslot)) & ctlreg)) {
+               if (pin == 1)
+                       pin += (20 - busslot);
+               else {
+                       /* Must be a card-based bridge.  */
+                       printk(KERN_WARNING "takara_swizzle: cannot handle "
+                              "card-bridge behind builtin bridge yet.\n");
+               }
+       }
+
+       *pinp = pin;
+       return slot;
+}
+
 static void __init
 takara_pci_fixup(void)
 {
        layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
-       common_pci_fixup(takara_map_irq, common_swizzle);
-       enable_ide(0x26e);
+       common_pci_fixup(takara_map_irq, takara_swizzle);
+       /* enable_ide(0x26e); */
 }
 
 
@@ -147,7 +197,7 @@ struct alpha_machine_vector takara_mv __initmv = {
 
        nr_irqs:                20,
        irq_probe_mask:         _PROBE_MASK(20),
-       update_irq_hw:          NULL,
+       update_irq_hw:          takara_update_irq_hw,
        ack_irq:                generic_ack_irq,
        device_interrupt:       takara_device_interrupt,
 
index e75c373836498b07a71f76c7f346a4ec3095565c..e7f32dc9a7a5e372dbf04f8d7a22a8fea4b94f95 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/alpha/kernel/time.c
  *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *  Copyright (C) 1991, 1992, 1995, 1999  Linus Torvalds
  *
  * This file contains the PC-specific time handling details:
  * reading the RTC at bootup, etc..
 #include "irq.h"
 
 extern rwlock_t xtime_lock;
-extern volatile unsigned long lost_ticks;      /*kernel/sched.c*/
-
-extern rwlock_t xtime_lock;
-extern volatile unsigned long lost_ticks;      /*kernel/sched.c*/
+extern volatile unsigned long lost_ticks;      /* kernel/sched.c */
 
 static int set_rtc_mmss(unsigned long);
 
index a2c8ecb37b93ef4a81421d327a7e8c79c9fd79af..1d727893900b3b1c333cda238dcd65369f4864fd 100644 (file)
@@ -753,19 +753,29 @@ bootsect_panic_mess:
 ! This routine checks that the keyboard command queue is empty
 ! (after emptying the output buffers)
 !
-! No timeout is used - if this hangs there is something wrong with
-! the machine, and we probably couldn't proceed anyway.
+! Some machines have delusions that the keyboard buffer is always full
+! with no keyboard attached...
+
 empty_8042:
+       push    cx
+       mov     cx,#0xFFFF
+
+empty_8042_loop:
+       dec     cx
+       jz      empty_8042_end_loop
+
        call    delay
        in      al,#0x64        ! 8042 status port
        test    al,#1           ! output buffer?
        jz      no_output
        call    delay
        in      al,#0x60        ! read it
-       jmp     empty_8042
+       jmp     empty_8042_loop
 no_output:
        test    al,#2           ! is input buffer full?
-       jnz     empty_8042      ! yes - loop
+       jnz     empty_8042_loop ! yes - loop
+empty_8042_end_loop:
+        pop     cx
        ret
 
 !
index 7c5ad2712040a19ffe4d99cff20cb8450f6aa4c7..9c6948c600ada81fdf929ddf2610969fb88f8f75 100644 (file)
@@ -112,21 +112,25 @@ static int mca_default_procfn(char* buf, int slot);
 static ssize_t proc_mca_read(struct file*, char*, size_t, loff_t *);
 
 static struct file_operations proc_mca_operations = {
-       NULL,                   /* array_lseek */
-       proc_mca_read,          /* array_read */
-       NULL,                   /* array_write */
-       NULL,                   /* array_readdir */
-       NULL,                   /* array_poll */
-       NULL,                   /* array_ioctl */
+       NULL,                   /* llseek */
+       proc_mca_read,          /* read */
+       NULL,                   /* write */
+       NULL,                   /* readdir */
+       NULL,                   /* poll */
+       NULL,                   /* ioctl */
        NULL,                   /* mmap */
-       NULL,                   /* no special open code */
+       NULL,                   /* open */
        NULL,                   /* flush */
-       NULL,                   /* no special release code */
-       NULL                    /* can't fsync */
+       NULL,                   /* release */
+       NULL,                   /* fsync */
+       NULL,                   /* fascync */
+       NULL,                   /* check_media_change */
+       NULL,                   /* revalidate */
+       NULL                    /* lock */
 };
 
 static struct inode_operations proc_mca_inode_operations = {
-       &proc_mca_operations,   /* default base directory file-ops */
+       &proc_mca_operations,   /* default file-ops */
        NULL,                   /* create */
        NULL,                   /* lookup */
        NULL,                   /* link */
@@ -142,7 +146,10 @@ static struct inode_operations proc_mca_inode_operations = {
        NULL,                   /* writepage */
        NULL,                   /* bmap */
        NULL,                   /* truncate */
-       NULL                    /* permission */
+       NULL,                   /* permission */
+       NULL,                   /* smap */
+       NULL,                   /* updatepage */
+       NULL                    /* revalidate */
 };
 #endif
 
@@ -220,18 +227,19 @@ __initfunc(void mca_init(void))
        if(!MCA_bus)
                return;
        printk("Micro Channel bus detected.\n");
-       save_flags(flags);
-       cli();
 
        /* Allocate MCA_info structure (at address divisible by 8) */
 
-       mca_info = kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
+       mca_info = (struct MCA_info *)kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
 
        if(mca_info == NULL) {
                printk("Failed to allocate memory for mca_info!");
-               restore_flags(flags);
                return;
        }
+       memset(mca_info, 0, sizeof(struct MCA_info));
+
+       save_flags(flags);
+       cli();
 
        /* Make sure adapter setup is off */
 
@@ -705,12 +713,15 @@ __initfunc(void mca_do_proc_init(void))
                mca_info->slot[i].dev = 0;
 
                if(!mca_isadapter(i)) continue;
-               node = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+
+               node = (struct proc_dir_entry *)kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
 
                if(node == NULL) {
                        printk("Failed to allocate memory for MCA proc-entries!");
                        return;
                }
+               memset(node, 0, sizeof(struct proc_dir_entry));
+
                if(i < MCA_MAX_SLOT_NR) {
                        node->low_ino = PROC_MCA_SLOT + i;
                        node->namelen = sprintf(mca_info->slot[i].procname,
@@ -854,7 +865,7 @@ static ssize_t proc_mca_read(struct file* file,
        type = inode->i_ino;
        pid = type >> 16;
        type &= 0x0000ffff;
-       start = 0;
+       start = NULL;
        dp = (struct proc_dir_entry *) inode->u.generic_ip;
        length = mca_fill((char *) page, pid, type,
                          &start, ppos, count);
@@ -862,7 +873,7 @@ static ssize_t proc_mca_read(struct file* file,
                free_page(page);
                return length;
        }
-       if(start != 0) {
+       if(start != NULL) {
                /* We have had block-adjusting processing! */
 
                copy_to_user(buf, start, length);
index be2e6e992fc59c04d506bc246f77bdf19a5765c9..202de42d756378060315c504d8c898e04dabd8c1 100644 (file)
@@ -12,6 +12,8 @@
  * 
  *  Force Centaur C6 processors to report MTRR capability.
  *      Bart Hartgers <bart@etpmod.phys.tue.nl>, May 199.
+ *
+ *  Intel Mobile Pentium II detection fix. Sean Gilley, June 1999.
  */
 
 /*
@@ -688,7 +690,7 @@ static struct cpu_model_info cpu_models[] __initdata = {
            NULL, NULL, NULL, NULL }},
        { X86_VENDOR_INTEL,     6,
          { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
-           NULL, "Pentium II (Deschutes)", "Celeron (Mendocino)", NULL,
+            NULL, "Pentium II (Deschutes)", "Mobile Pentium II", NULL,
            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
        { X86_VENDOR_AMD,       4,
          { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
@@ -794,13 +796,19 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c))
                        if (c->x86_model <= 16)
                                p = cpu_models[i].model_names[c->x86_model];
 
-                       /* Names for the Pentium II processors */
+                       /* Names for the Pentium II Celeron processors 
+                           detectable only by also checking the cache size */
                        if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
-                           && (cpu_models[i].x86 == 6) 
-                           && (c->x86_model == 5)
-                           && (c->x86_cache_size == 0)) {
-                               p = "Celeron (Covington)";
-                       }
+                           && (cpu_models[i].x86 == 6)){ 
+                               if(c->x86_model == 6 && c->x86_cache_size == 128) {
+                                       p = "Celeron (Mendocino)"; 
+                               }
+                               else { 
+                               if (c->x86_model == 5 && c->x86_cache_size == 0) {
+                                       p = "Celeron (Covington)";
+                               }
+                        }
+                    }
                }
                        
        }
index c0aa02d6695663dc03d80ef7c9db0e3bf493c141..32e7c4c56f4a7c87edbb9339a1953b4cee769435 100644 (file)
@@ -698,6 +698,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
                        default:
                                lock_kernel();
                                sigaddset(&current->signal, signr);
+                               recalc_sigpending(current);
                                current->flags |= PF_SIGNALED;
                                do_exit(exit_code);
                                /* NOTREACHED */
index 841295d8227f597108ad07fd805ba588ebc64150..9bb8e690ee4ad2b98e12e0c71c653fa139339e54 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
index b4c986f4cd156ef6654d88afd217b4c2b247c2b4..a9615798772fb12ede0428731551634cdbd65630 100644 (file)
@@ -1924,8 +1924,6 @@ static int start_motor(void (*function)(void) )
 
 static void floppy_ready(void)
 {
-       unsigned long flags;
-       
        CHECK_RESET;
        if (start_motor(floppy_ready)) return;
        if (fdc_dtr()) return;
@@ -1945,7 +1943,7 @@ static void floppy_ready(void)
        if ((raw_cmd->flags & FD_RAW_READ) || 
            (raw_cmd->flags & FD_RAW_WRITE))
        {
-               flags=claim_dma_lock();
+               unsigned long flags = claim_dma_lock();
                fd_chose_dma_mode(raw_cmd->kernel_data,
                                  raw_cmd->length);
                release_dma_lock(flags);
index a3292e409c86457f6674f798846e95d798482bda..ad93cff38e4b731277d4520339bf53470975aa7d 100644 (file)
@@ -1,3 +1,4 @@
+
 /* 
     bttv - Bt848 frame grabber driver
 
@@ -545,6 +546,8 @@ static struct tvcard tvcards[] =
         { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},
         /* "Leadtek WinView 601", */
         { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
+        /* AVEC Intercapture */
+        { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
 
@@ -2900,6 +2903,18 @@ static void init_tea6300(struct i2c_bus *bus)
         I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */
 }
 
+static void init_tea6320(struct i2c_bus *bus)
+{
+  I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB  */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB  */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB         */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB       */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */
+}
+
 static void init_tda8425(struct i2c_bus *bus) 
 {
         I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB  */
@@ -3027,9 +3042,16 @@ static void idcard(int i)
         
         if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0)
         {
+          if(btv->type==BTTV_AVEC_INTERCAP)
+            {
+                printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr);
+                btv->audio_chip = TEA6320;
+                init_tea6320(&(btv->i2c));
+            } else {
                printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr);
                btv->audio_chip = TEA6300;
                init_tea6300(&(btv->i2c));
+            }
         } else
                printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr);
 
@@ -3073,6 +3095,9 @@ static void idcard(int i)
                case BTTV_WINVIEW_601:
                        strcpy(btv->video_dev.name,"BT848(Leadtek WinView 601)");
                        break;     
+                case BTTV_AVEC_INTERCAP:
+                        strcpy(btv->video_dev.name,"(AVEC Intercapture)");
+                        break;
        }
        printk("%s\n",btv->video_dev.name);
        audio(btv, AUDIO_MUTE);
index 41024d7aad17a532a7e959bef4434aff394f3ab9..a8059a5cf2d04404e6ee657d3e1ccdce3b4dee48 100644 (file)
@@ -211,6 +211,7 @@ struct bttv
 #define BTTV_ZOLTRIX       0x0f
 #define BTTV_PIXVIEWPLAYTV 0x10
 #define BTTV_WINVIEW_601   0x11
+#define BTTV_AVEC_INTERCAP 0x12
 
 #define AUDIO_TUNER        0x00
 #define AUDIO_RADIO        0x01
@@ -225,6 +226,7 @@ struct bttv
 #define TDA8425            0x02
 #define TDA9840            0x03
 #define TEA6300            0x04
+#define TEA6320            0x05
 
 #define I2C_TSA5522        0xc2
 #define I2C_TDA9840       0x84
@@ -233,7 +235,7 @@ struct bttv
 #define I2C_HAUPEE         0xa0
 #define I2C_STBEE          0xae
 #define I2C_VHX           0xc0
-#define I2C_TEA6300        0x80
+#define I2C_TEA6300        0x80 /* same as TEA6320 */
 
 #define TDA9840_SW        0x00
 #define TDA9840_LVADJ     0x02
@@ -261,6 +263,22 @@ struct bttv
 #define TEA6300_FA         0x04                /* fader control */
 #define TEA6300_SW         0x05                /* mute and source switch */
 
+
+#define TEA6320_V          0x00
+#define TEA6320_FFR        0x01  /* volume front right */
+#define TEA6320_FFL        0x02  /* volume front left */
+#define TEA6320_FRR        0x03  /* volume rear right */
+#define TEA6320_FRL        0x04  /* volume rear left */
+#define TEA6320_BA         0x05  /* bass */
+#define TEA6320_TR         0x06  /* treble */
+#define TEA6320_S          0x07  /* switch register */
+                                 /* values for those registers: */
+#define TEA6320_S_SA       0x01  /* stereo A input */
+#define TEA6320_S_SB       0x02  /* stereo B */
+#define TEA6320_S_SC       0x04  /* stereo C */
+#define TEA6320_S_GMU      0x80  /* general mute */
+
+
 #define PT2254_L_CHANEL 0x10
 #define PT2254_R_CHANEL 0x08
 #define PT2254_DBS_IN_2 0x400
index cff73b4a35e0ae7f47e099a06ef3dbd593a0e6cc..b72e5f89082d94ce6f0cc5c37f04e9952e0c29c6 100644 (file)
@@ -9,6 +9,7 @@
  *     Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
  *
  * Original release 01/11/99
+ * ==FILEDATE 19990524==
  *
  * This code is released under the GNU General Public License (GPL)
  *
@@ -72,7 +73,7 @@
  */
 
 #define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.0"
+#define HDLC_VERSION "1.2"
 
 #include <linux/version.h>
 #include <linux/config.h>
@@ -813,6 +814,8 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
 {
        struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
        int error = 0;
+       int count;
+       unsigned long flags;
        
        if (debuglevel >= DEBUG_LEVEL_INFO)     
                printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
@@ -824,21 +827,29 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
 
        switch (cmd) {
        case FIONREAD:
-               {
-                       /* report count of read data available */
-                       /* in next available frame (if any) */
-                       int count;
-                       unsigned long flags;
-                       spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
-                       if (n_hdlc->rx_buf_list.head)
-                               count = n_hdlc->rx_buf_list.head->count;
-                       else
-                               count = 0;
-                       spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
-                       PUT_USER (error, count, (int *) arg);
-               }
+               /* report count of read data available */
+               /* in next available frame (if any) */
+               spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
+               if (n_hdlc->rx_buf_list.head)
+                       count = n_hdlc->rx_buf_list.head->count;
+               else
+                       count = 0;
+               spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
+               PUT_USER (error, count, (int *) arg);
                break;
-               
+
+       case TIOCOUTQ:
+               /* get the pending tx byte count in the driver */
+               count = tty->driver.chars_in_buffer ?
+                               tty->driver.chars_in_buffer(tty) : 0;
+               /* add size of next output frame in queue */
+               spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
+               if (n_hdlc->tx_buf_list.head)
+                       count += n_hdlc->tx_buf_list.head->count;
+               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
+               PUT_USER (error, count, (int*)arg);
+               break;
+
        default:
                error = n_tty_ioctl (tty, file, cmd, arg);
                break;
index 08d502d8505f2ef3286473c3ecde616f1c95b27b..bdb7808d3ee4c375e81e2c6dc59eb26aea77a06a 100644 (file)
@@ -1,7 +1,7 @@
 /* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card 
  *
  * by Fred Gleason <fredg@wava.com>
- * Version 0.3.1
+ * Version 0.3.2
  *
  * (Loosely) based on code for the Aztech radio card by
  *
@@ -558,7 +558,7 @@ __initfunc(int cadet_init(struct video_init *v))
                return -EINVAL;
                
        request_region(io,2,"cadet");
-       printk(KERN_INFO "ADS Cadet Radio Card at %x\n",io);
+       printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
        return 0;
 }
 
@@ -571,12 +571,11 @@ static int cadet_probe(void)
 
        for(i=0;i<8;i++) {
                io=iovals[i];
-               if(check_region(io,2)) {
-                       return -1;
-               }  
-               cadet_setfreq(1410);
-               if(cadet_getfreq()==1410) {
-                       return io;
+               if(check_region(io,2)>=0) {
+                       cadet_setfreq(1410);
+                       if(cadet_getfreq()==1410) {
+                               return io;
+                       }
                }
        }
        return -1;
index 0881c88218c2040cd6734403e83ebb43e828f3f7..fda50c69e8e9e6796233504f5fa091ee67b020cd 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * linux/drivers/char/synclink.c
  *
+ * ==FILEDATE 19990610==
+ *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
  *
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
 #define BREAKPOINT() asm("   int $3");
 
 #define MAX_ISA_DEVICES 10
 
-#include <linux/config.h>
+#include <linux/config.h>      
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -68,7 +71,7 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+#if LINUX_VERSION_CODE >= VERSION(2,1,0) 
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <asm/serial.h>
@@ -209,8 +212,21 @@ typedef struct _BH_EVENT {
 } BH_EVENT, *BH_QUEUE;     /* Queue of BH actions to be done.  */
 
 #define MAX_BH_QUEUE_ENTRIES 200
+#define IO_PIN_SHUTDOWN_LIMIT (MAX_BH_QUEUE_ENTRIES/4)
 
 #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+struct _input_signal_events {
+       int     ri_up;  
+       int     ri_down;
+       int     dsr_up;
+       int     dsr_down;
+       int     dcd_up;
+       int     dcd_down;
+       int     cts_up;
+       int     cts_down;
+};
+
 /*
  * Device instance data structure
  */
@@ -266,6 +282,11 @@ struct mgsl_struct {
        int bh_running;         /* Protection from multiple */
        int isr_overflow;
        int bh_requested;
+       
+       int dcd_chkcount;               /* check counts to prevent */
+       int cts_chkcount;               /* too many IRQs if a signal */
+       int dsr_chkcount;               /* is floating */
+       int ri_chkcount;
 
        char *buffer_list;              /* virtual address of Rx & Tx buffer lists */
        unsigned long buffer_list_phys;
@@ -327,6 +348,11 @@ struct mgsl_struct {
        char flag_buf[HDLC_MAX_FRAME_SIZE];
        char char_buf[HDLC_MAX_FRAME_SIZE];     
        BOOLEAN drop_rts_on_tx_done;
+
+       BOOLEAN loopmode_insert_requested;
+       BOOLEAN loopmode_send_done_requested;
+       
+       struct  _input_signal_events    input_signal_events;
 };
 
 #define MGSL_MAGIC 0x5401
@@ -712,6 +738,13 @@ void usc_loopback_frame( struct mgsl_struct *info );
 
 void mgsl_tx_timeout(unsigned long context);
 
+
+void usc_loopmode_cancel_transmit( struct mgsl_struct * info );
+void usc_loopmode_insert_request( struct mgsl_struct * info );
+int usc_loopmode_active( struct mgsl_struct * info);
+void usc_loopmode_send_done( struct mgsl_struct * info );
+int usc_loopmode_send_active( struct mgsl_struct * info );
+
 /*
  * Defines a BUS descriptor value for the PCI adapter
  * local bus address ranges.
@@ -820,7 +853,8 @@ static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode);
 static int mgsl_txenable(struct mgsl_struct * info, int enable);
 static int mgsl_txabort(struct mgsl_struct * info);
 static int mgsl_rxenable(struct mgsl_struct * info, int enable);
-static int mgsl_wait_event(struct mgsl_struct * info, int mask);
+static int mgsl_wait_event(struct mgsl_struct * info, int * mask);
+static int mgsl_loopmode_send_done( struct mgsl_struct * info );
 
 #define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
 
@@ -865,7 +899,7 @@ MODULE_PARM(debug_level,"i");
 #endif
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "1.00";
+static char *driver_version = "1.7";
 
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
@@ -1001,6 +1035,7 @@ void mgsl_format_bh_queue( struct mgsl_struct *info )
 
        /* As a safety measure, mark the end of the chain with a NULL */
        info->free_bh_queue_tail->link = NULL;
+       info->isr_overflow=0;
 
 }      /* end of mgsl_format_bh_queue() */
 
@@ -1092,6 +1127,14 @@ int mgsl_bh_queue_get( struct mgsl_struct *info )
                spin_unlock_irqrestore(&info->irq_spinlock,flags);
                return 1;
        }
+       
+       if ( info->isr_overflow ) {
+               if (debug_level >= DEBUG_LEVEL_BH)
+                       printk("ISR overflow cleared.\n");
+               info->isr_overflow=0;
+               usc_EnableMasterIrqBit(info);
+               usc_EnableDmaInterrupts(info,DICR_MASTER);
+       }
 
        /* Mark BH routine as complete */
        info->bh_running   = 0;
@@ -1155,10 +1198,6 @@ void mgsl_bh_handler(void* Context)
                }
        }
 
-       if ( info->isr_overflow ) {
-               printk("ISR overflow detected.\n");
-       }
-
        if ( debug_level >= DEBUG_LEVEL_BH )
                printk( "%s(%d):mgsl_bh_handler(%s) exit\n",
                        __FILE__,__LINE__,info->device_name);
@@ -1199,6 +1238,7 @@ void mgsl_bh_receive_dma( struct mgsl_struct *info, unsigned short status )
 void mgsl_bh_transmit_data( struct mgsl_struct *info, unsigned short Datacount )
 {
        struct tty_struct *tty = info->tty;
+       unsigned long flags;
        
        if ( debug_level >= DEBUG_LEVEL_BH )
                printk( "%s(%d):mgsl_bh_transmit_data() entry on %s\n",
@@ -1215,7 +1255,15 @@ void mgsl_bh_transmit_data( struct mgsl_struct *info, unsigned short Datacount )
                }
                wake_up_interruptible(&tty->write_wait);
        }
-       
+
+       /* if transmitter idle and loopmode_send_done_requested
+        * then start echoing RxD to TxD
+        */
+       spin_lock_irqsave(&info->irq_spinlock,flags);
+       if ( !info->tx_active && info->loopmode_send_done_requested )
+               usc_loopmode_send_done( info );
+       spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
 }      /* End Of mgsl_bh_transmit_data() */
 
 /* mgsl_bh_status_handler()
@@ -1240,6 +1288,23 @@ void mgsl_bh_status_handler( struct mgsl_struct *info, unsigned short status )
                printk( "%s(%d):mgsl_bh_status_handler() entry on %s\n",
                        __FILE__,__LINE__,info->device_name);
 
+       if (status & MISCSTATUS_RI_LATCHED) {
+               if (info->ri_chkcount)
+                       (info->ri_chkcount)--;
+       }
+       if (status & MISCSTATUS_DSR_LATCHED) {
+               if (info->dsr_chkcount)
+                       (info->dsr_chkcount)--;
+       }
+       if (status & MISCSTATUS_DCD_LATCHED) {
+               if (info->dcd_chkcount)
+                       (info->dcd_chkcount)--;
+       }
+       if (status & MISCSTATUS_CTS_LATCHED) {
+               if (info->cts_chkcount)
+                       (info->cts_chkcount)--;
+       }
+       
 }      /* End Of mgsl_bh_status_handler() */
 
 /* mgsl_isr_receive_status()
@@ -1259,8 +1324,21 @@ void mgsl_isr_receive_status( struct mgsl_struct *info )
                printk("%s(%d):mgsl_isr_receive_status status=%04X\n",
                        __FILE__,__LINE__,status);
                        
-       usc_ClearIrqPendingBits( info, RECEIVE_STATUS );
-       usc_UnlatchRxstatusBits( info, status );
+       if ( (status & RXSTATUS_ABORT_RECEIVED) && 
+               info->loopmode_insert_requested &&
+               usc_loopmode_active(info) )
+       {
+               ++info->icount.rxabort;
+               info->loopmode_insert_requested = FALSE;
+               /* clear CMR:13 to start echoing RxD to TxD */
+               info->cmr_value &= ~BIT13;
+               usc_OutReg(info, CMR, info->cmr_value);
+               /* disable received abort irq (no longer required) */
+               usc_OutReg(info, RICR,
+                       (usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED));
+       }
 
        if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) {
                if (status & RXSTATUS_EXITED_HUNT)
@@ -1278,6 +1356,9 @@ void mgsl_isr_receive_status( struct mgsl_struct *info )
                usc_RTCmd( info, RTCmd_PurgeRxFifo );
        }
 
+       usc_ClearIrqPendingBits( info, RECEIVE_STATUS );
+       usc_UnlatchRxstatusBits( info, status );
+
 }      /* end of mgsl_isr_receive_status() */
 
 /* mgsl_isr_transmit_status()
@@ -1300,7 +1381,7 @@ void mgsl_isr_transmit_status( struct mgsl_struct *info )
        
        usc_ClearIrqPendingBits( info, TRANSMIT_STATUS );
        usc_UnlatchTxstatusBits( info, status );
-
        if ( status & TXSTATUS_EOF_SENT )
                info->icount.txok++;
        else if ( status & TXSTATUS_UNDERRUN )
@@ -1356,12 +1437,32 @@ void mgsl_isr_io_pin( struct mgsl_struct *info )
                      MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) {
                icount = &info->icount;
                /* update input line counters */
-               if (status & MISCSTATUS_RI_LATCHED)
+               if (status & MISCSTATUS_RI_LATCHED) {
+                       if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+                               usc_DisablestatusIrqs(info,SICR_RI);
                        icount->rng++;
-               if (status & MISCSTATUS_DSR_LATCHED)
+                       if ( status & MISCSTATUS_RI )
+                               info->input_signal_events.ri_up++;      
+                       else
+                               info->input_signal_events.ri_down++;    
+               }
+               if (status & MISCSTATUS_DSR_LATCHED) {
+                       if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+                               usc_DisablestatusIrqs(info,SICR_DSR);
                        icount->dsr++;
+                       if ( status & MISCSTATUS_DSR )
+                               info->input_signal_events.dsr_up++;
+                       else
+                               info->input_signal_events.dsr_down++;
+               }
                if (status & MISCSTATUS_DCD_LATCHED) {
+                       if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+                               usc_DisablestatusIrqs(info,SICR_DCD);
                        icount->dcd++;
+                       if ( status & MISCSTATUS_DCD )
+                               info->input_signal_events.dcd_up++;
+                       else
+                               info->input_signal_events.dcd_down++;
 #ifdef CONFIG_HARD_PPS
                        if ((info->flags & ASYNC_HARDPPS_CD) &&
                            (status & MISCSTATUS_DCD_LATCHED))
@@ -1369,7 +1470,15 @@ void mgsl_isr_io_pin( struct mgsl_struct *info )
 #endif
                }
                if (status & MISCSTATUS_CTS_LATCHED)
+               {
+                       if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+                               usc_DisablestatusIrqs(info,SICR_CTS);
                        icount->cts++;
+                       if ( status & MISCSTATUS_CTS )
+                               info->input_signal_events.cts_up++;
+                       else
+                               info->input_signal_events.cts_down++;
+               }
                wake_up_interruptible(&info->status_event_wait_q);
                wake_up_interruptible(&info->event_wait_q);
 
@@ -1411,6 +1520,8 @@ void mgsl_isr_io_pin( struct mgsl_struct *info )
                }
        }
 
+       mgsl_bh_queue_put(info, BH_TYPE_STATUS, status);
+       
        /* for diagnostics set IRQ flag */
        if ( status & MISCSTATUS_TXC_LATCHED ){
                usc_OutReg( info, SICR,
@@ -1642,8 +1753,10 @@ void mgsl_isr_receive_dma( struct mgsl_struct *info )
        /* Post a receive event for BH processing. */
        mgsl_bh_queue_put( info, BH_TYPE_RECEIVE_DMA, status );
        
-       if ( status & BIT3 )
+       if ( status & BIT3 ) {
                info->rx_overflow = 1;
+               info->icount.buf_overrun++;
+       }
 
 }      /* end of mgsl_isr_receive_dma() */
 
@@ -1696,9 +1809,9 @@ static void mgsl_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                if ( info->isr_overflow ) {
                        printk(KERN_ERR"%s(%d):%s isr overflow irq=%d\n",
                                __FILE__,__LINE__,info->device_name, irq);
-                               /* Interrupt overflow. Reset adapter and exit. */
-//                             UscReset(info);
-//                             break;
+                       usc_DisableMasterIrqBit(info);
+                       usc_DisableDmaInterrupts(info,DICR_MASTER);
+                       break;
                }
        }
        
@@ -1980,6 +2093,11 @@ static void mgsl_change_params(struct mgsl_struct *info)
                usc_set_async_mode(info);
                
        usc_set_serial_signals(info);
+       
+       info->dcd_chkcount = 0;
+       info->cts_chkcount = 0;
+       info->ri_chkcount = 0;
+       info->dsr_chkcount = 0;
 
        /* enable modem signal IRQs and read initial signal states */
        usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI);          
@@ -2112,16 +2230,27 @@ static int mgsl_write(struct tty_struct * tty, int from_user,
 
        if ( info->params.mode == MGSL_MODE_HDLC ) {
                /* operating in synchronous (frame oriented) mode */
-       
+
                if (info->tx_active) {
                        ret = 0; goto cleanup; 
                }
-               
+       
+               /* if operating in HDLC LoopMode and the adapter  */
+               /* has yet to be inserted into the loop, we can't */
+               /* transmit                                       */
+
+               if ( (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) &&
+                       !usc_loopmode_active(info) )
+               {
+                       ret = 0;
+                       goto cleanup;
+               }
+
                if ( info->xmit_cnt ) {
                        /* Send accumulated from send_char() calls */
                        /* as frame and wait before accepting more data. */
                        ret = 0;
-                               
+                       
                        /* copy data from circular xmit_buf to */
                        /* transmit DMA buffer. */
                        mgsl_load_tx_dma_buffer(info,
@@ -2578,8 +2707,19 @@ static int mgsl_txenable(struct mgsl_struct * info, int enable)
                        
        spin_lock_irqsave(&info->irq_spinlock,flags);
        if ( enable ) {
-               if ( !info->tx_enabled )
+               if ( !info->tx_enabled ) {
+
                        usc_start_transmitter(info);
+                       /*--------------------------------------------------
+                        * if HDLC/SDLC Loop mode, attempt to insert the
+                        * station in the 'loop' by setting CMR:13. Upon
+                        * receipt of the next GoAhead (RxAbort) sequence,
+                        * the OnLoop indicator (CCSR:7) should go active
+                        * to indicate that we are on the loop
+                        *--------------------------------------------------*/
+                       if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+                               usc_loopmode_insert_request( info );
+               }
        } else {
                if ( info->tx_enabled )
                        usc_stop_transmitter(info);
@@ -2604,7 +2744,12 @@ static int mgsl_txabort(struct mgsl_struct * info)
                        
        spin_lock_irqsave(&info->irq_spinlock,flags);
        if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC )
-               usc_TCmd(info,TCmd_SendAbort);
+       {
+               if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+                       usc_loopmode_cancel_transmit( info );
+               else
+                       usc_TCmd(info,TCmd_SendAbort);
+       }
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
        return 0;
        
@@ -2640,25 +2785,39 @@ static int mgsl_rxenable(struct mgsl_struct * info, int enable)
 /* mgsl_wait_event()   wait for specified event to occur
  *     
  * Arguments:          info    pointer to device instance data
- *                     mask    bitmask of events to wait for
- * Return Value:       bit mask of triggering event, otherwise error code
+ *                     mask    pointer to bitmask of events to wait for
+ * Return Value:       0       if successful and bit mask updated with
+ *                             of events triggerred,
+ *                     otherwise error code
  */
-static int mgsl_wait_event(struct mgsl_struct * info, int mask)
+static int mgsl_wait_event(struct mgsl_struct * info, int * mask_ptr)
 {
        unsigned long flags;
        int s;
        int rc=0;
        u16 regval;
        struct mgsl_icount cprev, cnow;
+       int events = 0;
+       int mask;
+       struct  _input_signal_events signal_events_prev, signal_events_now;
+
+       COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
+       if (rc) {
+               return  -EFAULT;
+       }
                 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgsl_wait_event(%s,%d)\n", __FILE__,__LINE__,
                        info->device_name, mask);
-                       
+
        spin_lock_irqsave(&info->irq_spinlock,flags);
-       
+
+       usc_get_serial_signals(info);
+       s = info->serial_signals;
+
        /* note the counters on entry */
        cprev = info->icount;
+       signal_events_prev = info->input_signal_events;
        
        if (mask & MgslEvent_ExitHuntMode) {
                /* enable exit hunt mode IRQ */
@@ -2676,7 +2835,22 @@ static int mgsl_wait_event(struct mgsl_struct * info, int mask)
        
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
        
-       while(!rc) {
+       /* Determine if any user requested events for input signals is currently TRUE */
+       
+       events |= (mask & ((s & SerialSignal_DSR) ?
+                       MgslEvent_DsrActive:MgslEvent_DsrInactive));
+
+       events |= (mask & ((s & SerialSignal_DCD) ?
+                       MgslEvent_DcdActive:MgslEvent_DcdInactive));
+               
+       events |= (mask & ((s & SerialSignal_CTS) ?
+                       MgslEvent_CtsActive:MgslEvent_CtsInactive));
+               
+       events |= (mask & ((s & SerialSignal_RI) ?
+                       MgslEvent_RiActive:MgslEvent_RiInactive));
+       
+
+       while(!events) {
                /* sleep until event occurs */
                interruptible_sleep_on(&info->event_wait_q);
                
@@ -2687,44 +2861,57 @@ static int mgsl_wait_event(struct mgsl_struct * info, int mask)
                }
                        
                spin_lock_irqsave(&info->irq_spinlock,flags);
+
                /* get icount and serial signal states */
                cnow = info->icount;
-               s = info->serial_signals;
+               signal_events_now = info->input_signal_events;
                spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+               if (signal_events_now.dsr_up != signal_events_prev.dsr_up && 
+                               mask & MgslEvent_DsrActive )
+                       events |= MgslEvent_DsrActive;
                
-               rc = 0;         
+               if (signal_events_now.dsr_down != signal_events_prev.dsr_down && 
+                               mask & MgslEvent_DsrInactive )
+                       events |= MgslEvent_DsrInactive;
+
+               if (signal_events_now.dcd_up != signal_events_prev.dcd_up &&
+                               mask & MgslEvent_DcdActive )
+                       events |= MgslEvent_DcdActive;
                
-               if (cnow.dsr != cprev.dsr)
-                       rc |= (mask & ((s & SerialSignal_DSR) ?
-                               MgslEvent_DsrActive:MgslEvent_DsrInactive));
+               if (signal_events_now.dcd_down != signal_events_prev.dcd_down &&
+                               mask & MgslEvent_DcdInactive )
+                       events |= MgslEvent_DcdInactive;
+               
+               if (signal_events_now.cts_up != signal_events_prev.cts_up &&
+                               mask & MgslEvent_CtsActive )
+                       events |= MgslEvent_CtsActive;
+               
+               if (signal_events_now.cts_down != signal_events_prev.cts_down &&
+                               mask & MgslEvent_CtsInactive )
+                       events |= MgslEvent_CtsInactive;
+               
+               if (signal_events_now.ri_up != signal_events_prev.ri_up &&
+                               mask & MgslEvent_RiActive )
+                       events |= MgslEvent_RiActive;
+               
+               if (signal_events_now.ri_down != signal_events_prev.ri_down &&
+                               mask & MgslEvent_RiInactive )
+                       events |= MgslEvent_RiInactive;
                
-               if (cnow.dcd != cprev.dcd)
-                       rc |= (mask & ((s & SerialSignal_DCD) ?
-                               MgslEvent_DcdActive:MgslEvent_DcdInactive));
-                               
-               if (cnow.cts != cprev.cts)
-                       rc |= (mask & ((s & SerialSignal_CTS) ?
-                               MgslEvent_CtsActive:MgslEvent_CtsInactive));
-                               
-               if (cnow.rng != cprev.rng)
-                       rc |= (mask & ((s & SerialSignal_RI) ?
-                               MgslEvent_RiActive:MgslEvent_RiInactive));
-                               
                if (cnow.exithunt != cprev.exithunt)
-                       rc |= (mask & MgslEvent_ExitHuntMode);
-                       
+                       events |= (mask & MgslEvent_ExitHuntMode);
+
                if (cnow.rxidle != cprev.rxidle)
-                       rc |= (mask & MgslEvent_ExitHuntMode);
-                               
-               if (!rc)
-                       rc = -EIO; /* no change => error */
-                       
+                       events |= (mask & MgslEvent_IdleReceived);
+               
                cprev = cnow;
+               signal_events_prev = signal_events_now;
        }
        
        if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
                spin_lock_irqsave(&info->irq_spinlock,flags);
-               if (!info->event_wait_q) {
+               if (!waitqueue_active(&info->event_wait_q)) {
                        /* disable enable exit hunt mode/idle rcvd IRQs */
                        regval = usc_InReg(info,RICR);
                        usc_OutReg(info, RICR, regval & 
@@ -2732,7 +2919,10 @@ static int mgsl_wait_event(struct mgsl_struct * info, int mask)
                }
                spin_unlock_irqrestore(&info->irq_spinlock,flags);
        }
-       
+
+       if ( rc == 0 )
+               PUT_USER(rc, events, mask_ptr);
+               
        return rc;
        
 }      /* end of mgsl_wait_event() */
@@ -2772,7 +2962,7 @@ static int get_modem_info(struct mgsl_struct * info, unsigned int *value)
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgsl_get_modem_info %s value=%08X\n",
-                        __FILE__,__LINE__, info->device_name, *value );
+                        __FILE__,__LINE__, info->device_name, result );
                        
        PUT_USER(err,result,value);
        return err;
@@ -2928,7 +3118,9 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
                case MGSL_IOCGSTATS:
                        return mgsl_get_stats(info,(struct mgsl_icount*)arg);
                case MGSL_IOCWAITEVENT:
-                       return mgsl_wait_event(info,(int)arg);
+                       return mgsl_wait_event(info,(int*)arg);
+               case MGSL_IOCLOOPTXDONE:
+                       return mgsl_loopmode_send_done(info);
                case MGSL_IOCCLRMODCOUNT:
                        while(MOD_IN_USE)
                                MOD_DEC_USE_COUNT;
@@ -3626,11 +3818,6 @@ static inline int line_info(char *buf, struct mgsl_struct *info)
        }
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
        
-#if 0 && LINUX_VERSION_CODE >= VERSION(2,1,0)
-       ret += sprintf(buf+ret, "irq_spinlock=%08X\n",
-                       info->irq_spinlock.lock );
-#endif
-       
        return ret;
        
 }      /* end of line_info() */
@@ -4223,6 +4410,18 @@ int mgsl_enumerate_devices()
                        if ( PCIBIOS_SUCCESSFUL == pcibios_find_device(
                                MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) {
                                
+#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+                               struct pci_dev *pdev = pci_find_slot(bus,func);
+                               irq_line = pdev->irq;                           
+#else                                                                                          
+                               if (pcibios_read_config_byte(bus,func,
+                                       PCI_INTERRUPT_LINE,&irq_line) ) {
+                                       printk( "%s(%d):USC I/O addr not set.\n",
+                                               __FILE__,__LINE__);
+                                       continue;
+                               }
+#endif
+
                                if (pcibios_read_config_dword(bus,func,
                                        PCI_BASE_ADDRESS_3,&shared_mem_base) ) {
                                        printk( "%s(%d):Shared mem addr not set.\n",
@@ -4244,13 +4443,6 @@ int mgsl_enumerate_devices()
                                        continue;
                                }
                                
-                               if (pcibios_read_config_byte(bus,func,
-                                       PCI_INTERRUPT_LINE,&irq_line) ) {
-                                       printk( "%s(%d):USC I/O addr not set.\n",
-                                               __FILE__,__LINE__);
-                                       continue;
-                               }
-                               
                                info = mgsl_allocate_device();
                                if ( !info ) {
                                        /* error allocating device instance data */
@@ -4667,29 +4859,53 @@ void usc_set_sdlc_mode( struct mgsl_struct *info )
 {
        u16 RegValue;
 
-       /* Channel mode Register (CMR)
-        *
-        * <15..14>  00    Tx Sub modes, Underrun Action
-        * <13>      0     1 = Send Preamble before opening flag
-        * <12>      0     1 = Consecutive Idles share common 0
-        * <11..8>   0110  Transmitter mode = HDLC/SDLC
-        * <7..4>    0000  Rx Sub modes, addr/ctrl field handling
-        * <3..0>    0110  Receiver mode = HDLC/SDLC
-        *
-        * 0000 0110 0000 0110 = 0x0606
-        */
+       if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+       {
+          /*
+          ** Channel Mode Register (CMR)
+          **
+          ** <15..14>    10    Tx Sub Modes, Send Flag on Underrun
+          ** <13>        0     0 = Transmit Disabled (initially)
+          ** <12>        0     1 = Consecutive Idles share common 0
+          ** <11..8>     1110  Transmitter Mode = HDLC/SDLC Loop
+          ** <7..4>      0000  Rx Sub Modes, addr/ctrl field handling
+          ** <3..0>      0110  Receiver Mode = HDLC/SDLC
+          **
+          ** 1000 1110 0000 0110 = 0x8e06
+          */
+          RegValue = 0x8e06;
+          /*--------------------------------------------------
+           * ignore user options for UnderRun Actions and
+           * preambles
+           *--------------------------------------------------*/
+       }
+       else
+       {       
+               /* Channel mode Register (CMR)
+                *
+                * <15..14>  00    Tx Sub modes, Underrun Action
+                * <13>      0     1 = Send Preamble before opening flag
+                * <12>      0     1 = Consecutive Idles share common 0
+                * <11..8>   0110  Transmitter mode = HDLC/SDLC
+                * <7..4>    0000  Rx Sub modes, addr/ctrl field handling
+                * <3..0>    0110  Receiver mode = HDLC/SDLC
+                *
+                * 0000 0110 0000 0110 = 0x0606
+                */
 
-       RegValue = 0x0606;
+               RegValue = 0x0606;
 
-       if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 )
-               RegValue |= BIT14;
-       else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG )
-               RegValue |= BIT15;
-       else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
-               RegValue |= BIT15 + BIT14;
+               if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 )
+                       RegValue |= BIT14;
+               else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG )
+                       RegValue |= BIT15;
+               else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
+                       RegValue |= BIT15 + BIT14;
 
-       if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
-               RegValue |= BIT13;
+               if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
+                       RegValue |= BIT13;
+       }
 
        if ( info->params.flags & HDLC_FLAG_SHARE_ZERO )
                RegValue |= BIT12;
@@ -4858,6 +5074,8 @@ void usc_set_sdlc_mode( struct mgsl_struct *info )
                RegValue |= 0x0003;     /* RxCLK from DPLL */
        else if ( info->params.flags & HDLC_FLAG_RXC_BRG )
                RegValue |= 0x0004;     /* RxCLK from BRG0 */
+       else if ( info->params.flags & HDLC_FLAG_RXC_TXCPIN)
+               RegValue |= 0x0006;     /* RxCLK from TXC Input */
        else
                RegValue |= 0x0007;     /* RxCLK from Port1 */
 
@@ -4865,6 +5083,8 @@ void usc_set_sdlc_mode( struct mgsl_struct *info )
                RegValue |= 0x0018;     /* TxCLK from DPLL */
        else if ( info->params.flags & HDLC_FLAG_TXC_BRG )
                RegValue |= 0x0020;     /* TxCLK from BRG0 */
+       else if ( info->params.flags & HDLC_FLAG_TXC_RXCPIN)
+               RegValue |= 0x0038;     /* RxCLK from TXC Input */
        else
                RegValue |= 0x0030;     /* TxCLK from Port0 */
 
@@ -4918,10 +5138,24 @@ void usc_set_sdlc_mode( struct mgsl_struct *info )
                /*  of rounding up and then subtracting 1 we just don't subtract */
                /*  the one in this case. */
 
-               Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed);
-               if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2)
-                      / info->params.clock_speed) )
-                       Tc--;
+               /*--------------------------------------------------
+                * ejz: for DPLL mode, application should use the
+                * same clock speed as the partner system, even 
+                * though clocking is derived from the input RxData.
+                * In case the user uses a 0 for the clock speed,
+                * default to 0xffffffff and don't try to divide by
+                * zero
+                *--------------------------------------------------*/
+               if ( info->params.clock_speed )
+               {
+                       Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed);
+                       if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2)
+                              / info->params.clock_speed) )
+                               Tc--;
+               }
+               else
+                       Tc = -1;
+                                 
 
                /* Write 16-bit Time Constant for BRG1 */
                usc_OutReg( info, TC1R, Tc );
@@ -6324,6 +6558,13 @@ void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, const char *Buffer,
        if ( debug_level >= DEBUG_LEVEL_DATA )
                mgsl_trace_block(info,Buffer,BufferSize,1);     
 
+       if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) {
+               /* set CMR:13 to start transmit when
+                * next GoAhead (abort) is received
+                */
+               info->cmr_value |= BIT13;                         
+       }
+               
        /* Setup the status and RCC (Frame Size) fields of the 1st */
        /* buffer entry in the transmit DMA buffer list. */
 
@@ -6377,7 +6618,7 @@ BOOLEAN mgsl_register_test( struct mgsl_struct *info )
        unsigned int i;
        BOOLEAN rc = TRUE;
        unsigned long flags;
-       
+
        spin_lock_irqsave(&info->irq_spinlock,flags);
        usc_reset(info);
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
@@ -6467,7 +6708,7 @@ BOOLEAN mgsl_irq_test( struct mgsl_struct *info )
        usc_reset(info);
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
        
-       if ( !info->irq_occurred )
+       if ( !info->irq_occurred ) 
                return FALSE;
        else
                return TRUE;
@@ -6495,7 +6736,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
        volatile unsigned long EndTime;
        unsigned long flags;
        MGSL_PARAMS tmp_params;
-       
+
        /* save current port options */
        memcpy(&tmp_params,&info->params,sizeof(MGSL_PARAMS));
        /* load default port options */
@@ -6653,7 +6894,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
        /**********************************/
        /* WAIT FOR TRANSMIT FIFO TO FILL */
        /**********************************/
-                                                                                                                        
+       
        /* Wait 100ms */
        EndTime = jiffies + jiffies_from_ms(100);
 
@@ -6720,7 +6961,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
 
        if ( rc == TRUE ){
                /* CHECK FOR TRANSMIT ERRORS */
-               if ( status & (BIT5 + BIT1) )
+               if ( status & (BIT5 + BIT1) ) 
                        rc = FALSE;
        }
 
@@ -6977,13 +7218,90 @@ void mgsl_tx_timeout(unsigned long context)
        if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
                info->icount.txtimeout++;
        }
-       
        spin_lock_irqsave(&info->irq_spinlock,flags);
        info->tx_active = 0;
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+       if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+               usc_loopmode_cancel_transmit( info );
+
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
        
        mgsl_bh_transmit_data(info,0);
        
 }      /* end of mgsl_tx_timeout() */
 
+/* signal that there are no more frames to send, so that
+ * line is 'released' by echoing RxD to TxD when current
+ * transmission is complete (or immediately if no tx in progress).
+ */
+static int mgsl_loopmode_send_done( struct mgsl_struct * info )
+{
+       unsigned long flags;
+       
+       spin_lock_irqsave(&info->irq_spinlock,flags);
+       if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) {
+               if (info->tx_active)
+                       info->loopmode_send_done_requested = TRUE;
+               else
+                       usc_loopmode_send_done(info);
+       }
+       spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+       return 0;
+}
+
+/* release the line by echoing RxD to TxD
+ * upon completion of a transmit frame
+ */
+void usc_loopmode_send_done( struct mgsl_struct * info )
+{
+       info->loopmode_send_done_requested = FALSE;
+       /* clear CMR:13 to 0 to start echoing RxData to TxData */
+       info->cmr_value &= ~BIT13;                        
+       usc_OutReg(info, CMR, info->cmr_value);
+}
+
+/* abort a transmit in progress while in HDLC LoopMode
+ */
+void usc_loopmode_cancel_transmit( struct mgsl_struct * info )
+{
+       /* reset tx dma channel and purge TxFifo */
+       usc_RTCmd( info, RTCmd_PurgeTxFifo );
+       usc_DmaCmd( info, DmaCmd_ResetTxChannel );
+       usc_loopmode_send_done( info );
+}
+
+/* for HDLC/SDLC LoopMode, setting CMR:13 after the transmitter is enabled
+ * is an Insert Into Loop action. Upon receipt of a GoAhead sequence (RxAbort)
+ * we must clear CMR:13 to begin repeating TxData to RxData
+ */
+void usc_loopmode_insert_request( struct mgsl_struct * info )
+{
+       info->loopmode_insert_requested = TRUE;
+       /* enable RxAbort irq. On next RxAbort, clear CMR:13 to
+        * begin repeating TxData on RxData (complete insertion)
+        */
+       usc_OutReg( info, RICR, 
+               (usc_InReg( info, RICR ) | RXSTATUS_ABORT_RECEIVED ) );
+               
+       /* set CMR:13 to insert into loop on next GoAhead (RxAbort) */
+       info->cmr_value |= BIT13;
+       usc_OutReg(info, CMR, info->cmr_value);
+}
+
+/* return 1 if station is inserted into the loop, otherwise 0
+ */
+int usc_loopmode_active( struct mgsl_struct * info)
+{
+       return usc_InReg( info, CCSR ) & BIT7 ? 1 : 0 ;
+}
+
+/* return 1 if USC is in loop send mode, otherwise 0
+ */
+int usc_loopmode_send_active( struct mgsl_struct * info )
+{
+       return usc_InReg( info, CCSR ) & BIT6 ? 1 : 0 ;
+}                        
+
index 1a96bec113a0cfa63581b18d2ee1df1476c3d004..55ff8eacc835c117014d05e220de6a7a7a8ab59b 100644 (file)
@@ -84,7 +84,9 @@ static struct tunertype tuners[] = {
              //  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
                16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623},
        {"Temic 4036 FY5 NTSC", TEMIC, NTSC,
-               16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+               16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+        {"Alps HSBH1", TEMIC, NTSC,
+                16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
 };
 
 /* ---------------------------------------------------------------------- */
index 439cc530d7288f5ddcb79d7ba6225b9698ff368d..afb0f10fb6d832bc2dd2c0da463b25b549ae639a 100644 (file)
@@ -31,6 +31,7 @@
 #define TUNER_TEMIC_NTSC    6
 #define TUNER_TEMIC_PAL_I   7
 #define TUNER_TEMIC_4036FY5_NTSC       8
+#define TUNER_ALPS_TSBH1_NTSC 9
 
 #define NOTUNER 0
 #define PAL     1
index 3e9b7ace163d19aa75dd62a11e347e23634f9775..e63d7611f2a406b3a765d26f4b4f542693e1ac10 100644 (file)
@@ -298,9 +298,9 @@ void parport_unregister_device(struct pardevice *dev)
        port = dev->port;
 
        if (port->cad == dev) {
-               printk(KERN_WARNING "%s: refused to unregister "
-                      "currently active device %s.\n", port->name, dev->name);
-               return;
+               printk(KERN_DEBUG "%s: %s forgot to release port\n",
+                      port->name, dev->name);
+               parport_release (dev);
        }
 
        spin_lock(&port->pardevice_lock);
index 7dc831e58f69f3c8cef7c1202a3a290025c0d8f7..26c82991c0fff982ab17c7b0fb319501258e5a8f 100644 (file)
@@ -1009,6 +1009,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
                        outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
                }
        }
+       vp->stats.tx_bytes+=skb->len;
        return 0;
 }
 
@@ -1209,6 +1210,7 @@ vortex_rx(struct device *dev)
                                netif_rx(skb);
                                dev->last_rx = jiffies;
                                vp->stats.rx_packets++;
+                               vp->stats.rx_bytes+=skb->len;
                                /* Wait a limited time to go to next packet. */
                                for (i = 200; i >= 0; i--)
                                        if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -1256,6 +1258,7 @@ boomerang_rx(struct device *dev)
                        short pkt_len = rx_status & 0x1fff;
                        struct sk_buff *skb;
 
+                       vp->stats.rx_bytes+=pkt_len;
                        if (vortex_debug > 4)
                                printk("Receiving packet size %d status %4.4x.\n",
                                           pkt_len, rx_status);
index ef1ba68ef2bf0560305d60c01f1b32eeb6505097..84f471587c2bb86beb2e18122ed86faf9194a883 100644 (file)
@@ -109,6 +109,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   fi
   if [ "$CONFIG_MCA" = "y" ]; then
     tristate 'NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
+    tristate 'SKnet MCA support' CONFIG_SKMC
   fi
   bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
   if [ "$CONFIG_NET_EISA" = "y" ]; then
index 6506f718d215876bb37a5948937355ba13a04fdf..261f6847b5e5f4202c9575912a3a7f363a94843b 100644 (file)
@@ -486,6 +486,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SKMC),y)
+L_OBJS += sk_mca.o
+else
+  ifeq ($(CONFIG_SKMC),m)
+  M_OBJS += sk_mca.o
+  endif
+endif
+
 ifeq ($(CONFIG_ELMC_II),y)
 L_OBJS += 3c527.o
 else
index 124e6e7bca13cbaa3da2a65cf0b1df3300dfbd02..86a2081ed044751daa2ef5196612242ff702dbd6 100644 (file)
@@ -69,6 +69,7 @@ extern int el1_probe(struct device *);
 extern int wavelan_probe(struct device *);
 extern int el16_probe(struct device *);
 extern int elmc_probe(struct device *);
+extern int skmca_probe(struct device *);
 extern int elplus_probe(struct device *);
 extern int ac3200_probe(struct device *);
 extern int es_probe(struct device *);
@@ -266,6 +267,9 @@ struct devprobe mca_probes[] __initdata = {
 #endif
 #ifdef CONFIG_ELMC             /* 3c523 */
        {elmc_probe, 0},
+#endif
+#ifdef CONFIG_SKMC              /* SKnet Microchannel */
+        {skmca_probe, 0},
 #endif
        {NULL, 0},
 };
index bc4084f8611f3a2983a822279c87a2b0f13c98e5..ad688beb72387a1849ad23f6b85310949372eb2d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cosa.c,v 1.21 1999/02/06 19:49:18 kas Exp $ */
+/* $Id: cosa.c,v 1.24 1999/05/28 17:28:34 kas Exp $ */
 
 /*
  *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
  * The Comtrol Hostess SV11 driver by Alan Cox
  * The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox
  */
+/*
+ *     5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br>
+ *             fixed a deadlock in cosa_sppp_open
+ */
 \f
 /* ---------- Headers, macros, data structures ---------- */
 
@@ -753,8 +757,13 @@ static struct net_device_stats *cosa_net_stats(struct device *dev)
 
 static void chardev_channel_init(struct channel_data *chan)
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
        chan->rsem = MUTEX;
        chan->wsem = MUTEX;
+#else
+       init_MUTEX(&chan->rsem);
+       init_MUTEX(&chan->wsem);
+#endif
 }
 
 static long long cosa_lseek(struct file * file,
@@ -1264,8 +1273,10 @@ static void put_driver_status(struct cosa_data *cosa)
                        debug_status_out(cosa, 0);
 #endif
                }
+               cosa_putdata8(cosa, 0);
                cosa_putdata8(cosa, status);
 #ifdef DEBUG_IO
+               debug_data_cmd(cosa, 0);
                debug_data_cmd(cosa, status);
 #endif
        }
@@ -1658,6 +1669,7 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
                                printk(KERN_WARNING
                                        "%s: No channel wants data in TX IRQ\n",
                                        cosa->name);
+                               put_driver_status_nolock(cosa);
                                clear_bit(TXBIT, &cosa->rxtx);
                                spin_unlock_irqrestore(&cosa->lock, flags);
                                return;
index 94fb660a73243118e0f706635b477d8bfd17c087..b4e4a911bdd5a55c10cdf1dff5b2d1a5658001b3 100644 (file)
@@ -739,7 +739,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
                if (tickssofar < 5)
                        return 1;
                if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
-                          tx_done(dev) ? "IRQ conflict" : "network cable problem");
+                          tx_done(dev) ? "IRQ conflict ?" : "network cable problem");
                /* Try to restart the adaptor. */
                dev->tbusy=0;
                dev->trans_start = jiffies;
index 1a7831e83506f26f7cd55d62798cce846788fad6..df988de482926d75d286785d5b3dc12edb2448e1 100644 (file)
@@ -10,6 +10,7 @@ dep_tristate 'NSC PC87108' CONFIG_NSC_FIR  $CONFIG_IRDA
 dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
 dep_tristate 'Sharp UIRCC' CONFIG_SHARP_FIR $CONFIG_IRDA
 dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
+dep_tristate 'SMC IrCC' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
 
 comment 'Dongle support' 
 bool 'Serial dongle support' CONFIG_DONGLE
index bd691dcae7fc0c830c8fd058257546edcd27d9f3..b92dde935af913ee1f02900a682c58c149297c35 100644 (file)
@@ -28,6 +28,22 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_IRPORT_SIR),y)
+L_OBJS += irport.o
+else
+  ifeq ($(CONFIG_IRPORT_SIR),m)
+  M_OBJS += irport.o
+  endif
+endif
+
+ifeq ($(CONFIG_IRPORT_SIR),y)
+L_OBJS += irport.o
+else
+  ifeq ($(CONFIG_IRPORT_SIR),m)
+  M_OBJS += irport.o
+  endif
+endif
+
 ifeq ($(CONFIG_NSC_FIR),y)
 L_OBJS += pc87108.o
 else
@@ -60,6 +76,30 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_TOSHIBA_FIR),y)
+L_OBJS += toshoboe.o
+else
+  ifeq ($(CONFIG_TOSHIBA_FIR),m)
+  M_OBJS += toshoboe.o
+  endif
+endif
+
+ifeq ($(CONFIG_TOSHIBA_FIR),y)
+L_OBJS += toshoboe.o
+else
+  ifeq ($(CONFIG_TOSHIBA_FIR),m)
+  M_OBJS += toshoboe.o
+  endif
+endif
+
+ifeq ($(CONFIG_SMC_IRCC_FIR),y)
+L_OBJS += irport.o smc-ircc.o
+else
+  ifeq ($(CONFIG_SMC_IRCC_FIR),m)
+  M_OBJS += irport.o smc-ircc.o
+  endif
+endif
+
 ifeq ($(CONFIG_ESI_DONGLE),y)
 L_OBJS += esi.o
 else
@@ -100,6 +140,22 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_LITELINK_DONGLE),y)
+L_OBJS += litelink.o
+else
+  ifeq ($(CONFIG_LITELINK_DONGLE),m)
+  M_OBJS += litelink.o
+  endif
+endif
+
+ifeq ($(CONFIG_LITELINK_DONGLE),y)
+L_OBJS += litelink.o
+else
+  ifeq ($(CONFIG_LITELINK_DONGLE),m)
+  M_OBJS += litelink.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 clean:
index 11fde80062e4f08392671622696d31a33fbccc48..8e86770a1153c81ef594790f7397a3cfdd94e4cb 100644 (file)
@@ -7,7 +7,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Mon May 10 15:12:54 1999
+ * Modified at:   Sun May 16 14:35:11 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
 #include <linux/sched.h>
 #include <linux/init.h>
 
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irda_device.h>
 #include <net/irda/dongle.h>
 
-static void actisys_reset(struct irda_device *dev, int unused);
+static void actisys_reset(struct irda_device *dev);
 static void actisys_open(struct irda_device *idev, int type);
 static void actisys_close(struct irda_device *dev);
 static void actisys_change_speed( struct irda_device *dev, int baudrate);
-static void actisys_reset(struct irda_device *dev, int unused);
 static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos);
 
 /* These are the baudrates supported */
@@ -169,7 +164,7 @@ static void actisys_change_speed(struct irda_device *idev, int baudrate)
  *     1. Clear DTR for a few ms.
  *
  */
-static void actisys_reset(struct irda_device *idev, int unused)
+static void actisys_reset(struct irda_device *idev)
 {
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
index b12885846bc74870a99673eabeaae4148005721b..b1f47b77540318109e1b3f7d14902316338152d4 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Thomas Davis, <ratbert@radiks.net>
  * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Mon May 10 15:13:12 1999
+ * Modified at:   Sun May 16 14:35:21 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:      esi.c
  *
 #include <linux/sched.h>
 #include <linux/init.h>
 
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irda_device.h>
@@ -44,7 +40,7 @@
 static void esi_open(struct irda_device *idev, int type);
 static void esi_close(struct irda_device *driver);
 static void esi_change_speed(struct irda_device *idev, int baud);
-static void esi_reset(struct irda_device *idev, int unused);
+static void esi_reset(struct irda_device *idev);
 static void esi_qos_init(struct irda_device *idev, struct qos_info *qos);
 
 static struct dongle dongle = {
@@ -116,7 +112,7 @@ static void esi_change_speed(struct irda_device *idev, int baud)
        irda_device_set_dtr_rts(idev, dtr, rts);
 }
 
-static void esi_reset( struct irda_device *idev, int unused)
+static void esi_reset( struct irda_device *idev)
 {
        /* Empty */
 }
index 3b06f3838ad7dd925ca47aa42cda21e21d6700c7..938315bc5f3ee6e3469fc5f9dc3a40aa3426de6c 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Feb  6 21:02:33 1999
- * Modified at:   Mon May 10 16:01:33 1999
+ * Modified at:   Tue Jun  1 08:47:41 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
 #include <linux/sched.h>
 #include <linux/init.h>
 
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irda_device.h>
 #include <net/irda/irtty.h>
 #include <net/irda/dongle.h>
 
-static void girbil_reset(struct irda_device *dev, int unused);
+static void girbil_reset(struct irda_device *dev);
 static void girbil_open(struct irda_device *dev, int type);
 static void girbil_close(struct irda_device *dev);
 static void girbil_change_speed(struct irda_device *dev, int baud);
@@ -165,7 +161,7 @@ static void girbil_change_speed(struct irda_device *idev, int speed)
  *       0. set RTS, and wait at least 5 ms 
  *        1. clear RTS 
  */
-void girbil_reset(struct irda_device *idev, int unused)
+void girbil_reset(struct irda_device *idev)
 {
        __u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
 
@@ -177,22 +173,26 @@ void girbil_reset(struct irda_device *idev, int unused)
 
        /* Sleep at least 5 ms */
        current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(2);
+       schedule_timeout(MSECS_TO_JIFFIES(20));
        
        /* Set DTR and clear RTS to enter command mode */
        irda_device_set_dtr_rts(idev, FALSE, TRUE);
 
        current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(2);
+       schedule_timeout(MSECS_TO_JIFFIES(20));
 
        /* Write control byte */
        irda_device_raw_write(idev, &control, 1);
 
        current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(2);
+       schedule_timeout(MSECS_TO_JIFFIES(20));
 
        /* Go back to normal mode */
        irda_device_set_dtr_rts(idev, TRUE, TRUE);
+
+               /* Make sure the IrDA chip also goes to defalt speed */
+       if (idev->change_speed)
+               idev->change_speed(idev, 9600);
 }
 
 /*
@@ -204,7 +204,7 @@ void girbil_reset(struct irda_device *idev, int unused)
 static void girbil_init_qos(struct irda_device *idev, struct qos_info *qos)
 {
        qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-       qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */
+       qos->min_turn_time.bits &= 0x03;
 }
 
 #ifdef MODULE
index 7c8864f5d79ef04cfb9d2525445b5e4545ca6bb3..5fb0cd4f28d22025cb0f2466cc30faf7726602bd 100644 (file)
@@ -1,43 +1,38 @@
 /*********************************************************************
- *               
+ * 
  * Filename:     irport.c
- * Version:      0.9
- * Description:   Serial driver for IrDA. 
+ * Version:      1.0
+ * Description:   Half duplex serial port SIR driver for IrDA. 
  * Status:       Experimental.
  * Author:       Dag Brattli <dagb@cs.uit.no>
  * Created at:   Sun Aug  3 13:49:59 1997
- * Modified at:   Sat May 23 23:15:20 1998
+ * Modified at:   Tue Jun  1 10:02:42 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:      serial.c by Linus Torvalds 
  * 
- *     Copyright (c) 1997,1998 Dag Brattli <dagb@cs.uit.no>
- *     All Rights Reserved.
+ *     Copyright (c) 1997, 1998, 1999 Dag Brattli, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
- *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *
- *     NOTICE:
+ * 
+ *     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., 59 Temple Place, Suite 330, Boston, 
+ *     MA 02111-1307 USA
  *
  *     This driver is ment to be a small half duplex serial driver to be
- *     used for IR-chipsets that has a UART (16550) compatibility mode. If
- *     your chipset is is UART only, you should probably use IrTTY instead
- *     since the Linux serial driver is probably more robust and optimized.
- *
- *     The functions in this file may be used by FIR drivers, but this
- *     driver knows nothing about FIR drivers so don't ever insert such
- *     code into this file. Instead you should code your FIR driver in a
- *     separate file, and then call the functions in this file if
- *     necessary. This is becase it is difficult to use the Linux serial
- *     driver with a FIR driver becase they must share interrupts etc. Most
- *     FIR chipsets can function in advanced SIR mode, and you should
- *     probably use that mode instead of the UART compatibility mode (and
- *     then just forget about this file)
+ *     used for IR-chipsets that has a UART (16550) compatibility mode. 
+ *     Eventually it will replace irtty, because of irtty has some 
+ *     problems that is hard to get around when we don't have control
+ *     over the serial driver. This driver may also be used by FIR 
+ *     drivers to handle SIR mode for them.
  *
  ********************************************************************/
 
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
+#include <linux/skbuff.h>
+#include <linux/serial_reg.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 
-#include <linux/skbuff.h>
-#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/spinlock.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
@@ -86,7 +82,6 @@ static void irport_receive(struct irda_device *idev);
 static int  irport_net_init(struct device *dev);
 static int  irport_net_open(struct device *dev);
 static int  irport_net_close(struct device *dev);
-static void irport_wait_until_sent(struct irda_device *idev);
 static int  irport_is_receiving(struct irda_device *idev);
 static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts);
 static int  irport_raw_write(struct irda_device *idev, __u8 *buf, int len);
@@ -158,12 +153,15 @@ static int irport_open(int i, unsigned int iobase, unsigned int irq)
         idev->io.io_ext    = IO_EXTENT;
         idev->io.fifo_size = 16;
 
+       idev->netdev.base_addr = iobase;
+       idev->netdev.irq = irq;
+
        /* Lock the port that we need */
        ret = check_region(idev->io.iobase2, idev->io.io_ext);
        if (ret < 0) { 
-               DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-                      idev->io.iobase2);
-               /* w83977af_cleanup( self->idev);  */
+               DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+                     idev->io.iobase2);
+               /* irport_cleanup(self->idev);  */
                return -ENODEV;
        }
        request_region(idev->io.iobase2, idev->io.io_ext, idev->name);
@@ -207,12 +205,10 @@ static int irport_open(int i, unsigned int iobase, unsigned int irq)
 
 static int irport_close(struct irda_device *idev)
 {
-       DEBUG(0, __FUNCTION__ "()\n");
-
        ASSERT(idev != NULL, return -1;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
 
-       /* Release the PORT that this driver is using */
+       /* Release the IO-port that this driver is using */
        DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
              idev->io.iobase2);
        release_region(idev->io.iobase2, idev->io.io_ext);
@@ -224,24 +220,37 @@ static int irport_close(struct irda_device *idev)
        return 0;
 }
 
-void irport_start(int iobase)
+void irport_start(struct irda_device *idev, int iobase)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&idev->lock, flags);
+
+       irport_stop(idev, iobase);
+
        /* Initialize UART */
        outb(UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
        outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
        
        /* Turn on interrups */
-       outb((UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER);
+       outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
 
+       spin_unlock_irqrestore(&idev->lock, flags);
 }
 
-void irport_stop(int iobase)
+void irport_stop(struct irda_device *idev, int iobase)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&idev->lock, flags);
+
        /* Reset UART */
        outb(0, iobase+UART_MCR);
        
        /* Turn off interrupts */
        outb(0, iobase+UART_IER);
+
+       spin_unlock_irqrestore(&idev->lock, flags);
 }
 
 /*
@@ -254,24 +263,24 @@ int irport_probe(int iobase)
 {
        DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
 
-
        return 0;
 }
 
 /*
  * Function irport_change_speed (idev, speed)
  *
- *    Set speed of port to specified baudrate
+ *    Set speed of IrDA port to specified baudrate
  *
  */
 void irport_change_speed(struct irda_device *idev, int speed)
 {
+       unsigned long flags;
        int iobase; 
        int fcr;    /* FIFO control reg */
        int lcr;    /* Line control reg */
        int divisor;
 
-       DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
+       DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
 
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
@@ -281,12 +290,24 @@ void irport_change_speed(struct irda_device *idev, int speed)
        /* Update accounting for new speed */
        idev->io.baudrate = speed;
 
+       spin_lock_irqsave(&idev->lock, flags);
+
        /* Turn off interrupts */
        outb(0, iobase+UART_IER); 
 
        divisor = SPEED_MAX/speed;
        
-       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+       fcr = UART_FCR_ENABLE_FIFO;
+
+       /* 
+        * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
+        * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
+        * about this timeout since it will always be fast enough. 
+        */
+       if (idev->io.baudrate < 38400)
+               fcr |= UART_FCR_TRIGGER_1;
+       else 
+               fcr |= UART_FCR_TRIGGER_14;
         
        /* IrDA ports use 8N1 */
        lcr = UART_LCR_WLEN8;
@@ -297,8 +318,10 @@ void irport_change_speed(struct irda_device *idev, int speed)
        outb(lcr,                 iobase+UART_LCR); /* Set 8N1  */
        outb(fcr,                 iobase+UART_FCR); /* Enable FIFO's */
 
-       /* Turn on receive interrups */
-       outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); 
+       /* Turn on interrups */
+       outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
+
+       spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*
@@ -312,10 +335,13 @@ static void irport_write_wakeup(struct irda_device *idev)
 {
        int actual = 0;
        int iobase;
+       int fcr;
 
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 
+       DEBUG(4, __FUNCTION__ "()\n");
+
        /* Finished with frame?  */
        if (idev->tx_buff.len > 0)  {
                /* Write data left in transmit buffer */
@@ -335,9 +361,18 @@ static void irport_write_wakeup(struct irda_device *idev)
                /* Schedule network layer, so we can get some more frames */
                mark_bh(NET_BH);
 
-               outb(UART_FCR_ENABLE_FIFO | 
-                    UART_FCR_TRIGGER_14  |
-                    UART_FCR_CLEAR_RCVR, iobase+UART_FCR); /* Enable FIFO's */
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
+
+               if (idev->io.baudrate < 38400)
+                       fcr |= UART_FCR_TRIGGER_1;
+               else 
+                       fcr |= UART_FCR_TRIGGER_14;
+
+               /* 
+                * Reset Rx FIFO to make sure that all reflected transmit data
+                * will be discarded
+                */
+               outb(fcr, iobase+UART_FCR);
 
                /* Turn on receive interrupts */
                outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); 
@@ -347,7 +382,7 @@ static void irport_write_wakeup(struct irda_device *idev)
 /*
  * Function irport_write (driver)
  *
- *    
+ *    Fill Tx FIFO with transmit data
  *
  */
 static int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
@@ -356,21 +391,18 @@ static int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
 
        /* Tx FIFO should be empty! */
        if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-               DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+               DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
                return -1;
        }
         
        /* Fill FIFO with current frame */
-       while (( fifo_size-- > 0) && (actual < len)) {
+       while ((fifo_size-- > 0) && (actual < len)) {
                /* Transmit next byte */
-               outb( buf[actual], iobase+UART_TX);
+               outb(buf[actual], iobase+UART_TX);
 
                actual++;
        }
         
-       DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-             fifo_size, actual, len);
-
        return actual;
 }
 
@@ -384,11 +416,10 @@ static int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
 int irport_hard_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct irda_device *idev;
+       unsigned long flags;
        int actual = 0;
        int iobase;
 
-       DEBUG(5, __FUNCTION__ "(), dev=%p\n", dev);
-
        ASSERT(dev != NULL, return 0;);
        
        idev = (struct irda_device *) dev->priv;
@@ -399,8 +430,19 @@ int irport_hard_xmit(struct sk_buff *skb, struct device *dev)
        iobase = idev->io.iobase2;
 
        /* Lock transmit buffer */
-       if (irda_lock((void *) &dev->tbusy) == FALSE)
-               return -EBUSY;
+       if (irda_lock((void *) &dev->tbusy) == FALSE) {
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 5)
+                       return -EBUSY;
+
+               WARNING("%s: transmit timed out\n", dev->name);
+               irport_start(idev, iobase);
+               irport_change_speed(idev, idev->io.baudrate);
+
+               dev->trans_start = jiffies;
+       }
+
+       spin_lock_irqsave(&idev->lock, flags);
        
        /* Init tx buffer */
        idev->tx_buff.data = idev->tx_buff.head;
@@ -415,6 +457,8 @@ int irport_hard_xmit(struct sk_buff *skb, struct device *dev)
        /* Turn on transmit finished interrupt. Will fire immediately!  */
        outb(UART_IER_THRI, iobase+UART_IER); 
 
+       spin_unlock_irqrestore(&idev->lock, flags);
+
        dev_kfree_skb(skb);
        
        return 0;
@@ -431,10 +475,7 @@ static void irport_receive(struct irda_device *idev)
        int iobase;
        int boguscount = 0;
 
-       if (!idev)
-               return;
-
-       DEBUG(4, __FUNCTION__ "()\n");
+       ASSERT(idev != NULL, return;);
 
        iobase = idev->io.iobase2;
 
@@ -466,27 +507,42 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        int boguscount = 0;
 
        if (!idev) {
-               printk(KERN_WARNING __FUNCTION__ 
-                      "() irq %d for unknown device.\n", irq);
+               WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq);
                return;
        }
 
+       spin_lock(&idev->lock);
+
        idev->netdev.interrupt = 1;
 
        iobase = idev->io.iobase2;
 
-       iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+       iir = inb(iobase+UART_IIR) & UART_IIR_ID;
        while (iir) {
                /* Clear interrupt */
                lsr = inb(iobase+UART_LSR);
 
-               if ((iir & UART_IIR_THRI) && (lsr & UART_LSR_THRE)) {
-                       /* Transmitter ready for data */
-                       irport_write_wakeup(idev);
-               } else if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) {
-                       /* Receive interrupt */
-                       irport_receive(idev);
-               }
+               DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+                     iir, lsr, iobase);
+
+               switch (iir) {
+               case UART_IIR_RLSI:
+                       DEBUG(0, __FUNCTION__ "(), RLSI\n");
+                       break;
+               case UART_IIR_RDI:
+                       if (lsr & UART_LSR_DR)
+                               /* Receive interrupt */
+                               irport_receive(idev);
+                       break;
+               case UART_IIR_THRI:
+                       if (lsr & UART_LSR_THRE)
+                               /* Transmitter ready for data */
+                               irport_write_wakeup(idev);
+                       break;
+               default:
+                       DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+                       break;
+               } 
                
                /* Make sure we don't stay here to long */
                if (boguscount++ > 32)
@@ -495,6 +551,8 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                iir = inb(iobase + UART_IIR) & UART_IIR_ID;
        }
        idev->netdev.interrupt = 0;
+
+       spin_unlock(&idev->lock);
 }
 
 static int irport_net_init(struct device *dev)
@@ -524,18 +582,21 @@ static int irport_net_open(struct device *dev)
        iobase = idev->io.iobase2;
 
        if (request_irq(idev->io.irq2, irport_interrupt, 0, idev->name, 
-                       (void *) idev)) {
+                       (void *) idev))
                return -EAGAIN;
-       }
+
+       irport_start(idev, iobase);
+
+       MOD_INC_USE_COUNT;
 
        /* Ready to play! */
        dev->tbusy = 0;
        dev->interrupt = 0;
        dev->start = 1;
 
-       MOD_INC_USE_COUNT;
-
-       irport_start(iobase);
+       /* Change speed to make sure dongles follow us again */
+       if (idev->change_speed)
+               idev->change_speed(idev, 9600);
 
        return 0;
 }
@@ -558,12 +619,12 @@ static int irport_net_close(struct device *dev)
 
        iobase = idev->io.iobase2;
 
-       irport_stop(iobase);
-
        /* Stop device */
        dev->tbusy = 1;
        dev->start = 0;
 
+       irport_stop(idev, iobase);
+
        free_irq(idev->io.irq2, idev);
 
        MOD_DEC_USE_COUNT;
@@ -571,12 +632,32 @@ static int irport_net_close(struct device *dev)
        return 0;
 }
 
-static void irport_wait_until_sent(struct irda_device *idev)
+/*
+ * Function irport_wait_until_sent (idev)
+ *
+ *    Delay exectution until finished transmitting
+ *
+ */
+void irport_wait_until_sent(struct irda_device *idev)
 {
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(60*HZ/1000);
+       int iobase;
+
+       iobase = idev->io.iobase2;
+
+       /* Wait until Tx FIFO is empty */
+       while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+               DEBUG(2, __FUNCTION__ "(), waiting!\n");
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(MSECS_TO_JIFFIES(60));
+       }
 }
 
+/*
+ * Function irport_is_receiving (idev)
+ *
+ *    Returns true is we are currently receiving data
+ *
+ */
 static int irport_is_receiving(struct irda_device *idev)
 {
        return (idev->rx_buff.state != OUTSIDE_FRAME);
@@ -636,6 +717,9 @@ static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len)
 MODULE_PARM(io, "1-4i");
 MODULE_PARM(irq, "1-4i");
 
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode");
+
 /*
  * Function cleanup_module (void)
  *
index e27bab10c3f7182949ddf5cffaea2fbc814c608b..84df367da08ab1c1054d37deebe11afcf684b34c 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri May  7 12:50:33 1999
- * Modified at:   Mon May 10 15:12:18 1999
+ * Modified at:   Wed May 19 07:25:15 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
 #include <linux/tty.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <asm/ioctls.h>
-#include <asm/uaccess.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irda_device.h>
 #include <net/irda/dongle.h>
 
-static void litelink_reset(struct irda_device *dev, int unused);
+#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
+#define MAX_DELAY 10000   /* 1 ms */
+
 static void litelink_open(struct irda_device *idev, int type);
 static void litelink_close(struct irda_device *dev);
-static void litelink_change_speed( struct irda_device *dev, int baudrate);
-static void litelink_reset(struct irda_device *dev, int unused);
+static void litelink_change_speed(struct irda_device *dev, int baudrate);
+static void litelink_reset(struct irda_device *dev);
 static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos);
 
 /* These are the baudrates supported */
@@ -105,13 +105,13 @@ static void litelink_change_speed(struct irda_device *idev, int baudrate)
        irda_device_set_dtr_rts(idev, TRUE, FALSE);
 
        /* Sleep a minimum of 15 us */
-       udelay(15);
+       udelay(MIN_DELAY);
 
        /* Go back to normal mode */
        irda_device_set_dtr_rts(idev, TRUE, TRUE);
        
        /* Sleep a minimum of 15 us */
-       udelay(15);
+       udelay(MIN_DELAY);
        
        /* Cycle through avaiable baudrates until we reach the correct one */
        for (i=0; i<5 && baud_rates[i] != baudrate; i++) {
@@ -120,13 +120,13 @@ static void litelink_change_speed(struct irda_device *idev, int baudrate)
                irda_device_set_dtr_rts(idev, FALSE, TRUE);
                
                /* Sleep a minimum of 15 us */
-               udelay(15);
+               udelay(MIN_DELAY);
                
                /* Set DTR, Set RTS */
                irda_device_set_dtr_rts(idev, TRUE, TRUE);
                
                /* Sleep a minimum of 15 us */
-               udelay(15);
+               udelay(MIN_DELAY);
         }
 }
 
@@ -137,11 +137,8 @@ static void litelink_change_speed(struct irda_device *idev, int baudrate)
  *      called with a process context!
  *
  */
-static void litelink_reset(struct irda_device *idev, int unused)
+static void litelink_reset(struct irda_device *idev)
 {
-       struct irtty_cb *self;
-        struct tty_struct *tty;
-
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
@@ -149,19 +146,19 @@ static void litelink_reset(struct irda_device *idev, int unused)
        irda_device_set_dtr_rts(idev, TRUE, TRUE);
 
        /* Sleep a minimum of 15 us */
-       udelay(15);
+       udelay(MIN_DELAY);
 
        /* Clear RTS to reset dongle */
        irda_device_set_dtr_rts(idev, TRUE, FALSE);
 
        /* Sleep a minimum of 15 us */
-       udelay(15);
+       udelay(MIN_DELAY);
 
        /* Go back to normal mode */
        irda_device_set_dtr_rts(idev, TRUE, TRUE);
        
        /* Sleep a minimum of 15 us */
-       udelay(15);
+       udelay(MIN_DELAY);
 
        /* This dongles speed defaults to 115200 bps */
        idev->qos.baud_rate.value = 115200;
@@ -173,7 +170,7 @@ static void litelink_reset(struct irda_device *idev, int unused)
  *    Initialize QoS capabilities
  *
  */
-static void litelink_init_qos( struct irda_device *idev, struct qos_info *qos)
+static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos)
 {
        qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
        qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */
index 340f836e7b9c402e0b36d07b9ac69c92a00eaba3..9433ec6b5db60f2038bbe022f7723caed95dc797 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Sun May  9 12:57:46 1999
+ * Modified at:   Mon May 24 15:19:21 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
@@ -72,7 +72,7 @@ static int qos_mtt_bits = 0x07;  /* 1 ms or more */
 #define CHIP_IO_EXTENT 8
 
 static unsigned int io[]  = { 0x2f8, ~0, ~0, ~0 };
-static unsigned int io2[] = { 0x150, 0, 0, 0};
+static unsigned int io2[] = { 0x150, 0, 0, 0 };
 static unsigned int irq[] = { 3, 0, 0, 0 };
 static unsigned int dma[] = { 0, 0, 0, 0 };
 
@@ -98,28 +98,28 @@ static char *dongle_types[] = {
 };
 
 /* Some prototypes */
-static int  pc87108_open( int i, unsigned int iobase, unsigned int board_addr, 
-                         unsigned int irq, unsigned int dma);
+static int  pc87108_open(int i, unsigned int iobase, unsigned int board_addr, 
+                        unsigned int irq, unsigned int dma);
 #ifdef MODULE
-static int  pc87108_close( struct irda_device *idev);
+static int  pc87108_close(struct irda_device *idev);
 #endif /* MODULE */
-static int  pc87108_probe( int iobase, int board_addr, int irq, int dma);
-static void pc87108_pio_receive( struct irda_device *idev);
-static int  pc87108_dma_receive( struct irda_device *idev); 
+static int  pc87108_probe(int iobase, int board_addr, int irq, int dma);
+static void pc87108_pio_receive(struct irda_device *idev);
+static int  pc87108_dma_receive(struct irda_device *idev); 
 static int  pc87108_dma_receive_complete(struct irda_device *idev, int iobase);
-static int  pc87108_hard_xmit( struct sk_buff *skb, struct device *dev);
-static int  pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size);
-static void pc87108_dma_write( struct irda_device *idev, int iobase);
-static void pc87108_change_speed( struct irda_device *idev, int baud);
+static int  pc87108_hard_xmit(struct sk_buff *skb, struct device *dev);
+static int  pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void pc87108_dma_write(struct irda_device *idev, int iobase);
+static void pc87108_change_speed(struct irda_device *idev, int baud);
 static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void pc87108_wait_until_sent( struct irda_device *idev);
-static int  pc87108_is_receiving( struct irda_device *idev);
-static int  pc87108_read_dongle_id ( int iobase);
-static void pc87108_init_dongle_interface ( int iobase, int dongle_id);
+static void pc87108_wait_until_sent(struct irda_device *idev);
+static int  pc87108_is_receiving(struct irda_device *idev);
+static int  pc87108_read_dongle_id (int iobase);
+static void pc87108_init_dongle_interface (int iobase, int dongle_id);
 
-static int  pc87108_net_init( struct device *dev);
-static int  pc87108_net_open( struct device *dev);
-static int  pc87108_net_close( struct device *dev);
+static int  pc87108_net_init(struct device *dev);
+static int  pc87108_net_open(struct device *dev);
+static int  pc87108_net_close(struct device *dev);
 
 /*
  * Function pc87108_init ()
@@ -131,11 +131,11 @@ __initfunc(int pc87108_init(void))
 {
        int i;
 
-       for ( i=0; (io[i] < 2000) && (i < 4); i++) {
+       for (i=0; (io[i] < 2000) && (i < 4); i++) {
                int ioaddr = io[i];
                if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
                        continue;
-               if (pc87108_open( i, io[i], io2[i], irq[i], dma[i]) == 0)
+               if (pc87108_open(i, io[i], io2[i], irq[i], dma[i]) == 0)
                        return 0;
        }
        return -ENODEV;
@@ -167,29 +167,29 @@ static void pc87108_cleanup(void)
  *    Open driver instance
  *
  */
-static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr, 
-                        unsigned int irq, unsigned int dma)
+static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr, 
+                       unsigned int irq, unsigned int dma)
 {
        struct pc87108 *self;
        struct irda_device *idev;
        int ret;
        int dongle_id;
 
-       DEBUG( 0, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
 
-       if (( dongle_id = pc87108_probe( iobase, board_addr, irq, dma)) == -1)
+       if ((dongle_id = pc87108_probe(iobase, board_addr, irq, dma)) == -1)
                return -1;
 
        /*
         *  Allocate new instance of the driver
         */
-       self = kmalloc( sizeof(struct pc87108), GFP_KERNEL);
-       if ( self == NULL) {
-               printk( KERN_ERR "IrDA: Can't allocate memory for "
-                       "IrDA control block!\n");
+       self = kmalloc(sizeof(struct pc87108), GFP_KERNEL);
+       if (self == NULL) {
+               printk(KERN_ERR "IrDA: Can't allocate memory for "
+                      "IrDA control block!\n");
                return -ENOMEM;
        }
-       memset( self, 0, sizeof(struct pc87108));
+       memset(self, 0, sizeof(struct pc87108));
    
        /* Need to store self somewhere */
        dev_self[i] = self;
@@ -204,24 +204,24 @@ static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr,
         idev->io.fifo_size = 32;
 
        /* Lock the port that we need */
-       ret = check_region( idev->io.iobase, idev->io.io_ext);
-       if ( ret < 0) { 
-               DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-                      idev->io.iobase);
+       ret = check_region(idev->io.iobase, idev->io.io_ext);
+       if (ret < 0) { 
+               DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+                     idev->io.iobase);
                /* pc87108_cleanup( self->idev);  */
                return -ENODEV;
        }
-       request_region( idev->io.iobase, idev->io.io_ext, idev->name);
+       request_region(idev->io.iobase, idev->io.io_ext, idev->name);
 
        /* Initialize QoS for this device */
-       irda_init_max_qos_capabilies( &idev->qos);
+       irda_init_max_qos_capabilies(&idev->qos);
        
        /* The only value we must override it the baudrate */
        idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
                IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
        
        idev->qos.min_turn_time.bits = qos_mtt_bits;
-       irda_qos_bits_to_value( &idev->qos);
+       irda_qos_bits_to_value(&idev->qos);
        
        idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
 
@@ -245,10 +245,10 @@ static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr,
        idev->netdev.stop            = pc87108_net_close;
 
        idev->io.dongle_id = dongle_id;
-       pc87108_init_dongle_interface( iobase, dongle_id);
+       pc87108_init_dongle_interface(iobase, dongle_id);
 
        /* Open the IrDA device */
-       irda_device_open( idev, driver_name, self);
+       irda_device_open(idev, driver_name, self);
        
        return 0;
 }
@@ -267,15 +267,14 @@ static int pc87108_close(struct irda_device *idev)
 
        DEBUG( 4, __FUNCTION__ "()\n");
 
-       ASSERT( idev != NULL, return -1;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+       ASSERT(idev != NULL, return -1;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
 
         iobase = idev->io.iobase;
        self = (struct pc87108 *) idev->priv;
 
        /* Release the PORT that this driver is using */
-       DEBUG( 4, __FUNCTION__ "(), Releasing Region %03x\n", 
-              idev->io.iobase);
+       DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase);
        release_region(idev->io.iobase, idev->io.io_ext);
 
        irda_device_close(idev);
@@ -292,22 +291,22 @@ static int pc87108_close(struct irda_device *idev)
  *    Returns non-negative on success.
  *
  */
-static int pc87108_probe( int iobase, int board_addr, int irq, int dma) 
+static int pc87108_probe(int iobase, int board_addr, int irq, int dma) 
 {
        int version;
        __u8 temp=0;
        int dongle_id;
        
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
        /* Base Address and Interrupt Control Register BAIC */
        outb(0, board_addr);
-       switch ( iobase) {
-       case 0x3E8: outb( 0x14, board_addr+1); break;
-       case 0x2E8: outb( 0x15, board_addr+1); break;
-       case 0x3F8: outb( 0x16, board_addr+1); break;
-       case 0x2F8: outb( 0x17, board_addr+1); break;
-       default:    DEBUG(0, __FUNCTION__ "(), invalid base_address");
+       switch (iobase) {
+       case 0x3E8: outb(0x14, board_addr+1); break;
+       case 0x2E8: outb(0x15, board_addr+1); break;
+       case 0x3F8: outb(0x16, board_addr+1); break;
+       case 0x2F8: outb(0x17, board_addr+1); break;
+       default:    ERROR(__FUNCTION__ "(), invalid base_address");
        }
        
        /* Control Signal Routing Register CSRT */
@@ -319,74 +318,73 @@ static int pc87108_probe( int iobase, int board_addr, int irq, int dma)
        case 9:  temp = 0x05; break;
        case 11: temp = 0x06; break;
        case 15: temp = 0x07; break;
-       default: DEBUG( 0, __FUNCTION__ "(), invalid irq");
+       default: ERROR(__FUNCTION__ "(), invalid irq");
        }
-       outb( 1, board_addr);
-
+       outb(1, board_addr);
+       
        switch (dma) {  
-       case 0: outb( 0x08+temp, board_addr+1); break;
-       case 1: outb( 0x10+temp, board_addr+1); break;
-       case 3: outb( 0x18+temp, board_addr+1); break;
+       case 0: outb(0x08+temp, board_addr+1); break;
+       case 1: outb(0x10+temp, board_addr+1); break;
+       case 3: outb(0x18+temp, board_addr+1); break;
        default: DEBUG( 0, __FUNCTION__ "(), invalid dma");
        }
 
        /* Mode Control Register MCTL */
-       outb( 2, board_addr);
-       outb( 0x03, board_addr+1);
+       outb(2, board_addr);
+       outb(0x03, board_addr+1);
                
        /* read the Module ID */
-       switch_bank( iobase, BANK3);
-       version =  inb( iobase+MID);
+       switch_bank(iobase, BANK3);
+       version = inb(iobase+MID);
        
        /* should be 0x2? */
-       if (0x20 != (version & 0xf0))
-       {
-               DEBUG( 0, __FUNCTION__ "(), Wrong chip version");       
+       if (0x20 != (version & 0xf0)) {
+               ERROR(__FUNCTION__ "(), Wrong chip version %02x\n", version);
                return -1;
        }
        
        /* Switch to advanced mode */
        switch_bank( iobase, BANK2);
-       outb( ECR1_EXT_SL, iobase+ECR1);
-       switch_bank( iobase, BANK0);
+       outb(ECR1_EXT_SL, iobase+ECR1);
+       switch_bank(iobase, BANK0);
 
-       dongle_id = pc87108_read_dongle_id( iobase);
-       DEBUG( 0, __FUNCTION__ "(), Found dongle: %s\n", 
-              dongle_types[ dongle_id]);
+       dongle_id = pc87108_read_dongle_id(iobase);
+       DEBUG(0, __FUNCTION__ "(), Found dongle: %s\n", 
+             dongle_types[ dongle_id]);
        
        /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
-       switch_bank( iobase, BANK0);    
-       outb( FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
+       switch_bank(iobase, BANK0);     
+       outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
        
        /* Set FIFO size to 32 */
-       switch_bank( iobase, BANK2);
-       outb( EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);   
+       switch_bank(iobase, BANK2);
+       outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);    
 
        /* IRCR2: FEND_MD is set */
-       switch_bank( iobase, BANK5);
-       outb( 0x2a, iobase+4);
+       switch_bank(iobase, BANK5);
+       outb(0x2a, iobase+4);
 
        /* Make sure that some defaults are OK */
-       switch_bank( iobase, BANK6);
-       outb( 0x20, iobase+0); /* Set 32 bits FIR CRC */
-       outb( 0x0a, iobase+1); /* Set MIR pulse width */
-       outb( 0x0d, iobase+2); /* Set SIR pulse width */
-       outb( 0x2a, iobase+4); /* Set beginning frag, and preamble length */
+       switch_bank(iobase, BANK6);
+       outb(0x20, iobase+0); /* Set 32 bits FIR CRC */
+       outb(0x0a, iobase+1); /* Set MIR pulse width */
+       outb(0x0d, iobase+2); /* Set SIR pulse width */
+       outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
 
        /* Receiver frame length */
-       switch_bank( iobase, BANK4);
-       outb( 2048 & 0xff, iobase+6);
-       outb(( 2048 >> 8) & 0x1f, iobase+7);
+       switch_bank(iobase, BANK4);
+       outb(2048 & 0xff, iobase+6);
+       outb((2048 >> 8) & 0x1f, iobase+7);
 
        /* Transmitter frame length */
-       outb( 2048 & 0xff, iobase+4);
-       outb(( 2048 >> 8) & 0x1f, iobase+5);
+       outb(2048 & 0xff, iobase+4);
+       outb((2048 >> 8) & 0x1f, iobase+5);
        
-       DEBUG( 0, "PC87108 driver loaded. Version: 0x%02x\n", version);
+       DEBUG(0, "PC87108 driver loaded. Version: 0x%02x\n", version);
 
        /* Enable receive interrupts */
-       switch_bank( iobase, BANK0);
-       outb( IER_RXHDL_IE, iobase+IER);
+       switch_bank(iobase, BANK0);
+       outb(IER_RXHDL_IE, iobase+IER);
 
        return dongle_id;
 }
@@ -409,10 +407,10 @@ static int pc87108_read_dongle_id ( int iobase)
        bank = inb( iobase+BSR);
 
        /* Select Bank 7 */
-       switch_bank( iobase, BANK7);
+       switch_bank(iobase, BANK7);
        
        /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
-       outb( 0x00, iobase+7);
+       outb(0x00, iobase+7);
        
        /* ID0, 1, and 2 are pulled up/down very slowly */
        udelay(50);
@@ -421,16 +419,16 @@ static int pc87108_read_dongle_id ( int iobase)
        dongle_id = inb( iobase+4) & 0x0f;
 
 #ifdef BROKEN_DONGLE_ID
-       if ( dongle_id == 0x0a)
+       if (dongle_id == 0x0a)
                dongle_id = 0x09;
 #endif
-
+       
        /* Go back to  bank 0 before returning */
-       switch_bank( iobase, BANK0);
+       switch_bank(iobase, BANK0);
 
-       DEBUG( 0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id);
+       DEBUG(0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id);
 
-       outb( bank, iobase+BSR);
+       outb(bank, iobase+BSR);
 
        return dongle_id;
 }
@@ -443,7 +441,7 @@ static int pc87108_read_dongle_id ( int iobase)
  *     power-on/reset. It also needs to be used whenever you suspect that
  *     the dongle is changed. 
  */
-static void pc87108_init_dongle_interface ( int iobase, int dongle_id)
+static void pc87108_init_dongle_interface (int iobase, int dongle_id)
 {
        int bank;
 
@@ -818,11 +816,11 @@ static void pc87108_dma_write( struct irda_device *idev, int iobase)
              iobase+ECR1);
        
        /* Enable DMA */
-       switch_bank( iobase, BANK0);    
-       outb( inb( iobase+MCR)|MCR_DMA_EN, iobase+MCR);
+       switch_bank(iobase, BANK0);     
+       outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
 
        /* Restore bank register */
-       outb( bsr, iobase+BSR);
+       outb(bsr, iobase+BSR);
 }
 
 /*
@@ -832,7 +830,7 @@ static void pc87108_dma_write( struct irda_device *idev, int iobase)
  *    got transfered
  *
  */
-static int pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size)
+static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
 {
        int actual = 0;
        __u8 bank;
@@ -851,16 +849,16 @@ static int pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size)
        }
 
        /* Fill FIFO with current frame */
-       while (( fifo_size-- > 0) && (actual < len)) {
+       while ((fifo_size-- > 0) && (actual < len)) {
                /* Transmit next byte */
-               outb( buf[actual++], iobase+TXD);
+               outb(buf[actual++], iobase+TXD);
        }
         
-       DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-              fifo_size, actual, len);
+       DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
+             fifo_size, actual, len);
 
        /* Restore bank */
-       outb( bank, iobase+BSR);
+       outb(bank, iobase+BSR);
 
        return actual;
 }
@@ -1466,6 +1464,9 @@ MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("NSC PC87108 IrDA Device Driver");
 
 MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(io2, "1-4i");
+MODULE_PARM(irq, "1-4i");
 
 /*
  * Function init_module (void)
diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c
new file mode 100644 (file)
index 0000000..4daa5f7
--- /dev/null
@@ -0,0 +1,969 @@
+/*********************************************************************
+ *                
+ * Filename:      smc-ircc.c
+ * Version:       0.1
+ * Description:   Driver for the SMC Infrared Communications Controller (SMC)
+ * Status:        Experimental.
+ * Author:        Thomas Davis (tadavis@jps.net)
+ * Created at:    
+ * Modified at:   Wed May 19 15:30:08 1999
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1998-1999 Thomas Davis, All Rights Reserved.
+ *      
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *  
+ *     I, Thomas Davis, admit no liability nor provide warranty for any
+ *     of this software. This material is provided "AS-IS" and at no charge.
+ *
+ *     Applicable Models : Fujitsu Lifebook 635t
+ *                        Sony PCG-505TX (gets DMA wrong.)
+ *
+ ********************************************************************/
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#include <net/irda/wrapper.h>
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irlap_frame.h>
+#include <net/irda/irda_device.h>
+
+#include <net/irda/smc-ircc.h>
+#include <net/irda/irport.h>
+
+static char *driver_name = "smc-ircc";
+
+#define CHIP_IO_EXTENT 8
+
+static unsigned int io[]  = { 0x2e8, 0x140, ~0, ~0 };
+static unsigned int io2[] = { 0x2f8, 0x3e8, 0, 0};
+
+static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL};
+
+/* Some prototypes */
+static int  ircc_open( int i, unsigned int iobase, unsigned int board_addr);
+static int  ircc_close( struct irda_device *idev);
+static int  ircc_probe( int iobase, int board_addr);
+static int  ircc_dma_receive( struct irda_device *idev); 
+static int  ircc_dma_receive_complete(struct irda_device *idev, int iobase);
+static int  ircc_hard_xmit( struct sk_buff *skb, struct device *dev);
+static void ircc_dma_write( struct irda_device *idev, int iobase);
+static void ircc_change_speed( struct irda_device *idev, int baud);
+static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void ircc_wait_until_sent( struct irda_device *idev);
+static int  ircc_is_receiving( struct irda_device *idev);
+
+static int  ircc_net_init( struct device *dev);
+static int  ircc_net_open( struct device *dev);
+static int  ircc_net_close( struct device *dev);
+
+static int ircc_debug=3;
+static int ircc_irq=255;
+static int ircc_dma=255;
+
+static inline void register_bank(int port, int bank)
+{
+        outb(((inb(port+UART_MASTER) & 0xF0) | (bank & 0x07)),
+             port+UART_MASTER);
+}
+
+static inline unsigned int serial_in(int port, int offset)
+{
+        return inb(port+offset);
+}
+
+static inline void serial_out(int port, int offset, int value)
+{
+        outb(value, port+offset);
+}
+
+/*
+ * Function ircc_init ()
+ *
+ *    Initialize chip. Just try to find out how many chips we are dealing with
+ *    and where they are
+ */
+__initfunc(int ircc_init(void))
+{
+       int i;
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+       for ( i=0; (io[i] < 2000) && (i < 4); i++) {
+               int ioaddr = io[i];
+               if (check_region(ioaddr, CHIP_IO_EXTENT))
+                       continue;
+               if (ircc_open( i, io[i], io2[i]) == 0)
+                       return 0;
+       }
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+       return -ENODEV;
+}
+
+/*
+ * Function ircc_cleanup ()
+ *
+ *    Close all configured chips
+ *
+ */
+#ifdef MODULE
+static void ircc_cleanup(void)
+{
+       int i;
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       for ( i=0; i < 4; i++) {
+               if ( dev_self[i])
+                       ircc_close( &(dev_self[i]->idev));
+       }
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+#endif /* MODULE */
+
+/*
+ * Function ircc_open (iobase, irq)
+ *
+ *    Open driver instance
+ *
+ */
+static int ircc_open( int i, unsigned int iobase, unsigned int iobase2)
+{
+       struct ircc_cb *self;
+       struct irda_device *idev;
+       int ret;
+       int config;
+
+       DEBUG( ircc_debug, __FUNCTION__ " -->\n");
+
+       if ((config = ircc_probe( iobase, iobase2)) == -1) {
+               DEBUG(ircc_debug, 
+                     __FUNCTION__ ": addr 0x%04x - no device found!\n", iobase);
+               return -1;
+       }
+       
+       /*
+        *  Allocate new instance of the driver
+        */
+       self = kmalloc( sizeof(struct ircc_cb), GFP_KERNEL);
+       if ( self == NULL) {
+               printk( KERN_ERR "IrDA: Can't allocate memory for "
+                       "IrDA control block!\n");
+               return -ENOMEM;
+       }
+       memset(self, 0, sizeof(struct ircc_cb));
+   
+       /* Need to store self somewhere */
+       dev_self[i] = self;
+
+       idev = &self->idev;
+
+       /* Initialize IO */
+       idev->io.iobase    = iobase;
+        idev->io.iobase2   = iobase2; /* Used by irport */
+        idev->io.irq       = config >> 4 & 0x0f;
+       if (ircc_irq < 255) {
+               printk(KERN_INFO "smc: Overriding IRQ - chip says %d, using %d\n",
+                     idev->io.irq, ircc_irq);
+               idev->io.irq = ircc_irq;
+       }
+        idev->io.io_ext    = CHIP_IO_EXTENT;
+        idev->io.io_ext2   = 8;       /* Used by irport */
+        idev->io.dma       = config & 0x0f;
+       if (ircc_dma < 255) {
+               printk(KERN_INFO "smc: Overriding DMA - chip says %d, using %d\n",
+                     idev->io.dma, ircc_dma);
+               idev->io.dma = ircc_dma;
+       }
+        idev->io.fifo_size = 16;
+
+       /* Lock the port that we need */
+       ret = check_region( idev->io.iobase, idev->io.io_ext);
+       if ( ret < 0) { 
+               DEBUG( 0, __FUNCTION__ ": can't get iobase of 0x%03x\n",
+                      idev->io.iobase);
+               /* ircc_cleanup( self->idev);  */
+               return -ENODEV;
+       }
+       ret = check_region( idev->io.iobase2, idev->io.io_ext2);
+       if ( ret < 0) { 
+               DEBUG( 0, __FUNCTION__ ": can't get iobase of 0x%03x\n",
+                      idev->io.iobase2);
+               /* ircc_cleanup( self->idev);  */
+               return -ENODEV;
+       }
+       request_region( idev->io.iobase, idev->io.io_ext, idev->name);
+        request_region( idev->io.iobase2, idev->io.io_ext2, idev->name);
+
+       /* Initialize QoS for this device */
+       irda_init_max_qos_capabilies( &idev->qos);
+       
+#if 1
+       /* The only value we must override it the baudrate */
+       idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+               IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
+#else
+       /* The only value we must override it the baudrate */
+       idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+               IR_115200;
+#endif
+
+       idev->qos.min_turn_time.bits = 0x07;
+       irda_qos_bits_to_value( &idev->qos);
+
+       idev->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO;
+       
+       /* Specify which buffer allocation policy we need */
+       idev->rx_buff.flags = GFP_KERNEL | GFP_DMA;
+       idev->tx_buff.flags = GFP_KERNEL | GFP_DMA;
+
+       /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+       idev->rx_buff.truesize = 4000; 
+       idev->tx_buff.truesize = 4000;
+       
+       /* Initialize callbacks */
+       idev->change_speed    = ircc_change_speed;
+       idev->wait_until_sent = ircc_wait_until_sent;
+       idev->is_receiving    = ircc_is_receiving;
+     
+       /* Override the network functions we need to use */
+       idev->netdev.init            = ircc_net_init;
+       idev->netdev.hard_start_xmit = ircc_hard_xmit;
+       idev->netdev.open            = ircc_net_open;
+       idev->netdev.stop            = ircc_net_close;
+
+       irport_start(idev, iobase2);
+
+       /* Open the IrDA device */
+       irda_device_open( idev, driver_name, self);
+       
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+       return 0;
+}
+
+/*
+ * Function ircc_close (idev)
+ *
+ *    Close driver instance
+ *
+ */
+static int ircc_close( struct irda_device *idev)
+{
+       int iobase;
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       ASSERT( idev != NULL, return -1;);
+       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+        iobase = idev->io.iobase;
+
+       irport_stop(idev, idev->io.iobase2);
+
+       register_bank(iobase, 0);
+       serial_out(iobase, UART_IER, 0);
+       serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+
+       register_bank(iobase, 1);
+
+        serial_out(iobase, UART_SCE_CFGA, 
+                  UART_CFGA_IRDA_SIR_A | UART_CFGA_TX_POLARITY);
+        serial_out(iobase, UART_SCE_CFGB, UART_CFGB_IR);
+       /* Release the PORT that this driver is using */
+       DEBUG( ircc_debug, 
+              __FUNCTION__ ": releasing 0x%03x\n", idev->io.iobase);
+
+       release_region( idev->io.iobase, idev->io.io_ext);
+
+       if ( idev->io.iobase2) {
+               DEBUG( ircc_debug, __FUNCTION__ ": releasing 0x%03x\n", 
+                      idev->io.iobase2);
+               release_region( idev->io.iobase2, idev->io.io_ext2);
+       }
+
+       irda_device_close( idev);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+       return 0;
+}
+
+/*
+ * Function ircc_probe (iobase, board_addr, irq, dma)
+ *
+ *    Returns non-negative on success.
+ *
+ */
+static int ircc_probe( int iobase, int iobase2) 
+{
+       int version = 1;
+       int low, high, chip, config, dma, irq;
+       
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       register_bank(iobase, 3);
+       high = serial_in(iobase, UART_ID_HIGH);
+       low = serial_in(iobase, UART_ID_LOW);
+       chip = serial_in(iobase, UART_CHIP_ID);
+       version = serial_in(iobase, UART_VERSION);
+       config = serial_in(iobase, UART_INTERFACE);
+       irq = config >> 4 & 0x0f;
+       dma = config & 0x0f;
+
+       if (high == 0x10 && low == 0xb8 && chip == 0xf1) {
+               DEBUG(0, "SMC IrDA Controller found; version = %d, "
+                     "port 0x%04x, dma %d, interrupt %d\n",
+                     version, iobase, dma, irq);
+       } else {
+               return -1;
+       }
+
+       serial_out(iobase, UART_MASTER, 0);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+       return config;
+}
+
+/*
+ * Function ircc_change_speed (idev, baud)
+ *
+ *    Change the speed of the device
+ *
+ */
+static void ircc_change_speed( struct irda_device *idev, int speed)
+{
+       struct ircc_cb *self;
+       int iobase, ir_mode, select, fast; 
+
+       DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+       self = idev->priv;
+       iobase = idev->io.iobase;
+
+       /* Update accounting for new speed */
+       idev->io.baudrate = speed;
+
+       switch ( speed) {
+       case 9600:
+       case 19200:
+       case 37600:
+       case 57600:
+       case 115200:
+               DEBUG(ircc_debug+1, 
+                     __FUNCTION__ ": using irport to change speed to %d\n",
+                     speed);
+               register_bank(iobase, 0);
+               serial_out(iobase, UART_IER, 0);
+               serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+               serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+               irport_start(idev, idev->io.iobase2);
+               irport_change_speed( idev, speed);
+               return;
+               break;
+
+       case 576000:            
+               ir_mode = UART_CFGA_IRDA_HDLC;
+               select = 0;
+               fast = 0;
+               DEBUG( ircc_debug, __FUNCTION__ ": handling baud of 576000\n");
+               break;
+       case 1152000:
+               ir_mode = UART_CFGA_IRDA_HDLC;
+               select = UART_1152;
+               fast = 0;
+               DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 1152000\n");
+               break;
+       case 4000000:
+               ir_mode = UART_CFGA_IRDA_4PPM;
+               select = 0;
+               fast = UART_LCR_A_FAST;
+               DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 4000000\n");
+               break;
+       default:
+               DEBUG( 0, __FUNCTION__ ": unknown baud rate of %d\n", speed);
+               return;
+       }
+
+#if 0
+       serial_out(idev->io.iobase2, 4, 0x08);
+#endif
+
+       serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+
+       register_bank(iobase, 0);
+       serial_out(iobase, UART_IER, 0);
+       
+               irport_stop(idev, idev->io.iobase2);
+
+       idev->netdev.tbusy = 0;
+       
+       register_bank(iobase, 1);
+
+       serial_out(iobase, UART_SCE_CFGA, 
+                  ((serial_in(iobase, UART_SCE_CFGA) & 0x87) | ir_mode));
+
+       serial_out(iobase, UART_SCE_CFGB,
+                  ((serial_in(iobase, UART_SCE_CFGB) & 0x3f) | UART_CFGB_IR));
+
+       (void) serial_in(iobase, UART_FIFO_THRESHOLD);
+       serial_out(iobase, UART_FIFO_THRESHOLD, 64);
+
+       register_bank(iobase, 4);
+
+       serial_out(iobase, UART_CONTROL,
+                  (serial_in(iobase, UART_CONTROL) & 0x30) 
+                  | select | UART_CRC );
+
+       register_bank(iobase, 0);
+
+       serial_out(iobase, UART_LCR_A, fast);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_hard_xmit (skb, dev)
+ *
+ *    Transmit the frame!
+ *
+ */
+static int ircc_hard_xmit( struct sk_buff *skb, struct device *dev)
+{
+       struct irda_device *idev;
+       int iobase;
+       int mtt;
+
+       DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+       idev = (struct irda_device *) dev->priv;
+
+       ASSERT( idev != NULL, return 0;);
+       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+       iobase = idev->io.iobase;
+
+       DEBUG(ircc_debug+1, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len);
+
+       /* Use irport for SIR speeds */
+       if (idev->io.baudrate <= 115200) {
+               DEBUG(ircc_debug+1, __FUNCTION__ ": calling irport_hard_xmit\n");
+               return irport_hard_xmit(skb, dev);
+       }
+       
+       DEBUG(ircc_debug, __FUNCTION__ ": using dma; len=%d\n", skb->len);
+
+       /* Lock transmit buffer */
+       if (irda_lock((void *) &dev->tbusy) == FALSE)
+               return -EBUSY;
+
+       memcpy( idev->tx_buff.head, skb->data, skb->len);
+
+       /* Make sure that the length is a multiple of 16 bits */
+       if ( skb->len & 0x01)
+               skb->len++;
+
+       idev->tx_buff.len = skb->len;
+       idev->tx_buff.data = idev->tx_buff.head;
+#if 0
+       idev->tx_buff.offset = 0;
+#endif
+       
+       mtt = irda_get_mtt( skb);
+       
+       /* Use udelay for delays less than 50 us. */
+       if (mtt)
+               udelay( mtt);
+       
+       ircc_dma_write( idev, iobase);
+       
+       dev_kfree_skb( skb);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+       return 0;
+}
+
+/*
+ * Function ircc_dma_xmit (idev, iobase)
+ *
+ *    Transmit data using DMA
+ *
+ */
+static void ircc_dma_write( struct irda_device *idev, int iobase)
+{
+       struct ircc_cb *self;
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       ASSERT( idev != NULL, return;);
+       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+       self = idev->priv;
+       iobase = idev->io.iobase;
+
+       setup_dma( idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
+                  DMA_MODE_WRITE);
+       
+       idev->io.direction = IO_XMIT;
+
+       serial_out(idev->io.iobase2, 4, 0x08);
+
+       register_bank(iobase, 4);
+       serial_out(iobase, UART_CONTROL, 
+                  (serial_in(iobase, UART_CONTROL) & 0xF0));
+
+       serial_out(iobase, UART_BOF_COUNT_LO, 2);
+       serial_out(iobase, UART_BRICKWALL_CNT_LO, 0);
+#if 1
+       serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, idev->tx_buff.len >> 8);
+       serial_out(iobase, UART_TX_SIZE_LO, idev->tx_buff.len & 0xff);
+#else
+       serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0);
+       serial_out(iobase, UART_TX_SIZE_LO, 0);
+#endif
+
+       register_bank(iobase, 1);
+       serial_out(iobase, UART_SCE_CFGB,
+                  serial_in(iobase, UART_SCE_CFGB) | UART_CFGB_DMA_ENABLE);
+
+       register_bank(iobase, 0);
+
+       serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME | UART_IER_EOM);
+       serial_out(iobase, UART_LCR_B,
+                  UART_LCR_B_SCE_TRANSMIT|UART_LCR_B_SIP_ENABLE);
+
+       serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_dma_xmit_complete (idev)
+ *
+ *    The transfer of a frame in finished. This function will only be called 
+ *    by the interrupt handler
+ *
+ */
+static void ircc_dma_xmit_complete( struct irda_device *idev, int underrun)
+{
+       struct ircc_cb *self;
+       int iobase, d;
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       ASSERT( idev != NULL, return;);
+       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+       register_bank(idev->io.iobase, 1);
+
+       serial_out(idev->io.iobase, UART_SCE_CFGB,
+                  serial_in(idev->io.iobase, UART_SCE_CFGB) &
+                  ~UART_CFGB_DMA_ENABLE);
+
+       d = get_dma_residue(idev->io.dma);
+
+       DEBUG(ircc_debug, __FUNCTION__ ": dma residue = %d, len=%d, sent=%d\n", 
+             d, idev->tx_buff.len, idev->tx_buff.len - d);
+
+       self = idev->priv;
+
+       iobase = idev->io.iobase;
+
+       /* Check for underrrun! */
+       if ( underrun) {
+               idev->stats.tx_errors++;
+               idev->stats.tx_fifo_errors++;           
+       } else {
+               idev->stats.tx_packets++;
+               idev->stats.tx_bytes +=  idev->tx_buff.len;
+       }
+
+       /* Unlock tx_buff and request another frame */
+       idev->netdev.tbusy = 0; /* Unlock */
+       idev->media_busy = FALSE;
+       
+       /* Tell the network layer, that we can accept more frames */
+       mark_bh( NET_BH);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_dma_receive (idev)
+ *
+ *    Get ready for receiving a frame. The device will initiate a DMA
+ *    if it starts to receive a frame.
+ *
+ */
+static int ircc_dma_receive( struct irda_device *idev) 
+{
+       struct ircc_cb *self;
+       int iobase;
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       ASSERT( idev != NULL, return -1;);
+       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+       self = idev->priv;
+       iobase= idev->io.iobase;
+
+       setup_dma( idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, 
+                  DMA_MODE_READ);
+       
+       /* driver->media_busy = FALSE; */
+       idev->io.direction = IO_RECV;
+       idev->rx_buff.data = idev->rx_buff.head;
+#if 0
+       idev->rx_buff.offset = 0;
+#endif
+
+       register_bank(iobase, 4);
+       serial_out(iobase, UART_CONTROL, 
+                  (serial_in(iobase, UART_CONTROL) &0xF0));
+       serial_out(iobase, UART_BOF_COUNT_LO, 2);
+       serial_out(iobase, UART_BRICKWALL_CNT_LO, 0);
+       serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0);
+       serial_out(iobase, UART_TX_SIZE_LO, 0);
+       serial_out(iobase, UART_RX_SIZE_HI, 0);
+       serial_out(iobase, UART_RX_SIZE_LO, 0);
+
+       register_bank(iobase, 0);
+       serial_out(iobase, 
+                  UART_LCR_B, UART_LCR_B_SCE_RECEIVE | UART_LCR_B_SIP_ENABLE);
+       
+       register_bank(iobase, 1);
+       serial_out(iobase, UART_SCE_CFGB,
+                  serial_in(iobase, UART_SCE_CFGB) | 
+                  UART_CFGB_DMA_ENABLE | UART_CFGB_DMA_BURST);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+       return 0;
+}
+
+/*
+ * Function ircc_dma_receive_complete (idev)
+ *
+ *    Finished with receiving frames
+ *
+ *    
+ */
+static int ircc_dma_receive_complete( struct irda_device *idev, int iobase)
+{
+       struct sk_buff *skb;
+       struct ircc_cb *self;
+       int len, msgcnt;
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       self = idev->priv;
+
+       msgcnt = serial_in(idev->io.iobase, UART_LCR_B) & 0x08;
+
+       DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n",
+             get_dma_residue(idev->io.dma));
+
+       len = idev->rx_buff.truesize - get_dma_residue(idev->io.dma) - 4;
+
+       DEBUG(ircc_debug, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
+
+       skb = dev_alloc_skb( len+1);
+
+       if (skb == NULL)  {
+               printk( KERN_INFO __FUNCTION__ 
+                       ": memory squeeze, dropping frame.\n");
+               return FALSE;
+       }
+                       
+       /* Make sure IP header gets aligned */
+       skb_reserve( skb, 1); 
+       skb_put( skb, len);
+
+       memcpy(skb->data, idev->rx_buff.data, len);
+       idev->stats.rx_packets++;
+
+       skb->dev = &idev->netdev;
+       skb->mac.raw  = skb->data;
+       skb->protocol = htons(ETH_P_IRDA);
+       netif_rx( skb);
+
+       register_bank(idev->io.iobase, 1);
+       serial_out(idev->io.iobase, UART_SCE_CFGB,
+                  serial_in(idev->io.iobase, UART_SCE_CFGB) &
+                  ~UART_CFGB_DMA_ENABLE);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+       return TRUE;
+}
+
+/*
+ * Function ircc_interrupt (irq, dev_id, regs)
+ *
+ *    An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int iobase, iir;
+
+       struct irda_device *idev = (struct irda_device *) dev_id;
+
+       DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+
+       if (idev == NULL) {
+               printk( KERN_WARNING "%s: irq %d for unknown device.\n", 
+                       driver_name, irq);
+               return;
+       }
+       
+       if (idev->io.baudrate <= 115200) {
+               DEBUG(ircc_debug+1, __FUNCTION__ 
+                     ": routing interrupt to irport_interrupt\n");
+               return irport_interrupt( irq, dev_id, regs);
+       }
+
+       iobase = idev->io.iobase;
+
+       idev->netdev.interrupt = 1;
+
+       serial_out(iobase, UART_MASTER, 0);
+
+       register_bank(iobase, 0);
+
+       iir = serial_in(iobase, UART_IIR);
+
+       serial_out(iobase, UART_IER, 0);
+
+       DEBUG(ircc_debug, __FUNCTION__ ": iir = 0x%02x\n", iir);
+
+       if (iir & UART_IIR_EOM) {
+               DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_EOM\n");
+               if (idev->io.direction == IO_RECV) {
+                       ircc_dma_receive_complete(idev, iobase);
+               } else {
+                       ircc_dma_xmit_complete(idev, iobase);
+               }
+               ircc_dma_receive(idev);
+       }
+
+       if (iir & UART_IIR_ACTIVE_FRAME) {
+               DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_ACTIVE_FRAME\n");
+               idev->rx_buff.state = INSIDE_FRAME;
+#if 0
+               ircc_dma_receive(idev);
+#endif
+       }
+
+       if (iir & UART_IIR_RAW_MODE) {
+               DEBUG(ircc_debug, __FUNCTION__ ": IIR RAW mode interrupt.\n");
+       }
+
+       idev->netdev.interrupt = 0;
+
+       register_bank(iobase, 0);
+       serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME|UART_IER_EOM);
+       serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_wait_until_sent (idev)
+ *
+ *    This function should put the current thread to sleep until all data 
+ *    have been sent, so it is safe to change the speed.
+ */
+static void ircc_wait_until_sent( struct irda_device *idev)
+{
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       /* Just delay 60 ms */
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(6);
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_is_receiving (idev)
+ *
+ *    Return TRUE is we are currently receiving a frame
+ *
+ */
+static int ircc_is_receiving( struct irda_device *idev)
+{
+       int status = FALSE;
+       /* int iobase; */
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       ASSERT( idev != NULL, return FALSE;);
+       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+
+       DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n",
+             get_dma_residue(idev->io.dma));
+
+       status = ( idev->rx_buff.state != OUTSIDE_FRAME);
+       
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+       return status;
+}
+
+/*
+ * Function ircc_net_init (dev)
+ *
+ *    Initialize network device
+ *
+ */
+static int ircc_net_init( struct device *dev)
+{
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+       /* Setup to be a normal IrDA network device driver */
+       irda_device_setup( dev);
+
+       /* Insert overrides below this line! */
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+       return 0;
+}
+
+
+/*
+ * Function ircc_net_open (dev)
+ *
+ *    Start the device
+ *
+ */
+static int ircc_net_open( struct device *dev)
+{
+       struct irda_device *idev;
+       int iobase;
+       
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+       
+       ASSERT( dev != NULL, return -1;);
+       idev = (struct irda_device *) dev->priv;
+       
+       ASSERT( idev != NULL, return 0;);
+       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+       
+       iobase = idev->io.iobase;
+
+       if (request_irq( idev->io.irq, ircc_interrupt, 0, idev->name, 
+                        (void *) idev)) {
+               return -EAGAIN;
+       }
+       /*
+        * Always allocate the DMA channel after the IRQ,
+        * and clean up on failure.
+        */
+       if (request_dma(idev->io.dma, idev->name)) {
+               free_irq( idev->io.irq, idev);
+               return -EAGAIN;
+       }
+               
+       /* Ready to play! */
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+
+       /* turn on interrupts */
+       
+       MOD_INC_USE_COUNT;
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+       return 0;
+}
+
+/*
+ * Function ircc_net_close (dev)
+ *
+ *    Stop the device
+ *
+ */
+static int ircc_net_close(struct device *dev)
+{
+       struct irda_device *idev;
+       int iobase;
+
+       DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+       
+       /* Stop device */
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       ASSERT( dev != NULL, return -1;);
+       idev = (struct irda_device *) dev->priv;
+       
+       ASSERT( idev != NULL, return 0;);
+       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+       
+       iobase = idev->io.iobase;
+
+       disable_dma( idev->io.dma);
+
+       /* Disable interrupts */
+       
+       free_irq( idev->io.irq, idev);
+       free_dma( idev->io.dma);
+
+       MOD_DEC_USE_COUNT;
+
+       DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+       return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>");
+MODULE_DESCRIPTION("SMC IrCC controller driver");
+MODULE_PARM(ircc_debug,"1i");
+MODULE_PARM(ircc_dma, "1i");
+MODULE_PARM(ircc_irq, "1i");
+
+/*
+ * Function init_module (void)
+ *
+ *    
+ *
+ */
+int init_module(void)
+{
+       return ircc_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    
+ *
+ */
+void cleanup_module(void)
+{
+       ircc_cleanup();
+}
+
+#endif
index e99cb0d445018121fe718d74e9c8644e7050ab8a..123e2bd2818caeafd568a8cdaa4a8b1ecc15f0b6 100644 (file)
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      tekram.c
- * Version:       1.1
+ * Version:       1.2
  * Description:   Implementation of the Tekram IrMate IR-210B dongle
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Mon May 10 16:10:17 1999
+ * Modified at:   Sun May 16 14:33:42 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
 #include <linux/sched.h>
 #include <linux/init.h>
 
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
 #include <net/irda/irtty.h>
 #include <net/irda/dongle.h>
 
-static void tekram_reset(struct irda_device *dev, int unused);
+static void tekram_reset(struct irda_device *dev);
 static void tekram_open(struct irda_device *dev, int type);
 static void tekram_close(struct irda_device *dev);
 static void tekram_change_speed(struct irda_device *dev, int baud);
@@ -49,7 +45,7 @@ static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos);
 #define TEKRAM_19200  0x03
 #define TEKRAM_9600   0x04
 
-#define TEKRAM_PW 0x10 /* Pulse select bit */
+#define TEKRAM_PW     0x10 /* Pulse select bit */
 
 static struct dongle dongle = {
        TEKRAM_DONGLE,
@@ -112,7 +108,7 @@ static void tekram_change_speed(struct irda_device *idev, int baud)
 
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-       
+
        switch (baud) {
        default:
        case 9600:
@@ -121,7 +117,7 @@ static void tekram_change_speed(struct irda_device *idev, int baud)
        case 19200:
                byte = TEKRAM_PW|TEKRAM_19200;
                break;
-       case 34800:
+       case 38400:
                byte = TEKRAM_PW|TEKRAM_38400;
                break;
        case 57600:
@@ -132,6 +128,9 @@ static void tekram_change_speed(struct irda_device *idev, int baud)
                break;
        }
 
+       /* Need to reset the dongle and go to 9600 bps before programming */
+       tekram_reset(idev);
+       
        /* Set DTR, Clear RTS */
        irda_device_set_dtr_rts(idev, TRUE, FALSE);
        
@@ -162,7 +161,7 @@ static void tekram_change_speed(struct irda_device *idev, int baud)
  *        3. clear DTR to SPACE state, wait at least 50 us for further 
  *         operation
  */
-void tekram_reset(struct irda_device *idev, int unused)
+void tekram_reset(struct irda_device *idev)
 {
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
@@ -185,8 +184,10 @@ void tekram_reset(struct irda_device *idev, int unused)
        irda_device_set_dtr_rts(idev, TRUE, TRUE);
        
        udelay(50);
-
-       /* Finished! */
+       
+       /* Make sure the IrDA chip also goes to defalt speed */
+       if (idev->change_speed)
+               idev->change_speed(idev, 9600);
 }
 
 /*
index f3454c531d94e92d66f0888b423e8ac3adc39fa4..d9e1e107f574a244ac72e16051f7692c6b293e9e 100644 (file)
@@ -7,7 +7,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Dec 26 10:59:03 1998
- * Modified at:   Mon May 10 22:11:09 1999
+ * Modified at:   Wed May 19 15:29:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -216,7 +216,7 @@ static int uircc_open(int i, unsigned int iobase, unsigned int iobase2,
        idev->netdev.open            = uircc_net_open;
        idev->netdev.stop            = uircc_net_close;
 
-       irport_start(iobase2);
+       irport_start(idev, iobase2);
 
        /* Open the IrDA device */
        irda_device_open(idev, driver_name, self);
@@ -251,7 +251,7 @@ static int uircc_close(struct irda_device *idev)
        /* Disable modem */
        outb(0x00, iobase+UIRCC_CR10);
 
-       irport_stop(idev->io.iobase2);
+       irport_stop(idev, idev->io.iobase2);
 
        /* Release the PORT that this driver is using */
        DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase);
@@ -350,7 +350,7 @@ static void uircc_change_speed(struct irda_device *idev, int speed)
        case 37600:
        case 57600:
        case 115200:
-               irport_start(idev->io.iobase2);
+               irport_start(idev, idev->io.iobase2);
                irport_change_speed(idev, speed);
 
                /* Some magic to disable FIR and enable SIR */
@@ -367,7 +367,7 @@ static void uircc_change_speed(struct irda_device *idev, int speed)
                DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
                break;
        case 4000000:
-               irport_stop(idev->io.iobase2);
+               irport_stop(idev, idev->io.iobase2);
 
                /* Some magic to disable SIR and enable FIR */
                uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001);
index f773172153e2dd3f0e19c9158d18d967a348a5a4..029d6de5168cc71b7706e91cb18d5b2d589481f6 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Thu May 13 08:03:27 1999
+ * Modified at:   Fri May 21 22:18:19 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
@@ -80,8 +80,6 @@ static unsigned int dma[] =
 
 static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL};
 
-static struct st_fifo_entry prev;
-
 /* Some prototypes */
 static int  w83977af_open(int i, unsigned int iobase, unsigned int irq, 
                           unsigned int dma);
@@ -113,8 +111,6 @@ __initfunc(int w83977af_init(void))
 
        DEBUG(0, __FUNCTION__ "()\n");
 
-       prev.status = 0;
-
        for (i=0; (io[i] < 2000) && (i < 4); i++) { 
                int ioaddr = io[i];
                if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
index 9f47c66e876b0e569aeef337b4734b7809a038bb..cc7a9976e5d5cdefd4ba7aae9acea1f8fa50c8a8 100644 (file)
@@ -5,7 +5,7 @@
  * same Gnu Public License that covers that work.
  *
  * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
  *    [feel free to mail ....]
  *
  * when using as module: (no autoprobing!)
index b3dfdd21a28af4bc0a74c4d9f712c425496fa695..b08db36373b5a7af63fc083b480dea48180efd86 100644 (file)
@@ -4,7 +4,7 @@
  * This is an extension to the Linux operating system, and is covered by the
  * same Gnu Public License that covers that work.
  *
- * copyrights (c) 1994 by Michael Hipp (mhipp@student.uni-tuebingen.de)
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
  *
  * I have done a look in the following sources:
  *   crynwr-packet-driver by Russ Nelson
index 8fd432aa99dff909c6c791e93be166c792e41ef2..9e22ce1a412de81a649049395e351a99ca3a86f7 100644 (file)
@@ -16,7 +16,7 @@
  *
  * comments/bugs/suggestions can be sent to:
  *   Michael Hipp
- *   email: Michael.Hipp@student.uni-tuebingen.de
+ *   email: hippm@informatik.uni-tuebingen.de
  *
  * sources:
  *   some things are from the 'ni6510-packet-driver for dos by Russ Nelson'
@@ -45,6 +45,7 @@
  */
 
 /*
+ * 99.Jun.8: added support for /proc/net/dev byte count for xosview (HK)
  * 96.Sept.29: virt_to_bus stuff added for new memory modell
  * 96.April.29: Added Harald Koenig's Patches (MH)
  * 96.April.13: enhanced error handling .. more tests (MH)
@@ -966,8 +967,10 @@ static void ni65_xmit_intr(struct device *dev,int csr0)
                                p->stats.tx_errors++;
                        tmdp->status2 = 0;
                }
-               else
+               else {
+                       p->stats.tx_bytes -= (short)(tmdp->blen);
                        p->stats.tx_packets++;
+               }
 
 #ifdef XMT_VIA_SKB
                if(p->tmd_skb[p->tmdlast]) {
@@ -1054,6 +1057,7 @@ static void ni65_recv_intr(struct device *dev,int csr0)
                                eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
 #endif
                                p->stats.rx_packets++;
+                               p->stats.rx_bytes += len;
                                skb->protocol=eth_type_trans(skb,dev);
                                netif_rx(skb);
                        }
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
new file mode 100644 (file)
index 0000000..720b50b
--- /dev/null
@@ -0,0 +1,1143 @@
+/* 
+net-3-driver for the SKNET MCA-based cards
+
+This is an extension to the Linux operating system, and is covered by the
+same Gnu Public License that covers that work.
+
+Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de, aarnold@elsa.de)
+
+This driver is based both on the 3C523 driver and the SK_G16 driver.
+
+paper sources:
+  'PC Hardware: Aufbau, Funktionsweise, Programmierung' by 
+  Hans-Peter Messmer for the basic Microchannel stuff
+  
+  'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
+  for help on Ethernet driver programming
+
+  'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
+  for documentation on the AM7990 LANCE
+
+  'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
+  for documentation on the Junior board
+
+  'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
+  documentation on the MC2 bord
+  
+  A big thank you to the S&K support for providing me so quickly with
+  documentation!
+
+  Also see http://www.syskonnect.com/
+
+  Missing things:
+
+  -> set debug level via ioctl instead of compile-time switches
+  -> I didn't follow the development of the 2.1.x kernels, so my
+     assumptions about which things changed with which kernel version 
+     are probably nonsense
+
+History:
+  May 16th, 1999
+       startup
+  May 22st, 1999
+       added private structure, methods
+        begun building data structures in RAM
+  May 23nd, 1999
+       can receive frames, send frames
+  May 24th, 1999
+        modularized intialization of LANCE
+        loadable as module
+       still Tx problem :-(
+  May 26th, 1999
+       MC2 works
+       support for multiple devices
+       display media type for MC2+
+  May 28th, 1999
+       fixed problem in GetLANCE leaving interrupts turned off
+        increase TX queue to 4 packets to improve send performance
+  May 29th, 1999
+       a few corrections in statistics, caught rcvr overruns 
+        reinitialization of LANCE/board in critical situations
+        MCA info implemented
+       implemented LANCE multicast filter
+  Jun 6th, 1999
+       additions for Linux 2.2
+
+ *************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/mca.h>
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define _SK_MCA_DRIVER_
+#include "sk_mca.h"
+
+/* ------------------------------------------------------------------------
+ * global static data - not more since we can handle multiple boards and
+ * have to pack all state info into the device struct!
+ * ------------------------------------------------------------------------ */
+
+static char *MediaNames[Media_Count]=
+            {"10Base2", "10BaseT", "10Base5", "Unknown"};
+
+static unsigned char poly[] =
+       {1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
+        1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0};
+
+/* ------------------------------------------------------------------------
+ * private subfunctions
+ * ------------------------------------------------------------------------ */
+
+/* dump parts of shared memory - only needed during debugging */
+
+#ifdef DEBUG
+static void dumpmem(struct device *dev, u32 start, u32 len)
+{
+  int z;
+
+  for (z = 0; z < len; z++)
+  {
+    if ((z & 15) == 0)
+      printk("%04x:", z);
+    printk(" %02x", readb(dev->mem_start + start + z));
+    if ((z & 15) == 15)
+      printk("\n");
+  }
+}
+
+/* print exact time - ditto */
+
+static void PrTime(void)
+{
+  struct timeval tv;
+
+  do_gettimeofday(&tv);
+  printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
+}
+#endif
+
+/* deduce resources out of POS registers */
+
+static void getaddrs(int slot, int junior, int *base, int *irq,
+                     skmca_medium *medium)
+{
+  u_char pos0, pos1, pos2;
+  
+  if (junior)
+  {
+    pos0 = mca_read_stored_pos(slot, 2);
+    *base = ((pos0 & 0x0e) << 13) + 0xc0000;
+    *irq = ((pos0 & 0x10) >> 4) + 10;
+    *medium = Media_Unknown;
+  }
+  else
+  {
+    /* reset POS 104 Bits 0+1 so the shared memory region goes to the
+       configured area between 640K and 1M.  Afterwards, enable the MC2.
+       I really don't know what rode SK to do this... */
+       
+    mca_write_pos(slot, 4, mca_read_stored_pos(slot, 4) & 0xfc);
+    mca_write_pos(slot, 2, mca_read_stored_pos(slot, 2) | 0x01);
+       
+    pos1 = mca_read_stored_pos(slot, 3);
+    pos2 = mca_read_stored_pos(slot, 4);
+    *base = ((pos1 & 0x07) << 14) + 0xc0000;
+    switch (pos2 & 0x0c)
+    {
+      case 0: *irq = 3; break;
+      case 4: *irq = 5; break;
+      case 8: *irq = 10; break;
+      case 12: *irq = 11; break;
+    }
+    *medium = (pos2 >> 6) & 3;
+  }
+}
+
+/* check for both cards:
+   When the MC2 is turned off, it was configured for more than 15MB RAM,
+   is disabled and won't get detected using the standard probe.  We
+   therefore have to scan the slots manually :-( */
+
+static int dofind(int *junior, int firstslot)
+{
+  int slot;
+  unsigned int id;
+
+  for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++)
+  {
+    id = mca_read_stored_pos(slot, 0)
+       + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
+       
+    *junior = 0;
+    if (id == SKNET_MCA_ID)
+      return slot;
+    *junior = 1;
+    if (id == SKNET_JUNIOR_MCA_ID)
+      return slot;
+  }
+  return MCA_NOTFOUND;
+}
+
+/* reset the whole board */
+
+static void ResetBoard(struct device *dev)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+
+  writeb(CTRL_RESET_ON, priv->ctrladdr);
+  udelay(10);
+  writeb(CTRL_RESET_OFF, priv->ctrladdr);
+}
+
+/* set LANCE register - must be atomic */
+
+static void SetLANCE(struct device *dev, u16 addr, u16 value)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  unsigned long flags;
+
+  /* disable interrupts */
+
+  save_flags(flags);
+  cli();
+
+  /* wait until no transfer is pending */
+  
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* transfer register address to RAP */
+
+  writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
+  writew(addr, priv->ioregaddr);
+  writeb(IOCMD_GO, priv->cmdaddr);
+  udelay(1);
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* transfer data to register */
+
+  writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
+  writew(value, priv->ioregaddr);
+  writeb(IOCMD_GO, priv->cmdaddr);
+  udelay(1);
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* reenable interrupts */
+
+  restore_flags(flags);
+}
+
+/* get LANCE register */
+
+static u16 GetLANCE(struct device *dev, u16 addr)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  unsigned long flags;
+  unsigned int res;
+
+  /* disable interrupts */
+
+  save_flags(flags);
+  cli();
+
+  /* wait until no transfer is pending */
+
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* transfer register address to RAP */
+
+  writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
+  writew(addr, priv->ioregaddr);
+  writeb(IOCMD_GO, priv->cmdaddr);
+  udelay(1);
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* transfer data from register */
+
+  writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
+  writeb(IOCMD_GO, priv->cmdaddr);
+  udelay(1);
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+  res = readw(priv->ioregaddr);
+
+  /* reenable interrupts */
+
+  restore_flags(flags);
+
+  return res;
+}
+
+/* build up descriptors in shared RAM */
+
+static void InitDscrs(struct device *dev)
+{
+  u32 bufaddr;
+
+  /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
+     are always 0. */
+
+  bufaddr = RAM_DATABASE;
+  {
+    LANCE_TxDescr descr;
+    int z;
+
+    for (z = 0; z < TXCOUNT; z++)
+    {
+      descr.LowAddr = bufaddr;
+      descr.Flags = 0;
+      descr.Len = 0xf000;
+      descr.Status = 0;
+      memcpy_toio(dev->mem_start + RAM_TXBASE + (z * sizeof(LANCE_TxDescr)),
+                  &descr, sizeof(LANCE_TxDescr));
+      memset_io(dev->mem_start + bufaddr, 0, RAM_BUFSIZE);
+      bufaddr += RAM_BUFSIZE;
+    }
+  }
+
+  /* do the same for the Rx descriptors */
+  {
+    LANCE_RxDescr descr;
+    int z;
+
+    for (z = 0; z < RXCOUNT; z++)
+    {
+      descr.LowAddr = bufaddr;
+      descr.Flags = RXDSCR_FLAGS_OWN;
+      descr.MaxLen = -RAM_BUFSIZE;
+      descr.Len = 0;
+      memcpy_toio(dev->mem_start + RAM_RXBASE + (z * sizeof(LANCE_RxDescr)),
+                  &descr, sizeof(LANCE_RxDescr));
+      memset_io(dev->mem_start + bufaddr, 0, RAM_BUFSIZE);
+      bufaddr += RAM_BUFSIZE;
+    }
+  }
+}
+
+/* calculate the hash bit position for a given multicast address
+   taken more or less directly from the AMD datasheet... */
+
+static void UpdateCRC(unsigned char *CRC, int bit)
+{
+  int j;
+
+  /* shift CRC one bit */
+
+  memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
+  CRC[0] = 0;
+
+  /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
+
+  if (bit ^ CRC[32])
+    for (j = 0; j < 32; j++)
+      CRC[j] ^= poly[j];
+}
+
+static unsigned int GetHash(char *address)
+{
+  unsigned char CRC[33];
+  int i, byte, hashcode;
+
+  /* a multicast address has bit 0 in the first byte set */
+
+  if ((address[0] & 1) == 0)
+    return -1;
+
+  /* initialize CRC */
+
+  memset(CRC, 1, sizeof(CRC));
+
+  /* loop through address bits */
+
+  for (byte = 0; byte < 6; byte++)
+    for (i = 0; i < 8; i++)
+      UpdateCRC(CRC, (address[byte] >> i) & 1);
+
+  /* hashcode is the 6 least significant bits of the CRC */
+
+  hashcode = 0;
+  for (i = 0; i < 6; i++)
+    hashcode = (hashcode << 1) + CRC[i];
+  return hashcode;
+}
+
+/* feed ready-built initialization block into LANCE */
+
+static void InitLANCE(struct device *dev)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+
+  /* build up descriptors. */
+
+  InitDscrs(dev);
+
+  /* next RX descriptor to be read is the first one.  Since the LANCE
+     will start from the beginning after initialization, we have to 
+     reset out pointers too. */
+
+  priv->nextrx = 0;
+
+  /* no TX descriptors active */
+
+  priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
+
+  /* set up the LANCE bus control register - constant for SKnet boards */
+
+  SetLANCE(dev, LANCE_CSR3, CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
+
+  /* write address of initialization block into LANCE */
+
+  SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
+  SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
+
+  /* we don't get ready until the LANCE has read the init block */
+
+  dev->tbusy = 1;
+
+  /* let LANCE read the initialization block.  LANCE is ready
+     when we receive the corresponding interrupt. */
+
+  SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
+}
+
+/* stop the LANCE so we can reinitialize it */
+
+static void StopLANCE(struct device *dev)
+{
+  /* can't take frames any more */
+
+  dev->tbusy = 1;
+
+  /* disable interrupts, stop it */
+
+  SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
+}
+
+/* initialize card and LANCE for proper operation */
+
+static void InitBoard(struct device *dev)
+{
+  LANCE_InitBlock block;
+
+  /* Lay out the shared RAM - first we create the init block for the LANCE.
+     We do not overwrite it later because we need it again when we switch
+     promiscous mode on/off. */
+
+  block.Mode = 0;
+  if (dev->flags & IFF_PROMISC)
+    block.Mode |= LANCE_INIT_PROM;
+  memcpy(block.PAdr, dev->dev_addr, 6);
+  memset(block.LAdrF, 0, sizeof(block.LAdrF));
+  block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
+  block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
+
+  memcpy_toio(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+
+  /* initialize LANCE. Implicitly sets up other structures in RAM. */
+
+  InitLANCE(dev);
+}
+
+/* deinitialize card and LANCE */
+
+static void DeinitBoard(struct device *dev)
+{
+  /* stop LANCE */
+
+  StopLANCE(dev);
+
+  /* reset board */
+
+  ResetBoard(dev);
+}
+
+/* ------------------------------------------------------------------------
+ * interrupt handler(s)
+ * ------------------------------------------------------------------------ */
+
+/* LANCE has read initializazion block -> start it */
+
+static u16 irqstart_handler(struct device *dev, u16 oldcsr0)
+{
+  /* now we're ready to transmit */
+
+  dev->tbusy = 0;
+
+  /* reset IDON bit, start LANCE */
+
+  SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
+  return GetLANCE(dev, LANCE_CSR0);
+}
+
+/* receive interrupt */
+
+static u16 irqrx_handler(struct device *dev, u16 oldcsr0)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  LANCE_RxDescr descr;
+  unsigned int descraddr;
+
+  /* did we loose blocks due to a FIFO overrun ? */
+
+  if (oldcsr0 & CSR0_MISS)
+    priv->stat.rx_fifo_errors++;
+
+  /* run through queue until we reach a descriptor we do not own */
+
+  descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
+  while (1)
+  {
+    /* read descriptor */
+    memcpy_fromio(&descr, dev->mem_start + descraddr, sizeof(LANCE_RxDescr));
+    /* if we reach a descriptor we do not own, we're done */
+    if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
+      break;
+
+#ifdef DEBUG
+    PrTime(); printk("Receive packet on descr %d len %d\n", priv->nextrx, descr.Len);
+#endif
+
+    /* erroneous packet ? */
+    if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0)
+    {
+      priv->stat.rx_errors++;
+      if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
+        priv->stat.rx_crc_errors++;
+      else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
+        priv->stat.rx_frame_errors++;
+      else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
+        priv->stat.rx_fifo_errors++;
+    }
+
+    /* good packet ? */
+    else
+    {
+      struct sk_buff *skb;
+
+      skb = dev_alloc_skb(descr.Len + 2);
+      if (skb == NULL)
+        priv->stat.rx_dropped++;
+      else
+      {
+        memcpy_fromio(skb_put(skb, descr.Len),
+                      dev->mem_start + descr.LowAddr, descr.Len);
+        skb->dev = dev;
+        skb->protocol = eth_type_trans(skb, dev);
+        skb->ip_summed = CHECKSUM_NONE;
+        priv->stat.rx_packets++;
+#if LINUX_VERSION_CODE >= 0x020119       /* byte counters for >= 2.1.25 */
+        priv->stat.rx_bytes += descr.Len;
+#endif
+        netif_rx(skb);
+      }
+    }
+
+    /* give descriptor back to LANCE */
+    descr.Len = 0;
+    descr.Flags |= RXDSCR_FLAGS_OWN;
+
+    /* update descriptor in shared RAM */
+    memcpy_toio(dev->mem_start + descraddr, &descr, sizeof(LANCE_RxDescr));
+
+    /* go to next descriptor */
+    priv->nextrx++; descraddr += sizeof(LANCE_RxDescr);
+    if (priv->nextrx >= RXCOUNT)
+    {
+      priv->nextrx = 0;
+      descraddr = RAM_RXBASE;
+    }
+  }
+
+  /* reset RINT bit */
+
+  SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
+  return GetLANCE(dev, LANCE_CSR0);
+}
+
+/* transmit interrupt */
+
+static u16 irqtx_handler(struct device *dev, u16 oldcsr0)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  LANCE_TxDescr descr;
+  unsigned int descraddr;
+
+  /* check descriptors at most until no busy one is left */
+
+  descraddr = RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
+  while (priv->txbusy > 0)
+  {
+    /* read descriptor */
+    memcpy_fromio(&descr, dev->mem_start + descraddr, sizeof(LANCE_TxDescr));
+
+    /* if the LANCE still owns this one, we've worked out all sent packets */
+    if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
+      break;
+
+#ifdef DEBUG
+    PrTime(); printk("Send packet done on descr %d\n", priv->nexttxdone);
+#endif
+
+    /* update statistics */
+    if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0)
+    {
+      priv->stat.tx_packets++;
+#if LINUX_VERSION_CODE >= 0x020119       /* byte counters for >= 2.1.25 */
+      priv->stat.tx_bytes++;
+#endif
+    }
+    else
+    {
+      priv->stat.tx_errors++;
+      if ((descr.Status & TXDSCR_STATUS_UFLO) != 0)
+      {
+        priv->stat.tx_fifo_errors++;
+        InitLANCE(dev);
+      }
+      else if ((descr.Status & TXDSCR_STATUS_LCOL) != 0)
+        priv->stat.tx_window_errors++;
+      else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
+        priv->stat.tx_carrier_errors++;
+      else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
+        priv->stat.tx_aborted_errors++;
+    }
+
+    /* go to next descriptor */
+    priv->nexttxdone++;
+    descraddr += sizeof(LANCE_TxDescr);
+    if (priv->nexttxdone >= TXCOUNT)
+    {
+      priv->nexttxdone = 0;
+      descraddr = RAM_TXBASE;
+    }
+    priv->txbusy--;
+  }
+
+  /* reset TX interrupt bit */
+
+  SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
+  oldcsr0 = GetLANCE(dev, LANCE_CSR0);
+
+  /* at least one descriptor is freed.  Therefore we can accept
+     a new one */
+
+  dev->tbusy = 0;
+
+  /* inform upper layers we're in business again */
+
+  mark_bh(NET_BH);
+
+  return oldcsr0;
+}
+
+/* general interrupt entry */
+
+static void irq_handler(int irq, void *device, struct pt_regs *regs)
+{
+  struct device *dev = (struct device*) device;
+  u16 csr0val;
+
+  /* read CSR0 to get interrupt cause */
+
+  csr0val = GetLANCE(dev, LANCE_CSR0);
+
+  /* in case we're not meant... */
+
+  if ((csr0val & CSR0_INTR) == 0)
+    return;
+
+  dev->interrupt = 1;
+
+  /* loop through the interrupt bits until everything is clear */
+
+  do
+  {
+    if ((csr0val & CSR0_IDON) != 0)
+      csr0val = irqstart_handler(dev, csr0val);
+    if ((csr0val & CSR0_RINT) != 0)
+      csr0val = irqrx_handler(dev, csr0val);
+    if ((csr0val & CSR0_TINT) != 0)
+      csr0val = irqtx_handler(dev, csr0val);
+  }
+  while ((csr0val & CSR0_INTR) != 0);
+
+  dev->interrupt = 0;
+}
+
+/* ------------------------------------------------------------------------
+ * driver methods
+ * ------------------------------------------------------------------------ */
+
+/* MCA info */
+
+static int skmca_getinfo(char *buf, int slot, void *d)
+{
+  int len = 0, i;
+  struct device *dev = (struct device*) d;
+  skmca_priv *priv;
+  
+  /* can't say anything about an uninitialized device... */
+
+  if (dev == NULL)
+    return len;
+  if (dev->priv == NULL)
+    return len;
+  priv = (skmca_priv*) dev->priv;
+
+  /* print info */
+
+  len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
+  len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
+                 dev->mem_end - 1);
+  len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]);
+  len += sprintf(buf + len, "Device: %s\n", dev->name);
+  len += sprintf(buf + len, "MAC address:");
+  for (i = 0; i < 6; i ++ )
+    len += sprintf( buf+len, " %02x", dev->dev_addr[i] );
+  buf[len++] = '\n';
+  buf[len] = 0;
+
+  return len;
+}
+
+/* open driver.  Means also initialization and start of LANCE */
+
+static int skmca_open(struct device *dev)
+{
+  int result;
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+
+  /* register resources - only necessary for IRQ */
+  result = request_irq(priv->realirq, irq_handler, SA_SHIRQ | SA_SAMPLE_RANDOM,
+                       "sk_mca", dev);
+  if (result != 0)
+  {
+    printk("%s: failed to register irq %d\n", dev->name, dev->irq);
+    return result;
+  }
+  dev->irq = priv->realirq;
+
+  /* set up the card and LANCE */
+  InitBoard(dev);
+
+#ifdef MODULE
+  MOD_INC_USE_COUNT;
+#endif
+
+  return 0;
+}
+
+/* close driver.  Shut down board and free allocated resources */
+
+static int skmca_close(struct device *dev)
+{
+  /* turn off board */
+  DeinitBoard(dev);
+
+  /* release resources */
+  if (dev->irq != 0)
+    free_irq(dev->irq, dev);
+  dev->irq = 0;
+
+#ifdef MODULE
+  MOD_DEC_USE_COUNT;
+#endif
+
+  return 0;
+}
+
+/* transmit a block. */
+
+static int skmca_tx(struct sk_buff *skb, struct device *dev)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  LANCE_TxDescr descr;
+  unsigned int address;
+  int tmplen, retval = 0;
+  unsigned long flags;
+
+  /* if we get called with a NULL descriptor, the Ethernet layer thinks 
+     our card is stuck an we should reset it.  We'll do this completely: */
+
+  if (skb == NULL)
+  {
+    DeinitBoard(dev);
+    InitBoard(dev);
+    return 0; /* don't try to free the block here ;-) */
+  }
+
+  /* is there space in the Tx queue ? If no, the upper layer gave us a
+     packet in spite of us not being ready and is really in trouble.
+     We'll do the dropping for him: */
+  if (priv->txbusy >= TXCOUNT)
+  {
+    priv->stat.tx_dropped++;
+    retval = -EIO;
+    goto tx_done;
+  }
+
+  /* get TX descriptor */
+  address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
+  memcpy_fromio(&descr, dev->mem_start + address, sizeof(LANCE_TxDescr));
+
+  /* enter packet length as 2s complement - assure minimum length */
+  tmplen = skb->len;
+  if (tmplen < 60)
+    tmplen = 60;
+  descr.Len = 65536 - tmplen;
+
+  /* copy filler into RAM - in case we're filling up... 
+     we're filling a bit more than necessary, but that doesn't harm
+     since the buffer is far larger... */
+  if (tmplen > skb->len)
+  {
+    char *fill = "NetBSD is a nice OS too! ";
+    unsigned int destoffs = 0, l = strlen(fill);
+
+    while (destoffs < tmplen)
+    {
+      memcpy_toio(dev->mem_start + descr.LowAddr + destoffs, fill, l);
+      destoffs += l;
+    }
+  }
+
+  /* do the real data copying */
+  memcpy_toio(dev->mem_start + descr.LowAddr, skb->data, skb->len);
+
+  /* hand descriptor over to LANCE - this is the first and last chunk */
+  descr.Flags = TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
+
+#ifdef DEBUG
+  PrTime(); printk("Send packet on descr %d len %d\n", priv->nexttxput, skb->len);
+#endif
+
+  /* one more descriptor busy */
+  save_flags(flags);
+  cli();
+  priv->nexttxput++;
+  if (priv->nexttxput >= TXCOUNT)
+    priv->nexttxput = 0;
+  priv->txbusy++;
+  dev->tbusy = (priv->txbusy >= TXCOUNT);
+
+  /* write descriptor back to RAM */
+  memcpy_toio(dev->mem_start + address, &descr, sizeof(LANCE_TxDescr));
+
+  /* if no descriptors were active, give the LANCE a hint to read it
+     immediately */
+
+  if (priv->txbusy == 0)
+    SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
+
+  restore_flags(flags);
+
+tx_done:
+
+  /* When did that change exactly ? */
+
+#if LINUX_VERSION_CODE >= 0x020200
+  dev_kfree_skb(skb);
+#else
+  dev_kfree_skb(skb, FREE_WRITE);
+#endif
+  return retval;
+}
+
+/* return pointer to Ethernet statistics */
+
+static struct enet_statistics *skmca_stats(struct device *dev)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+
+  return &(priv->stat);
+}
+
+/* we don't support runtime reconfiguration, since am MCA card can
+   be unambigously identified by its POS registers. */
+
+static int skmca_config(struct device *dev, struct ifmap *map)
+{
+  return 0;
+}
+
+/* switch receiver mode.  We use the LANCE's multicast filter to prefilter
+   multicast addresses. */
+
+static void skmca_set_multicast_list(struct device *dev)
+{
+  LANCE_InitBlock block;
+
+  /* first stop the LANCE... */
+  StopLANCE(dev);
+
+  /* ...then modify the initialization block... */
+  memcpy_fromio(&block, dev->mem_start + RAM_INITBASE, sizeof(block));
+  if (dev->flags & IFF_PROMISC)
+    block.Mode |= LANCE_INIT_PROM;
+  else
+    block.Mode &= ~LANCE_INIT_PROM;
+
+  if (dev->flags & IFF_ALLMULTI)   /* get all multicasts */
+  {
+    memset(block.LAdrF, 8, 0xff);
+  }
+  else                             /* get selected/no multicasts */
+  {
+    struct dev_mc_list *mptr;
+    int code;
+
+    memset(block.LAdrF, 8, 0x00);
+    for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next)
+    {
+      code = GetHash(mptr->dmi_addr);
+      block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
+    }
+  }
+
+  memcpy_toio(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+
+  /* ...then reinit LANCE with the correct flags */
+  InitLANCE(dev);
+}
+
+/* ------------------------------------------------------------------------
+ * hardware check
+ * ------------------------------------------------------------------------ */
+
+#ifdef MODULE
+static int startslot; /* counts through slots when probing multiple devices */
+#else
+#define startslot 0   /* otherwise a dummy, since there is only eth0 in-kern*/
+#endif
+
+int skmca_probe(struct device *dev)
+{
+  int force_detect = 0;
+  int junior, slot, i;
+  int base = 0, irq = 0;
+  skmca_priv *priv;
+  skmca_medium medium;
+
+  /* can't work without an MCA bus ;-) */
+  
+  if (MCA_bus == 0)
+    return ENODEV;
+    
+  /* start address of 1 --> forced detection */
+  
+  if (dev->mem_start == 1)
+    force_detect = 1;
+
+  /* search through slots */
+  
+  if (dev != NULL)
+  {
+    base = dev->mem_start;
+    irq = dev->irq;
+  }
+  slot = dofind(&junior, startslot);
+
+  while (slot != -1)
+  {
+    /* deduce card addresses */
+
+    getaddrs(slot, junior, &base, &irq, &medium);
+
+#if 0
+    /* this should work, but it doesn't with 2.2.9 :-( 
+       somehow 'mca_is_adapter_used()' is missing in kernel syms... */
+#if LINUX_VERSION_CODE >= 0x020200
+    /* slot already in use ? */
+
+    if (mca_is_adapter_used(slot))
+    {
+      slot = dofind(&junior, slot + 1);
+      continue;
+    }
+#endif
+#endif
+
+    /* were we looking for something different ? */
+    
+    if ((dev->irq != 0) || (dev->mem_start != 0))
+    {
+      if ((dev->irq != 0) && (dev->irq != irq))
+      {
+        slot = dofind(&junior, slot + 1);
+        continue;
+      }
+      if ((dev->mem_start != 0) && (dev->mem_start != base))
+      {
+        slot = dofind(&junior, slot + 1);
+        continue;
+      }
+    }
+  
+    /* found something that matches */
+    
+    break;
+  }
+
+  /* nothing found ? */
+  
+  if (slot == -1)
+    return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV;
+    
+  /* make procfs entries */
+    
+  if (junior)
+    mca_set_adapter_name(slot, "SKNET junior MC2 Ethernet Adapter");
+  else
+    mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
+  mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
+
+#if LINUX_VERSION_CODE >= 0x020200
+  mca_mark_as_used(slot);
+#endif
+  
+  /* announce success */
+  printk("%s: SKNet %s adapter found in slot %d\n", dev->name, 
+         junior ? "Junior MC2" : "MC2+", slot + 1);
+
+  /* allocate structure */
+  priv = dev->priv = (skmca_priv*) kmalloc(sizeof(skmca_priv), GFP_KERNEL);
+  priv->slot = slot;
+  priv->macbase = base + 0x3fc0;
+  priv->ioregaddr = base + 0x3ff0;
+  priv->ctrladdr = base + 0x3ff2;
+  priv->cmdaddr = base + 0x3ff3;
+  priv->realirq = irq;
+  priv->medium = medium;
+  memset(&(priv->stat), 0, sizeof(struct enet_statistics));
+  
+  /* set base + irq for this device (irq not allocated so far) */
+  dev->irq = 0;
+  dev->mem_start = base;
+  dev->mem_end = base + 0x4000;
+  /* set methods */
+  dev->open = skmca_open;
+  dev->stop = skmca_close;
+  dev->set_config = skmca_config;
+  dev->hard_start_xmit = skmca_tx;
+  dev->do_ioctl = NULL;
+  dev->get_stats = skmca_stats;
+  dev->set_multicast_list = skmca_set_multicast_list;
+  dev->flags |= IFF_MULTICAST;
+
+  /* generic setup */
+  ether_setup(dev);
+  dev->interrupt = 0;
+  dev->tbusy = 0;
+  dev->start = 0;
+  /* copy out MAC address */
+  for (i = 0; i < 6; i++)
+    dev->dev_addr[i] = readb(priv->macbase + (i << 1));
+
+  /* print config */
+  printk("%s: IRQ %d, memory %#lx-%#lx, "
+         "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
+         dev->name, priv->realirq,  dev->mem_start, dev->mem_end - 1,
+         dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+         dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+  printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
+
+  /* reset board */
+
+  ResetBoard(dev);
+
+#ifdef MODULE
+  startslot = slot + 1;
+#endif
+
+  return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * modularization support
+ * ------------------------------------------------------------------------ */
+
+#ifdef MODULE
+
+#define DEVMAX 5
+
+static char NameSpace[8 * DEVMAX];
+static struct device moddevs[DEVMAX] =
+       {{NameSpace +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+        {NameSpace +  8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+        {NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+        {NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+        {NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}};
+
+int irq=0;
+int io=0;
+
+int init_module(void)
+{
+  int z, res;
+
+  startslot = 0;
+  for (z = 0; z < DEVMAX; z++)
+  {
+    strcpy(moddevs[z].name, "     ");
+    res = register_netdev(moddevs + z);
+    if (res != 0)
+      return (z > 0) ? 0 : -EIO;
+  }
+
+  return 0;
+}
+
+void cleanup_module(void)
+{
+  struct device *dev;
+  skmca_priv *priv;
+  int z;
+
+  if (MOD_IN_USE)
+  {
+    printk("cannot unload, module in use\n");
+    return;
+  }
+
+  for (z = 0; z < DEVMAX; z++)
+  {
+    dev = moddevs + z;
+    if (dev->priv != NULL)
+    {
+      priv = (skmca_priv*) dev->priv;
+      DeinitBoard(dev);
+      if (dev->irq != 0)
+        free_irq(dev->irq, dev);
+      dev->irq = 0;
+      unregister_netdev(dev);
+#if LINUX_VERSION_CODE >= 0x020200
+      mca_mark_as_unused(priv->slot);
+#endif
+      mca_set_adapter_procfn(priv->slot, NULL, NULL);
+      kfree_s(dev->priv, sizeof(skmca_priv));
+      dev->priv = NULL;
+    }
+  }
+}
+#endif /* MODULE */
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
new file mode 100644 (file)
index 0000000..f45aadf
--- /dev/null
@@ -0,0 +1,174 @@
+#ifndef _SK_MCA_INCLUDE_
+#define _SK_MCA_INCLUDE_
+
+#ifdef _SK_MCA_DRIVER_
+
+/* Adapter ID's */
+#define SKNET_MCA_ID 0x6afd
+#define SKNET_JUNIOR_MCA_ID 0x6be9
+
+/* media enumeration - defined in a way that it fits onto the MC2+'s
+   POS registers... */
+   
+typedef enum {Media_10Base2, Media_10BaseT,
+              Media_10Base5, Media_Unknown, Media_Count} skmca_medium;
+
+/* private structure */
+typedef struct
+        {
+          unsigned int slot;       /* MCA-Slot-#                       */
+          unsigned int macbase;    /* base address of MAC address PROM */
+          unsigned int ioregaddr;  /* address of I/O-register (Lo)     */
+          unsigned int ctrladdr;   /* address of control/stat register */
+          unsigned int cmdaddr;    /* address of I/O-command register  */
+          int nextrx;              /* index of next RX descriptor to
+                                      be read                          */
+          int nexttxput;           /* index of next free TX descriptor */
+          int nexttxdone;          /* index of next TX descriptor to 
+                                      be finished                      */
+          int txbusy;              /* # of busy TX descriptors         */
+          struct enet_statistics stat; /* packet statistics            */
+          int realirq;             /* memorizes actual IRQ, even when 
+                                      currently not allocated          */
+          skmca_medium medium;     /* physical cannector               */
+        } skmca_priv;
+
+/* card registers: control/status register bits */
+
+#define CTRL_ADR_DATA      0      /* Bit 0 = 0 ->access data register  */
+#define CTRL_ADR_RAP       1      /* Bit 0 = 1 ->access RAP register   */
+#define CTRL_RW_WRITE      0      /* Bit 1 = 0 ->write register        */
+#define CTRL_RW_READ       2      /* Bit 1 = 1 ->read register         */
+#define CTRL_RESET_ON      0      /* Bit 3 = 0 ->reset board           */
+#define CTRL_RESET_OFF     8      /* Bit 3 = 1 ->no reset of board     */
+
+#define STAT_ADR_DATA      0      /* Bit 0 of ctrl register read back  */
+#define STAT_ADR_RAP       1
+#define STAT_RW_WRITE      0      /* Bit 1 of ctrl register read back  */
+#define STAT_RW_READ       2
+#define STAT_RESET_ON      0      /* Bit 3 of ctrl register read back  */
+#define STAT_RESET_OFF     8
+#define STAT_IRQ_ACT       0      /* interrupt pending                 */
+#define STAT_IRQ_NOACT     16     /* no interrupt pending              */
+#define STAT_IO_NOBUSY     0      /* no transfer busy                  */
+#define STAT_IO_BUSY       32     /* transfer busy                     */
+
+/* I/O command register bits */
+
+#define IOCMD_GO           128    /* Bit 7 = 1 -> start register xfer  */
+
+/* LANCE registers */
+
+#define LANCE_CSR0         0      /* Status/Control                    */
+
+#define CSR0_ERR           0x8000 /* general error flag                */
+#define CSR0_BABL          0x4000 /* transmitter timeout               */
+#define CSR0_CERR          0x2000 /* collision error                   */
+#define CSR0_MISS          0x1000 /* lost Rx block                     */
+#define CSR0_MERR          0x0800 /* memory access error               */
+#define CSR0_RINT          0x0400 /* receiver interrupt                */
+#define CSR0_TINT          0x0200 /* transmitter interrupt             */
+#define CSR0_IDON          0x0100 /* initialization done               */
+#define CSR0_INTR          0x0080 /* general interrupt flag            */
+#define CSR0_INEA          0x0040 /* interrupt enable                  */
+#define CSR0_RXON          0x0020 /* receiver enabled                  */
+#define CSR0_TXON          0x0010 /* transmitter enabled               */
+#define CSR0_TDMD          0x0008 /* force transmission now            */
+#define CSR0_STOP          0x0004 /* stop LANCE                        */
+#define CSR0_STRT          0x0002 /* start LANCE                       */
+#define CSR0_INIT          0x0001 /* read initialization block         */          
+
+#define LANCE_CSR1         1      /* addr bit 0..15 of initialization  */
+#define LANCE_CSR2         2      /*          16..23 block             */
+
+#define LANCE_CSR3         3      /* Bus control                       */
+#define CSR3_BCON_HOLD     0      /* Bit 0 = 0 -> BM1,BM0,HOLD         */
+#define CSR3_BCON_BUSRQ    1      /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ    */
+#define CSR3_ALE_HIGH      0      /* Bit 1 = 0 -> ALE asserted high    */
+#define CSR3_ALE_LOW       2      /* Bit 1 = 1 -> ALE asserted low     */
+#define CSR3_BSWAP_OFF     0      /* Bit 2 = 0 -> no byte swap         */
+#define CSR3_BSWAP_ON      0      /* Bit 2 = 1 -> byte swap            */
+
+/* LANCE structures */
+
+typedef struct                    /* LANCE initialization block        */
+        {
+          u16 Mode;               /* mode flags                        */
+          u8  PAdr[6];            /* MAC address                       */
+          u8  LAdrF[8];           /* Multicast filter                  */
+          u32 RdrP;               /* Receive descriptor                */
+          u32 TdrP;               /* Transmit descriptor               */
+        } LANCE_InitBlock;
+        
+/* Mode flags init block */
+
+#define LANCE_INIT_PROM    0x8000 /* enable promiscous mode            */
+#define LANCE_INIT_INTL    0x0040 /* internal loopback                 */
+#define LANCE_INIT_DRTY    0x0020 /* disable retry                     */
+#define LANCE_INIT_COLL    0x0010 /* force collision                   */
+#define LANCE_INIT_DTCR    0x0008 /* disable transmit CRC              */
+#define LANCE_INIT_LOOP    0x0004 /* loopback                          */
+#define LANCE_INIT_DTX     0x0002 /* disable transmitter               */
+#define LANCE_INIT_DRX     0x0001 /* disable receiver                  */
+
+typedef struct                    /* LANCE Tx descriptor               */
+        {
+          u16 LowAddr;            /* bit 0..15 of address              */
+          u16 Flags;              /* bit 16..23 of address + Flags     */
+          u16 Len;                /* 2s complement of packet length    */
+          u16 Status;             /* Result of transmission            */
+        } LANCE_TxDescr;
+
+#define TXDSCR_FLAGS_OWN   0x8000 /* LANCE owns descriptor             */
+#define TXDSCR_FLAGS_ERR   0x4000 /* summary error flag                */
+#define TXDSCR_FLAGS_MORE  0x1000 /* more than one retry needed?       */
+#define TXDSCR_FLAGS_ONE   0x0800 /* one retry?                        */
+#define TXDSCR_FLAGS_DEF   0x0400 /* transmission deferred?            */
+#define TXDSCR_FLAGS_STP   0x0200 /* first packet in chain?            */
+#define TXDSCR_FLAGS_ENP   0x0100 /* last packet in chain?             */
+
+#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error?                     */
+#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit?   */
+#define TXDSCR_STATUS_LCOL 0x1000 /* late collision?                   */
+#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier?                  */
+#define TXDSCR_STATUS_RTRY 0x0400 /* retry error?                      */
+        
+typedef struct                    /* LANCE Rx descriptor               */
+        {
+          u16 LowAddr;            /* bit 0..15 of address              */
+          u16 Flags;              /* bit 16..23 of address + Flags     */
+          u16 MaxLen;             /* 2s complement of buffer length    */
+          u16 Len;                /* packet length                     */
+        } LANCE_RxDescr;
+
+#define RXDSCR_FLAGS_OWN   0x8000 /* LANCE owns descriptor             */
+#define RXDSCR_FLAGS_ERR   0x4000 /* summary error flag                */
+#define RXDSCR_FLAGS_FRAM  0x2000 /* framing error flag                */
+#define RXDSCR_FLAGS_OFLO  0x1000 /* FIFO overflow?                    */
+#define RXDSCR_FLAGS_CRC   0x0800 /* CRC error?                        */
+#define RXDSCR_FLAGS_BUFF  0x0400 /* buffer error?                     */
+#define RXDSCR_FLAGS_STP   0x0200 /* first packet in chain?            */
+#define RXDCSR_FLAGS_ENP   0x0100 /* last packet in chain?             */
+
+/* RAM layout */
+
+#define TXCOUNT            4      /* length of TX descriptor queue     */
+#define LTXCOUNT           2      /* log2 of it                        */
+#define RXCOUNT            4      /* length of RX descriptor queue     */
+#define LRXCOUNT           2      /* log2 of it                        */
+
+#define RAM_INITBASE       0      /* LANCE init block                  */
+#define RAM_TXBASE         24     /* Start of TX descriptor queue      */
+#define RAM_RXBASE         \
+(RAM_TXBASE + (TXCOUNT * 8))      /* Start of RX descriptor queue      */
+#define RAM_DATABASE       \
+(RAM_RXBASE + (RXCOUNT * 8))      /* Start of data area for frames     */
+#define RAM_BUFSIZE        1580   /* max. frame size - should never be
+                                     reached                           */
+
+#endif /* _SK_MCA_DRIVER_ */
+
+extern int skmca_probe(struct device *);
+
+
+#endif /* _SK_MCA_INCLUDE_ */
\ No newline at end of file
index ca93037a87c8f4801d52a4f8a06e268b9db2b642..ed0b2ab3e52d4fd3d23e37581adb13ece7e85958 100644 (file)
@@ -535,9 +535,11 @@ struct pci_dev_info dev_info[] = {
        DEVICE( INTEL,          INTEL_82450GX,  "82450GX Orion P6"),
        DEVICE( KTI,            KTI_ET32P2,     "ET32P2"),
        DEVICE( ADAPTEC,        ADAPTEC_7810,   "AIC-7810 RAID"),
+       DEVICE( ADAPTEC,        ADAPTEC_7821,   "AIC-7860"),
        DEVICE( ADAPTEC,        ADAPTEC_7850,   "AIC-7850"),
        DEVICE( ADAPTEC,        ADAPTEC_7855,   "AIC-7855"),
        DEVICE( ADAPTEC,        ADAPTEC_5800,   "AIC-5800"),
+       DEVICE( ADAPTEC,        ADAPTEC_3860,   "AIC-7860"),
        DEVICE( ADAPTEC,        ADAPTEC_7860,   "AIC-7860"),
        DEVICE( ADAPTEC,        ADAPTEC_7861,   "AIC-7861"),
        DEVICE( ADAPTEC,        ADAPTEC_7870,   "AIC-7870"),
@@ -551,13 +553,26 @@ struct pci_dev_info dev_info[] = {
        DEVICE( ADAPTEC,        ADAPTEC_7882,   "AIC-7882U"),
        DEVICE( ADAPTEC,        ADAPTEC_7883,   "AIC-7883U"),
        DEVICE( ADAPTEC,        ADAPTEC_7884,   "AIC-7884U"),
+       DEVICE( ADAPTEC,        ADAPTEC_7885,   "AIC-7885U"),
+       DEVICE( ADAPTEC,        ADAPTEC_7886,   "AIC-7886U"),
+       DEVICE( ADAPTEC,        ADAPTEC_7887,   "AIC-7887U"),
+       DEVICE( ADAPTEC,        ADAPTEC_7888,   "AIC-7888U"),
        DEVICE( ADAPTEC,        ADAPTEC_1030,   "ABA-1030 DVB receiver"),
        DEVICE( ADAPTEC2,       ADAPTEC2_2940U2,"AHA-2940U2"),
-       DEVICE( ADAPTEC2,       ADAPTEC2_78902, "AIC-7890/1"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_2930U2,"AHA-2930U2"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7890B, "AIC-7890/1"),
        DEVICE( ADAPTEC2,       ADAPTEC2_7890,  "AIC-7890/1"),
        DEVICE( ADAPTEC2,       ADAPTEC2_3940U2,"AHA-3940U2"),
        DEVICE( ADAPTEC2,       ADAPTEC2_3950U2D,"AHA-3950U2D"),
        DEVICE( ADAPTEC2,       ADAPTEC2_7896,  "AIC-7896/7"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7892A, "AIC-7892"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7892B, "AIC-7892"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7892D, "AIC-7892"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7892P, "AIC-7892"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7899A, "AIC-7899"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7899B, "AIC-7899"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7899D, "AIC-7899"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_7899P, "AIC-7899"),
        DEVICE( ATRONICS,       ATRONICS_2015,  "IDE-2015PL"),
        DEVICE( TIGERJET,       TIGERJET_300,   "Tiger300 ISDN"),
        DEVICE( ARK,            ARK_STING,      "Stingray"),
index 72bec263f091f6adc7919ec19047a1277046c2ac..fe064c0348623f75dc032d5f8905b8ed7a3ff647 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/config.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
index 531222b5c81a6845b815e8dfb5642d64aed2d5c7..e5c31c787e25ee8aeabb2b465d887f82e57d3836 100644 (file)
@@ -25,10 +25,8 @@ dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
 dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
-    bool '   Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
-    if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
-      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24
-    fi
+    bool '   Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+    int  '   Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
     bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
     int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
 fi
index bbeeeb2f634fa267e72a555bfa026f75e399ccd7..0497bbb10f115f6af2f70bbc193059302d7aa75f 100644 (file)
@@ -17,6 +17,10 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     AHA-274xT               
     AHA-2842
     AHA-2910B               
+    AHA-2920C
+    AHA-2930
+    AHA-2930U
+    AHA-2930U2
     AHA-2940               
     AHA-2940W              
     AHA-2940U              
@@ -77,8 +81,8 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     Adaptec Cards
     ----------------------------
     AHA-2920 (Only the cards that use the Future Domain chipset are not
-              supported, any 2920 cards based on Adaptec AIC chipsets are
-             supported)
+              supported, any 2920 cards based on Adaptec AIC chipsets,
+             such as the 2920C, are supported)
     AAA-13x Raid Adapters
     AAA-113x Raid Port Card
 
@@ -108,7 +112,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     Jess Johnson    jester@frenzy.com
       (AIC7xxx FAQ author)
     Doug Ledford    dledford@redhat.com
-      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer)
+      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer)
     
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
     author of the driver. John has since retired from the project. Thanks
@@ -325,11 +329,12 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
        list and someone can help you out.
 
     "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable
-        tagged queueing on specific devices.  As of driver version 5.1.8, we
-        now globally enable tagged queueing by default.  In order to
-        disable tagged queueing for certian devices at boot time, a user may
-        use this boot param.  The driver will then parse this message out
-        and disable the specific device entries that are present based upon
+        or enable Tagged Command Queueing (TCQ) on specific devices.  As of
+       driver version 5.1.11, TCQ is now either on or off by default
+       according to the setting you choose during the make config process.
+       In order to en/disable TCQ for certian devices at boot time, a user
+       may use this boot param.  The driver will then parse this message out
+        and en/disable the specific device entries that are present based upon
         the value given.  The param line is parsed in the following manner:
 
           { - first instance indicates the start of this parameter values
@@ -419,10 +424,10 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     see this documentation, you need to use one of the advanced configuration
     programs (menuconfig and xconfig).  If you are using the "make menuconfig"
     method of configuring your kernel, then you would simply highlight the
-    option in question and hit the F1 key.  If you are using the "make xconfig"
-    method of configuring your kernel, then simply click on the help button next
-    to the option you have questions about.  The help information from the
-    Configure.help file will then get automatically displayed.
+    option in question and hit the ? key.  If you are using the "make xconfig"
+    method of configuring your kernel, then simply click on the help button
+    next to the option you have questions about.  The help information from
+    the Configure.help file will then get automatically displayed.
 
   /proc support
   ------------------------------
index e5907b67ae4e95104be344f99eebd9506bec98fd..df7fa30e63a8e23eac1d76ba1d546ed466d542df 100644 (file)
  * under normal conditions.
  */
 
-/*
- * AIC7XXX_FAKE_NEGOTIATION_CMDS
- *   We now have two distinctly different methods of device negotiation
- *   in this code.  The two methods are selected by either defining or not
- *   defining this option.  The difference is as follows:
- *
- *   With AIC7XXX_FAKE_NEGOTIATION_CMDS not set (commented out)
- *     When the driver is in need of issuing a negotiation command for any
- *     given device, it will add the negotiation message on to part of a
- *     regular SCSI command for the device.  In the process, if the device
- *     is configured for and using tagged queueing, then the code will
- *     also issue that single command as a non-tagged command, attach the
- *     negotiation message to that one command, and use a temporary
- *     queue depth of one to keep the untagged and tagged commands from
- *     overlapping.
- *       Pros: This doesn't use any extra SCB structures, it's simple, it
- *         works most of the time (if not all of the time now), and
- *         since we get the device capability info frmo the INQUIRY data
- *         now, shouldn't cause any problems.
- *       Cons: When we need to send a negotiation command to a device, we
- *         must use a command that is being sent to LUN 0 of the device.
- *         If we try sending one to high LUN numbers, then some devices
- *         get noticeably upset.  Since we have to wait for a command with
- *         LUN == 0 to come along, we may not be able to renegotiate when
- *         we want if the user is actually using say LUN 1 of a CD Changer
- *         instead of using LUN 0 for an extended period of time.
- *
- *   With AIC7XXX_FAKE_NEGOTIATION_CMDS defined
- *     When we need to negotiate with a device, instead of attaching our
- *     negotiation message to an existing command, we insert our own
- *     fictional Scsi_Cmnd into the chain that has the negotiation message
- *     attached to it.  We send this one command as untagged regardless
- *     of the device type, and we fiddle with the queue depth the same as
- *     we would with the option unset to avoid overlapping commands.  The
- *     primary difference between this and the unset option is that the
- *     negotiation message is no longer attached to a specific command,
- *     instead it is its own command and is merely triggered by a
- *     combination of both A) We need to negotiate and B) The mid level
- *     SCSI code has sent us a command.  We still don't do any negotiation
- *     unless there is a valid SCSI command to be processed.
- *       Pros: This fixes the problem above in the Cons section.  Since we
- *         issue our own fake command, we can set the LUN to 0 regardless
- *         of what the LUN is in the real command.  It also means that if
- *         the device get's nasty over negotiation issues, it won't be
- *         showing up on a regular command, so we won't get any SENSE buffer
- *         data or STATUS_BYTE returns to the mid level code that are caused
- *         by snits in the negotiation code.
- *       Cons: We add more code, and more complexity.  This means more ways
- *         in which things could break.  It means a larger driver.  It means
- *         more resource consumption for the fake commands.  However, the
- *         biggest problem is this.  Take a system where there is a CD-ROM
- *         on the SCSI bus.  Someone has a CD in the CD-ROM and is using it.
- *         For some reason the SCSI bus gets reset.  We don't touch the
- *         CD-ROM again for quite a period of time (so we don't renegotiate
- *         after the reset until we do touch the CD-ROM again).  In the
- *         time while we aren't using the CD-ROM, the current disc is
- *         removed and a new one put in.  When we go to check that disc, we
- *         will first have to renegotiate.  In so doing, we issue our fake
- *         SCSI command, which happens to be TEST_UNIT_READY.  The CD-ROM
- *         negotiates with us, then responds to our fake command with a
- *         CHECK_CONDITION status.  We REQUEST_SENSE from the CD-ROM, it
- *         then sends the SENSE data to our fake command to tell it that
- *         it has been through a disc change.  There, now we've cleared out
- *         the SENSE data along with our negotiation command, and when the
- *         real command executes, it won't pick up that the CD was changed.
- *         That's the biggest Con to this approach.  In the future, I could
- *         probably code around this problem though, so this option is still
- *         viable.
- *
- *  So, which command style should you use?  I would appreciate it if people
- *  could try out both types.  I want to know about any cases where one
- *  method works and the other doesn't.  If one method works on significantly
- *  more systems than another, then it will become the default.  If the second
- *  option turns out to work best, then I'll find a way to work around that
- *  big con I listed.
- *
- *  -- July 7, 02:33
- *    OK...I just added some code that should make the Con listed for the
- *    fake commands a non issue now.  However, it needs testing.  For now,
- *    I'm going to make the default to use the fake commands, we'll see how
- *    it goes.
- */
-#define AIC7XXX_FAKE_NEGOTIATION_CMDS
-
 /*
  * AIC7XXX_STRICT_PCI_SETUP
  *   Should we assume the PCI config options on our controllers are set with
 #include "aic7xxx/sequencer.h"
 #include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
+#include <scsi/scsicam.h>
 
 #include <linux/stat.h>
 #include <linux/malloc.h>        /* for kmalloc() */
@@ -354,7 +270,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.10"
+#define AIC7XXX_C_VERSION  "5.1.17"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -447,10 +363,10 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
-#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
 #else
-#define AIC7XXX_CMDS_PER_LUN 24
+#define AIC7XXX_CMDS_PER_DEVICE 8
 #endif
 
 /* Set this to the delay in seconds after SCSI bus reset. */
@@ -495,7 +411,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  *
  * *** Determining commands per LUN ***
  * 
- * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
+ * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
  * own algorithm to determine the commands/LUN.  If SCB paging is
  * enabled, which is always now, the default is 8 commands per lun
  * that indicates it supports tagged queueing.  All non-tagged devices
@@ -513,8 +429,13 @@ typedef struct
  * Make a define that will tell the driver not to use tagged queueing
  * by default.
  */
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
+                              0, 0, 0, 0, 0, 0, 0, 0}
+#else
 #define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
                               255, 255, 255, 255, 255, 255, 255, 255}
+#endif
 
 /*
  * Modify this as you see fit for your system.  By setting tag_commands
@@ -553,6 +474,27 @@ adapter_tag_info_t aic7xxx_tag_info[] =
 };
 */
 
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS}
+};
+
+
 /*
  * Define an array of board names that can be indexed by aha_type.
  * Don't forget to change this when changing the types!
@@ -579,11 +521,14 @@ static const char *board_names[] = {
   "Adaptec AHA-2944 Ultra SCSI host adapter",           /* AIC_7884 */
   "Adaptec AIC-7895 Ultra SCSI host adapter",           /* AIC_7895 */
   "Adaptec AIC-7890/1 Ultra2 SCSI host adapter",        /* AIC_7890 */
+  "Adaptec AHA-293X Ultra2 SCSI host adapter",          /* AIC_7890 */
   "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
   "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
   "Adaptec AHA-394X Ultra2 SCSI host adapter",          /* AIC_7897 */
   "Adaptec AHA-395X Ultra2 SCSI host adapter",          /* AIC_7897 */
   "Adaptec PCMCIA SCSI controller",                     /* card bus stuff */
+  "Adaptec AIC-7892 Ultra 160/m SCSI host adapter",     /* AIC_7892 */
+  "Adaptec AIC-7899 Ultra 160/m SCSI host adapter",     /* AIC_7899 */
 };
 
 /*
@@ -851,15 +796,17 @@ typedef enum {
         SCB_DEVICE_RESET        = 0x0020,
         SCB_RESET               = 0x0040,
         SCB_RECOVERY_SCB        = 0x0080,
-        SCB_WAS_BUSY            = 0x0100,
+        SCB_MSGOUT_PPR          = 0x0100,
         SCB_MSGOUT_SENT         = 0x0200,
         SCB_MSGOUT_SDTR         = 0x0400,
         SCB_MSGOUT_WDTR         = 0x0800,
-        SCB_MSGOUT_BITS         = SCB_MSGOUT_SENT | 
+        SCB_MSGOUT_BITS         = SCB_MSGOUT_PPR |
+                                  SCB_MSGOUT_SENT | 
                                   SCB_MSGOUT_SDTR |
                                   SCB_MSGOUT_WDTR,
         SCB_QUEUED_ABORT        = 0x1000,
-        SCB_QUEUED_FOR_DONE     = 0x2000
+        SCB_QUEUED_FOR_DONE     = 0x2000,
+        SCB_WAS_BUSY            = 0x4000
 } scb_flag_type;
 
 typedef enum {
@@ -913,6 +860,8 @@ typedef enum {
   AHC_AIC7890          = 0x0006,
   AHC_AIC7895          = 0x0007,
   AHC_AIC7896          = 0x0008,
+  AHC_AIC7892          = 0x0009,
+  AHC_AIC7899          = 0x000a,
   AHC_VL               = 0x0100,
   AHC_EISA             = 0x0200,
   AHC_PCI              = 0x0400,
@@ -929,6 +878,7 @@ typedef enum {
   AHC_QUEUE_REGS       = 0x0040,
   AHC_SG_PRELOAD       = 0x0080,
   AHC_SPIOCAP          = 0x0100,
+  AHC_ULTRA3           = 0x0200,
   AHC_AIC7770_FE       = AHC_FENONE,
   AHC_AIC7850_FE       = AHC_SPIOCAP,
   AHC_AIC7860_FE       = AHC_ULTRA|AHC_SPIOCAP,
@@ -938,6 +888,8 @@ typedef enum {
                          AHC_QUEUE_REGS|AHC_SG_PRELOAD,
   AHC_AIC7895_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
   AHC_AIC7896_FE       = AHC_AIC7890_FE,
+  AHC_AIC7892_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
+  AHC_AIC7899_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
 } ahc_feature;
 
 struct aic7xxx_scb {
@@ -1014,9 +966,12 @@ typedef struct {
   unsigned char goal_period;
   unsigned char cur_offset;
   unsigned char goal_offset;
+  unsigned char cur_options;
+  unsigned char goal_options;
   unsigned char user_width;
   unsigned char user_period;
   unsigned char user_offset;
+  unsigned char user_options;
 } transinfo_type;
 
 /*
@@ -1045,10 +1000,11 @@ struct aic7xxx_host {
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
   scb_data_type           *scb_data;
+  volatile unsigned short  needdv;
+  volatile unsigned short  needppr;
   volatile unsigned short  needsdtr;
-  volatile unsigned short  sdtr_pending;
   volatile unsigned short  needwdtr;
-  volatile unsigned short  wdtr_pending;
+  volatile unsigned short  dtr_pending;
   struct aic7xxx_cmd_queue {
     Scsi_Cmnd *head;
     Scsi_Cmnd *tail;
@@ -1071,9 +1027,10 @@ struct aic7xxx_host {
 #define  DEVICE_PRESENT                 0x01
 #define  BUS_DEVICE_RESET_PENDING       0x02
 #define  DEVICE_RESET_DELAY             0x04
-#define  DEVICE_PRINT_SDTR              0x08
-#define  DEVICE_PRINT_WDTR              0x10
+#define  DEVICE_PRINT_DTR               0x08
+#define  DEVICE_PARITY_ERROR            0x10
 #define  DEVICE_WAS_BUSY                0x20
+#define  DEVICE_SCSI_3                  0x40
 #define  DEVICE_SCANNED                 0x80
   volatile unsigned char   dev_flags[MAX_TARGETS];
   volatile unsigned char   dev_active_cmds[MAX_TARGETS];
@@ -1090,11 +1047,10 @@ struct aic7xxx_host {
 #endif
 
 
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
-  Scsi_Cmnd               *dev_wdtr_cmnd[MAX_TARGETS];
-  Scsi_Cmnd               *dev_sdtr_cmnd[MAX_TARGETS];
-#endif
+  Scsi_Cmnd               *dev_dtr_cmnd[MAX_TARGETS];
 
+  unsigned int             dev_checksum[MAX_TARGETS];
+  
   unsigned char            dev_last_queue_full[MAX_TARGETS];
   unsigned char            dev_last_queue_full_count[MAX_TARGETS];
   unsigned char            dev_max_queue_depth[MAX_TARGETS];
@@ -1102,7 +1058,7 @@ struct aic7xxx_host {
   volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
 
 
-  unsigned char            msg_buf[9];       /* The message for the target */
+  unsigned char            msg_buf[13];      /* The message for the target */
   unsigned char            msg_type;
 #define MSG_TYPE_NONE              0x00
 #define MSG_TYPE_INITIATOR_MSGOUT  0x01
@@ -1132,6 +1088,7 @@ struct aic7xxx_host {
   int                      scsi_id_b;        /* channel B for twin adapters */
   unsigned int             bios_address;
   int                      board_name_index;
+  unsigned short           needppr_copy;     /* default config */
   unsigned short           needsdtr_copy;    /* default config */
   unsigned short           needwdtr_copy;    /* default config */
   unsigned short           ultraenb;         /* Ultra mode target list */
@@ -1192,9 +1149,12 @@ struct aic7xxx_host {
  * Provides a mapping of transfer periods in ns/4 to the proper value to
  * stick in the SCSIRATE reg to use that transfer rate.
  */
-#define AHC_SYNCRATE_ULTRA2 0
-#define AHC_SYNCRATE_ULTRA  2
-#define AHC_SYNCRATE_FAST   5
+#define AHC_SYNCRATE_ULTRA3 0
+#define AHC_SYNCRATE_ULTRA2 1
+#define AHC_SYNCRATE_ULTRA  3
+#define AHC_SYNCRATE_FAST   6
+#define AHC_SYNCRATE_CRC 0x40
+#define AHC_SYNCRATE_SE  0x10
 static struct aic7xxx_syncrate {
   /* Rates in Ultra mode have bit 8 of sxfr set */
 #define                ULTRA_SXFR 0x100
@@ -1203,6 +1163,7 @@ static struct aic7xxx_syncrate {
   unsigned char period;
   const char *rate[2];
 } aic7xxx_syncrates[] = {
+  { 0x42,  0x000,   9,  {"80.0", "160.0"} },
   { 0x13,  0x000,  10,  {"40.0", "80.0"} },
   { 0x14,  0x000,  11,  {"33.0", "66.6"} },
   { 0x15,  0x100,  12,  {"20.0", "40.0"} },
@@ -1410,35 +1371,6 @@ static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
 
 #endif
 
-/*
- * See the comments earlier in the file for what this item is all about
- * If you have more than 4 controllers, you will need to increase the
- * the number of items in the array below.  Additionally, if you don't
- * want to have lilo pass a humongous config line to the aic7xxx driver,
- * then you can get in and manually adjust these instead of leaving them
- * at the default.  Pay attention to the comments earlier in this file
- * concerning this array if you are going to hand modify these values.
- */
-static adapter_tag_info_t aic7xxx_tag_info[] =
-{
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS}
-};
-
 #define VERBOSE_NORMAL         0x0000
 #define VERBOSE_NEGOTIATION    0x0001
 #define VERBOSE_SEQINT         0x0002
@@ -1920,6 +1852,7 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
       aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
       aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
       aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
+      udelay(15);
       break;
 
     default:
@@ -2084,28 +2017,101 @@ aic7xxx_info(struct Scsi_Host *dooh)
  *-F*************************************************************************/
 static struct aic7xxx_syncrate *
 aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
-  unsigned int maxsync)
+  unsigned int maxsync, unsigned char *options)
 {
   struct aic7xxx_syncrate *syncrate;
+  int done = FALSE;
 
+  switch(*options)
+  {
+    case MSG_EXT_PPR_OPTION_DT_CRC:
+    case MSG_EXT_PPR_OPTION_DT_UNITS:
+      if(!(p->features & AHC_ULTRA3))
+      {
+        *options = 0;
+        maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+      }
+      break;
+    case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+    case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+      if(!(p->features & AHC_ULTRA3))
+      {
+        *options = 0;
+        maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+      }
+      else
+      {
+        /*
+         * we don't support the Quick Arbitration variants of dual edge
+         * clocking.  As it turns out, we want to send back the
+         * same basic option, but without the QA attribute.
+         * We know that we are responding because we would never set
+         * these options ourself, we would only respond to them.
+         */
+        switch(*options)
+        {
+          case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+            *options = MSG_EXT_PPR_OPTION_DT_CRC;
+            break;
+          case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+            *options = MSG_EXT_PPR_OPTION_DT_UNITS;
+            break;
+        }
+      }
+      break;
+    default:
+      *options = 0;
+      maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+      break;
+  }
   syncrate = &aic7xxx_syncrates[maxsync];
   while ( (syncrate->rate[0] != NULL) &&
          (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) )
   {
-    if ( *period <= syncrate->period )
+    if (*period <= syncrate->period) 
     {
-      /*
-       * When responding to a target that requests sync, the requested rate
-       * may fall between two rates that we can output, but still be a rate
-       * that we can receive.  Because of this, we want to respond with the
-       * same rate that it sent to us even if the persiod we use to send
-       * data to it is lower.  Only lower the response period if we must.
-       */
-      if(syncrate == &aic7xxx_syncrates[maxsync])
+      switch(*options)
+      {
+        case MSG_EXT_PPR_OPTION_DT_CRC:
+        case MSG_EXT_PPR_OPTION_DT_UNITS:
+          if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+          {
+            done = TRUE;
+            /*
+             * oops, we went too low for the CRC/DualEdge signalling, so
+             * clear the options byte
+             */
+            *options = 0;
+            /*
+             * We'll be sending a reply to this packet to set the options
+             * properly, so unilaterally set the period as well.
+             */
+            *period = syncrate->period;
+          }
+          else
+          {
+            done = TRUE;
+            if(syncrate == &aic7xxx_syncrates[maxsync])
+            {
+              *period = syncrate->period;
+            }
+          }
+          break;
+        default:
+          if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+          {
+            done = TRUE;
+            if(syncrate == &aic7xxx_syncrates[maxsync])
+            {
+              *period = syncrate->period;
+            }
+          }
+          break;
+      }
+      if(done)
       {
-        *period = syncrate->period;
+        break;
       }
-      break;
     }
     syncrate++;
   }
@@ -2115,6 +2121,7 @@ aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
     /*
      * Use async transfers for this target
      */
+    *options = 0;
     *period = 0;
     syncrate = NULL;
   }
@@ -2135,7 +2142,7 @@ aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate,
 {
   struct aic7xxx_syncrate *syncrate;
 
-  if ((p->features & AHC_ULTRA2) != 0)
+  if (p->features & AHC_ULTRA2)
   {
     scsirate &= SXFR_ULTRA2;
   }
@@ -2147,12 +2154,14 @@ aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate,
   syncrate = &aic7xxx_syncrates[maxsync];
   while (syncrate->rate[0] != NULL)
   {
-    if ((p->features & AHC_ULTRA2) != 0)
+    if (p->features & AHC_ULTRA2)
     {
       if (syncrate->sxfr_ultra2 == 0)
         break;
       else if (scsirate == syncrate->sxfr_ultra2)
         return (syncrate->period);
+      else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC))
+        return (syncrate->period);
     }
     else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR))
     {
@@ -2206,11 +2215,11 @@ aic7xxx_validate_offset(struct aic7xxx_host *p,
 static void
 aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
     int target, int channel, unsigned int period, unsigned int offset,
-    unsigned int type)
+    unsigned char options, unsigned int type)
 {
   unsigned char tindex;
   unsigned short target_mask;
-  unsigned char lun;
+  unsigned char lun, old_options;
   unsigned int old_period, old_offset;
 
   tindex = target | (channel << 3);
@@ -2225,6 +2234,7 @@ aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
 
   old_period = p->transinfo[tindex].cur_period;
   old_offset = p->transinfo[tindex].cur_offset;
+  old_options = p->transinfo[tindex].cur_options;
 
   
   if (type & AHC_TRANS_CUR)
@@ -2237,7 +2247,18 @@ aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
       scsirate &= ~SXFR_ULTRA2;
       if (syncrate != NULL)
       {
-        scsirate |= syncrate->sxfr_ultra2;
+        switch(options)
+        {
+          case MSG_EXT_PPR_OPTION_DT_UNITS:
+            /*
+             * mask off the CRC bit in the xfer settings
+             */
+            scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC);
+            break;
+          default:
+            scsirate |= syncrate->sxfr_ultra2;
+            break;
+        }
       }
       if (type & AHC_TRANS_ACTIVE)
       {
@@ -2278,9 +2299,10 @@ aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
     aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
     p->transinfo[tindex].cur_period = period;
     p->transinfo[tindex].cur_offset = offset;
+    p->transinfo[tindex].cur_options = options;
     if ( !(type & AHC_TRANS_QUITE) &&
          (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
-         (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+         (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
     {
       if (offset)
       {
@@ -2295,7 +2317,7 @@ aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
         printk(INFO_LEAD "Using asynchronous transfers.\n",
                p->host_no, channel, target, lun);
       }
-      p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+      p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
     }
   }
 
@@ -2303,12 +2325,14 @@ aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
   {
     p->transinfo[tindex].goal_period = period;
     p->transinfo[tindex].goal_offset = offset;
+    p->transinfo[tindex].goal_options = options;
   }
 
   if (type & AHC_TRANS_USER)
   {
     p->transinfo[tindex].user_period = period;
     p->transinfo[tindex].user_offset = offset;
+    p->transinfo[tindex].user_options = options;
   }
 }
 
@@ -2325,20 +2349,13 @@ aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun,
 {
   unsigned char tindex;
   unsigned short target_mask;
-  unsigned int old_width, new_offset;
+  unsigned int old_width;
 
   tindex = target | (channel << 3);
   target_mask = 1 << tindex;
   
   old_width = p->transinfo[tindex].cur_width;
 
-  if (p->features & AHC_ULTRA2)
-    new_offset = MAX_OFFSET_ULTRA2;
-  else if (width == MSG_EXT_WDTR_BUS_16_BIT)
-    new_offset = MAX_OFFSET_16BIT;
-  else
-    new_offset = MAX_OFFSET_8BIT;
-  
   if (type & AHC_TRANS_CUR) 
   {
     unsigned char scsirate;
@@ -2356,12 +2373,12 @@ aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun,
 
     p->transinfo[tindex].cur_width = width;
 
-    if ((aic7xxx_verbose & VERBOSE_NEGOTIATION2) && 
-        (p->dev_flags[tindex] & DEVICE_PRINT_WDTR))
+    if ( !(type & AHC_TRANS_QUITE) &&
+          (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && 
+          (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
     {
       printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target,
         lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" );
-      p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
     }
   }
 
@@ -2370,14 +2387,21 @@ aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun,
   if (type & AHC_TRANS_USER)
     p->transinfo[tindex].user_width = width;
 
-  /*
-   * Having just set the width, the SDTR should come next, and we need a valid
-   * offset for the SDTR.  So, we make sure we put a valid one in here now as
-   * the goal_offset.
-   */
   if (p->transinfo[tindex].goal_offset)
-    p->transinfo[tindex].goal_offset = new_offset;
-
+  {
+    if (p->features & AHC_ULTRA2)
+    {
+      p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+    }
+    else if (width == MSG_EXT_WDTR_BUS_16_BIT)
+    {
+      p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+    }
+    else
+    {
+      p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+    }
+  }
 }
       
 /*+F*************************************************************************
@@ -2543,14 +2567,6 @@ aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
   if (match != 0)
     match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
 
-  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
-  {
-    printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) %s search criteria"
-      " (scsi%d:%d:%d:%d:tag%d)\n", p->host_no, CTL_OF_SCB(scb),
-      scb->hscb->tag, (match) ? "matches" : "doesn't match",
-      p->host_no, channel, target, lun, tag);
-  }
-
   return (match);
 }
 
@@ -2584,14 +2600,13 @@ aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
  *   to the free list.
  *-F*************************************************************************/
 static unsigned char
-aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr,
+                               unsigned char prev)
 {
   unsigned char next;
-  unsigned char prev;
 
   aic_outb(p, scbptr, SCBPTR);
   next = aic_inb(p, SCB_NEXT);
-  prev = aic_inb(p, SCB_PREV);
   aic7xxx_add_curscb_to_free_list(p);
 
   if (prev != SCB_LIST_NULL)
@@ -2604,11 +2619,6 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
     aic_outb(p, next, DISCONNECTED_SCBH);
   }
 
-  if (next != SCB_LIST_NULL)
-  {
-    aic_outb(p, next, SCBPTR);
-    aic_outb(p, prev, SCB_PREV);
-  }
   return next;
 }
 
@@ -2755,7 +2765,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
          * Place in the scb array; never is removed
          */
         p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
-        scbq_insert_head(&p->scb_data->free_scbs, scbp);
+        scbq_insert_tail(&p->scb_data->free_scbs, scbp);
       }
       scbp->kmalloc_ptr = scb_ap;
     }
@@ -2796,6 +2806,7 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
   Scsi_Cmnd *cmd;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
   unsigned int cpu_flags = 0;
+#endif
   
   DRIVER_LOCK
   while (p->completeq.head != NULL)
@@ -2803,20 +2814,9 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    sti();
     cmd->scsi_done(cmd);
-    cli();
   }
   DRIVER_UNLOCK
-#else
-  while (p->completeq.head != NULL)
-  {
-    cmd = p->completeq.head;
-    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
-    cmd->host_scribble = NULL;
-    cmd->scsi_done(cmd);
-  }
-#endif
 }
 
 /*+F*************************************************************************
@@ -2889,16 +2889,13 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       }
 #define WIDE_INQUIRY_BITS 0x60
 #define SYNC_INQUIRY_BITS 0x10
+#define SCSI_VERSION_BITS 0x07
       if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
            (p->features & AHC_WIDE) )
       {
         p->needwdtr |= (1<<tindex);
         p->needwdtr_copy |= (1<<tindex);
-        if ( (p->flags & AHC_SEEPROM_FOUND) &&
-             (p->transinfo[tindex].user_width != MSG_EXT_WDTR_BUS_16_BIT) )
-          p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
-        else
-          p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
+        p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
       }
       else
       {
@@ -2916,28 +2913,10 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         p->needsdtr |= (1<<tindex);
         p->needsdtr_copy |= (1<<tindex);
 
-        if (p->flags & AHC_SEEPROM_FOUND)
+        p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+        p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+        if (p->transinfo[tindex].user_offset)
         {
-          p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-          p->transinfo[tindex].goal_offset = p->transinfo[tindex].user_offset;
-        }
-        else
-        {
-          if (p->features & AHC_ULTRA2)
-          {
-            p->transinfo[tindex].goal_period =
-              aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
-          }
-          else if (p->features & AHC_ULTRA)
-          {
-            p->transinfo[tindex].goal_period =
-              aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
-          }
-          else
-          {
-            p->transinfo[tindex].goal_period =
-              aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
-          }
           if (p->features & AHC_ULTRA2)
             p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
           else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
@@ -2952,14 +2931,57 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         p->needsdtr_copy &= ~(1<<tindex);
         p->transinfo[tindex].goal_period = 0;
         p->transinfo[tindex].goal_offset = 0;
+        p->transinfo[tindex].goal_options = 0;
+      }
+      if ( (buffer[2] & SCSI_VERSION_BITS) == 3 )
+      {
+        p->dev_flags[tindex] |= DEVICE_SCSI_3;
+        /*
+         * OK, we are a SCSI 3 device and we are in need of negotiation.
+         * Use PPR messages instead of WDTR and SDTR messages.
+         */
+        if ( (p->needsdtr & (1<<tindex)) ||
+             (p->needwdtr & (1<<tindex)) )
+        {
+          p->needppr |= (1<<tindex);
+          p->needppr_copy |= (1<<tindex);
+        }
+        p->needwdtr &= ~(1<<tindex);
+        p->needwdtr_copy &= ~(1<<tindex);
+        p->needsdtr &= ~(1<<tindex);
+        p->needsdtr_copy &= ~(1<<tindex);
+      }
+      /*
+       * Get the INQUIRY checksum.  We use this on Ultra 160/m
+       * and older devices both.  It allows us to drop speed on any bus type
+       * while at the same time giving us the needed domain validation for
+       * Ultra 160/m
+       *
+       * Note: We only get the checksum and set the SCANNED bit if this is
+       * one of our dtr commands.  If we don't do this, then we end up
+       * getting bad checksum results on the mid-level SCSI code's INQUIRY
+       * commands.
+       */
+      if(p->dev_dtr_cmnd[tindex] == cmd) {
+        unsigned int checksum = 0;
+        int *ibuffer;
+        int i=0;
+
+        ibuffer = (int *)buffer;
+        for( i = 0; i < (cmd->request_bufflen >> 2); i++)
+        {
+          checksum += ibuffer[i];
+        }
+        p->dev_checksum[tindex] = checksum;
+        p->dev_flags[tindex] |= DEVICE_SCANNED;
+        p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
       }
-      p->dev_flags[tindex] |= DEVICE_SCANNED;
-      p->dev_flags[tindex] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
 #undef WIDE_INQUIRY_BITS
 #undef SYNC_INQUIRY_BITS
+#undef SCSI_VERSION_BITS
     }
   }
-  else if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+  else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
@@ -2979,11 +3001,11 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 
     if (scb->flags & SCB_MSGOUT_WDTR)
     {
-      p->wdtr_pending &= ~mask;
+      p->dtr_pending &= ~mask;
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
         {
           printk(INFO_LEAD "Device failed to complete Wide Negotiation "
             "processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -2991,7 +3013,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
             "disabling future\n", p->host_no, CTL_OF_SCB(scb));
           printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
             CTL_OF_SCB(scb));
-          p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
         }
         p->needwdtr &= ~mask;
         p->needwdtr_copy &= ~mask;
@@ -2999,11 +3020,11 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     }
     if (scb->flags & SCB_MSGOUT_SDTR)
     {
-      p->sdtr_pending &= ~mask;
+      p->dtr_pending &= ~mask;
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
         {
           printk(INFO_LEAD "Device failed to complete Sync Negotiation "
             "processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -3011,12 +3032,38 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
             "disabling future\n", p->host_no, CTL_OF_SCB(scb));
           printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
             CTL_OF_SCB(scb));
-          p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
         }
         p->needsdtr &= ~mask;
         p->needsdtr_copy &= ~mask;
       }
     }
+    if (scb->flags & SCB_MSGOUT_PPR)
+    {
+      p->dtr_pending &= ~mask;
+      if(message_error)
+      {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Parallel Protocol "
+            "Request processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Parallel Protocol Request negotiation to this "
+            "device.\n", p->host_no, CTL_OF_SCB(scb));
+        }
+        /*
+         * Disable PPR negotiation and revert back to WDTR and SDTR setup
+         */
+        p->needppr &= ~mask;
+        p->needppr_copy &= ~mask;
+        p->needsdtr |= mask;
+        p->needsdtr_copy |= mask;
+        p->needwdtr |= mask;
+        p->needwdtr_copy |= mask;
+      }
+    }
   }
   queue_depth = p->dev_temp_queue_depth[tindex];
   if (queue_depth >= p->dev_active_cmds[tindex])
@@ -3058,16 +3105,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   p->dev_active_cmds[tindex]--;
   p->activescbs--;
 
-  /*
-   * If this was an untagged I/O, unbusy the target so the sequencer won't
-   * mistake things later
-   */
-  if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
-      scb->hscb->tag)
-  {
-    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
-  }
-
   {
     int actual;
 
@@ -3122,7 +3159,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 #endif /* AIC7XXX_PROC_STATS */
       }
 #ifdef AIC7XXX_PROC_STATS
-      x = -10;
+      x = -11;
       while(actual)
       {
         actual >>= 1;
@@ -3429,11 +3466,10 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
       if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
         printk(INFO_LEAD "Cleaning up status information "
           "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+      p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
       if ( tag == SCB_LIST_NULL )
       {
-        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR |
-                           DEVICE_RESET_DELAY;
+        p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
         p->dev_expires[i] = jiffies + (4 * HZ);
         p->dev_timer_active |= (0x01 << i);
         p->dev_last_queue_full_count[i] = 0;
@@ -3625,7 +3661,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
   if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
     printk(INFO_LEAD "Cleaning disconnected scbs "
       "list.\n", p->host_no, channel, target, lun);
-  if (p->features & AHC_PAGESCBS)
+  if (p->flags & AHC_PAGESCBS)
   {
     unsigned char next, prev, scb_index;
 
@@ -3641,14 +3677,14 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
           "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
           p->scb_data->numscbs);
-        next = aic7xxx_rem_scb_from_disc_list(p, next);
+        next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
       }
       else
       {
         scbp = p->scb_data->scb_array[scb_index];
         if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
-          next = aic7xxx_rem_scb_from_disc_list(p, next);
+          next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
           if (scbp->flags & SCB_WAITINGQ)
           {
             p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
@@ -3677,7 +3713,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
    * Walk the free list making sure no entries on the free list have
    * a valid SCB_TAG value or SCB_CONTROL byte.
    */
-  if (p->features & AHC_PAGESCBS)
+  if (p->flags & AHC_PAGESCBS)
   {
     unsigned char next;
 
@@ -3734,7 +3770,6 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
     {
       aic_outb(p, SCB_LIST_NULL, SCB_TAG);
       aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
-      aic_outb(p, SCB_LIST_NULL, SCB_PREV);
       aic_outb(p, 0, SCB_CONTROL);
       aic7xxx_add_curscb_to_free_list(p);
     }
@@ -3863,28 +3898,35 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
   if (channel == 1)
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
-    p->sdtr_pending &= 0x00FF;
+    p->dtr_pending &= 0x00FF;
     offset_min = 8;
     offset_max = 16;
   }
   else
   {
-    if (p->features & AHC_WIDE)
+    if (p->features & AHC_TWIN)
     {
-      p->needsdtr = p->needsdtr_copy;
-      p->needwdtr = p->needwdtr_copy;
-      p->sdtr_pending = 0x0;
-      p->wdtr_pending = 0x0;
+      /* Channel A */
+      p->needsdtr |= (p->needsdtr_copy & 0x00FF);
+      p->dtr_pending &= 0xFF00;
       offset_min = 0;
-      offset_max = 16;
+      offset_max = 8;
     }
     else
     {
-      /* Channel A */
-      p->needsdtr |= (p->needsdtr_copy & 0x00FF);
-      p->sdtr_pending &= 0xFF00;
+      p->needppr = p->needppr_copy;
+      p->needsdtr = p->needsdtr_copy;
+      p->needwdtr = p->needwdtr_copy;
+      p->dtr_pending = 0x0;
       offset_min = 0;
-      offset_max = 8;
+      if (p->features & AHC_WIDE)
+      {
+        offset_max = 16;
+      }
+      else
+      {
+        offset_max = 8;
+      }
     }
   }
 
@@ -4186,6 +4228,30 @@ aic7xxx_timer(struct aic7xxx_host *p)
 #endif
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_ppr
+ *
+ * Description:
+ *   Build up a Parallel Protocol Request message for use with SCSI-3
+ *   devices.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int tindex = TARGET_INDEX(scb->cmd);
+
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_PPR;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period;
+  p->msg_buf[p->msg_index++] = 0;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options;
+  p->msg_len += 8;
+}
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_construct_sdtr
@@ -4304,10 +4370,10 @@ aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
   /*
    * Go back to async/narrow transfers and renegotiate.
    */
+  p->needppr |= (p->needppr_copy & targ_mask);
   p->needsdtr |= (p->needsdtr_copy & targ_mask);
   p->needwdtr |= (p->needwdtr_copy & targ_mask);
-  p->sdtr_pending &= ~targ_mask;
-  p->wdtr_pending &= ~targ_mask;
+  p->dtr_pending &= ~targ_mask;
   aic_outb(p, 0, TARG_SCSIRATE + tindex);
   if (p->features & AHC_ULTRA2)
     aic_outb(p, 0, TARG_OFFSET + tindex);
@@ -4315,7 +4381,7 @@ aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
   if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
     printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
       target, -1);
-  aic7xxx_run_done_queue(p, /*complete*/ FALSE);
+  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
 }
 
 /*+F*************************************************************************
@@ -4360,6 +4426,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                p->host_no, channel, target, lun,
                aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
                (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+        if (aic7xxx_panic_on_abort)
+          aic7xxx_panic_abort(p, NULL);
       }
       break;
 
@@ -4387,7 +4455,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
 
         aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
-        aic7xxx_run_done_queue(p, FALSE);
+        aic7xxx_run_done_queue(p, TRUE);
 
       }
       break;
@@ -4517,7 +4585,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                   aic7xxx_reset_device(p, target, channel, lun, i);
                   reset++;
                 }
-                aic7xxx_run_done_queue(p, FALSE);
+                aic7xxx_run_done_queue(p, TRUE);
               }
             }
             aic7xxx_verbose = old_verbose;
@@ -4533,6 +4601,51 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
           }
         }
+        else if (scb->flags & SCB_MSGOUT_PPR)
+        {
+          /*
+           * As per the draft specs, any device capable of supporting any of
+           * the option values other than 0 are not allowed to reject the
+           * PPR message.  Instead, they must negotiate out what they do
+           * support instead of rejecting our offering.
+           */
+          p->needppr &= ~target_mask;
+          p->needppr_copy &= ~target_mask;
+          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+            (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+          p->transinfo[tindex].goal_options = 0;
+          p->dtr_pending &= ~target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting PPR messages, falling "
+              "back.\n", p->host_no, channel, target, lun);
+          }
+          if ( p->transinfo[tindex].goal_width )
+          {
+            p->needwdtr |= target_mask;
+            p->needwdtr_copy |= target_mask;
+            p->dtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_WDTR;
+          }
+          if ( p->transinfo[tindex].goal_offset )
+          {
+            p->needsdtr |= target_mask;
+            p->needsdtr_copy |= target_mask;
+            if( !(p->dtr_pending & target_mask) )
+            {
+              p->dtr_pending |= target_mask;
+              scb->flags |= SCB_MSGOUT_SDTR;
+            }
+          }
+          if ( p->dtr_pending & target_mask )
+          {
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+        }
         else if (scb->flags & SCB_MSGOUT_WDTR)
         {
           /*
@@ -4540,20 +4653,18 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
            */
           p->needwdtr &= ~target_mask;
           p->needwdtr_copy &= ~target_mask;
-          p->wdtr_pending &= ~target_mask;
+          p->dtr_pending &= ~target_mask;
           scb->flags &= ~SCB_MSGOUT_BITS;
           aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
             (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
-          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
                                AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-          if ( (p->needsdtr_copy & target_mask) &&
-               !(p->sdtr_pending & target_mask) )
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
-            p->sdtr_pending |= target_mask;
-            scb->flags |= SCB_MSGOUT_SDTR;
-            aic_outb(p, HOST_MSG, MSG_OUT);
-            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+            printk(INFO_LEAD "Device is rejecting WDTR messages, using "
+              "narrow transfers.\n", p->host_no, channel, target, lun);
           }
+          p->needsdtr |= (p->needsdtr_copy & target_mask);
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
@@ -4562,10 +4673,15 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           */
           p->needsdtr &= ~target_mask;
           p->needsdtr_copy &= ~target_mask;
-          p->sdtr_pending &= ~target_mask;
+          p->dtr_pending &= ~target_mask;
           scb->flags &= ~SCB_MSGOUT_SDTR;
-          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
             (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting SDTR messages, using "
+              "async transfers.\n", p->host_no, channel, target, lun);
+          }
         }
         else if (aic7xxx_verbose & VERBOSE_SEQINT)
         {
@@ -4681,41 +4797,24 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                  * However, if this SCB already was attempting to negotiate,
                  * then we assume this isn't the problem and skip this part.
                  */
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
                 if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
                      (p->dev_flags[tindex] & DEVICE_SCANNED) &&
-                     !(p->wdtr_pending & target_mask) && 
-                     !(p->sdtr_pending & target_mask) )
+                     !(p->dtr_pending & target_mask) ) 
                 {
+                  p->needppr |= (p->needppr_copy & target_mask);
                   p->needwdtr |= (p->needwdtr_copy & target_mask);
                   p->needsdtr |= (p->needsdtr_copy & target_mask);
                 }
-                else if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) ||
-                          (scb->cmd == p->dev_sdtr_cmnd[tindex]) )
+                else if ( scb->cmd == p->dev_dtr_cmnd[tindex] )
                 {
                   /*
                    * This is already a negotiation command, so we must have
-                   * already done either WDTR or SDTR (or maybe both).  So
-                   * we simply check sdtr_pending and needsdtr to see if we
-                   * should throw out SDTR on this command.
-                   *
-                   * Note: Don't check the needsdtr_copy here, instead just
-                   * check to see if WDTR wiped out our SDTR and set needsdtr.
-                   * Even if WDTR did wipe out SDTR and set needsdtr, if
-                   * parse_msg() then turned around and started our SDTR
-                   * in back to back fasion, then conclusion of that should
-                   * have negated any needsdtr setting.  That's why we only
-                   * check needsdtr and sdtr_pending.
+                   * already done PPR, WDTR or SDTR.  Since our negotiation
+                   * could have gotten rejected, we don't really know the
+                   * full state of things.  Don't do anything here, and allow
+                   * the negotiation_complete() handler to do the right
+                   * thing.
                    */
-                  scb->flags &= ~SCB_MSGOUT_BITS;
-                  if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) &&
-                       !(p->sdtr_pending & target_mask) &&
-                       (p->needsdtr & target_mask) )
-                  {
-                    p->sdtr_pending |= target_mask;
-                    hscb->control |= MK_MESSAGE;
-                    scb->flags |= SCB_MSGOUT_SDTR;
-                  }
 
                   /*
                    * This is the important part though.  We are getting sense
@@ -4736,43 +4835,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                     hscb->data_pointer = scb->sg_list[0].address;
                   }
                 }
-#else
-                if (  (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
-                     !(scb->flags & SCB_MSGOUT_BITS) && 
-                      (scb->cmd->lun == 0) &&
-                      (p->dev_flags[TARGET_INDEX(scb->cmd)] & DEVICE_SCANNED) )
-                {
-                  if ( (p->needwdtr_copy & target_mask) &&
-                      !(p->wdtr_pending & target_mask) &&
-                      !(p->sdtr_pending & target_mask) )
-                  {
-                    p->needwdtr |= target_mask;
-                    p->wdtr_pending |= target_mask;
-                    hscb->control |= MK_MESSAGE;
-                    scb->flags |= SCB_MSGOUT_WDTR;
-                  }
-                  if ( p->needsdtr_copy & target_mask )
-                  {
-                    p->needsdtr |= target_mask;
-                    if ( !(p->wdtr_pending & target_mask) &&
-                         !(p->sdtr_pending & target_mask) )
-                    {
-                      p->sdtr_pending |= target_mask;
-                      hscb->control |= MK_MESSAGE;
-                      scb->flags |= SCB_MSGOUT_SDTR;
-                    }
-                  }
-                }
-                else
-                  scb->flags &= ~SCB_MSGOUT_BITS;
-#endif /* AIC7XXX_FAKE_NEGOTIATION_CMDS */
                 scb->flags |= SCB_SENSE;
                 /*
                  * Ensure the target is busy since this will be an
                  * an untagged request.
                  */
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
-                if (aic7xxx_verbose > 0xffff)
+                if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
                 {
                   if (scb->flags & SCB_MSGOUT_BITS)
                     printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no,
@@ -4914,7 +4983,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                 }
               }
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
-              if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+              if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
+                  (aic7xxx_verbose > 0xffff) )
               {
                 if (queue_flag)
                   printk(INFO_LEAD "Queue full received; queue depth %d, "
@@ -4928,8 +4998,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 #endif
               if (queue_flag)
               {
-                p->dev_temp_queue_depth[tindex] = 
-                  p->dev_active_cmds[tindex];
                 if ( p->dev_last_queue_full[tindex] !=
                      p->dev_active_cmds[tindex] )
                 {
@@ -4951,11 +5019,29 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                       p->dev_active_cmds[tindex];
                   p->dev_last_queue_full[tindex] = 0;
                   p->dev_last_queue_full_count[tindex] = 0;
+                  p->dev_temp_queue_depth[tindex] = 
+                    p->dev_active_cmds[tindex];
                 }
-                else
+                else if (p->dev_active_cmds[tindex] == 0)
                 {
-                  p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
-                }
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+                  {
+                    printk(INFO_LEAD "QUEUE_FULL status received with 0 "
+                           "commands active.\n", p->host_no, CTL_OF_SCB(scb));
+                    printk(INFO_LEAD "Tagged Command Queueing disabled\n",
+                           p->host_no, CTL_OF_SCB(scb));
+                  }
+                  p->dev_max_queue_depth[tindex] = 1;
+                  p->dev_temp_queue_depth[tindex] = 1;
+                  scb->tag_action = 0;
+                  scb->hscb->control &= ~(MSG_ORDERED_Q_TAG|MSG_SIMPLE_Q_TAG);
+                }
+                else
+                {
+                  p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
+                  p->dev_temp_queue_depth[tindex] = 
+                    p->dev_active_cmds[tindex];
+                }
               }
               break;
             }
@@ -4989,7 +5075,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
          */
 
         if ( !(scb->flags & SCB_DEVICE_RESET) &&
-              (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG) &&
+              (msg_out == MSG_IDENTIFYFLAG) &&
               (scb->hscb->control & TAG_ENB) )
         {
           p->msg_buf[p->msg_index++] = scb->tag_action;
@@ -5020,34 +5106,68 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
               CTL_OF_SCB(scb));
         }
+        else if (scb->flags & SCB_MSGOUT_PPR)
+        {
+          unsigned int max_sync, period;
+          unsigned char options = p->transinfo[tindex].goal_options;
+
+          if (p->features & AHC_ULTRA2)
+          {
+            if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+                !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+            {
+              if( (p->features & AHC_ULTRA3) &&
+                  (p->dev_flags[tindex] & DEVICE_SCSI_3) &&
+                  (p->transinfo[tindex].goal_width ==
+                   MSG_EXT_WDTR_BUS_16_BIT) &&
+                  (options != 0) )
+              {
+                max_sync = AHC_SYNCRATE_ULTRA3;
+              }
+              else
+              {
+                max_sync = AHC_SYNCRATE_ULTRA2;
+              }
+            }
+            else
+            {
+              max_sync = AHC_SYNCRATE_ULTRA;
+            }
+          }
+          else if (p->features & AHC_ULTRA)
+          {
+            max_sync = AHC_SYNCRATE_ULTRA;
+          }
+          else
+          {
+            max_sync = AHC_SYNCRATE_FAST;
+          }
+          period = p->transinfo[tindex].goal_period;
+          aic7xxx_find_syncrate(p, &period, max_sync, &options);
+          p->transinfo[tindex].goal_period = period;
+          p->transinfo[tindex].goal_options = options;
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
+                   p->host_no, CTL_OF_SCB(scb), period,
+                   p->transinfo[tindex].goal_offset,
+                   p->transinfo[tindex].goal_width, options);
+          }
+          aic7xxx_construct_ppr(p, scb);
+        }
         else if (scb->flags & SCB_MSGOUT_WDTR)
         {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-          if (aic7xxx_verbose > 0xffff)
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
             printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
                    CTL_OF_SCB(scb));
-#endif
-          aic7xxx_construct_wdtr(p,
-            p->transinfo[TARGET_INDEX(scb->cmd)].goal_width);
+          }
+          aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width);
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
           unsigned int max_sync, period;
-          /*
-           * We need to set an accurate goal_offset instead of
-           * the ridiculously high one we default to.  We should
-           * now know if we are wide.  Plus, the WDTR code will 
-           * set our goal_offset for us as well.
-           */
-          if (p->transinfo[tindex].goal_offset)
-          {
-            if (p->features & AHC_ULTRA2)
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-            else if (p->transinfo[tindex].cur_width == MSG_EXT_WDTR_BUS_16_BIT)
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-            else
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-          }
+          unsigned char options = 0;
           /*
            * Now that the device is selected, use the bits in SBLKCTL and
            * SSTAT2 to determine the max sync rate for this device.
@@ -5073,14 +5193,14 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             max_sync = AHC_SYNCRATE_FAST;
           }
           period = p->transinfo[tindex].goal_period;
-          aic7xxx_find_syncrate(p, &period, max_sync);
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-          if (aic7xxx_verbose > 0xffff)
+          aic7xxx_find_syncrate(p, &period, max_sync, &options);
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
             printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
                    CTL_OF_SCB(scb),
                    p->transinfo[tindex].goal_period,
                    p->transinfo[tindex].goal_offset);
-#endif
+          }
           aic7xxx_construct_sdtr(p, period,
             p->transinfo[tindex].goal_offset);
         }
@@ -5154,15 +5274,15 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 #if AIC7XXX_NOT_YET 
     case TRACEPOINT:
       {
-        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
-          target, lun);
+        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
+               channel, target, lun);
       }
       break;
 
     case TRACEPOINT2:
       {
-        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
-          target, lun);
+        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
+               channel, target, lun);
       }
       break;
 
@@ -5237,7 +5357,7 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       case MSG_EXT_SDTR:
       {
         unsigned int period, offset;
-        unsigned char maxsync, saved_offset;
+        unsigned char maxsync, saved_offset, options;
         struct aic7xxx_syncrate *syncrate;
         
         if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
@@ -5253,7 +5373,13 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 
         period = p->msg_buf[3];
         saved_offset = offset = p->msg_buf[4];
+        options = 0;
 
+        /*
+         * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+         * using the SDTR messages.  We need the PPR messages to enable the
+         * higher speeds that include things like Dual Edge clocking.
+         */
         if (p->features & AHC_ULTRA2)
         {
           if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
@@ -5283,7 +5409,9 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
         {
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+          if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
+              !(p->needsdtr_copy & target_mask) &&
+               (p->transinfo[tindex].user_offset) )
           {
             /*
              * Not only is the device starting this up, but it also hasn't
@@ -5295,38 +5423,49 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
              */
             p->transinfo[tindex].goal_period =
               p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
+            if(p->features & AHC_ULTRA2)
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+            }
+            else if (p->transinfo[tindex].cur_width)
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+            }
+            else
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+            }
             p->needsdtr_copy |= target_mask;
           }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive SDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
           if ( !p->transinfo[tindex].goal_offset )
             period = 255;
           if ( p->transinfo[tindex].goal_period > period )
             period = p->transinfo[tindex].goal_period;
         }
   
-        syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
+        syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
         aic7xxx_validate_offset(p, syncrate, &offset,
                                 target_scsirate & WIDEXFER);
         aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                             offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                             offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
 
         /*
-         * Did we drop to async?  If so, are we sending a reply?  If we are,
+         * Did we drop to async?  Or are we sending a reply?  If we are,
          * then we have to make sure that the reply value reflects the proper
          * settings so we need to set the goal values according to what
          * we need to send.
          */
-        if ( (offset == 0) || (offset != saved_offset) ||
+        if ( (offset != saved_offset) ||
              ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
               (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
         {
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
-          if ( offset == 0 )
-          {
-            p->needsdtr_copy &= ~target_mask;
-          }
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
+                               options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
         }
         
         /*
@@ -5334,15 +5473,13 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
          * go async, then send an SDTR back to the target
          */
         p->needsdtr &= ~target_mask;
-        p->sdtr_pending &= ~target_mask;
-        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ==
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) &&
-             (offset == saved_offset) )
-        {
-          scb->flags &= ~SCB_MSGOUT_BITS;
-        }
-        else
+        p->dtr_pending &= ~target_mask;
+        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
+             (offset != saved_offset) )
         {
+          reply = TRUE;
+          p->dtr_pending |= target_mask;
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_SDTR;
           aic_outb(p, HOST_MSG, MSG_OUT);
@@ -5376,12 +5513,11 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
             {
               reject = TRUE;
               if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                   ((p->dev_flags[tindex] & DEVICE_PRINT_WDTR) ||
+                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
                     (aic7xxx_verbose > 0xffff)) )
               {
                 printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
                   p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
-                p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
               }
             } /* We fall through on purpose */
             case MSG_EXT_WDTR_BUS_8_BIT:
@@ -5395,15 +5531,11 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
               break;
             }
           }
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          p->wdtr_pending &= ~target_mask;
+          p->dtr_pending &= ~target_mask;
           p->needwdtr &= ~target_mask;
         }
         else
         {
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_WDTR;
-          reply = TRUE;
           if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
           {
             /* 
@@ -5413,13 +5545,33 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
              */
             p->transinfo[tindex].goal_period =
               p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
+            if(p->transinfo[tindex].user_offset)
+            {
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else if( p->transinfo[tindex].user_width &&
+                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+                       p->features & AHC_WIDE )
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
+            }
             p->transinfo[tindex].goal_width =
               p->transinfo[tindex].user_width;
             p->needwdtr_copy |= target_mask;
             p->needsdtr_copy |= target_mask;
           }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive WDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
           switch(bus_width)
           {
             default:
@@ -5441,8 +5593,11 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
               break;
             }
           }
+          reply = TRUE;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_WDTR;
           p->needwdtr &= ~target_mask;
-          p->wdtr_pending &= ~target_mask;
+          p->dtr_pending |= target_mask;
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
         }
@@ -5456,24 +5611,211 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
          * supports SDTR at all.  Therefore, we check needsdtr_copy instead
          * of needstr.
          */
-        aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+        aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
                              AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-        if ( (p->needsdtr_copy & target_mask) &&
-            !(p->sdtr_pending & target_mask))
+        p->needsdtr |= (p->needsdtr_copy & target_mask);
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_PPR:
+      {
+        unsigned char bus_width, trans_options, new_trans_options;
+        unsigned int period, offset;
+        unsigned char maxsync, saved_offset;
+        struct aic7xxx_syncrate *syncrate;
+        
+        if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        /*
+         * If we aren't on one of the new Ultra3 cards, then reject any PPR
+         * message since we can't support any option field other than 0
+         */
+        if( !(p->features & AHC_ULTRA3) )
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
+        {
+          break;
+        }
+
+        period = p->msg_buf[3];
+        offset = saved_offset = p->msg_buf[5];
+        bus_width = p->msg_buf[6];
+        trans_options = new_trans_options = p->msg_buf[7] & 0xf;
+
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+        {
+          printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n",
+                 p->host_no, CTL_OF_SCB(scb), period, offset, bus_width,
+                 trans_options);
+        }
+
+        if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+            !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+        {
+          if(p->features & AHC_ULTRA3)
+          {
+            maxsync = AHC_SYNCRATE_ULTRA3;
+          }
+          else
+          {
+            maxsync = AHC_SYNCRATE_ULTRA2;
+          }
+        }
+        else
         {
-          p->needsdtr |= target_mask;
-          if ( !reject && !reply )
+          maxsync = AHC_SYNCRATE_ULTRA;
+        }
+        /*
+         * We might have a device that is starting negotiation with us
+         * before we can start up negotiation with it....be prepared to
+         * have a device ask for a higher speed then we want to give it
+         * in that case
+         */
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
+        {
+          reply = TRUE;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_PPR;
+          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
           {
-            scb->flags &= ~SCB_MSGOUT_WDTR;
-            if (p->transinfo[tindex].goal_period)
+            /*
+             * Not only is the device starting this up, but it also hasn't
+             * been scanned yet, so this would likely be our TUR or our
+             * INQUIRY command at scan time, so we need to use the
+             * settings from the SEEPROM if they existed.  Of course, even
+             * if we didn't find a SEEPROM, we stuffed default values into
+             * the user settings anyway, so use those in all cases.
+             */
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            if(p->transinfo[tindex].user_offset)
             {
-              p->sdtr_pending |= target_mask;
-              scb->flags |= SCB_MSGOUT_SDTR;
-              aic_outb(p, HOST_MSG, MSG_OUT);
-              aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else if( p->transinfo[tindex].user_width &&
+                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+                       p->features & AHC_WIDE )
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
+            }
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
+            p->transinfo[tindex].goal_options =
+              p->transinfo[tindex].user_options;
+            p->needppr_copy |= target_mask;
+          }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive PPR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+          if ( !p->transinfo[tindex].goal_offset )
+            period = 255;
+          if ( p->transinfo[tindex].goal_period > period )
+            period = p->transinfo[tindex].goal_period;
+          if ( p->transinfo[tindex].goal_options == 0 )
+            new_trans_options = 0;
+          switch(bus_width)
+          {
+            default:
+            {
+              if ( (p->features & AHC_WIDE) &&
+                   (p->transinfo[tindex].goal_width ==
+                    MSG_EXT_WDTR_BUS_16_BIT) )
+              {
+                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              p->needwdtr_copy &= ~target_mask;
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              aic7xxx_set_width(p, target, channel, lun, bus_width,
+                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+              break;
             }
           }
         }
+        else
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reply = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                    (aic7xxx_verbose > 0xffff)) )
+              {
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+              }
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              /*
+               * According to the spec, if we aren't wide, we also can't be
+               * Dual Edge so clear the options byte
+               */
+              new_trans_options = 0;
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              break;
+            }
+          }
+        }
+
+        aic7xxx_set_width(p, target, channel, lun, bus_width,
+                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
+                                         &new_trans_options);
+        aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
+        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                             offset, new_trans_options,
+                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+
+        if( (offset != saved_offset) ||
+            (trans_options != new_trans_options) ||
+            ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) )
+        {
+          aic7xxx_set_width(p, target, channel, lun, bus_width,
+                            AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                               offset, new_trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          reply = TRUE;
+        }
+        p->dtr_pending &= ~target_mask;
+        p->needppr &= ~target_mask;
+        if(reply)
+        {
+          p->dtr_pending |= target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_PPR;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
         done = TRUE;
         break;
       }
@@ -5485,7 +5827,7 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     } /* end of switch(p->msg_type) */
   } /* end of if (!reject && (p->msg_len > 2)) */
 
-  if (reject)
+  if (!reply && reject)
   {
     aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
     aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
@@ -5657,12 +5999,14 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     if (aic7xxx_verbose & VERBOSE_RESET)
       printk(WARN_LEAD "Someone else reset the channel!!\n",
            p->host_no, channel, -1, -1);
+    if (aic7xxx_panic_on_abort)
+      aic7xxx_panic_abort(p, NULL);
     /*
      * Go through and abort all commands for the channel, but do not
      * reset the channel again.
      */
     aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
-    aic7xxx_run_done_queue(p, FALSE);
+    aic7xxx_run_done_queue(p, TRUE);
     scb = NULL;
   }
   else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
@@ -5698,7 +6042,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
             CTL_OF_SCB(scb), scb->hscb->tag);
         aic7xxx_reset_device(p, target, channel, ALL_LUNS,
                 (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
-        aic7xxx_run_done_queue(p, FALSE);
+        aic7xxx_run_done_queue(p, TRUE);
         scb = NULL;
         printerror = 0;
       }
@@ -5709,6 +6053,22 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
         printerror = 0;
       }
     }
+    if ( (scb != NULL) &&
+         (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+    {
+      /*
+       * This might be a SCSI-3 device that is dropping the bus due to
+       * errors and signalling that we should reduce the transfer speed.
+       * All we have to do is complete this command (since it's a negotiation
+       * command already) and the checksum routine should flag an error and
+       * reduce the speed setting and renegotiate.  We call the reset routing
+       * just to clean out the hardware from this scb.
+       */
+      printerror = 0;
+      aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
+      aic7xxx_run_done_queue(p, TRUE);
+      scb = NULL;
+    }
     if (printerror != 0)
     {
       if (scb != NULL)
@@ -5724,7 +6084,12 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
           tag = SCB_LIST_NULL;
         }
         aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
-        aic7xxx_run_done_queue(p, FALSE);
+        aic7xxx_run_done_queue(p, TRUE);
+      }
+      else
+      {
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+        aic7xxx_run_done_queue(p, TRUE);
       }
       printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
              "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
@@ -5829,12 +6194,26 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
         cmd->result = 0;
         scb = NULL;
       }
+      if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
+      {
+        /*
+         * Turn off the needsdtr, needwdtr, and needppr bits since this device
+         * doesn't seem to exist.
+         */
+        p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+      }
     }
     /*
      * Restarting the sequencer will stop the selection and make sure devices
      * are allowed to reselect in.
      */
     aic_outb(p, 0, SCSISEQ);
+    aic_outb(p, CLRSELINGO, CLRSINT0);
     aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
     p->flags &= ~AHC_HANDLING_REQINITS;
     aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
@@ -5868,6 +6247,8 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     Scsi_Cmnd *cmd;
     unsigned char mesg_out = MSG_NOOP;
     unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char sstat2 = aic_inb(p, SSTAT2);
+    unsigned char tindex = TARGET_INDEX(scb->cmd);
 
     cmd = scb->cmd;
     switch (lastphase)
@@ -5898,12 +6279,81 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
         break;
     }
 
-    /*
-     * A parity error has occurred during a data
-     * transfer phase. Flag it and continue.
-     */
-    printk(WARN_LEAD "Parity error during %s phase.\n",
-           p->host_no, CTL_OF_SCB(scb), phase);
+    /*
+     * A parity error has occurred during a data
+     * transfer phase. Flag it and continue.
+     */
+    if( (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && (lastphase == P_DATAIN) )
+    {
+      printk(WARN_LEAD "CRC error during %s phase.\n",
+             p->host_no, CTL_OF_SCB(scb), phase);
+      if(sstat2 & CRCVALERR)
+      {
+        printk(WARN_LEAD "  CRC error in intermediate CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & CRCENDERR)
+      {
+        printk(WARN_LEAD "  CRC error in ending CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & CRCREQERR)
+      {
+        printk(WARN_LEAD "  Target incorrectly requested a CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & DUAL_EDGE_ERROR)
+      {
+        printk(WARN_LEAD "  Dual Edge transmission error.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+    }
+    else
+    {
+      printk(WARN_LEAD "Parity error during %s phase.\n",
+             p->host_no, CTL_OF_SCB(scb), phase);
+    }
+
+    if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
+    {
+      struct aic7xxx_syncrate *syncrate;
+      unsigned int period = p->transinfo[tindex].cur_period;
+      unsigned char options = p->transinfo[tindex].cur_options;
+      /*
+       * oops, we had a failure, lower the transfer rate and try again.  It's
+       * worth noting here that it might be wise to also check for typical
+       * wide setting on narrow cable type problems and try disabling wide
+       * instead of slowing down if those exist.  That's hard to do with simple
+       * checksums though.
+       */
+      if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+      {
+        syncrate++;
+        if( (syncrate->rate[0] != NULL) &&
+            (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+        {
+          p->transinfo[tindex].goal_period = syncrate->period;
+          if( !(syncrate->sxfr_ultra2 & 0x40) )
+          {
+            p->transinfo[tindex].goal_options = 0;
+          }
+        }
+        else
+        {
+          p->transinfo[tindex].goal_offset = 0;
+          p->transinfo[tindex].goal_period = 0;
+          p->transinfo[tindex].goal_options = 0;
+        }
+        p->needppr |= (p->needppr_copy & (1<<tindex));
+        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+      }
+      p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
+    }
+    else
+    {
+      p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
+    }
 
     /*
      * We've set the hardware to assert ATN if we get a parity
@@ -6072,13 +6522,6 @@ aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
       printk("HSCB %d bad, SCB_NEXT points to self.\n", i);
       bogus = TRUE;
     }
-    temp = aic_inb(p, SCB_PREV);
-    if ((temp != SCB_LIST_NULL) &&
-        (temp >= p->scb_data->maxhscbs))
-    {
-      printk("HSCB %d bad, SCB_PREV invalid(%d).\n", i, temp);
-      bogus = TRUE;
-    }
     if (scb_status[i] == 0)
       lost++;
     if (lost > 1)
@@ -6163,7 +6606,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
     unsigned char scb_index;
 
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
-    if(aic7xxx_verbose > 0xffff)
+    if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
       printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
 #endif
     
@@ -6368,7 +6811,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
  *   Determines the queue depth for a given device.  There are two ways
  *   a queue depth can be obtained for a tagged queueing device.  One
  *   way is the default queue depth which is determined by whether
- *   AIC7XXX_CMDS_PER_LUN is defined.  If it is defined, then it is used
+ *   AIC7XXX_CMDS_PER_DEVICE is defined.  If it is defined, then it is used
  *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
  *   default queue depth (dependent on the number of hardware SCBs).
  *   The other way we determine queue depth is through the use of the
@@ -6396,7 +6839,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
   {
     int tag_enabled = TRUE;
 
-    default_depth = AIC7XXX_CMDS_PER_LUN;
+    default_depth = AIC7XXX_CMDS_PER_DEVICE;
  
     if (!(p->discenable & target_mask))
     {
@@ -6958,7 +7401,7 @@ read_seeprom(struct aic7xxx_host *p, int offset,
   }
   printk("\n");
 #endif
-  if (checksum != scarray[len - 1])
+  if ( (checksum != scarray[len - 1]) || (checksum == 0) )
   {
     return (0);
   }
@@ -7371,7 +7814,6 @@ detect_maxscb(struct aic7xxx_host *p)
       aic_outb(p, i, SCBPTR);
       aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
       aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
-      aic_outb(p, i - 1, SCB_PREV);  /* Set the prev pointer. */
       aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
       aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS);  /* no busy untagged */
       aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
@@ -7840,6 +8282,11 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
    */
   aic7xxx_loadseq(p);
 
+  /*
+   * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
+   */
+  aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
+
   if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
   {
     aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
@@ -8035,6 +8482,7 @@ aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
     {
       p->transinfo[i].goal_period = 0;
       p->transinfo[i].goal_offset = 0;
+      p->transinfo[i].goal_options = 0;
       p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
     }
     DRIVER_LOCK_INIT
@@ -8090,10 +8538,14 @@ aic7xxx_free(struct aic7xxx_host *p)
    */
   for (i = 0; i < MAX_TARGETS; i++)
   {
-    if(p->dev_wdtr_cmnd[i])
-      kfree(p->dev_wdtr_cmnd[i]);
-    if(p->dev_sdtr_cmnd[i])
-      kfree(p->dev_sdtr_cmnd[i]);
+    if(p->dev_dtr_cmnd[i])
+    {
+      if(p->dev_dtr_cmnd[i]->request_buffer)
+      {
+        kfree(p->dev_dtr_cmnd[i]->request_buffer);
+      }
+      kfree(p->dev_dtr_cmnd[i]);
+    }
   }
 
 }
@@ -8184,14 +8636,16 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
     {
       printk("aic7xxx: Using leftover BIOS values.\n");
     }
-    if ( *sxfrctl1 & STPWEN )
+    if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
     {
       p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
       sc->adapter_control &= ~CFAUTOTERM;
       sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
     }
     if (aic7xxx_extended)
-      p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
+      p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+    else
+      p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
   }
   else
   {
@@ -8256,8 +8710,7 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
    * Limit to 16 targets just in case.  The 2842 for one is known to
    * blow the max_targets setting, future cards might also.
    */
-  max_targets = MIN(sc->max_targets & CFMAXTARG,
-                   ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8));
+  max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8);
 
   if (have_seeprom)
   {
@@ -8279,7 +8732,7 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
     mask = (0x01 << i);
     if (!have_seeprom)
     {
-      if(aic_inb(p, SCSISEQ) != 0)
+      if (aic_inb(p, SCSISEQ) != 0)
       {
         /*
          * OK...the BIOS set things up and left behind the settings we need.
@@ -8323,7 +8776,9 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
         sc->device_flags[i] = CFDISC;
         if (p->features & AHC_WIDE)
           sc->device_flags[i] |= CFWIDEB;
-        if (p->features & AHC_ULTRA2)
+        if (p->features & AHC_ULTRA3)
+          sc->device_flags[i] |= 2;
+        else if (p->features & AHC_ULTRA2)
           sc->device_flags[i] |= 3;
         else if (p->features & AHC_ULTRA)
           sc->device_flags[i] |= CFSYNCHISULTRA;
@@ -8339,20 +8794,30 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
     }
     if (p->flags & AHC_NEWEEPROM_FMT)
     {
-      if (sc->device_flags[i] & CFSYNCHISULTRA)
-      {
-        p->ultraenb |= mask;
-      }
-      else if (sc->device_flags[i] & CFNEWULTRAFORMAT)
+      if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+          !(p->features & AHC_ULTRA2) )
       {
-        if ( ((sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03) &&
-             !(p->features & AHC_ULTRA2) )
+        /*
+         * I know of two different Ultra BIOSes that do this differently.
+         * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
+         * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s
+         * while on the IBM Netfinity 5000 they want the same thing
+         * to be something else, while flags[i] & CFXFER == 0x03 and
+         * SYNCISULTRA false should be 40MByte/s.  So, we set both to
+         * 40MByte/s and the lower speeds be damned.  People will have
+         * to select around the conversely mapped lower speeds in order
+         * to select lower speeds on these boards.
+         */
+        if ((sc->device_flags[i] & (CFXFER)) == 0x03)
         {
           sc->device_flags[i] &= ~CFXFER;
           sc->device_flags[i] |= CFSYNCHISULTRA;
-          p->ultraenb |= mask;
         }
       }
+      if (sc->device_flags[i] & CFSYNCHISULTRA)
+      {
+        p->ultraenb |= mask;
+      }
     }
     else if (sc->adapter_control & CFULTRAEN)
     {
@@ -8364,18 +8829,54 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
       p->ultraenb &= ~mask;
       p->transinfo[i].user_offset = 0;
       p->transinfo[i].user_period = 0;
+      p->transinfo[i].user_options = 0;
       p->transinfo[i].cur_offset = 0;
       p->transinfo[i].cur_period = 0;
+      p->transinfo[i].cur_options = 0;
       p->needsdtr_copy &= ~mask;
     }
     else
     {
-      if (p->features & AHC_ULTRA2)
+      if (p->features & AHC_ULTRA3)
+      {
+        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
+        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+        if( (sc->device_flags[i] & CFXFER) < 0x03 )
+        {
+          scsirate = (sc->device_flags[i] & CFXFER);
+          p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC;
+          if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 )
+          {
+            p->transinfo[i].cur_options = 
+              ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ?
+                 MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS);
+          }
+          else
+          {
+            p->transinfo[i].cur_options = 0;
+          }
+        }
+        else
+        {
+          scsirate = (sc->device_flags[i] & CFXFER) |
+                     ((p->ultraenb & mask) ? 0x18 : 0x10);
+          p->transinfo[i].user_options = 0;
+          p->transinfo[i].cur_options = 0;
+        }
+        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
+                                       AHC_SYNCRATE_ULTRA3);
+        p->transinfo[i].cur_period = aic7xxx_find_period(p,
+                                       aic_inb(p, TARG_SCSIRATE + i),
+                                       AHC_SYNCRATE_ULTRA3);
+      }
+      else if (p->features & AHC_ULTRA2)
       {
         p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
         p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
         scsirate = (sc->device_flags[i] & CFXFER) |
                    ((p->ultraenb & mask) ? 0x18 : 0x10);
+        p->transinfo[i].user_options = 0;
+        p->transinfo[i].cur_options = 0;
         p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
                                        AHC_SYNCRATE_ULTRA2);
         p->transinfo[i].cur_period = aic7xxx_find_period(p,
@@ -8385,10 +8886,9 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
       else
       {
         scsirate = (sc->device_flags[i] & CFXFER) << 4;
-        if (sc->device_flags[i] & CFWIDEB)
-          p->transinfo[i].user_offset = MAX_OFFSET_16BIT;
-        else
-          p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
+        p->transinfo[i].user_options = 0;
+        p->transinfo[i].cur_options = 0;
+        p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
         if (p->features & AHC_ULTRA)
         {
           short ultraenb;
@@ -8427,9 +8927,10 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
   }
   aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
   aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+  p->needppr = p->needppr_copy = p->needdv = 0;
   p->needwdtr = p->needwdtr_copy;
   p->needsdtr = p->needsdtr_copy;
-  p->wdtr_pending = p->sdtr_pending = 0;
+  p->dtr_pending = 0;
 
   /*
    * We set the p->ultraenb from the SEEPROM to begin with, but now we make
@@ -8453,6 +8954,7 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
     {
       case AHC_AIC7895:
       case AHC_AIC7896:
+      case AHC_AIC7899:
         if (p->adapter_control & CFBPRIMARY)
           p->flags |= AHC_CHANNEL_B_PRIMARY;
       default:
@@ -8783,6 +9285,14 @@ aic7xxx_detect(Scsi_Host_Template *template)
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
        AHC_PAGESCBS, AHC_AIC7850_FE,                         6,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7860_FE,                                       7,
@@ -8825,6 +9335,18 @@ aic7xxx_detect(Scsi_Host_Template *template)
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
        AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
        AHC_AIC7895_FE,                                      19,
@@ -8833,30 +9355,66 @@ aic7xxx_detect(Scsi_Host_Template *template)
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7890_FE,                                      20,
        32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_78902, AHC_AIC7890,
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7890_FE,                                      20,
        32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7890_FE,                                      21,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      22,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      22,
+       AHC_AIC7896_FE,                                      23,
        32, C56_66 },
       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      23,
+       AHC_AIC7896_FE,                                      24,
        32, C56_66 },
       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      24,
+       AHC_AIC7896_FE,                                      25,
        32, C56_66 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                      25,
+       AHC_AIC7860_FE,                                      26,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
     };
 
     unsigned short command;
@@ -8926,11 +9484,11 @@ aic7xxx_detect(Scsi_Host_Template *template)
           }
 #ifdef AIC7XXX_STRICT_PCI_SETUP
           command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
-            PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
-            PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+            PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
 #else
           command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
 #endif
+          command &= ~PCI_COMMAND_INVALIDATE;
           if (aic7xxx_pci_parity == 0)
             command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
           pci_write_config_word(pdev, PCI_COMMAND, command);
@@ -8940,15 +9498,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
           {
             printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
           }
-          devconfig |= 0x80000000;
-          if ((aic7xxx_pci_parity == 0) || (aic7xxx_pci_parity == -1))
-          {
-            devconfig &= ~(0x00000008);
-          }
-          else
-          {
-            devconfig |= 0x00000008;
-          }
+          devconfig |= 0x80000040;
           pci_write_config_dword(pdev, DEVCONFIG, devconfig);
 #endif /* AIC7XXX_STRICT_PCI_SETUP */
 #else  /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
@@ -8976,11 +9526,11 @@ aic7xxx_detect(Scsi_Host_Template *template)
           }
 #ifdef AIC7XXX_STRICT_PCI_SETUP
           command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
-            PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
-            PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+            PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
 #else
           command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
 #endif
+          command &= ~PCI_COMMAND_INVALIDATE;
           if (aic7xxx_pci_parity == 0)
             command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
           pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, command);
@@ -8990,15 +9540,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
           {
             printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
           }
-          devconfig |= 0x80000000;
-          if ((aic7xxx_pci_parity == 0) || (aic7xxx_pci_parity == -1))
-          {
-            devconfig &= ~(0x00000008);
-          }
-          else
-          {
-            devconfig |= 0x00000008;
-          }
+          devconfig |= 0x80000040;
           pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, devconfig);
 #endif /* AIC7XXX_STRICT_PCI_SETUP */
 #endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
@@ -9137,6 +9679,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
 
             case AHC_AIC7895: /* 7895 */
             case AHC_AIC7896: /* 7896/7 */
+            case AHC_AIC7899: /* 7899 */
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               if (PCI_FUNC(temp_p->pdev->devfn) != 0)
               {
@@ -9185,43 +9728,38 @@ aic7xxx_detect(Scsi_Host_Template *template)
            */
           switch (temp_p->chip & AHC_CHIPID_MASK)
           {
-            case AHC_AIC7890:
-            case AHC_AIC7896:
+            case AHC_AIC7892:
+            case AHC_AIC7899:
               aic_outb(temp_p, 0, SCAMCTL);
               /*
-               * We used to set DPARCKEN in this register, but after talking
-               * to a tech from Adaptec, I found out they don't use that
-               * particular bit in their own register settings, and when you
-               * combine that with the fact that I determined that we were
-               * seeing Data-Path Parity Errors on things we shouldn't see
-               * them on, I think there is a bug in the silicon and the way
-               * to work around it is to disable this particular check.  Also
-               * This bug only showed up on certain commands, so it seems to
-               * be pattern related or some such.  The commands we would
-               * typically send as a linux TEST_UNIT_READY or INQUIRY command
-               * could cause it to be triggered, while regular commands that
-               * actually made reasonable use of the SG array capabilities
-               * seemed not to cause the problem.
+               * Switch to the alt mode of the chip...
                */
+              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
               /*
-              aic_outb(temp_p, aic_inb(temp_p, DSCOMMAND0) |
-                               CACHETHEN | DPARCKEN | MPARCKEN |
-                               USCBSIZE32 | CIOPARCKEN,
-                               DSCOMMAND0);
+               * Set our options...the last two items set our CRC after x byte
+              * count in target mode...
                */
+              aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
+             aic_outb(temp_p, 0x00, 0x0b);
+             aic_outb(temp_p, 0x10, 0x0a);
+              /*
+               * switch back to normal mode...
+               */
+              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
+              aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
+                              TARGCRCENDEN | TARGCRCCNTEN,
+                       CRCCONTROL1);
+              aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
+                                 MPARCKEN | CIOPARCKEN | CACHETHEN) & 
+                               ~DPARCKEN), DSCOMMAND0);
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7890:
+            case AHC_AIC7896:
+              aic_outb(temp_p, 0, SCAMCTL);
               aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
                                 CACHETHEN | MPARCKEN | USCBSIZE32 |
                                 CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
-              /* FALLTHROUGH */
-            default:
-              /*
-               * We attempt to read a SEEPROM on *everything*.  If we fail,
-               * then we fail, but this covers things like 2910c cards that
-               * now have SEEPROMs with their 7856 chipset that we would
-               * otherwise ignore.  They still don't have a BIOS, but they
-               * have a SEEPROM that the SCSISelect utility on the Adaptec
-               * diskettes can configure.
-               */
               aic7xxx_load_seeprom(temp_p, &sxfrctl1);
               break;
             case AHC_AIC7850:
@@ -9233,14 +9771,13 @@ aic7xxx_detect(Scsi_Host_Template *template)
               aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
                                 CACHETHEN | MPARCKEN) & ~DPARCKEN,
                        DSCOMMAND0);
+              /* FALLTHROUGH */
+            default:
               aic7xxx_load_seeprom(temp_p, &sxfrctl1);
               break;
             case AHC_AIC7880:
               /*
-               * Only set the DSCOMMAND0 register if this is a Rev B.
-               * chipset.  For those, we also enable Ultra mode by
-               * force due to brain-damage on the part of some BIOSes
-               * We overload the devconfig variable here since we can.
+               * Check the rev of the chipset before we change DSCOMMAND0
                */
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
@@ -9272,6 +9809,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
           {
             case AHC_AIC7895:
             case AHC_AIC7896:
+            case AHC_AIC7899:
               current_p = list_p;
               while(current_p != NULL)
               {
@@ -9315,6 +9853,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
               break;
             case AHC_AIC7895:
             case AHC_AIC7896:
+            case AHC_AIC7899:
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
 #else
@@ -9364,7 +9903,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
            */
           if (temp_p->features & AHC_ULTRA2)
           {
-            aic_outb(temp_p, RD_DFTHRSH_75 | WR_DFTHRSH_75, DFF_THRSH);
+            aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
           }
           else
           {
@@ -9512,7 +10051,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
               }
             }
             /*
-             * Are we dealing with a 7985 where we need to sort the
+             * Are we dealing with a 7895/6/7/9 where we need to sort the
              * channels as well, if so, the bios_address values should
              * be the same
              */
@@ -9603,7 +10142,54 @@ aic7xxx_detect(Scsi_Host_Template *template)
   return (found);
 }
 
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
+                                           Scsi_Cmnd *old_cmd, int tindex);
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_allocate_negotiation_command
+ *
+ * Description:
+ *   allocate the actual command struct and fill in the gaps...
+ *-F*************************************************************************/
+static Scsi_Cmnd *
+aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
+                                     Scsi_Cmnd *old_cmd, int tindex)
+{
+  Scsi_Cmnd *cmd;
+  char *buffer;
+
+  if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+  {
+    return(NULL);
+  }
+  if (!(buffer = kmalloc(256, GFP_ATOMIC)))
+  {
+    kfree(p->dev_dtr_cmnd[tindex]);
+    p->dev_dtr_cmnd[tindex] = NULL;
+    return(NULL);
+  }
+  cmd = p->dev_dtr_cmnd[tindex];
+  memset(cmd, 0, sizeof(Scsi_Cmnd));
+  memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
+  memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
+  memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
+  cmd->lun = 0;
+  cmd->request_bufflen = 255;
+  cmd->request_buffer = buffer;
+  cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
+  cmd->bufflen = 0;
+  cmd->buffer = NULL;
+  cmd->underflow = 0;
+  cmd->cmd_len = 6;
+  cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
+  cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
+  cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
+  cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
+  cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
+  cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
+  return(cmd);
+}
 
 /*+F*************************************************************************
  * Function:
@@ -9616,6 +10202,117 @@ aic7xxx_detect(Scsi_Host_Template *template)
 static void
 aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
 {
+  unsigned int checksum;
+  int i;
+  int *ibuffer;
+  struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
+  int tindex = TARGET_INDEX(cmd);
+  struct aic7xxx_syncrate *syncrate;
+
+  /*
+   * perform our minimalistic domain validation
+   */
+  if(p->dev_flags[tindex] & DEVICE_SCANNED)
+  {
+    ibuffer = (int *)cmd->request_buffer;
+    checksum = 0;
+    for(i = 0; i < (cmd->request_bufflen >> 2); i++)
+    {
+      checksum += ibuffer[i];
+    }
+    if( (checksum != p->dev_checksum[tindex]) &&
+        (p->transinfo[tindex].cur_offset != 0) )
+    {
+      unsigned int period = p->transinfo[tindex].cur_period;
+      unsigned char options = p->transinfo[tindex].cur_options;
+
+      if (p->needdv & (1<<tindex))
+      {
+        /*
+         * oops, we had a failure, lower the transfer rate and try again.  It's
+         * worth noting here that it might be wise to also check for typical
+         * wide setting on narrow cable type problems and try disabling wide
+         * instead of slowing down if those exist.  That's hard to do with simple
+         * checksums though.
+         */
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION) 
+        {
+          printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
+                 "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
+        }
+        if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+        {
+          syncrate++;
+          if( (syncrate->rate[0] != NULL) &&
+              (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+          {
+            p->transinfo[tindex].goal_period = syncrate->period;
+            if( !(syncrate->sxfr_ultra2 & 0x40) )
+            {
+              p->transinfo[tindex].goal_options = 0;
+            }
+          }
+          else
+          {
+            p->transinfo[tindex].goal_offset = 0;
+            p->transinfo[tindex].goal_period = 0;
+            p->transinfo[tindex].goal_options = 0;
+          }
+          p->needppr |= (p->needppr_copy & (1<<tindex));
+          p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+          p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+        }
+        p->needdv &= ~(1<<tindex);
+      }
+      else
+      {
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION) 
+        {
+          printk(INFO_LEAD "Performing Domain validation.\n",
+                 p->host_no, CTL_OF_CMD(cmd));
+        }
+        /*
+         * Update the checksum in case the INQUIRY data has changed, maybe
+         * in relation to a change in the mode pages, or whatever.
+         */
+        p->dev_checksum[tindex] = checksum;
+        /*
+         * Signal that we are trying out the domain validation
+         */
+        p->needdv |= (1<<tindex);
+        /*
+         * Signal that we need to re-negotiate things, this also gets us our
+         * INQUIRY command to re-checksum off of.
+         */
+        p->needppr |= (p->needppr_copy & (1<<tindex));
+        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+      }
+    } 
+    else
+    {
+      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+          (p->needdv & (1<<tindex)) )
+      {
+        printk(INFO_LEAD "Successfully completed Domain validation.\n",
+               p->host_no, CTL_OF_CMD(cmd));
+      }
+      /*
+       * We successfully did our checksum, so don't leave the needdv flag set
+       * in case we might have set it last time through.
+       */
+      p->needdv &= ~(1<<tindex);
+    }
+  }
+
+  p->dtr_pending &= ~(0x01 << tindex);
+  /*
+   * This looks recursive in the extreme, but if this was a WDTR negotiation
+   * and we didn't follow up with SDTR yet, then this will get it started.
+   * For all other cases, this should work out to be a no-op, unless we are
+   * doing domain validation and happen to need a new negotiation command.
+   */
+  aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
   return;
 }
 
@@ -9632,81 +10329,63 @@ aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
   int tindex)
 {
 
-  if ( (p->needwdtr & (1<<tindex)) && !(p->wdtr_pending & (1<<tindex)) )
+  if ( !(p->dtr_pending & (1<<tindex)) &&
+       ( (p->needppr & (1<<tindex)) ||
+         (p->needwdtr & (1<<tindex)) ||
+         (p->needsdtr & (1<<tindex)) ) )
   {
-    if(p->dev_wdtr_cmnd[tindex] == NULL)
+    if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
+         (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
     {
-      Scsi_Cmnd *cmd;
-
-      if (!(p->dev_wdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
-      {
-        return;
-      }
-      cmd = p->dev_wdtr_cmnd[tindex];
-      memset(cmd, 0, sizeof(Scsi_Cmnd));
-      memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
-      memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
-      memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
-      cmd->lun = 0;
-      cmd->request_bufflen = 0;
-      cmd->request_buffer = NULL;
-      cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
-      cmd->bufflen = 0;
-      cmd->buffer = NULL;
-      cmd->underflow = 0;
-      cmd->cmd_len = 6;
+      return;
     }
     /*
-     * Before sending this thing out, we also amke the cmd->next pointer
+     * Before sending this thing out, we also make the cmd->next pointer
      * point to the real command so we can stuff any possible SENSE data
-     * intp the real command instead of this fake command.  This has to be
+     * into the real command instead of this fake command.  This has to be
      * done each time the command is built, not just the first time, hence
      * it's outside of the above if()...
      */
-    p->dev_wdtr_cmnd[tindex]->next = old_cmd;
-    aic7xxx_queue(p->dev_wdtr_cmnd[tindex], 
-                  aic7xxx_negotiation_complete);
-  }
-  else if ( (p->needsdtr & (1<<tindex)) && !(p->sdtr_pending & (1<<tindex)) &&
-            !(p->wdtr_pending & (1<<tindex)) )
-  {
-    if(p->dev_sdtr_cmnd[tindex] == NULL)
+    p->dev_dtr_cmnd[tindex]->next = old_cmd;
+    /*
+     * Clear the buffer so checksums come out right....
+     */
+    memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
+           p->dev_dtr_cmnd[tindex]->request_bufflen);
+    /*
+     * Remove any commands for this particular device that might be on the
+     * waiting_scbs queue or qinfifo so that this command goes out first.
+     * This is vital for our implementation of domain validation.
+     */
+    pause_sequencer(p);
+    aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
+                SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
+    unpause_sequencer(p, FALSE);
     {
-      Scsi_Cmnd *cmd;
+      struct aic7xxx_scb *scb, *next;
 
-      if (!(p->dev_sdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+      scb = p->waiting_scbs.head;
+      while(scb != NULL)
       {
-        return;
+        if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
+                              ALL_LUNS, SCB_LIST_NULL) )
+        {
+          next = scb->q_next;
+          scbq_remove(&p->waiting_scbs, scb);
+          scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+          scb = next;
+        }
+        else
+        {
+          scb = scb->q_next;
+        }
       }
-      cmd = p->dev_sdtr_cmnd[tindex];
-      memset(cmd, 0, sizeof(Scsi_Cmnd));
-      memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
-      memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
-      memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
-      cmd->lun = 0;
-      cmd->request_bufflen = 0;
-      cmd->request_buffer = NULL;
-      cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
-      cmd->bufflen = 0;
-      cmd->buffer = NULL;
-      cmd->underflow = 0;
-      cmd->cmd_len = 6;
     }
-    /*
-     * Before sending this thing out, we also amke the cmd->next pointer
-     * point to the real command so we can stuff any possible SENSE data
-     * intp the real command instead of this fake command.  This has to be
-     * done each time the command is built, not just the first time, hence
-     * it's outside of the above if()...
-     */
-    p->dev_sdtr_cmnd[tindex]->next = old_cmd;
-    aic7xxx_queue(p->dev_sdtr_cmnd[tindex], 
+    aic7xxx_queue(p->dev_dtr_cmnd[tindex], 
                   aic7xxx_negotiation_complete);
   }
 }
 
-#endif
-
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
 /*+F*************************************************************************
  * Function:
@@ -9744,8 +10423,9 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
 {
   unsigned short mask;
   struct aic7xxx_hwscb *hscb;
+  unsigned char tindex = TARGET_INDEX(cmd);
 
-  mask = (0x01 << TARGET_INDEX(cmd));
+  mask = (0x01 << tindex);
   hscb = scb->hscb;
 
   /*
@@ -9757,11 +10437,12 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
-    if (p->tagenable & mask)
+    if ( (p->tagenable & mask) &&
+         (cmd->cmnd[0] != TEST_UNIT_READY) )
     {
       cmd->tag = hscb->tag;
-      p->dev_commands_sent[TARGET_INDEX(cmd)]++;
-      if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
+      p->dev_commands_sent[tindex]++;
+      if (p->dev_commands_sent[tindex] < 200)
       {
         hscb->control |= MSG_SIMPLE_Q_TAG;
         scb->tag_action = MSG_SIMPLE_Q_TAG;
@@ -9778,74 +10459,38 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
           hscb->control |= MSG_SIMPLE_Q_TAG;
           scb->tag_action = MSG_SIMPLE_Q_TAG;
         }
-        p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
+        p->dev_commands_sent[tindex] = 0;
       }
     }
   }
-  if (p->dev_flags[TARGET_INDEX(cmd)] & DEVICE_SCANNED)
+  if ( cmd == p->dev_dtr_cmnd[tindex] )
   {
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
-    if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) )
+    p->dtr_pending |= mask;
+    scb->tag_action = 0;
+    if (p->dev_flags[tindex] & DEVICE_SCANNED)
     {
-      if (cmd == p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
+      hscb->control &= DISCENB;
+      hscb->control |= MK_MESSAGE;
+      if(p->needppr & mask)
       {
-        p->wdtr_pending |= mask;
-        scb->flags |= SCB_MSGOUT_WDTR;
-        hscb->control &= DISCENB;
-        hscb->control |= MK_MESSAGE;
-        scb->tag_action = 0;
+        scb->flags |= SCB_MSGOUT_PPR;
       }
-      else
+      else if(p->needwdtr & mask)
       {
-        aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
+        scb->flags |= SCB_MSGOUT_WDTR;
       }
-    }
-    else if ( (p->needsdtr & mask) && !(p->sdtr_pending & mask) &&
-              !(p->wdtr_pending & mask) )
-    {
-      if (cmd == p->dev_sdtr_cmnd[TARGET_INDEX(cmd)])
+      else if(p->needsdtr & mask)
       {
-        p->sdtr_pending |= mask;
         scb->flags |= SCB_MSGOUT_SDTR;
-        hscb->control &= DISCENB;
-        hscb->control |= MK_MESSAGE;
-        scb->tag_action = 0;
       }
-      else if (cmd != p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
-      {
-        aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
-      }
-    }
-#else
-    if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) &&
-         !(p->sdtr_pending & mask) && (cmd->lun == 0) )
-    {
-      p->wdtr_pending |= mask;
-      scb->flags |= SCB_MSGOUT_WDTR;
-      hscb->control &= DISCENB;
-      hscb->control |= MK_MESSAGE;
-      scb->tag_action = 0;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Building WDTR command.\n", p->host_no,
-               CTL_OF_CMD(cmd));
-#endif
-    }
-    else if ( (p->needsdtr & mask) && !(p->wdtr_pending & mask) &&
-              !(p->sdtr_pending & mask) && (cmd->lun == 0) )
-    {
-      p->sdtr_pending |= mask;
-      scb->flags |= SCB_MSGOUT_SDTR;
-      hscb->control &= DISCENB;
-      hscb->control |= MK_MESSAGE;
-      scb->tag_action = 0;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Building SDTR command.\n", p->host_no,
-               CTL_OF_CMD(cmd));
-#endif
     }
-#endif
+  }
+  if ( !(p->dtr_pending & mask) &&
+        ( (p->needppr & mask) ||
+          (p->needwdtr & mask) ||
+          (p->needsdtr & mask) ) )
+  {
+    aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
   }
   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
         ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
@@ -9897,7 +10542,6 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     scb->sg_count = cmd->use_sg;
     hscb->SG_segment_count = cmd->use_sg;
     hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[1]));
-
   }
   else
   {
@@ -9922,12 +10566,6 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
       hscb->data_pointer = 0;
     }
   }
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-  if((cmd->cmnd[0] == TEST_UNIT_READY) && (aic7xxx_verbose & VERBOSE_PROBE2))
-  {
-    aic7xxx_print_scb(p, scb);
-  }
-#endif
 }
 
 /*+F*************************************************************************
@@ -10262,13 +10900,14 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
     if(p->dev_flags[i] & DEVICE_PRESENT)
     {
       mask = (0x01 << i);
-      printk(INFO_LEAD "dev_flags=0x%x, WDTR:%c/%c/%c, SDTR:%c/%c/%c,"
-             " q_depth=%d:%d\n",
+      printk(INFO_LEAD "dev_flags=0x%x, Pending:%c, PPR:%c/%c, WDTR:%c/%c, "
+             "SDTR:%c/%c, q_depth=%d:%d\n",
         p->host_no, 0, i, 0, p->dev_flags[i],
-        (p->wdtr_pending & mask) ? 'Y' : 'N',
+        (p->dtr_pending & mask) ? 'Y' : 'N',
+        (p->needppr & mask) ? 'Y' : 'N',
+        (p->needppr_copy & mask) ? 'Y' : 'N',
         (p->needwdtr & mask) ? 'Y' : 'N',
         (p->needwdtr_copy & mask) ? 'Y' : 'N',
-        (p->sdtr_pending & mask) ? 'Y' : 'N',
         (p->needsdtr & mask) ? 'Y' : 'N',
         (p->needsdtr_copy & mask) ? 'Y' : 'N',
         p->dev_active_cmds[i],
@@ -10347,13 +10986,13 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
      * We haven't found the offending SCB yet, and it should be around
      * somewhere, so go look for it in the cards SCBs.
      */
-    printk("SCBPTR CONTROL TAG PREV NEXT\n");
+    printk("SCBPTR CONTROL TAG NEXT\n");
     for(i=0; i<p->scb_data->maxhscbs; i++)
     {
       aic_outb(p, i, SCBPTR);
-      printk("   %3d      %02x  %02x   %02x   %02x\n", i,
+      printk("   %3d      %02x  %02x   %02x\n", i,
              aic_inb(p, SCB_CONTROL), aic_inb(p, SCB_TAG),
-             aic_inb(p, SCB_PREV), aic_inb(p, SCB_NEXT));
+             aic_inb(p, SCB_NEXT));
     }
   }
   
@@ -10569,21 +11208,13 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
     int tindex = TARGET_INDEX(cmd);
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
     unsigned short mask;
 
     mask = (1 << tindex);
 
-    if (p->wdtr_pending & mask)
-    {
-      if (p->dev_wdtr_cmnd[tindex]->next != cmd)
-        found = 1;
-      else
-        found = 0;
-    }
-    else if (p->sdtr_pending & mask)
+    if (p->dtr_pending & mask)
     {
-      if (p->dev_sdtr_cmnd[tindex]->next != cmd)
+      if (p->dev_dtr_cmnd[tindex]->next != cmd)
         found = 1;
       else
         found = 0;
@@ -10606,7 +11237,6 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
       DRIVER_UNLOCK
       return(SCSI_ABORT_PENDING);
     }
-#endif
     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
       printk(INFO_LEAD "SCB found on waiting list and "
           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
@@ -10864,6 +11494,8 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
         printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
           CTL_OF_SCB(scb));
+      aic7xxx_run_done_queue(p, TRUE);
+      aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
       return(SCSI_RESET_NOT_RUNNING);
@@ -11034,16 +11666,21 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
 int
 aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
 {
-  int heads, sectors, cylinders;
+  int heads, sectors, cylinders, ret;
   struct aic7xxx_host *p;
+  struct buffer_head *bh;
 
   p = (struct aic7xxx_host *) disk->device->host->hostdata;
+  bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
 
-  /*
-   * XXX - if I could portably find the card's configuration
-   *       information, then this could be autodetected instead
-   *       of left to a boot-time switch.
-   */
+  if ( bh )
+  {
+    ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
+    brelse(bh);
+    if ( ret != -1 )
+      return(ret);
+  }
+  
   heads = 64;
   sectors = 32;
   cylinders = disk->capacity / (heads * sectors);
@@ -11150,6 +11787,12 @@ aic7xxx_print_card(struct aic7xxx_host *p)
           0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
           0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
           0xfe, 0xff} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xfc} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xfc} },
   };
 #ifdef CONFIG_PCI
   static struct register_ranges cards_ns[] = {
@@ -11164,6 +11807,10 @@ aic7xxx_print_card(struct aic7xxx_host *p)
     { 5, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3} },
     { 6, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47,
           0xdc, 0xe3} },
+    { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+          0xff, 0xff} },
+    { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+          0xff, 0xff} },
     { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
           0xff, 0xff} }
   };
index 945cefbcc8348dd7da6df244d9eea9af86751b9f..7f348aa9393ac25d0a8330da19069bc2772f0746 100644 (file)
@@ -213,6 +213,25 @@ register STCNT {
        access_mode RW
 }
 
+/*
+ * Option Mode Register (Alternate Mode) (p. 5-198)
+ * This register is used to set certain options on Ultra3 based chips.
+ * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set)
+ */
+register OPTIONMODE {
+       address                 0x008
+       access_mode RW
+       bit     AUTORATEEN      0x80
+       bit     AUTOACKEN       0x40
+       bit     ATNMGMNTEN      0x20
+       bit     BUSFREEREV      0x10
+       bit     EXPPHASEDIS     0x08
+       bit     SCSIDATL_IMGEN  0x04
+       bit     AUTO_MSGOUT_DE  0x02
+       bit     DIS_MSGIN_DUALEDGE      0x01
+}
+
+
 /*
  * Clear SCSI Interrupt 0 (p. 3-20)
  * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
@@ -285,7 +304,13 @@ register SSTAT2 {
        address                 0x00d
        access_mode RO
        bit     OVERRUN         0x80
+       bit     SHVALID         0x40
+       bit     WIDE_RES        0x20
        bit     EXP_ACTIVE      0x10    /* SCSI Expander Active */
+       bit     CRCVALERR       0x08    /* CRC Value Error */
+       bit     CRCENDERR       0x04    /* CRC End Error */
+       bit     CRCREQERR       0x02    /* CRC REQ Error */
+       bit     DUAL_EDGE_ERROR 0x01    /* Invalid pins for Dual Edge phase */
        mask    SFCNT           0x1f
 }
 
@@ -709,6 +734,7 @@ register ERROR {
        bit     SQPARERR        0x08
        bit     ILLOPCODE       0x04
        bit     ILLSADDR        0x02
+       bit     DSCTMOUT        0x02    /* Ultra3 only */
        bit     ILLHADDR        0x01
 }
 
@@ -787,6 +813,17 @@ register QINCNT    {
        access_mode RO
 }
 
+/*
+ * SCSIDATL IMAGE Register (p. 5-104)
+ * Write to this register also go to SCSIDATL but this register will preserve
+ * the data for later reading as long as the SCSIDATL_IMGEN bit in the
+ * OPTIONMODE register is set.
+ */
+register SCSIDATL_IMG {
+       address                 0x09c
+       access_mode RW
+}
+
 /*
  * Queue Out FIFO (p. 3-61)
  * Queue of SCBs that have completed and await the host
@@ -796,6 +833,21 @@ register QOUTFIFO {
        access_mode WO
 }
 
+/*
+ * CRC Control 1 Register (p. 5-105)
+ * Control bits for the Ultra 160/m CRC facilities
+ */
+register CRCCONTROL1 {
+       address                 0x09d
+       access_mode RW
+       bit     CRCONSEEN       0x80 /* CRC ON Single Edge ENable */
+       bit     CRCVALCHKEN     0x40 /* CRC Value Check Enable */
+       bit     CRCENDCHKEN     0x20 /* CRC End Check Enable */
+       bit     CRCREQCHKEN     0x10
+       bit     TARGCRCENDEN    0x08 /* Enable End CRC transfer when target */
+       bit     TARGCRCCNTEN    0x40 /* Enable CRC transfer when target */
+}
+
 /*
  * Queue Out Count (p. 3-61)
  * Number of queued SCBs in the Out FIFO
@@ -805,12 +857,28 @@ register QOUTCNT {
        access_mode RO
 }
 
+/*
+ * SCSI Phase Register (p. 5-106)
+ * Current bus phase
+ */
+register SCSIPHASE {
+       address                 0x09e
+       access_mode RO
+       bit     SP_STATUS               0x20
+       bit     SP_COMMAND              0x10
+       bit     SP_MSG_IN               0x08
+       bit     SP_MSG_OUT              0x04
+       bit     SP_DATA_IN              0x02
+       bit     SP_DATA_OUT     0x01
+}
+
 /*
  * Special Function
  */
 register SFUNCT {
        address                 0x09f
        access_mode RW
+       bit     ALT_MODE        0x80
 }
 
 /*
@@ -960,19 +1028,29 @@ register HNSCB_QOFF {
        address                 0x0F4
 }
 
+register HESCB_QOFF {
+       address                 0x0F5
+}
+
 register SNSCB_QOFF {
        address                 0x0F6
 }
 
+register SESCB_QOFF {
+       address                 0x0F7
+}
+
 register SDSCB_QOFF {
        address                 0x0F8
 }
 
 register QOFF_CTLSTA {
        address                 0x0FA
+       bit     ESTABLISH_SCB_AVAIL     0x80
        bit     SCB_AVAIL       0x40
        bit     SNSCB_ROLLOVER  0x20
        bit     SDSCB_ROLLOVER  0x10
+       bit     SESCB_ROLLOVER  0x08
        mask    SCB_QSIZE       0x07
        mask    SCB_QSIZE_256   0x06
 }
index 60a718a3a6796abc4983efcc03d517e9db04e054..4cb8e82c04162b4d611da2c5b304e013145f96a5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
  *
- * Copyright (c) 1994-1998 Justin Gibbs.
+ * Copyright (c) 1994-1999 Justin Gibbs.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -58,6 +58,7 @@
 
 reset:
        clr     SCSISIGO;               /* De-assert BSY */
+       and     SXFRCTL1, ~BITBUCKET;
        /* Always allow reselection */
        if ((p->flags & AHC_TARGETMODE) != 0) {
                mvi     SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
@@ -72,8 +73,8 @@ reset:
        }
 
        call    clear_target_state;
-       and     SXFRCTL0, ~SPIOEN;
 poll_for_work:
+       and     SXFRCTL0, ~SPIOEN;
        if ((p->features & AHC_QUEUE_REGS) == 0) {
                mov     A, QINPOS;
        }
@@ -134,6 +135,21 @@ dma_queued_scb:
        mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
        mov     RETURN_2         call dma_scb;
 
+/*
+ * Preset the residual fields in case we never go through a data phase.
+ * This isn't done by the host so we can avoid a DMA to clear these
+ * fields for the normal case of I/O that completes without underrun
+ * or overrun conditions.
+ */
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               bmov    SCB_RESID_DCNT, SCB_DATACNT, 3;
+       } else {
+               mov     SCB_RESID_DCNT[0],SCB_DATACNT[0];
+               mov     SCB_RESID_DCNT[1],SCB_DATACNT[1];
+               mov     SCB_RESID_DCNT[2],SCB_DATACNT[2];
+       }
+       mov     SCB_RESID_SGCNT, SCB_SGCOUNT;
+
 start_scb:
        /*
         * Place us on the waiting list in case our selection
@@ -174,8 +190,7 @@ initialize_scsiid:
  * set in SXFRCTL0.
  */
 initialize_channel:
-       or      A, CLRSTCNT|CLRCHN, SINDEX;
-       or      SXFRCTL0, A;
+       or      SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;
        if ((p->features & AHC_ULTRA) != 0) {
 ultra:
                mvi     SINDEX, ULTRA_ENB+1;
@@ -402,29 +417,42 @@ await_busfree:
        mvi     INTSTAT, BAD_PHASE;
        
 clear_target_state:
-       clr     DFCNTRL;                /*
-                                        * We assume that the kernel driver
-                                        * may reset us at any time, even
-                                        * in the middle of a DMA, so clear
-                                        * DFCNTRL too.
-                                        */
-       clr     SCSIRATE;               /*
-                                        * We don't know the target we will
-                                        * connect to, so default to narrow
-                                        * transfers to avoid parity problems.
-                                        */
-       and     SXFRCTL0, ~(FAST20);
+       /*
+        * We assume that the kernel driver may reset us
+        * at any time, even in the middle of a DMA, so
+        * clear DFCNTRL too.
+        */
+       clr     DFCNTRL;
+
+       /*
+        * We don't know the target we will connect to,
+        * so default to narrow transfers to avoid
+        * parity problems.
+        */
+       if ((p->features & AHC_ULTRA2) != 0) {
+               bmov    SCSIRATE, ALLZEROS, 2;
+       } else {
+               clr     SCSIRATE;
+               and     SXFRCTL0, ~(FAST20);
+       }
        mvi     LASTPHASE, P_BUSFREE;
        /* clear target specific flags */
-       and     SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret;
+       clr     SEQ_FLAGS ret;
 
 /*
  * If we re-enter the data phase after going through another phase, the
  * STCNT may have been cleared, so restore it from the residual field.
  */
 data_phase_reinit:
-       mvi     DINDEX, STCNT;
-       mvi     SCB_RESID_DCNT  call bcopy_3;
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               if ((p->features & AHC_ULTRA2) != 0) {
+                       bmov    HCNT, SCB_RESID_DCNT, 3;
+               }
+               bmov    STCNT, SCB_RESID_DCNT, 3;
+       } else {
+               mvi     DINDEX, STCNT;
+               mvi     SCB_RESID_DCNT  call bcopy_3;
+       }
        jmp     data_phase_loop;
 
 p_data:
@@ -455,20 +483,16 @@ p_data:
         */
        if ((p->features & AHC_CMD_CHAN) != 0) {
                bmov    HADDR, SCB_DATAPTR, 7;
+               bmov    STCNT, HCNT, 3;
+               bmov    SG_COUNT, SCB_SGCOUNT, 5;
        } else {
                mvi     DINDEX, HADDR;
                mvi     SCB_DATAPTR     call bcopy_7;
-       }
-
-       if ((p->features & AHC_ULTRA2) == 0) {
                call    set_stcnt_from_hcnt;
+               mvi     DINDEX, SG_COUNT;
+               mvi     SCB_SGCOUNT     call bcopy_5;
        }
 
-       mov     SG_COUNT,SCB_SGCOUNT;
-
-       mvi     DINDEX, SG_NEXT;
-       mvi     SCB_SGPTR       call bcopy_4;
-
 data_phase_loop:
 /* Guard against overruns */
        test    SG_COUNT, 0xff jnz data_phase_inbounds;
@@ -480,8 +504,11 @@ data_phase_loop:
  */
        or      SXFRCTL1,BITBUCKET;
        and     DMAPARAMS, ~(HDMAEN|SDMAEN);
-       if ((p->features & AHC_ULTRA2) != 0) {
-               bmov    HCNT, ALLONES, 3;
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               if ((p->features & AHC_ULTRA2) != 0) {
+                       bmov    HCNT, ALLONES, 3;
+               }
+               bmov    STCNT, ALLONES, 3;
        } else {
                mvi     STCNT[0], 0xFF;
                mvi     STCNT[1], 0xFF;
@@ -489,23 +516,21 @@ data_phase_loop:
        }
 data_phase_inbounds:
 /* If we are the last SG block, tell the hardware. */
+if ((p->features & AHC_ULTRA2) == 0) {
        cmp     SG_COUNT,0x01 jne data_phase_wideodd;
-       if ((p->features & AHC_ULTRA2) != 0) {
-               or      SG_CACHEPTR, LAST_SEG;
-       } else {
-               and     DMAPARAMS, ~WIDEODD;
-       }
+       and     DMAPARAMS, ~WIDEODD;
+}
 data_phase_wideodd:
        if ((p->features & AHC_ULTRA2) != 0) {
                mov     SINDEX, ALLONES;
                mov     DFCNTRL, DMAPARAMS;
-               test    SSTAT0, SDONE jnz .;/* Wait for preload to complete */
+               test    SSTAT0, SDONE jnz .;
 data_phase_dma_loop:
-               test    SSTAT0, SDONE jnz data_phase_dma_done;
+               test    SSTAT0, SDONE jnz data_phase_dma_done;
                test    SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */
 data_phase_dma_phasemis:
                test    SSTAT0,SDONE    jnz . + 2;
-               mov     SINDEX,ALLZEROS;        /* Remeber the phasemiss */
+               clr     SINDEX;                 /* Remember the phasemiss */
        } else {
                mov     DMAPARAMS  call dma;
        }
@@ -554,6 +579,9 @@ sg_load:
                mvi     CCSGCTL, CCSGRESET;
 prefetched_segs_avail:
                bmov    HADDR, CCSGRAM, 8;
+               if ((p->features & AHC_ULTRA2) == 0) {
+                       bmov    STCNT, HCNT, 3;
+               }
        } else {
                mvi     DINDEX, HADDR;
                mvi     SG_NEXT call bcopy_4;
@@ -575,10 +603,6 @@ prefetched_segs_avail:
                 * };
                 */
                mvi     HADDR   call dfdat_in_7;
-       }
-
-       if ((p->features & AHC_ULTRA2) == 0) {
-               /* Load STCNT as well.  It is a mirror of HCNT */
                call    set_stcnt_from_hcnt;
        }
 
@@ -587,28 +611,33 @@ prefetched_segs_avail:
        add     SG_NEXT[0],SG_SIZEOF;
        adc     SG_NEXT[1],A;
 
+       test    SSTAT1, REQINIT jz .;
        test    SSTAT1,PHASEMIS jz data_phase_loop;
-       /* Ensure the last seg is visable at the shaddow layer */
+
        if ((p->features & AHC_ULTRA2) != 0) {
-               or      DFCNTRL, PRELOADEN;
+               mov     DFCNTRL, DMAPARAMS;
+               test    SSTAT0, SDONE jnz .;
        }
 
 data_phase_finish:
-       if ((p->features & AHC_ULTRA2) != 0) {
-               call    ultra2_dmafinish;
-       }
 /*
  * After a DMA finishes, save the SG and STCNT residuals back into the SCB
  * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
  * were transferred on the SCSI (as opposed to the host) bus.
  */
-       mov     SCB_RESID_DCNT[0],STCNT[0];
-       mov     SCB_RESID_DCNT[1],STCNT[1];
-       mov     SCB_RESID_DCNT[2],STCNT[2];
-       mov     SCB_RESID_SGCNT, SG_COUNT;
-
        if ((p->features & AHC_ULTRA2) != 0) {
-               or      SXFRCTL0, CLRSTCNT|CLRCHN;
+               call    ultra2_dmafinish;
+       }
+       if ((p->features & AHC_ULTRA2) == 0) {
+               if ((p->features & AHC_CMD_CHAN) != 0) {
+                       bmov    SCB_RESID_DCNT, STCNT, 3;
+                       mov     SCB_RESID_SGCNT, SG_COUNT;
+               } else {
+                       mov     SCB_RESID_DCNT[0],STCNT[0];
+                       mov     SCB_RESID_DCNT[1],STCNT[1];
+                       mov     SCB_RESID_DCNT[2],STCNT[2];
+                       mov     SCB_RESID_SGCNT, SG_COUNT;
+               }
        }
 
        jmp     ITloop;
@@ -616,7 +645,6 @@ data_phase_finish:
 data_phase_overrun:
        if ((p->features & AHC_ULTRA2) != 0) {
                call    ultra2_dmafinish;
-               or      SXFRCTL0, CLRSTCNT|CLRCHN;
        }
 /*
  * Turn off BITBUCKET mode and notify the host
@@ -635,6 +663,9 @@ ultra2_dmafinish:
 ultra2_dmahalt:
                and     DFCNTRL, ~(SCSIEN|HDMAEN);
                test    DFCNTRL, HDMAEN jnz .;
+               bmov    SCB_RESID_DCNT, STCNT, 3;
+               mov     SCB_RESID_SGCNT, SG_COUNT;
+               or      SXFRCTL0, CLRSTCNT|CLRCHN;
                ret;
        }
 
@@ -647,25 +678,32 @@ p_command:
 /*
  * Load HADDR and HCNT.
  */
-       if ((p->features & AHC_ULTRA2) != 0) {
-               or      SG_CACHEPTR, LAST_SEG;
-       }
-
        if ((p->features & AHC_CMD_CHAN) != 0) {
                bmov    HADDR, SCB_CMDPTR, 5;
                bmov    HCNT[1], ALLZEROS, 2;
+               if ((p->features & AHC_ULTRA2) == 0) {
+                       bmov    STCNT, HCNT, 3;
+               }
        } else {
                mvi     DINDEX, HADDR;
                mvi     SCB_CMDPTR      call bcopy_5;
                clr     HCNT[1];
                clr     HCNT[2];
+               call    set_stcnt_from_hcnt;
        }
 
        if ((p->features & AHC_ULTRA2) == 0) {
-               call    set_stcnt_from_hcnt;
                mvi     (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
        } else {
-               mvi     (PRELOADEN|SCSIEN|HDMAEN|DIRECTION) call dma;
+               mvi     DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+               test    SSTAT0, SDONE jnz .;
+p_command_dma_loop:
+               test    SSTAT0, DMADONE jnz p_command_ultra2_dma_done;
+               test    SSTAT1,PHASEMIS jz p_command_dma_loop;  /* ie. underrun */
+p_command_ultra2_dma_done:
+               and     DFCNTRL, ~(SCSIEN|HDMAEN);
+               test    DFCNTRL, HDMAEN jnz .;
+               or      SXFRCTL0, CLRSTCNT|CLRCHN;
        }
        jmp     ITloop;
 
@@ -698,6 +736,8 @@ p_status:
  * in case the target decides to put us in this phase for some strange
  * reason.
  */
+p_mesgout_retry:
+       or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
 p_mesgout:
        mov     SINDEX, MSG_OUT;
        cmp     SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
@@ -749,9 +789,7 @@ p_mesgout_onebyte:
  * that the target is requesting that the last message(s) be resent.
  */
        call    phase_lock;
-       cmp     LASTPHASE, P_MESGOUT    jne p_mesgout_done;
-       or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
-       jmp     p_mesgout;
+       cmp     LASTPHASE, P_MESGOUT    je p_mesgout_retry;
 
 p_mesgout_done:
        mvi     CLRSINT1,CLRATNO;       /* Be sure to turn ATNO off */
@@ -889,21 +927,23 @@ mesgin_disconnect:
  */
 mesgin_sdptrs:
        test    SEQ_FLAGS, DPHASE       jz mesgin_done;
-       mov     SCB_SGCOUNT,SG_COUNT;
-
-       /* The SCB SGPTR becomes the next one we'll download */
-       mvi     DINDEX, SCB_SGPTR;
-       mvi     SG_NEXT call bcopy_4;
-       
-       /* The SCB DATAPTR0 becomes the current SHADDR */
-       mvi     DINDEX, SCB_DATAPTR;
-       mvi     SHADDR          call bcopy_4;
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer.
- */
-       mvi     SCB_RESID_DCNT  call    bcopy_3;
-
+       /*
+        * The SCB SGPTR becomes the next one we'll download,
+        * and the SCB DATAPTR becomes the current SHADDR.
+        * Use the residual number since STCNT is corrupted by
+        * any message transfer.
+        */
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               bmov    SCB_SGCOUNT, SG_COUNT, 5;
+               bmov    SCB_DATAPTR, SHADDR, 4;
+               bmov    SCB_DATACNT, SCB_RESID_DCNT, 3;
+       } else {
+               mvi     DINDEX, SCB_SGCOUNT;
+               mvi     SG_COUNT        call bcopy_5;
+               mvi     DINDEX, SCB_DATAPTR;
+               mvi     SHADDR          call bcopy_4;
+               mvi     SCB_RESID_DCNT  call    bcopy_3;
+       }
        jmp     mesgin_done;
 
 /*
@@ -934,6 +974,7 @@ mesgin_identify:
        }
        or      SAVED_TCL,A;            /* SAVED_TCL should be complete now */
 
+       mvi     ARG_2, SCB_LIST_NULL;   /* SCBID of prev SCB in disc List */
        call    get_untagged_SCBID;
        cmp     ARG_1, SCB_LIST_NULL    je snoop_tag;
        if ((p->flags & AHC_PAGESCBS) != 0) {
@@ -964,19 +1005,8 @@ snoop_tag_loop:
 get_tag:
        mvi     ARG_1   call inb_next;  /* tag value */
 
-       if ((p->flags & AHC_PAGESCBS) == 0) {
-index_by_tag:
-               mov     SCBPTR,ARG_1;
-               test    SCB_CONTROL,TAG_ENB     jz  not_found;
-               mov     SCBPTR  call rem_scb_from_disc_list;
-       } else {
-               /*
-                * Ensure that the SCB the tag points to is for
-                * an SCB transaction to the reconnecting target.
-                */
 use_retrieveSCB:
-               call    retrieveSCB;
-       }
+       call    retrieveSCB;
 setup_SCB:
        mov     A, SAVED_TCL;
        cmp     SCB_TCL, A      jne not_found_cleanup_scb;
@@ -1079,6 +1109,7 @@ mesgin_phasemis:
  * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
  * during initialization.
  */
+if ((p->features & AHC_ULTRA2) == 0) {
 dma:
        mov     DFCNTRL,SINDEX;
 dma_loop:
@@ -1118,10 +1149,9 @@ dma_halt:
         * to drain the data fifo until there is space for the input
         * latch to drain and HDMAEN de-asserts.
         */
-       if ((p->features & AHC_ULTRA2) == 0) {
-               mov     NONE, DFDAT;
-       }
-       test    DFCNTRL, HDMAEN jnz dma_halt;
+       mov     NONE, DFDAT;
+       test    DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+}
 return:
        ret;
 
@@ -1150,6 +1180,7 @@ findSCB_by_SCBID:
        mov     A, ARG_1;                       /* Tag passed in ARG_1 */
        mvi     SCB_TAG jmp findSCB_loop;       /* &SCB_TAG -> SINDEX */
 findSCB_next:
+       mov     ARG_2, SCBPTR;
        cmp     SCB_NEXT, SCB_LIST_NULL je notFound;
        mov     SCBPTR,SCB_NEXT;
        dec     SINDEX;         /* Last comparison moved us too far */
@@ -1173,19 +1204,15 @@ retrieveSCB:
 
 /*
  * This routine expects SINDEX to contain the index of the SCB to be
- * removed and SCBPTR to be pointing to that SCB.
+ * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the
+ * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL
+ * if it is at the head.
  */
 rem_scb_from_disc_list:
 /* Remove this SCB from the disconnection list */
-       cmp     SCB_NEXT,SCB_LIST_NULL je unlink_prev;
-       mov     DINDEX, SCB_PREV;
-       mov     SCBPTR, SCB_NEXT;
-       mov     SCB_PREV, DINDEX;
-       mov     SCBPTR, SINDEX;
-unlink_prev:
-       cmp     SCB_PREV,SCB_LIST_NULL  je rHead;/* At the head of the list */
+       cmp     ARG_2, SCB_LIST_NULL    je rHead;
        mov     DINDEX, SCB_NEXT;
-       mov     SCBPTR, SCB_PREV;
+       mov     SCBPTR, ARG_2;
        mov     SCB_NEXT, DINDEX;
        mov     SCBPTR, SINDEX ret;
 rHead:
@@ -1285,9 +1312,10 @@ get_SCBID_from_host:
 phase_lock:     
        test    SSTAT1, REQINIT jz phase_lock;
        test    SSTAT1, SCSIPERR jnz phase_lock;
-       and     LASTPHASE, PHASE_MASK, SCSISIGI;
-       mov     SCSISIGO, LASTPHASE ret;
+       and     SCSISIGO, PHASE_MASK, SCSISIGI;
+       and     LASTPHASE, PHASE_MASK, SCSISIGI ret;
 
+if ((p->features & AHC_CMD_CHAN) == 0) {
 set_stcnt_from_hcnt:
        mov     STCNT[0], HCNT[0];
        mov     STCNT[1], HCNT[1];
@@ -1304,6 +1332,7 @@ bcopy_3:
        mov     DINDIR, SINDIR;
        mov     DINDIR, SINDIR;
        mov     DINDIR, SINDIR ret;
+}
 
 /*
  * Setup addr assuming that A is an index into
@@ -1407,12 +1436,14 @@ dfdat_in_7_continued:
  * Wait for DMA from host memory to data FIFO to complete, then disable
  * DMA and wait for it to acknowledge that it's off.
  */
+if ((p->features & AHC_CMD_CHAN) == 0) {
 dma_finish:
        test    DFSTATUS,HDONE  jz dma_finish;
        /* Turn off DMA */
        and     DFCNTRL, ~HDMAEN;
        test    DFCNTRL, HDMAEN jnz .;
        ret;
+}
 
 add_scb_to_free_list:
        if ((p->flags & AHC_PAGESCBS) != 0) {
@@ -1433,8 +1464,7 @@ dma_up_scb:
        mvi     DMAPARAMS, FIFORESET;
        mov     SCB_TAG         call dma_scb;
 unlink_disc_scb:
-       /* jmp instead of call since we want to return anyway */
-       mov     SCBPTR  jmp rem_scb_from_disc_list;
+       mov     DISCONNECTED_SCBH, SCB_NEXT ret;
 dequeue_free_scb:
        mov     SCBPTR, FREE_SCBH;
        mov     FREE_SCBH, SCB_NEXT ret;
@@ -1446,10 +1476,5 @@ add_scb_to_disc_list:
  * candidates for paging out an SCB if one is needed for a new command.
  * Modifying the disconnected list is a critical(pause dissabled) section.
  */
-       mvi     SCB_PREV, SCB_LIST_NULL;
        mov     SCB_NEXT, DISCONNECTED_SCBH;
-       mov     DISCONNECTED_SCBH, SCBPTR;
-       cmp     SCB_NEXT,SCB_LIST_NULL je return;
-       mov     SCBPTR,SCB_NEXT;
-       mov     SCB_PREV,DISCONNECTED_SCBH;
-       mov     SCBPTR,DISCONNECTED_SCBH ret;
+       mov     DISCONNECTED_SCBH, SCBPTR ret;
index 16c40138893204060a9e32e784639357f70e80af..a79f89c651732d5f4b466ae73ad35e14deac467d 100644 (file)
 #define MSG_EXT_WDTR_LEN       0x02
 #define MSG_EXT_WDTR_BUS_8_BIT 0x00
 #define MSG_EXT_WDTR_BUS_16_BIT        0x01
-#define MSG_EXT_WDTR_BUS_32_BIT        0x02 
+#define MSG_EXT_WDTR_BUS_32_BIT        0x02
+
+#define MSG_EXT_PPR     0x04
+#define MSG_EXT_PPR_LEN        0x06
+#define MSG_EXT_PPR_OPTION_ST 0x00
+#define MSG_EXT_PPR_OPTION_DT_CRC 0x02
+#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03
+#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04
+#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05
index 6e5eca864a8c6dc7ff469b371addf5b9e0350145..3314514f4f5f8f9b592a2bbb7e473c7d4c24967a 100644 (file)
@@ -160,21 +160,17 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Compile Options:\n");
-#ifdef AIC7XXX_RESET_DELAY
-  size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
+#else
+  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
 #endif
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
-  size += sprintf(BLS, "                             Check below to see "
-                       "which\n"
-                       "                             devices use tagged "
-                       "queueing\n");
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled (This is no longer "
-                       "an option)\n");
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
 #else
   size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
 #endif
+  size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
   size += sprintf(BLS, "           SCSI Adapter: %s\n",
@@ -194,8 +190,21 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
     }
     if (p->features & AHC_WIDE)
       wide = "Wide ";
-    if (p->features & AHC_ULTRA2)
-      ultra = "Ultra2-LVD/SE ";
+    if (p->features & AHC_ULTRA3)
+    {
+      switch(p->chip & AHC_CHIPID_MASK)
+      {
+        case AHC_AIC7892:
+        case AHC_AIC7899:
+          ultra = "Ultra-160/m LVD/SE ";
+          break;
+        default:
+          ultra = "Ultra-3 LVD/SE ";
+          break;
+      }
+    }
+    else if (p->features & AHC_ULTRA2)
+      ultra = "Ultra-2 LVD/SE ";
     else if (p->features & AHC_ULTRA)
       ultra = "Ultra ";
     size += sprintf(BLS, "                           %s%sController%s\n",
@@ -250,11 +259,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   }
   size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
   size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
-#ifdef AIC7XXX_CMDS_PER_LUN
-  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
-#else
-  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
-#endif
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
   size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
                        "instance %d:\n", p->instance);
   size += sprintf(BLS, "      {");
@@ -295,11 +300,12 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
     if (p->transinfo[target].cur_offset != 0)
     {
       struct aic7xxx_syncrate *sync_rate;
+      unsigned char options = p->transinfo[target].cur_options;
       int period = p->transinfo[target].cur_period;
       int rate = (p->transinfo[target].cur_width ==
                   MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
 
-      sync_rate = aic7xxx_find_syncrate(p, &period, AHC_SYNCRATE_ULTRA2);
+      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
       if (sync_rate != NULL)
       {
         size += sprintf(BLS, "%s MByte/sec, offset %d\n",
@@ -313,18 +319,21 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
       }
     }
     size += sprintf(BLS, "  Transinfo settings: ");
-    size += sprintf(BLS, "current(%d/%d/%d), ",
+    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
                     p->transinfo[target].cur_period,
                     p->transinfo[target].cur_offset,
-                    p->transinfo[target].cur_width);
-    size += sprintf(BLS, "goal(%d/%d/%d), ",
+                    p->transinfo[target].cur_width,
+                    p->transinfo[target].cur_options);
+    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
                     p->transinfo[target].goal_period,
                     p->transinfo[target].goal_offset,
-                    p->transinfo[target].goal_width);
-    size += sprintf(BLS, "user(%d/%d/%d)\n",
+                    p->transinfo[target].goal_width,
+                    p->transinfo[target].goal_options);
+    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
                     p->transinfo[target].user_period,
                     p->transinfo[target].user_offset,
-                    p->transinfo[target].user_width);
+                    p->transinfo[target].user_width,
+                    p->transinfo[target].user_options);
 #ifdef AIC7XXX_PROC_STATS
     size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
         sp->r_total + sp->w_total, sp->r_total, sp->w_total);
index d12d1b6e54a53ab30116bc1f6bb8c75a730915cc..b42750864288e66e2a1143273a5fca561c333229 100644 (file)
 
 #define        STCNT                           0x08
 
+#define        OPTIONMODE                      0x08
+#define                AUTORATEEN              0x80
+#define                AUTOACKEN               0x40
+#define                ATNMGMNTEN              0x20
+#define                BUSFREEREV              0x10
+#define                EXPPHASEDIS             0x08
+#define                SCSIDATL_IMGEN          0x04
+#define                AUTO_MSGOUT_DE          0x02
+#define                DIS_MSGIN_DUALEDGE      0x01
+
 #define        CLRSINT0                        0x0b
 #define                CLRSELDO                0x40
 #define                CLRSELDI                0x20
 
 #define        SSTAT2                          0x0d
 #define                OVERRUN                 0x80
+#define                SHVALID                 0x40
+#define                WIDE_RES                0x20
 #define                SFCNT                   0x1f
 #define                EXP_ACTIVE              0x10
+#define                CRCVALERR               0x08
+#define                CRCENDERR               0x04
+#define                CRCREQERR               0x02
+#define                DUAL_EDGE_ERROR         0x01
 
 #define        SSTAT3                          0x0e
 #define                SCSICNT                 0xf0
 #define                DPARERR                 0x10
 #define                SQPARERR                0x08
 #define                ILLOPCODE               0x04
+#define                DSCTMOUT                0x02
 #define                ILLSADDR                0x02
 #define                ILLHADDR                0x01
 
 
 #define        QINCNT                          0x9c
 
+#define        SCSIDATL_IMG                    0x9c
+
 #define        QOUTFIFO                        0x9d
 
+#define        CRCCONTROL1                     0x9d
+#define                CRCONSEEN               0x80
+#define                TARGCRCCNTEN            0x40
+#define                CRCVALCHKEN             0x40
+#define                CRCENDCHKEN             0x20
+#define                CRCREQCHKEN             0x10
+#define                TARGCRCENDEN            0x08
+
+#define        SCSIPHASE                       0x9e
+#define                SP_STATUS               0x20
+#define                SP_COMMAND              0x10
+#define                SP_MSG_IN               0x08
+#define                SP_MSG_OUT              0x04
+#define                SP_DATA_IN              0x02
+#define                SP_DATA_OUT             0x01
+
 #define        QOUTCNT                         0x9e
 
 #define        SFUNCT                          0x9f
+#define                ALT_MODE                0x80
 
 #define        SCB_CONTROL                     0xa0
 #define                MK_MESSAGE              0x80
 
 #define        HNSCB_QOFF                      0xf4
 
+#define        HESCB_QOFF                      0xf5
+
 #define        SNSCB_QOFF                      0xf6
 
+#define        SESCB_QOFF                      0xf7
+
 #define        SDSCB_QOFF                      0xf8
 
 #define        QOFF_CTLSTA                     0xfa
+#define                ESTABLISH_SCB_AVAIL     0x80
 #define                SCB_AVAIL               0x40
 #define                SNSCB_ROLLOVER          0x20
 #define                SDSCB_ROLLOVER          0x10
+#define                SESCB_ROLLOVER          0x08
 #define                SCB_QSIZE               0x07
 #define                SCB_QSIZE_256           0x06
 
index 9205cc4af388a6ee59534c06480694cab5ff6bbe..f11373fef1539ed88ee38b7cc9217d61379ffe27 100644 (file)
@@ -3,38 +3,44 @@
   */
 static unsigned char seqprog[] = {
        0xff, 0x6a, 0x06, 0x08,
+       0x7f, 0x02, 0x04, 0x08,
        0x32, 0x6a, 0x00, 0x00,
        0x12, 0x6a, 0x00, 0x00,
        0xff, 0x6a, 0xd6, 0x09,
        0xff, 0x6a, 0xdc, 0x09,
-       0x00, 0x65, 0x38, 0x59,
+       0x00, 0x65, 0x42, 0x59,
        0xf7, 0x01, 0x02, 0x08,
        0xff, 0x4e, 0xc8, 0x08,
        0xbf, 0x60, 0xc0, 0x08,
-       0x60, 0x0b, 0x7c, 0x68,
+       0x60, 0x0b, 0x86, 0x68,
        0x40, 0x00, 0x0e, 0x68,
        0x08, 0x1f, 0x3e, 0x10,
-       0x60, 0x0b, 0x7c, 0x68,
+       0x60, 0x0b, 0x86, 0x68,
        0x40, 0x00, 0x0e, 0x68,
        0x08, 0x1f, 0x3e, 0x10,
-       0xff, 0x3e, 0x3e, 0x60,
-       0x40, 0xfa, 0x10, 0x78,
+       0xff, 0x3e, 0x4a, 0x60,
+       0x40, 0xfa, 0x12, 0x78,
        0xff, 0xf6, 0xd4, 0x08,
        0x01, 0x4e, 0x9c, 0x18,
        0x40, 0x60, 0xc0, 0x00,
-       0x00, 0x4d, 0x10, 0x70,
+       0x00, 0x4d, 0x12, 0x70,
        0x01, 0x4e, 0x9c, 0x18,
        0xbf, 0x60, 0xc0, 0x08,
-       0x00, 0x6a, 0x72, 0x5c,
+       0x00, 0x6a, 0x92, 0x5c,
        0xff, 0x4e, 0xc8, 0x18,
-       0x02, 0x6a, 0x88, 0x5b,
+       0x02, 0x6a, 0xa8, 0x5b,
        0xff, 0x52, 0x20, 0x09,
        0x0d, 0x6a, 0x6a, 0x00,
-       0x00, 0x52, 0xfe, 0x5b,
+       0x00, 0x52, 0x1e, 0x5c,
+       0x03, 0xb0, 0x52, 0x31,
+       0xff, 0xb0, 0x52, 0x09,
+       0xff, 0xb1, 0x54, 0x09,
+       0xff, 0xb2, 0x56, 0x09,
+       0xff, 0xa3, 0x50, 0x09,
        0xff, 0x3e, 0x74, 0x09,
        0xff, 0x90, 0x7c, 0x08,
        0xff, 0x3e, 0x20, 0x09,
-       0x00, 0x65, 0x44, 0x58,
+       0x00, 0x65, 0x50, 0x58,
        0x00, 0x65, 0x0e, 0x40,
        0xf7, 0x1f, 0xca, 0x08,
        0x08, 0xa1, 0xc8, 0x08,
@@ -47,51 +53,50 @@ static unsigned char seqprog[] = {
        0x0f, 0x05, 0x0a, 0x08,
        0x00, 0x05, 0x0a, 0x00,
        0x5a, 0x6a, 0x00, 0x04,
-       0x12, 0x65, 0xc8, 0x00,
-       0x00, 0x01, 0x02, 0x00,
+       0x12, 0x65, 0x02, 0x00,
        0x31, 0x6a, 0xca, 0x00,
-       0x80, 0x37, 0x64, 0x68,
+       0x80, 0x37, 0x6e, 0x68,
        0xff, 0x65, 0xca, 0x18,
        0xff, 0x37, 0xdc, 0x08,
        0xff, 0x6e, 0xc8, 0x08,
-       0x00, 0x6c, 0x6c, 0x78,
+       0x00, 0x6c, 0x76, 0x78,
        0x20, 0x01, 0x02, 0x00,
        0x4c, 0x37, 0xc8, 0x28,
-       0x08, 0x1f, 0x74, 0x78,
+       0x08, 0x1f, 0x7e, 0x78,
        0x08, 0x37, 0x6e, 0x00,
        0x08, 0x64, 0xc8, 0x00,
        0x70, 0x64, 0xca, 0x18,
        0xff, 0x6c, 0x0a, 0x08,
        0x20, 0x64, 0xca, 0x18,
        0xff, 0x6c, 0x08, 0x0c,
-       0x40, 0x0b, 0x04, 0x69,
-       0x80, 0x0b, 0xf6, 0x78,
+       0x40, 0x0b, 0x0e, 0x69,
+       0x80, 0x0b, 0x00, 0x79,
        0xa4, 0x6a, 0x06, 0x00,
        0x40, 0x6a, 0x16, 0x00,
-       0x10, 0x03, 0xf2, 0x78,
+       0x10, 0x03, 0xfc, 0x78,
        0xff, 0x50, 0xc8, 0x08,
        0x88, 0x6a, 0xcc, 0x00,
-       0x49, 0x6a, 0xee, 0x5b,
+       0x49, 0x6a, 0x0e, 0x5c,
        0x01, 0x6a, 0x26, 0x01,
        0xff, 0x6a, 0xca, 0x08,
        0x08, 0x01, 0x02, 0x00,
-       0x02, 0x0b, 0x92, 0x78,
+       0x02, 0x0b, 0x9c, 0x78,
        0xf7, 0x01, 0x02, 0x08,
        0xff, 0x06, 0xcc, 0x08,
        0xff, 0x66, 0x32, 0x09,
        0x01, 0x65, 0xca, 0x18,
-       0x80, 0x66, 0xa0, 0x78,
+       0x80, 0x66, 0xaa, 0x78,
        0xff, 0x66, 0xa2, 0x08,
-       0x10, 0x03, 0x90, 0x68,
+       0x10, 0x03, 0x9a, 0x68,
        0xfc, 0x65, 0xc8, 0x18,
-       0x00, 0x65, 0xa8, 0x48,
+       0x00, 0x65, 0xb2, 0x48,
        0xff, 0x6a, 0x32, 0x01,
        0x01, 0x64, 0x18, 0x19,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
        0x84, 0x6a, 0x06, 0x00,
        0x08, 0x01, 0x02, 0x00,
-       0x02, 0x0b, 0xb2, 0x78,
+       0x02, 0x0b, 0xbc, 0x78,
        0xff, 0x06, 0xc8, 0x08,
        0xff, 0x64, 0x32, 0x09,
        0xff, 0x6a, 0xca, 0x08,
@@ -105,33 +110,33 @@ static unsigned char seqprog[] = {
        0x0b, 0x65, 0xca, 0x18,
        0xff, 0x65, 0xc8, 0x08,
        0x00, 0x8c, 0x18, 0x19,
-       0x02, 0x0b, 0xce, 0x78,
-       0x01, 0x65, 0xd4, 0x60,
+       0x02, 0x0b, 0xd8, 0x78,
+       0x01, 0x65, 0xde, 0x60,
        0xf7, 0x01, 0x02, 0x08,
        0xff, 0x06, 0x32, 0x09,
        0xff, 0x65, 0xca, 0x18,
-       0xff, 0x65, 0xce, 0x68,
+       0xff, 0x65, 0xd8, 0x68,
        0x0a, 0x93, 0x26, 0x01,
-       0x00, 0x65, 0x64, 0x5c,
-       0x40, 0x51, 0xe6, 0x78,
+       0x00, 0x65, 0x84, 0x5c,
+       0x40, 0x51, 0xf0, 0x78,
        0xe4, 0x6a, 0x06, 0x00,
        0x08, 0x01, 0x02, 0x00,
-       0x04, 0x6a, 0x18, 0x5b,
+       0x04, 0x6a, 0x40, 0x5b,
        0x01, 0x50, 0xa0, 0x18,
-       0x00, 0x50, 0xec, 0xe0,
+       0x00, 0x50, 0xf6, 0xe0,
        0xff, 0x6a, 0xa0, 0x08,
        0xff, 0x6a, 0x3a, 0x01,
        0x02, 0x6a, 0x22, 0x01,
-       0x40, 0x51, 0xf2, 0x68,
+       0x40, 0x51, 0xfc, 0x68,
        0xff, 0x6a, 0x06, 0x08,
        0x00, 0x65, 0x0e, 0x40,
        0x20, 0x6a, 0x16, 0x00,
        0xf0, 0x19, 0x6e, 0x08,
        0x08, 0x6a, 0x18, 0x00,
        0x08, 0x11, 0x22, 0x00,
-       0x08, 0x6a, 0x5a, 0x58,
+       0x08, 0x6a, 0x66, 0x58,
        0x08, 0x6a, 0x68, 0x00,
-       0x00, 0x65, 0x18, 0x41,
+       0x00, 0x65, 0x22, 0x41,
        0x12, 0x6a, 0x00, 0x00,
        0x40, 0x6a, 0x16, 0x00,
        0xff, 0x3e, 0x20, 0x09,
@@ -139,362 +144,373 @@ static unsigned char seqprog[] = {
        0xff, 0xa1, 0x6e, 0x08,
        0x08, 0x6a, 0x18, 0x00,
        0x08, 0x11, 0x22, 0x00,
-       0x08, 0x6a, 0x5a, 0x58,
+       0x08, 0x6a, 0x66, 0x58,
        0x80, 0x6a, 0x68, 0x00,
        0x80, 0x36, 0x6c, 0x00,
-       0x00, 0x65, 0xd2, 0x5b,
+       0x00, 0x65, 0xf2, 0x5b,
        0xff, 0x3d, 0xc8, 0x08,
-       0xbf, 0x64, 0x48, 0x79,
-       0x80, 0x64, 0xf0, 0x71,
-       0xa0, 0x64, 0x0e, 0x72,
-       0xc0, 0x64, 0x08, 0x72,
-       0xe0, 0x64, 0x52, 0x72,
+       0xbf, 0x64, 0x58, 0x79,
+       0x80, 0x64, 0x0e, 0x72,
+       0xa0, 0x64, 0x3a, 0x72,
+       0xc0, 0x64, 0x32, 0x72,
+       0xe0, 0x64, 0x7a, 0x72,
        0x01, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x18, 0x41,
+       0x00, 0x65, 0x22, 0x41,
        0xf7, 0x11, 0x22, 0x08,
-       0x00, 0x65, 0x38, 0x59,
+       0x00, 0x65, 0x42, 0x59,
        0xff, 0x06, 0xd4, 0x08,
        0xf7, 0x01, 0x02, 0x08,
-       0x09, 0x0c, 0x32, 0x79,
+       0x09, 0x0c, 0x3c, 0x79,
        0x08, 0x0c, 0x0e, 0x68,
        0x01, 0x6a, 0x22, 0x01,
        0xff, 0x6a, 0x26, 0x09,
+       0x02, 0x6a, 0x08, 0x30,
        0xff, 0x6a, 0x08, 0x08,
        0xdf, 0x01, 0x02, 0x08,
        0x01, 0x6a, 0x7a, 0x00,
-       0x03, 0x36, 0x6c, 0x0c,
+       0xff, 0x6a, 0x6c, 0x0c,
+       0x03, 0xa9, 0x18, 0x31,
+       0x03, 0xa9, 0x10, 0x30,
        0x08, 0x6a, 0xcc, 0x00,
-       0xa9, 0x6a, 0xe8, 0x5b,
-       0x00, 0x65, 0x66, 0x41,
+       0xa9, 0x6a, 0x08, 0x5c,
+       0x00, 0x65, 0x78, 0x41,
        0xa8, 0x6a, 0x6a, 0x00,
        0x79, 0x6a, 0x6a, 0x00,
-       0x40, 0x3d, 0x50, 0x69,
+       0x40, 0x3d, 0x60, 0x69,
        0x04, 0x35, 0x6a, 0x00,
-       0x00, 0x65, 0x3a, 0x5b,
+       0x00, 0x65, 0x62, 0x5b,
        0x80, 0x6a, 0xd4, 0x01,
-       0x10, 0x36, 0x42, 0x69,
+       0x10, 0x36, 0x4e, 0x69,
        0x10, 0x36, 0x6c, 0x00,
        0x07, 0xac, 0x10, 0x31,
+       0x03, 0x8c, 0x10, 0x30,
+       0x05, 0xa3, 0x70, 0x30,
        0x88, 0x6a, 0xcc, 0x00,
-       0xac, 0x6a, 0xe0, 0x5b,
-       0x00, 0x65, 0xda, 0x5b,
-       0xff, 0xa3, 0x70, 0x08,
-       0x39, 0x6a, 0xcc, 0x00,
-       0xa4, 0x6a, 0xe6, 0x5b,
-       0xff, 0x38, 0x74, 0x69,
+       0xac, 0x6a, 0x00, 0x5c,
+       0x00, 0x65, 0xfa, 0x5b,
+       0x38, 0x6a, 0xcc, 0x00,
+       0xa3, 0x6a, 0x04, 0x5c,
+       0xff, 0x38, 0x88, 0x69,
        0x80, 0x02, 0x04, 0x00,
        0xe7, 0x35, 0x6a, 0x08,
        0x03, 0x69, 0x18, 0x31,
+       0x03, 0x69, 0x10, 0x30,
        0xff, 0x6a, 0x10, 0x00,
        0xff, 0x6a, 0x12, 0x00,
        0xff, 0x6a, 0x14, 0x00,
-       0x01, 0x38, 0x7a, 0x61,
-       0x02, 0xfc, 0xf8, 0x01,
+       0x01, 0x38, 0x8c, 0x61,
        0xbf, 0x35, 0x6a, 0x08,
        0xff, 0x69, 0xca, 0x08,
        0xff, 0x35, 0x26, 0x09,
-       0x04, 0x0b, 0x7e, 0x69,
-       0x04, 0x0b, 0x8a, 0x69,
-       0x10, 0x0c, 0x80, 0x79,
-       0x04, 0x0b, 0x88, 0x69,
+       0x04, 0x0b, 0x90, 0x69,
+       0x04, 0x0b, 0x9c, 0x69,
+       0x10, 0x0c, 0x92, 0x79,
+       0x04, 0x0b, 0x9a, 0x69,
        0xff, 0x6a, 0xca, 0x08,
-       0x00, 0x35, 0x22, 0x5b,
-       0x80, 0x02, 0xd6, 0x69,
-       0xff, 0x65, 0xc8, 0x79,
+       0x00, 0x35, 0x4a, 0x5b,
+       0x80, 0x02, 0xf0, 0x69,
+       0xff, 0x65, 0xe0, 0x79,
        0xff, 0x38, 0x70, 0x18,
-       0xff, 0x38, 0xc8, 0x79,
-       0x80, 0xea, 0xaa, 0x61,
+       0xff, 0x38, 0xe0, 0x79,
+       0x80, 0xea, 0xbc, 0x61,
        0xef, 0x38, 0xc8, 0x18,
        0x80, 0x6a, 0xc8, 0x00,
-       0x00, 0x65, 0x9c, 0x49,
+       0x00, 0x65, 0xae, 0x49,
        0x33, 0x38, 0xc8, 0x28,
        0xff, 0x64, 0xd0, 0x09,
        0x04, 0x39, 0xc0, 0x31,
        0x09, 0x6a, 0xd6, 0x01,
-       0x80, 0xeb, 0xa2, 0x79,
+       0x80, 0xeb, 0xb4, 0x79,
        0xf7, 0xeb, 0xd6, 0x09,
-       0x08, 0xeb, 0xa6, 0x69,
+       0x08, 0xeb, 0xb8, 0x69,
        0x01, 0x6a, 0xd6, 0x01,
        0x08, 0xe9, 0x10, 0x31,
+       0x03, 0x8c, 0x10, 0x30,
        0x88, 0x6a, 0xcc, 0x00,
-       0x39, 0x6a, 0xe6, 0x5b,
+       0x39, 0x6a, 0x06, 0x5c,
        0x08, 0x6a, 0x18, 0x01,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
        0x0d, 0x93, 0x26, 0x01,
-       0x00, 0x65, 0x64, 0x5c,
-       0x88, 0x6a, 0x54, 0x5c,
-       0x00, 0x65, 0xda, 0x5b,
+       0x00, 0x65, 0x84, 0x5c,
+       0x88, 0x6a, 0x74, 0x5c,
+       0x00, 0x65, 0xfa, 0x5b,
        0xff, 0x6a, 0xc8, 0x08,
        0x08, 0x39, 0x72, 0x18,
        0x00, 0x3a, 0x74, 0x20,
-       0x10, 0x0c, 0x66, 0x79,
-       0x80, 0x93, 0x26, 0x01,
-       0x00, 0x65, 0xe0, 0x59,
+       0x01, 0x0c, 0xd8, 0x79,
+       0x10, 0x0c, 0x78, 0x79,
+       0xff, 0x35, 0x26, 0x09,
+       0x04, 0x0b, 0xde, 0x69,
+       0x00, 0x65, 0xf8, 0x59,
+       0x03, 0x08, 0x52, 0x31,
+       0xff, 0x38, 0x50, 0x09,
        0xff, 0x08, 0x52, 0x09,
        0xff, 0x09, 0x54, 0x09,
        0xff, 0x0a, 0x56, 0x09,
        0xff, 0x38, 0x50, 0x09,
-       0x12, 0x01, 0x02, 0x00,
-       0x00, 0x65, 0x18, 0x41,
-       0x00, 0x65, 0xe0, 0x59,
-       0x12, 0x01, 0x02, 0x00,
+       0x00, 0x65, 0x22, 0x41,
+       0x00, 0x65, 0xf8, 0x59,
        0x7f, 0x02, 0x04, 0x08,
        0xe1, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x18, 0x41,
-       0x04, 0x93, 0xea, 0x69,
+       0x00, 0x65, 0x22, 0x41,
+       0x04, 0x93, 0x02, 0x6a,
        0xdf, 0x93, 0x26, 0x09,
-       0x20, 0x93, 0xe4, 0x69,
+       0x20, 0x93, 0xfc, 0x69,
        0x02, 0x93, 0x26, 0x01,
-       0x01, 0x94, 0xe6, 0x79,
+       0x01, 0x94, 0xfe, 0x79,
        0xd7, 0x93, 0x26, 0x09,
-       0x08, 0x93, 0xec, 0x69,
+       0x08, 0x93, 0x04, 0x6a,
+       0x03, 0x08, 0x52, 0x31,
+       0xff, 0x38, 0x50, 0x09,
+       0x12, 0x01, 0x02, 0x00,
        0xff, 0x6a, 0xd4, 0x0c,
-       0x00, 0x65, 0x3a, 0x5b,
-       0x02, 0xfc, 0xf8, 0x01,
+       0x00, 0x65, 0x62, 0x5b,
        0x05, 0xb4, 0x10, 0x31,
        0x02, 0x6a, 0x1a, 0x31,
+       0x03, 0x8c, 0x10, 0x30,
        0x88, 0x6a, 0xcc, 0x00,
-       0xb4, 0x6a, 0xe4, 0x5b,
+       0xb4, 0x6a, 0x04, 0x5c,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
-       0x00, 0x65, 0xda, 0x5b,
-       0x3d, 0x6a, 0x22, 0x5b,
-       0xac, 0x6a, 0x22, 0x5b,
-       0x00, 0x65, 0x18, 0x41,
-       0x00, 0x65, 0x3a, 0x5b,
+       0x00, 0x65, 0xfa, 0x5b,
+       0x3d, 0x6a, 0x4a, 0x5b,
+       0xac, 0x6a, 0x26, 0x01,
+       0x04, 0x0b, 0x24, 0x6a,
+       0x01, 0x0b, 0x2a, 0x6a,
+       0x10, 0x0c, 0x26, 0x7a,
+       0xd7, 0x93, 0x26, 0x09,
+       0x08, 0x93, 0x2c, 0x6a,
+       0x12, 0x01, 0x02, 0x00,
+       0x00, 0x65, 0x22, 0x41,
+       0x00, 0x65, 0x62, 0x5b,
        0xff, 0x06, 0x44, 0x09,
-       0x00, 0x65, 0x18, 0x41,
+       0x00, 0x65, 0x22, 0x41,
+       0x10, 0x3d, 0x06, 0x00,
        0xff, 0x34, 0xca, 0x08,
-       0x80, 0x65, 0x32, 0x62,
+       0x80, 0x65, 0x5e, 0x62,
        0x0f, 0xa1, 0xca, 0x08,
        0x07, 0xa1, 0xca, 0x08,
        0x40, 0xa0, 0xc8, 0x08,
        0x00, 0x65, 0xca, 0x00,
        0x80, 0x65, 0xca, 0x00,
-       0x80, 0xa0, 0x22, 0x7a,
+       0x80, 0xa0, 0x4e, 0x7a,
        0xff, 0x65, 0x0c, 0x08,
-       0x00, 0x65, 0x34, 0x42,
-       0x20, 0xa0, 0x3a, 0x7a,
+       0x00, 0x65, 0x60, 0x42,
+       0x20, 0xa0, 0x66, 0x7a,
        0xff, 0x65, 0x0c, 0x08,
-       0x00, 0x65, 0xd2, 0x5b,
-       0xa0, 0x3d, 0x46, 0x62,
+       0x00, 0x65, 0xf2, 0x5b,
+       0xa0, 0x3d, 0x6e, 0x62,
        0x23, 0xa0, 0x0c, 0x08,
-       0x00, 0x65, 0xd2, 0x5b,
-       0xa0, 0x3d, 0x46, 0x62,
-       0x00, 0xb9, 0x3a, 0x42,
-       0xff, 0x65, 0x3a, 0x62,
+       0x00, 0x65, 0xf2, 0x5b,
+       0xa0, 0x3d, 0x6e, 0x62,
+       0x00, 0xb9, 0x66, 0x42,
+       0xff, 0x65, 0x66, 0x62,
        0xa1, 0x6a, 0x22, 0x01,
        0xff, 0x6a, 0xd4, 0x08,
-       0x10, 0x51, 0x46, 0x72,
+       0x10, 0x51, 0x6e, 0x72,
        0x40, 0x6a, 0x18, 0x00,
        0xff, 0x65, 0x0c, 0x08,
-       0x00, 0x65, 0xd2, 0x5b,
-       0xa0, 0x3d, 0x46, 0x62,
-       0x10, 0x3d, 0x06, 0x00,
-       0x00, 0x65, 0x0e, 0x42,
+       0x00, 0x65, 0xf2, 0x5b,
+       0xa0, 0x3d, 0x38, 0x72,
        0x40, 0x6a, 0x18, 0x00,
        0xff, 0x34, 0xa6, 0x08,
-       0x80, 0x34, 0x4e, 0x62,
+       0x80, 0x34, 0x76, 0x62,
        0x7f, 0xa0, 0x40, 0x09,
        0x08, 0x6a, 0x68, 0x00,
-       0x00, 0x65, 0x18, 0x41,
-       0x64, 0x6a, 0x12, 0x5b,
-       0x80, 0x64, 0xbe, 0x6a,
-       0x04, 0x64, 0xa4, 0x72,
-       0x02, 0x64, 0xaa, 0x72,
-       0x00, 0x6a, 0x6c, 0x72,
-       0x03, 0x64, 0xba, 0x72,
-       0x01, 0x64, 0xa0, 0x72,
-       0x07, 0x64, 0x00, 0x73,
-       0x08, 0x64, 0x68, 0x72,
+       0x00, 0x65, 0x22, 0x41,
+       0x64, 0x6a, 0x3a, 0x5b,
+       0x80, 0x64, 0xea, 0x6a,
+       0x04, 0x64, 0xcc, 0x72,
+       0x02, 0x64, 0xd2, 0x72,
+       0x00, 0x6a, 0x94, 0x72,
+       0x03, 0x64, 0xe6, 0x72,
+       0x01, 0x64, 0xc8, 0x72,
+       0x07, 0x64, 0x28, 0x73,
+       0x08, 0x64, 0x90, 0x72,
        0x11, 0x6a, 0x22, 0x01,
-       0x07, 0x6a, 0x04, 0x5b,
+       0x07, 0x6a, 0x2c, 0x5b,
        0xff, 0x06, 0xd4, 0x08,
-       0x00, 0x65, 0x18, 0x41,
-       0xff, 0xa8, 0x70, 0x6a,
-       0xff, 0xa2, 0x88, 0x7a,
+       0x00, 0x65, 0x22, 0x41,
+       0xff, 0xa8, 0x98, 0x6a,
+       0xff, 0xa2, 0xb0, 0x7a,
        0x01, 0x6a, 0x6a, 0x00,
-       0x00, 0xb9, 0xfe, 0x5b,
-       0xff, 0xa2, 0x88, 0x7a,
+       0x00, 0xb9, 0x1e, 0x5c,
+       0xff, 0xa2, 0xb0, 0x7a,
        0x71, 0x6a, 0x22, 0x01,
        0xff, 0x6a, 0xd4, 0x08,
-       0x40, 0x51, 0x88, 0x62,
+       0x40, 0x51, 0xb0, 0x62,
        0x0d, 0x6a, 0x6a, 0x00,
-       0x00, 0xb9, 0xfe, 0x5b,
+       0x00, 0xb9, 0x1e, 0x5c,
        0xff, 0x3e, 0x74, 0x09,
        0xff, 0x90, 0x7c, 0x08,
-       0x00, 0x65, 0x44, 0x58,
-       0x00, 0x65, 0x2a, 0x41,
-       0x20, 0xa0, 0x90, 0x6a,
+       0x00, 0x65, 0x50, 0x58,
+       0x00, 0x65, 0x34, 0x41,
+       0x20, 0xa0, 0xb8, 0x6a,
        0xff, 0x37, 0xc8, 0x08,
-       0x00, 0x6a, 0xa8, 0x5b,
-       0xff, 0x6a, 0xbe, 0x5b,
+       0x00, 0x6a, 0xc8, 0x5b,
+       0xff, 0x6a, 0xde, 0x5b,
        0xff, 0xf8, 0xc8, 0x08,
        0xff, 0x4f, 0xc8, 0x08,
-       0x01, 0x6a, 0xa8, 0x5b,
-       0x00, 0xb9, 0xbe, 0x5b,
+       0x01, 0x6a, 0xc8, 0x5b,
+       0x00, 0xb9, 0xde, 0x5b,
        0x01, 0x4f, 0x9e, 0x18,
        0x02, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x6c, 0x5c,
-       0x00, 0x65, 0x2a, 0x41,
+       0x00, 0x65, 0x8c, 0x5c,
+       0x00, 0x65, 0x34, 0x41,
        0x41, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x18, 0x41,
+       0x00, 0x65, 0x22, 0x41,
        0x04, 0xa0, 0x40, 0x01,
-       0x00, 0x65, 0x84, 0x5c,
-       0x00, 0x65, 0x2a, 0x41,
-       0x10, 0x36, 0x68, 0x7a,
-       0xff, 0x38, 0x46, 0x09,
-       0xa4, 0x6a, 0xcc, 0x00,
-       0x39, 0x6a, 0xe6, 0x5b,
+       0x00, 0x65, 0xa4, 0x5c,
+       0x00, 0x65, 0x34, 0x41,
+       0x10, 0x36, 0x90, 0x7a,
+       0x05, 0x38, 0x46, 0x31,
+       0x04, 0x14, 0x58, 0x31,
+       0x03, 0xa9, 0x60, 0x31,
+       0xa3, 0x6a, 0xcc, 0x00,
+       0x38, 0x6a, 0x04, 0x5c,
        0xac, 0x6a, 0xcc, 0x00,
-       0x14, 0x6a, 0xe6, 0x5b,
-       0xa9, 0x6a, 0xe8, 0x5b,
-       0x00, 0x65, 0x68, 0x42,
+       0x14, 0x6a, 0x06, 0x5c,
+       0xa9, 0x6a, 0x08, 0x5c,
+       0x00, 0x65, 0x90, 0x42,
        0xef, 0x36, 0x6c, 0x08,
-       0x00, 0x65, 0x68, 0x42,
+       0x00, 0x65, 0x90, 0x42,
        0x0f, 0x64, 0xc8, 0x08,
        0x07, 0x64, 0xc8, 0x08,
        0x00, 0x37, 0x6e, 0x00,
-       0x00, 0x65, 0x78, 0x5b,
-       0xff, 0x51, 0xce, 0x72,
-       0x20, 0x36, 0xde, 0x7a,
-       0x00, 0x90, 0x5c, 0x5b,
-       0x00, 0x65, 0xe0, 0x42,
+       0xff, 0x6a, 0xa4, 0x00,
+       0x00, 0x65, 0x98, 0x5b,
+       0xff, 0x51, 0xfc, 0x72,
+       0x20, 0x36, 0x06, 0x7b,
+       0x00, 0x90, 0x86, 0x5b,
+       0x00, 0x65, 0x08, 0x43,
        0xff, 0x06, 0xd4, 0x08,
-       0x00, 0x65, 0xd2, 0x5b,
-       0xe0, 0x3d, 0xfa, 0x62,
-       0x20, 0x12, 0xfa, 0x62,
-       0x51, 0x6a, 0x08, 0x5b,
-       0xff, 0x51, 0x20, 0x09,
-       0x20, 0xa0, 0xfa, 0x7a,
-       0x00, 0x90, 0x5c, 0x5b,
-       0x00, 0x65, 0x56, 0x5b,
+       0x00, 0x65, 0xf2, 0x5b,
+       0xe0, 0x3d, 0x22, 0x63,
+       0x20, 0x12, 0x22, 0x63,
+       0x51, 0x6a, 0x30, 0x5b,
+       0x00, 0x65, 0x80, 0x5b,
        0xff, 0x37, 0xc8, 0x08,
-       0x00, 0xa1, 0xf2, 0x62,
-       0x04, 0xa0, 0xf2, 0x7a,
+       0x00, 0xa1, 0x1a, 0x63,
+       0x04, 0xa0, 0x1a, 0x7b,
        0xfb, 0xa0, 0x40, 0x09,
        0x80, 0x36, 0x6c, 0x00,
-       0x80, 0xa0, 0x68, 0x7a,
+       0x80, 0xa0, 0x90, 0x7a,
        0x7f, 0xa0, 0x40, 0x09,
-       0xff, 0x6a, 0x04, 0x5b,
-       0x00, 0x65, 0x68, 0x42,
-       0x04, 0xa0, 0xf8, 0x7a,
-       0x00, 0x65, 0x84, 0x5c,
-       0x00, 0x65, 0xfa, 0x42,
-       0x00, 0x65, 0x6c, 0x5c,
+       0xff, 0x6a, 0x2c, 0x5b,
+       0x00, 0x65, 0x90, 0x42,
+       0x04, 0xa0, 0x20, 0x7b,
+       0x00, 0x65, 0xa4, 0x5c,
+       0x00, 0x65, 0x22, 0x43,
+       0x00, 0x65, 0x8c, 0x5c,
        0x31, 0x6a, 0x22, 0x01,
-       0x0c, 0x6a, 0x04, 0x5b,
-       0x00, 0x65, 0x68, 0x42,
+       0x0c, 0x6a, 0x2c, 0x5b,
+       0x00, 0x65, 0x90, 0x42,
        0x61, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x68, 0x42,
+       0x00, 0x65, 0x90, 0x42,
        0x10, 0x3d, 0x06, 0x00,
        0xff, 0x65, 0x68, 0x0c,
        0xff, 0x06, 0xd4, 0x08,
-       0x01, 0x0c, 0x0a, 0x7b,
-       0x04, 0x0c, 0x0a, 0x6b,
+       0x01, 0x0c, 0x32, 0x7b,
+       0x04, 0x0c, 0x32, 0x6b,
        0xe0, 0x03, 0x7a, 0x08,
-       0xe0, 0x3d, 0x1e, 0x63,
+       0xe0, 0x3d, 0x46, 0x63,
        0xff, 0x65, 0xcc, 0x08,
        0xff, 0x12, 0xda, 0x0c,
        0xff, 0x06, 0xd4, 0x0c,
        0xff, 0x65, 0x0c, 0x08,
-       0x02, 0x0b, 0x1a, 0x7b,
+       0x02, 0x0b, 0x42, 0x7b,
        0xff, 0x6a, 0xd4, 0x0c,
        0xd1, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x18, 0x41,
+       0x00, 0x65, 0x22, 0x41,
        0xff, 0x65, 0x26, 0x09,
-       0x01, 0x0b, 0x32, 0x6b,
-       0x10, 0x0c, 0x24, 0x7b,
-       0x04, 0x0b, 0x2c, 0x6b,
+       0x01, 0x0b, 0x5a, 0x6b,
+       0x10, 0x0c, 0x4c, 0x7b,
+       0x04, 0x0b, 0x54, 0x6b,
        0xff, 0x6a, 0xca, 0x08,
-       0x04, 0x93, 0x30, 0x6b,
-       0x01, 0x94, 0x2e, 0x7b,
-       0x10, 0x94, 0x30, 0x6b,
+       0x04, 0x93, 0x58, 0x6b,
+       0x01, 0x94, 0x56, 0x7b,
+       0x10, 0x94, 0x58, 0x6b,
        0xc7, 0x93, 0x26, 0x09,
        0xff, 0x99, 0xd4, 0x08,
-       0x08, 0x93, 0x34, 0x6b,
+       0x38, 0x93, 0x5c, 0x6b,
        0xff, 0x6a, 0xd4, 0x0c,
-       0x80, 0x36, 0x38, 0x6b,
+       0x80, 0x36, 0x60, 0x6b,
        0x21, 0x6a, 0x22, 0x05,
        0xff, 0x65, 0x20, 0x09,
-       0xff, 0x51, 0x46, 0x63,
+       0xff, 0x51, 0x6e, 0x63,
        0xff, 0x37, 0xc8, 0x08,
-       0xa1, 0x6a, 0x50, 0x43,
+       0xa1, 0x6a, 0x7a, 0x43,
        0xff, 0x51, 0xc8, 0x08,
-       0xb9, 0x6a, 0x50, 0x43,
-       0xff, 0xba, 0x54, 0x73,
+       0xb9, 0x6a, 0x7a, 0x43,
+       0xff, 0x90, 0xa4, 0x08,
+       0xff, 0xba, 0x7e, 0x73,
        0xff, 0xba, 0x20, 0x09,
        0xff, 0x65, 0xca, 0x18,
-       0x00, 0x6c, 0x4a, 0x63,
+       0x00, 0x6c, 0x72, 0x63,
        0xff, 0x90, 0xca, 0x0c,
        0xff, 0x6a, 0xca, 0x04,
-       0x20, 0x36, 0x72, 0x7b,
-       0x00, 0x90, 0x3e, 0x5b,
-       0xff, 0x65, 0x72, 0x73,
-       0xff, 0xba, 0x66, 0x73,
-       0xff, 0xbb, 0xcc, 0x08,
-       0xff, 0xba, 0x20, 0x09,
-       0xff, 0x66, 0x76, 0x09,
-       0xff, 0x65, 0x20, 0x09,
-       0xff, 0xbb, 0x70, 0x73,
+       0x20, 0x36, 0x92, 0x7b,
+       0x00, 0x90, 0x66, 0x5b,
+       0xff, 0x65, 0x92, 0x73,
+       0xff, 0x52, 0x90, 0x73,
        0xff, 0xba, 0xcc, 0x08,
-       0xff, 0xbb, 0x20, 0x09,
+       0xff, 0x52, 0x20, 0x09,
        0xff, 0x66, 0x74, 0x09,
        0xff, 0x65, 0x20, 0x0d,
        0xff, 0xba, 0x7e, 0x0c,
-       0x00, 0x6a, 0x72, 0x5c,
+       0x00, 0x6a, 0x92, 0x5c,
        0x0d, 0x6a, 0x6a, 0x00,
-       0x00, 0x51, 0xfe, 0x43,
-       0xff, 0x3f, 0xcc, 0x73,
+       0x00, 0x51, 0x1e, 0x44,
+       0xff, 0x3f, 0xec, 0x73,
        0xff, 0x6a, 0xa2, 0x00,
-       0x00, 0x3f, 0x3e, 0x5b,
-       0xff, 0x65, 0xcc, 0x73,
+       0x00, 0x3f, 0x66, 0x5b,
+       0xff, 0x65, 0xec, 0x73,
        0x20, 0x36, 0x6c, 0x00,
-       0x20, 0xa0, 0x86, 0x6b,
+       0x20, 0xa0, 0xa6, 0x6b,
        0xff, 0xb9, 0xa2, 0x0c,
        0xff, 0x6a, 0xa2, 0x04,
        0xff, 0x65, 0xa4, 0x08,
        0xe0, 0x6a, 0xcc, 0x00,
-       0x45, 0x6a, 0xf2, 0x5b,
+       0x45, 0x6a, 0x12, 0x5c,
        0x01, 0x6a, 0xd0, 0x01,
        0x09, 0x6a, 0xd6, 0x01,
-       0x80, 0xeb, 0x92, 0x7b,
+       0x80, 0xeb, 0xb2, 0x7b,
        0x01, 0x6a, 0xd6, 0x01,
        0x01, 0xe9, 0xa4, 0x34,
        0x88, 0x6a, 0xcc, 0x00,
-       0x45, 0x6a, 0xf2, 0x5b,
+       0x45, 0x6a, 0x12, 0x5c,
        0x01, 0x6a, 0x18, 0x01,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
        0x0d, 0x6a, 0x26, 0x01,
-       0x00, 0x65, 0x64, 0x5c,
+       0x00, 0x65, 0x84, 0x5c,
        0xff, 0x99, 0xa4, 0x0c,
        0xff, 0x65, 0xa4, 0x08,
        0xe0, 0x6a, 0xcc, 0x00,
-       0x45, 0x6a, 0xf2, 0x5b,
+       0x45, 0x6a, 0x12, 0x5c,
        0x01, 0x6a, 0xd0, 0x01,
        0x01, 0x6a, 0xdc, 0x05,
        0x88, 0x6a, 0xcc, 0x00,
-       0x45, 0x6a, 0xf2, 0x5b,
+       0x45, 0x6a, 0x12, 0x5c,
        0x01, 0x6a, 0x18, 0x01,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
        0x01, 0x6a, 0x26, 0x05,
        0x01, 0x65, 0xd8, 0x31,
        0x09, 0xee, 0xdc, 0x01,
-       0x80, 0xee, 0xc2, 0x7b,
+       0x80, 0xee, 0xe2, 0x7b,
        0xff, 0x6a, 0xdc, 0x0d,
        0xff, 0x65, 0x32, 0x09,
        0x0a, 0x93, 0x26, 0x01,
-       0x00, 0x65, 0x64, 0x44,
+       0x00, 0x65, 0x84, 0x44,
        0xff, 0x37, 0xc8, 0x08,
-       0x00, 0x6a, 0x88, 0x5b,
+       0x00, 0x6a, 0xa8, 0x5b,
        0xff, 0x52, 0xa2, 0x0c,
-       0x01, 0x0c, 0xd2, 0x7b,
-       0x04, 0x0c, 0xd2, 0x6b,
-       0xe0, 0x03, 0x7a, 0x08,
-       0xff, 0x3d, 0x06, 0x0c,
+       0x01, 0x0c, 0xf2, 0x7b,
+       0x04, 0x0c, 0xf2, 0x6b,
+       0xe0, 0x03, 0x06, 0x08,
+       0xe0, 0x03, 0x7a, 0x0c,
        0xff, 0x8c, 0x10, 0x08,
        0xff, 0x8d, 0x12, 0x08,
        0xff, 0x8e, 0x14, 0x0c,
@@ -515,29 +531,29 @@ static unsigned char seqprog[] = {
        0x00, 0x6c, 0xda, 0x24,
        0xff, 0x65, 0xc8, 0x08,
        0xe0, 0x6a, 0xcc, 0x00,
-       0x41, 0x6a, 0xee, 0x5b,
+       0x41, 0x6a, 0x0e, 0x5c,
        0xff, 0x90, 0xe2, 0x09,
        0x20, 0x6a, 0xd0, 0x01,
-       0x04, 0x35, 0x10, 0x7c,
+       0x04, 0x35, 0x30, 0x7c,
        0x1d, 0x6a, 0xdc, 0x01,
-       0xdc, 0xee, 0x0c, 0x64,
-       0x00, 0x65, 0x1c, 0x44,
+       0xdc, 0xee, 0x2c, 0x64,
+       0x00, 0x65, 0x3c, 0x44,
        0x01, 0x6a, 0xdc, 0x01,
        0x20, 0xa0, 0xd8, 0x31,
        0x09, 0xee, 0xdc, 0x01,
-       0x80, 0xee, 0x16, 0x7c,
+       0x80, 0xee, 0x36, 0x7c,
        0x19, 0x6a, 0xdc, 0x01,
-       0xd8, 0xee, 0x1a, 0x64,
+       0xd8, 0xee, 0x3a, 0x64,
        0xff, 0x6a, 0xdc, 0x09,
-       0x18, 0xee, 0x1e, 0x6c,
+       0x18, 0xee, 0x3e, 0x6c,
        0xff, 0x6a, 0xd4, 0x0c,
        0x88, 0x6a, 0xcc, 0x00,
-       0x41, 0x6a, 0xee, 0x5b,
+       0x41, 0x6a, 0x0e, 0x5c,
        0x20, 0x6a, 0x18, 0x01,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
        0xff, 0x35, 0x26, 0x09,
-       0x04, 0x35, 0x48, 0x6c,
+       0x04, 0x35, 0x68, 0x6c,
        0xa0, 0x6a, 0xca, 0x00,
        0x20, 0x65, 0xc8, 0x18,
        0xff, 0x6c, 0x32, 0x09,
@@ -548,14 +564,14 @@ static unsigned char seqprog[] = {
        0xff, 0x6c, 0x32, 0x09,
        0xff, 0x6c, 0x32, 0x09,
        0xff, 0x6c, 0x32, 0x09,
-       0x00, 0x65, 0x34, 0x64,
+       0x00, 0x65, 0x54, 0x64,
        0x0a, 0x93, 0x26, 0x01,
-       0x00, 0x65, 0x64, 0x5c,
-       0x04, 0x35, 0x38, 0x7b,
-       0xa0, 0x6a, 0x54, 0x5c,
-       0x00, 0x65, 0x56, 0x5c,
-       0x00, 0x65, 0x56, 0x5c,
-       0x00, 0x65, 0x56, 0x44,
+       0x00, 0x65, 0x84, 0x5c,
+       0x04, 0x35, 0x60, 0x7b,
+       0xa0, 0x6a, 0x74, 0x5c,
+       0x00, 0x65, 0x76, 0x5c,
+       0x00, 0x65, 0x76, 0x5c,
+       0x00, 0x65, 0x76, 0x44,
        0xff, 0x65, 0xcc, 0x08,
        0xff, 0x99, 0xda, 0x08,
        0xff, 0x99, 0xda, 0x08,
@@ -564,37 +580,40 @@ static unsigned char seqprog[] = {
        0xff, 0x99, 0xda, 0x08,
        0xff, 0x99, 0xda, 0x08,
        0xff, 0x99, 0xda, 0x0c,
-       0x08, 0x94, 0x64, 0x7c,
+       0x08, 0x94, 0x84, 0x7c,
        0xf7, 0x93, 0x26, 0x09,
-       0x08, 0x93, 0x68, 0x6c,
+       0x08, 0x93, 0x88, 0x6c,
        0xff, 0x6a, 0xd4, 0x0c,
        0xff, 0x40, 0x74, 0x09,
        0xff, 0x90, 0x80, 0x08,
        0xff, 0x6a, 0x72, 0x05,
-       0xff, 0x40, 0x80, 0x64,
-       0xff, 0x3f, 0x78, 0x64,
+       0xff, 0x40, 0xa0, 0x64,
+       0xff, 0x3f, 0x98, 0x64,
        0xff, 0x6a, 0xca, 0x04,
        0xff, 0x3f, 0x20, 0x09,
        0x01, 0x6a, 0x6a, 0x00,
-       0x00, 0xb9, 0xfe, 0x5b,
-       0x00, 0x90, 0x5c, 0x43,
+       0x00, 0xb9, 0x1e, 0x5c,
+       0xff, 0xba, 0x7e, 0x0c,
        0xff, 0x40, 0x20, 0x09,
        0xff, 0xba, 0x80, 0x0c,
-       0xff, 0x6a, 0x76, 0x01,
        0xff, 0x3f, 0x74, 0x09,
-       0xff, 0x90, 0x7e, 0x08,
-       0xff, 0xba, 0x38, 0x73,
-       0xff, 0xba, 0x20, 0x09,
-       0xff, 0x3f, 0x76, 0x09,
-       0xff, 0x3f, 0x20, 0x0d,
+       0xff, 0x90, 0x7e, 0x0c,
 };
 
+static int aic7xxx_patch13_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch13_func(struct aic7xxx_host *p)
+{
+       return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+}
+
 static int aic7xxx_patch12_func(struct aic7xxx_host *p);
 
 static int
 aic7xxx_patch12_func(struct aic7xxx_host *p)
 {
-       return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+       return ((p->features & AHC_CMD_CHAN) == 0);
 }
 
 static int aic7xxx_patch11_func(struct aic7xxx_host *p);
@@ -699,71 +718,81 @@ struct sequencer_patch {
                        skip_instr :10,
                        skip_patch :12;
 } sequencer_patches[] = {
-       { aic7xxx_patch1_func, 1, 1, 2 },
-       { aic7xxx_patch0_func, 2, 1, 1 },
-       { aic7xxx_patch2_func, 3, 2, 1 },
-       { aic7xxx_patch3_func, 7, 1, 1 },
+       { aic7xxx_patch1_func, 2, 1, 2 },
+       { aic7xxx_patch0_func, 3, 1, 1 },
+       { aic7xxx_patch2_func, 4, 2, 1 },
        { aic7xxx_patch3_func, 8, 1, 1 },
-       { aic7xxx_patch4_func, 11, 4, 1 },
-       { aic7xxx_patch5_func, 16, 3, 2 },
-       { aic7xxx_patch0_func, 19, 4, 1 },
-       { aic7xxx_patch6_func, 23, 1, 1 },
-       { aic7xxx_patch7_func, 26, 1, 1 },
-       { aic7xxx_patch4_func, 34, 4, 1 },
-       { aic7xxx_patch8_func, 38, 3, 2 },
-       { aic7xxx_patch0_func, 41, 3, 1 },
-       { aic7xxx_patch9_func, 47, 7, 1 },
-       { aic7xxx_patch4_func, 55, 3, 1 },
-       { aic7xxx_patch8_func, 58, 2, 1 },
-       { aic7xxx_patch1_func, 63, 60, 1 },
-       { aic7xxx_patch8_func, 164, 1, 2 },
-       { aic7xxx_patch0_func, 165, 1, 1 },
-       { aic7xxx_patch2_func, 169, 1, 1 },
-       { aic7xxx_patch2_func, 172, 1, 2 },
-       { aic7xxx_patch0_func, 173, 2, 1 },
-       { aic7xxx_patch10_func, 175, 1, 1 },
-       { aic7xxx_patch8_func, 182, 1, 2 },
-       { aic7xxx_patch0_func, 183, 3, 1 },
-       { aic7xxx_patch8_func, 187, 1, 2 },
-       { aic7xxx_patch0_func, 188, 1, 1 },
-       { aic7xxx_patch8_func, 189, 7, 2 },
-       { aic7xxx_patch0_func, 196, 1, 1 },
-       { aic7xxx_patch2_func, 201, 13, 2 },
-       { aic7xxx_patch0_func, 214, 8, 1 },
-       { aic7xxx_patch10_func, 222, 1, 1 },
-       { aic7xxx_patch8_func, 227, 1, 1 },
-       { aic7xxx_patch8_func, 228, 1, 1 },
-       { aic7xxx_patch8_func, 233, 1, 1 },
-       { aic7xxx_patch8_func, 235, 2, 1 },
-       { aic7xxx_patch8_func, 240, 8, 1 },
-       { aic7xxx_patch8_func, 249, 1, 1 },
-       { aic7xxx_patch2_func, 250, 2, 2 },
-       { aic7xxx_patch0_func, 252, 4, 1 },
-       { aic7xxx_patch10_func, 256, 2, 2 },
-       { aic7xxx_patch0_func, 258, 1, 1 },
-       { aic7xxx_patch11_func, 265, 1, 2 },
-       { aic7xxx_patch0_func, 266, 1, 1 },
-       { aic7xxx_patch5_func, 328, 1, 2 },
-       { aic7xxx_patch0_func, 329, 1, 1 },
-       { aic7xxx_patch3_func, 332, 1, 1 },
-       { aic7xxx_patch11_func, 351, 1, 2 },
-       { aic7xxx_patch0_func, 352, 1, 1 },
-       { aic7xxx_patch6_func, 356, 1, 1 },
-       { aic7xxx_patch7_func, 364, 3, 2 },
-       { aic7xxx_patch0_func, 367, 1, 1 },
-       { aic7xxx_patch1_func, 396, 3, 1 },
-       { aic7xxx_patch10_func, 410, 1, 1 },
-       { aic7xxx_patch2_func, 453, 7, 2 },
-       { aic7xxx_patch0_func, 460, 8, 1 },
-       { aic7xxx_patch2_func, 469, 4, 2 },
-       { aic7xxx_patch0_func, 473, 6, 1 },
-       { aic7xxx_patch2_func, 479, 4, 2 },
-       { aic7xxx_patch0_func, 483, 3, 1 },
-       { aic7xxx_patch2_func, 512, 17, 4 },
-       { aic7xxx_patch12_func, 520, 4, 2 },
-       { aic7xxx_patch0_func, 524, 2, 1 },
-       { aic7xxx_patch0_func, 529, 33, 1 },
-       { aic7xxx_patch6_func, 566, 2, 1 },
-       { aic7xxx_patch6_func, 569, 9, 1 },
+       { aic7xxx_patch3_func, 9, 1, 1 },
+       { aic7xxx_patch4_func, 12, 4, 1 },
+       { aic7xxx_patch5_func, 17, 3, 2 },
+       { aic7xxx_patch0_func, 20, 4, 1 },
+       { aic7xxx_patch6_func, 24, 1, 1 },
+       { aic7xxx_patch7_func, 27, 1, 1 },
+       { aic7xxx_patch2_func, 30, 1, 2 },
+       { aic7xxx_patch0_func, 31, 3, 1 },
+       { aic7xxx_patch4_func, 40, 4, 1 },
+       { aic7xxx_patch8_func, 44, 3, 2 },
+       { aic7xxx_patch0_func, 47, 3, 1 },
+       { aic7xxx_patch9_func, 52, 7, 1 },
+       { aic7xxx_patch4_func, 60, 3, 1 },
+       { aic7xxx_patch8_func, 63, 2, 1 },
+       { aic7xxx_patch1_func, 68, 60, 1 },
+       { aic7xxx_patch8_func, 162, 1, 2 },
+       { aic7xxx_patch0_func, 163, 2, 1 },
+       { aic7xxx_patch2_func, 167, 2, 3 },
+       { aic7xxx_patch8_func, 167, 1, 1 },
+       { aic7xxx_patch0_func, 169, 2, 1 },
+       { aic7xxx_patch8_func, 172, 1, 2 },
+       { aic7xxx_patch0_func, 173, 1, 1 },
+       { aic7xxx_patch2_func, 177, 1, 1 },
+       { aic7xxx_patch2_func, 180, 3, 2 },
+       { aic7xxx_patch0_func, 183, 5, 1 },
+       { aic7xxx_patch2_func, 191, 2, 3 },
+       { aic7xxx_patch8_func, 191, 1, 1 },
+       { aic7xxx_patch0_func, 193, 3, 1 },
+       { aic7xxx_patch10_func, 196, 2, 1 },
+       { aic7xxx_patch8_func, 198, 7, 2 },
+       { aic7xxx_patch0_func, 205, 1, 1 },
+       { aic7xxx_patch2_func, 210, 14, 3 },
+       { aic7xxx_patch10_func, 223, 1, 1 },
+       { aic7xxx_patch0_func, 224, 9, 1 },
+       { aic7xxx_patch8_func, 238, 2, 1 },
+       { aic7xxx_patch8_func, 240, 1, 1 },
+       { aic7xxx_patch10_func, 241, 6, 3 },
+       { aic7xxx_patch2_func, 241, 2, 2 },
+       { aic7xxx_patch0_func, 243, 4, 1 },
+       { aic7xxx_patch8_func, 248, 1, 1 },
+       { aic7xxx_patch8_func, 252, 11, 1 },
+       { aic7xxx_patch2_func, 264, 3, 3 },
+       { aic7xxx_patch10_func, 266, 1, 1 },
+       { aic7xxx_patch0_func, 267, 5, 1 },
+       { aic7xxx_patch10_func, 272, 1, 2 },
+       { aic7xxx_patch0_func, 273, 7, 1 },
+       { aic7xxx_patch11_func, 287, 1, 2 },
+       { aic7xxx_patch0_func, 288, 1, 1 },
+       { aic7xxx_patch5_func, 348, 1, 2 },
+       { aic7xxx_patch0_func, 349, 1, 1 },
+       { aic7xxx_patch3_func, 352, 1, 1 },
+       { aic7xxx_patch2_func, 362, 3, 2 },
+       { aic7xxx_patch0_func, 365, 5, 1 },
+       { aic7xxx_patch11_func, 373, 1, 2 },
+       { aic7xxx_patch0_func, 374, 1, 1 },
+       { aic7xxx_patch6_func, 379, 1, 1 },
+       { aic7xxx_patch1_func, 416, 3, 1 },
+       { aic7xxx_patch10_func, 421, 11, 1 },
+       { aic7xxx_patch2_func, 469, 7, 2 },
+       { aic7xxx_patch0_func, 476, 8, 1 },
+       { aic7xxx_patch2_func, 485, 4, 2 },
+       { aic7xxx_patch0_func, 489, 6, 1 },
+       { aic7xxx_patch2_func, 495, 4, 2 },
+       { aic7xxx_patch0_func, 499, 3, 1 },
+       { aic7xxx_patch12_func, 509, 10, 1 },
+       { aic7xxx_patch2_func, 528, 17, 4 },
+       { aic7xxx_patch13_func, 536, 4, 2 },
+       { aic7xxx_patch0_func, 540, 2, 1 },
+       { aic7xxx_patch0_func, 545, 33, 1 },
+       { aic7xxx_patch12_func, 578, 4, 1 },
+       { aic7xxx_patch6_func, 582, 2, 1 },
+       { aic7xxx_patch6_func, 585, 9, 1 },
 
 };
index 2966ca4cd30991fc683881d9ed751f33ace89068..b09a8361f67fa4064bf6e9dd70a7028dc9ac2923 100644 (file)
@@ -296,6 +296,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 #define SCSI_1          1
 #define SCSI_1_CCS      2
 #define SCSI_2          3
+#define SCSI_3          4
 
 /*
  *  Every SCSI command starts with a one byte OP-code.
index 459a245d577bd58f7eeaa3aa47ef4ed5ef4a6834..2b0e98e3e8f90444b8702e6381fdcdbdf3980aff 100644 (file)
@@ -298,7 +298,7 @@ void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
                     scd->type < MAX_SCSI_DEVICE_CODE ? 
                     scsi_device_types[(int)scd->type] : "Unknown          " );
     y += sprintf(buffer + len + y, "               ANSI"
-                    " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
+                    " SCSI revision: %02x", (scd->scsi_level - 1)?scd->scsi_level - 1:1);
     if (scd->scsi_level == 2)
        y += sprintf(buffer + len + y, " CCS\n");
     else
index e73335a24566e7d26b67a321f6d5a043a9e8cee0..1d45432b5de7e5f8f0851075bb73af3d8b19eff1 100644 (file)
 #include "constants.h"
 
 #include "sd.h"
+#include <scsi/scsicam.h>
 /*
  * This source file contains the symbol table used by scsi loadable
  * modules.
  */
-extern int scsicam_bios_param (Disk * disk,
-                               int dev,        int *ip ); 
-
 
 extern void print_command (unsigned char *command);
 extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
@@ -47,6 +45,7 @@ EXPORT_SYMBOL(scsi_malloc);
 EXPORT_SYMBOL(scsi_register);
 EXPORT_SYMBOL(scsi_unregister);
 EXPORT_SYMBOL(scsicam_bios_param);
+EXPORT_SYMBOL(scsi_partsize);
 EXPORT_SYMBOL(scsi_allocate_device);
 EXPORT_SYMBOL(scsi_do_cmd);
 EXPORT_SYMBOL(scsi_command_size);
index 9aa0d8fbc1caa2bd08cf14e14c6b8c40887b1d5f..a3016e00e88b065d80d9a8d9382ffe460a04bcf4 100644 (file)
@@ -21,9 +21,8 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
+#include <scsi/scsicam.h>
 
-static int partsize(struct buffer_head *bh, unsigned long capacity,
-    unsigned int  *cyls, unsigned int *hds, unsigned int *secs);
 static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
     unsigned int *secs);
 
@@ -51,7 +50,7 @@ int scsicam_bios_param (Disk *disk, /* SCSI disk */
        return -1;
 
     /* try to infer mapping from partition table */
-    ret_code = partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, 
+    ret_code = scsi_partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, 
        (unsigned int *) ip + 0, (unsigned int *) ip + 1);
     brelse (bh);
 
@@ -80,7 +79,7 @@ int scsicam_bios_param (Disk *disk, /* SCSI disk */
 }
 
 /*
- * Function : static int partsize(struct buffer_head *bh, unsigned long 
+ * Function : static int scsi_partsize(struct buffer_head *bh, unsigned long 
  *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
  *
  * Purpose : to determine the BIOS mapping used to create the partition
@@ -90,7 +89,7 @@ int scsicam_bios_param (Disk *disk, /* SCSI disk */
  *
  */
 
-static int partsize(struct buffer_head *bh, unsigned long capacity,
+int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
     unsigned int  *cyls, unsigned int *hds, unsigned int *secs) {
     struct partition *p, *largest = NULL;
     int i, largest_cyl;
index e32d6f6cf613e791abbd4d37867ee5c81e0fb96f..aa8b8b0f1a1596e933cd4a4b001d02e8cb58b0f8 100644 (file)
@@ -1729,7 +1729,7 @@ static int fop_revalidate_scsidisk(kdev_t dev){
 static void sd_detach(Scsi_Device * SDp)
 {
     Scsi_Disk * dpnt;
-    int i;
+    int i, j;
     int max_p;
     int start;
 
@@ -1741,8 +1741,8 @@ static void sd_detach(Scsi_Device * SDp)
            max_p = sd_gendisk.max_p;
            start = i << sd_gendisk.minor_shift;
 
-           for (i=max_p - 1; i >=0 ; i--) {
-               int index = start+i;
+           for (j=max_p - 1; j >=0 ; j--) {
+               int index = start+j;
                kdev_t devi = MKDEV_SD_PARTITION(index);
                 struct super_block *sb = get_super(devi);
                sync_dev(devi);
@@ -1759,7 +1759,7 @@ static void sd_detach(Scsi_Device * SDp)
            SDp->attached--;
            sd_template.dev_noticed--;
            sd_template.nr_dev--;
-           SD_GENDISK(start).nr_real--;
+           SD_GENDISK(i).nr_real--;
            return;
        }
     return;
index fd63ef0f6045b65906654d14dfc05bd6e368ae02..6196f51ad167bf9d69dec898cf72d426e605109e 100644 (file)
  *
  *  Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
  */
- static char * sg_version_str = "Version: 2.1.32 (990501)";
+ static char * sg_version_str = "Version: 2.1.34 (990603)";
+ static int sg_version_num = 20134; /* 2 digits for each component */
 /*
- *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
- *      - scatter list logic replaces previous large atomic SG_BIG_BUFF
- *        sized allocation. See notes in <scsi/sg.h> include file. 
- * 
+ *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
  *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
  *        (otherwise the macros compile to empty statements), then do
  *        Should use hlcomplete but it is too "noisy" (sd uses it).
  *
  *      - This driver obtains memory (heap) for the low-level driver to
- *        transfer/dma to and from. It is obtained from up to 4 sources:
- *              - 1 SG_SCATTER_SZ sized buffer on open() (per fd)
- *                [could be less if SG_SCATTER_SZ bytes not available]
- *              - obtain heap as required on write()s (get_free_pages)
+ *        transfer/dma to and from. It is obtained from up to 3 sources:
+ *              - obtain heap via get_free_pages()
  *              - obtain heap from the shared scsi dma pool
  *              - obtain heap from kernel directly (kmalloc) [last choice]
- *        the 'alt_address' field in the scatter_list structure and the
+ *        Each open() attempts to obtain a "reserve" buffer of
+ *        SG_DEF_RESERVED_SIZE bytes (or 0 bytes if opened O_RDONLY). The
+ *        amount actually obtained [which could be 0 bytes] can be found from
+ *        the SG_GET_RESERVED_SIZE ioctl(). This reserved buffer size can
+ *        be changed by calling the SG_SET_RESERVED_SIZE ioctl(). Since this
+ *        is an ambit claim, it should be followed by a SG_GET_RESERVED_SIZE
+ *        ioctl() to find out how much was actually obtained.
+ *        A subsequent write() to this file descriptor will use the
+ *        reserved buffer unless:
+ *              - it is already in use (eg during command queuing)
+ *              - or the write() needs a buffer size larger than the
+ *                reserved size
+ *        In these cases the write() will attempt to get the required memory
+ *        for the duration of this request but, if memory is low, it may
+ *        fail with ENOMEM.
+ *
+ *      - The 'alt_address' field in the scatter_list structure and the
  *        related 'mem_src' indicate the source of the heap allocation.
  *
  */
 #include <scsi/sg.h>
 
 
-int sg_big_buff = SG_SCATTER_SZ;  /* sg_big_buff is ro through sysctl */
+int sg_big_buff = SG_DEF_RESERVED_SIZE; /* sg_big_buff is ro through sysctl */
 /* N.B. This global is here to keep existing software happy. It now holds
-   the size of the "first buffer" of the most recent sucessful sg_open(). 
+   the size of the reserve buffer of the most recent sucessful sg_open(). 
    Only available when 'sg' compiled into kernel (rather than a module). 
-   This should probably be deprecated (use SG_GET_RESERVED_SIZE instead). */
+   This is deprecated (use SG_GET_RESERVED_SIZE ioctl() instead). */
 
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -89,7 +101,6 @@ static int sg_num_pool = 0;
 static int sg_num_page = 0;
 #endif
 
-#define SG_HEAP_FB 0    /* heap obtained at open() (one buffer per fd) */
 #define SG_HEAP_PAGE 1  /* heap from kernel via get_free_pages() */
 #define SG_HEAP_KMAL 2  /* heap from kernel via kmalloc() */
 #define SG_HEAP_POOL 3  /* heap from scsi dma pool (mid-level) */
@@ -112,9 +123,9 @@ typedef struct sg_scatter_hold  /* holding area for scsi scatter gather info */
 {
     unsigned short use_sg;      /* Number of pieces of scatter-gather */
     unsigned short sglist_len;  /* size of malloc'd scatter-gather list */
-    unsigned bufflen;           /* Size of data buffer */
+    unsigned bufflen;           /* Size of (aggregate) data buffer */
     unsigned b_malloc_len;      /* actual len malloc'ed in buffer */
-    void * buffer;              /* Data buffer or scatter list (12 bytes) */
+    void * buffer;              /* Data buffer or scatter list,12 bytes each*/
     char mem_src;               /* heap whereabouts of 'buffer' */
 } Sg_scatter_hold;    /* 20 bytes long on i386 */
 
@@ -126,10 +137,10 @@ typedef struct sg_request  /* SG_MAX_QUEUE requests outstanding per file */
     Scsi_Cmnd * my_cmdp;        /* NULL -> ready to read, else id */
     struct sg_request * nextrp; /* NULL -> tail request (slist) */
     struct sg_fd * parentfp;    /* NULL -> not in use */
-    Sg_scatter_hold data;       /* hold buffers, perhaps scatter list */
-    struct sg_header header;    /* scsi command+info <include/sg.h> */
-    char fb_used;               /* 1 -> using fst_buf, normally 0 (used) */
-} Sg_request; /* around 72 bytes long on i386 */
+    Sg_scatter_hold data;       /* hold buffer, perhaps scatter list */
+    struct sg_header header;    /* scsi command+info, see <scsi/sg.h> */
+    char res_used;              /* 1 -> using reserve buffer, 0 -> not ... */
+} Sg_request; /* 72 bytes long on i386 */
 
 typedef struct sg_fd /* holds the state of a file descriptor */
 {
@@ -137,41 +148,52 @@ typedef struct sg_fd /* holds the state of a file descriptor */
     struct sg_device * parentdp;     /* owning device */
     struct wait_queue * read_wait;   /* queue read until command done */
     int timeout;                     /* defaults to SG_DEFAULT_TIMEOUT */
-    char * fst_buf;     /* try to grab SG_SCATTER_SZ sized buffer on open */
-    int fb_size;        /* actual size of allocated fst_buf */
-    Sg_request * headrp; /* head of request slist, NULL->empty */
+    Sg_scatter_hold reserve;  /* buffer held for this file descriptor */
+    unsigned save_scat_len;   /* original length of trunc. scat. element */
+    Sg_request * headrp;      /* head of request slist, NULL->empty */
     struct fasync_struct * async_qp; /* used by asynchronous notification */
     Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
-    char low_dma;       /* as in parent but possible overridden to 1 */
+    char low_dma;       /* as in parent but possibly overridden to 1 */
     char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
     char closed;        /* 1 -> fd closed but request(s) outstanding */
-    char my_mem_src;    /* heap whereabouts of this sg_fb object */
+    char my_mem_src;    /* heap whereabouts of this Sg_fd object */
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
     char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
-} Sg_fd; /* around 1192 bytes long on i386 */
+    char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
+} Sg_fd; /* 1208 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
 {
     Scsi_Device * device;
-    struct wait_queue * generic_wait;/* queue open if O_EXCL on prev. open */
+    struct wait_queue * o_excl_wait; /* queue open() when O_EXCL in use */
     int sg_tablesize;   /* adapter's max scatter-gather table size */
     Sg_fd * headfp;     /* first open fd belonging to this device */
     kdev_t i_rdev;      /* holds device major+minor number */
     char exclude;       /* opened for exclusive access */
     char sgdebug;       /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
-    unsigned char merge_fd; /* 0->sequencing per fd (def) else fd count */
-} Sg_device; /* around 24 bytes long on i386 */
+    unsigned char merge_fd; /* 0->sequencing per fd, else fd count */
+} Sg_device; /* 24 bytes long on i386 */
 
 
 static int sg_fasync(int fd, struct file * filp, int mode);
 static void sg_command_done(Scsi_Cmnd * SCpnt);
-static int sg_sc_build(Sg_request * srp, int max_buff_size,
-                       const char * inp, int num_write_xfer);
-static int sg_sc_undo_rem(Sg_request * srp, char * outp,
-                          int num_read_xfer);
-static char * sg_malloc(Sg_request * srp, int size, int * retSzp, 
+static int sg_start_req(Sg_request * srp, int max_buff_size,
+                        const char * inp, int num_write_xfer);
+static void sg_finish_rem_req(Sg_request * srp, char * outp,
+                              int num_read_xfer);
+static int sg_build_scat(Sg_scatter_hold * schp, int buff_size, 
+                         const Sg_fd * sfp);
+static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp, 
+                          int num_write_xfer);
+static void sg_remove_scat(Sg_scatter_hold * schp);
+static void sg_read_xfer(Sg_scatter_hold * schp, char * outp,
+                         int num_read_xfer);
+static void sg_build_reserve(Sg_fd * sfp, int req_size);
+static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
+static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
+static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, 
                         int * mem_srcp);
-static void sg_free(Sg_request * srp, char * buff, int size, int mem_src);
+static void sg_free(char * buff, int size, int mem_src);
 static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, 
                             int * retSzp);
 static void sg_low_free(char * buff, int size, int mem_src);
@@ -180,7 +202,7 @@ static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
 static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id);
 static Sg_request * sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp);
-static int sg_fb_in_use(const Sg_fd * sfp);
+static int sg_res_in_use(const Sg_fd * sfp);
 static void sg_clr_scpnt(Scsi_Cmnd * SCpnt);
 static void sg_shorten_timeout(Scsi_Cmnd * scpnt);
 static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of);
@@ -197,6 +219,7 @@ static int sg_open(struct inode * inode, struct file * filp)
     int flags = filp->f_flags;
     Sg_device * sdp;
     Sg_fd * sfp;
+    int res;
 
     if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max))
         return -ENXIO;
@@ -207,38 +230,35 @@ static int sg_open(struct inode * inode, struct file * filp)
         printk("sg_open: inode maj=%d, min=%d   sdp maj=%d, min=%d\n",
                MAJOR(inode->i_rdev), MINOR(inode->i_rdev),
                MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev));
+    /* If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.  */
     if(! scsi_block_when_processing_errors(sdp->device))
         return -ENXIO;
-/*  if (O_RDWR != (flags & O_ACCMODE)) */
-/*      return -EACCES;   May just want to get to a ioctl, so remove */
 
     SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
-   /* If we want exclusive access, then wait until the device is not
-    * busy, and then set the flag to prevent anyone else from using it. */
+
     if (flags & O_EXCL) {
         if (O_RDONLY == (flags & O_ACCMODE))
             return -EACCES;   /* Can't lock it with read only access */
-        while (sdp->headfp) {
-            if (flags & O_NONBLOCK)
-                return -EBUSY;
-            interruptible_sleep_on(&sdp->generic_wait);
-            if (signal_pending(current))
-                return -ERESTARTSYS;
-        }
-        sdp->exclude = 1;
+        if (sdp->headfp && (filp->f_flags & O_NONBLOCK))
+            return -EBUSY;
+        res = 0;  /* following is a macro that beats race condition */
+        __wait_event_interruptible(sdp->o_excl_wait, 
+               ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), 
+                                   res);
+        if (res)
+            return res; /* -ERESTARTSYS because signal hit process */
     }
-    else { /* Wait until nobody has an exclusive open on this device. */
-        while (sdp->exclude) {
-            if (flags & O_NONBLOCK)
-                return -EBUSY;
-            interruptible_sleep_on(&sdp->generic_wait);
-            if (signal_pending(current))
-                return -ERESTARTSYS;
-        }
+    else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
+        if (filp->f_flags & O_NONBLOCK)
+            return -EBUSY;
+        res = 0;  /* following is a macro that beats race condition */
+        __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res);
+        if (res)
+            return res; /* -ERESTARTSYS because signal hit process */
     }
-    /* OK, we should have grabbed the device.  Mark the thing so
-     * that other processes know that we have it, and initialize the
-     * state variables to known values. */
     if (! sdp->headfp) { /* no existing opens on this device */
         sdp->sgdebug = 0;
         sdp->sg_tablesize = sdp->device->host->sg_tablesize;
@@ -284,16 +304,14 @@ static int sg_release(struct inode * inode, struct file * filp)
     if(sg_template.module)
         __MOD_DEC_USE_COUNT(sg_template.module);
     sdp->exclude = 0;
-    wake_up_interruptible(&sdp->generic_wait);
+    wake_up_interruptible(&sdp->o_excl_wait);
     return 0;
 }
 
-/* Read back the results of a SCSI command which was sent in a prior
-   write(). */
 static ssize_t sg_read(struct file * filp, char * buf,
                        size_t count, loff_t *ppos)
 {
-    int k;
+    int k, res;
     Sg_device * sdp;
     Sg_fd * sfp;
     Sg_request * srp;
@@ -305,13 +323,8 @@ static ssize_t sg_read(struct file * filp, char * buf,
     SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", 
                                MINOR(sdp->i_rdev), (int)count));
     
-    /* If we are in the middle of error recovery, don't let anyone
-     * else try and use this device.  Also, if error recovery fails, it
-     * may try and take the device offline, in which case all further
-     * access to the device is prohibited.  */
     if(! scsi_block_when_processing_errors(sdp->device))
         return -ENXIO;
-
     if (ppos != &filp->f_pos)
         ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
     if ((k = verify_area(VERIFY_WRITE, buf, count)))
@@ -319,13 +332,15 @@ static ssize_t sg_read(struct file * filp, char * buf,
     if (sfp->force_packid && (count >= size_sg_header))
         req_pack_id = shp->pack_id;
     srp = sg_get_request(sfp, req_pack_id);
-    while(! srp) {
+    if (! srp) { /* now wait on packet to arrive */
         if (filp->f_flags & O_NONBLOCK)
             return -EAGAIN;
-        interruptible_sleep_on(&sfp->read_wait);
-        if (signal_pending(current))
-            return -ERESTARTSYS;
-        srp = sg_get_request(sfp, req_pack_id);
+        res = 0;  /* following is a macro that beats race condition */
+        __wait_event_interruptible(sfp->read_wait, 
+                                   (srp = sg_get_request(sfp, req_pack_id)),
+                                   res);
+        if (res)
+            return res; /* -ERESTARTSYS because signal hit process */
     }
     if (2 != sfp->underrun_flag)
         srp->header.pack_len = srp->header.reply_len;   /* Why ????? */
@@ -337,13 +352,13 @@ static ssize_t sg_read(struct file * filp, char * buf,
         if (count > srp->header.reply_len)
             count = srp->header.reply_len;
         if (count > size_sg_header) /* release does copy_to_user */
-            sg_sc_undo_rem(srp, buf, count - size_sg_header);
+            sg_finish_rem_req(srp, buf, count - size_sg_header);
         else
-            sg_sc_undo_rem(srp, NULL, 0);
+            sg_finish_rem_req(srp, NULL, 0);
     }
     else {
         count = (srp->header.result == 0) ? 0 : -EIO;
-        sg_sc_undo_rem(srp, NULL, 0);
+        sg_finish_rem_req(srp, NULL, 0);
     }
     return count;
 }
@@ -366,22 +381,15 @@ static ssize_t sg_write(struct file * filp, const char * buf,
     SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", 
                                MINOR(sdp->i_rdev), (int)count));
 
-/* If we are in the middle of error recovery, don't let anyone
- * else try and use this device.  Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.  */
     if(! scsi_block_when_processing_errors(sdp->device) )
         return -ENXIO;
-
     if (ppos != &filp->f_pos)
         ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
 
     if ((k = verify_area(VERIFY_READ, buf, count)))
         return k;  /* protects following copy_from_user()s + get_user()s */
-/* The minimum scsi command length is 6 bytes.  If we get anything
- * less than this, it is clearly bogus.  */
     if (count < (size_sg_header + 6))
-        return -EIO;
+        return -EIO;   /* The minimum scsi command length is 6 bytes. */ 
 
     srp = sg_add_request(sfp);
     if (! srp) {
@@ -392,55 +400,54 @@ static ssize_t sg_write(struct file * filp, const char * buf,
     buf += size_sg_header;
     srp->header.pack_len = count;
     __get_user(opcode, buf);
-    cmd_size = COMMAND_SIZE(opcode);
-    if ((opcode >= 0xc0) && srp->header.twelve_byte) 
-        cmd_size = 12;
+    if (sfp->next_cmd_len > 0) {
+        if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
+            SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
+            sfp->next_cmd_len = 0;
+            return -EDOM;
+        }
+        cmd_size = sfp->next_cmd_len;
+        sfp->next_cmd_len = 0; /* reset so only this write() effected */
+    }
+    else {
+        cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */
+        if ((opcode >= 0xc0) && srp->header.twelve_byte) 
+            cmd_size = 12;
+    }
     SCSI_LOG_TIMEOUT(4, printk("sg_write:   scsi opcode=0x%02x, cmd_size=%d\n", 
                                (int)opcode, cmd_size));
 /* Determine buffer size.  */
     input_size = count - cmd_size;
     mxsize = (input_size > srp->header.reply_len) ? input_size :
                                                     srp->header.reply_len;
-/* Don't include the command header itself in the size.  */
     mxsize -= size_sg_header;
     input_size -= size_sg_header;
-/* Verify user has actually passed enough bytes for this command. */
     if (input_size < 0) {
-        sg_sc_undo_rem(srp, NULL, 0);
-        return -EIO; 
+        sg_remove_request(sfp, srp);
+        return -EIO; /* User did not pass enough bytes for this command. */
     }
-
-/* If we cannot allocate the buffer, report an error. */
-    if ((k = sg_sc_build(srp, mxsize, buf + cmd_size, input_size))) {
+    if ((k = sg_start_req(srp, mxsize, buf + cmd_size, input_size))) {
         SCSI_LOG_TIMEOUT(1, printk("sg_write: build err=%d\n", k));
-        sg_sc_undo_rem(srp, NULL, 0);
-        return k;
+        sg_finish_rem_req(srp, NULL, 0);
+        return k;    /* probably out of space --> ENOMEM */
     }
-
 /*  SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */
-/* Grab a command pointer for the device we want to talk to. If we
- * don't want to block, just return with the appropriate message.  */
     if (! (SCpnt = scsi_allocate_device(NULL, sdp->device, 
                                         !(filp->f_flags & O_NONBLOCK)))) {
-        sg_sc_undo_rem(srp, NULL, 0);
-        return -EAGAIN;
+        sg_finish_rem_req(srp, NULL, 0);
+        return -EAGAIN;   /* No available command blocks at the moment */
     }
 /*  SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */
-
     srp->my_cmdp = SCpnt;
     SCpnt->request.rq_dev = sdp->i_rdev;
     SCpnt->request.rq_status = RQ_ACTIVE;
     SCpnt->sense_buffer[0] = 0;
     SCpnt->cmd_len = cmd_size;
-    /* Now copy the SCSI command from the user's address space.  */
     __copy_from_user(cmnd, buf, cmd_size);
-
-/* Set the LUN field in the command structure.  */
+/* Set the LUN field in the command structure, overriding user input  */
     cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
+
 /*  SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */
-/* Now pass the actual command down to the low-level driver.  We
- * do not do any more here - when the interrupt arrives, we will
- * then do the post-processing.  */
     spin_lock_irqsave(&io_request_lock, flags);
     SCpnt->use_sg = srp->data.use_sg;
     SCpnt->sglist_len = srp->data.sglist_len;
@@ -454,6 +461,8 @@ static ssize_t sg_write(struct file * filp, const char * buf,
     srp->data.sglist_len = 0;
     srp->data.bufflen = 0;
     srp->data.buffer = NULL;
+/* Now send everything of to mid-level. The next time we hear about this
+   packet is when sg_command_done() is called (ie a callback). */
     scsi_do_cmd(SCpnt, (void *)cmnd,
                 (void *)SCpnt->buffer, mxsize,
                 sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES);
@@ -475,9 +484,6 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
         return -ENXIO;
     SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", 
                                MINOR(sdp->i_rdev), (int)cmd_in));
-     /* If we are in the middle of error recovery, then don't allow any
-     *  access to this device.  Also, error recovery *may* have taken the
-     *  device offline, in which case all further access is prohibited.  */
     if(! scsi_block_when_processing_errors(sdp->device) )
         return -ENXIO;
 
@@ -485,20 +491,18 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
     {
     case SG_SET_TIMEOUT:
         return get_user(sfp->timeout, (int *)arg);
-    case SG_GET_TIMEOUT:
+    case SG_GET_TIMEOUT:  /* N.B. User receives timeout as return value */
         return sfp->timeout; /* strange ..., for backward compatibility */
     case SG_SET_FORCE_LOW_DMA:
         result = get_user(val, (int *)arg);
         if (result) return result;
         if (val) {
-            if ((0 == sfp->low_dma) && (0 == sg_fb_in_use(sfp))) {
-                sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
-                sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, 1, 
-                                             SG_HEAP_PAGE, &sfp->fb_size);
-            }
             sfp->low_dma = 1;
-            if (! sfp->fst_buf)
-                return -ENOMEM;
+            if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
+                val = (int)sfp->reserve.bufflen;
+                sg_remove_scat(&sfp->reserve);
+                sg_build_reserve(sfp, val);
+            }
         }
         else
             sfp->low_dma = sdp->device->host->unchecked_isa_dma;
@@ -550,15 +554,20 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
     case SG_GET_SG_TABLESIZE:
         return put_user(sdp->sg_tablesize, (int *)arg);
     case SG_SET_RESERVED_SIZE:
-        /* currently ignored, future extension */
         if (O_RDWR != (filp->f_flags & O_ACCMODE))
             return -EACCES;
         result = get_user(val, (int *)arg);
         if (result) return result;
-        /* logic should go here */
+        if (val != sfp->reserve.bufflen) {
+            if (sg_res_in_use(sfp))
+                return -EBUSY;
+            sg_remove_scat(&sfp->reserve);
+            sg_build_reserve(sfp, val);
+        }
         return 0;
     case SG_GET_RESERVED_SIZE:
-        return put_user(sfp->fb_size, (int *)arg);
+        val = (int)sfp->reserve.bufflen;
+        return put_user(val, (int *)arg);
     case SG_GET_MERGE_FD:
         return put_user((int)sdp->merge_fd, (int *)arg);
     case SG_SET_MERGE_FD:
@@ -587,6 +596,13 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
         return 0;
     case SG_GET_UNDERRUN_FLAG:
         return put_user((int)sfp->underrun_flag, (int *)arg);
+    case SG_NEXT_CMD_LEN:
+        result = get_user(val, (int *)arg);
+        if (result) return result;
+        sfp->next_cmd_len = (val > 0) ? val : 0;
+        return 0;
+    case SG_GET_VERSION_NUM:
+        return put_user(sg_version_num, (int *)arg);
     case SG_EMULATED_HOST:
         return put_user(sdp->device->host->hostt->emulated, (int *)arg);
     case SCSI_IOCTL_SEND_COMMAND:
@@ -594,8 +610,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
            user already has read/write access to the generic device and so
            can execute arbitrary SCSI commands.  */
         if (O_RDWR != (filp->f_flags & O_ACCMODE))
-            return -EACCES; /* require write access since these could be
-                               dangerous */
+            return -EACCES; /* very dangerous things can be done here */
         return scsi_ioctl_send_command(sdp->device, (void *)arg);
     case SG_SET_DEBUG:
         result = get_user(val, (int *)arg);
@@ -613,8 +628,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
         return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
     default:
         if (O_RDWR != (filp->f_flags & O_ACCMODE))
-            return -EACCES; /* require write access since these could be
-                               dangerous */
+            return -EACCES; /* don't know so take safe approach */
         return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
     }
 }
@@ -664,8 +678,7 @@ static int sg_fasync(int fd, struct file * filp, int mode)
 }
 
 /* This function is called by the interrupt handler when we
- * actually have a command that is complete.  Change the
- * flags to indicate that we have a result.  */
+ * actually have a command that is complete. */
 static void sg_command_done(Scsi_Cmnd * SCpnt)
 {
     int dev = MINOR(SCpnt->request.rq_dev);
@@ -712,17 +725,16 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
     sg_clr_scpnt(SCpnt);
     srp->my_cmdp = NULL;
 
-    SCSI_LOG_TIMEOUT(4, 
-              printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", 
+    SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", 
                 dev, (int)status_byte(SCpnt->result), (int)SCpnt->result));
-/* See if the command completed normally, or whether something went wrong. */
     memcpy(srp->header.sense_buffer, SCpnt->sense_buffer,
            sizeof(SCpnt->sense_buffer));
     switch (host_byte(SCpnt->result)) 
-    {
+    { /* This setup of 'result' is for backward compatibility and is best
+         ignored by the user who should use target, host + driver status */
     case DID_OK:
-    case DID_PASSTHROUGH: /* just guessing */
-    case DID_SOFT_ERROR:  /* just guessing */
+    case DID_PASSTHROUGH: 
+    case DID_SOFT_ERROR:
       srp->header.result = 0;
       break;
     case DID_NO_CONNECT:
@@ -738,12 +750,6 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
       srp->header.result = EIO;
       break;
     case DID_ERROR:
-      /* There really should be DID_UNDERRUN and DID_OVERRUN error values,
-       * and a means for callers of scsi_do_cmd to indicate whether an
-       * underrun or overrun should signal an error.  Until that can be
-       * implemented, this kludge allows for returning useful error values
-       * except in cases that return DID_ERROR that might be due to an
-       * underrun. */
       if (SCpnt->sense_buffer[0] == 0 &&
           status_byte(SCpnt->result) == GOOD)
           srp->header.result = 0;
@@ -767,8 +773,6 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
 /* filesystems using this device. */
         sdp->device->changed = 1;
     }
-
-/* Pick up error and status information */
     srp->header.target_status = status_byte(SCpnt->result);
     if ((sdp->sgdebug > 0) && 
         ((CHECK_CONDITION == srp->header.target_status) ||
@@ -784,15 +788,14 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
         SCSI_LOG_TIMEOUT(1,
                printk("sg__done: already closed, freeing ...\n"));
 /* should check if module is unloaded <<<<<<< */
-        sg_sc_undo_rem(srp, NULL, 0);
+        sg_finish_rem_req(srp, NULL, 0);
         if (NULL == sfp->headrp) { 
             SCSI_LOG_TIMEOUT(1,
                 printk("sg__done: already closed, final cleanup\n"));
             sg_remove_sfp(sdp, sfp);
         }
     }
-/* Now wake up the process that is waiting for the result. */
-    /* A. Rubini says this is preferable+faster than wake_up() */
+/* Now wake up any sg_read() that is waiting for this packet. */
     wake_up_interruptible(&sfp->read_wait);
     if ((sfp->async_qp) && (! closed))
         kill_fasync(sfp->async_qp, SIGPOLL);
@@ -873,17 +876,20 @@ static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of)
             printk("  *** Following data belongs to invoking FD ***\n");
         else if (! fp->parentdp)
             printk(">> Following FD has NULL parent pointer ???\n");
-        printk("   FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n",
-               k, fp->timeout, fp->fb_size, (int)fp->cmd_q);
-        printk("   low_dma=%d, force_packid=%d, urun_flag=%d, closed=%d\n",
-               (int)fp->low_dma, (int)fp->force_packid, 
-               (int)fp->underrun_flag, (int)fp->closed);
+        printk("   FD(%d): timeout=%d, bufflen=%d, use_sg=%d\n",
+               k, fp->timeout, fp->reserve.bufflen, (int)fp->reserve.use_sg);
+        printk("   low_dma=%d, cmd_q=%d, s_sc_len=%d, f_packid=%d\n",
+               (int)fp->low_dma, (int)fp->cmd_q, (int)fp->save_scat_len,
+               (int)fp->force_packid);
+        printk("   urun_flag=%d, next_cmd_len=%d, closed=%d\n",
+               (int)fp->underrun_flag, (int)fp->next_cmd_len, 
+               (int)fp->closed);
         srp = fp->headrp;
         if (NULL == srp)
             printk("     No requests active\n");
         while (srp) {
-            if (srp->fb_used)
-                printk("using 1st buff >> ");
+            if (srp->res_used)
+                printk("reserved buff >> ");
             else
                 printk("     ");
             if (srp->my_cmdp)
@@ -988,7 +994,7 @@ static int sg_attach(Scsi_Device * scsidp)
 
     SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
     sdp->device = scsidp;
-    sdp->generic_wait = NULL;
+    sdp->o_excl_wait = NULL;
     sdp->headfp= NULL;
     sdp->exclude = 0;
     sdp->merge_fd = 0;  /* Cope with SG_DEF_MERGE_FD on open */
@@ -1041,10 +1047,8 @@ static void sg_detach(Scsi_Device * scsidp)
         }
         scsidp->attached--;
         sg_template.nr_dev--;
-        /*
-         * avoid associated device /dev/sg? bying incremented
-         * each time module is inserted/removed , <dan@lectra.fr>
-         */
+/* avoid associated device /dev/sg? being incremented
+ * each time module is inserted/removed , <dan@lectra.fr> */
         sg_template.dev_noticed--;
         return;
     }
@@ -1099,42 +1103,80 @@ static void sg_shorten_timeout(Scsi_Cmnd * scpnt)
 #endif
 }
 
-static int sg_sc_build(Sg_request * srp, int max_buff_size,
-                       const char * inp, int num_write_xfer)
+static int sg_start_req(Sg_request * srp, int max_buff_size,
+                        const char * inp, int num_write_xfer)
+{
+    int res;
+    Sg_fd * sfp = srp->parentfp;
+    Sg_scatter_hold * req_schp = &srp->data;
+    Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+    SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n", 
+                               max_buff_size)); 
+    if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) {
+        sg_link_reserve(sfp, srp, max_buff_size);
+        sg_write_xfer(req_schp, inp, num_write_xfer);
+    }
+    else {
+        res = sg_build_scat(req_schp, max_buff_size, sfp);
+        if (res) {
+            sg_remove_scat(req_schp);
+            return res;
+        }
+        sg_write_xfer(req_schp, inp, num_write_xfer);
+    }
+    return 0;
+}
+
+static void sg_finish_rem_req(Sg_request * srp, char * outp, 
+                              int num_read_xfer)
+{
+    Sg_fd * sfp = srp->parentfp;
+    Sg_scatter_hold * req_schp = &srp->data;
+
+    SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n",
+                               (int)srp->res_used)); 
+    if (num_read_xfer > 0)
+        sg_read_xfer(req_schp, outp, num_read_xfer);
+    if (srp->res_used)
+        sg_unlink_reserve(sfp, srp);
+    else 
+        sg_remove_scat(req_schp);
+    sg_remove_request(sfp, srp);
+}
+
+static int sg_build_scat(Sg_scatter_hold * schp, int buff_size, 
+                         const Sg_fd * sfp)
 {
     int ret_sz, mem_src;
-    int blk_size = max_buff_size;
+    int blk_size = buff_size;
     char * p = NULL;
 
-    if ((blk_size < 0) || (! srp))
+    if ((blk_size < 0) || (! sfp))
         return -EFAULT;
-    
-    SCSI_LOG_TIMEOUT(4, printk("sg_sc_build: m_b_s=%d, num_write_xfer=%d\n", 
-                                  max_buff_size, num_write_xfer)); 
     if (0 == blk_size)
         ++blk_size;             /* don't know why */
 /* round request up to next highest SG_SECTOR_SZ byte boundary */
     blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
-    SCSI_LOG_TIMEOUT(5, printk("sg_sc_build: blk_size=%d\n", blk_size));
-
+    SCSI_LOG_TIMEOUT(4, printk("sg_build_scat: buff_size=%d, blk_size=%d\n",
+                               buff_size, blk_size));
     if (blk_size <= SG_SCATTER_SZ) {
-        mem_src = SG_HEAP_FB;
-        p = sg_malloc(srp, blk_size, &ret_sz, &mem_src);
+        mem_src = SG_HEAP_PAGE;
+        p = sg_malloc(sfp, blk_size, &ret_sz, &mem_src);
         if (! p)
             return -ENOMEM;
         if (blk_size == ret_sz) { /* got it on the first attempt */
-            srp->data.buffer = p;
-            srp->data.bufflen = blk_size;
-            srp->data.mem_src = mem_src;
-            srp->data.b_malloc_len = blk_size;
-            if (inp && (num_write_xfer > 0))
-                __copy_from_user(srp->data.buffer, inp, num_write_xfer);
+            schp->use_sg = 0;
+            schp->buffer = p;
+            schp->bufflen = blk_size;
+            schp->mem_src = mem_src;
+            schp->b_malloc_len = blk_size;
             return 0;
         }
     }
     else {
         mem_src = SG_HEAP_PAGE;
-        p = sg_malloc(srp, SG_SCATTER_SZ, &ret_sz, &mem_src);
+        p = sg_malloc(sfp, SG_SCATTER_SZ, &ret_sz, &mem_src);
         if (! p)
             return -ENOMEM;
     }
@@ -1144,23 +1186,23 @@ static int sg_sc_build(Sg_request * srp, int max_buff_size,
         int k, rem_sz, num, nxt;
         int sc_bufflen = PAGE_SIZE;
         int mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1;
-        int sg_tablesize = srp->parentfp->parentdp->sg_tablesize;
+        int sg_tablesize = sfp->parentdp->sg_tablesize;
         int first = 1;
 
         k = SG_HEAP_KMAL;  /* want to protect mem_src, use k as scratch */
-        srp->data.buffer = (struct scatterlist *)sg_malloc(srp, 
+        schp->buffer = (struct scatterlist *)sg_malloc(sfp, 
                                 sc_bufflen, &num, &k);
-        srp->data.mem_src = (char)k;
+        schp->mem_src = (char)k;
         /* N.B. ret_sz and mem_src carried into this block ... */
-        if (! srp->data.buffer)
+        if (! schp->buffer)
             return -ENOMEM;
         else if (num != sc_bufflen) {
             sc_bufflen = num;
             mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1;
         }
-        srp->data.sglist_len = sc_bufflen;
-        memset(srp->data.buffer, 0, sc_bufflen);
-        for (k = 0, sclp = srp->data.buffer, rem_sz = blk_size, nxt =0; 
+        schp->sglist_len = sc_bufflen;
+        memset(schp->buffer, 0, sc_bufflen);
+        for (k = 0, sclp = schp->buffer, rem_sz = blk_size, nxt =0; 
              (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); 
              ++k, rem_sz -= ret_sz, ++sclp) {
             if (first) 
@@ -1168,7 +1210,7 @@ static int sg_sc_build(Sg_request * srp, int max_buff_size,
             else {
                 num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
                 mem_src = SG_HEAP_PAGE;
-                p = sg_malloc(srp, num, &ret_sz, &mem_src);
+                p = sg_malloc(sfp, num, &ret_sz, &mem_src);
                 if (! p)
                     break;
             }
@@ -1176,73 +1218,188 @@ static int sg_sc_build(Sg_request * srp, int max_buff_size,
             sclp->length = ret_sz;
             sclp->alt_address = (char *)(long)mem_src;
             
-            if(inp && (num_write_xfer > 0)) {
-                num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz;
-                __copy_from_user(sclp->address, inp, num);
-                num_write_xfer -= num;
-                inp += num;
-            }
             SCSI_LOG_TIMEOUT(5, 
-                printk("sg_sc_build: k=%d, a=0x%p, len=%d, ms=%d\n", 
+                printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n", 
                 k, sclp->address, ret_sz, mem_src));
         } /* end of for loop */
-        srp->data.use_sg = k;
+        schp->use_sg = k;
         SCSI_LOG_TIMEOUT(5, 
-            printk("sg_sc_build: use_sg=%d, rem_sz=%d\n", k, rem_sz));
-        srp->data.bufflen = blk_size;
+            printk("sg_build_scat: use_sg=%d, rem_sz=%d\n", k, rem_sz));
+        schp->bufflen = blk_size;
         if (rem_sz > 0)   /* must have failed */
             return -ENOMEM;
     }
     return 0;
 }
 
-static int sg_sc_undo_rem(Sg_request * srp, char * outp,
-                          int num_read_xfer)
+static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp, 
+                          int num_write_xfer)
 {
-    if (! srp)
-        return -EFAULT;
-    SCSI_LOG_TIMEOUT(4, printk("sg_sc_undo_rem: num_read_xfer=%d\n", 
-                               num_read_xfer)); 
-    if (! outp)
-        num_read_xfer = 0;
-    if(srp->data.use_sg) {
-        int k, num, mem_src;
-        struct scatterlist * sclp = (struct scatterlist *)srp->data.buffer;
-
-        for (k = 0; (k < srp->data.use_sg) && sclp->address; ++k, ++sclp) {
-            if (num_read_xfer > 0) {
-                num = (int)sclp->length;
-                if (num > num_read_xfer) {
-                    __copy_to_user(outp, sclp->address, num_read_xfer);
-                    outp += num_read_xfer;
-                    num_read_xfer = 0;
-                }
-                else {
-                    __copy_to_user(outp, sclp->address, num);
-                    outp += num;
-                    num_read_xfer -= num;
-                }
+    SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_write_xfer=%d, use_sg=%d\n", 
+                               num_write_xfer, schp->use_sg)); 
+    if ((! inp) || (num_write_xfer <= 0))
+        return;
+    if (schp->use_sg > 0) {
+        int k, num;
+        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+        for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) { 
+            num = (int)sclp->length;
+            if (num > num_write_xfer) {
+                __copy_from_user(sclp->address, inp, num_write_xfer);
+                break;
             }
+            else {
+                __copy_from_user(sclp->address, inp, num);
+                num_write_xfer -= num;
+                if (num_write_xfer <= 0)
+                    break;
+                inp += num;
+            }
+        }
+    }
+    else
+        __copy_from_user(schp->buffer, inp, num_write_xfer);
+}
+
+static void sg_remove_scat(Sg_scatter_hold * schp)
+{
+    SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: use_sg=%d\n", schp->use_sg)); 
+    if(schp->use_sg > 0) {
+        int k, mem_src;
+        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+        for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
             mem_src = (int)(long)sclp->alt_address;
             SCSI_LOG_TIMEOUT(5, 
-                printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n", 
+                printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n", 
                        k, sclp->address, sclp->length, mem_src));
-            sg_free(srp, sclp->address, sclp->length, mem_src);
+            sg_free(sclp->address, sclp->length, mem_src);
+            sclp->address = NULL;
+            sclp->length = 0;
         }
-        sg_free(srp, srp->data.buffer, srp->data.sglist_len, 
-                srp->data.mem_src);
+        sg_free(schp->buffer, schp->sglist_len, schp->mem_src);
+    }
+    else if (schp->buffer)
+        sg_free(schp->buffer, schp->b_malloc_len, schp->mem_src);
+    schp->buffer = NULL;
+    schp->bufflen = 0;
+    schp->use_sg = 0;
+    schp->sglist_len = 0;
+}
+
+static void sg_read_xfer(Sg_scatter_hold * schp, char * outp,
+                         int num_read_xfer)
+{
+    SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_read_xfer=%d\n", 
+                               num_read_xfer)); 
+    if ((! outp) || (num_read_xfer <= 0))
+        return;
+    if(schp->use_sg > 0) {
+        int k, num;
+        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+        for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
+            num = (int)sclp->length;
+            if (num > num_read_xfer) {
+                __copy_to_user(outp, sclp->address, num_read_xfer);
+                break;
+            }
+            else {
+                __copy_to_user(outp, sclp->address, num);
+                num_read_xfer -= num;
+                if (num_read_xfer <= 0)
+                    break;
+                outp += num;
+            }
+        }
+    }
+    else
+        __copy_to_user(outp, schp->buffer, num_read_xfer);
+}
+
+static void sg_build_reserve(Sg_fd * sfp, int req_size)
+{
+    Sg_scatter_hold * schp = &sfp->reserve;
+
+    SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size)); 
+    do {
+        if (req_size < PAGE_SIZE)
+            req_size = PAGE_SIZE;
+        if (0 == sg_build_scat(schp, req_size, sfp))
+            return;
+        else
+            sg_remove_scat(schp);
+        req_size >>= 1; /* divide by 2 */
+    } while (req_size >  (PAGE_SIZE / 2));
+}
+
+static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
+{
+    Sg_scatter_hold * req_schp = &srp->data;
+    Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+    SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); 
+    if (rsv_schp->use_sg > 0) {
+        int k, num;
+        int rem = size;
+        struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
+
+        for (k = 0; k < rsv_schp->use_sg; ++k, ++sclp) {
+            num = (int)sclp->length;
+            if (rem <= num) {
+                sfp->save_scat_len = num;
+                sclp->length = (unsigned)rem;
+                break;
+            }
+            else
+                rem -= num;
+        }
+        if (k < rsv_schp->use_sg) {
+            req_schp->use_sg = k + 1;   /* adjust scatter list length */
+            req_schp->bufflen = size;
+            req_schp->sglist_len = rsv_schp->sglist_len;
+            req_schp->buffer = rsv_schp->buffer;
+            req_schp->mem_src = rsv_schp->mem_src;
+            req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+        }
+        else
+            SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n")); 
     }
     else {
-        if (num_read_xfer > 0) 
-            __copy_to_user(outp, srp->data.buffer, num_read_xfer);
-        sg_free(srp, srp->data.buffer, srp->data.b_malloc_len, 
-                srp->data.mem_src);
+        req_schp->use_sg = 0;
+        req_schp->bufflen = size;
+        req_schp->buffer = rsv_schp->buffer;
+        req_schp->mem_src = rsv_schp->mem_src;
+        req_schp->use_sg = rsv_schp->use_sg;
+        req_schp->b_malloc_len = rsv_schp->b_malloc_len;
     }
-    if (0 == sg_remove_request(srp->parentfp, srp)) {
-        SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n", 
-                                   srp));
+    srp->res_used = 1;
+}
+
+static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
+{
+    Sg_scatter_hold * req_schp = &srp->data;
+    Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+    SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->use_sg=%d\n",
+                               (int)req_schp->use_sg)); 
+    if (rsv_schp->use_sg > 0) {
+        struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
+
+        if (sfp->save_scat_len > 0) 
+            (sclp + (req_schp->use_sg - 1))->length = 
+                                        (unsigned)sfp->save_scat_len;
+        else
+            SCSI_LOG_TIMEOUT(1, printk(
+                        "sg_unlink_reserve: BAD save_scat_len\n")); 
     }
-    return 0;
+    req_schp->use_sg = 0;
+    req_schp->bufflen = 0;
+    req_schp->buffer = NULL;
+    req_schp->sglist_len = 0;
+    sfp->save_scat_len = 0;
+    srp->res_used = 0;
 }
 
 static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id)
@@ -1292,7 +1449,7 @@ static Sg_request * sg_add_request(Sg_fd * sfp)
     if (resp) {
         resp->parentfp = sfp;
         resp->nextrp = NULL;
-        resp->fb_used = 0;
+        resp->res_used = 0;
         memset(&resp->data, 0, sizeof(Sg_scatter_hold));
         memset(&resp->header, 0, sizeof(struct sg_header));
         resp->my_cmdp = NULL;
@@ -1347,13 +1504,6 @@ static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved)
                    sdp->device->host->unchecked_isa_dma : 1;
     sfp->cmd_q = SG_DEF_COMMAND_Q;
     sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG;
-    if (get_reserved)
-        sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, 
-                                     SG_HEAP_PAGE, &sfp->fb_size);
-    else
-        sfp->fst_buf = NULL;
-    if (! sfp->fst_buf)
-        sfp->fb_size = 0;
     sfp->parentdp = sdp;
     if (! sdp->headfp)
         sdp->headfp = sfp;
@@ -1363,11 +1513,14 @@ static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved)
            pfp = pfp->nextfp;
         pfp->nextfp = sfp;
     }
-    sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */
     SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n",
                                sfp, (int)sfp->my_mem_src));
-    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   fb_sz=%d, fst_buf=0x%p\n",
-                               sfp->fb_size, sfp->fst_buf));
+    if (get_reserved) {
+        sg_build_reserve(sfp, SG_DEF_RESERVED_SIZE);
+        sg_big_buff = sfp->reserve.bufflen; /* sysctl shows most recent size */
+        SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, use_sg=%d\n",
+                               sfp->reserve.bufflen, sfp->reserve.use_sg));
+    }
     return sfp;
 }
 
@@ -1388,7 +1541,7 @@ static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
         while (srp) {
             tsrp = srp->nextrp;
             if (! srp->my_cmdp)
-                sg_sc_undo_rem(srp, NULL, 0);
+                sg_finish_rem_req(srp, NULL, 0);
             else
                 ++dirty;
             srp = tsrp;
@@ -1409,12 +1562,12 @@ static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
                 prev_fp = fp;
             }
         }
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    fb_sz=%d, fst_buf=0x%p\n",
-                 sfp->fb_size, sfp->fst_buf));
-        sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
+        if (sfp->reserve.bufflen > 0) {
+SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    bufflen=%d, use_sg=%d\n",
+                 (int)sfp->reserve.bufflen, (int)sfp->reserve.use_sg));
+            sg_remove_scat(&sfp->reserve);
+        }
         sfp->parentdp = NULL;
-        sfp->fst_buf = NULL;
-        sfp->fb_size = 0;
     SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    sfp=0x%p\n", sfp));
         sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src);
         res = 1;
@@ -1427,12 +1580,12 @@ SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    fb_sz=%d, fst_buf=0x%p\n",
     return res;
 }
 
-static int sg_fb_in_use(const Sg_fd * sfp)
+static int sg_res_in_use(const Sg_fd * sfp)
 {
     const Sg_request * srp = sfp->headrp;
 
     while (srp) {
-        if (srp->fb_used)
+        if (srp->res_used)
             return 1;
         srp = srp->nextrp;
     }
@@ -1511,7 +1664,7 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
     return resp;
 }
 
-static char * sg_malloc(Sg_request * srp, int size, int * retSzp, 
+static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, 
                         int * mem_srcp)
 {
     char * resp = NULL;
@@ -1520,26 +1673,16 @@ static char * sg_malloc(Sg_request * srp, int size, int * retSzp,
     if (size <= 0)
         ;
     else {
-        Sg_fd * sfp = srp->parentfp;
         int low_dma = sfp->low_dma;
         int l_ms = -1;  /* invalid value */
 
         switch (*mem_srcp) 
         {
         case SG_HEAP_PAGE:
-        case SG_HEAP_FB:
             l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
             if (resp)
                 break;
-            if ((size <= sfp->fb_size) && (0 == sg_fb_in_use(sfp))) {
-                SCSI_LOG_TIMEOUT(6,
-                    printk("sg_malloc: scsi_malloc failed, get fst_buf\n"));
-                resp = sfp->fst_buf;
-                srp->fb_used = 1;
-                l_ms = SG_HEAP_FB;
-                break;
-            }
             resp = sg_low_malloc(size, low_dma, l_ms, &size);
             if (! resp) {
                 l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
@@ -1595,18 +1738,12 @@ static void sg_low_free(char * buff, int size, int mem_src)
                mem_src, buff, size);
 }
 
-static void sg_free(Sg_request * srp, char * buff, int size, int mem_src)
+static void sg_free(char * buff, int size, int mem_src)
 {
-    Sg_fd * sfp = srp->parentfp;
-
     SCSI_LOG_TIMEOUT(6, 
         printk("sg_free: buff=0x%p, size=%d\n", buff, size));
-    if ((! sfp) || (! buff) || (size <= 0))
+    if ((! buff) || (size <= 0))
         ;
-    else if (sfp->fst_buf == buff) {
-        srp->fb_used = 0;
-        SCSI_LOG_TIMEOUT(6, printk("sg_free:   left cause fst_buf\n"));
-    }
     else
         sg_low_free(buff, size, mem_src);
 }
index 3b8d32fb3468cf97d2b6bc9f330fcb49522199cb..8d71cc16e2892a99b2ba1285e1e58d85bbc0a1c1 100644 (file)
@@ -69,9 +69,9 @@ if [ "$CONFIG_INET" = "y" ]; then
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     tristate 'NFS server support' CONFIG_NFSD
-  fi
-  if [ "$CONFIG_NFSD" != "n" ]; then
-    bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
+    if [ "$CONFIG_NFSD" != "n" ]; then
+      bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
+    fi
   fi
   if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
     define_bool CONFIG_SUNRPC y
index 55eed097a3cb2ce36c643cd819b4a03ccb6b325b..d7ad2158e436a03908fc848ea1ba54fa18918762 100644 (file)
@@ -145,7 +145,7 @@ static void coda_put_super(struct super_block *sb)
         sb->s_dev = 0;
        coda_cache_clear_all(sb);
        sb_info = coda_sbp(sb);
-       sb_info->sbi_vcomm->vc_inuse = 0;
+/*     sb_info->sbi_vcomm->vc_inuse = 0; You can not do this: psdev_release would see usagecount == 0 and would refuse to decrease MOD_USE_COUNT --pavel */ 
        coda_super_info.sbi_sb = NULL;
        printk("Coda: Bye bye.\n");
        memset(sb_info, 0, sizeof(* sb_info));
index 5f792e31b77d6eac0ac68341453b74a3eadc51b0..f606b76e46be4d6ea28ed6f9b8a33ce4570eae8f 100644 (file)
@@ -257,6 +257,7 @@ nfs_readpage(struct file *file, struct page *page)
 
 out_error:
        clear_bit(PG_locked, &page->flags);
+       wake_up(&page->wait);
 out_free:
        free_page(page_address(page));
 out:
index a85501cbbbbb1a7990b3a722a3a7adbb29c0e562..f343aecd32662e267583ad6619b2b53443a521e0 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ALPHA_INIT_H
 #define _ALPHA_INIT_H
 
+#ifndef MODULE
 #define __init __attribute__ ((__section__ (".text.init")))
 #define __initdata __attribute__ ((__section__ (".data.init")))
 #define __initfunc(__arginit) \
@@ -11,6 +12,7 @@
 #define __INIT         .section        .text.init,"ax"
 #define __FINIT                .previous
 #define __INITDATA     .section        .data.init,"a"
+#endif
 
 #define __cacheline_aligned __attribute__((__aligned__(32)))
 
index dc976cb5fca71750b6053e894806da37d9356fbe..d2fdc410bf645e1532e4637b7d606fd1404accdb 100644 (file)
  */
 static inline void __set_hae(unsigned long new_hae)
 {
-       unsigned long ipl = swpipl(7);
+       unsigned long flags;
+       __save_and_cli(flags);
 
        alpha_mv.hae_cache = new_hae;
        *alpha_mv.hae_register = new_hae;
        mb();
-
        /* Re-read to make sure it was written.  */
        new_hae = *alpha_mv.hae_register;
-       setipl(ipl);
+
+       __restore_flags(flags);
 }
 
 static inline void set_hae(unsigned long new_hae)
index aeec2c041b12422cd4cc590f23f69f0c692767d2..98014045f3aba6761cdb921031605241314d6d60 100644 (file)
@@ -108,7 +108,7 @@ __EXTERN_INLINE void ev5_get_mmu_context(struct task_struct *p)
        if (mm) {
                unsigned long asn = asn_cache;
                /* Check if our ASN is of an older version,
-                  or on a different CPU, and thus invalid */
+                  or on a different CPU, and thus invalid */
                if ((mm->context ^ asn) & ~HARDWARE_ASN_MASK)
                        get_new_mmu_context(p, mm);
        }
index 2e8b4e0a1794c54754af0d7a47e991945ce50e18..350db2a9fa70ebf296b034e14351dc549451b860 100644 (file)
@@ -86,16 +86,6 @@ struct el_common_EV5_uncorrectable_mcheck {
         unsigned long   ld_lock;          /* Contents of EV5 LD_LOCK register*/
 };
 
-
-extern void wrent(void *, unsigned long);
-extern void wrkgp(unsigned long);
-extern void wrusp(unsigned long);
-extern unsigned long rdusp(void);
-extern unsigned long rdmces (void);
-extern void wrmces (unsigned long);
-extern unsigned long whami(void);
-extern void wripir(unsigned long);
-
 extern void halt(void) __attribute__((noreturn));
 
 #define switch_to(prev,next,last)                      \
@@ -154,85 +144,91 @@ enum amask_enum {
        AMASK_PRECISE_TRAP = (1UL << 9),
 };
 
-enum amask_enum {
-       AMASK_BWX = (1UL << 0),
-       AMASK_FIX = (1UL << 1),
-       AMASK_MAX = (1UL << 8),
-       AMASK_PRECISE_TRAP = (1UL << 9),
-};
-
 #define amask(mask)                                            \
 ({ unsigned long __amask, __input = (mask);                    \
    __asm__ ("amask %1,%0" : "=r"(__amask) : "rI"(__input));    \
    __amask; })
 
-static inline unsigned long 
-wrperfmon(unsigned long perf_fun, unsigned long arg)
-{
-          register unsigned long __r0 __asm__("$0");
-         register unsigned long __r16 __asm__("$16");
-         register unsigned long __r17 __asm__("$17");
-         __r16 = perf_fun;
-         __r17 = arg;
-         __asm__ __volatile__(
-                 "call_pal %1"
-                 : "=r"(__r0)
-                 : "i"(PAL_wrperfmon), "r"(__r16), "r"(__r17)
-                 : "$1", "$22", "$23", "$24", "$25", "$26");
-         return __r0;
+#define __CALL_PAL_R0(NAME, TYPE)                              \
+static inline TYPE NAME(void)                                  \
+{                                                              \
+       register TYPE __r0 __asm__("$0");                       \
+       __asm__ __volatile__(                                   \
+               "call_pal %1 # " #NAME                          \
+               :"=r" (__r0)                                    \
+               :"i" (PAL_ ## NAME)                             \
+               :"$1", "$16", "$22", "$23", "$24", "$25");      \
+       return __r0;                                            \
 }
 
+#define __CALL_PAL_W1(NAME, TYPE0)                             \
+static inline void NAME(TYPE0 arg0)                            \
+{                                                              \
+       register TYPE0 __r16 __asm__("$16") = arg0;             \
+       __asm__ __volatile__(                                   \
+               "call_pal %1 # "#NAME                           \
+               : "=r"(__r16)                                   \
+               : "i"(PAL_ ## NAME), "0"(__r16)                 \
+               : "$1", "$22", "$23", "$24", "$25");            \
+}
 
-#define call_pal1(palno,arg)                                           \
-({                                                                     \
-       register unsigned long __r0 __asm__("$0");                      \
-       register unsigned long __r16 __asm__("$16"); __r16 = arg;       \
-       __asm__ __volatile__(                                           \
-               "call_pal %3 #call_pal1"                                \
-               :"=r" (__r0),"=r" (__r16)                               \
-               :"1" (__r16),"i" (palno)                                \
-               :"$1", "$22", "$23", "$24", "$25", "memory");           \
-       __r0;                                                           \
-})
-
-#define getipl()                                                       \
-({                                                                     \
-       register unsigned long r0 __asm__("$0");                        \
-       __asm__ __volatile__(                                           \
-               "call_pal %1 #getipl"                                   \
-               :"=r" (r0)                                              \
-               :"i" (PAL_rdps)                                         \
-               :"$1", "$16", "$22", "$23", "$24", "$25", "memory");    \
-       r0;                                                             \
-})
+#define __CALL_PAL_W2(NAME, TYPE0, TYPE1)                      \
+static inline void NAME(TYPE0 arg0, TYPE1 arg1)                        \
+{                                                              \
+       register TYPE0 __r16 __asm__("$16") = arg0;             \
+       register TYPE1 __r17 __asm__("$17") = arg1;             \
+       __asm__ __volatile__(                                   \
+               "call_pal %2 # "#NAME                           \
+               : "=r"(__r16), "=r"(__r17)                      \
+               : "i"(PAL_ ## NAME), "0"(__r16), "1"(__r17)     \
+               : "$1", "$22", "$23", "$24", "$25");            \
+}
 
-#define setipl(ipl)                                                    \
-({                                                                     \
-       register unsigned long __r16 __asm__("$16"); __r16 = (ipl);     \
-       __asm__ __volatile__(                                           \
-               "call_pal %2 #setipl"                                   \
-               :"=r" (__r16)                                           \
-               :"0" (__r16),"i" (PAL_swpipl)                           \
-               :"$0", "$1", "$22", "$23", "$24", "$25", "memory");     \
-})
+#define __CALL_PAL_RW1(NAME, RTYPE, TYPE0)                     \
+static inline RTYPE NAME(TYPE0 arg0)                           \
+{                                                              \
+       register RTYPE __r0 __asm__("$0");                      \
+       register TYPE0 __r16 __asm__("$16") = arg0;             \
+       __asm__ __volatile__(                                   \
+               "call_pal %2 # "#NAME                           \
+               : "=r"(__r16), "=r"(__r0)                       \
+               : "i"(PAL_ ## NAME), "0"(__r16)                 \
+               : "$1", "$22", "$23", "$24", "$25");            \
+       return __r0;                                            \
+}
 
-#define swpipl(ipl)                                            \
-({                                                             \
-       register unsigned long __r0 __asm__("$0");              \
-       register unsigned long __r16 __asm__("$16") = (ipl);    \
+#define __CALL_PAL_RW2(NAME, RTYPE, TYPE0, TYPE1)              \
+static inline RTYPE NAME(TYPE0 arg0, TYPE1 arg1)               \
+{                                                              \
+       register RTYPE __r0 __asm__("$0");                      \
+       register TYPE0 __r16 __asm__("$16") = arg0;             \
+       register TYPE1 __r17 __asm__("$17") = arg1;             \
        __asm__ __volatile__(                                   \
-               "call_pal %3 #swpipl"                           \
-               :"=r" (__r0),"=r" (__r16)                       \
-               :"1" (__r16),"i" (PAL_swpipl)                   \
-               :"$1", "$22", "$23", "$24", "$25", "memory");   \
-       __r0;                                                   \
-})
+               "call_pal %3 # "#NAME                           \
+               : "=r"(__r16), "=r"(__r17), "=r"(__r0)          \
+               : "i"(PAL_ ## NAME), "0"(__r16), "1"(__r17)     \
+               : "$1", "$22", "$23", "$24", "$25");            \
+       return __r0;                                            \
+}
 
-#define __cli()                        setipl(7)
-#define __sti()                        setipl(0)
-#define __save_flags(flags)    ((flags) = getipl())
+__CALL_PAL_R0(rdmces, unsigned long);
+__CALL_PAL_R0(rdps, unsigned long);
+__CALL_PAL_R0(rdusp, unsigned long);
+__CALL_PAL_RW1(swpipl, unsigned long, unsigned long);
+__CALL_PAL_R0(whami, unsigned long);
+__CALL_PAL_W2(wrent, void*, unsigned long);
+__CALL_PAL_W1(wripir, unsigned long);
+__CALL_PAL_W1(wrkgp, unsigned long);
+__CALL_PAL_W1(wrmces, unsigned long);
+__CALL_PAL_RW2(wrperfmon, unsigned long, unsigned long, unsigned long);
+__CALL_PAL_W1(wrusp, unsigned long);
+__CALL_PAL_W1(wrvptptr, unsigned long);
+
+#define __cli()                        ((void) swpipl(7))
+#define __sti()                        ((void) swpipl(0))
+#define __save_flags(flags)    ((flags) = rdps())
 #define __save_and_cli(flags)  ((flags) = swpipl(7))
-#define __restore_flags(flags) setipl(flags)
+#define __restore_flags(flags) ((void) swpipl(flags))
 
 #ifdef __SMP__
 
index ebd9a4f1a73d1e93e5aca4e81aa56759cdd3068a..2ceaa977dbd3d34e0cf5e23e57a9c0add6909c7a 100644 (file)
@@ -357,10 +357,18 @@ __initfunc(static void check_cyrix_cpu(void))
 __initfunc(static void check_cyrix_coma(void))
 {
        if (boot_cpu_data.coma_bug) {
-               unsigned char ccr1;
+               unsigned char ccr3, tmp;
                cli();
-               ccr1 = getCx86 (CX86_CCR1);
-               setCx86 (CX86_CCR1, ccr1 | 0x10);
+               ccr3 = getCx86(CX86_CCR3);
+               setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
+               tmp = getCx86(0x31);
+               setCx86(0x31, tmp | 0xf8);
+               tmp = getCx86(0x32);
+               setCx86(0x32, tmp | 0x7f);
+               setCx86(0x33, 0);
+               tmp = getCx86(0x3c);
+               setCx86(0x3c, tmp | 0x87);
+               setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
                sti();
                printk("Cyrix processor with \"coma bug\" found, workaround enabled\n");
        }
index 56bbeacf940413e2189c0a79475d29f6e2e8fae8..91cb1aff8f7eb35f613428e7d37c8e752b557c26 100644 (file)
 
 #define PCI_VENDOR_ID_ADAPTEC          0x9004
 #define PCI_DEVICE_ID_ADAPTEC_7810     0x1078
+#define PCI_DEVICE_ID_ADAPTEC_7821     0x2178
 #define PCI_DEVICE_ID_ADAPTEC_7850     0x5078
 #define PCI_DEVICE_ID_ADAPTEC_7855     0x5578
 #define PCI_DEVICE_ID_ADAPTEC_5800     0x5800
+#define PCI_DEVICE_ID_ADAPTEC_3860     0x6038
 #define PCI_DEVICE_ID_ADAPTEC_1480A    0x6075
 #define PCI_DEVICE_ID_ADAPTEC_7860     0x6078
 #define PCI_DEVICE_ID_ADAPTEC_7861     0x6178
 #define PCI_DEVICE_ID_ADAPTEC_7882     0x8278
 #define PCI_DEVICE_ID_ADAPTEC_7883     0x8378
 #define PCI_DEVICE_ID_ADAPTEC_7884     0x8478
+#define PCI_DEVICE_ID_ADAPTEC_7885     0x8578
+#define PCI_DEVICE_ID_ADAPTEC_7886     0x8678
+#define PCI_DEVICE_ID_ADAPTEC_7887     0x8778
+#define PCI_DEVICE_ID_ADAPTEC_7888     0x8878
 #define PCI_DEVICE_ID_ADAPTEC_1030     0x8b78
 
 #define PCI_VENDOR_ID_ADAPTEC2         0x9005
 #define PCI_DEVICE_ID_ADAPTEC2_2940U2  0x0010
-#define PCI_DEVICE_ID_ADAPTEC2_78902   0x0013
+#define PCI_DEVICE_ID_ADAPTEC2_2930U2  0x0011
+#define PCI_DEVICE_ID_ADAPTEC2_7890B   0x0013
 #define PCI_DEVICE_ID_ADAPTEC2_7890    0x001f
 #define PCI_DEVICE_ID_ADAPTEC2_3940U2  0x0050
 #define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051
 #define PCI_DEVICE_ID_ADAPTEC2_7896    0x005f
+#define PCI_DEVICE_ID_ADAPTEC2_7892A   0x0080
+#define PCI_DEVICE_ID_ADAPTEC2_7892B   0x0081
+#define PCI_DEVICE_ID_ADAPTEC2_7892D   0x0083
+#define PCI_DEVICE_ID_ADAPTEC2_7892P   0x008f
+#define PCI_DEVICE_ID_ADAPTEC2_7899A   0x00c0
+#define PCI_DEVICE_ID_ADAPTEC2_7899B   0x00c1
+#define PCI_DEVICE_ID_ADAPTEC2_7899D   0x00c3
+#define PCI_DEVICE_ID_ADAPTEC2_7899P   0x00cf
 
 #define PCI_VENDOR_ID_ATRONICS         0x907f
 #define PCI_DEVICE_ID_ATRONICS_2015    0x2015
index 69dc86725f5b0c342893873ad410611d89beac5c..70ce90e103a9d5d7f94eb7ecf27268d4d42ec203 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
+ * ==FILEDATE 19990523==
+ *
  * Copyright (C) 1998 by Microgate Corporation
  * 
  * Redistribution of this file is permitted under 
 #define HDLC_FLAG_AUTO_RTS             0x0080
 #define HDLC_FLAG_RXC_DPLL             0x0100
 #define HDLC_FLAG_RXC_BRG              0x0200
+#define HDLC_FLAG_RXC_TXCPIN   0x8000
+#define HDLC_FLAG_RXC_RXCPIN   0x0000
 #define HDLC_FLAG_TXC_DPLL             0x0400
 #define HDLC_FLAG_TXC_BRG              0x0800
+#define HDLC_FLAG_TXC_TXCPIN   0x0000
+#define HDLC_FLAG_TXC_RXCPIN   0x0008
 #define HDLC_FLAG_DPLL_DIV8            0x1000
 #define HDLC_FLAG_DPLL_DIV16           0x2000
 #define HDLC_FLAG_DPLL_DIV32           0x0000
+#define HDLC_FLAG_HDLC_LOOPMODE                0x4000
 
 #define HDLC_CRC_NONE                  0
 #define HDLC_CRC_16_CCITT              1
@@ -87,6 +94,7 @@
 #define HDLC_ENCODING_NRZB                     1
 #define HDLC_ENCODING_NRZI_MARK                        2
 #define HDLC_ENCODING_NRZI_SPACE               3
+#define HDLC_ENCODING_NRZI                     HDLC_ENCODING_NRZI_SPACE
 #define HDLC_ENCODING_BIPHASE_MARK             4
 #define HDLC_ENCODING_BIPHASE_SPACE            5
 #define HDLC_ENCODING_BIPHASE_LEVEL            6
@@ -227,17 +235,19 @@ struct mgsl_icount {
  * MGSL_IOCTXABORT     abort transmitting frame (HDLC)
  * MGSL_IOCGSTATS      return current statistics
  * MGSL_IOCWAITEVENT   wait for specified event to occur
+ * MGSL_LOOPTXDONE     transmit in HDLC LoopMode done
  */
 #define MGSL_MAGIC_IOC 'm'
-#define MGSL_IOCSPARAMS                _IOW(MGSL_MAGIC_IOC,0,sizeof(MGSL_PARAMS))
-#define MGSL_IOCGPARAMS                _IOR(MGSL_MAGIC_IOC,1,sizeof(MGSL_PARAMS))
+#define MGSL_IOCSPARAMS                _IOW(MGSL_MAGIC_IOC,0,struct _MGSL_PARAMS)
+#define MGSL_IOCGPARAMS                _IOR(MGSL_MAGIC_IOC,1,struct _MGSL_PARAMS)
 #define MGSL_IOCSTXIDLE                _IO(MGSL_MAGIC_IOC,2)
 #define MGSL_IOCGTXIDLE                _IO(MGSL_MAGIC_IOC,3)
 #define MGSL_IOCTXENABLE       _IO(MGSL_MAGIC_IOC,4)
 #define MGSL_IOCRXENABLE       _IO(MGSL_MAGIC_IOC,5)
 #define MGSL_IOCTXABORT                _IO(MGSL_MAGIC_IOC,6)
 #define MGSL_IOCGSTATS         _IO(MGSL_MAGIC_IOC,7)
-#define MGSL_IOCWAITEVENT      _IO(MGSL_MAGIC_IOC,8)
+#define MGSL_IOCWAITEVENT      _IOWR(MGSL_MAGIC_IOC,8,int)
 #define MGSL_IOCCLRMODCOUNT    _IO(MGSL_MAGIC_IOC,15)
+#define MGSL_IOCLOOPTXDONE     _IO(MGSL_MAGIC_IOC,9)
 
 #endif /* _SYNCLINK_H_ */
index 64496d67191e7fb7c21e470338d6498fb413194b..82f129fca4c2443bfef4f33b88f54e4d598ba862 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 22:47:12 1998
- * Modified at:   Mon May 10 14:51:06 1999
+ * Modified at:   Sun May 16 13:40:03 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -35,15 +35,15 @@ typedef enum {
        ACTISYS_PLUS_DONGLE,
        GIRBIL_DONGLE,
        LITELINK_DONGLE,
-} DONGLE_T;
+} IRDA_DONGLE;
 
 struct irda_device;
 
 struct dongle {
-       DONGLE_T type;
+       IRDA_DONGLE type;
        void (*open)(struct irda_device *, int type);
        void (*close)(struct irda_device *);
-       void (*reset)( struct irda_device *, int unused);
+       void (*reset)( struct irda_device *);
        void (*change_speed)( struct irda_device *, int baudrate);
        void (*qos_init)( struct irda_device *, struct qos_info *);
 };
index 2319017ccefcbed737754bc6e7d0c68f6f72e957..66d0fbc8bf417a113afedc7510a807759b8af4f9 100644 (file)
@@ -77,9 +77,9 @@ typedef enum {
 
 #define IRCOMM_MAGIC            0x434f4d4d
 #define COMM_INIT_CTRL_PARAM    3          /* length of initial control parameters */
-#define COMM_HEADER             1          /* length of clen field */
-#define COMM_HEADER_SIZE        (TTP_MAX_HEADER+COMM_HEADER)
-#define COMM_DEFAULT_DATA_SIZE  64
+#define COMM_HEADER_SIZE        1          /* length of clen field */
+#define COMM_MAX_HEADER_SIZE    (TTP_MAX_HEADER+COMM_HEADER_SIZE)
+#define COMM_DEFAULT_SDU_SIZE   (64 - COMM_HEADER_SIZE)
 #define IRCOMM_MAX_CONNECTION   1          /* Don't change for now */
 
 
@@ -177,8 +177,8 @@ struct ircomm_cb {
        int null_modem_mode;     /* switch for null modem emulation */
        int ttp_stop;
 
-       int max_txbuff_size;          
-       __u32 max_sdu_size;
+       __u32 tx_max_sdu_size;          
+       __u32 rx_max_sdu_size;
        __u8 max_header_size;
 
        __u32 daddr;        /* Device address of the peer device */ 
index 21b12e4ff4e70441ffd6a2d7f8bb4f9f5a387685..5272633f7bb5538f95d171386697008aacc05c4a 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr 14 12:41:42 1998
- * Modified at:   Mon May 10 15:46:02 1999
+ * Modified at:   Wed May 19 08:44:48 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -124,14 +124,14 @@ struct irda_device {
 
        struct dongle *dongle; /* Dongle driver */
 
-       /* spinlock_t lock; */ /* For serializing operations */
+       spinlock_t lock;       /* For serializing operations */
        
        /* Media busy stuff */
        int media_busy;
        struct timer_list media_busy_timer;
 
        /* Callbacks for driver specific implementation */
-        void (*change_speed)(struct irda_device *driver, int baud);
+        void (*change_speed)(struct irda_device *idev, int baud);
        int  (*is_receiving)(struct irda_device *);    /* receiving? */
        void (*set_dtr_rts)(struct irda_device *idev, int dtr, int rts);
        int  (*raw_write)(struct irda_device *idev, __u8 *buf, int len);
index 131e3f9235a0010c36a5c6fda14518dbed891536..fc343e5c059adfea45bd666db9115fc225053241 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Sun May  9 11:45:33 1999
+ * Modified at:   Mon May 31 13:54:20 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -124,6 +124,9 @@ struct irlan_client_cb {
        int unicast_open;
        int broadcast_open;
 
+       int tx_busy;
+       struct sk_buff_head txq; /* Transmit control queue */
+
        struct timer_list kick_timer;
 };
 
@@ -163,7 +166,7 @@ struct irlan_cb {
        struct device dev;        /* Ethernet device structure*/
        struct enet_statistics stats;
 
-       __u32 saddr;              /* Source devcie address */
+       __u32 saddr;              /* Source device address */
        __u32 daddr;              /* Destination device address */
        int   netdev_registered;
        int   notify_irmanager;
@@ -201,6 +204,8 @@ void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout);
 
 void irlan_open_data_tsap(struct irlan_cb *self);
 
+int irlan_run_ctrl_tx_queue(struct irlan_cb *self);
+
 void irlan_get_provider_info(struct irlan_cb *self);
 void irlan_get_unicast_addr(struct irlan_cb *self);
 void irlan_get_media_char(struct irlan_cb *self);
index 6ad33ee48982e7c86969a19687a0471668cd1e72..376df91ffe66c28aab7a26a75da3872017a9b490 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:36:58 1998
- * Modified at:   Thu Apr 22 14:09:37 1999
+ * Modified at:   Fri May 14 23:29:00 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -32,6 +32,7 @@ int  irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb);
 int  irlan_eth_xmit(struct sk_buff *skb, struct device *dev);
 
 void irlan_eth_flow_indication( void *instance, void *sap, LOCAL_FLOW flow);
+void irlan_eth_send_gratuitous_arp(struct device *dev);
 
 void irlan_eth_set_multicast_list( struct device *dev);
 struct enet_statistics *irlan_eth_get_stats(struct device *dev);
index 81981273b97096255c7e1b6edf264fd015df1a57..0912e0496d70b34a45742e433f50478b0052874d 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug  3 13:49:59 1997
- * Modified at:   Mon May 10 22:12:56 1999
+ * Modified at:   Wed May 19 15:31:16 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>
 
 #define FRAME_MAX_SIZE 2048
 
-void irport_start(int iobase);
-void irport_stop(int iobase);
+void irport_start(struct irda_device *idev, int iobase);
+void irport_stop(struct irda_device *idev, int iobase);
 int  irport_probe(int iobase);
 
 void irport_change_speed(struct irda_device *idev, int speed);
 void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 int  irport_hard_xmit(struct sk_buff *skb, struct device *dev);
+void irport_wait_until_sent(struct irda_device *idev);
 
 #endif
index 1e208ccf460878e533ada0e79e88b656bed105ed..523de0db65415774d19af1dc18dceb4c8b20b30e 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Jun  9 13:26:50 1998
- * Modified at:   Thu Feb 25 20:34:21 1999
+ * Modified at:   Tue May 25 07:54:41 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (C) 1998, Aage Kvalnes <aage@cs.uit.no>
@@ -30,8 +30,6 @@
 #include <linux/types.h>
 #include <asm/spinlock.h>
 
-/* #include <net/irda/irda.h> */
-
 #ifndef QUEUE_H
 #define QUEUE_H
 
index 1fc7d6b0f6ad11a15031636ef2a127606907cb6f..f483be0c1ce8988ac4b927cb62b7ac5283472b72 100644 (file)
@@ -53,6 +53,8 @@ struct irvtd_cb {
        struct sk_buff_head rxbuff; 
        struct ircomm_cb *comm;     /* ircomm instance */
 
+       __u32 tx_max_sdu_size;
+       __u32 max_header_size;
        /* 
         * These members are used for compatibility with usual serial device.
         * See linux/serial.h
@@ -69,7 +71,8 @@ struct irvtd_cb {
        struct wait_queue       *delta_msr_wait;
        struct wait_queue       *tx_wait;
 
-       struct timer_list       timer;
+       struct timer_list       tx_timer;
+       struct timer_list       rx_timer;
 
        long pgrp;
        long session;  
diff --git a/include/net/irda/smc-ircc.h b/include/net/irda/smc-ircc.h
new file mode 100644 (file)
index 0000000..2c5cbf4
--- /dev/null
@@ -0,0 +1,160 @@
+/*********************************************************************
+ *                
+ * Filename:      smc.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Thomas Davis (tadavis@jps.net)
+ *
+ *     Copyright (c) 1998, 1999 Thomas Davis (tadavis@jps.net>
+ *     All Rights Reserved
+ *      
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *  
+ *     I, Thomas Davis, admit no liability nor provide warranty for any
+ *     of this software. This material is provided "AS-IS" and at no charge.
+ *     
+ * Definitions for the SMC IrCC controller.
+ *
+ ********************************************************************/
+
+#ifndef SMC_IRCC_H
+#define SMC_IRCC_H
+
+#define UART_MASTER                    0x07
+#define UART_MASTER_POWERDOWN  1<<7
+#define UART_MASTER_RESET              1<<6
+#define UART_MASTER_INT_EN             1<<5
+#define UART_MASTER_ERROR_RESET        1<<4
+
+/* Register block 0 */
+
+#define UART_IIR       0x01
+#define UART_IER       0x02
+#define UART_LSR       0x03
+#define UART_LCR_A     0x04
+#define UART_LCR_B     0x05
+#define UART_BSR       0x06
+
+#define UART_IIR_ACTIVE_FRAME  1<<7
+#define UART_IIR_EOM           1<<6
+#define UART_IIR_RAW_MODE              1<<5
+#define UART_IIR_FIFO          1<<4
+
+#define UART_IER_ACTIVE_FRAME  1<<7
+#define UART_IER_EOM           1<<6
+#define UART_IER_RAW_MODE              1<<5
+#define UART_IER_FIFO          1<<4
+
+#define UART_LSR_UNDERRUN              1<<7
+#define UART_LSR_OVERRUN               1<<6
+#define UART_LSR_FRAME_ERROR   1<<5
+#define UART_LSR_SIZE_ERROR            1<<4
+#define UART_LSR_CRC_ERROR             1<<3
+#define UART_LSR_FRAME_ABORT   1<<2
+
+#define UART_LCR_A_FIFO_RESET        1<<7
+#define UART_LCR_A_FAST              1<<6
+#define UART_LCR_A_GP_DATA           1<<5
+#define UART_LCR_A_RAW_TX            1<<4
+#define UART_LCR_A_RAW_RX            1<<3
+#define UART_LCR_A_ABORT             1<<2
+#define UART_LCR_A_DATA_DONE         1<<1
+
+#define UART_LCR_B_SCE_DISABLED        0x00<<6
+#define UART_LCR_B_SCE_TRANSMIT        0x01<<6
+#define UART_LCR_B_SCE_RECEIVE         0x02<<6
+#define UART_LCR_B_SCE_UNDEFINED       0x03<<6
+#define UART_LCR_B_SIP_ENABLE          1<<5
+#define UART_LCR_B_BRICK_WALL          1<<4
+
+#define UART_BSR_NOT_EMPTY     1<<7
+#define UART_BSR_FIFO_FULL     1<<6
+#define UART_BSR_TIMEOUT       1<<5
+
+/* Register block 1 */
+
+#define UART_SCE_CFGA  0x00
+#define UART_SCE_CFGB  0x01
+#define UART_FIFO_THRESHOLD    0x02
+
+#define UART_CFGA_AUX_IR               0x01<<7
+#define UART_CFGA_HALF_DUPLEX  0x01<<2
+#define UART_CFGA_TX_POLARITY  0x01<<1
+#define UART_CFGA_RX_POLARITY  0x01
+
+#define UART_CFGA_COM          0x00<<3
+#define UART_CFGA_IRDA_SIR_A   0x01<<3
+#define UART_CFGA_ASK_SIR              0x02<<3
+#define UART_CFGA_IRDA_SIR_B   0x03<<3
+#define UART_CFGA_IRDA_HDLC    0x04<<3
+#define UART_CFGA_IRDA_4PPM    0x05<<3
+#define UART_CFGA_CONSUMER             0x06<<3
+#define UART_CFGA_RAW_IR               0x07<<3
+#define UART_CFGA_OTHER                0x08<<3
+
+#define UART_IR_HDLC                   0x04
+#define UART_IR_4PPM                   0x01
+#define UART_IR_CONSUMER               0x02
+
+#define UART_CFGB_LOOPBACK             0x01<<5
+#define UART_CFGB_LPBCK_TX_CRC 0x01<<4
+#define UART_CFGB_NOWAIT               0x01<<3
+#define UART_CFGB_STRING_MOVE  0x01<<2
+#define UART_CFGB_DMA_BURST    0x01<<1
+#define UART_CFGB_DMA_ENABLE   0x01
+
+#define UART_CFGB_COM          0x00<<6
+#define UART_CFGB_IR           0x01<<6
+#define UART_CFGB_AUX          0x02<<6
+#define UART_CFGB_INACTIVE             0x03<<6
+
+/* Register block 2 - Consumer IR - not used */
+
+/* Register block 3 - Identification Registers! */
+
+#define UART_ID_HIGH   0x00   /* 0x10 */
+#define UART_ID_LOW    0x01   /* 0xB8 */
+#define UART_CHIP_ID   0x02   /* 0xF1 */
+#define UART_VERSION   0x03   /* 0x01 */
+#define UART_INTERFACE 0x04   /* low 4 = DMA, high 4 = IRQ */
+
+/* Register block 4 - IrDA */
+#define UART_CONTROL        0x00
+#define UART_BOF_COUNT_LO      0x01
+#define UART_BRICKWALL_CNT_LO 0x02
+#define UART_BRICKWALL_TX_CNT_HI   0x03
+#define UART_TX_SIZE_LO   0x04
+#define UART_RX_SIZE_HI   0x05
+#define UART_RX_SIZE_LO   0x06
+
+#define UART_1152     0x01<<7
+#define UART_CRC      0x01<<6
+
+/* For storing entries in the status FIFO */
+struct st_fifo_entry {
+       int status;
+       int len;
+};
+
+struct st_fifo {
+       struct st_fifo_entry entries[10];
+       int head;
+       int tail;
+       int len;
+};
+
+/* Private data for each instance */
+struct ircc_cb {
+       struct st_fifo st_fifo;
+
+       int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
+       int tx_len;          /* Number of frames in tx_buff */
+
+       struct irda_device idev;
+};
+
+#endif
diff --git a/include/net/irda/smc_ircc.h b/include/net/irda/smc_ircc.h
deleted file mode 100644 (file)
index 8750618..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-#if 0
-static char *rcsid = "$Id: smc_ircc.h,v 1.5 1998/07/27 01:25:29 ratbert Exp $";
-#endif
-
-#ifndef SMC_IRCC_H
-#define SMC_IRCC_H
-
-#define FIR_XMIT       1
-#define FIR_RECEIVE    2
-#define SIR_XMIT       3
-#define SIR_RECEIVE    4
-
-#define MASTER                 0x07
-#define MASTER_POWERDOWN       1<<7
-#define MASTER_RESET           1<<6
-#define MASTER_INT_EN          1<<5
-#define MASTER_ERROR_RESET     1<<4
-
-/* Register block 0 */
-
-#define IIR    0x01
-#define IER    0x02
-#define LSR    0x03
-#define LCR_A  0x04
-#define LCR_B  0x05
-#define BSR    0x06
-
-#define IIR_ACTIVE_FRAME       1<<7
-#define IIR_EOM                1<<6
-#define IIR_RAW_MODE           1<<5
-#define IIR_FIFO               1<<4
-
-#define IER_ACTIVE_FRAME       1<<7
-#define IER_EOM                1<<6
-#define IER_RAW_MODE           1<<5
-#define IER_FIFO               1<<4
-
-#define LSR_UNDER_RUN          1<<7
-#define LSR_OVER_RUN           1<<6
-#define LSR_FRAME_ERROR        1<<5
-#define LSR_SIZE_ERROR         1<<4
-#define LSR_CRC_ERROR          1<<3
-#define LSR_FRAME_ABORT        1<<2
-
-#define LCR_A_FIFO_RESET        1<<7
-#define LCR_A_FAST              1<<6
-#define LCR_A_GP_DATA           1<<5
-#define LCR_A_RAW_TX            1<<4
-#define LCR_A_RAW_RX            1<<3
-#define LCR_A_ABORT             1<<2
-#define LCR_A_DATA_DONE         1<<1
-
-#define LCR_B_SCE_MODE_DISABLED        0x00<<6
-#define LCR_B_SCE_MODE_TRANSMIT        0x01<<6
-#define LCR_B_SCE_MODE_RECEIVE         0x02<<6
-#define LCR_B_SCE_MODE_UNDEFINED       0x03<<6
-#define LCR_B_SIP_ENABLE               1<<5
-#define LCR_B_BRICK_WALL               1<<4
-
-#define BSR_NOT_EMPTY  1<<7
-#define BSR_FIFO_FULL  1<<6
-#define BSR_TIMEOUT    1<<5
-
-/* Register block 1 */
-
-#define SCE_CFG_A      0x00
-#define SCE_CFG_B      0x01
-#define FIFO_THRESHOLD 0x02
-
-#define CFG_A_AUX_IR           0x01<<7
-#define CFG_A_HALF_DUPLEX      0x01<<2
-#define CFG_A_TX_POLARITY      0x01<<1
-#define CFG_A_RX_POLARITY      0x01
-
-#define CFG_A_COM              0x00<<3
-#define CFG_A_IRDA_SIR_A       0x01<<3
-#define CFG_A_ASK_SIR          0x02<<3
-#define CFG_A_IRDA_SIR_B       0x03<<3
-#define CFG_A_IRDA_HDLC        0x04<<3
-#define CFG_A_IRDA_4PPM        0x05<<3
-#define CFG_A_CONSUMER         0x06<<3
-#define CFG_A_RAW_IR           0x07<<3
-#define CFG_A_OTHER            0x08<<3
-
-#define IR_HDLC                        0x04
-#define IR_4PPM                        0x01
-#define IR_CONSUMER            0x02
-
-#define CFG_B_LOOPBACK         0x01<<5
-#define CFG_B_LPBCK_TX_CRC     0x01<<4
-#define CFG_B_NOWAIT           0x01<<3
-#define CFB_B_STRING_MOVE      0x01<<2
-#define CFG_B_DMA_BURST        0x01<<1
-#define CFG_B_DMA_ENABLE       0x01
-
-#define CFG_B_MUX_COM          0x00<<6
-#define CFG_B_MUX_IR           0x01<<6
-#define CFG_B_MUX_AUX          0x02<<6
-#define CFG_B_INACTIVE         0x03<<6
-
-/* Register block 2 - Consumer IR - not used */
-
-/* Register block 3 - Identification Registers! */
-
-#define SMSC_ID_HIGH   0x00   /* 0x10 */
-#define SMSC_ID_LOW    0x01   /* 0xB8 */
-#define CHIP_ID        0x02   /* 0xF1 */
-#define VERSION_NUMBER 0x03   /* 0x01 */
-#define HOST_INTERFACE 0x04   /* low 4 = DMA, high 4 = IRQ */
-
-/* Register block 4 - IrDA */
-#define IR_CONTROL        0x00
-#define BOF_COUNT_LO      0x01
-#define BRICK_WALL_CNT_LO 0x02
-#define BRICK_TX_CNT_HI   0x03
-#define TX_DATA_SIZE_LO   0x04
-#define RX_DATA_SIZE_HI   0x05
-#define RX_DATA_SIZE_LO   0x06
-
-#define SELECT_1152     0x01<<7
-#define CRC_SELECT      0x01<<6
-
-#endif
index 954e1407ee549635e66eb8260fd2fcc6417cd37e..a9f00e229fddcaff65807dafd3aa428ccc48ebfa 100644 (file)
@@ -14,4 +14,6 @@
 #define SCSICAM_H
 #include <linux/kdev_t.h>
 extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip);
+extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
+           unsigned int  *cyls, unsigned int *hds, unsigned int *secs);
 #endif /* def SCSICAM_H */
index 3e112c659ae6ae81331ccba785198cfbb6ad82c1..8b50bb3da939203f14340869cdaf5ea6107d4995 100644 (file)
@@ -12,10 +12,16 @@ Original driver (sg.h):
 *       Copyright (C) 1998, 1999 Douglas Gilbert
 
 
-    Version: 2.1.32 (990501)
-    This version for later 2.1.x series and 2.2.x kernels
+    Version: 2.1.34 (990603)
+    This version for later 2.1.x and 2.2.x series kernels
     D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
 
+    Changes since 2.1.33 (990521)
+        - implement SG_SET_RESERVED_SIZE and associated memory re-org.
+        - add SG_NEXT_CMD_LEN to override SCSI command lengths
+        - add SG_GET_VERSION_NUM to get version expressed as an integer
+    Changes since 2.1.32 (990501)
+        - fix race condition in sg_read() and sg_open()
     Changes since 2.1.31 (990327)
         - add ioctls SG_GET_UNDERRUN_FLAG and _SET_. Change the default
           to _not_ flag underruns (affects aic7xxx driver)
@@ -25,24 +31,6 @@ Original driver (sg.h):
     Changes since 2.1.30 (990320)
         - memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
         -                increase max allowable mid-level pool usage
-    Changes since 2.1.21 (990315)
-        - skipped to 2.1.30 indicating interface change (revert to 2.1.9)
-        - remove attempt to accomodate cdrecord 1.8, will fix app
-        - keep SG_?ET_RESERVED_SIZE naming for clarity
-    Changes since 2.1.20 (990313)
-        - ommission: left out logic for SG_?ET_ALT_INTERFACE, now added
-    Changes since 2.1.9 (990309)
-        - skipped to version 2.1.20 to indicate some interface changes
-        - incorporate sg changes to make cdrecord 1.8 work (had its
-          own patches that were different from the original)
-        - change SG_?ET_BUFF_SIZE to SG_?ET_RESERVED_SIZE for clarity
-    Changes since 2.1.8 (990303)
-        - debug ">9" option dumps debug for _all_ active sg devices
-        - increase allowable dma pool usage + increase minimum threshhold
-        - pad out sg_scsi_id structure
-    Changes since 2.1.7 (990227)
-        - command queuing now "non-default" [back. compat. with cdparanoia]
-        - Tighten access on some ioctls
 
 
     New features and changes:
@@ -52,24 +40,32 @@ Original driver (sg.h):
         - the SCSI target, host and driver status are returned
           in unused fields of sg_header (maintaining its original size).
         - asynchronous notification support added (SIGPOLL, SIGIO) for
-          read()s ( write()s should never block).
-        - pack_id logic added so read() can be made to wait for a specific
-          pack_id. 
+          read()s (write()s should never block).
+        - pack_id logic added so read() can wait for a specific pack_id. 
         - uses memory > ISA_DMA_THRESHOLD if adapter allows it (e.g. a
           pci scsi adapter).
         - this driver no longer uses a single SG_BIG_BUFF sized buffer
-          obtained at driver/module init time. Rather it obtains a 
-          SG_SCATTER_SZ buffer when a fd is open()ed and frees it at
-          the corresponding release() (ie pr fd). Hence open() can return
-          ENOMEM! If write() request > SG_SCATTER_SZ bytes for data then
-          it can fail with ENOMEM as well (if so, scale back).
+          obtained at driver/module init time. Rather it tries to obtain a 
+          SG_DEF_RESERVED_SIZE buffer when a fd is open()ed and frees it
+          at the corresponding release() (ie per fd). Actually the "buffer"
+          may be a collection of buffers if scatter-gather is being used.
+        - add SG_SET_RESERVED_SIZE ioctl allowing the user to request a
+          large buffer for duration of current file descriptor's lifetime.
+        - SG_GET_RESERVED_SIZE ioctl can be used to find out how much
+          actually has been reserved.
+        - add SG_NEXT_CMD_LEN ioctl to override SCSI command length on
+          the next write() to this file descriptor.
+        - SG_GET_RESERVED_SIZE's presence as a symbol can be used for
+          compile time identification of the version 2 sg driver.
+          However, it is recommended that run time identification based on
+          calling the ioctl of the same name is a more flexible and
+          safer approach.
         - adds several ioctl calls, see ioctl section below.
-        - SG_SCATTER_SZ's presence indicates this version of "sg" driver.
  
  Good documentation on the original "sg" device interface and usage can be
- found in the Linux HOWTO document: "SCSI Programming HOWTO" by Heiko
- Eissfeldt; last updated 7 May 1996. I will add more info on using the
extensions in this driver as required. A quick summary:
+ found in the Linux HOWTO document: "SCSI Programming HOWTO" (version 0.5)
+ by Heiko Eissfeldt; last updated 7 May 1996. Here is a quick summary of
sg basics:
  An SG device is accessed by writing SCSI commands plus any associated 
  outgoing data to it; the resulting status codes and any incoming data
  are then obtained by a read call. The device can be opened O_NONBLOCK
@@ -88,38 +84,37 @@ Original driver (sg.h):
  The given SCSI command has its LUN field overwritten internally by the
  value associated with the device that has been opened.
 
- Memory (RAM) is used within this driver for direct memory access (DMA)
- in transferring data to and from the SCSI device. The dreaded ENOMEM
- seems to be more prevalent under early 2.2.x kernels than under the
- 2.0.x kernel series. For a given (large) transfer the memory obtained by
- this driver must be contiguous or scatter-gather must be used (if
- supported by the adapter). [Furthermore, ISA SCSI adapters can only use
- memory below the 16MB level on a i386.]
- This driver tries hard to find some suitable memory before admitting
- defeat and returning ENOMEM. All is not lost if application writers
- then back off the amount they are requesting. The value returned by
- the SG_GET_RESERVED_SIZE ioctl is guaranteed to be available (one
- per fd). This driver does the following:
-   -  attempts to reserve a SG_SCATTER_SZ sized buffer on open(). The
-      actual amount reserved is given by the SG_GET_RESERVED_SIZE ioctl().
-   -  each write() needs to reserve a DMA buffer of the size of the
-      data buffer indicated (excluding sg_header and command overhead).
-      This buffer, depending on its size, adapter type (ISA or not) and
-      the amount of memory available will be obtained from the kernel
-      directly (get_free_pages or kmalloc) or the from the scsi mid-level
-      dma pool (taking care not to exhaust it).
-      If the buffer requested is > SG_SCATTER_SZ or memory is tight then
-      scatter-gather will be used if supported by the adapter.
-  -   write() will also attempt to use the buffer reserved on open()
-      if it is large enough.
- The above strategy ensures that a write() can always depend on a buffer 
- of the size indicated by the SG_GET_RESERVED_SIZE ioctl() (which could be
- 0, but at least the app knows things are tight in advance).
- Hence application writers can adopt quite aggressive strategies (e.g. 
- requesting 512KB) and scale them back in the face of ENOMEM errors.
- N.B. Queuing up commands also ties up kernel memory.
-
- More documentation can be found at www.torque.net/sg
+ This device currently uses "indirect IO" in the sense that data is
+ DMAed into kernel buffers from the hardware and afterwards is
+ transferred into the user space (or vice versa if you are writing).
+ Transfer speeds or up to 20 to 30MBytes/sec have been measured using
+ indirect IO. For faster throughputs "direct IO" which cuts out the
+ double handling of data is required. This will also need a new interface.
+
+ Grabbing memory for those kernel buffers used in this driver for DMA may
+ cause the dreaded ENOMEM error. This error seems to be more prevalent 
+ under early 2.2.x kernels than under the 2.0.x kernel series. For a given 
+ (large) transfer the memory obtained by this driver must be contiguous or
+ scatter-gather must be used (if supported by the adapter). [Furthermore, 
+ ISA SCSI adapters can only use memory below the 16MB level on a i386.]
+
+ When a "sg" device is open()ed O_RDWR then this driver will attempt to
+ reserve a buffer of SG_DEF_RESERVED_SIZE that will be used by subsequent
+ write()s on this file descriptor as long as:
+    -  it is not already in use (eg when command queuing is in use)
+    -  the write() does not call for a buffer size larger than the
+       reserved size.
+ In these cases the write() will attempt to find the memory it needs for
+ DMA buffers dynamically and in the worst case will fail with ENOMEM.
+ The amount of memory actually reserved depends on various dynamic factors
+ and can be checked with the SG_GET_RESERVED_SIZE ioctl(). [In a very
+ tight memory situation it may yield 0!] The size of the reserved buffer
+ can be changed with the SG_SET_RESERVED_SIZE ioctl(). It should be
+ followed with a call to the SG_GET_RESERVED_SIZE ioctl() to find out how
+ much was actually reserved.
+
+ More documentation plus test and utility programs can be found at 
+ http://www.torque.net/sg
 */
 
 #define SG_MAX_SENSE 16   /* too little, unlikely to change in 2.2.x */
@@ -129,7 +124,7 @@ struct sg_header
     int pack_len;    /* [o] reply_len (ie useless), ignored as input */
     int reply_len;   /* [i] max length of expected reply (inc. sg_header) */
     int pack_id;     /* [io] id number of packet (use ints >= 0) */
-    int result;      /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */
+    int result;      /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
     unsigned int twelve_byte:1; 
         /* [i] Force 12 byte command length for group 6 & 7 commands  */
     unsigned int target_status:5;   /* [o] scsi status from target */
@@ -154,9 +149,9 @@ typedef struct sg_scsi_id {
     int unused3;  
 } Sg_scsi_id;
 
-/* ioctls  ( _GET_s yield result via 'int *' 3rd argument unless 
-            otherwise indicated */
-#define SG_SET_TIMEOUT 0x2201  /* unit: jiffies, 10ms on i386 */
+/* IOCTLs: ( _GET_s yield result via 'int *' 3rd argument unless 
+             otherwise indicated) */
+#define SG_SET_TIMEOUT 0x2201  /* unit: jiffies (10ms on i386) */
 #define SG_GET_TIMEOUT 0x2202  /* yield timeout as _return_ value */
 
 #define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */
@@ -165,23 +160,21 @@ typedef struct sg_scsi_id {
 #define SG_SET_TRANSFORM 0x2204
 #define SG_GET_TRANSFORM 0x2205
 
-#define SG_SET_RESERVED_SIZE 0x2275  /* currently ignored, future addition */
-/* Following yields buffer reserved by open(): 0 <= x <= SG_SCATTER_SZ */
-#define SG_GET_RESERVED_SIZE 0x2272
+#define SG_SET_RESERVED_SIZE 0x2275  /* request a new reserved buffer size */
+#define SG_GET_RESERVED_SIZE 0x2272  /* actual size of reserved buffer */
 
 /* The following ioctl takes a 'Sg_scsi_id *' object as its 3rd argument. */
-#define SG_GET_SCSI_ID 0x2276   /* Yields fd's bus,chan,dev,lun+type */
+#define SG_GET_SCSI_ID 0x2276   /* Yields fd's bus, chan, dev, lun + type */
 /* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */
 
-/* Override adapter setting and always DMA using low memory ( <16MB on i386).
-   Default is 0 (off - use adapter setting) */
+/* Override host setting and always DMA using low memory ( <16MB on i386) */
 #define SG_SET_FORCE_LOW_DMA 0x2279  /* 0-> use adapter setting, 1-> force */
 #define SG_GET_LOW_DMA 0x227a   /* 0-> use all ram for dma; 1-> low dma ram */
 
 /* When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which
    will attempt to read that pack_id or block (or return EAGAIN). If 
    pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0
-   (default) then pack_id ignored by read() and oldest readable fetched. */ 
+   then pack_id ignored by read() and oldest readable fetched. */ 
 #define SG_SET_FORCE_PACK_ID 0x227b
 #define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */
 
@@ -194,43 +187,47 @@ typedef struct sg_scsi_id {
 /* Yields max scatter gather tablesize allowed by current host adapter */
 #define SG_GET_SG_TABLESIZE 0x227F  /* 0 implies can't do scatter gather */
 
-/* Control whether sequencing per file descriptor (default) or per device */
-#define SG_GET_MERGE_FD 0x2274   /* 0-> per fd (default), 1-> per device */
+/* Control whether sequencing per file descriptor or per device */
+#define SG_GET_MERGE_FD 0x2274   /* 0-> per fd, 1-> per device */
 #define SG_SET_MERGE_FD 0x2273   /* Attempt to change sequencing state,
-  if more than 1 fd open on device, will fail with EBUSY */
+  if more than current fd open on device, will fail with EBUSY */
 
 /* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q) */
 #define SG_GET_COMMAND_Q 0x2270   /* Yields 0 (queuing off) or 1 (on) */
 #define SG_SET_COMMAND_Q 0x2271   /* Change queuing state with 0 or 1 */
 
-/* Get/set whether DMA underrun will cause an error (DID_ERROR) [this only
-   currently applies to the [much-used] aic7xxx driver) */
+/* Get/set whether DMA underrun will cause an error (DID_ERROR). This only
+   currently applies to the [much-used] aic7xxx driver. */
 #define SG_GET_UNDERRUN_FLAG 0x2280 /* Yields 0 (don't flag) or 1 (flag) */
 #define SG_SET_UNDERRUN_FLAG 0x2281 /* Change flag underrun state */
 
+#define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
+#define SG_NEXT_CMD_LEN 0x2283  /* override SCSI command length with given
+                   number on the next write() on this file descriptor */
+
+
+#define SG_SCATTER_SZ (8 * 4096)  /* PAGE_SIZE not available to user */
+/* Largest size (in bytes) a single scatter-gather list element can have.
+   The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on 
+   i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
+   by adapter then this value is the largest data block that can be
+   read/written by a single scsi command. The user can find the value of
+   PAGE_SIZE by calling getpagesize() defined in unistd.h . */
 
 #define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
 #define SG_DEFAULT_RETRIES 1
 
-/* Default modes, commented if they differ from original sg driver */
+/* Defaults, commented if they differ from original sg driver */
 #define SG_DEF_COMMAND_Q 0
 #define SG_DEF_MERGE_FD 0       /* was 1 -> per device sequencing */
 #define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
 #define SG_DEF_FORCE_PACK_ID 0
 #define SG_DEF_UNDERRUN_FLAG 0
+#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ
 
 /* maximum outstanding requests, write() yields EDOM if exceeded */
 #define SG_MAX_QUEUE 16
 
-#define SG_SCATTER_SZ (8 * 4096)  /* PAGE_SIZE not available to user */
-/* Largest size (in bytes) a single scatter-gather list element can have.
-   The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on 
-   i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
-   by adapter then this value is the largest data block that can be
-   read/written by a single scsi command. Max number of scatter-gather
-   list elements seems to be limited to 255. */
-
-#define SG_BIG_BUFF SG_SCATTER_SZ       /* for backward compatibility */
-/* #define SG_BIG_BUFF (SG_SCATTER_SZ * 8) */ /* =256KB, if you want */
+#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE    /* for backward compatibility */
 
 #endif
index bf1eb7a6e87ea301892dd009a8d87db51814f13a..d18d9596b461645ee31520b837c2aed7b4a1e455 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/unistd.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 
 #include <asm/uaccess.h>
 
@@ -324,7 +325,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
 
                if (nr_queued_signals < max_queued_signals) {
                        q = (struct signal_queue *)
-                           kmem_cache_alloc(signal_queue_cachep, GFP_KERNEL);
+                           kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
                }
                
                if (q) {
@@ -417,6 +418,7 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
        if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN)
                t->sig->action[sig-1].sa.sa_handler = SIG_DFL;
        sigdelset(&t->blocked, sig);
+       recalc_sigpending(t);
        spin_unlock_irqrestore(&t->sigmask_lock, flags);
 
        return send_sig_info(sig, info, t);
index 2ce90cc58b38826a52b54435862c4167a0655ae7..a70385b910338b406b1235ed7d01b45267e30873 100644 (file)
@@ -900,6 +900,8 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
                return -EINVAL;
        if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
                return -EFAULT;
+       if (new_rlim.rlim_cur < 0 || new_rlim.rlim_max < 0)
+               return -EINVAL;
        old_rlim = current->rlim + resource;
        if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
             (new_rlim.rlim_max > old_rlim->rlim_max)) &&
index 9cdfe35df226ff5efa04dceecf9ea6aa0dd14ae7..588d6c7edf1b053932615fc34f57261bf4afe544 100644 (file)
@@ -622,7 +622,7 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
        
        pte = *page_table;
        new_page = __get_free_page(GFP_USER);
-       /* Did someone else copy this page for us while we slept? */
+       /* Did swap_out() unmapped the protected page while we slept? */
        if (pte_val(*page_table) != pte_val(pte))
                goto end_wp_page;
        if (!pte_present(pte))
@@ -652,36 +652,42 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
                delete_from_swap_cache(page_map);
                /* FallThrough */
        case 1:
-               /* We can release the kernel lock now.. */
-               unlock_kernel();
-
                flush_cache_page(vma, address);
                set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
                flush_tlb_page(vma, address);
 end_wp_page:
+               /*
+                * We can release the kernel lock now.. Now swap_out will see
+                * a dirty page and so won't get confused and flush_tlb_page
+                * won't SMP race. -Andrea
+                */
+               unlock_kernel();
+
                if (new_page)
                        free_page(new_page);
                return 1;
        }
                
-       unlock_kernel();
        if (!new_page)
-               return 0;
+               goto no_new_page;
 
-       if (PageReserved(mem_map + MAP_NR(old_page)))
+       if (PageReserved(page_map))
                ++vma->vm_mm->rss;
        copy_cow_page(old_page,new_page);
        flush_page_to_ram(old_page);
        flush_page_to_ram(new_page);
        flush_cache_page(vma, address);
        set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
-       free_page(old_page);
        flush_tlb_page(vma, address);
+       unlock_kernel();
+       __free_page(page_map);
        return 1;
 
 bad_wp_page:
        printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
        send_sig(SIGKILL, tsk, 1);
+no_new_page:
+       unlock_kernel();
        if (new_page)
                free_page(new_page);
        return 0;
index 42ca4900aeedf3c6dd57df0c1722b53db5645e81..e84b717ea09d4440f9117b0bc775286a942b0e18 100644 (file)
@@ -5,6 +5,7 @@
  *  Swap reorganised 29.12.95, Stephen Tweedie
  */
 
+#include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
@@ -554,7 +555,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
        } else if (S_ISREG(swap_dentry->d_inode->i_mode)) {
                error = -EBUSY;
                for (i = 0 ; i < nr_swapfiles ; i++) {
-                       if (i == type)
+                       if (i == type || !swap_info[i].swap_file)
                                continue;
                        if (swap_dentry->d_inode == swap_info[i].swap_file->d_inode)
                                goto bad_swap;
index a0534b740b7eb16b2e43451e1e3684943f4117cc..e1affe1e46696bc466e569d8377ccb4f7554f681 100644 (file)
@@ -3,7 +3,7 @@
  *     
  *             Alan Cox, <alan@redhat.com>
  *
- *     Version: $Id: icmp.c,v 1.52 1999/03/21 12:04:11 davem Exp $
+ *     Version: $Id: icmp.c,v 1.52.2.1 1999/06/09 01:56:07 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
index 73dc306c4760b04df094a8c09ea5fe01bd63677a..bdd690599a2b1a7f60706dc80657e67bb6c8b049 100644 (file)
@@ -437,7 +437,7 @@ static void dump_packet(const struct iphdr *ip,
 
        for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
                printk(" O=0x%8.8X", *opt++);
-       printk(" %s(#%d)\n", tcpsyn ? "SYN " : /* "PENANCE" */ "", count);
+       printk(" %s(#%d)\n", syn ? "SYN " : /* "PENANCE" */ "", count);
 }
 
 /* function for checking chain labels for user space. */
@@ -532,7 +532,7 @@ ip_fw_domatch(struct ip_fwkernel *f,
        f->counters[slot].bcnt+=ntohs(ip->tot_len);
        f->counters[slot].pcnt++;
        if (f->ipfw.fw_flg & IP_FW_F_PRN) {
-               dump_packet(ip,rif,f,label,src_port,dst_port,count,syn);
+               dump_packet(ip,rif,f,label,src_port,dst_port,count,tcpsyn);
        }
        ip->tos = (ip->tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor;
 
index 63356bdec1f213ba99d835960e6a568d1a420f73..8ceff8acf89d6ed05552eac780aae7a5cc1d48ef 100644 (file)
@@ -9,7 +9,7 @@
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- *     Version: $Id: ipmr.c,v 1.40 1999/03/25 10:04:25 davem Exp $
+ *     Version: $Id: ipmr.c,v 1.40.2.1 1999/06/09 01:56:17 davem Exp $
  *
  *     Fixes:
  *     Michael Chastain        :       Incorrect size of copying.
index 8912d6cb989a406b1c7636e0ab01b0e3ebd95552..92300cb30ef17d8c75b40a04a1563b4c59165105 100644 (file)
@@ -2,34 +2,31 @@
 # IrDA protocol configuration
 #
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  if [ "$CONFIG_NET" != "n" ] ; then
+if [ "$CONFIG_NET" != "n" ] ; then
 
-    mainmenu_option next_comment
-    comment 'IrDA subsystem support'
-    dep_tristate 'IrDA subsystem support' CONFIG_IRDA $CONFIG_EXPERIMENTAL $CONFIG_NET
+  mainmenu_option next_comment
+  comment 'IrDA subsystem support'
+  dep_tristate 'IrDA subsystem support' CONFIG_IRDA $CONFIG_NET
 
-    if [ "$CONFIG_IRDA" != "n" ] ; then
-      comment 'IrDA protocols'
-      source net/irda/irlan/Config.in
-      source net/irda/ircomm/Config.in
-      source net/irda/irlpt/Config.in
+  if [ "$CONFIG_IRDA" != "n" ] ; then
+    comment 'IrDA protocols'
+    source net/irda/irlan/Config.in
+    source net/irda/ircomm/Config.in
+    source net/irda/irlpt/Config.in
 
-      bool 'IrDA protocol options' CONFIG_IRDA_OPTIONS
-      if [ "$CONFIG_IRDA_OPTIONS" != "n" ] ; then
-        comment '   IrDA options'
-        bool '   Cache last LSAP' CONFIG_IRDA_CACHE_LAST_LSAP
-       bool '   Fast RRs' CONFIG_IRDA_FAST_RR
-       bool '   Debug information' CONFIG_IRDA_DEBUG
-      fi
+    bool 'IrDA protocol options' CONFIG_IRDA_OPTIONS
+    if [ "$CONFIG_IRDA_OPTIONS" != "n" ] ; then
+      comment '   IrDA options'
+      bool '   Cache last LSAP' CONFIG_IRDA_CACHE_LAST_LSAP
+      bool '   Fast RRs' CONFIG_IRDA_FAST_RR
+      bool '   Debug information' CONFIG_IRDA_DEBUG
     fi
+  fi
 
-    if [ "$CONFIG_IRDA" != "n" ] ; then
-      source net/irda/compressors/Config.in
-      source drivers/net/irda/Config.in
-    fi
-  endmenu
-
+  if [ "$CONFIG_IRDA" != "n" ] ; then
+    source net/irda/compressors/Config.in
+    source drivers/net/irda/Config.in
   fi
+  endmenu
 fi
 
index 385805ff219b800661753d14f194bdc65f8b8140..c6ffeec868c5fa57d5c29bb889338d1d5a406004 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 31 10:12:43 1998
- * Modified at:   Tue May 11 12:42:26 1999
+ * Modified at:   Wed May 19 16:12:06 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
  * 
@@ -145,7 +145,7 @@ static void irda_connect_confirm(void *instance, void *sap,
        else
                self->max_data_size = max_sdu_size;
 
-       DEBUG(0, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+       DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
 
        memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
 
@@ -189,7 +189,7 @@ static void irda_connect_indication(void *instance, void *sap,
        else
                self->max_data_size = max_sdu_size;
 
-       DEBUG(0, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+       DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
 
        memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
 
@@ -250,12 +250,12 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
        
        switch (flow) {
        case FLOW_STOP:
-               DEBUG( 0, __FUNCTION__ "(), IrTTP wants us to slow down\n");
+               DEBUG(1, __FUNCTION__ "(), IrTTP wants us to slow down\n");
                self->tx_flow = flow;
                break;
        case FLOW_START:
                self->tx_flow = flow;
-               DEBUG(0, __FUNCTION__ "(), IrTTP wants us to start again\n");
+               DEBUG(1, __FUNCTION__ "(), IrTTP wants us to start again\n");
                wake_up_interruptible(sk->sleep);
                break;
        default:
@@ -703,7 +703,11 @@ static int irda_create(struct socket *sock, int protocol)
 
        sock_init_data(sock, sk);
 
-       sock->ops    = &irda_stream_ops;
+       if (sock->type == SOCK_STREAM)
+               sock->ops = &irda_stream_ops;
+       else
+               sock->ops = &irda_dgram_ops;
+
        sk->protocol = protocol;
 
        /* Register as a client with IrLMP */
@@ -1123,7 +1127,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
 
-       DEBUG(0, __FUNCTION__ "(), cmd=%#x\n", cmd);
+       DEBUG(4, __FUNCTION__ "(), cmd=%#x\n", cmd);
        
        switch (cmd) {
        case TIOCOUTQ: {
@@ -1170,7 +1174,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                return -EINVAL;
                
        default:
-               DEBUG(0, __FUNCTION__ "(), doing device ioctl!\n");
+               DEBUG(1, __FUNCTION__ "(), doing device ioctl!\n");
                return dev_ioctl(cmd, (void *) arg);
        }
 
index 41fc4d20a5e80ef3b674c96de4a5fd41e38f1a97..05000ea198e49ad4c1c9ad82a332ccb9e45fcb06 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr  6 15:33:50 1999
- * Modified at:   Sun May  9 22:40:43 1999
+ * Modified at:   Fri May 28 20:46:38 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -224,10 +224,12 @@ int discovery_proc_read(char *buf, char **start, off_t offset, int len,
        
        discovery = (discovery_t *) hashbin_get_first(cachelog);
        while ( discovery != NULL) {
-               len += sprintf( buf+len, "  name: %s,", 
-                               discovery->info);
+               len += sprintf(buf+len, "name: %s,", discovery->info);
                
-               len += sprintf( buf+len, " hint: ");
+               len += sprintf(buf+len, " hint: 0x%02x%02x", 
+                              discovery->hints.byte[0], 
+                              discovery->hints.byte[1]);
+#if 0
                if ( discovery->hints.byte[0] & HINT_PNP)
                        len += sprintf( buf+len, "PnP Compatible ");
                if ( discovery->hints.byte[0] & HINT_PDA)
@@ -251,14 +253,14 @@ int discovery_proc_read(char *buf, char **start, off_t offset, int len,
                        len += sprintf( buf+len, "IrCOMM ");
                if ( discovery->hints.byte[1] & HINT_OBEX)
                        len += sprintf( buf+len, "IrOBEX ");
-               
+#endif         
                len += sprintf(buf+len, ", saddr: 0x%08x", 
                               discovery->saddr);
 
                len += sprintf(buf+len, ", daddr: 0x%08x\n", 
                               discovery->daddr);
                
-               len += sprintf( buf+len, "\n");
+               len += sprintf(buf+len, "\n");
                
                discovery = (discovery_t *) hashbin_get_next(cachelog);
        }
index 97fc3cf279d266bd4d47d0e903ca3e9eaa4b33d3..5300f5f3c462e3e699b9e51dd5176404f6971aa0 100644 (file)
@@ -41,7 +41,7 @@
 
 #include <net/irda/ircomm_common.h>
 
-static char *revision_date = "Sun Apr 18 00:40:19 1999";
+static char *revision_date = "Tue May 18 03:11:39 1999";
 
 
 static void ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, 
@@ -205,15 +205,17 @@ __initfunc(int ircomm_init(void))
                ircomm[i]->enq_char = 0x05;
                ircomm[i]->ack_char = 0x06;  
 
-               ircomm[i]->max_txbuff_size = COMM_DEFAULT_DATA_SIZE;   /* 64 */
-               ircomm[i]->max_sdu_size = SAR_DISABLE;  
-               ircomm[i]->ctrl_skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+               ircomm[i]->max_header_size = COMM_MAX_HEADER_SIZE;
+               ircomm[i]->tx_max_sdu_size = COMM_DEFAULT_SDU_SIZE;
+               ircomm[i]->rx_max_sdu_size = SAR_DISABLE;  
+               ircomm[i]->ctrl_skb = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE
+                                                   + COMM_MAX_HEADER_SIZE);
                if (ircomm[i]->ctrl_skb == NULL){
                        DEBUG(0,"ircomm:init_module:alloc_skb failed!\n");
                        return -ENOMEM;
                }
 
-               skb_reserve(ircomm[i]->ctrl_skb,COMM_HEADER_SIZE);
+               skb_reserve(ircomm[i]->ctrl_skb,COMM_MAX_HEADER_SIZE);
 
        }
 
@@ -302,14 +304,16 @@ static void ircomm_accept_connect_confirm(void *instance, void *sap,
        DEBUG(0,__FUNCTION__"(): got connected!\n");
 
        if (max_sdu_size == SAR_DISABLE)
-               self->max_txbuff_size = qos->data_size.value - max_header_size;
+               self->tx_max_sdu_size =(qos->data_size.value - max_header_size
+                                       - COMM_HEADER_SIZE);
        else {
-               ASSERT(max_sdu_size >= COMM_DEFAULT_DATA_SIZE, return;);
-               self->max_txbuff_size = max_sdu_size; /* use fragmentation */
+               ASSERT(max_sdu_size >= COMM_DEFAULT_SDU_SIZE, return;);
+               /* use fragmentation */
+               self->tx_max_sdu_size = max_sdu_size - COMM_HEADER_SIZE;
        }
 
        self->qos = qos;
-       self->max_header_size = max_header_size;
+       self->max_header_size = max_header_size + COMM_HEADER_SIZE;
        self->null_modem_mode = 0;         /* disable null modem emulation */
 
        ircomm_do_event(self, TTP_CONNECT_CONFIRM, skb);
@@ -331,12 +335,13 @@ static void ircomm_accept_connect_indication(void *instance, void *sap,
        DEBUG(0,__FUNCTION__"()\n");
 
        if (max_sdu_size == SAR_DISABLE)
-               self->max_txbuff_size = qos->data_size.value - max_header_size;
+               self->tx_max_sdu_size =(qos->data_size.value - max_header_size
+                                       - COMM_HEADER_SIZE);
        else
-               self->max_txbuff_size = max_sdu_size;
+               self->tx_max_sdu_size = max_sdu_size - COMM_HEADER_SIZE;
 
        self->qos = qos;
-       self->max_header_size = max_header_size;
+       self->max_header_size = max_header_size + COMM_HEADER_SIZE;
 
        ircomm_do_event( self, TTP_CONNECT_INDICATION, skb);
 
@@ -558,7 +563,7 @@ static void issue_connect_request(struct ircomm_cb *self,
 
                irttp_connect_request(self->tsap, self->dlsap, 
                                      self->saddr, self->daddr, 
-                                     NULL, self->max_sdu_size, userdata); 
+                                     NULL, self->rx_max_sdu_size, userdata); 
                break;
 
        default:
@@ -592,7 +597,8 @@ static void connect_indication(struct ircomm_cb *self, struct qos_info *qos,
 
        if (self->notify.connect_indication)
                self->notify.connect_indication(self->notify.instance, self, 
-                                               qos, 0, 0, skb);
+                                               qos, self->tx_max_sdu_size,
+                                               self->max_header_size, skb);
 }
     
 #if 0
@@ -611,7 +617,8 @@ static void connect_confirm(struct ircomm_cb *self, struct sk_buff *skb)
        /* give a connect_confirm to the client */
        if( self->notify.connect_confirm )
                self->notify.connect_confirm(self->notify.instance,
-                                            self, NULL, SAR_DISABLE, 0, skb);
+                                            self, NULL, self->tx_max_sdu_size,
+                                            self->max_header_size, skb);
 }
 
 static void issue_connect_response(struct ircomm_cb *self,
@@ -623,7 +630,7 @@ static void issue_connect_response(struct ircomm_cb *self,
                DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented yet\n");
                /* irlmp_connect_rsp(); */
        } else
-               irttp_connect_response(self->tsap, self->max_sdu_size, skb);
+               irttp_connect_response(self->tsap, self->rx_max_sdu_size, skb);
 }
 
 static void issue_disconnect_request(struct ircomm_cb *self,
@@ -1054,7 +1061,7 @@ static void start_discovering(struct ircomm_cb *self)
 
        hints = irlmp_service_to_hint(S_COMM);
 
-       DEBUG(0,__FUNCTION__"():start discovering..\n");
+       DEBUG(1,__FUNCTION__"():start discovering..\n");
        switch (ircomm_cs) {
        case 0:
                MOD_INC_USE_COUNT;
@@ -1155,12 +1162,12 @@ void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype)
        ASSERT( self->magic == IRCOMM_MAGIC, return;);
 
 
-       DEBUG(0, __FUNCTION__"():sending connect_request...\n");
+       DEBUG(1, __FUNCTION__"():sending connect_request...\n");
 
        self->servicetype= servicetype;
        /* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
 
-       self->max_sdu_size = SAR_DISABLE;
+       self->rx_max_sdu_size = SAR_DISABLE;
        ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, NULL);
 }
 
@@ -1181,20 +1188,18 @@ void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
 
        if (!userdata){
                /* FIXME: check for errors and initialize? DB */
-               userdata = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+               userdata = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
                if (userdata == NULL)
                        return;
 
-               skb_reserve(userdata,COMM_HEADER_SIZE);
+               skb_reserve(userdata,COMM_MAX_HEADER_SIZE);
        }
 
        /* enable null-modem emulation (i.e. server mode )*/
        self->null_modem_mode = 1;
 
-       self->max_sdu_size = max_sdu_size;
-       if (max_sdu_size != SAR_DISABLE)
-               self->max_txbuff_size = max_sdu_size;
-
+       self->rx_max_sdu_size = max_sdu_size;
+       
        ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata);
 }      
 
@@ -1307,10 +1312,10 @@ static void ircomm_tx_controlchannel(struct ircomm_cb *self )
        ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb);
        self->control_ch_pending = 0;
 
-       skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+       skb = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
        ASSERT(skb != NULL, return ;);
 
-       skb_reserve(skb,COMM_HEADER_SIZE);
+       skb_reserve(skb,COMM_MAX_HEADER_SIZE);
        self->ctrl_skb = skb;
 }
 
index 356913ff4cf84c982d746c927f02111cc1ef8bb5..26a2b3aaabe0d0622939814511e20cfe3d48e28f 100644 (file)
@@ -51,7 +51,7 @@ struct termios *irvtd_termios_locked[COMM_MAX_TTY];
 static int irvtd_refcount;
 struct irvtd_cb **irvtd = NULL;
 
-static char *revision_date = "Sun Apr 18 17:31:53 1999";
+static char *revision_date = "Wed May 26 00:49:11 1999";
 
 
 /*
@@ -83,8 +83,10 @@ static void irvtd_break(struct tty_struct *tty, int break_state);
 static void irvtd_send_xchar(struct tty_struct *tty, char ch);
 static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout);
 
-static void irvtd_start_timer( struct irvtd_cb *driver);
-static void irvtd_timer_expired(unsigned long data);
+static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout);
+static void irvtd_tx_timer_expired(unsigned long data);
+static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout);
+static void irvtd_rx_timer_expired(unsigned long data);
 
 static int line_info(char *buf, struct irvtd_cb *driver);
 static int irvtd_read_proc(char *buf, char **start, off_t offset, int len,
@@ -118,7 +120,7 @@ static void irvtd_write_to_tty( struct irvtd_cb *driver)
        if(driver->rx_disable)
                return;
 
-       skb = skb_dequeue(&driver->rxbuff);
+       skb = skb_dequeue(&driver->rxbuff);
        if(skb == NULL)
                return; /* there's nothing */
 
@@ -211,8 +213,13 @@ static void irvtd_write_to_tty( struct irvtd_cb *driver)
        
        if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW &&
           driver->ttp_stoprx){
-               irttp_flow_request(driver->comm->tsap, FLOW_START);
+               DEBUG(1, __FUNCTION__"():FLOW_START\n");
+               /* 
+                * next 2 lines must follow this order since irttp_flow_request()
+                * will run its rx queue
+                */
                driver->ttp_stoprx = 0;
+               irttp_flow_request(driver->comm->tsap, FLOW_START);
        }
 
        if(skb_queue_empty(&driver->rxbuff) && driver->disconnect_pend){
@@ -236,10 +243,14 @@ static int irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb)
        skb_queue_tail( &driver->rxbuff, skb );
 
        if(skb_queue_len(&driver->rxbuff) > IRVTD_RX_QUEUE_HIGH){
+               DEBUG(1, __FUNCTION__"():FLOW_STOP\n");
                irttp_flow_request(driver->comm->tsap, FLOW_STOP);
                driver->ttp_stoprx = 1;
        }
        irvtd_write_to_tty(driver);
+
+       if(!skb_queue_empty(&driver->rxbuff))
+               irvtd_start_rx_timer(driver,0);
        return 0;
 }
 
@@ -255,22 +266,36 @@ static int irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb)
  */
 
 
-static void irvtd_start_timer( struct irvtd_cb *driver)
+static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout)
+{
+       ASSERT( driver != NULL, return;);
+       ASSERT( driver->magic == IRVTD_MAGIC, return;);
+
+       del_timer( &driver->tx_timer);
+       
+       driver->tx_timer.data     = (unsigned long) driver;
+       driver->tx_timer.function = &irvtd_tx_timer_expired;
+       driver->tx_timer.expires  = jiffies + timeout;
+       
+       add_timer( &driver->tx_timer);
+}
+
+static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout)
 {
        ASSERT( driver != NULL, return;);
        ASSERT( driver->magic == IRVTD_MAGIC, return;);
 
-       del_timer( &driver->timer);
+       del_timer( &driver->rx_timer);
        
-       driver->timer.data     = (unsigned long) driver;
-       driver->timer.function = &irvtd_timer_expired;
-       driver->timer.expires  = jiffies + (HZ / 5);  /* 200msec */
+       driver->rx_timer.data     = (unsigned long) driver;
+       driver->rx_timer.function = &irvtd_rx_timer_expired;
+       driver->rx_timer.expires  = jiffies + timeout;
        
-       add_timer( &driver->timer);
+       add_timer( &driver->rx_timer);
 }
 
 
-static void irvtd_timer_expired(unsigned long data)
+static void irvtd_tx_timer_expired(unsigned long data)
 {
        struct irvtd_cb *driver = (struct irvtd_cb *)data;
 
@@ -279,11 +304,26 @@ static void irvtd_timer_expired(unsigned long data)
        DEBUG(4, __FUNCTION__"()\n");
 
        irvtd_send_data_request(driver);
+}
 
-       irvtd_write_to_tty(driver);
+static void irvtd_rx_timer_expired(unsigned long data)
+{
+       struct irvtd_cb *driver = (struct irvtd_cb *)data;
 
-       /* start our timer again and again */
-       irvtd_start_timer(driver);
+       ASSERT(driver != NULL,return;);
+       ASSERT(driver->magic == IRVTD_MAGIC,return;);
+       DEBUG(4, __FUNCTION__"()\n");
+
+       while(TTY_FLIPBUF_SIZE - driver->tty->flip.count
+             && !skb_queue_empty(&driver->rxbuff))
+               irvtd_write_to_tty(driver);
+
+       DEBUG(1, __FUNCTION__"(): room in flip_buffer = %d\n",
+             TTY_FLIPBUF_SIZE - driver->tty->flip.count);
+       
+       if(!skb_queue_empty(&driver->rxbuff))
+               /* handle it later */
+               irvtd_start_rx_timer(driver, 1);
 }
 
 
@@ -310,21 +350,23 @@ static void irvtd_send_data_request(struct irvtd_cb *driver)
        }
 #endif
 
-       DEBUG(1, __FUNCTION__"():sending %d octets\n",(int)skb->len );
+       DEBUG(1, __FUNCTION__"():len = %d, room = %d\n",(int)skb->len,
+             skb_tailroom(skb));
        driver->icount.tx += skb->len;
        err = ircomm_data_request(driver->comm, driver->txbuff);
        if (err){
                ASSERT(err == 0,;);
-               DEBUG(0,"%d chars are lost\n",(int)skb->len);
+               DEBUG(1,"%d chars are lost\n",(int)skb->len);
                skb_trim(skb, 0);
        }
 
        /* allocate a new frame */
-       skb = driver->txbuff = dev_alloc_skb(driver->comm->max_txbuff_size);
+       skb = driver->txbuff 
+               = dev_alloc_skb(driver->tx_max_sdu_size + driver->max_header_size);
        if (skb == NULL){
                printk(__FUNCTION__"():alloc_skb failed!\n");
        } else {
-               skb_reserve(skb, COMM_HEADER_SIZE);
+               skb_reserve(skb, driver->max_header_size);
        }
 
        wake_up_interruptible(&driver->tty->write_wait);
@@ -355,6 +397,9 @@ void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
        ASSERT(driver != NULL, return;);
        ASSERT(driver->magic == IRVTD_MAGIC, return;);
 
+
+       driver->tx_max_sdu_size = max_sdu_size;
+       driver->max_header_size = max_header_size;
        /*
         * set default value
         */
@@ -408,6 +453,8 @@ void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
        ASSERT(comm != NULL, return;);
        ASSERT(comm->magic == IRCOMM_MAGIC, return;);
 
+       driver->tx_max_sdu_size = max_sdu_size;
+       driver->max_header_size = max_header_size;
        DEBUG(4, __FUNCTION__ "():sending connect_response...\n");
 
        ircomm_connect_response(comm, NULL, SAR_DISABLE );
@@ -481,11 +528,12 @@ void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd)
        if(cmd == TX_READY){
                driver->ttp_stoptx = 0;
                driver->tty->hw_stopped = driver->cts_stoptx;
-               irvtd_start_timer( driver);
 
                if(driver->cts_stoptx)
                        return;
 
+               /* push tx queue so that client can send at least 1 octet */
+               irvtd_send_data_request(driver);
                /* 
                 * driver->tty->write_wait will keep asleep if
                 * our txbuff is full.
@@ -500,7 +548,7 @@ void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd)
 
        if(cmd == TX_BUSY){
                driver->ttp_stoptx = driver->tty->hw_stopped = 1;
-               del_timer( &driver->timer);
+               del_timer( &driver->tx_timer);
                return;
        }
 
@@ -681,7 +729,7 @@ static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp,
 
        driver->blocked_open--;
 
-       DEBUG(0, __FUNCTION__"():after blocking\n");
+       DEBUG(1, __FUNCTION__"():after blocking\n");
 
        if (retval)
                return retval;
@@ -768,7 +816,7 @@ static int irvtd_startup(struct irvtd_cb *driver)
        struct notify_t irvtd_notify;
 
        /* FIXME: it should not be hard coded */
-       __u8 oct_seq[6] = { 0,1,4,1,1,1 }; 
+       __u8 oct_seq[6] = { 0,1,6,1,1,1 }; 
 
        DEBUG(4,__FUNCTION__"()\n" );
        if(driver->flags & ASYNC_INITIALIZED)
@@ -779,12 +827,12 @@ static int irvtd_startup(struct irvtd_cb *driver)
         */
 
        skb_queue_head_init(&driver->rxbuff);
-       driver->txbuff = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE); 
+       driver->txbuff = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE); 
        if (!driver->txbuff){
                DEBUG(0,__FUNCTION__"(), alloc_skb failed!\n");
                return -ENOMEM;
        }
-       skb_reserve(driver->txbuff, COMM_HEADER_SIZE);
+       skb_reserve(driver->txbuff, COMM_MAX_HEADER_SIZE);
 
        irda_notify_init(&irvtd_notify);
        irvtd_notify.data_indication = irvtd_receive_data;
@@ -813,22 +861,20 @@ static int irvtd_startup(struct irvtd_cb *driver)
 
        driver->flags |= ASYNC_INITIALIZED;
 
-       /*
-        * discover a peer device
-        *         TODO: other servicetype(i.e. 3wire,3wireraw) support
-        */
-       ircomm_connect_request(driver->comm, NINE_WIRE);
-       
-       /*
-        * TODO:we have to initialize control-channel here!
-        *   i.e.set something into RTS,CTS and so on....
-        */
-
        if (driver->tty)
                clear_bit(TTY_IO_ERROR, &driver->tty->flags);
 
        change_speed(driver);
-       irvtd_start_timer( driver);
+
+       /*
+        * discover a peer device
+        */
+       if(driver->tty->termios->c_cflag & CRTSCTS)
+         ircomm_connect_request(driver->comm, NINE_WIRE);
+       else
+         ircomm_connect_request(driver->comm, THREE_WIRE);
+
+       /* irvtd_start_timer( driver); */
 
        driver->rx_disable = 0;
        driver->tx_disable = 1;
@@ -991,7 +1037,8 @@ static void irvtd_shutdown(struct irvtd_cb * driver)
        if (driver->tty)
                set_bit(TTY_IO_ERROR, &driver->tty->flags);
        
-       del_timer( &driver->timer);
+       del_timer( &driver->tx_timer);
+       del_timer( &driver->rx_timer);
 
        irias_delete_object("IrDA:IrCOMM");
 
@@ -1146,13 +1193,21 @@ int irvtd_write(struct tty_struct * tty, int from_user,
        DEBUG(4, __FUNCTION__"()\n");
 
        save_flags(flags);
-       while(1){
+       while(count > 0){
                cli();
                skb = driver->txbuff;
                ASSERT(skb != NULL, break;);
                c = MIN(count, (skb_tailroom(skb)));
                if (c <= 0)
-                       break;
+               {
+                       if(!driver->ttp_stoptx)
+                       {
+                               irvtd_send_data_request(driver);
+                               continue;
+                       }
+                       else
+                               break;
+               }
 
                /* write to the frame */
 
@@ -1166,9 +1221,9 @@ int irvtd_write(struct tty_struct * tty, int from_user,
                wrote += c;
                count -= c;
                buf += c;
-               irvtd_send_data_request(driver);
        }
        restore_flags(flags);
+       irvtd_send_data_request(driver);
        return (wrote);
 }
 
@@ -1201,19 +1256,27 @@ void irvtd_put_char(struct tty_struct *tty, unsigned char ch)
        DEBUG(4, __FUNCTION__"()\n");
 
 
+ again:
        save_flags(flags);cli();
        skb = driver->txbuff;
        ASSERT(skb != NULL,return;);
+       if(!skb_tailroom(skb))
+       {
+               restore_flags(flags);
+               irvtd_send_data_request(driver);
+               goto again;
+       }
        ASSERT(skb_tailroom(skb) > 0, return;);
-       DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) MAX(%d):\n",
+       DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) room(%d):\n",
              (int)ch ,(int)skb->len,
-             driver->comm->max_txbuff_size - COMM_HEADER_SIZE);
+             skb_tailroom(skb));
 
        /* append a character  */
        frame = skb_put(skb,1);
        frame[0] = ch;
 
        restore_flags(flags);
+       irvtd_start_tx_timer(driver,20);
        return;
 }
 
@@ -1637,6 +1700,7 @@ void irvtd_throttle(struct tty_struct *tty){
        driver->comm->dte = driver->mcr;
        ircomm_control_request(driver->comm, DTELINE_STATE );
 
+       DEBUG(1, __FUNCTION__"():FLOW_STOP\n");
         irttp_flow_request(driver->comm->tsap, FLOW_STOP);
 }
 
@@ -1651,6 +1715,7 @@ void irvtd_unthrottle(struct tty_struct *tty){
        driver->comm->dte = driver->mcr;
        ircomm_control_request(driver->comm, DTELINE_STATE );
 
+       DEBUG(1, __FUNCTION__"():FLOW_START\n");
         irttp_flow_request(driver->comm->tsap, FLOW_START);
 }
 
@@ -1861,6 +1926,12 @@ static int line_info(char *buf, struct irvtd_cb *driver)
        if (driver->msr & MSR_RI) 
                ret += sprintf(buf+ret, "|RI");
 
+       ret += sprintf(buf+ret, "\n");
+       ret += sprintf(buf+ret, "rx queue:%d",
+                      skb_queue_len( &driver->rxbuff));
+       ret += sprintf(buf+ret, "ttp_stoprx:%s",
+                      driver->ttp_stoprx?"TRUE":"FALSE");
+
  exit:
        ret += sprintf(buf+ret, "\n");
        return ret;
index d6452769fa7b581c2e155b6ea2b40cf0602b7a7d..08ce2adced8899bf7e6240419176e30168a45593 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Sep  2 20:22:08 1998
- * Modified at:   Mon May 10 23:02:47 1999
+ * Modified at:   Tue Jun  1 09:05:13 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -102,6 +102,12 @@ __initfunc(int irda_device_init( void))
 #ifdef CONFIG_NSC_FIR
        pc87108_init();
 #endif
+#ifdef CONFIG_TOSHIBA_FIR
+       toshoboe_init();
+#endif
+#ifdef CONFIG_SMC_IRCC_FIR
+       ircc_init();
+#endif
 #ifdef CONFIG_ESI_DONGLE
        esi_init();
 #endif
@@ -114,6 +120,10 @@ __initfunc(int irda_device_init( void))
 #ifdef CONFIG_GIRBIL_DONGLE
        girbil_init();
 #endif
+#ifdef CONFIG_GIRBIL_DONGLE
+       litelink_init();
+#endif
+
        return 0;
 }
 
@@ -166,6 +176,8 @@ int irda_device_open(struct irda_device *self, char *name, void *priv)
        /* Initialize timers */
        init_timer(&self->media_busy_timer);    
 
+       self->lock = SPIN_LOCK_UNLOCKED;
+
        /* A pointer to the low level implementation */
        self->priv = priv;
 
@@ -197,7 +209,7 @@ int irda_device_open(struct irda_device *self, char *name, void *priv)
        /* Open network device */
        dev_open(&self->netdev);
 
-       MESSAGE("IrDA: Registred device %s\n", self->name);
+       MESSAGE("IrDA: Registered device %s\n", self->name);
 
        irda_device_set_media_busy(self, FALSE);
 
@@ -304,6 +316,8 @@ void irda_device_set_media_busy(struct irda_device *self, int status)
  */
 static void __irda_device_change_speed(struct irda_device *self, int speed)
 {
+       int n = 0;
+
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
        
@@ -311,22 +325,37 @@ static void __irda_device_change_speed(struct irda_device *self, int speed)
         *  Is is possible to change speed yet? Wait until the last byte 
         *  has been transmitted.
         */
-       if (self->wait_until_sent) {
-               self->wait_until_sent(self);
-               
-               if (self->dongle)
-                       self->dongle->change_speed(self, speed);
-               
-               if (self->change_speed) {
-                       self->change_speed(self, speed);
-                       
-                       /* Update the QoS value only */
-                       self->qos.baud_rate.value = speed;
+       if (!self->wait_until_sent) {
+               ERROR("IrDA: wait_until_sent() "
+                     "has not implemented by the IrDA device driver!\n");
+               return;
+       }
+
+       /* Make sure all transmitted data has actually been sent */
+       self->wait_until_sent(self);
+
+       /* Make sure nobody tries to transmit during the speed change */
+       while (irda_lock((void *) &self->netdev.tbusy) == FALSE) {
+               WARNING(__FUNCTION__ "(), device locked!\n");
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(MSECS_TO_JIFFIES(10));
+
+               if (n++ > 10) {
+                       WARNING(__FUNCTION__ "(), breaking loop!\n");
+                       break;
                }
-       } else {
-               WARNING("IrDA: wait_until_sent() "
-                       "has not implemented by the IrDA device driver!\n");
        }
+       
+       if (self->dongle)
+               self->dongle->change_speed(self, speed);
+       
+       if (self->change_speed) {
+               self->change_speed(self, speed);
+               
+               /* Update the QoS value only */
+               self->qos.baud_rate.value = speed;
+       }
+       self->netdev.tbusy = FALSE;
 }
 
 /*
@@ -337,8 +366,6 @@ static void __irda_device_change_speed(struct irda_device *self, int speed)
  */
 inline void irda_device_change_speed(struct irda_device *self, int speed)
 {
-       DEBUG(4, __FUNCTION__ "()\n");
-
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
 
@@ -349,27 +376,27 @@ inline void irda_device_change_speed(struct irda_device *self, int speed)
 
 inline int irda_device_is_media_busy( struct irda_device *self)
 {
-       ASSERT( self != NULL, return FALSE;);
-       ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+       ASSERT(self != NULL, return FALSE;);
+       ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
        
        return self->media_busy;
 }
 
 inline int irda_device_is_receiving( struct irda_device *self)
 {
-       ASSERT( self != NULL, return FALSE;);
-       ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+       ASSERT(self != NULL, return FALSE;);
+       ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
 
-       if ( self->is_receiving)
-               return self->is_receiving( self);
+       if (self->is_receiving)
+               return self->is_receiving(self);
        else
                return FALSE;
 }
 
-inline struct qos_info *irda_device_get_qos( struct irda_device *self)
+inline struct qos_info *irda_device_get_qos(struct irda_device *self)
 {
-       ASSERT( self != NULL, return NULL;);
-       ASSERT( self->magic == IRDA_DEVICE_MAGIC, return NULL;);
+       ASSERT(self != NULL, return NULL;);
+       ASSERT(self->magic == IRDA_DEVICE_MAGIC, return NULL;);
 
        return &self->qos;
 }
@@ -391,8 +418,6 @@ int irda_device_setup(struct device *dev)
 {
        struct irda_device *self;
 
-       DEBUG(4, __FUNCTION__ "()\n");
-
        ASSERT(dev != NULL, return -1;);
 
        self = (struct irda_device *) dev->priv;
@@ -464,6 +489,8 @@ static int irda_device_net_change_mtu( struct device *dev, int new_mtu)
      return 0;  
 }
 
+
+#define SIOCSDONGLE     SIOCDEVPRIVATE
 static int irda_device_net_ioctl(struct device *dev, /* ioctl device */
                                 struct ifreq *rq,   /* Data passed */
                                 int    cmd)         /* Ioctl number */
@@ -574,6 +601,10 @@ static int irda_device_net_ioctl(struct device *dev, /* ioctl device */
 #endif 
                break;
 #endif
+       case SIOCSDONGLE: /* Set dongle */
+               /* Initialize dongle */
+               irda_device_init_dongle(self, (int) rq->ifr_data);
+               break;
        default:
                ret = -EOPNOTSUPP;
        }
@@ -649,6 +680,11 @@ void irda_device_init_dongle(struct irda_device *self, int type)
                ERROR("IrDA: Unable to find requested dongle\n");
                return;
        }
+       
+       /* Check if we're already using a dongle */
+       if (self->dongle) {
+               self->dongle->close(self);
+       }
 
        /* Set the dongle to be used by this driver */
        self->dongle = node->dongle;
@@ -658,7 +694,7 @@ void irda_device_init_dongle(struct irda_device *self, int type)
        node->dongle->qos_init(self, &self->qos);
        
        /* Reset dongle */
-       node->dongle->reset(self, 0);
+       node->dongle->reset(self);
 
        /* Set to default baudrate */
        irda_device_change_speed(self, 9600);
index 66b94eec8092e251ff0e68e52cb15bb77fd47624..e231a08d47f7034e84cd4c84ef36a4731f252ed5 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Tue May 11 00:22:39 1999
+ * Modified at:   Mon May 31 14:19:34 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
@@ -213,7 +213,7 @@ static int irlan_client_ctrl_data_indication(void *instance, void *sap,
 {
        struct irlan_cb *self;
        
-       DEBUG(4, __FUNCTION__ "()\n");
+       DEBUG(2, __FUNCTION__ "()\n");
        
        self = (struct irlan_cb *) instance;
        
@@ -223,6 +223,12 @@ static int irlan_client_ctrl_data_indication(void *instance, void *sap,
        
        irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb); 
 
+       /* Ready for a new command */
+       self->client.tx_busy = FALSE;
+
+       /* Check if we have some queued commands waiting to be sent */
+       irlan_run_ctrl_tx_queue(self);
+
        return 0;
 }
 
index 682cda8540e9e647bd362f74c06d53e43275a503..2b92e7a74733fae9eadd1a809f721468df628142 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu May  6 13:42:38 1999
+ * Modified at:   Fri May 14 23:08:15 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
index 1284d561a7fa8ccef075b182fa998db85892acc3..d0a77557b787241eb308a53c31528d56367149c6 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Sun May  9 11:48:49 1999
+ * Modified at:   Mon May 31 14:25:19 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -301,7 +301,9 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev)
        init_timer(&self->client.kick_timer);
 
        hashbin_insert(irlan, (QUEUE *) self, daddr, NULL);
-               
+       
+       skb_queue_head_init(&self->client.txq);
+       
        irlan_next_client_state(self, IRLAN_IDLE);
        irlan_next_provider_state(self, IRLAN_IDLE);
 
@@ -321,7 +323,7 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev)
  */
 static void __irlan_close(struct irlan_cb *self)
 {
-       DEBUG(0, __FUNCTION__ "()\n");
+       DEBUG(2, __FUNCTION__ "()\n");
        
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -423,8 +425,6 @@ void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos,
 {
        struct irlan_cb *self;
 
-       DEBUG(2, __FUNCTION__ "()\n");
-
        self = (struct irlan_cb *) instance;
 
        ASSERT(self != NULL, return;);
@@ -444,9 +444,15 @@ void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos,
         */
        irlan_get_unicast_addr(self);
        irlan_open_unicast_addr(self);
+       
+       /* Open broadcast and multicast filter by default */
+       irlan_set_broadcast_filter(self, TRUE);
+       irlan_set_multicast_filter(self, TRUE);
 
        /* Ready to transfer Ethernet frames */
        self->dev.tbusy = 0;
+
+       irlan_eth_send_gratuitous_arp(&self->dev);
 }
 
 /*
@@ -495,9 +501,6 @@ void irlan_disconnect_indication(void *instance, void *sap, LM_REASON reason,
                break;
        }
        
-       /* Stop IP from transmitting more packets */
-       /* irlan_client_flow_indication(handle, FLOW_STOP, priv); */
-
        irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
        irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
 }
@@ -507,7 +510,7 @@ void irlan_open_data_tsap(struct irlan_cb *self)
        struct notify_t notify;
        struct tsap_cb *tsap;
 
-       DEBUG(0, __FUNCTION__ "()\n");
+       DEBUG(2, __FUNCTION__ "()\n");
 
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -522,7 +525,7 @@ void irlan_open_data_tsap(struct irlan_cb *self)
        notify.udata_indication      = irlan_eth_receive;
        notify.connect_indication    = irlan_connect_indication;
        notify.connect_confirm       = irlan_connect_confirm;
-       notify.flow_indication       = irlan_eth_flow_indication;
+       /*notify.flow_indication       = irlan_eth_flow_indication;*/
        notify.disconnect_indication = irlan_disconnect_indication;
        notify.instance              = self;
        strncpy(notify.name, "IrLAN data", NOTIFY_MAX_NAME);
@@ -555,7 +558,6 @@ void irlan_close_tsaps(struct irlan_cb *self)
                irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
                irttp_close_tsap(self->tsap_data);
                self->tsap_data = NULL;
-               
        }
        if (self->client.tsap_ctrl) {
                irttp_disconnect_request(self->client.tsap_ctrl, NULL, 
@@ -608,14 +610,59 @@ void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel)
                irias_add_string_attrib(obj, "Name", "Linux");
 #endif
                irias_add_string_attrib(obj, "DeviceID", "HWP19F0");
-               irias_add_integer_attrib(obj, "CompCnt", 2);
-               irias_add_string_attrib(obj, "Comp#01", "PNP8294");
-               irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+               irias_add_integer_attrib(obj, "CompCnt", 1);
+               if (self->provider.access_type == ACCESS_PEER)
+                       irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+               else
+                       irias_add_string_attrib(obj, "Comp#01", "PNP8294");
+
                irias_add_string_attrib(obj, "Manufacturer", "Linux-IrDA Project");
                irias_insert_object(obj);
        }
 }
 
+/*
+ * Function irlan_run_ctrl_tx_queue (self)
+ *
+ *    Try to send the next command in the control transmit queue
+ *
+ */
+int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
+{
+       struct sk_buff *skb;
+
+       if (irda_lock(&self->client.tx_busy) == FALSE)
+               return -EBUSY;
+
+       skb = skb_dequeue(&self->client.txq);
+       if (!skb) {
+               self->client.tx_busy = FALSE;
+               return 0;
+       }
+       if (self->client.tsap_ctrl == NULL) {
+               self->client.tx_busy = FALSE;
+               dev_kfree_skb(skb);
+               return -1;
+       }
+
+       return irttp_data_request(self->client.tsap_ctrl, skb);
+}
+
+/*
+ * Function irlan_ctrl_data_request (self, skb)
+ *
+ *    This function makes sure that commands on the control channel is being
+ *    sent in a command/response fashion
+ */
+void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
+{
+       /* Queue command */
+       skb_queue_tail(&self->client.txq, skb);
+
+       /* Try to send command */
+       irlan_run_ctrl_tx_queue(self);
+}
+
 /*
  * Function irlan_get_provider_info (self)
  *
@@ -645,7 +692,8 @@ void irlan_get_provider_info(struct irlan_cb *self)
        frame[0] = CMD_GET_PROVIDER_INFO;
        frame[1] = 0x00;                 /* Zero parameters */
        
-       irttp_data_request(self->client.tsap_ctrl, skb);
+       /* irttp_data_request(self->client.tsap_ctrl, skb); */
+       irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -683,7 +731,8 @@ void irlan_open_data_channel(struct irlan_cb *self)
 
 /*     self->use_udata = TRUE; */
 
-       irttp_data_request(self->client.tsap_ctrl, skb);
+       /* irttp_data_request(self->client.tsap_ctrl, skb); */
+       irlan_ctrl_data_request(self, skb);
 }
 
 void irlan_close_data_channel(struct irlan_cb *self) 
@@ -696,6 +745,10 @@ void irlan_close_data_channel(struct irlan_cb *self)
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
 
+       /* Check if the TSAP is still there */
+       if (self->client.tsap_ctrl == NULL)
+               return;
+
        skb = dev_alloc_skb(64);
        if (!skb)
                return;
@@ -711,7 +764,8 @@ void irlan_close_data_channel(struct irlan_cb *self)
 
        irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
 
-       irttp_data_request(self->client.tsap_ctrl, skb);
+       /* irttp_data_request(self->client.tsap_ctrl, skb); */
+       irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -747,7 +801,8 @@ void irlan_open_unicast_addr(struct irlan_cb *self)
        irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
        irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); 
        
-       irttp_data_request(self->client.tsap_ctrl, skb);
+       /* irttp_data_request(self->client.tsap_ctrl, skb); */
+       irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -787,8 +842,9 @@ void irlan_set_broadcast_filter(struct irlan_cb *self, int status)
                irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); 
        else
                irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); 
-       
-       irttp_data_request(self->client.tsap_ctrl, skb);
+
+       /* irttp_data_request(self->client.tsap_ctrl, skb); */
+       irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -826,8 +882,9 @@ void irlan_set_multicast_filter(struct irlan_cb *self, int status)
                irlan_insert_string_param(skb, "FILTER_MODE", "ALL"); 
        else
                irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); 
-       
-       irttp_data_request(self->client.tsap_ctrl, skb);
+
+       /* irttp_data_request(self->client.tsap_ctrl, skb); */
+       irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -864,7 +921,8 @@ void irlan_get_unicast_addr(struct irlan_cb *self)
        irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
        irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC"); 
        
-       irttp_data_request(self->client.tsap_ctrl, skb);
+       /* irttp_data_request(self->client.tsap_ctrl, skb); */
+       irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -899,7 +957,8 @@ void irlan_get_media_char(struct irlan_cb *self)
        
        irlan_insert_string_param(skb, "MEDIA", "802.3");
        
-       irttp_data_request(self->client.tsap_ctrl, skb);
+       /* irttp_data_request(self->client.tsap_ctrl, skb); */
+       irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -1153,34 +1212,34 @@ void print_ret_code(__u8 code)
                printk(KERN_INFO "Success\n");
                break;
        case 1:
-               printk(KERN_WARNING "Insufficient resources\n");
+               WARNING("IrLAN: Insufficient resources\n");
                break;
        case 2:
-               printk(KERN_WARNING "Invalid command format\n");
+               WARNING("IrLAN: Invalid command format\n");
                break;
        case 3:
-               printk(KERN_WARNING "Command not supported\n");
+               WARNING("IrLAN: Command not supported\n");
                break;
        case 4:
-               printk(KERN_WARNING "Parameter not supported\n");
+               WARNING("IrLAN: Parameter not supported\n");
                break;
        case 5:
-               printk(KERN_WARNING "Value not supported\n");
+               WARNING("IrLAN: Value not supported\n");
                break;
        case 6:
-               printk(KERN_WARNING "Not open\n");
+               WARNING("IrLAN: Not open\n");
                break;
        case 7:
-               printk(KERN_WARNING "Authentication required\n");
+               WARNING("IrLAN: Authentication required\n");
                break;
        case 8:
-               printk(KERN_WARNING "Invalid password\n");
+               WARNING("IrLAN: Invalid password\n");
                break;
        case 9:
-               printk(KERN_WARNING "Protocol error\n");
+               WARNING("IrLAN: Protocol error\n");
                break;
        case 255:
-               printk(KERN_WARNING "Asynchronous status\n");
+               WARNING("IrLAN: Asynchronous status\n");
                break;
        }
 }
index 26b16a196dcd277e8390888c090d8528e630612b..c2e2453db64e7d77c647f88a2abdd02dd6880b2d 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:37:58 1998
- * Modified at:   Mon May 10 20:23:49 1999
+ * Modified at:   Mon May 31 19:57:08 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
@@ -50,7 +50,7 @@ int irlan_eth_init(struct device *dev)
        struct irmanager_event mgr_event;
        struct irlan_cb *self;
 
-       DEBUG(0, __FUNCTION__"()\n");
+       DEBUG(2, __FUNCTION__"()\n");
 
        ASSERT(dev != NULL, return -1;);
        
@@ -66,7 +66,12 @@ int irlan_eth_init(struct device *dev)
        
        ether_setup(dev);
        
-       dev->tx_queue_len = TTP_MAX_QUEUE;
+       /* 
+        * Lets do all queueing in IrTTP instead of this device driver.
+        * Queueing here as well can introduce some strange latency
+        * problems, which we will avoid by setting the queue size to 0.
+        */
+       dev->tx_queue_len = 0;
 
        if (self->provider.access_type == ACCESS_DIRECT) {
                /*  
@@ -110,7 +115,7 @@ int irlan_eth_open(struct device *dev)
 {
        struct irlan_cb *self;
        
-       DEBUG(0, __FUNCTION__ "()\n");
+       DEBUG(2, __FUNCTION__ "()\n");
 
        ASSERT(dev != NULL, return -1;);
 
@@ -145,7 +150,7 @@ int irlan_eth_close(struct device *dev)
 {
        struct irlan_cb *self = (struct irlan_cb *) dev->priv;
 
-       DEBUG(0, __FUNCTION__ "()\n");
+       DEBUG(2, __FUNCTION__ "()\n");
        
        /* Stop device */
        dev->tbusy = 1;
@@ -180,26 +185,16 @@ int irlan_eth_close(struct device *dev)
 int irlan_eth_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct irlan_cb *self;
+       int ret;
 
        self = (struct irlan_cb *) dev->priv;
 
        ASSERT(self != NULL, return 0;);
        ASSERT(self->magic == IRLAN_MAGIC, return 0;);
 
-       /* Lock transmit buffer */
-       if (irda_lock((void *) &dev->tbusy) == FALSE) {
-               /*
-                * If we get here, some higher level has decided we are broken.
-                * There should really be a "kick me" function call instead.
-                */
-               int tickssofar = jiffies - dev->trans_start; 
-               
-               if (tickssofar < 5) 
-                       return -EBUSY;
-               
-               dev->tbusy = 0;
-               dev->trans_start = jiffies;
-       }
+       /* Check if IrTTP can accept more frames */
+       if (dev->tbusy)
+               return -EBUSY;
        
        /* skb headroom large enough to contain all IrDA-headers? */
        if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
@@ -218,31 +213,30 @@ int irlan_eth_xmit(struct sk_buff *skb, struct device *dev)
        } 
 
        dev->trans_start = jiffies;
-       self->stats.tx_packets++;
-       self->stats.tx_bytes += skb->len; 
 
        /* Now queue the packet in the transport layer */
        if (self->use_udata)
-               irttp_udata_request(self->tsap_data, skb);
-       else {
-               if (irttp_data_request(self->tsap_data, skb) < 0) {
-                       /*   
-                        * IrTTPs tx queue is full, so we just have to
-                        * drop the frame! You might think that we should
-                        * just return -1 and don't deallocate the frame,
-                        * but that is dangerous since it's possible that
-                        * we have replaced the original skb with a new
-                        * one with larger headroom, and that would really
-                        * confuse do_dev_queue_xmit() in dev.c! I have
-                        * tried :-) DB 
-                        */
-                       dev_kfree_skb(skb);
-                       ++self->stats.tx_dropped;
-               
-                       return 0;
-               }
+               ret = irttp_udata_request(self->tsap_data, skb);
+       else
+               ret = irttp_data_request(self->tsap_data, skb);
+
+       if (ret < 0) {
+               /*   
+                * IrTTPs tx queue is full, so we just have to
+                * drop the frame! You might think that we should
+                * just return -1 and don't deallocate the frame,
+                * but that is dangerous since it's possible that
+                * we have replaced the original skb with a new
+                * one with larger headroom, and that would really
+                * confuse do_dev_queue_xmit() in dev.c! I have
+                * tried :-) DB 
+                */
+               dev_kfree_skb(skb);
+               self->stats.tx_dropped++;
+       } else {
+               self->stats.tx_packets++;
+               self->stats.tx_bytes += skb->len; 
        }
-       dev->tbusy = 0; /* Finished! */
        
        return 0;
 }
@@ -276,11 +270,11 @@ int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
        skb->dev = &self->dev;
        skb->protocol=eth_type_trans(skb, skb->dev); /* Remove eth header */
        
-       netif_rx(skb);   /* Eat it! */
-       
        self->stats.rx_packets++;
        self->stats.rx_bytes += skb->len; 
 
+       netif_rx(skb);   /* Eat it! */
+       
        return 0;
 }
 
@@ -295,8 +289,6 @@ void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
        struct irlan_cb *self;
        struct device *dev;
 
-       DEBUG(4, __FUNCTION__ "()\n");
-
        self = (struct irlan_cb *) instance;
 
        ASSERT(self != NULL, return;);
@@ -344,7 +336,7 @@ void irlan_eth_rebuild_header(void *buff, struct device *dev,
  *    Send gratuitous ARP to announce that we have changed
  *    hardware address, so that all peers updates their ARP tables
  */
-void irlan_etc_send_gratuitous_arp(struct device *dev) 
+void irlan_eth_send_gratuitous_arp(struct device *dev)
 {
        struct in_device *in_dev;
 
@@ -375,16 +367,21 @@ void irlan_eth_set_multicast_list(struct device *dev)
 
        self = dev->priv; 
 
-       DEBUG(0, __FUNCTION__ "()\n");
-       return;
+       DEBUG(2, __FUNCTION__ "()\n");
+
        ASSERT(self != NULL, return;); 
        ASSERT(self->magic == IRLAN_MAGIC, return;);
 
-       if (dev->flags&IFF_PROMISC) {
-               /* Enable promiscuous mode */
-               DEBUG(0, "Promiscous mode not implemented\n");
-               /* outw(MULTICAST|PROMISC, ioaddr); */
+       /* Check if data channel has been connected yet */
+       if (self->client.state != IRLAN_DATA) {
+               DEBUG(1, __FUNCTION__ "(), delaying!\n");
+               return;
        }
+
+       if (dev->flags & IFF_PROMISC) {
+               /* Enable promiscuous mode */
+               WARNING("Promiscous mode not implemented by IrLAN!\n");
+       } 
        else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) {
                /* Disable promiscuous mode, use normal mode. */
                DEBUG(4, __FUNCTION__ "(), Setting multicast filter\n");
@@ -404,13 +401,10 @@ void irlan_eth_set_multicast_list(struct device *dev)
                irlan_set_multicast_filter(self, FALSE);
        }
 
-       if (dev->flags & IFF_BROADCAST) {
-               DEBUG(4, __FUNCTION__ "(), Setting broadcast filter\n");
+       if (dev->flags & IFF_BROADCAST)
                irlan_set_broadcast_filter(self, TRUE);
-       } else {
-               DEBUG(4, __FUNCTION__ "(), Clearing broadcast filter\n");
+       else
                irlan_set_broadcast_filter(self, FALSE);
-       }
 }
 
 /*
index 4f199e4ee74fc477dfe66c2bcdd9e6a862eaaf2b..ec7178db4a01e1b263f8af7b9593a43f703f12b0 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Jan 29 11:16:38 1999
- * Modified at:   Sat May  8 15:25:23 1999
+ * Modified at:   Fri May 14 23:11:01 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -23,6 +23,7 @@
  ********************************************************************/
 
 #include <linux/skbuff.h>
+#include <linux/random.h>
 
 #include <net/irda/irlan_common.h>
 
index d24923652a586949b5e53da3010f2aef4858c08e..245884cf71da1413ad627a45c5bc5ffaf18e6508 100644 (file)
@@ -1,26 +1,31 @@
 /*********************************************************************
  *                
  * Filename:      irlap.c
- * Version:       0.9
- * Description:   An IrDA LAP driver for Linux
- * Status:        Stable.
+ * Version:       1.0
+ * Description:   IrLAP implementation for Linux
+ * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Apr 23 10:12:29 1999
+ * Modified at:   Mon May 31 21:43:55 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
- *     All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *     
- *     This program is free software; you can redistribute iyt and/or 
+ *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
- *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *
+ * 
+ *     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., 59 Temple Place, Suite 330, Boston, 
+ *     MA 02111-1307 USA
+ *     
  ********************************************************************/
 
 #include <linux/config.h>
@@ -60,23 +65,23 @@ static char *lap_reasons[] = {
 };
 
 #ifdef CONFIG_PROC_FS
-int irlap_proc_read( char *, char **, off_t, int, int);
+int irlap_proc_read(char *, char **, off_t, int, int);
 
 #endif /* CONFIG_PROC_FS */
 
-__initfunc(int irlap_init( void))
+__initfunc(int irlap_init(void))
 {
        /* Allocate master array */
-       irlap = hashbin_new( HB_LOCAL);
-       if ( irlap == NULL) {
-               printk( KERN_WARNING "IrLAP: Can't allocate irlap hashbin!\n");
+       irlap = hashbin_new(HB_LOCAL);
+       if (irlap == NULL) {
+               printk(KERN_WARNING "IrLAP: Can't allocate irlap hashbin!\n");
                return -ENOMEM;
        }
 
 #ifdef CONFIG_IRDA_COMPRESSION
-       irlap_compressors = hashbin_new( HB_LOCAL);
-       if ( irlap_compressors == NULL) {
-               printk( KERN_WARNING "IrLAP: Can't allocate compressors hashbin!\n");
+       irlap_compressors = hashbin_new(HB_LOCAL);
+       if (irlap_compressors == NULL) {
+               printk(KERN_WARNING "IrLAP: Can't allocate compressors hashbin!\n");
                return -ENOMEM;
        }
 #endif
@@ -86,12 +91,12 @@ __initfunc(int irlap_init( void))
 
 void irlap_cleanup(void)
 {
-       ASSERT( irlap != NULL, return;);
+       ASSERT(irlap != NULL, return;);
 
-       hashbin_delete( irlap, (FREE_FUNC) __irlap_close);
+       hashbin_delete(irlap, (FREE_FUNC) __irlap_close);
 
 #ifdef CONFIG_IRDA_COMPRESSION
-       hashbin_delete( irlap_compressors, (FREE_FUNC) kfree);
+       hashbin_delete(irlap_compressors, (FREE_FUNC) kfree);
 #endif
 }
 
@@ -101,32 +106,32 @@ void irlap_cleanup(void)
  *    Initialize IrLAP layer
  *
  */
-struct irlap_cb *irlap_open( struct irda_device *irdev)
+struct irlap_cb *irlap_open(struct irda_device *irdev)
 {
        struct irlap_cb *self;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
        
-       ASSERT( irdev != NULL, return NULL;);
-       ASSERT( irdev->magic == IRDA_DEVICE_MAGIC, return NULL;);
+       ASSERT(irdev != NULL, return NULL;);
+       ASSERT(irdev->magic == IRDA_DEVICE_MAGIC, return NULL;);
 
        /* Initialize the irlap structure. */
-       self = kmalloc( sizeof( struct irlap_cb), GFP_KERNEL);
-       if ( self == NULL)
+       self = kmalloc(sizeof(struct irlap_cb), GFP_KERNEL);
+       if (self == NULL)
                return NULL;
        
-       memset( self, 0, sizeof(struct irlap_cb));
+       memset(self, 0, sizeof(struct irlap_cb));
        self->magic = LAP_MAGIC;
 
        /* Make a binding between the layers */
        self->irdev = irdev;
        self->netdev = &irdev->netdev;
 
-       irlap_next_state( self, LAP_OFFLINE);
+       irlap_next_state(self, LAP_OFFLINE);
 
        /* Initialize transmitt queue */
-       skb_queue_head_init( &self->tx_list);
-       skb_queue_head_init( &self->wx_list);
+       skb_queue_head_init(&self->tx_list);
+       skb_queue_head_init(&self->wx_list);
 
        /* My unique IrLAP device address! */
        get_random_bytes(&self->saddr, sizeof(self->saddr));
@@ -140,21 +145,21 @@ struct irlap_cb *irlap_open( struct irda_device *irdev)
                self->caddr &= 0xfe;
        }
 
-       init_timer( &self->slot_timer);
-       init_timer( &self->query_timer);
-       init_timer( &self->discovery_timer);
-       init_timer( &self->final_timer);                
-       init_timer( &self->poll_timer);
-       init_timer( &self->wd_timer);
-       init_timer( &self->backoff_timer);
+       init_timer(&self->slot_timer);
+       init_timer(&self->query_timer);
+       init_timer(&self->discovery_timer);
+       init_timer(&self->final_timer);         
+       init_timer(&self->poll_timer);
+       init_timer(&self->wd_timer);
+       init_timer(&self->backoff_timer);
 
-       irlap_apply_default_connection_parameters( self);
+       irlap_apply_default_connection_parameters(self);
        
-       irlap_next_state( self, LAP_NDM);
+       irlap_next_state(self, LAP_NDM);
 
-       hashbin_insert( irlap, (QUEUE *) self, self->saddr, NULL);
+       hashbin_insert(irlap, (QUEUE *) self, self->saddr, NULL);
 
-       irlmp_register_link( self, self->saddr, &self->notify);
+       irlmp_register_link(self, self->saddr, &self->notify);
        
        return self;
 }
@@ -165,26 +170,26 @@ struct irlap_cb *irlap_open( struct irda_device *irdev)
  *    Remove IrLAP and all allocated memory. Stop any pending timers.
  *
  */
-static void __irlap_close( struct irlap_cb *self)
+static void __irlap_close(struct irlap_cb *self)
 {
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
        /* Stop timers */
-       del_timer( &self->slot_timer);
-       del_timer( &self->query_timer);
-       del_timer( &self->discovery_timer);
-       del_timer( &self->final_timer);         
-       del_timer( &self->poll_timer);
-       del_timer( &self->wd_timer);
-       del_timer( &self->backoff_timer);
-
-       irlap_flush_all_queues( self);
+       del_timer(&self->slot_timer);
+       del_timer(&self->query_timer);
+       del_timer(&self->discovery_timer);
+       del_timer(&self->final_timer);          
+       del_timer(&self->poll_timer);
+       del_timer(&self->wd_timer);
+       del_timer(&self->backoff_timer);
+
+       irlap_flush_all_queues(self);
        
        self->irdev = NULL;
        self->magic = 0;
        
-       kfree( self);
+       kfree(self);
 }
 
 /*
@@ -193,27 +198,27 @@ static void __irlap_close( struct irlap_cb *self)
  *    Remove IrLAP instance
  *
  */
-void irlap_close( struct irlap_cb *self) 
+void irlap_close(struct irlap_cb *self) 
 {
        struct irlap_cb *lap;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
-       irlap_disconnect_indication( self, LAP_DISC_INDICATION);
+       irlap_disconnect_indication(self, LAP_DISC_INDICATION);
 
        irlmp_unregister_link(self->saddr);
        self->notify.instance = NULL;
 
        /* Be sure that we manage to remove ourself from the hash */
-       lap = hashbin_remove( irlap, self->saddr, NULL);
-       if ( !lap) {
-               DEBUG( 1, __FUNCTION__ "(), Didn't find myself!\n");
+       lap = hashbin_remove(irlap, self->saddr, NULL);
+       if (!lap) {
+               DEBUG(1, __FUNCTION__ "(), Didn't find myself!\n");
                return;
        }
-       __irlap_close( lap);
+       __irlap_close(lap);
 }
 
 /*
@@ -243,7 +248,7 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
  */
 void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) 
 {
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
        
        irlap_do_event(self, CONNECT_RESPONSE, skb, NULL);
 }
@@ -324,23 +329,23 @@ inline void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb)
  *    Received some data that was sent unreliable
  *
  */
-void irlap_unit_data_indication( struct irlap_cb *self, struct sk_buff *skb)
+void irlap_unit_data_indication(struct irlap_cb *self, struct sk_buff *skb)
 {
-       DEBUG( 1, __FUNCTION__ "()\n"); 
+       DEBUG(1, __FUNCTION__ "()\n"); 
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
+       ASSERT(skb != NULL, return;);
 
        /* Hide LAP header from IrLMP layer */
-       skb_pull( skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+       skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
 
 #ifdef CONFIG_IRDA_COMPRESSION
-       if ( self->qos_tx.compression.value) {
+       if (self->qos_tx.compression.value) {
                
-               skb = irlap_decompress_frame( self, skb);
-               if ( !skb) {
-                       DEBUG( 1, __FUNCTION__ "(), Decompress error!\n");
+               skb = irlap_decompress_frame(self, skb);
+               if (!skb) {
+                       DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
                        return;
                }
        }
@@ -354,40 +359,35 @@ void irlap_unit_data_indication( struct irlap_cb *self, struct sk_buff *skb)
  *    Queue data for transmission, must wait until XMIT state
  *
  */
-inline void irlap_data_request( struct irlap_cb *self, struct sk_buff *skb,
+inline void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
                                int reliable)
 {
-       DEBUG( 4, __FUNCTION__ "()\n");
-       
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
-
-       DEBUG( 4, __FUNCTION__ "(), tx_list=%d\n", 
-                  skb_queue_len( &self->tx_list));
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
+       ASSERT(skb != NULL, return;);
 
 #ifdef CONFIG_IRDA_COMPRESSION
-       if ( self->qos_tx.compression.value) {
-               skb = irlap_compress_frame( self, skb);
-               if ( !skb) {
-                       DEBUG( 1, __FUNCTION__ "(), Compress error!\n");
+       if (self->qos_tx.compression.value) {
+               skb = irlap_compress_frame(self, skb);
+               if (!skb) {
+                       DEBUG(1, __FUNCTION__ "(), Compress error!\n");
                        return;
                }
        }
 #endif
        
-       ASSERT( skb_headroom( skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), 
-               return;);
-       skb_push( skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+       ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), 
+              return;);
+       skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
 
        /*  
         *  Must set frame format now so that the rest of the code knows 
         *  if its dealing with an I or an UI frame
         */
-       if ( reliable)
+       if (reliable)
                skb->data[1] = I_FRAME;
        else {
-               DEBUG( 4, __FUNCTION__ "(), queueing unreliable frame\n");
+               DEBUG(4, __FUNCTION__ "(), queueing unreliable frame\n");
                skb->data[1] = UI_FRAME;
        }
 
@@ -395,20 +395,20 @@ inline void irlap_data_request( struct irlap_cb *self, struct sk_buff *skb,
         *  Send event if this frame only if we are in the right state 
         *  FIXME: udata should be sent first! (skb_queue_head?)
         */
-       if (( self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
+       if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
                /*
                 *  Check if the transmit queue contains some unsent frames,
                 *  and if so, make sure they are sent first
                 */
-               if ( !skb_queue_empty( &self->tx_list)) {
-                       skb_queue_tail( &self->tx_list, skb);
-                       skb = skb_dequeue( &self->tx_list);
+               if (!skb_queue_empty(&self->tx_list)) {
+                       skb_queue_tail(&self->tx_list, skb);
+                       skb = skb_dequeue(&self->tx_list);
                        
-                       ASSERT( skb != NULL, return;);
+                       ASSERT(skb != NULL, return;);
                }
-               irlap_do_event( self, SEND_I_CMD, skb, NULL);
+               irlap_do_event(self, SEND_I_CMD, skb, NULL);
        } else
-               skb_queue_tail( &self->tx_list, skb);   
+               skb_queue_tail(&self->tx_list, skb);    
 }
 
 /*
@@ -444,33 +444,33 @@ void irlap_disconnect_request(struct irlap_cb *self)
  *    Disconnect request from other device
  *
  */
-void irlap_disconnect_indication( struct irlap_cb *self, LAP_REASON reason) 
+void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) 
 {
-       DEBUG( 1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); 
+       DEBUG(1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); 
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
 #ifdef CONFIG_IRDA_COMPRESSION
-       irda_free_compression( self);
+       irda_free_compression(self);
 #endif
        /* Flush queues */
-       irlap_flush_all_queues( self);
+       irlap_flush_all_queues(self);
        
-       switch( reason) {
+       switch(reason) {
        case LAP_RESET_INDICATION:
-               DEBUG( 1, __FUNCTION__ "(), Sending reset request!\n");
-               irlap_do_event( self, RESET_REQUEST, NULL, NULL);
+               DEBUG(1, __FUNCTION__ "(), Sending reset request!\n");
+               irlap_do_event(self, RESET_REQUEST, NULL, NULL);
                break;
        case LAP_NO_RESPONSE:      /* FALLTROUGH */     
        case LAP_DISC_INDICATION:  /* FALLTROUGH */
        case LAP_FOUND_NONE:       /* FALLTROUGH */
        case LAP_MEDIA_BUSY:
-               irlmp_link_disconnect_indication( self->notify.instance, 
+               irlmp_link_disconnect_indication(self->notify.instance, 
                                                  self, reason, NULL);
                break;
        default:
-               DEBUG( 1, __FUNCTION__ "(), Reason %d not implemented!\n", 
+               DEBUG(1, __FUNCTION__ "(), Reason %d not implemented!\n", 
                       reason);
        }
 }
@@ -485,22 +485,22 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
 {
        struct irlap_info info;
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( discovery != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
+       ASSERT(discovery != NULL, return;);
        
-       DEBUG( 4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
+       DEBUG(4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
 
-       ASSERT(( discovery->nslots == 1) || ( discovery->nslots == 6) ||
-              ( discovery->nslots == 8) || ( discovery->nslots == 16), 
+       ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
+              (discovery->nslots == 8) || (discovery->nslots == 16), 
               return;);
        
        /*
         *  Discovery is only possible in NDM mode
         */ 
-       if ( self->state == LAP_NDM) {
-               ASSERT( self->discovery_log == NULL, return;);
-               self->discovery_log= hashbin_new( HB_LOCAL);
+       if (self->state == LAP_NDM) {
+               ASSERT(self->discovery_log == NULL, return;);
+               self->discovery_log= hashbin_new(HB_LOCAL);
                
                info.S = discovery->nslots; /* Number of slots */
                info.s = 0; /* Current slot */
@@ -526,11 +526,11 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
 
                self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
                
-               irlap_do_event( self, DISCOVERY_REQUEST, NULL, &info);
+               irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
        } else { 
-               DEBUG( 4, __FUNCTION__ 
+               DEBUG(4, __FUNCTION__ 
                       "(), discovery only possible in NDM mode\n");
-               irlap_discovery_confirm( self, NULL);
+               irlap_discovery_confirm(self, NULL);
        } 
 }
 
@@ -540,12 +540,12 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
  *    A device has been discovered in front of this station, we
  *    report directly to LMP.
  */
-void irlap_discovery_confirm( struct irlap_cb *self, hashbin_t *discovery_log) 
+void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log) 
 {
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
        
-       ASSERT( self->notify.instance != NULL, return;);
+       ASSERT(self->notify.instance != NULL, return;);
        
        /* 
         * Check for successful discovery, since we are then allowed to clear 
@@ -556,7 +556,7 @@ void irlap_discovery_confirm( struct irlap_cb *self, hashbin_t *discovery_log)
                irda_device_set_media_busy(self->irdev, FALSE);
        
        /* Inform IrLMP */
-       irlmp_link_discovery_confirm( self->notify.instance, discovery_log);
+       irlmp_link_discovery_confirm(self->notify.instance, discovery_log);
        
        /* 
         *  IrLMP has now the responsibilities for the discovery_log 
@@ -572,13 +572,13 @@ void irlap_discovery_confirm( struct irlap_cb *self, hashbin_t *discovery_log)
  */
 void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) 
 {
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( discovery != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
+       ASSERT(discovery != NULL, return;);
 
-       ASSERT( self->notify.instance != NULL, return;);
+       ASSERT(self->notify.instance != NULL, return;);
        
        irlmp_link_discovery_indication(self->notify.instance, discovery);
 }
@@ -591,12 +591,12 @@ void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery)
  */
 void irlap_status_indication(int quality_of_link) 
 {
-       switch( quality_of_link) {
+       switch(quality_of_link) {
        case STATUS_NO_ACTIVITY:
-               printk( KERN_INFO "IrLAP, no activity on link!\n");
+               printk(KERN_INFO "IrLAP, no activity on link!\n");
                break;
        case STATUS_NOISY:
-               printk( KERN_INFO "IrLAP, noisy link!\n");
+               printk(KERN_INFO "IrLAP, noisy link!\n");
                break;
        default:
                break;
@@ -610,17 +610,17 @@ void irlap_status_indication(int quality_of_link)
  *    
  *
  */
-void irlap_reset_indication( struct irlap_cb *self)
+void irlap_reset_indication(struct irlap_cb *self)
 {
-       DEBUG( 1, __FUNCTION__ "()\n");
+       DEBUG(1, __FUNCTION__ "()\n");
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
        
-       if ( self->state == LAP_RESET_WAIT)
-               irlap_do_event( self, RESET_REQUEST, NULL, NULL);
+       if (self->state == LAP_RESET_WAIT)
+               irlap_do_event(self, RESET_REQUEST, NULL, NULL);
        else
-               irlap_do_event( self, RESET_RESPONSE, NULL, NULL);
+               irlap_do_event(self, RESET_RESPONSE, NULL, NULL);
 }
 
 /*
@@ -631,7 +631,7 @@ void irlap_reset_indication( struct irlap_cb *self)
  */
 void irlap_reset_confirm(void)
 {
-       DEBUG( 1, __FUNCTION__ "()\n");
+       DEBUG(1, __FUNCTION__ "()\n");
 }
 
 /*
@@ -641,15 +641,15 @@ void irlap_reset_confirm(void)
  *    S = Number of slots (0 -> S-1)
  *    s = Current slot
  */
-int irlap_generate_rand_time_slot( int S, int s) 
+int irlap_generate_rand_time_slot(int S, int s) 
 {
        int slot;
        
-       ASSERT(( S - s) > 0, return 0;);
+       ASSERT((S - s) > 0, return 0;);
 
        slot = s + jiffies % (S-s);
        
-       ASSERT(( slot >= s) || ( slot < S), return 0;);
+       ASSERT((slot >= s) || (slot < S), return 0;);
        
        return slot;
 }
@@ -661,51 +661,51 @@ int irlap_generate_rand_time_slot( int S, int s)
  *    not intuitive and you should not try to change it. If you think it
  *    contains bugs, please mail a patch to the author instead.
  */
-void irlap_update_nr_received( struct irlap_cb *self, int nr) 
+void irlap_update_nr_received(struct irlap_cb *self, int nr) 
 {
        struct sk_buff *skb = NULL;
        int count = 0;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
        /*
          * Remove all the ack-ed frames from the window queue.
          */
 
-       DEBUG( 4, "--> wx_list=%d, va=%d, nr=%d\n", 
-              skb_queue_len( &self->wx_list), self->va, nr);
+       DEBUG(4, "--> wx_list=%d, va=%d, nr=%d\n", 
+              skb_queue_len(&self->wx_list), self->va, nr);
 
        /* 
         *  Optimize for the common case. It is most likely that the receiver
         *  will acknowledge all the frames we have sent! So in that case we
         *  delete all frames stored in window.
         */
-       if ( nr == self->vs) {
-               while (( skb = skb_dequeue( &self->wx_list)) != NULL) {
+       if (nr == self->vs) {
+               while ((skb = skb_dequeue(&self->wx_list)) != NULL) {
                     dev_kfree_skb(skb);
                }
                /* The last acked frame is the next to send minus one */
                self->va = nr - 1;
        } else {
                /* Remove all acknowledged frames in current window */
-               while (( skb_peek( &self->wx_list) != NULL) && 
-                      ((( self->va+1) % 8) != nr)) 
+               while ((skb_peek(&self->wx_list) != NULL) && 
+                      (((self->va+1) % 8) != nr)) 
                {
-                       skb = skb_dequeue( &self->wx_list);
+                       skb = skb_dequeue(&self->wx_list);
                        dev_kfree_skb(skb);
                        
                        self->va = (self->va + 1) % 8;
                        count++;
                }
                
-               DEBUG( 4, "irlap_update_nr_received(), removed %d\n", count);
-               DEBUG( 4, "wx_list=%d, va=%d, nr=%d -->\n", 
-                      skb_queue_len( &self->wx_list), self->va, nr);
+               DEBUG(4, "irlap_update_nr_received(), removed %d\n", count);
+               DEBUG(4, "wx_list=%d, va=%d, nr=%d -->\n", 
+                      skb_queue_len(&self->wx_list), self->va, nr);
        }
        
        /* Advance window */
-       self->window = self->window_size - skb_queue_len( &self->wx_list);
+       self->window = self->window_size - skb_queue_len(&self->wx_list);
 }
 
 /*
@@ -713,14 +713,14 @@ void irlap_update_nr_received( struct irlap_cb *self, int nr)
  *
  *    Validate the next to send (ns) field from received frame.
  */
-int irlap_validate_ns_received( struct irlap_cb *self, int ns) 
+int irlap_validate_ns_received(struct irlap_cb *self, int ns) 
 {
-       ASSERT( self != NULL, return -ENODEV;);
-       ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+       ASSERT(self != NULL, return -ENODEV;);
+       ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
 
        /*  ns as expected?  */
-       if ( ns == self->vr) {
-               DEBUG( 4, __FUNCTION__ "(), expected!\n");
+       if (ns == self->vr) {
+               DEBUG(4, __FUNCTION__ "(), expected!\n");
                return NS_EXPECTED;
        }
        /*
@@ -737,14 +737,14 @@ int irlap_validate_ns_received( struct irlap_cb *self, int ns)
  *    Validate the next to receive (nr) field from received frame.
  *
  */
-int irlap_validate_nr_received( struct irlap_cb *self, int nr) 
+int irlap_validate_nr_received(struct irlap_cb *self, int nr) 
 {
-       ASSERT( self != NULL, return -ENODEV;);
-       ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+       ASSERT(self != NULL, return -ENODEV;);
+       ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
 
        /*  nr as expected?  */
-       if ( nr == self->vs) {
-               DEBUG( 4, __FUNCTION__ "(), expected!\n");
+       if (nr == self->vs) {
+               DEBUG(4, __FUNCTION__ "(), expected!\n");
                return NR_EXPECTED;
        }
 
@@ -752,11 +752,11 @@ int irlap_validate_nr_received( struct irlap_cb *self, int nr)
         *  unexpected nr? (but within current window), first we check if the 
         *  ns numbers of the frames in the current window wrap.
         */
-       if ( self->va < self->vs) {
-               if (( nr >= self->va) && ( nr <= self->vs))
+       if (self->va < self->vs) {
+               if ((nr >= self->va) && (nr <= self->vs))
                        return NR_UNEXPECTED;
        } else {
-               if (( nr >= self->va) || ( nr <= self->vs)) 
+               if ((nr >= self->va) || (nr <= self->vs)) 
                        return NR_UNEXPECTED;
        }
        
@@ -770,12 +770,12 @@ int irlap_validate_nr_received( struct irlap_cb *self, int nr)
  *    Initialize the connection state parameters
  *
  */
-void irlap_initiate_connection_state( struct irlap_cb *self) 
+void irlap_initiate_connection_state(struct irlap_cb *self) 
 {
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
        /* Next to send and next to receive */
        self->vs = self->vr = 0;
@@ -829,24 +829,24 @@ void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos)
  *    Flush all queues
  *
  */
-void irlap_flush_all_queues( struct irlap_cb *self) 
+void irlap_flush_all_queues(struct irlap_cb *self) 
 {
        struct sk_buff* skb;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
        /* Free transmission queue */
-       while (( skb = skb_dequeue( &self->tx_list)) != NULL)
-               dev_kfree_skb( skb);
+       while ((skb = skb_dequeue(&self->tx_list)) != NULL)
+               dev_kfree_skb(skb);
        
        /* Free sliding window buffered packets */
-       while (( skb = skb_dequeue( &self->wx_list)) != NULL)
-               dev_kfree_skb( skb);
+       while ((skb = skb_dequeue(&self->wx_list)) != NULL)
+               dev_kfree_skb(skb);
 
 #ifdef CONFIG_IRDA_RECYCLE_RR
-       if ( self->recycle_rr_skb) { 
-               dev_kfree_skb( self->recycle_rr_skb);
+       if (self->recycle_rr_skb) { 
+               dev_kfree_skb(self->recycle_rr_skb);
                self->recycle_rr_skb = NULL;
        }
 #endif
@@ -866,7 +866,7 @@ void irlap_change_speed(struct irlap_cb *self, int speed)
        ASSERT(self->magic == LAP_MAGIC, return;);
 
        if (!self->irdev) {
-               DEBUG( 1, __FUNCTION__ "(), driver missing!\n");
+               DEBUG(1, __FUNCTION__ "(), driver missing!\n");
                return;
        }
 
@@ -883,8 +883,8 @@ void irlap_init_comp_qos_capabilities(struct irlap_cb *self)
        __u8 mask; /* Current bit tested */
        int i;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
        /* 
         *  Find out which compressors we support. We do this be checking that
@@ -892,24 +892,24 @@ void irlap_init_comp_qos_capabilities(struct irlap_cb *self)
         *  actually been loaded. Ths is sort of hairy code but that is what 
         *  you get when you do a little bit flicking :-)
         */
-       DEBUG( 4, __FUNCTION__ "(), comp bits 0x%02x\n", 
+       DEBUG(4, __FUNCTION__ "(), comp bits 0x%02x\n", 
               self->qos_rx.compression.bits); 
        mask = 0x80; /* Start with testing MSB */
-       for ( i=0;i<8;i++) {
-               DEBUG( 4, __FUNCTION__ "(), testing bit %d\n", 8-i);
-               if ( self->qos_rx.compression.bits & mask) {
-                       DEBUG( 4, __FUNCTION__ "(), bit %d is set by defalt\n",
+       for (i=0;i<8;i++) {
+               DEBUG(4, __FUNCTION__ "(), testing bit %d\n", 8-i);
+               if (self->qos_rx.compression.bits & mask) {
+                       DEBUG(4, __FUNCTION__ "(), bit %d is set by defalt\n",
                               8-i);
-                       comp = hashbin_find( irlap_compressors, 
+                       comp = hashbin_find(irlap_compressors, 
                                             compression[ msb_index(mask)], 
                                             NULL);
-                       if ( !comp) {
+                       if (!comp) {
                                /* Protocol not supported, so clear the bit */
-                               DEBUG( 4, __FUNCTION__ "(), Compression "
+                               DEBUG(4, __FUNCTION__ "(), Compression "
                                       "protocol %d has not been loaded!\n", 
                                       compression[msb_index(mask)]);
                                self->qos_rx.compression.bits &= ~mask;
-                               DEBUG( 4, __FUNCTION__ 
+                               DEBUG(4, __FUNCTION__ 
                                       "(), comp bits 0x%02x\n", 
                                       self->qos_rx.compression.bits); 
                        }
@@ -931,20 +931,20 @@ void irlap_init_comp_qos_capabilities(struct irlap_cb *self)
 void irlap_init_qos_capabilities(struct irlap_cb *self,
                                 struct qos_info *qos_user)
 {
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( self->irdev != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
+       ASSERT(self->irdev != NULL, return;);
 
        /* Start out with the maximum QoS support possible */
-       irda_init_max_qos_capabilies( &self->qos_rx);
+       irda_init_max_qos_capabilies(&self->qos_rx);
 
 #ifdef CONFIG_IRDA_COMPRESSION
-       irlap_init_comp_qos_capabilities( self);
+       irlap_init_comp_qos_capabilities(self);
 #endif
 
        /* Apply drivers QoS capabilities */
-       irda_qos_compute_intersection( &self->qos_rx, 
-                                      irda_device_get_qos( self->irdev));
+       irda_qos_compute_intersection(&self->qos_rx, 
+                                     irda_device_get_qos(self->irdev));
 
        /*
         *  Check for user supplied QoS parameters. The service user is only 
@@ -952,17 +952,17 @@ void irlap_init_qos_capabilities(struct irlap_cb *self,
         *  user may not have set all of them.
         */
        if (qos_user) {
-               DEBUG( 1, __FUNCTION__ "(), Found user specified QoS!\n");
+               DEBUG(1, __FUNCTION__ "(), Found user specified QoS!\n");
 
-               if ( qos_user->baud_rate.bits)
+               if (qos_user->baud_rate.bits)
                        self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
 
-               if ( qos_user->max_turn_time.bits)
+               if (qos_user->max_turn_time.bits)
                        self->qos_rx.max_turn_time.bits &= qos_user->max_turn_time.bits;
-               if ( qos_user->data_size.bits)
+               if (qos_user->data_size.bits)
                        self->qos_rx.data_size.bits &= qos_user->data_size.bits;
 
-               if ( qos_user->link_disc_time.bits)
+               if (qos_user->link_disc_time.bits)
                        self->qos_rx.link_disc_time.bits &= qos_user->link_disc_time.bits;
 #ifdef CONFIG_IRDA_COMPRESSION
                self->qos_rx.compression.bits &= qos_user->compression.bits;
@@ -984,7 +984,7 @@ void irlap_init_qos_capabilities(struct irlap_cb *self,
        /* Set disconnect time */
        self->qos_rx.link_disc_time.bits &= 0x07;
 
-       irda_qos_bits_to_value( &self->qos_rx);
+       irda_qos_bits_to_value(&self->qos_rx);
 }
 
 /*
@@ -993,14 +993,14 @@ void irlap_init_qos_capabilities(struct irlap_cb *self,
  *    Use the default connection and transmission parameters
  * 
  */
-void irlap_apply_default_connection_parameters( struct irlap_cb *self)
+void irlap_apply_default_connection_parameters(struct irlap_cb *self)
 {
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
-       irlap_change_speed( self, 9600);
+       irlap_change_speed(self, 9600);
 
        /* Default value in NDM */
        self->bofs_count = 11;
@@ -1028,12 +1028,12 @@ void irlap_apply_default_connection_parameters( struct irlap_cb *self)
 void irlap_apply_connection_parameters(struct irlap_cb *self, 
                                       struct qos_info *qos) 
 {
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
-       irlap_change_speed( self, qos->baud_rate.value);
+       irlap_change_speed(self, qos->baud_rate.value);
 
        self->window_size = qos->window_size.value;
        self->window      = qos->window_size.value;
@@ -1045,7 +1045,7 @@ void irlap_apply_connection_parameters(struct irlap_cb *self,
         */
        self->window_bytes = qos->baud_rate.value 
                * qos->max_turn_time.value / 10000;
-       DEBUG( 4, "Setting window_bytes = %d\n", self->window_bytes);
+       DEBUG(4, "Setting window_bytes = %d\n", self->window_bytes);
 
        /*
         *  Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to 
@@ -1058,10 +1058,10 @@ void irlap_apply_connection_parameters(struct irlap_cb *self,
        else
                self->N1 = 3000 / qos->max_turn_time.value;
        
-       DEBUG( 4, "Setting N1 = %d\n", self->N1);
+       DEBUG(4, "Setting N1 = %d\n", self->N1);
        
        self->N2 = qos->link_disc_time.value * 1000 / qos->max_turn_time.value;
-       DEBUG( 4, "Setting N2 = %d\n", self->N2);
+       DEBUG(4, "Setting N2 = %d\n", self->N2);
 
        /* 
         *  Initialize timeout values, some of the rules are listed on 
@@ -1072,11 +1072,11 @@ void irlap_apply_connection_parameters(struct irlap_cb *self,
        self->wd_timeout = self->poll_timeout * 2;
 
 #ifdef CONFIG_IRDA_COMPRESSION
-       if ( qos->compression.value) {
-               DEBUG( 1, __FUNCTION__ "(), Initializing compression\n");
-               irda_set_compression( self, qos->compression.value);
+       if (qos->compression.value) {
+               DEBUG(1, __FUNCTION__ "(), Initializing compression\n");
+               irda_set_compression(self, qos->compression.value);
 
-               irlap_compressor_init( self, 0);
+               irlap_compressor_init(self, 0);
        }
 #endif
 }
@@ -1088,7 +1088,7 @@ void irlap_apply_connection_parameters(struct irlap_cb *self,
  *    Give some info to the /proc file system
  *
  */
-int irlap_proc_read( char *buf, char **start, off_t offset, int len, 
+int irlap_proc_read(char *buf, char **start, off_t offset, int len, 
                     int unused)
 {
        struct irlap_cb *self;
@@ -1100,81 +1100,81 @@ int irlap_proc_read( char *buf, char **start, off_t offset, int len,
 
        len = 0;
 
-       self = (struct irlap_cb *) hashbin_get_first( irlap);
-       while ( self != NULL) {
-               ASSERT( self != NULL, return -ENODEV;);
-               ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+       self = (struct irlap_cb *) hashbin_get_first(irlap);
+       while (self != NULL) {
+               ASSERT(self != NULL, return -ENODEV;);
+               ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
 
-               len += sprintf( buf+len, "irlap%d <-> %s ",
+               len += sprintf(buf+len, "irlap%d <-> %s ",
                                i++, self->irdev->name);
-               len += sprintf( buf+len, "state: %s\n", 
+               len += sprintf(buf+len, "state: %s\n", 
                                irlap_state[ self->state]);
                
-               len += sprintf( buf+len, "  caddr: %#02x, ", self->caddr);
-               len += sprintf( buf+len, "saddr: %#08x, ", self->saddr);
-               len += sprintf( buf+len, "daddr: %#08x\n", self->daddr);
+               len += sprintf(buf+len, "  caddr: %#02x, ", self->caddr);
+               len += sprintf(buf+len, "saddr: %#08x, ", self->saddr);
+               len += sprintf(buf+len, "daddr: %#08x\n", self->daddr);
                
-               len += sprintf( buf+len, "  win size: %d, ", 
+               len += sprintf(buf+len, "  win size: %d, ", 
                                self->window_size);
-               len += sprintf( buf+len, "win: %d, ", self->window);
-               len += sprintf( buf+len, "win bytes: %d, ", self->window_bytes);
-               len += sprintf( buf+len, "bytes left: %d\n", self->bytes_left);
-
-               len += sprintf( buf+len, "  tx queue len: %d ", 
-                               skb_queue_len( &self->tx_list));
-               len += sprintf( buf+len, "win queue len: %d ", 
-                               skb_queue_len( &self->wx_list));
-               len += sprintf( buf+len, "rbusy: %s\n", self->remote_busy ? 
+               len += sprintf(buf+len, "win: %d, ", self->window);
+               len += sprintf(buf+len, "win bytes: %d, ", self->window_bytes);
+               len += sprintf(buf+len, "bytes left: %d\n", self->bytes_left);
+
+               len += sprintf(buf+len, "  tx queue len: %d ", 
+                               skb_queue_len(&self->tx_list));
+               len += sprintf(buf+len, "win queue len: %d ", 
+                               skb_queue_len(&self->wx_list));
+               len += sprintf(buf+len, "rbusy: %s\n", self->remote_busy ? 
                                "TRUE" : "FALSE");
                
-               len += sprintf( buf+len, "  retrans: %d ", self->retry_count);
-               len += sprintf( buf+len, "vs: %d ", self->vs);
-               len += sprintf( buf+len, "vr: %d ", self->vr);
-               len += sprintf( buf+len, "va: %d\n", self->va);
+               len += sprintf(buf+len, "  retrans: %d ", self->retry_count);
+               len += sprintf(buf+len, "vs: %d ", self->vs);
+               len += sprintf(buf+len, "vr: %d ", self->vr);
+               len += sprintf(buf+len, "va: %d\n", self->va);
                
-               len += sprintf( buf+len, "  qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
+               len += sprintf(buf+len, "  qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
                
-               len += sprintf( buf+len, "  tx\t%d\t", 
+               len += sprintf(buf+len, "  tx\t%d\t", 
                                self->qos_tx.baud_rate.value);
-               len += sprintf( buf+len, "%d\t", 
+               len += sprintf(buf+len, "%d\t", 
                                self->qos_tx.max_turn_time.value);
-               len += sprintf( buf+len, "%d\t",
+               len += sprintf(buf+len, "%d\t",
                                self->qos_tx.data_size.value);
-               len += sprintf( buf+len, "%d\t",
+               len += sprintf(buf+len, "%d\t",
                                self->qos_tx.window_size.value);
-               len += sprintf( buf+len, "%d\t",
+               len += sprintf(buf+len, "%d\t",
                                self->qos_tx.additional_bofs.value);
-               len += sprintf( buf+len, "%d\t", 
+               len += sprintf(buf+len, "%d\t", 
                                self->qos_tx.min_turn_time.value);
-               len += sprintf( buf+len, "%d\t", 
+               len += sprintf(buf+len, "%d\t", 
                                self->qos_tx.link_disc_time.value);
 #ifdef CONFIG_IRDA_COMPRESSION
-               len += sprintf( buf+len, "%d",
+               len += sprintf(buf+len, "%d",
                                self->qos_tx.compression.value);
 #endif
-               len += sprintf( buf+len, "\n");
+               len += sprintf(buf+len, "\n");
 
-               len += sprintf( buf+len, "  rx\t%d\t", 
+               len += sprintf(buf+len, "  rx\t%d\t", 
                                self->qos_rx.baud_rate.value);
-               len += sprintf( buf+len, "%d\t", 
+               len += sprintf(buf+len, "%d\t", 
                                self->qos_rx.max_turn_time.value);
-               len += sprintf( buf+len, "%d\t",
+               len += sprintf(buf+len, "%d\t",
                                self->qos_rx.data_size.value);
-               len += sprintf( buf+len, "%d\t",
+               len += sprintf(buf+len, "%d\t",
                                self->qos_rx.window_size.value);
-               len += sprintf( buf+len, "%d\t",
+               len += sprintf(buf+len, "%d\t",
                                self->qos_rx.additional_bofs.value);
-               len += sprintf( buf+len, "%d\t", 
+               len += sprintf(buf+len, "%d\t", 
                                self->qos_rx.min_turn_time.value);
-               len += sprintf( buf+len, "%d\t", 
+               len += sprintf(buf+len, "%d\t", 
                                self->qos_rx.link_disc_time.value);
 #ifdef CONFIG_IRDA_COMPRESSION
-               len += sprintf( buf+len, "%d",
+               len += sprintf(buf+len, "%d",
                                self->qos_rx.compression.value);
 #endif
-               len += sprintf( buf+len, "\n");
+               len += sprintf(buf+len, "\n");
                
-               self = (struct irlap_cb *) hashbin_get_next( irlap);
+               self = (struct irlap_cb *) hashbin_get_next(irlap);
        }
        restore_flags(flags);
 
index 936401339cfd4c70d64ac429e3f278037136edd3..aeb8ff6788798f026165eba0fa4d8da9f941e864 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Sun May  9 22:44:32 1999
+ * Modified at:   Mon May 31 21:55:42 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
@@ -209,8 +209,8 @@ void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
  *    Rushes through the state machine without any delay. If state == XMIT
  *    then send queued data frames. 
  */
-void irlap_do_event( struct irlap_cb *self, IRLAP_EVENT event, 
-                    struct sk_buff *skb, struct irlap_info *info) 
+void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, 
+                   struct sk_buff *skb, struct irlap_info *info) 
 {
        int ret;
        
@@ -218,7 +218,7 @@ void irlap_do_event( struct irlap_cb *self, IRLAP_EVENT event,
                return;
        
        DEBUG(4, __FUNCTION__ "(), event = %s, state = %s\n", 
-             irlap_event[ event], irlap_state[ self->state]); 
+             irlap_event[event], irlap_state[self->state]); 
        
        ret = (*state[ self->state]) (self, event, skb, info);
        
@@ -236,13 +236,12 @@ void irlap_do_event( struct irlap_cb *self, IRLAP_EVENT event,
                if (skb_queue_len(&self->tx_list)) {
                        /* Try to send away all queued data frames */
                        while ((skb = skb_dequeue(&self->tx_list)) != NULL) {
-                               ret = (*state[ self->state])(self, SEND_I_CMD,
-                                                            skb, NULL);
+                               ret = (*state[self->state])(self, SEND_I_CMD,
+                                                           skb, NULL);
                                if ( ret == -EPROTO)
                                        break; /* Try again later! */
                        }
                } else if (self->disconnect_pending) {
-                       DEBUG(0, __FUNCTION__ "(), disconnecting!\n");
                        self->disconnect_pending = FALSE;
                        
                        ret = (*state[self->state])(self, DISCONNECT_REQUEST,
@@ -761,36 +760,30 @@ static int irlap_state_offline( struct irlap_cb *self, IRLAP_EVENT event,
  *    stations.
  * 
  */
-static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event, 
-                              struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, 
+                             struct sk_buff *skb, struct irlap_info *info) 
 {
        int ret = 0;
        
-       ASSERT( self != NULL, return -ENODEV;);
-       ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
-
-       DEBUG( 4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d", 
-              irlap_event[ event], self->vs, self->vr); 
+       DEBUG(4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d", 
+             irlap_event[event], self->vs, self->vr);
                
        switch (event) {
        case SEND_I_CMD:
-               ASSERT( skb != NULL, return -1;);
-               DEBUG( 4, __FUNCTION__ "(), Window=%d\n", self->window);
-               
                /*
                 *  Only send frame if send-window > 0.
                 */ 
-               if (( self->window > 0) && ( !self->remote_busy)) {
+               if ((self->window > 0) && (!self->remote_busy)) {
 
                        /*
                         *  Test if we have transmitted more bytes over the 
                         *  link than its possible to do with the current 
                         *  speed and turn-around-time.
                         */
-                       if (( skb->len+self->bofs_count) > self->bytes_left) {
-                               DEBUG( 4, __FUNCTION__ "(), Not allowed to "
-                                      "transmit more bytes!\n");
-                               skb_queue_head( &self->tx_list, skb);
+                       if ((skb->len+self->bofs_count) > self->bytes_left) {
+                               DEBUG(4, __FUNCTION__ "(), Not allowed to "
+                                     "transmit more bytes!\n");
+                               skb_queue_head(&self->tx_list, skb);
 
                                /*
                                 *  We should switch state to LAP_NRM_P, but
@@ -802,7 +795,7 @@ static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event,
                                 */
                                return -EPROTO;
                        }
-                       self->bytes_left -= ( skb->len + self->bofs_count);
+                       self->bytes_left -= (skb->len + self->bofs_count);
 
                        /*
                         *  Send data with poll bit cleared only if window > 1
@@ -811,11 +804,9 @@ static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event,
                        if (( self->window > 1) && 
                            skb_queue_len( &self->tx_list) > 0) 
                        {   
-                               DEBUG( 4, __FUNCTION__ "(), window > 1\n");
                                irlap_send_data_primary( self, skb);
                                irlap_next_state( self, LAP_XMIT_P);
                        } else {
-                               DEBUG( 4, __FUNCTION__ "(), window <= 1\n");
                                irlap_send_data_primary_poll( self, skb);
                                irlap_next_state( self, LAP_NRM_P);
                                
@@ -933,9 +924,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
        int ns_status;
        int nr_status;
 
-       ASSERT(self != NULL, return -1;);
-       ASSERT(self->magic == LAP_MAGIC, return -1;);
-
        switch (event) {
        case RECV_I_RSP: /* Optimize for the common case */
                /* FIXME: must check for remote_busy below */
@@ -947,7 +935,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
                 */
                self->fast_RR = FALSE;
 #endif
-
                ASSERT( info != NULL, return -1;);
 
                ns_status = irlap_validate_ns_received(self, info->ns);
@@ -1141,13 +1128,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
                }
                break;
        case RECV_RR_RSP:
-               DEBUG(4, __FUNCTION__ "(), RECV_RR_FRAME: "
-                     "Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n",
-                     self->retry_count, info->nr, self->va, self->vs, 
-                     self->vr);
-
-               ASSERT(info != NULL, return -1;);
-
                /*  
                 *  If you get a RR, the remote isn't busy anymore, 
                 *  no matter what the NR 
@@ -1194,14 +1174,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
                        /* Resend rejected frames */
                        irlap_resend_rejected_frames( self, CMD_FRAME);
                        
-                       /*
-                        *  Start only if not running, DB
-                        *  TODO: Should this one be here?
-                        */
-                       /* if ( !self->final_timer.prev) */
-/*                             irda_start_timer( FINAL_TIMER, self->final_timeout);  */
-
-                       /* Keep state */
                        irlap_next_state( self, LAP_NRM_P);
                } else if (ret == NR_INVALID) {
                        DEBUG(1, "irlap_state_nrm_p: received RR with "
@@ -1210,8 +1182,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
 
                        irlap_next_state( self, LAP_RESET_WAIT);
 
-                       irlap_disconnect_indication( self, 
-                                                    LAP_RESET_INDICATION);
+                       irlap_disconnect_indication(self, LAP_RESET_INDICATION);
                        self->xmitflag = TRUE;
                }
                if (skb)
@@ -1479,13 +1450,13 @@ static int irlap_state_xmit_s( struct irlap_cb *self, IRLAP_EVENT event,
                /*
                 *  Send frame only if send window > 1
                 */ 
-               if (( self->window > 0) && ( !self->remote_busy)) {
+               if ((self->window > 0) && ( !self->remote_busy)) {
                        /*
                         *  Test if we have transmitted more bytes over the 
                         *  link than its possible to do with the current 
                         *  speed and turn-around-time.
                         */
-                       if (( skb->len+self->bofs_count) > self->bytes_left) {
+                       if ((skb->len+self->bofs_count) > self->bytes_left) {
                                DEBUG( 4, "IrDA: Not allowed to transmit more bytes!\n");
                                skb_queue_head( &self->tx_list, skb);
                                /*
@@ -1507,11 +1478,9 @@ static int irlap_state_xmit_s( struct irlap_cb *self, IRLAP_EVENT event,
                        if (( self->window > 1) && 
                            skb_queue_len( &self->tx_list) > 0) 
                        {   
-                               DEBUG( 4, __FUNCTION__ "(), window > 1\n");
                                irlap_send_data_secondary( self, skb);
                                irlap_next_state( self, LAP_XMIT_S);
                        } else {
-                               DEBUG( 4, "(), window <= 1\n");
                                irlap_send_data_secondary_final( self, skb);
                                irlap_next_state( self, LAP_NRM_S);
 
@@ -1635,8 +1604,7 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event,
                /*
                 *  Check for Unexpected next to send (Ns)
                 */
-               if (( ns_status == NS_UNEXPECTED) && 
-                   ( nr_status == NR_EXPECTED)) 
+               if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
                {
                        /* Unexpected next to send, with final bit cleared */
                        if ( !info->pf) {
@@ -1659,8 +1627,7 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event,
                /* 
                 *  Unexpected Next to Receive(NR) ?
                 */
-               if (( ns_status == NS_EXPECTED) && 
-                   ( nr_status == NR_UNEXPECTED))
+               if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
                {
                        if ( info->pf) {
                                DEBUG( 4, "RECV_I_RSP: frame(s) lost\n");
@@ -1756,20 +1723,20 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event,
                                irlap_update_nr_received( self, info->nr);
                                del_timer( &self->wd_timer);
                                
-                               irlap_wait_min_turn_around( self, &self->qos_tx);
+                               irlap_wait_min_turn_around(self, &self->qos_tx);
                                irlap_next_state( self, LAP_XMIT_S);
                        } else {                        
                                self->remote_busy = FALSE;
                                /* Update Nr received */
-                               irlap_update_nr_received( self, info->nr);
-                               irlap_wait_min_turn_around( self, &self->qos_tx);
+                               irlap_update_nr_received(self, info->nr);
+                               irlap_wait_min_turn_around(self, &self->qos_tx);
                                
-                               irlap_send_rr_frame( self, RSP_FRAME);
+                               irlap_send_rr_frame(self, RSP_FRAME);
                                
-                               irlap_start_wd_timer( self, self->wd_timeout);
-                               irlap_next_state( self, LAP_NRM_S);
+                               irlap_start_wd_timer(self, self->wd_timeout);
+                               irlap_next_state(self, LAP_NRM_S);
                        }
-               } else if ( nr_status == NR_UNEXPECTED) {
+               } else if (nr_status == NR_UNEXPECTED) {
                        self->remote_busy = FALSE;
                        irlap_update_nr_received( self, info->nr);
                        irlap_resend_rejected_frames( self, RSP_FRAME);
@@ -1781,8 +1748,8 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event,
                } else {
                        DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
                } 
-               if ( skb)
-                       dev_kfree_skb( skb);
+               if (skb)
+                       dev_kfree_skb(skb);
 
                break;
        case RECV_SNRM_CMD:
@@ -1894,7 +1861,7 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event,
        ASSERT( self != NULL, return -ENODEV;);
        ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
        
-       switch( event) {
+       switch(event) {
        case RESET_RESPONSE:
                irlap_send_ua_response_frame( self, &self->qos_rx);
                irlap_initiate_connection_state( self);
index 8ffd26a6e051807f10ad8d906ceda709cf0edafe..3011284d12a59cec909094cabb83c42534b9939a 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Sun May  9 22:55:11 1999
+ * Modified at:   Mon May 31 09:29:13 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
@@ -1001,10 +1001,6 @@ void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb,
 {
        __u8  *frame;
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
-
        frame = skb->data;
        
        /* Insert connection address */
@@ -1014,15 +1010,6 @@ void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb,
        /* Insert next to receive (Vr) */
        frame[1] |= (self->vr << 5);  /* insert nr */
 
-#if 0
-       {
-               int ns;
-               ns = (frame[1] >> 1) & 0x07; /* Next to send */
-
-               DEBUG(0, __FUNCTION__ "(), ns=%d\n", ns);
-       }
-#endif
-
        irlap_queue_xmit(self, skb);
 }
 
@@ -1240,7 +1227,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct device *dev,
         *  Optimize for the common case and check if the frame is an
         *  I(nformation) frame. Only I-frames have bit 0 set to 0
         */
-       if(~control & 0x01) {
+       if (~control & 0x01) {
                irlap_recv_i_frame(self, skb, &info, command);
                self->stats.rx_packets++;
                return 0;
index f4d4608cb9dc9e6469ec8e9d74ca9c51d810bfcd..7df849c2a14d05c2a4c544f3430a4bc60efca3bf 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Sun May  9 22:45:06 1999
+ * Modified at:   Mon May 31 21:49:41 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -451,17 +451,16 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
        ASSERT(skb != NULL, return;);
        ASSERT(self->lap != NULL, return;);
 
-       DEBUG(0, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+       DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
              self->slsap_sel, self->dlsap_sel);
 
        self->qos = *self->lap->qos;
 
-       lap_header_size = irlap_get_header_size(self->lap->irlap);
-
-       max_seg_size = self->lap->qos->data_size.value-LMP_HEADER-
-               lap_header_size;
+       max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
        DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
        
+       lap_header_size = irlap_get_header_size(self->lap->irlap);
+
        max_header_size = LMP_HEADER + lap_header_size;
 
        DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", max_header_size);
@@ -519,11 +518,10 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
        ASSERT(self->lap != NULL, return;);
        self->qos = *self->lap->qos;
 
-       lap_header_size = irlap_get_header_size(self->lap->irlap);
-
-       max_seg_size = self->lap->qos->data_size.value-LMP_HEADER-
-               lap_header_size;
+       max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
        DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
+
+       lap_header_size = irlap_get_header_size(self->lap->irlap);
        
        max_header_size = LMP_HEADER + lap_header_size;
 
index ff396c4ff7bdcddd0adceab3ad84f4691793a1b3..95a707a7f988405b2f670b45e8fef7e7b3abcd97 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 02:09:59 1997
- * Modified at:   Sun May  9 21:00:05 1999
+ * Modified at:   Mon May 31 09:53:16 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
@@ -134,17 +134,17 @@ void irlmp_link_data_indication(struct lap_cb *self, int reliable,
                                       self->lsaps);
        
        if (lsap == NULL) {
-               DEBUG(0, "IrLMP, Sorry, no LSAP for received frame!\n");
-               DEBUG(0, __FUNCTION__ 
+               DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
+               DEBUG(2, __FUNCTION__ 
                      "(), slsap_sel = %02x, dlsap_sel = %02x\n", slsap_sel, 
                      dlsap_sel);
                if (fp[0] & CONTROL_BIT) {
-                       DEBUG(0, __FUNCTION__ 
+                       DEBUG(2, __FUNCTION__ 
                              "(), received control frame %02x\n", fp[2]);
                } else {
-                       DEBUG(0, __FUNCTION__ "(), received data frame\n");
+                       DEBUG(2, __FUNCTION__ "(), received data frame\n");
                }
-               dev_kfree_skb( skb);
+               dev_kfree_skb(skb);
                return;
        }
 
index 445a645a052b71d850ec44ea0ac31f48764b3b0a..ab7354e1d2dace4dbbc40fda2ecd867179302a21 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:55:39 1997
- * Modified at:   Mon May 10 15:28:49 1999
+ * Modified at:   Fri May 14 13:46:02 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
@@ -45,7 +45,7 @@
 #include <net/irda/wrapper.h>
 #include <net/irda/timer.h>
 
-extern struct proc_dir_entry proc_irda;
+extern struct proc_dir_entry *proc_irda;
 
 struct irda_cb irda; /* One global instance */
 
index 23b2a256e94553d5a54b6e6444eb61ef8ccffca3..8d5e31f4135753432190d42c0205566e478c9aee 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Mon May 10 17:12:53 1999
+ * Modified at:   Mon May 31 10:29:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -35,7 +35,7 @@
 #include <net/irda/irlmp.h>
 #include <net/irda/irttp.h>
 
-struct irttp_cb *irttp = NULL;
+static struct irttp_cb *irttp = NULL;
 
 static void __irttp_close_tsap(struct tsap_cb *self);
 
@@ -44,8 +44,7 @@ static int irttp_data_indication(void *instance, void *sap,
 static int irttp_udata_indication(void *instance, void *sap, 
                                  struct sk_buff *skb);
 static void irttp_disconnect_indication(void *instance, void *sap,  
-                                       LM_REASON reason,
-                                       struct sk_buff *);
+                                       LM_REASON reason, struct sk_buff *);
 static void irttp_connect_indication(void *instance, void *sap, 
                                     struct qos_info *qos, __u32 max_sdu_size,
                                     __u8 header_size, struct sk_buff *skb);
@@ -57,8 +56,8 @@ static void irttp_run_rx_queue(struct tsap_cb *self);
 
 static void irttp_flush_queues(struct tsap_cb *self);
 static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
 static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
+static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
 
 /*
  * Function irttp_init (void)
@@ -298,7 +297,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
 
        /* Check that nothing bad happens */
        if ((skb->len == 0) || (!self->connected)) {
-               DEBUG(4, __FUNCTION__ "(), No data, or not connected\n");
+               ERROR(__FUNCTION__ "(), No data, or not connected\n");
                return -ENOTCONN;
        }
 
@@ -307,8 +306,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
         *  inside an IrLAP frame
         */
        if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
-               DEBUG(1, __FUNCTION__ 
-                      "(), SAR disabled, and data is to large for IrLAP!\n");
+               ERROR(__FUNCTION__ 
+                     "(), SAR disabled, and data is to large for IrLAP!\n");
                return -EMSGSIZE;
        }
 
@@ -320,8 +319,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
            (self->tx_max_sdu_size != SAR_UNBOUND) && 
            (skb->len > self->tx_max_sdu_size))
        {
-               DEBUG(1, __FUNCTION__ "(), SAR enabled, "
-                      "but data is larger than TxMaxSduSize!\n");
+               ERROR(__FUNCTION__ "(), SAR enabled, "
+                     "but data is larger than TxMaxSduSize!\n");
                return -EMSGSIZE;
        }
        /* 
@@ -343,7 +342,6 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
                frame = skb_push(skb, TTP_HEADER);
                frame[0] = 0x00; /* Clear more bit */
                
-               DEBUG(4, __FUNCTION__ "(), queueing original skb\n");
                skb_queue_tail(&self->tx_queue, skb);
        } else {
                /*
@@ -384,12 +382,8 @@ static void irttp_run_tx_queue(struct tsap_cb *self)
 {
        struct sk_buff *skb = NULL;
        unsigned long flags;
-       __u8 *frame;
        int n;
 
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-       
        if (irda_lock(&self->tx_queue_lock) == FALSE)
                return;
 
@@ -424,12 +418,7 @@ static void irttp_run_tx_queue(struct tsap_cb *self)
                 *  More bit must be set by the data_request() or fragment() 
                 *  functions
                 */
-               frame = skb->data;
-
-               DEBUG(4, __FUNCTION__ "(), More=%s\n", frame[0] & 0x80 ? 
-                      "TRUE" : "FALSE" );
-
-               frame[0] |= (__u8) (n & 0x7f);
+               skb->data[0] |= (n & 0x7f);
                
                irlmp_data_request(self->lsap, skb);
                self->stats.tx_packets++;
@@ -437,12 +426,12 @@ static void irttp_run_tx_queue(struct tsap_cb *self)
                /* Check if we can accept more frames from client */
                if ((self->tx_sdu_busy) && 
                    (skb_queue_len(&self->tx_queue) < LOW_THRESHOLD)) 
-               { 
+               {
                        self->tx_sdu_busy = FALSE;
                        
                        if (self->notify.flow_indication)
                                self->notify.flow_indication(
-                                       self->notify.instance, self, 
+                                       self->notify.instance, self,
                                        FLOW_START);
                }
        }
@@ -541,23 +530,14 @@ static int irttp_data_indication(void *instance, void *sap,
                                 struct sk_buff *skb)
 {
        struct tsap_cb *self;
-       int more;
        int n;
-       __u8 *frame;
-       
+
        self = (struct tsap_cb *) instance;
 
        ASSERT(self != NULL, return -1;);
        ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-       ASSERT(skb != NULL, return -1;);
 
-       frame = skb->data;
-       
-       n = frame[0] & 0x7f;     /* Extract the credits */
-       more = frame[0] & 0x80;
-
-       DEBUG(3, __FUNCTION__"(), got %d credits, TSAP sel=%02x\n", 
-             n, self->stsap_sel);
+       n = skb->data[0] & 0x7f;     /* Extract the credits */
 
        self->stats.rx_packets++;
 
@@ -565,10 +545,9 @@ static int irttp_data_indication(void *instance, void *sap,
         *  Data or dataless frame? Dataless frames only contain the 
         *  TTP_HEADER
         */
-       if (skb->len == 1) {
-               /* Dataless flowdata TTP-PDU */
-               self->send_credit += n;
-       } else {
+       if (skb->len == 1)
+               self->send_credit += n; /* Dataless flowdata TTP-PDU */
+       else {
                /* Deal with inbound credit */
                self->send_credit += n;
                self->remote_credit--;
@@ -768,6 +747,10 @@ static void irttp_connect_confirm(void *instance, void *sap,
        self->connected = TRUE;
 
        parameters = frame[0] & 0x80;   
+
+       ASSERT(skb->len >= TTP_HEADER, return;);
+       skb_pull(skb, TTP_HEADER);
+               
        if (parameters) {
                plen = frame[1];
                pi   = frame[2];
@@ -793,13 +776,15 @@ static void irttp_connect_confirm(void *instance, void *sap,
 
                DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n", 
                      self->tx_max_sdu_size);
+               
+               /* Remove parameters */
+               ASSERT(skb->len >= (plen+1), return;);
+               skb_pull(skb, plen+1);
        }
        
        DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
              self->send_credit, self->avail_credit, self->remote_credit);
 
-       skb_pull(skb, TTP_HEADER);
-
        if (self->notify.connect_confirm) {
                self->notify.connect_confirm(self->notify.instance, self, qos,
                                             self->tx_max_sdu_size, 
@@ -814,7 +799,7 @@ static void irttp_connect_confirm(void *instance, void *sap,
  *
  */
 void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
-                             __u32 max_seg_size,  __u8 max_header_size, 
+                             __u32 max_seg_size, __u8 max_header_size, 
                              struct sk_buff *skb) 
 {
        struct tsap_cb *self;
@@ -847,7 +832,11 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
        self->send_credit = n;
        self->tx_max_sdu_size = 0;
        
-       parameters = frame[0] & 0x80;   
+       parameters = frame[0] & 0x80;
+
+       ASSERT(skb->len >= TTP_HEADER, return;);
+       skb_pull(skb, TTP_HEADER);
+               
        if (parameters) {
                DEBUG(3, __FUNCTION__ "(), Contains parameters!\n");
                plen = frame[1];
@@ -871,7 +860,10 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
                               "() illegal value length for max_sdu_size!\n");
                        self->tx_max_sdu_size = 0;
                };
-
+               
+               /* Remove parameters */
+               ASSERT(skb->len >= (plen+1), return;);
+               skb_pull(skb, plen+1);
 
                DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n", 
                      self->tx_max_sdu_size);
@@ -879,8 +871,6 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
 
        DEBUG(4, __FUNCTION__ "(), initial send_credit=%d\n", n);
 
-       skb_pull(skb, 1); /* Remove TTP header */
-
        if (self->notify.connect_indication) {
                self->notify.connect_indication(self->notify.instance, self, 
                                                qos, self->rx_max_sdu_size, 
@@ -1403,11 +1393,9 @@ static void irttp_todo_expired(unsigned long data)
        irttp_run_tx_queue(self);
 
        /*  Give avay some credits to peer?  */
-       if ((skb_queue_empty(&self->tx_queue)) && 
-           (self->remote_credit < LOW_THRESHOLD) && 
-           (self->avail_credit > 0)) 
+       if ((self->remote_credit < LOW_THRESHOLD) && 
+           (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
        {
-               DEBUG(4, __FUNCTION__ "(), sending credit!\n");
                irttp_give_credit(self);
        }
 
index b78368bc0e69c17d7da206ce9576c063fa75467f..70e6c3e73c820bc35b6c219ec76ed85be39bec96 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Sun May  2 21:58:00 1999
+ * Modified at:   Fri May 28 20:30:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -216,7 +216,7 @@ static void state_outside_frame(struct irda_device *idev, __u8 byte)
 /*
  * Function state_begin_frame (idev, byte)
  *
- *    
+ *    Begin of frame detected
  *
  */
 static void state_begin_frame(struct irda_device *idev, __u8 byte)
@@ -228,6 +228,10 @@ static void state_begin_frame(struct irda_device *idev, __u8 byte)
        case CE:
                /* Stuffed byte */
                idev->rx_buff.state = LINK_ESCAPE;
+
+               /* Time to initialize receive buffer */
+               idev->rx_buff.data = idev->rx_buff.head;
+               idev->rx_buff.len = 0;
                break;
        case EOF:
                /* Abort frame */
@@ -236,11 +240,11 @@ static void state_begin_frame(struct irda_device *idev, __u8 byte)
                idev->stats.rx_errors++;
                idev->stats.rx_frame_errors++;
                break;
-       default:
-               /* Got first byte of frame */
+       default:        
+               /* Time to initialize receive buffer */
                idev->rx_buff.data = idev->rx_buff.head;
                idev->rx_buff.len = 0;
-               
+
                idev->rx_buff.data[idev->rx_buff.len++] = byte;
                
                idev->rx_buff.fcs = irda_fcs(INIT_FCS, byte);
@@ -290,7 +294,7 @@ static void state_link_escape(struct irda_device *idev, __u8 byte)
 /*
  * Function state_inside_frame (idev, byte)
  *
- *    
+ *    Handle bytes received within a frame
  *
  */
 static void state_inside_frame(struct irda_device *idev, __u8 byte)