diff -u --recursive --new-file v2.2.9/linux/CREDITS linux/CREDITS
--- v2.2.9/linux/CREDITS	Tue May 11 13:10:26 1999
+++ linux/CREDITS	Wed Jun  9 22:23:01 1999
@@ -611,6 +611,13 @@
 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/
@@ -656,7 +663,7 @@
 E: rgooch@atnf.csiro.au
 D: parent process death signal to children
 D: prctl() syscall
-D: /proc/mtrr support to manipulate MTRRs on Pentium Pro's
+D: /proc/mtrr support to manipulate MTRRs on Intel P6 family
 S: CSIRO Australia Telescope National Facility
 S: P.O. Box 76, Epping
 S: New South Wales, 2121
@@ -754,6 +761,13 @@
 S: London SE16 1GD
 S: United Kingdom
 
+N: Bart Hartgers
+E: bart@etpmod.phys.tue.nl
+D: MTRR emulation with Centaur MCRs
+S: Gen Stedmanstraat 212
+S: 5623 HZ Eindhoven
+S: The Netherlands
+
 N: Kai Harrekilde-Petersen
 E: khp@dolphinics.no
 D: Original author of the ftape-HOWTO, i82078 fdc detection code.
@@ -801,7 +815,7 @@
 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
diff -u --recursive --new-file v2.2.9/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.2.9/linux/Documentation/Configure.help	Tue May 11 13:10:26 1999
+++ linux/Documentation/Configure.help	Wed Jun  9 16:59:34 1999
@@ -3749,34 +3749,49 @@
   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).
+  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 14 to 32 commands per 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 @@
   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
@@ -8684,6 +8713,9 @@
 
   The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
   MTRRs. These are supported.
+  
+  The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
+  are supported.
 
   Saying Y here also fixes a problem with buggy SMP BIOSes which only
   set the MTRRs for the boot CPU and not the secondary CPUs. This can
diff -u --recursive --new-file v2.2.9/linux/Documentation/isdn/CREDITS linux/Documentation/isdn/CREDITS
--- v2.2.9/linux/Documentation/isdn/CREDITS	Wed Apr  1 20:11:47 1998
+++ linux/Documentation/isdn/CREDITS	Wed Jun  2 11:29:27 1999
@@ -5,7 +5,7 @@
 Thomas Bogendörfer (tsbogend@bigbug.franken.de)
   Tester, lots of bugfixes and hints.
 
-Alan Cox (alan@cymru.net)
+Alan Cox (alan@redhat.com)
   For help getting into standard-kernel.
 
 Henner Eisen (eis@baty.hanse.de)
diff -u --recursive --new-file v2.2.9/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- v2.2.9/linux/Documentation/kernel-parameters.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/kernel-parameters.txt	Mon Jun  7 16:13:07 1999
@@ -0,0 +1,336 @@
+June 1999		  Kernel Parameters			v2.2.9
+			  ~~~~~~~~~~~~~~~~~
+
+The following is a consolidated list of the kernel parameters as defined
+in the file init/main.c and sorted into English Dictionary order (defined
+as ignoring all punctuation and sorting digits before letters in a case
+insensitive manner), and with descriptions where known.
+
+The text in square brackets at the beginning of the description state the
+restrictions on the kernel for the said kernel parameter to be valid. The
+restrictions referred to are that the relevant option is valid if:
+
+    APIC	APIC support is enabled.
+    APM 	Automatic Power Management support is enabled.
+    AX25	Appropriate AX.25 support is enabled.
+    CD		Appropriate CD support is enabled.
+    EIDE	EIDE/ATAPI support is enabled.
+    FB		The frame buffer device is enabled.
+    HW		Appropriate hardware is enabled.
+    ISDN	Appropriate ISDN support is enabled.
+    JOY 	Appropriate joystick support is enabled.
+    LPT 	Printer support is enabled.
+    MCA 	MCA bus support is enabled.
+    MDA 	The MDA console is enabled.
+    MOUSE	Appropriate mouse support is enabled.
+    NET 	Appropriate network support is enabled.
+    NFS 	Appropriate NFS support is enabled.
+    PARIDE	The ParIDE subsystem is enabled.
+    PCI 	PCI bus support is enabled.
+    PCMCIA	The PCMCIA subsystem is enabled.
+    PNP 	Plug & Play support is enabled.
+    PS2 	Appropriate PS/2 support is enabled.
+    RAM 	RAMdisc support is enabled.
+    SCSI	Appropriate SCSI support is enabled.
+    SERIAL	Serial support is enabled.
+    SMP 	The kernel is an SMP kernel.
+    SOUND	Appropriate sound system support is enabled.
+    VGA 	The VGA console has been enabled.
+    VT		Virtual terminal support is enabled.
+    XT		IBM PC/XT MFM hard disk support is enabled.
+
+In addition, the following text indicates that the option:
+
+    BUGS=	Relates to possible processor bugs on the said processor.
+    KNL 	Is a kernel start-up parameter.
+
+Note that ALL kernel parameters listed below are CASE SENSITIVE, and that
+a trailing = on the name of any parameter states that that parameter will
+be entered as an environment variable, whereas its absence indicates that
+it will appear as a kernel argument readable via /proc/cmdline by programs
+running once the system is up.
+
+    53c7xx=		[HW,SCSI]
+
+    adb_buttons=	[HW,MOUSE]
+
+    advansys=		[HW,SCSI]
+
+    aha152x=		[HW,SCSI]
+
+    aha1542=		[HW,SCSI]
+
+    aic7xxx=		[HW,SCSI]
+
+    AM53C974=		[HW,SCSI]
+
+    apm=		[APM] Automatic Power Management.
+
+    arcrimi=		[HW,NET]
+
+    atamouse=		[HW,MOUSE] Atari Mouse.
+
+    atascsi=		[HW,SCSI] Atari SCSI.
+
+    aztcd=		[HW,CD] Aztec CD driver.
+
+    baycom_par= 	[HW,AX25] BayCom Parallel Port AX.25 Modem.
+
+    baycom_ser_fdx=	[HW,AX25] BayCom Serial Port AX.25 Modem in Full
+			Duplex Mode.
+
+    baycom_ser_hdx=	[HW,AX25] BayCom Serial Port AX.25 Modem in Half
+			Duplex Mode.
+
+    bmouse=		[HW,MOUSE,PS2] Bus mouse.
+
+    BusLogic=		[HW,SCSI]
+
+    cdu31a=		[HW,CD]
+
+    cm206=		[HW,CD]
+
+    com20020=		[HW,NET]
+
+    com90io=		[HW,NET]
+
+    com90xx=		[HW,NET]
+
+    console=		
+
+    cyclades=		[HW,SERIAL] Cyclades multi-serial port adapter.
+
+    debug		[KNL] Enable kernel debugging.
+
+    decnet=		[HW,NET]
+
+    digi=		[HW,SERIAL]
+
+    digiepca=		[HW,SERIAL]
+
+    dmascc=		[HW,AX25,SERIAL] AX.25 Z80SCC driver with DMA
+			support available.
+
+    dmasound=		[HW,SOUND]
+
+    dtc3181e=		[HW,SCSI]
+
+    eata=		[HW,SCSI]
+
+    eda=		[HW,PS2]
+
+    edb=		[HW,PS2]
+
+    ether=		[HW,NET] Ethernet.
+
+    fd_mcs=		[HW,SCSI]
+
+    fdomain=		[HW,SCSI]
+
+    floppy=		[HW]
+
+    ftape=		[HW] Floppy Tape subsystem.
+
+    gdth=		[HW,SCSI]
+
+    gscd=		[HW,CD]
+
+    gvp11=		[HW,SCSI]
+
+    hd= 		[EIDE] IDE and EIDE hard drive subsystem.
+
+    hfmodem=		[HW,AX25]
+
+    HiSax=		[HW,ISDN]
+
+    hisax=		[HW,ISDN]
+
+    ibmmcascsi= 	[HW,MCA,SCSI] IBM MicroChannel SCSI adapter.
+
+    icn=		[HW,ISDN]
+
+    in2000=		[HW,SCSI]
+
+    init=		[KNL]
+
+    ip= 		[PNP]
+
+    isp16=		[HW,CD]
+
+    js_14=		[HW,JOY]
+
+    js_am=		[HW,JOY]
+
+    js_an=		[HW,JOY]
+
+    js_as=		[HW.JOY]
+
+    js_console= 	[HW,JOY]
+
+    js_console2=	[HW,JOY]
+
+    js_console3=	[HW,JOY]
+
+    js_db9=		[HW,JOY]
+
+    js_db9_2=		[HW,JOY]
+
+    js_db9_3=		[HW,JOY]
+
+    js_tg=		[HW,JOY]
+
+    js_tg_2=		[HW,JOY]
+
+    js_tg_3=		[HW,JOY]
+
+    kbd-reset		[VT]
+
+    load_ramdisk=	[RAM]
+
+    lp= 		[LPT] Parallel Printer.
+
+    ltpc=		[HW]
+
+    mac5380=		[HW,SCSI]
+
+    maxcpus=		[SMP] States the maximum number of processors that
+			an SMP kernel should make use of.
+
+    max_scsi_luns=	[SCSI]
+
+    mca-pentium 	[BUGS=ix86]
+
+    mcd=		[HW,CD]
+
+    mcdx=		[HW,CD]
+
+    md= 		[HW]
+
+    mdacon=		[MDA]
+
+    msmouse=		[HW,MOUSE] Microsoft Mouse.
+
+    ncr5380=		[HW,SCSI]
+
+    ncr53c400=		[HW,SCSI]
+
+    ncr53c400a= 	[HW,SCSI]
+
+    ncr53c406a= 	[HW,SCSI]
+
+    ncr53c8xx=		[HW,SCSI]
+
+    nfsaddrs=		[NFS]
+
+    nfsroot=		[NFS]
+
+    no387		[BUGS=ix86] Tells the kernel to use the 387 maths
+			emulation library even if a 387 maths coprocessor
+			is present.
+
+    noapic		[SMP,APIC] Tells the kernel not to make use of any
+			APIC that may be present on the system.
+
+    no-halt		[BUGS=ix86]
+
+    noinitrd		[RAM] Tells the kernel not to load any configured
+			initial ramdisc.
+
+    no-scroll		[VGA]
+
+    nosmp		[SMP] Tells an SMP kernel to act as a UP kernel.
+
+    optcd=		[HW,CD]
+
+    panic=		
+
+    parport=		[HW,LP]
+
+    pas16=		[HW,SCSI]
+
+    pcbit=		[HW,ISDN]
+
+    pcd.		[PARIDE]
+
+    pci=		[PCI]
+
+    pd. 		[PARIDE]
+
+    pf. 		[PARIDE]
+
+    pg. 		[PARIDE]
+
+    pirq=		[SMP,APIC]
+
+    plip=		[LP,NET] Parallel port network link.
+
+    profile=
+
+    prompt_ramdisk=	[RAM] Whether to prompt for ramdisk before loading
+			its contents into memory.
+
+    pt. 		[PARIDE]
+
+    ramdisk=		[RAM]
+
+    ramdisk_size=	[RAM]
+
+    ramdisk_start=	[RAM]
+
+    reboot=		[BUGS=ix86]
+
+    reserve=
+
+    riscom8=		[HW,SERIAL]
+
+    ro			[KNL] Mount root device read-only on boot.
+
+    root=		
+
+    rw			[KNL] Mount root device read-write on boot.
+
+    sbpcd=		[HW,CD] Soundblaster CD adapter.
+
+    scsi_logging=	[SCSI]
+
+    sjcd=		[HW,CD]
+
+    sonycd535=		[HW,CD]
+
+    sound=		[SOUND]
+
+    soundmodem= 	[HW,AX25,SOUND] Sound cards used as AX.25 modems.
+
+    specialix=		[HW,SERIAL] Specialix multi-serial port adapter.
+
+    st= 		[HW]
+
+    st0x=		[HW,SCSI]
+
+    stram_swap= 	[HW]
+
+    sym53c416=		[HW,SCSI]
+
+    sym53c8xx=		[HW,SCSI]
+
+    t128=		[HW,SCSI]
+
+    tmc8xx=		[HW,SCSI]
+
+    tmscsim=		[HW,SCSI]
+
+    tp720=		[HW,PS2]
+
+    u14-34f=		[HW,SCSI]
+
+    video=		[FB]
+
+    wd33c93=		[HW,SCSI]
+
+    wd7000=		[HW,SCSI]
+
+    wdt=		[HW]
+
+    xd= 		[HW,XT]
+
+    xd_geo=		[HW,XT]
diff -u --recursive --new-file v2.2.9/linux/Documentation/networking/ethertap.txt linux/Documentation/networking/ethertap.txt
--- v2.2.9/linux/Documentation/networking/ethertap.txt	Sun Jun  7 11:16:26 1998
+++ linux/Documentation/networking/ethertap.txt	Mon Jun  7 16:13:07 1999
@@ -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 @@
 
         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
 
diff -u --recursive --new-file v2.2.9/linux/Documentation/networking/ltpc.txt linux/Documentation/networking/ltpc.txt
--- v2.2.9/linux/Documentation/networking/ltpc.txt	Thu Nov 19 09:56:27 1998
+++ linux/Documentation/networking/ltpc.txt	Mon Jun  7 16:13:07 1999
@@ -65,7 +65,7 @@
 
 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
diff -u --recursive --new-file v2.2.9/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt
--- v2.2.9/linux/Documentation/scsi-generic.txt	Wed Apr 28 11:37:29 1999
+++ linux/Documentation/scsi-generic.txt	Mon Jun  7 16:13:07 1999
@@ -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 @@
 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 @@
     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 @@
 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 @@
 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 @@
     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 @@
 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 @@
 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 @@
 #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 @@
 #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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 (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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 
 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
diff -u --recursive --new-file v2.2.9/linux/Documentation/sound/CMI8330 linux/Documentation/sound/CMI8330
--- v2.2.9/linux/Documentation/sound/CMI8330	Wed Mar 10 15:29:44 1999
+++ linux/Documentation/sound/CMI8330	Wed May 26 09:29:42 1999
@@ -1,46 +1,48 @@
-How to enable CMI 8330 soundchip on Linux
+How to enable CMI 8330 (SOUNDPRO) soundchip on Linux
 ------------------------------------------
 Stefan Laudat <Stefan.Laudat@asit.ro>
 
-Hello folks, 
-	
-	The CMI8330 soundchip is a very small chip found on many recent 
-	motherboards. In order to use it you just have to use a proper 
-        isapnp.conf and a little bit of patience. 
+[Note: The CMI 8338 is unrelated and right now unsupported]
+
 	
-	Of course you will have to compile kernel sound support as module, 
-        as shown below:
+	In order to use CMI8330 under Linux  you just have to use a proper isapnp.conf, a good isapnp and a little bit of patience.  I use isapnp 1.17, but
+you may get a better one I guess at http://www.roestock.demon.co.uk/isapnptools/.
+
+	Of course you will have to compile kernel sound support as module, as shown below:
 
 CONFIG_SOUND=m
 CONFIG_SOUND_OSS=m
 CONFIG_SOUND_SB=m
 CONFIG_SOUND_ADLIB=m
 CONFIG_SOUND_MPU401=m
-# Just for fun :)
+# Mikro$chaft sound system (kinda useful here ;))	
 CONFIG_SOUND_MSS=m
 
 	The /etc/isapnp.conf file will be:
 
 <snip below>
 
+
 (READPORT 0x0203)
 (ISOLATE PRESERVE)
 (IDENTIFY *)
 (VERBOSITY 2)
 (CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
 (VERIFYLD N)
+
+
 # WSS 
 
 (CONFIGURE CMI0001/16777472 (LD 0
 (IO 0 (SIZE 8) (BASE 0x0530))
 (IO 1 (SIZE 8) (BASE 0x0388))
-(INT 0 (IRQ 5 (MODE +E)))
+(INT 0 (IRQ 7 (MODE +E)))
 (DMA 0 (CHANNEL 0))
 (NAME "CMI0001/16777472[0]{CMI8330/C3D Audio Adapter}")
 (ACT Y)
 ))
 
-# Control device ? 
+# MPU
 
 (CONFIGURE CMI0001/16777472 (LD 1
 (IO 0 (SIZE 2) (BASE 0x0330))
@@ -57,10 +59,11 @@
 (ACT Y)
 ))
 
-#  SB... 
+# SoundBlaster 
+ 
 (CONFIGURE CMI0001/16777472 (LD 3
 (IO 0 (SIZE 16) (BASE 0x0220))
-(INT 0 (IRQ 7 (MODE +E)))
+(INT 0 (IRQ 5 (MODE +E)))
 (DMA 0 (CHANNEL 1))
 (DMA 1 (CHANNEL 5))
 (NAME "CMI0001/16777472[3]{CMI8330/C3D Audio Adapter}")
@@ -74,13 +77,22 @@
 
 	The module sequence is trivial:
 
-/sbin/modprobe sound
-# You need to load the ad1848 module first. That matters, otherwise the 
-# chip falls into soundblaster compatibility and you won't get it back out
-/sbin/insmod ad1848 io=0x530 dma=0 irq=5 soundpro=1
+/sbin/insmod soundcore
+/sbin/insmod sound
 /sbin/insmod uart401
-/sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1
-/sbin/insmod mpu401 io=0x330
-/sbin/insmod opl3 io=0x388
+# insert this first
+/sbin/insmod ad1848 io=0x530 irq=7 dma=0 soundpro=1
+# The sb module is an alternative to the ad1848 (Microsoft Sound System)
+# Anyhow, this is full duplex and has MIDI
+/sbin/insmod sb io=0x220 dma=1 dma16=5 irq=5 mpu_io=0x330
+
+
 
-	The soundchip is now fully initialized. Enjoy it.
+Alma Chao <elysian@ethereal.torsion.org> suggests the following /etc/conf.modules:
+
+alias sound ad1848
+alias synth0 opl3
+options ad1848 io=0x530 irq=7 dma=0 soundpro=1
+options opl3 io=0x388
+
+	
diff -u --recursive --new-file v2.2.9/linux/Documentation/svga.txt linux/Documentation/svga.txt
--- v2.2.9/linux/Documentation/svga.txt	Thu Jul 16 18:09:22 1998
+++ linux/Documentation/svga.txt	Fri May 14 12:47:07 1999
@@ -1,5 +1,5 @@
-		       Video Mode Selection Support 2.11
-	      (c) 1995--1997 Martin Mares, <mj@k332.feld.cvut.cz>
+		       Video Mode Selection Support 2.13
+		    (c) 1995--1999 Martin Mares, <mj@ucw.cz>
 --------------------------------------------------------------------------------
 
 1. Intro
@@ -9,6 +9,11 @@
 to usage of the BIOS, the selection is limited to boot time (before the
 kernel decompression starts) and works only on 80X86 machines.
 
+   **  Short intro for the impatient: Just use vga=ask for the first time,
+   **  enter `scan' on the video mode prompt, pick the mode you want to use,
+   **  remember its mode ID (the four-digit hexadecimal number) and then
+   **  set the vga parameter to this number (converted to decimal first).
+
    The video mode to be used is selected by a kernel parameter which can be
 specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..."
 option of LILO (or some other boot loader you use) or by the "vidmode" utility
@@ -268,3 +273,4 @@
 		- Removed the doc section describing adding of new probing
 		  functions as I try to get rid of _all_ hardware probing here.
 2.12 (25-May-98)- Added support for VESA frame buffer graphics.
+2.13 (14-May-99)- Minor documentation fixes.
diff -u --recursive --new-file v2.2.9/linux/Documentation/video4linux/API.html linux/Documentation/video4linux/API.html
--- v2.2.9/linux/Documentation/video4linux/API.html	Fri Jan  8 22:35:59 1999
+++ linux/Documentation/video4linux/API.html	Mon Jun  7 16:13:07 1999
@@ -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 @@
 </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 @@
 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 @@
 <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 @@
 <TR><TD><b>teletext</b><TD>Teletext device</TD>
 </TABLE>
 <P>
-
+<H3>RDS Datastreams</H3>
+For radio devices that support it, it is possible to receive Radio Data
+System (RDS) data by means of a read() on the device.  The data is packed in
+groups of three, as follows:
+<TABLE>
+<TR><TD>First Octet</TD><TD>Least Siginificant Byte of RDS Block</TD></TR>
+<TR><TD>Second Octet</TD><TD>Most Siginificant Byte of RDS Block
+<TR><TD>Third Octet</TD><TD>Bit 7:</TD><TD>Error bit.  Indicates that
+an uncorrectable error occured during reception of this block.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bit 6:</TD><TD>Corrected bit.  Indicates that  
+an error was corrected for this data block.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bits 5-3:</TD><TD>Reeived Offset.  Indicates the  
+offset received by the sync system.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bits 2-0:</TD><TD>Offset Name.  Indicates the  
+offset applied to this data.</TD></TR>
+</TABLE>
 </BODY>
 </HTML>
diff -u --recursive --new-file v2.2.9/linux/Documentation/video4linux/bttv/CONTRIBUTORS linux/Documentation/video4linux/bttv/CONTRIBUTORS
--- v2.2.9/linux/Documentation/video4linux/bttv/CONTRIBUTORS	Wed Aug 26 11:37:33 1998
+++ linux/Documentation/video4linux/bttv/CONTRIBUTORS	Wed Jun  2 11:29:27 1999
@@ -3,7 +3,7 @@
 Michael Chu <mmchu@pobox.com>
   AverMedia fix and more flexible card recognition
 
-Alan Cox <alan@cymru.net>
+Alan Cox <alan@redhat.com>
   Video4Linux interface and 2.1.x kernel adaptation
 
 Chris Kleitsch
diff -u --recursive --new-file v2.2.9/linux/Documentation/video4linux/bttv/PROBLEMS linux/Documentation/video4linux/bttv/PROBLEMS
--- v2.2.9/linux/Documentation/video4linux/bttv/PROBLEMS	Wed Aug 26 11:37:33 1998
+++ linux/Documentation/video4linux/bttv/PROBLEMS	Mon Jun  7 16:13:07 1999
@@ -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.
@@ -50,13 +50,13 @@
   
   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
diff -u --recursive --new-file v2.2.9/linux/Documentation/video4linux/bttv/README.RADIO linux/Documentation/video4linux/bttv/README.RADIO
--- v2.2.9/linux/Documentation/video4linux/bttv/README.RADIO	Wed Aug 26 11:37:33 1998
+++ linux/Documentation/video4linux/bttv/README.RADIO	Mon Jun  7 16:13:07 1999
@@ -6,7 +6,7 @@
 
 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 -u --recursive --new-file v2.2.9/linux/Documentation/video4linux/bttv/README.WINVIEW linux/Documentation/video4linux/bttv/README.WINVIEW
--- v2.2.9/linux/Documentation/video4linux/bttv/README.WINVIEW	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/bttv/README.WINVIEW	Mon Jun  7 16:13:07 1999
@@ -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
+
diff -u --recursive --new-file v2.2.9/linux/Documentation/video4linux/bttv/THANKS linux/Documentation/video4linux/bttv/THANKS
--- v2.2.9/linux/Documentation/video4linux/bttv/THANKS	Wed Aug 26 11:37:33 1998
+++ linux/Documentation/video4linux/bttv/THANKS	Mon Jun  7 16:13:07 1999
@@ -17,7 +17,7 @@
   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.
 
diff -u --recursive --new-file v2.2.9/linux/MAINTAINERS linux/MAINTAINERS
--- v2.2.9/linux/MAINTAINERS	Tue May 11 13:10:27 1999
+++ linux/MAINTAINERS	Thu Jun  3 08:26:38 1999
@@ -385,6 +385,11 @@
 W:	http://www.rustcorp.com/linux/ipchains
 S:	Supported
 
+IP MASQUERADING:
+P:	Juanjo Ciarlante
+M:	jjciarla@raiz.uncu.edu.ar
+S:	Maintained
+
 IPX/SPX NETWORK LAYER
 P:	Jay Schulist
 M:	Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
diff -u --recursive --new-file v2.2.9/linux/Makefile linux/Makefile
--- v2.2.9/linux/Makefile	Thu May 13 23:10:29 1999
+++ linux/Makefile	Fri May 28 18:10:19 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 9
+SUBLEVEL = 10
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.2.9/linux/README linux/README
--- v2.2.9/linux/README	Fri Jan  8 22:36:00 1999
+++ linux/README	Sun May 30 10:17:03 1999
@@ -32,11 +32,11 @@
  - There is a lot of documentation available both in electronic form on
    the Internet and in books, both Linux-specific and pertaining to
    general UNIX questions.  I'd recommend looking into the documentation
-   subdirectories on any Linux ftp site for the LDP (Linux Documentation
+   subdirectories on any Linux FTP site for the LDP (Linux Documentation
    Project) books.  This README is not meant to be documentation on the
    system: there are much better sources available.
 
- - There are various readme's in the kernel Documentation/ subdirectory:
+ - There are various README files in the Documentation/ subdirectory:
    these typically contain kernel-specific installation notes for some 
    drivers for example. See ./Documentation/00-INDEX for a list of what
    is contained in each file.  Please read the Changes file, as it
@@ -219,7 +219,7 @@
    isn't anyone listed there, then the second best thing is to mail
    them to me (torvalds@transmeta.com), and possibly to any other
    relevant mailing-list or to the newsgroup.  The mailing-lists are
-   useful especially for SCSI and NETworking problems, as I can't test
+   useful especially for SCSI and networking problems, as I can't test
    either of those personally anyway. 
 
  - In all bug-reports, *please* tell what kernel you are talking about,
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.2.9/linux/arch/alpha/config.in	Tue May 11 13:10:27 1999
+++ linux/arch/alpha/config.in	Sat May 22 13:41:37 1999
@@ -142,6 +142,7 @@
 
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
 	-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
+	-o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \
 	-o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \
 	-o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
@@ -166,7 +167,11 @@
 	define_bool CONFIG_ALPHA_AVANTI y
 fi
 
-bool 'Symmetric multi-processing support' CONFIG_SMP
+if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
+	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ]
+then
+	bool 'Symmetric multi-processing support' CONFIG_SMP
+fi
 
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'PCI quirks' CONFIG_PCI_QUIRKS
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.2.9/linux/arch/alpha/defconfig	Wed Mar 10 15:29:45 1999
+++ linux/arch/alpha/defconfig	Sat Jun 12 11:52:51 1999
@@ -12,12 +12,11 @@
 #
 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_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 @@
 #
 # 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 @@
 # (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 @@
 # 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_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_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_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_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_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 @@
 # 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
 
 #
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.2.9/linux/arch/alpha/kernel/alpha_ksyms.c	Tue Jan 19 11:32:50 1999
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Sat May 22 13:41:43 1999
@@ -52,6 +52,7 @@
 EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
 EXPORT_SYMBOL(screen_info);
 EXPORT_SYMBOL(perf_irq);
 
@@ -170,8 +171,8 @@
 EXPORT_SYMBOL(__global_restore_flags);
 #if DEBUG_SPINLOCK
 EXPORT_SYMBOL(spin_unlock);
-EXPORT_SYMBOL(spin_lock);
-EXPORT_SYMBOL(spin_trylock);
+EXPORT_SYMBOL(debug_spin_lock);
+EXPORT_SYMBOL(debug_spin_trylock);
 #endif
 #if DEBUG_RWLOCK
 EXPORT_SYMBOL(write_lock);
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c
--- v2.2.9/linux/arch/alpha/kernel/core_cia.c	Wed Sep  9 14:51:03 1998
+++ linux/arch/alpha/kernel/core_cia.c	Sat May 22 13:41:43 1999
@@ -598,7 +598,7 @@
 {
 	CIA_jd = *(vuip)CIA_IOC_CIA_ERR;
 	DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd));
-	*(vuip)CIA_IOC_CIA_ERR = 0x0180;
+	*(vuip)CIA_IOC_CIA_ERR = CIA_jd;
 	mb();
 	return 0;
 }
@@ -698,6 +698,10 @@
 		reason = buf;
 		break;
 	}
+	mb();
+	mb();  /* magic */
+	draina();
+	cia_pci_clr_err();
 	wrmces(rdmces());	/* reset machine check pending flag */
 	mb();
 
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/fpreg.c linux/arch/alpha/kernel/fpreg.c
--- v2.2.9/linux/arch/alpha/kernel/fpreg.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/fpreg.c	Sat May 22 13:41:47 1999
@@ -1,10 +1,10 @@
 /*
- * kernel/fpreg.c
+ * arch/alpha/kernel/fpreg.c
  *
  * (C) Copyright 1998 Linus Torvalds
  */
 
-#ifdef __alpha_cix__
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
 #define STT(reg,val)  asm volatile ("ftoit $f"#reg",%0" : "=r"(val));
 #else
 #define STT(reg,val)  asm volatile ("stt $f"#reg",%0" : "=m"(val));
@@ -52,7 +52,7 @@
 	return val;
 }
 
-#ifdef __alpha_cix__
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
 #define LDT(reg,val)  asm volatile ("itoft %0,$f"#reg : : "r"(val));
 #else
 #define LDT(reg,val)  asm volatile ("ldt $f"#reg",%0" : : "m"(val));
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.2.9/linux/arch/alpha/kernel/head.S	Fri Oct 23 22:01:19 1998
+++ linux/arch/alpha/kernel/head.S	Sat Jun 12 11:52:52 1999
@@ -32,106 +32,27 @@
 
 #ifdef __SMP__
 	.align 3
-	.globl	__start_cpu
-	.ent	__start_cpu
-	/* On entry here from SRM console, the HWPCB of this processor
-	   has been loaded, and $27 contains the task pointer */
-__start_cpu:
-	.prologue 0
-	/* First order of business, load the GP */
-	br	$26,1f
-1:	ldgp	$29,0($26)
-	/* We need to get current loaded up with our first task...  */
-	mov	$27,$8
-	/* Set FEN */
-	lda	$16,1($31)
-	call_pal PAL_wrfen
-	/* ... and then we can start the processor.  */
-	jsr	$26,start_secondary
+	.globl	__smp_callin
+	.ent	__smp_callin
+	/* On entry here from SRM console, the HWPCB of the per-cpu
+	   slot for this processor has been loaded.  We've arranged
+	   for the UNIQUE value for this process to contain the PCBB
+	   of the target idle task.  */
+__smp_callin:
+	.prologue 1
+	ldgp	$29,0($27)	# First order of business, load the GP.
+
+	call_pal PAL_rduniq	# Grab the target PCBB.
+	mov	$0,$16		# Install it.
+	call_pal PAL_swpctx
+
+	lda	$8,0x3fff	# Find "current".
+	bic	$30,$8,$8
+	
+	jsr	$26,smp_callin
 	call_pal PAL_halt
-	.end __start_cpu
+	.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
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.2.9/linux/arch/alpha/kernel/irq.c	Tue Jan 19 11:32:50 1999
+++ linux/arch/alpha/kernel/irq.c	Sat May 22 13:42:26 1999
@@ -192,13 +192,21 @@
 }
 
 void
-disable_irq(unsigned int irq_nr)
+disable_irq_nosync(unsigned int irq_nr)
 {
 	unsigned long flags;
 
 	save_and_cli(flags);
 	mask_irq(irq_nr);
 	restore_flags(flags);
+}
+
+void
+disable_irq(unsigned int irq_nr)
+{
+	/* This works non-SMP, and SMP until we write code to distribute
+	   interrupts to more that cpu 0.  */
+	disable_irq_nosync(irq_nr);
 }
 
 void
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.2.9/linux/arch/alpha/kernel/process.c	Tue May 11 13:10:27 1999
+++ linux/arch/alpha/kernel/process.c	Sat May 22 13:42:29 1999
@@ -75,33 +75,46 @@
 	return 0;
 }
 
-static void __attribute__((noreturn))
-do_cpu_idle(void)
+#ifdef __SMP__
+void
+cpu_idle(void *unused)
 {
 	/* An endless idle loop with no priority at all.  */
 	current->priority = 0;
+	current->counter = -100;
+
 	while (1) {
-		check_pgt_cache();
-		run_task_queue(&tq_scheduler);
-		current->counter = 0;
-		schedule();
-	}
-}
+		/* FIXME -- EV6 and LCA45 know how to power down
+		   the CPU.  */
 
-#ifdef __SMP__
-void
-cpu_idle(void *unused)
-{
-	do_cpu_idle();
+		/* Although we are an idle CPU, we do not want to 
+		   get into the scheduler unnecessarily.  */
+		if (current->need_resched) {
+			schedule();
+			check_pgt_cache();
+		}
+	}
 }
 #endif
 
 asmlinkage int
 sys_idle(void)
 {
-	if (current->pid == 0)
-        	do_cpu_idle();
-	return -EPERM;
+	if (current->pid != 0)
+		return -EPERM;
+
+	/* An endless idle loop with no priority at all.  */
+	current->priority = 0;
+	current->counter = -100;
+	init_idle();
+
+	while (1) {
+		/* FIXME -- EV6 and LCA45 know how to power down
+		   the CPU.  */
+
+		schedule();
+		check_pgt_cache();
+	}
 }
 
 void
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.2.9/linux/arch/alpha/kernel/proto.h	Tue Feb 23 15:21:32 1999
+++ linux/arch/alpha/kernel/proto.h	Sat Jun 12 11:52:52 1999
@@ -151,6 +151,8 @@
 extern void setup_smp(void);
 extern int smp_info(char *buffer);
 extern void handle_ipi(struct pt_regs *);
+extern void smp_percpu_timer_interrupt(struct pt_regs *);
+extern int smp_boot_cpuid;
 
 /* bios32.c */
 extern void reset_for_srm(void);
@@ -178,7 +180,7 @@
 extern void wrmces(unsigned long mces);
 extern void cserve_ena(unsigned long);
 extern void cserve_dis(unsigned long);
-extern void __start_cpu(unsigned long);
+extern void __smp_callin(unsigned long);
 
 /* entry.S */
 extern void entArith(void);
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.2.9/linux/arch/alpha/kernel/setup.c	Wed Apr 28 11:37:29 1999
+++ linux/arch/alpha/kernel/setup.c	Sat May 22 13:42:31 1999
@@ -106,6 +106,7 @@
 WEAK(alphabook1_mv);
 WEAK(avanti_mv);
 WEAK(cabriolet_mv);
+WEAK(clipper_mv);
 WEAK(dp264_mv);
 WEAK(eb164_mv);
 WEAK(eb64p_mv);
@@ -330,6 +331,10 @@
 
 	/* Round it up to an even number of pages. */
 	high = (high + PAGE_SIZE) & (PAGE_MASK*2);
+
+	/* Enforce maximum of 2GB even if there is more.  Blah.  */
+	if (high > 0x80000000UL)
+		high = 0x80000000UL;
 	return PAGE_OFFSET + high;
 }
 
@@ -448,11 +453,11 @@
 	static struct alpha_machine_vector *tsunami_vecs[]  __initlocaldata =
 	{
 		NULL,
-		&dp264_mv,		/* dp164 */
+		&dp264_mv,		/* dp264 */
 		&dp264_mv,		/* warhol */
 		&dp264_mv,		/* windjammer */
 		&monet_mv,		/* monet */
-		&dp264_mv,		/* clipper */
+		&clipper_mv,		/* clipper */
 		&dp264_mv,		/* goldrush */
 		&webbrick_mv,		/* webbrick */
 		&dp264_mv,		/* catamaran */
@@ -537,6 +542,7 @@
 		&alphabook1_mv,
 		&avanti_mv,
 		&cabriolet_mv,
+		&clipper_mv,
 		&dp264_mv,
 		&eb164_mv,
 		&eb64p_mv,
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.2.9/linux/arch/alpha/kernel/signal.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/alpha/kernel/signal.c	Sat Jun 12 11:52:52 1999
@@ -24,6 +24,9 @@
 #include <asm/sigcontext.h>
 #include <asm/ucontext.h>
 
+#include "proto.h"
+
+
 #define DEBUG_SIG 0
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.2.9/linux/arch/alpha/kernel/smp.c	Tue May 11 13:10:27 1999
+++ linux/arch/alpha/kernel/smp.c	Sat Jun 12 11:52:52 1999
@@ -18,6 +18,7 @@
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 
+#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
@@ -29,6 +30,8 @@
 #include <asm/unistd.h>
 
 #include "proto.h"
+#include "irq.h"
+
 
 #define DEBUG_SMP 0
 #if DEBUG_SMP
@@ -37,62 +40,44 @@
 #define DBGS(args)
 #endif
 
-struct ipi_msg_flush_tb_struct {
-	volatile unsigned int flush_tb_mask;
-	union {
-		struct mm_struct *	flush_mm;
-		struct vm_area_struct *	flush_vma;
-	} p;
-	unsigned long flush_addr;
-	unsigned long flush_end;
-};
-
-static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
-static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED;
-
+/* A collection of per-processor data.  */
 struct cpuinfo_alpha cpu_data[NR_CPUS];
 
-spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+/* A collection of single bit ipi messages.  */
+static struct {
+	unsigned long bits __cacheline_aligned;
+} ipi_data[NR_CPUS];
 
-unsigned int boot_cpu_id = 0;
-static int smp_activated = 0;
-
-int smp_found_config = 0; /* Have we found an SMP box */
-static int max_cpus = -1;
+enum ipi_message_type {
+        IPI_RESCHEDULE,
+        IPI_CALL_FUNC,
+        IPI_CPU_STOP,
+};
 
-unsigned int cpu_present_map = 0;
+spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
 
-int smp_num_cpus = 1;
-int smp_num_probed = 0; /* Internal processor count */
+/* Set to a secondary's cpuid when it comes online.  */
+static unsigned long smp_secondary_alive;
 
-int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
+unsigned long cpu_present_mask;	/* Which cpus ids came online.  */
 
+static int max_cpus = -1;	/* Command-line limitation.  */
+int smp_boot_cpuid;		/* Which processor we booted from.  */
+int smp_num_probed;		/* Internal processor count */
+int smp_num_cpus = 1;		/* Number that came online.  */
+int smp_threads_ready;		/* True once the per process idle is forked. */
 cycles_t cacheflush_time;
 
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
-
-volatile int ipi_bits[NR_CPUS] __cacheline_aligned;
-
-unsigned long boot_cpu_palrev;
-
-volatile int smp_commenced = 0;
-volatile int smp_processors_ready = 0;
-
-volatile int cpu_number_map[NR_CPUS];
-volatile int cpu_logical_map[NR_CPUS];
+int cpu_number_map[NR_CPUS];
+int __cpu_logical_map[NR_CPUS];
 
 extern void calibrate_delay(void);
-extern struct thread_struct * original_pcb_ptr;
-
-static void smp_setup_percpu_timer(void);
-static void secondary_cpu_start(int, struct task_struct *);
-static void send_cpu_msg(char *, int);
+extern asmlinkage void entInt(void);
 
-/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */
+
+/*
+ * Process bootcommand SMP options, like "nosmp" and "maxcpus=".
+ */
 void __init
 smp_setup(char *str, int *ints)
 {
@@ -102,100 +87,87 @@
 		max_cpus = 0;
 }
 
-static void __init
-smp_store_cpu_info(int id)
+/*
+ * Called by both boot and secondaries to move global data into
+ *  per-processor storage.
+ */
+static inline void __init
+smp_store_cpu_info(int cpuid)
 {
-	/* This is it on Alpha, so far. */
-	cpu_data[id].loops_per_sec = loops_per_sec;
+	cpu_data[cpuid].loops_per_sec = loops_per_sec;
 }
 
-void __init
-smp_commence(void)
+/*
+ * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
+ */
+static inline void __init
+smp_setup_percpu_timer(int cpuid)
 {
-	/* Lets the callin's below out of their loop. */
-	mb();
-	smp_commenced = 1;
+	cpu_data[cpuid].prof_counter = 1;
+	cpu_data[cpuid].prof_multiplier = 1;
+
+#ifdef NOT_YET_PROFILING
+	load_profile_irq(mid_xlate[cpu], lvl14_resolution);
+	if (cpu == smp_boot_cpuid)
+		enable_pil_irq(14);
+#endif
 }
 
+/*
+ * Where secondaries begin a life of C.
+ */
 void __init
 smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
 
 	DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state));
-#ifdef HUH
-	local_flush_cache_all();
-	local_flush_tlb_all();
-#endif
-#if 0
-	set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif
+
+	/* Turn on machine checks.  */
+	wrmces(7);
+
+	/* Set trap vectors.  */
+	trap_init();
+
+	/* Set interrupt vector.  */
+	wrent(entInt, 0);
+
+	/* Setup the scheduler for this processor.  */
+	init_idle();
 
 	/* Get our local ticker going. */
-	smp_setup_percpu_timer();
+	smp_setup_percpu_timer(cpuid);
 
-#if 0
+	/* Must have completely accurate bogos.  */
+	__sti();
 	calibrate_delay();
-#endif
 	smp_store_cpu_info(cpuid);
-#ifdef HUH
-	local_flush_cache_all();
-	local_flush_tlb_all();
-#endif
 
 	/* Allow master to continue. */
-	set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]);
-#ifdef HUH
-	local_flush_cache_all();
-	local_flush_tlb_all();
-#endif
-
-#ifdef NOT_YET
-	while(!task[cpuid] || current_set[cpuid] != task[cpuid])
-	        barrier();
-#endif
-
-#ifdef HUH
-	local_flush_cache_all();
-	local_flush_tlb_all();
-#endif
-#if 0
-	__sti();
-#endif
-}
+	wmb();
+	smp_secondary_alive = cpuid;
 
-asmlinkage int __init
-start_secondary(void *unused)
-{
-	extern asmlinkage void entInt(void);
-	extern void paging_init_secondary(void);
+	/* Wait for the go code.  */
+	while (!smp_threads_ready)
+		barrier();
 
-	wrmces(7);
-	paging_init_secondary();
-	trap_init();
-	wrent(entInt, 0);
+	DBGS(("smp_callin: commencing CPU %d current %p\n",
+	      cpuid, current));
 
-	smp_callin();
-	while (!smp_commenced)
-		barrier();
-#if 1
-	printk("start_secondary: commencing CPU %d current %p\n",
-	       hard_smp_processor_id(), current);
-#endif
+	/* Do nothing.  */
 	cpu_idle(NULL);
 }
 
+
+/*
+ * Rough estimation for SMP scheduling, this is the number of cycles it
+ * takes for a fully memory-limited process to flush the SMP-local cache.
+ *
+ * We are not told how much cache there is, so we have to guess.
+ */
 static void __init
 smp_tune_scheduling (void)
 {
-	/*
-	 * Rough estimation for SMP scheduling, this is the number of
-	 * cycles it takes for a fully memory-limited process to flush
-	 * the SMP-local cache.
-	 *
-	 * We are not told how much cache there is, so we have to guess.
-	 */
-
 	struct percpu_struct *cpu;
 	unsigned long on_chip_cache;
 	unsigned long freq;
@@ -231,298 +203,18 @@
 	cacheflush_time = freq / 1024 * on_chip_cache / 5000;
 }
 
-
 /*
- *      Cycle through the processors sending START msgs to boot each.
+ * Send a message to a secondary's console.  "START" is one such
+ * interesting message.  ;-)
  */
-void __init
-smp_boot_cpus(void)
-{
-	int cpucount = 0;
-	int i, first, prev;
-
-	printk("Entering SMP Mode.\n");
-
-#if 0
-	__sti();
-#endif
-
-	for(i=0; i < NR_CPUS; i++) {
-		cpu_number_map[i] = -1;
-		cpu_logical_map[i] = -1;
-	        prof_counter[i] = 1;
-	        prof_multiplier[i] = 1;
-		ipi_bits[i] = 0;
-	}
-
-	cpu_number_map[boot_cpu_id] = 0;
-	cpu_logical_map[0] = boot_cpu_id;
-	current->processor = boot_cpu_id; /* ??? */
-
-	smp_store_cpu_info(boot_cpu_id);
-	smp_tune_scheduling();
-#ifdef NOT_YET
-	printk("CPU%d: ", boot_cpu_id);
-	print_cpu_info(&cpu_data[boot_cpu_id]);
-	set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif
-	smp_setup_percpu_timer();
-#ifdef HUH
-	local_flush_cache_all();
-#endif
-	if (smp_num_probed == 1)
-		return;  /* Not an MP box. */
-
-#if NOT_YET
-	/*
-	 * If SMP should be disabled, then really disable it!
-	 */
-	if (!max_cpus)
-	{
-		smp_found_config = 0;
-	        printk(KERN_INFO "SMP mode deactivated.\n");
-	}
-#endif
-
-	for (i = 0; i < NR_CPUS; i++) {
-
-		if (i == boot_cpu_id)
-			continue;
-
-	        if (cpu_present_map & (1 << i)) {
-	                struct task_struct *idle;
-	                int timeout;
-
-	                /* Cook up an idler for this guy. */
-	                kernel_thread(start_secondary, NULL, CLONE_PID);
-	                idle = task[++cpucount];
-			if (!idle)
-				panic("No idle process for CPU %d", i);
-	                idle->processor = i;
-
-			DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n",
-			      i, idle->state, idle->flags));
-
-	                /* whirrr, whirrr, whirrrrrrrrr... */
-#ifdef HUH
-	                local_flush_cache_all();
-#endif
-	                secondary_cpu_start(i, idle);
-
-	                /* wheee... it's going... wait for 5 secs...*/
-	                for (timeout = 0; timeout < 50000; timeout++) {
-				if (cpu_callin_map[i])
-					break;
-	                        udelay(100);
-	                }
-	                if (cpu_callin_map[i]) {
-				/* Another "Red Snapper". */
-				cpu_number_map[i] = cpucount;
-	                        cpu_logical_map[cpucount] = i;
-	                } else {
-				cpucount--;
-	                        printk("smp_boot_cpus: Processor %d"
-				       " is stuck 0x%lx.\n", i, idle->flags);
-	                }
-	        }
-	        if (!(cpu_callin_map[i])) {
-			cpu_present_map &= ~(1 << i);
-	                cpu_number_map[i] = -1;
-	        }
-	}
-#ifdef HUH
-	local_flush_cache_all();
-#endif
-	if (cpucount == 0) {
-		printk("smp_boot_cpus: ERROR - only one Processor found.\n");
-	        cpu_present_map = (1 << smp_processor_id());
-	} else {
-		unsigned long bogosum = 0;
-	        for (i = 0; i < NR_CPUS; i++) {
-			if (cpu_present_map & (1 << i))
-				bogosum += cpu_data[i].loops_per_sec;
-	        }
-	        printk("smp_boot_cpus: Total of %d Processors activated"
-		       " (%lu.%02lu BogoMIPS).\n",
-	               cpucount + 1,
-	               (bogosum + 2500)/500000,
-	               ((bogosum + 2500)/5000)%100);
-	        smp_activated = 1;
-	        smp_num_cpus = cpucount + 1;
-	}
-
-	/* Setup CPU list for IRQ distribution scheme. */
-	first = prev = -1;
-	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_present_map & (1 << i)) {
-			if (first == -1)
-				first = i;
-			if (prev != -1)
-				cpu_data[i].next = i;
-	                prev = i;
-	        }
-	}
-	cpu_data[prev].next = first;
-
-	/* Ok, they are spinning and ready to go. */
-	smp_processors_ready = 1;
-}
-
-static void __init
-smp_setup_percpu_timer(void)
-{
-	int cpu = smp_processor_id();
-
-	prof_counter[cpu] = prof_multiplier[cpu] = 1;
-#ifdef NOT_YET
-	load_profile_irq(mid_xlate[cpu], lvl14_resolution);
-	if (cpu == boot_cpu_id)
-		enable_pil_irq(14);
-#endif
-}
-
-extern void update_one_process(struct task_struct *p, unsigned long ticks,
-	                       unsigned long user, unsigned long system,
-			       int cpu);
-
-void
-smp_percpu_timer_interrupt(struct pt_regs *regs)
-{
-	int cpu = smp_processor_id();
-
-#ifdef NOT_YET
-	clear_profile_irq(mid_xlate[cpu]);
-	if(!user_mode(regs))
-		alpha_do_profile(regs->pc);
-#endif
-
-	if (!--prof_counter[cpu]) {
-		int user = user_mode(regs);
-	        if (current->pid) {
-			update_one_process(current, 1, user, !user, cpu);
-
-	                if (--current->counter < 0) {
-				current->counter = 0;
-	                        current->need_resched = 1;
-	                }
-
-	                spin_lock(&ticker_lock);
-	                if (user) {
-				if (current->priority < DEF_PRIORITY) {
-					kstat.cpu_nice++;
-					kstat.per_cpu_nice[cpu]++;
-				} else {
-					kstat.cpu_user++;
-					kstat.per_cpu_user[cpu]++;
-				}
-	                } else {
-				kstat.cpu_system++;
-				kstat.per_cpu_system[cpu]++;
-	                }
-	                spin_unlock(&ticker_lock);
-	        }
-	        prof_counter[cpu] = prof_multiplier[cpu];
-	}
-}
-
-int __init
-setup_profiling_timer(unsigned int multiplier)
-{
-#ifdef NOT_YET
-	int i;
-	unsigned long flags;
-
-	/* Prevent level14 ticker IRQ flooding. */
-	if((!multiplier) || (lvl14_resolution / multiplier) < 500)
-	        return -EINVAL;
-
-	save_and_cli(flags);
-	for(i = 0; i < NR_CPUS; i++) {
-	        if(cpu_present_map & (1 << i)) {
-	                load_profile_irq(mid_xlate[i], lvl14_resolution / multip
-lier);
-	                prof_multiplier[i] = multiplier;
-	        }
-	}
-	restore_flags(flags);
-
-	return 0;
-
-#endif
-  return -EINVAL;
-}
-
-/* Only broken Intel needs this, thus it should not even be
-   referenced globally.  */
-
-void __init
-initialize_secondary(void)
-{
-}
-
-static void __init
-secondary_cpu_start(int cpuid, struct task_struct *idle)
-{
-	struct percpu_struct *cpu;
-	int timeout;
-	  
-	cpu = (struct percpu_struct *)
-		((char*)hwrpb
-		 + hwrpb->processor_offset
-		 + cpuid * hwrpb->processor_size);
-
-	/* Set context to idle thread this CPU will use when running
-	   assumption is that the idle thread is all set to go... ??? */
-	memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct));
-	cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */
-
-	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n",
-	      cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb));
-	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
-	      cpuid, idle->state, idle->tss.pal_flags));
-
-	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
-	hwrpb->CPU_restart = __start_cpu;
-	hwrpb->CPU_restart_data = (unsigned long) idle;
-
-	/* Recalculate and update the HWRPB checksum */
-	hwrpb_update_checksum(hwrpb);
-
-	/*
-	 * Send a "start" command to the specified processor.
-	 */
-
-	/* SRM III 3.4.1.3 */
-	cpu->flags |= 0x22;	/* turn on Context Valid and Restart Capable */
-	cpu->flags &= ~1;	/* turn off Bootstrap In Progress */
-	mb();
-
-	send_cpu_msg("START\r\n", cpuid);
-
-	/* now, we wait... */
-	for (timeout = 10000; !(cpu->flags & 1); timeout--) {
-		if (timeout <= 0) {
-			printk("Processor %d failed to start\n", cpuid);
-	                        /* needed for pset_info to work */
-#if 0
-			ipc_processor_enable(cpu_to_processor(cpunum));
-#endif
-			return;
-		}
-		mdelay(1);
-		barrier();
-	}
-	DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
-}
-
 static void
-send_cpu_msg(char *str, int cpuid)
+send_secondary_console_msg(char *str, int cpuid)
 {
 	struct percpu_struct *cpu;
 	register char *cp1, *cp2;
 	unsigned long cpumask;
 	size_t len;
-	int timeout;
+	long timeout;
 
 	cpu = (struct percpu_struct *)
 		((char*)hwrpb
@@ -541,6 +233,7 @@
 	memcpy(cp1, cp2, len);
 
 	/* atomic test and set */
+	wmb();
 	set_bit(cpuid, &hwrpb->rxrdy);
 
 	if (hwrpb->txrdy & cpumask)
@@ -549,19 +242,21 @@
 	return;
 
 delay1:
-	for (timeout = 10000; timeout > 0; --timeout) {
+	/* Wait one second.  Note that jiffies aren't ticking yet.  */
+	for (timeout = 100000; timeout > 0; --timeout) {
 		if (!(hwrpb->txrdy & cpumask))
 			goto ready1;
-		udelay(100);
+		udelay(10);
 		barrier();
 	}
 	goto timeout;
 
 delay2:
-	for (timeout = 10000; timeout > 0; --timeout) {
+	/* Wait one second.  */
+	for (timeout = 100000; timeout > 0; --timeout) {
 		if (!(hwrpb->txrdy & cpumask))
 			goto ready2;
-		udelay(100);
+		udelay(10);
 		barrier();
 	}
 	goto timeout;
@@ -572,64 +267,17 @@
 }
 
 /*
- * setup_smp()
- *
- * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined
+ * A secondary console wants to send a message.  Receive it.
  */
-void __init
-setup_smp(void)
-{
-	struct percpu_struct *cpubase, *cpu;
-	int i;
-	  
-	boot_cpu_id = hard_smp_processor_id();
-	if (boot_cpu_id != 0) {
-		printk("setup_smp: boot_cpu_id != 0 (%d).\n", boot_cpu_id);
-	}
-
-	if (hwrpb->nr_processors > 1) {
-
-		DBGS(("setup_smp: nr_processors %ld\n",
-		      hwrpb->nr_processors));
-
-		cpubase = (struct percpu_struct *)
-			((char*)hwrpb + hwrpb->processor_offset);
-		boot_cpu_palrev = cpubase->pal_revision;
-
-		for (i = 0; i < hwrpb->nr_processors; i++ ) {
-			cpu = (struct percpu_struct *)
-				((char *)cpubase + i*hwrpb->processor_size);
-			if ((cpu->flags & 0x1cc) == 0x1cc) {
-				smp_num_probed++;
-				/* assume here that "whami" == index */
-				cpu_present_map |= (1 << i);
-				if (i != boot_cpu_id)
-				  cpu->pal_revision = boot_cpu_palrev;
-			}
-
-			DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
-			      i, cpu->flags, cpu->type));
-			DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
-			      i, cpu->pal_revision));
-		}
-	} else {
-		smp_num_probed = 1;
-		cpu_present_map = (1 << boot_cpu_id);
-	}
-	printk("setup_smp: %d CPUs probed, cpu_present_map 0x%x,"
-	       " boot_cpu_id %d\n",
-	       smp_num_probed, cpu_present_map, boot_cpu_id);
-}
-
 static void
-secondary_console_message(void)
+recv_secondary_console_msg(void)
 {
 	int mycpu, i, cnt;
 	unsigned long txrdy = hwrpb->txrdy;
 	char *cp1, *cp2, buf[80];
 	struct percpu_struct *cpu;
 
-	DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy));
+	DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy));
 
 	mycpu = hard_smp_processor_id();
 
@@ -637,7 +285,7 @@
 		if (!(txrdy & (1L << i)))
 			continue;
 
-		DBGS(("secondary_console_message: "
+		DBGS(("recv_secondary_console_msg: "
 		      "TXRDY contains CPU %d.\n", i));
 
 		cpu = (struct percpu_struct *)
@@ -645,9 +293,9 @@
 		   + hwrpb->processor_offset
 		   + i * hwrpb->processor_size);
 
- 		printk("secondary_console_message: 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)
@@ -664,85 +312,347 @@
 			}
 		}
 
-		printk("secondary_console_message: on %d message is '%s'\n",
-		       mycpu, buf);
+		printk(KERN_INFO "recv_secondary_console_msg: on %d "
+		       "message is '%s'\n", mycpu, buf);
 	}
 
 	hwrpb->txrdy = 0;
 }
 
-enum ipi_message_type {
-	IPI_TLB_ALL,
-	IPI_TLB_MM,
-	IPI_TLB_PAGE,
-	IPI_RESCHEDULE,
-	IPI_CPU_STOP
-};
-
-void
-handle_ipi(struct pt_regs *regs)
+/*
+ * Convince the console to have a secondary cpu begin execution.
+ */
+static int __init
+secondary_cpu_start(int cpuid, struct task_struct *idle)
 {
-	int this_cpu = smp_processor_id();
-	volatile int * pending_ipis = &ipi_bits[this_cpu];
-	unsigned long ops;
+	struct percpu_struct *cpu;
+	struct pcb_struct *hwpcb;
+	long timeout;
+	  
+	cpu = (struct percpu_struct *)
+		((char*)hwrpb
+		 + hwrpb->processor_offset
+		 + cpuid * hwrpb->processor_size);
+	hwpcb = (struct pcb_struct *) cpu->hwpcb;
 
-	DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
-	      this_cpu, *pending_ipis, regs->pc));
+	/* Initialize the CPU's HWPCB to something just good enough for
+	   us to get started.  Immediately after starting, we'll swpctx
+	   to the target idle task's tss.  Reuse the stack in the mean
+	   time.  Precalculate the target PCBB.  */
+	hwpcb->ksp = (unsigned long) idle + sizeof(union task_union) - 16;
+	hwpcb->usp = 0;
+	hwpcb->ptbr = idle->tss.ptbr;
+	hwpcb->pcc = 0;
+	hwpcb->asn = 0;
+	hwpcb->unique = virt_to_phys(&idle->tss);
+	hwpcb->flags = idle->tss.pal_flags;
+	hwpcb->res1 = hwpcb->res2 = 0;
 
-	mb();	/* Order interrupt and bit testing. */
-	while ((ops = xchg(pending_ipis, 0)) != 0) {
-	  mb();	/* Order bit clearing and data access. */
-	  do {
-		unsigned long which;
+	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
+	      hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique));
+	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
+	      cpuid, idle->state, idle->tss.pal_flags));
 
-		which = ops & -ops;
-		ops &= ~which;
-		which = ffz(~which);
+	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
+	hwrpb->CPU_restart = __smp_callin;
+	hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
 
-		if (which < IPI_RESCHEDULE) {
-			if (which == IPI_TLB_ALL)
-				tbia();
-			else if (which == IPI_TLB_MM) {
-				struct mm_struct * mm;
-				mm = ipi_msg_flush_tb.p.flush_mm;
-				if (mm == current->mm)
-					flush_tlb_current(mm);
-			}
-			else /* IPI_TLB_PAGE */ {
-				struct vm_area_struct * vma;
-				struct mm_struct * mm;
-				unsigned long addr;
-
-				vma = ipi_msg_flush_tb.p.flush_vma;
-				mm = vma->vm_mm;
-				addr = ipi_msg_flush_tb.flush_addr;
+	/* Recalculate and update the HWRPB checksum */
+	hwrpb_update_checksum(hwrpb);
+
+	/*
+	 * Send a "start" command to the specified processor.
+	 */
 
-				if (mm == current->mm)
-					flush_tlb_current_page(mm, vma, addr);
+	/* SRM III 3.4.1.3 */
+	cpu->flags |= 0x22;	/* turn on Context Valid and Restart Capable */
+	cpu->flags &= ~1;	/* turn off Bootstrap In Progress */
+	wmb();
+
+	send_secondary_console_msg("START\r\n", cpuid);
+
+	/* Wait 1 second for an ACK from the console.  Note that jiffies 
+	   aren't ticking yet.  */
+	for (timeout = 100000; timeout > 0; timeout--) {
+		if (cpu->flags & 1)
+			goto started;
+		udelay(10);
+		barrier();
+	}
+	printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
+	return -1;
+
+started:
+	DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
+	return 0;
+}
+
+/*
+ * Bring one cpu online.
+ */
+static int __init
+smp_boot_one_cpu(int cpuid, int cpunum)
+{
+	struct task_struct *idle;
+	long timeout;
+
+	/* Cook up an idler for this guy.  Note that the address we give
+	   to kernel_thread is irrelevant -- it's going to start where
+	   HWRPB.CPU_restart says to start.  But this gets all the other
+	   task-y sort of data structures set up like we wish.  */
+	kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM);
+	idle = task[cpunum];
+	if (!idle)
+		panic("No idle process for CPU %d", cpuid);
+	idle->processor = cpuid;
+
+	/* Schedule the first task manually.  */
+	/* ??? Ingo, what is this?  */
+	idle->has_cpu = 1;
+
+	DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
+	      cpuid, idle->state, idle->flags));
+
+	/* The secondary will change this once it is happy.  Note that
+	   secondary_cpu_start contains the necessary memory barrier.  */
+	smp_secondary_alive = -1;
+
+	/* Whirrr, whirrr, whirrrrrrrrr... */
+	if (secondary_cpu_start(cpuid, idle))
+		return -1;
+
+	/* We've been acked by the console; wait one second for the task
+	   to start up for real.  Note that jiffies aren't ticking yet.  */
+	for (timeout = 0; timeout < 100000; timeout++) {
+		if (smp_secondary_alive != -1)
+			goto alive;
+		udelay(10);
+		barrier();
+	}
+
+	printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
+	return -1;
+
+alive:
+	/* Another "Red Snapper". */
+	cpu_number_map[cpuid] = cpunum;
+	__cpu_logical_map[cpunum] = cpuid;
+	return 0;
+}
+
+/*
+ * Called from setup_arch.  Detect an SMP system and which processors
+ * are present.
+ */
+void __init
+setup_smp(void)
+{
+	struct percpu_struct *cpubase, *cpu;
+	int i;
+
+	smp_boot_cpuid = hard_smp_processor_id();
+	if (smp_boot_cpuid != 0) {
+		printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
+		       smp_boot_cpuid);
+	}
+
+	if (hwrpb->nr_processors > 1) {
+		int boot_cpu_palrev;
+
+		DBGS(("setup_smp: nr_processors %ld\n",
+		      hwrpb->nr_processors));
+
+		cpubase = (struct percpu_struct *)
+			((char*)hwrpb + hwrpb->processor_offset);
+		boot_cpu_palrev = cpubase->pal_revision;
+
+		for (i = 0; i < hwrpb->nr_processors; i++ ) {
+			cpu = (struct percpu_struct *)
+				((char *)cpubase + i*hwrpb->processor_size);
+			if ((cpu->flags & 0x1cc) == 0x1cc) {
+				smp_num_probed++;
+				/* Assume here that "whami" == index */
+				cpu_present_mask |= (1L << i);
+				cpu->pal_revision = boot_cpu_palrev;
 			}
-			clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
-		}
-		else if (which == IPI_RESCHEDULE) {
-			/* Reschedule callback.  Everything to be done
-			   is done by the interrupt return path.  */
-		}
-		else if (which == IPI_CPU_STOP) {
-			halt();
-		}
-		else {
-			printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n",
-			       this_cpu, which);
+
+			DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
+			      i, cpu->flags, cpu->type));
+			DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
+			      i, cpu->pal_revision));
 		}
-	  } while (ops);
-	  mb();	/* Order data access and bit testing. */
+	} else {
+		smp_num_probed = 1;
+		cpu_present_mask = (1L << smp_boot_cpuid);
 	}
 
-	cpu_data[this_cpu].ipi_count++;
+	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
+	       smp_num_probed, cpu_present_mask);
+}
 
-	if (hwrpb->txrdy)
-		secondary_console_message();
+/*
+ * Called by smp_init bring all the secondaries online and hold them.
+ */
+void __init
+smp_boot_cpus(void)
+{
+	int cpu_count, i;
+	unsigned long bogosum;
+
+	/* Take care of some initial bookkeeping.  */
+	memset(cpu_number_map, -1, sizeof(cpu_number_map));
+	memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map));
+	memset(ipi_data, 0, sizeof(ipi_data));
+
+	cpu_number_map[smp_boot_cpuid] = 0;
+	__cpu_logical_map[0] = smp_boot_cpuid;
+	current->processor = smp_boot_cpuid;
+
+	smp_store_cpu_info(smp_boot_cpuid);
+	smp_tune_scheduling();
+	smp_setup_percpu_timer(smp_boot_cpuid);
+
+	init_idle();
+
+	/* Nothing to do on a UP box, or when told not to.  */
+	if (smp_num_probed == 1 || max_cpus == 0) {
+	        printk(KERN_INFO "SMP mode deactivated.\n");
+		return;
+	}
+
+	printk(KERN_INFO "SMP starting up secondaries.\n");
+
+	cpu_count = 1;
+	for (i = 0; i < NR_CPUS; i++) {
+		if (i == smp_boot_cpuid)
+			continue;
+
+	        if (((cpu_present_mask >> i) & 1) == 0)
+			continue;
+
+		if (smp_boot_one_cpu(i, cpu_count))
+			continue;
+
+		cpu_count++;
+	}
+
+	if (cpu_count == 1) {
+		printk(KERN_ERR "SMP: Only one lonely processor alive.\n");
+		return;
+	}
+
+	bogosum = 0;
+        for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_present_mask & (1L << i))
+			bogosum += cpu_data[i].loops_per_sec;
+        }
+	printk(KERN_INFO "SMP: Total of %d processors activated "
+	       "(%lu.%02lu BogoMIPS).\n",
+	       cpu_count, (bogosum + 2500) / 500000,
+	       ((bogosum + 2500) / 5000) % 100);
+
+	smp_num_cpus = cpu_count;
+}
+
+/*
+ * Called by smp_init to release the blocking online cpus once they 
+ * are all started.
+ */
+void __init
+smp_commence(void)
+{
+	/* smp_init sets smp_threads_ready -- that's enough.  */
+	mb();
+}
+
+/*
+ * Only broken Intel needs this, thus it should not even be
+ * referenced globally.
+ */
+
+void __init
+initialize_secondary(void)
+{
 }
 
+
+extern void update_one_process(struct task_struct *p, unsigned long ticks,
+	                       unsigned long user, unsigned long system,
+			       int cpu);
+
+void
+smp_percpu_timer_interrupt(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	int user = user_mode(regs);
+	struct cpuinfo_alpha *data = &cpu_data[cpu];
+
+#ifdef NOT_YET_PROFILING
+	clear_profile_irq(mid_xlate[cpu]);
+	if (!user)
+		alpha_do_profile(regs->pc);
+#endif
+
+	if (!--data->prof_counter) {
+		/* We need to make like a normal interrupt -- otherwise
+		   timer interrupts ignore the global interrupt lock,
+		   which would be a Bad Thing.  */
+		irq_enter(cpu, TIMER_IRQ);
+
+		update_one_process(current, 1, user, !user, cpu);
+	        if (current->pid) {
+	                if (--current->counter < 0) {
+				current->counter = 0;
+	                        current->need_resched = 1;
+	                }
+
+	                if (user) {
+				if (current->priority < DEF_PRIORITY) {
+					kstat.cpu_nice++;
+					kstat.per_cpu_nice[cpu]++;
+				} else {
+					kstat.cpu_user++;
+					kstat.per_cpu_user[cpu]++;
+				}
+	                } else {
+				kstat.cpu_system++;
+				kstat.per_cpu_system[cpu]++;
+	                }
+	        }
+
+		data->prof_counter = data->prof_multiplier;
+		irq_exit(cpu, TIMER_IRQ);
+	}
+}
+
+int __init
+setup_profiling_timer(unsigned int multiplier)
+{
+#ifdef NOT_YET_PROFILING
+	int i;
+	unsigned long flags;
+
+	/* Prevent level14 ticker IRQ flooding. */
+	if((!multiplier) || (lvl14_resolution / multiplier) < 500)
+	        return -EINVAL;
+
+	save_and_cli(flags);
+	for (i = 0; i < NR_CPUS; i++) {
+	        if (cpu_present_mask & (1L << i)) {
+	                load_profile_irq(mid_xlate[i],
+					 lvl14_resolution / multiplier);
+	                prof_multiplier[i] = multiplier;
+	        }
+	}
+	restore_flags(flags);
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+
 static void
 send_ipi_message(unsigned long to_whom, enum ipi_message_type operation)
 {
@@ -755,7 +665,7 @@
 
 	for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
 		if (to_whom & j)
-			set_bit(operation, &ipi_bits[i]);
+			set_bit(operation, &ipi_data[i].bits);
 	}
 
 	mb();	/* Order bit setting and interrupt. */
@@ -766,123 +676,263 @@
 	}
 }
 
-int
-smp_info(char *buffer)
+/* Structure and data for smp_call_function.  This is designed to 
+   minimize static memory requirements.  Plus it looks cleaner.  */
+
+struct smp_call_struct {
+	void (*func) (void *info);
+	void *info;
+	long wait;
+	atomic_t unstarted_count;
+	atomic_t unfinished_count;
+};
+
+static struct smp_call_struct *smp_call_function_data;
+
+/* Atomicly drop data into a shared pointer.  The pointer is free if
+   it is initially locked.  If retry, spin until free.  */
+
+static inline int
+pointer_lock (void *lock, void *data, int retry)
 {
-	long i;
-	unsigned long sum = 0;
-	for (i = 0; i < NR_CPUS; i++)
-		sum += cpu_data[i].ipi_count;
+	void *old, *tmp;
 
-	return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n",
-		       smp_num_probed, smp_num_cpus, cpu_present_map, sum);
+	mb();
+again:
+	/* Compare and swap with zero.  */
+	asm volatile (
+	"1:	ldq_l	%0,%1\n"
+	"	mov	%3,%2\n"
+	"	bne	%0,2f\n"
+	"	stq_c	%2,%1\n"
+	"	beq	%2,1b\n"
+	"2:"
+	: "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp)
+	: "r"(data)
+	: "memory");
+
+	if (old == 0)
+		return 0;
+	if (! retry)
+		return -EBUSY;
+
+	while (*(void **)lock)
+		schedule();
+	goto again;
+}
+
+void
+handle_ipi(struct pt_regs *regs)
+{
+	int this_cpu = smp_processor_id();
+	unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
+	unsigned long ops;
+
+	DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
+	      this_cpu, *pending_ipis, regs->pc));
+
+	mb();	/* Order interrupt and bit testing. */
+	while ((ops = xchg(pending_ipis, 0)) != 0) {
+	  mb();	/* Order bit clearing and data access. */
+	  do {
+		unsigned long which;
+
+		which = ops & -ops;
+		ops &= ~which;
+		which = ffz(~which);
+
+		if (which == IPI_RESCHEDULE) {
+			/* Reschedule callback.  Everything to be done
+			   is done by the interrupt return path.  */
+		}
+		else if (which == IPI_CALL_FUNC) {
+			struct smp_call_struct *data;
+			void (*func)(void *info);
+			void *info;
+			int wait;
+
+			data = smp_call_function_data;
+			func = data->func;
+			info = data->info;
+			wait = data->wait;
+
+			/* Notify the sending CPU that the data has been
+			   received, and execution is about to begin.  */
+			mb();
+			atomic_dec (&data->unstarted_count);
+
+			/* At this point the structure may be gone unless
+			   wait is true.  */
+			(*func)(info);
+
+			/* Notify the sending CPU that the task is done.  */
+			mb();
+			if (wait) atomic_dec (&data->unfinished_count);
+		}
+		else if (which == IPI_CPU_STOP) {
+			halt();
+		}
+		else {
+			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
+			       this_cpu, which);
+		}
+	  } while (ops);
+
+	  mb();	/* Order data access and bit testing. */
+	}
+
+	cpu_data[this_cpu].ipi_count++;
+
+	if (hwrpb->txrdy)
+		recv_secondary_console_msg();
 }
 
 void
 smp_send_reschedule(int cpu)
 {
-	send_ipi_message(1 << cpu, IPI_RESCHEDULE);
+#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);
 }
 
 void
 smp_send_stop(void)
 {
-	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
+	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);
 }
 
-void
-flush_tlb_all(void)
+/*
+ * Run a function on all other CPUs.
+ *  <func>	The function to run. This must be fast and non-blocking.
+ *  <info>	An arbitrary pointer to pass to the function.
+ *  <retry>	If true, keep retrying until ready.
+ *  <wait>	If true, wait until function has completed on other CPUs.
+ *  [RETURNS]   0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or are or have executed.
+ */
+
+int
+smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
 {
-	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
-	long timeout = 1000000;
+	unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+	struct smp_call_struct data;
+	long timeout;
+	
+	data.func = func;
+	data.info = info;
+	data.wait = wait;
+	atomic_set(&data.unstarted_count, smp_num_cpus - 1);
+	atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+
+	/* Aquire the smp_call_function_data mutex.  */
+	if (pointer_lock(&smp_call_function_data, &data, retry))
+		return -EBUSY;
+
+	/* Send a message to all other CPUs.  */
+	send_ipi_message(to_whom, IPI_CALL_FUNC);
+
+	/* Wait for a minimal response.  */
+	timeout = jiffies + HZ;
+	while (atomic_read (&data.unstarted_count) > 0
+	       && time_before (jiffies, timeout))
+		barrier();
+
+	/* We either got one or timed out -- clear the lock.  */
+	mb();
+	smp_call_function_data = 0;
+	if (atomic_read (&data.unstarted_count) > 0)
+		return -ETIMEDOUT;
+
+	/* Wait for a complete response, if needed.  */
+	if (wait) {
+		while (atomic_read (&data.unfinished_count) > 0)
+			barrier();
+	}
 
-	spin_lock(&flush_tb_lock);
+	return 0;
+}
 
-	ipi_msg_flush_tb.flush_tb_mask = to_whom;
-	send_ipi_message(to_whom, IPI_TLB_ALL);
+static void
+ipi_flush_tlb_all(void *ignored)
+{
 	tbia();
+}
 
-	while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
-		udelay(1);
-		barrier();
+void
+flush_tlb_all(void)
+{
+	/* 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");
 	}
 
-	if (timeout == 0) {
-		printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
-		       smp_processor_id(),
-		       ipi_msg_flush_tb.flush_tb_mask);
-		ipi_msg_flush_tb.flush_tb_mask = 0;
-	}
+	tbia();
+}
 
-	spin_unlock(&flush_tb_lock);
+static void
+ipi_flush_tlb_mm(void *x)
+{
+	struct mm_struct *mm = (struct mm_struct *) x;
+	if (mm == current->mm)
+		flush_tlb_current(mm);
 }
 
 void
 flush_tlb_mm(struct mm_struct *mm)
 {
-	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
-	long timeout = 1000000;
-
-	spin_lock(&flush_tb_lock);
-
-	ipi_msg_flush_tb.flush_tb_mask = to_whom;
-	ipi_msg_flush_tb.p.flush_mm = mm;
-	send_ipi_message(to_whom, IPI_TLB_MM);
-
-	if (mm != current->mm)
-		flush_tlb_other(mm);
-	else
+	if (mm == current->mm)
 		flush_tlb_current(mm);
+	else
+		flush_tlb_other(mm);
 
-	while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
-		udelay(1);
-		barrier();
+	if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
+		printk(KERN_CRIT "flush_tlb_mm: timed out\n");
 	}
+}
 
-	if (timeout == 0) {
-		printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n",
-		       smp_processor_id(),
-		       ipi_msg_flush_tb.flush_tb_mask);
-		ipi_msg_flush_tb.flush_tb_mask = 0;
-	}
+struct flush_tlb_page_struct {
+	struct vm_area_struct *vma;
+	struct mm_struct *mm;
+	unsigned long addr;
+};
 
-	spin_unlock(&flush_tb_lock);
+static void
+ipi_flush_tlb_page(void *x)
+{
+	struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
+	if (data->mm == current->mm)
+		flush_tlb_current_page(data->mm, data->vma, data->addr);
 }
 
 void
 flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 {
-	int cpu = smp_processor_id();
-	unsigned long to_whom = cpu_present_map ^ (1 << cpu);
-	struct mm_struct * mm = vma->vm_mm;
-	int timeout = 1000000;
-
-	spin_lock(&flush_tb_lock);
-
-	ipi_msg_flush_tb.flush_tb_mask = to_whom;
-	ipi_msg_flush_tb.p.flush_vma = vma;
-	ipi_msg_flush_tb.flush_addr = addr;
-	send_ipi_message(to_whom, IPI_TLB_PAGE);
+	struct flush_tlb_page_struct data;
+	struct mm_struct *mm = vma->vm_mm;
 
-	if (mm != current->mm)
-		flush_tlb_other(mm);
-	else
-		flush_tlb_current_page(mm, vma, addr);
-
-	while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
-		udelay(1);
-		barrier();
-	}
+	data.vma = vma;
+	data.mm = mm;
+	data.addr = addr;
 
-	if (timeout == 0) {
-		printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n",
-		       smp_processor_id(),
-		       ipi_msg_flush_tb.flush_tb_mask);
-		ipi_msg_flush_tb.flush_tb_mask = 0;
+	if (mm == current->mm)
+		flush_tlb_current_page(mm, vma, addr);
+	else
+		flush_tlb_other(mm);
+	
+	if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) {
+		printk(KERN_CRIT "flush_tlb_page: timed out\n");
 	}
-
-	spin_unlock(&flush_tb_lock);
 }
 
 void
@@ -892,57 +942,47 @@
 	flush_tlb_mm(mm);
 }
 
-#if DEBUG_SPINLOCK
-
-#ifdef MANAGE_SPINLOCK_IPL
-
-static inline long 
-spinlock_raise_ipl(spinlock_t * lock)
+
+int
+smp_info(char *buffer)
 {
- 	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;
-}
+	long i;
+	unsigned long sum = 0;
+	for (i = 0; i < NR_CPUS; i++)
+		sum += cpu_data[i].ipi_count;
 
-static inline void
-spinlock_restore_ipl(long prev)
-{
-	setipl(prev);
+	return sprintf(buffer, "CPUs probed %d active %d map 0x%lx IPIs %ld\n",
+		       smp_num_probed, smp_num_cpus, cpu_present_mask, sum);
 }
 
-#else
-
-#define spinlock_raise_ipl(LOCK)	((void)(LOCK), 0)
-#define spinlock_restore_ipl(PREV)	((void)(PREV))
-
-#endif /* MANAGE_SPINLOCK_IPL */
-
+
+#if DEBUG_SPINLOCK
 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 = 1<<27;
+	long stuck;
 	void *inline_pc = __builtin_return_address(0);
 	unsigned long started = jiffies;
 	int printed = 0;
 	int cpu = smp_processor_id();
-	long old_ipl = spinlock_raise_ipl(lock);
 
+	stuck = 1L << 28;
  try_again:
 
-	stuck = 0x10000000; /* was 4G, now 256M */
-
 	/* Use sub-sections to put the actual loop at the end
 	   of this object file's text section so as to perfect
 	   branch prediction.  */
@@ -961,52 +1001,53 @@
 	"	blbs	%0,2b\n"
 	"	br	1b\n"
 	".previous"
-	: "=r" (tmp),
-	  "=m" (__dummy_lock(lock)),
-	  "=r" (stuck)
-	: "2" (stuck));
+	: "=r" (tmp), "=m" (__dummy_lock(lock)), "=r" (stuck)
+	: "1" (__dummy_lock(lock)), "2" (stuck));
 
 	if (stuck < 0) {
-		if (!printed) {
-			printk("spinlock stuck at %p(%d) owner %s at %p\n",
-			       inline_pc, cpu, lock->task->comm,
-			       lock->previous);
-			printed = 1;
-		}
-		stuck = 1<<30;
+		printk(KERN_WARNING
+		       "%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("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;
 }
 #endif /* DEBUG_SPINLOCK */
-
+
 #if DEBUG_RWLOCK
 void write_lock(rwlock_t * lock)
 {
@@ -1038,18 +1079,17 @@
 	"	blt	%1,8b\n"
 	"	br	1b\n"
 	".previous"
-	: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
-	, "=&r" (stuck_lock), "=&r" (stuck_reader)
-	: "0" (__dummy_lock(lock))
-	, "3" (stuck_lock), "4" (stuck_reader)
-	);
+	: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy),
+	  "=&r" (stuck_lock), "=&r" (stuck_reader)
+	: "0" (__dummy_lock(lock)), "3" (stuck_lock), "4" (stuck_reader));
 
 	if (stuck_lock < 0) {
-		printk("write_lock stuck at %p\n", inline_pc);
+		printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc);
 		goto try_again;
 	}
 	if (stuck_reader < 0) {
-		printk("write_lock stuck on readers at %p\n", inline_pc);
+		printk(KERN_WARNING "write_lock stuck on readers at %p\n",
+		       inline_pc);
 		goto try_again;
 	}
 }
@@ -1079,11 +1119,10 @@
 	"	br	1b\n"
 	".previous"
 	: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock)
-	: "0" (__dummy_lock(lock)), "2" (stuck_lock)
-	);
+	: "0" (__dummy_lock(lock)), "2" (stuck_lock));
 
 	if (stuck_lock < 0) {
-		printk("read_lock stuck at %p\n", inline_pc);
+		printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc);
 		goto try_again;
 	}
 }
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c
--- v2.2.9/linux/arch/alpha/kernel/sys_dp264.c	Tue Feb 23 15:21:32 1999
+++ linux/arch/alpha/kernel/sys_dp264.c	Sat Jun 12 11:52:52 1999
@@ -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
@@ -66,34 +66,60 @@
 }
 
 static void
+clipper_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+{
+	if (irq >= 16) {
+		volatile unsigned long *csr;
+
+		if (TSUNAMI_bootcpu < 2)
+			if (!TSUNAMI_bootcpu)
+				csr = &TSUNAMI_cchip->dim0.csr;
+			else
+				csr = &TSUNAMI_cchip->dim1.csr;
+		else
+			if (TSUNAMI_bootcpu == 2)
+				csr = &TSUNAMI_cchip->dim2.csr;
+			else
+				csr = &TSUNAMI_cchip->dim3.csr;
+		
+		*csr = (~mask >> 16) | (1UL << 55); /* master ISA enable */
+		mb();
+		*csr;
+	}
+	else if (irq >= 8)
+		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
+	else
+		outb(mask, 0x21);	/* ISA PIC1 */
+}
+
+static void
 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;
+	unsigned long pld;
+	unsigned int i;
 
-        /* Read the interrupt summary register of TSUNAMI */
-        pld = TSUNAMI_cchip->dir0.csr;
+	/* 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);
-                }
+	/*
+	 * 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
 }
 
@@ -104,24 +130,48 @@
 
 	ack = irq = (vector - 0x800) >> 4;
 
-        /*
-         * The DP264 SRM console reports PCI interrupts with a vector
-	 * 0x100 *higher* than one might expect, as PCI IRQ 0 (ie bit 0)
-	 * shows up as IRQ 16, etc, etc. We adjust it down by 16 to have
-	 * it line up with the actual bit numbers from the DIM registers,
-	 * which is how we manage the interrupts/mask. Sigh...
-         */
-        if (irq >= 32)
-                ack = irq = irq - 16;
+	/*
+	 * The SRM console reports PCI interrupts with a vector calculated by:
+	 *
+	 *	0x900 + (0x10 * DRIR-bit)
+	 *
+	 * 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;
+
+	handle_irq(irq, ack, regs);
+}
+
+static void 
+clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+	int irq, ack;
+
+	ack = irq = (vector - 0x800) >> 4;
 
+	/*
+	 * The SRM console reports PCI interrupts with a vector calculated by:
+	 *
+	 *	0x900 + (0x10 * DRIR-bit)
+	 *
+	 * 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);
 }
 
 static void __init
 dp264_init_irq(void)
 {
-	volatile unsigned long *csr;
-
 	outb(0, DMA1_RESET_REG);
 	outb(0, DMA2_RESET_REG);
 	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
@@ -130,23 +180,26 @@
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = dp264_srm_device_interrupt;
 
-	if (TSUNAMI_bootcpu < 2)
-		if (!TSUNAMI_bootcpu)
-			csr = &TSUNAMI_cchip->dim0.csr;
-		else
-			csr = &TSUNAMI_cchip->dim1.csr;
-	else
-		if (TSUNAMI_bootcpu == 2)
-			csr = &TSUNAMI_cchip->dim2.csr;
-		else
-			csr = &TSUNAMI_cchip->dim3.csr;
-		
-	/* Note invert on MASK bits.  */
-        *csr = ~(alpha_irq_mask);
-	mb();
-        *csr;
+	dp264_update_irq_hw(16, alpha_irq_mask, 0);
 
-        enable_irq(55);     /* Enable CYPRESS interrupt controller (ISA).  */
+        enable_irq(55);     /* Enable ISA interrupt controller.  */
+	enable_irq(2);
+}
+
+static void __init
+clipper_init_irq(void)
+{
+	outb(0, DMA1_RESET_REG);
+	outb(0, DMA2_RESET_REG);
+	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
+	outb(0, DMA2_MASK_REG);
+
+	if (alpha_using_srm)
+		alpha_mv.device_interrupt = clipper_srm_device_interrupt;
+
+	clipper_update_irq_hw(16, alpha_irq_mask, 0);
+
+        enable_irq(55);     /* Enable ISA interrupt controller.  */
 	enable_irq(2);
 }
 
@@ -221,7 +274,7 @@
 	const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5;
 	int irq = COMMON_TABLE_LOOKUP;
 
-	if (irq >= 0)
+	if (irq > 0)
 		irq += 16 * dev2hose(dev);
 
 	return irq;
@@ -250,42 +303,38 @@
 		{    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;
+	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 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)) ;
+			}
+			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;
+			/* 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
@@ -300,14 +349,34 @@
 		{    30,    30,    30,    30,    30}, /* IdSel 11 21143 #2 */
 		{    -1,    -1,    -1,    -1,    -1}, /* IdSel 12 unused */
 		{    -1,    -1,    -1,    -1,    -1}, /* IdSel 13 unused */
-		{    47,    47,    46,    45,    44}, /* IdSel 14 slot 0 */
+		{    35,    35,    34,    33,    32}, /* IdSel 14 slot 0 */
 		{    39,    39,    38,    37,    36}, /* IdSel 15 slot 1 */
 		{    43,    43,    42,    41,    40}, /* IdSel 16 slot 2 */
-		{    35,    35,    34,    33,    32}, /* IdSel 17 slot 3 */
-};
+		{    47,    47,    46,    45,    44}, /* IdSel 17 slot 3 */
+	};
 	const long min_idsel = 7, max_idsel = 17, irqs_per_slot = 5;
+	return COMMON_TABLE_LOOKUP;
+}
+
+static int __init
+clipper_map_irq(struct pci_dev *dev, int slot, int pin)
+{
+	static char irq_tab[7][5] __initlocaldata = {
+		/*INT    INTA   INTB   INTC   INTD */
+		{ 16+ 8, 16+ 8, 16+ 9, 16+10, 16+11}, /* IdSel 1 slot 1 */
+		{ 16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 2 slot 2 */
+		{ 16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 3 slot 3 */
+		{ 16+20, 16+20, 16+21, 16+22, 16+23}, /* IdSel 4 slot 4 */
+		{ 16+24, 16+24, 16+25, 16+26, 16+27}, /* IdSel 5 slot 5 */
+		{ 16+28, 16+28, 16+29, 16+30, 16+31}, /* IdSel 6 slot 6 */
+		{    -1,    -1,    -1,    -1,    -1}  /* IdSel 7 ISA Bridge */
+	};
+	const long min_idsel = 1, max_idsel = 7, irqs_per_slot = 5;
 	int irq = COMMON_TABLE_LOOKUP;
 
+	if (irq > 0)
+		irq += 16 * dev2hose(dev);
+
 	return irq;
 }
 
@@ -336,6 +405,13 @@
 	SMC669_Init(0);
 }
 
+static void __init
+clipper_pci_fixup(void)
+{
+	layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
+	common_pci_fixup(clipper_map_irq, common_swizzle);
+}
+
 
 /*
  * The System Vectors
@@ -407,5 +483,28 @@
 	pci_fixup:		webbrick_pci_fixup,
 	kill_arch:		generic_kill_arch,
 };
-/* No alpha_mv alias for webbrick, since we compile it in unconditionally
-   with DP264; setup_arch knows how to cope.  */
+
+struct alpha_machine_vector clipper_mv __initmv = {
+	vector_name:		"Clipper",
+	DO_EV6_MMU,
+	DO_DEFAULT_RTC,
+	DO_TSUNAMI_IO,
+	DO_TSUNAMI_BUS,
+	machine_check:		tsunami_machine_check,
+	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+
+	nr_irqs:		64,
+	irq_probe_mask:		_PROBE_MASK(64),
+	update_irq_hw:		clipper_update_irq_hw,
+	ack_irq:		generic_ack_irq,
+	device_interrupt:	dp264_device_interrupt,
+
+	init_arch:		tsunami_init_arch,
+	init_irq:		clipper_init_irq,
+	init_pit:		generic_init_pit,
+	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.  */
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/sys_takara.c linux/arch/alpha/kernel/sys_takara.c
--- v2.2.9/linux/arch/alpha/kernel/sys_takara.c	Wed Sep  9 14:51:04 1998
+++ linux/arch/alpha/kernel/sys_takara.c	Sat Jun 12 11:52:52 1999
@@ -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.
  */
@@ -30,11 +30,21 @@
 #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 @@
 		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 @@
 	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 @@
 
 	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,
 
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.2.9/linux/arch/alpha/kernel/time.c	Wed Apr 28 11:37:29 1999
+++ linux/arch/alpha/kernel/time.c	Sat Jun 12 11:52:52 1999
@@ -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..
@@ -42,6 +42,9 @@
 #include "proto.h"
 #include "irq.h"
 
+extern rwlock_t xtime_lock;
+extern volatile unsigned long lost_ticks;	/* kernel/sched.c */
+
 static int set_rtc_mmss(unsigned long);
 
 
@@ -86,15 +89,15 @@
 	long nticks;
 
 #ifdef __SMP__
-	extern void smp_percpu_timer_interrupt(struct pt_regs *);
-	extern unsigned int boot_cpu_id;
-	/* when SMP, do this for *all* CPUs, 
-	   but only do the rest for the boot CPU */
+	/* When SMP, do this for *all* CPUs, but only do the rest for
+           the boot CPU.  */
 	smp_percpu_timer_interrupt(regs);
-	if (smp_processor_id() != boot_cpu_id)
-	  return;
+	if (smp_processor_id() != smp_boot_cpuid)
+		return;
 #endif
 
+	write_lock(&xtime_lock);
+
 	/*
 	 * Calculate how many ticks have passed since the last update,
 	 * including any previous partial leftover.  Save any resulting
@@ -124,6 +127,8 @@
 		int tmp = set_rtc_mmss(xtime.tv_sec);
 		state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0);
 	}
+
+	write_unlock(&xtime_lock);
 }
 
 /*
@@ -226,7 +231,8 @@
 {
 	void (*irq_handler)(int, void *, struct pt_regs *);
 	unsigned int year, mon, day, hour, min, sec, cc1, cc2;
-	unsigned long cycle_freq, diff, one_percent;
+	unsigned long cycle_freq, one_percent;
+	long diff;
 
 	/*
 	 * The Linux interpretation of the CMOS clock register contents:
@@ -242,7 +248,7 @@
 
 	if (!est_cycle_freq) {
 		/* Sometimes the hwrpb->cycle_freq value is bogus. 
-	   	Go another round to check up on it and see.  */
+		   Go another round to check up on it and see.  */
 		do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
 		do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
 		cc2 = rpcc();
@@ -279,8 +285,7 @@
 	mon = CMOS_READ(RTC_MONTH);
 	year = CMOS_READ(RTC_YEAR);
 
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	{
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		BCD_TO_BIN(sec);
 		BCD_TO_BIN(min);
 		BCD_TO_BIN(hour);
@@ -328,18 +333,24 @@
 void
 do_gettimeofday(struct timeval *tv)
 {
-	unsigned long flags, delta_cycles, delta_usec;
-	unsigned long sec, usec;
-	__u32 now;
-	extern volatile unsigned long lost_ticks;	/*kernel/sched.c*/
+	unsigned long sec, usec, lost, flags;
+	unsigned long delta_cycles, delta_usec, partial_tick;
 
-	now = rpcc();
-	save_and_cli(flags);
+	read_lock_irqsave(&xtime_lock, flags);
+
+	delta_cycles = rpcc() - state.last_time;
 	sec = xtime.tv_sec;
 	usec = xtime.tv_usec;
-	delta_cycles = now - state.last_time;
-	restore_flags(flags);
+	partial_tick = state.partial_tick;
+	lost = lost_ticks;
+
+	read_unlock_irqrestore(&xtime_lock, flags);
 
+#ifdef __SMP__
+	/* Until and unless we figure out how to get cpu cycle counters
+	   in sync and keep them there, we can't use the rpcc tricks.  */
+	delta_usec = lost * (1000000 / HZ);
+#else
 	/*
 	 * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
 	 *	= cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
@@ -354,13 +365,10 @@
 	 */
 
 	delta_usec = (delta_cycles * state.scaled_ticks_per_cycle 
-			+ state.partial_tick
-			+ (lost_ticks << FIX_SHIFT) ) * 15625;
+		      + partial_tick
+		      + (lost << FIX_SHIFT)) * 15625;
 	delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
-
-	/* the 'lost_tics' term above implements this:	
-	 * delta_usec += lost_ticks * (1000000 / HZ);
-	 */
+#endif
 
 	usec += delta_usec;
 	if (usec >= 1000000) {
@@ -375,13 +383,41 @@
 void
 do_settimeofday(struct timeval *tv)
 {
-	cli();
-	xtime = *tv;
+	unsigned long delta_usec;
+	long sec, usec;
+	
+	write_lock_irq(&xtime_lock);
+
+	/* The offset that is added into time in do_gettimeofday above
+	   must be subtracted out here to keep a coherent view of the
+	   time.  Without this, a full-tick error is possible.  */
+
+#ifdef __SMP__
+	delta_usec = lost_ticks * (1000000 / HZ);
+#else
+	delta_usec = rpcc() - state.last_time;
+	delta_usec = (delta_usec * state.scaled_ticks_per_cycle 
+		      + state.partial_tick
+		      + (lost_ticks << FIX_SHIFT)) * 15625;
+	delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
+#endif
+
+	sec = tv->tv_sec;
+	usec = tv->tv_usec;
+	usec -= delta_usec;
+	if (usec < 0) {
+		usec += 1000000;
+		sec -= 1;
+	}
+
+	xtime.tv_sec = sec;
+	xtime.tv_usec = usec;
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+
+	write_unlock_irq(&xtime_lock);
 }
 
 
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.2.9/linux/arch/alpha/kernel/traps.c	Tue May 11 13:10:27 1999
+++ linux/arch/alpha/kernel/traps.c	Sat May 22 13:42:51 1999
@@ -1,5 +1,5 @@
 /*
- * kernel/traps.c
+ * arch/alpha/kernel/traps.c
  *
  * (C) Copyright 1994 Linus Torvalds
  */
@@ -95,6 +95,9 @@
 {
 	if (regs->ps & 8)
 		return;
+#ifdef __SMP__
+	printk("CPU %d ", hard_smp_processor_id());
+#endif
 	printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
 	dik_show_regs(regs, r9_15);
 	dik_show_code((unsigned int *)regs->pc);
@@ -128,8 +131,8 @@
 	if (summary & 1) {
 		/* Software-completion summary bit is set, so try to
 		   emulate the instruction.  */
-		if (implver() == IMPLVER_EV6) {
-			/* Whee!  EV6 has precice exceptions.  */
+		if (!amask(AMASK_PRECISE_TRAP)) {
+			/* 21264 (except pass 1) has precise exceptions.  */
 			if (alpha_fp_emul(regs.pc - 4))
 				return;
 		} else {
@@ -138,14 +141,12 @@
 		}
 	}
 
-	lock_kernel();
 #if 0
 	printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
 		current->comm, regs.pc, summary, write_mask);
 #endif
 	die_if_kernel("Arithmetic fault", &regs, 0, 0);
 	send_sig(SIGFPE, current, 1);
-	unlock_kernel();
 }
 
 asmlinkage void
@@ -235,10 +236,8 @@
 	  unsigned long a2, unsigned long a3, unsigned long a4,
 	  unsigned long a5, struct pt_regs regs)
 {
-	lock_kernel();
 	die_if_kernel("Instruction fault", &regs, type, 0);
 	force_sig(SIGILL, current);
-	unlock_kernel();
 }
 
 
@@ -453,10 +452,8 @@
 		unsigned long newpc;
 		newpc = fixup_exception(una_reg, fixup, pc);
 
-		lock_kernel();
 		printk("Forwarding unaligned exception at %lx (%lx)\n",
 		       pc, newpc);
-		unlock_kernel();
 
 		(&regs)->pc = newpc;
 		return;
@@ -610,11 +607,9 @@
 			cnt = 0;
 		}
 		if (++cnt < 5) {
-			lock_kernel();
 			printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
 			       current->comm, current->pid,
 			       regs->pc - 4, va, opcode, reg);
-			unlock_kernel();
 		}
 		last_time = jiffies;
 	}
@@ -868,16 +863,12 @@
 
 give_sigsegv:
 	regs->pc -= 4;  /* make pc point to faulting insn */
-	lock_kernel();
 	send_sig(SIGSEGV, current, 1);
-	unlock_kernel();
 	return;
 
 give_sigbus:
 	regs->pc -= 4;
-	lock_kernel();
 	send_sig(SIGBUS, current, 1);
-	unlock_kernel();
 	return;
 }
 
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.2.9/linux/arch/alpha/mm/init.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/alpha/mm/init.c	Sat May 22 13:42:53 1999
@@ -256,26 +256,6 @@
 	return start_mem;
 }
 
-#ifdef __SMP__
-/*
- * paging_init_secondary(), called ONLY by secondary CPUs,
- * sets up current->tss contents appropriately and does a load_PCB.
- * note that current should be pointing at the idle thread task struct
- * for this CPU.
- */
-void
-paging_init_secondary(void)
-{
-	current->tss.ptbr = init_task.tss.ptbr;
-	current->tss.pal_flags = 1;
-	current->tss.flags = 0;
-	load_PCB(&current->tss);
-	tbia();
-
-	return;
-}
-#endif /* __SMP__ */
-
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
 void
 srm_paging_stop (void)
diff -u --recursive --new-file v2.2.9/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.2.9/linux/arch/i386/boot/setup.S	Wed Dec 16 10:32:54 1998
+++ linux/arch/i386/boot/setup.S	Mon Jun  7 16:13:07 1999
@@ -753,19 +753,29 @@
 ! 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
 
 !
diff -u --recursive --new-file v2.2.9/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- v2.2.9/linux/arch/i386/boot/video.S	Mon Oct  5 13:13:35 1998
+++ linux/arch/i386/boot/video.S	Fri May 14 12:47:07 1999
@@ -1,14 +1,19 @@
 !
-!	Display adapter & video mode setup, version 2.12 (25-May-98)
+!	Display adapter & video mode setup, version 2.13 (14-May-99)
 !
-!	Copyright (C) 1995 -- 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+!	Copyright (C) 1995 -- 1999 Martin Mares <mj@ucw.cz>
 !	Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
 !
+!	For further information, look at Documentation/svga.txt.
+!
 
 #include <linux/config.h> /* for CONFIG_VIDEO_* */
 
 ! Enable autodetection of SVGA adapters and modes. If you really need this
-! feature, drop me a mail as I think of removing it some day...
+! feature, drop me a mail as I think of removing it some day. You can
+! always enter `scan' to get the video mode table and then use the real
+! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu
+! item numbers) which don't rely on any autodetection.
 #undef CONFIG_VIDEO_SVGA
 
 ! Enable autodetection of VESA modes
@@ -1939,7 +1944,7 @@
 badmdt:		.ascii	"You passed an undefined mode number."
 		db	0x0d, 0x0a, 0
 vesaer:		.ascii	"Error: Scanning of VESA modes failed. Please "
-		.ascii	"report to <mj@k332.feld.cvut.cz>."
+		.ascii	"report to <mj@ucw.cz>."
 		db	0x0d, 0x0a, 0
 old_name:	.ascii	"CGA/MDA/HGA"
 		db	0
diff -u --recursive --new-file v2.2.9/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- v2.2.9/linux/arch/i386/kernel/mca.c	Tue May 11 13:10:27 1999
+++ linux/arch/i386/kernel/mca.c	Mon Jun  7 16:18:16 1999
@@ -112,21 +112,25 @@
 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 @@
 	NULL,			/* writepage */
 	NULL,			/* bmap */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* updatepage */
+	NULL			/* revalidate */
 };
 #endif
 
@@ -220,18 +227,19 @@
 	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 @@
 		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 @@
 	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 @@
 		free_page(page);
 		return length;
 	}
-	if(start != 0) {
+	if(start != NULL) {
 		/* We have had block-adjusting processing! */
 
 		copy_to_user(buf, start, length);
diff -u --recursive --new-file v2.2.9/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.2.9/linux/arch/i386/kernel/mtrr.c	Tue May 11 13:10:27 1999
+++ linux/arch/i386/kernel/mtrr.c	Fri May 14 09:00:17 1999
@@ -1,6 +1,6 @@
 /*  Generic MTRR (Memory Type Range Register) driver.
 
-    Copyright (C) 1997-1998  Richard Gooch
+    Copyright (C) 1997-1999  Richard Gooch
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -196,6 +196,11 @@
     19990310   Richard Gooch <rgooch@atnf.csiro.au>
 	       Support K6-II/III based on Alan Cox's <alan@redhat.com> patches.
   v1.34
+    19990511   Bart Hartgers <bart@etpmod.phys.tue.nl>
+	       Support Centaur C6 MCR's.
+    19990512   Richard Gooch <rgooch@atnf.csiro.au>
+	       Minor cleanups.
+  v1.35
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -232,7 +237,7 @@
 #include <asm/hardirq.h>
 #include "irq.h"
 
-#define MTRR_VERSION            "1.34 (19990310)"
+#define MTRR_VERSION            "1.35 (19990512)"
 
 #define TRUE  1
 #define FALSE 0
@@ -313,8 +318,13 @@
     /*  Disable interrupts locally  */
     __save_flags (ctxt->flags); __cli ();
 
-    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return;
-
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_AMD:
+      case X86_VENDOR_CENTAUR:
+	return;
+	/*break;*/
+    }
     /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
     if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
 	asm volatile ("movl  %%cr4, %0\n\t"
@@ -352,12 +362,14 @@
 {
     unsigned long tmp;
 
-    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+    switch (boot_cpu_data.x86_vendor)
     {
+      case X86_VENDOR_AMD:
+      case X86_VENDOR_CENTAUR:
 	__restore_flags (ctxt->flags);
 	return;
+	/*break;*/
     }
-
     /*  Flush caches and TLBs  */
     asm volatile ("wbinvd" : : : "memory" );
 
@@ -399,7 +411,9 @@
 	return (config & 0xff);
 	/*break;*/
       case X86_VENDOR_CYRIX:
-	/*  Cyrix have 8 ARRs */
+	/*  Cyrix have 8 ARRs  */
+      case X86_VENDOR_CENTAUR:
+        /*  and Centaur has 8 MCR's  */
 	return 8;
 	/*break;*/
       case X86_VENDOR_AMD:
@@ -422,6 +436,7 @@
 	/*break;*/
       case X86_VENDOR_CYRIX:
       case X86_VENDOR_AMD:
+      case X86_VENDOR_CENTAUR:
 	return 1;
 	/*break;*/
     }
@@ -450,7 +465,6 @@
 
     /* Clean up mask_lo so it gives the real address mask. */
     mask_lo = (mask_lo & 0xfffff000UL);
-    
     /* This works correctly if size is a power of two, i.e. a
        contiguous range. */
     *size = ~(mask_lo - 1);
@@ -480,7 +494,6 @@
 
     /* Enable interrupts if it was enabled previously */
     __restore_flags (flags);
-    
     shift = ((unsigned char *) base)[1] & 0x0f;
     *base &= 0xfffff000UL;
 
@@ -550,6 +563,20 @@
     return;
 }   /*  End Function amd_get_mtrr  */
 
+static struct
+{
+    unsigned long high;
+    unsigned long low;
+} centaur_mcr[8];
+
+static void centaur_get_mcr (unsigned int reg, unsigned long *base,
+			     unsigned long *size, mtrr_type *type)
+{
+    *base = centaur_mcr[reg].high & 0xfffff000;
+    *size = (~(centaur_mcr[reg].low & 0xfffff000))+1;
+    *type = MTRR_TYPE_WRCOMB;	/*  If it is there, it is write-combining  */
+}   /*  End Function centaur_get_mcr  */
+
 static void (*get_mtrr) (unsigned int reg, unsigned long *base,
 			 unsigned long *size, mtrr_type *type) = NULL;
 
@@ -647,11 +674,10 @@
     else
 	/* Set the register to the base (already shifted for us), the
 	   type (off by one) and an inverted bitmask of the size
-        	   
 	   The size is the only odd bit. We are fed say 512K
 	   We invert this and we get 111 1111 1111 1011 but
 	   if you subtract one and invert you get the desired
-	   111 1111 1111 1100 mask 
+	   111 1111 1111 1100 mask
 	   */
 	*(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
     /*
@@ -663,10 +689,36 @@
     if (do_safe) set_mtrr_done (&ctxt);
 }   /*  End Function amd_set_mtrr_up  */
 
+
+static void centaur_set_mcr_up (unsigned int reg, unsigned long base,
+				unsigned long size, mtrr_type type,
+				int do_safe)
+{
+    struct set_mtrr_context ctxt;
+    unsigned long low, high;
+
+    if (do_safe) set_mtrr_prepare( &ctxt );
+    if (size == 0)
+    {
+        /*  Disable  */
+        high = low = 0;
+    }
+    else
+    {
+        high = base & 0xfffff000; /* base works on 4K pages... */
+        low = ((~(size-1))&0xfffff000);
+        low |= 0x1f;		  /* only support write-combining... */
+    }
+    centaur_mcr[reg].high = high;
+    centaur_mcr[reg].low = low;
+    wrmsr (0x110 + reg, low, high);
+    if (do_safe) set_mtrr_done( &ctxt );
+}   /*  End Function centaur_set_mtrr_up  */
+
 static void (*set_mtrr_up) (unsigned int reg, unsigned long base,
 			    unsigned long size, mtrr_type type,
 			    int do_safe) = NULL;
-     
+
 #ifdef __SMP__
 
 struct mtrr_var_range
@@ -694,23 +746,21 @@
 {
     unsigned int lo, hi;
     int changed = FALSE;
-    
-    rdmsr(MTRRphysBase_MSR(index), lo, hi); 
 
+    rdmsr(MTRRphysBase_MSR(index), lo, hi);
     if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
 	|| (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
-	wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); 
+	wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
 	changed = TRUE;
     }
 
-    rdmsr(MTRRphysMask_MSR(index), lo, hi); 
+    rdmsr(MTRRphysMask_MSR(index), lo, hi);
 
     if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
 	|| (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
-	wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); 
+	wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
 	changed = TRUE;
     }
-    
     return changed;
 }   /*  End Function set_mtrr_var_range_testing  */
 
@@ -723,7 +773,6 @@
 
     for (i = 0; i < 2; i++)
 	rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
- 
     for (i = 0; i < 8; i++)
 	rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
 }   /*  End Function get_fixed_ranges  */
@@ -777,14 +826,13 @@
     unsigned long lo, dummy;
 
     nvrs = state->num_var_ranges = get_num_var_ranges();
-    vrs = state->var_ranges 
+    vrs = state->var_ranges
               = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
     if (vrs == NULL)
 	nvrs = state->num_var_ranges = 0;
 
     for (i = 0; i < nvrs; i++)
 	get_mtrr_var_range (i, &vrs[i]);
-    
     get_fixed_ranges (state->fixed_ranges);
 
     rdmsr (MTRRdefType_MSR, lo, dummy);
@@ -818,7 +866,6 @@
 
     if ( set_fixed_ranges_testing(state->fixed_ranges) )
 	change_mask |= MTRR_CHANGE_MASK_FIXED;
-    
     /*  Set_mtrr_restore restores the old value of MTRRdefType,
 	so to set it we fiddle with the saved value  */
     if ((ctxt->deftype_lo & 0xff) != state->def_type
@@ -831,7 +878,7 @@
     return change_mask;
 }   /*  End Function set_mtrr_state  */
 
- 
+
 static atomic_t undone_count;
 static volatile int wait_barrier_execute = FALSE;
 static volatile int wait_barrier_cache_enable = FALSE;
@@ -1025,13 +1072,22 @@
 	}
 	/*  Fall through  */
       case X86_VENDOR_CYRIX:
+      case X86_VENDOR_CENTAUR:
 	if ( (base & 0xfff) || (size & 0xfff) )
 	{
 	    printk ("mtrr: size and base must be multiples of 4 kiB\n");
 	    printk ("mtrr: size: %lx  base: %lx\n", size, base);
 	    return -EINVAL;
 	}
-	if (base + size < 0x100000)
+        if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR)
+	{
+	    if (type != MTRR_TYPE_WRCOMB)
+	    {
+		printk ("mtrr: only write-combining is supported\n");
+		return -EINVAL;
+	    }
+	}
+	else if (base + size < 0x100000)
 	{
 	    printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
 		    base, size);
@@ -1050,7 +1106,7 @@
 	}
 	break;
       case X86_VENDOR_AMD:
-    	/* Apply the K6 block alignment and size rules 
+    	/* Apply the K6 block alignment and size rules
     	   In order
     	      o Uncached or gathering only
     	      o 128K or bigger block
@@ -1572,6 +1628,30 @@
     if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");
 }   /*  End Function cyrix_arr_init  */
 
+__initfunc(static void centaur_mcr_init (void))
+{
+    unsigned i;
+    struct set_mtrr_context ctxt;
+
+    set_mtrr_prepare (&ctxt);
+    /* Unfortunately, MCR's are read-only, so there is no way to
+     * find out what the bios might have done.
+     */
+    /* Clear all MCR's.
+     * This way we are sure that the centaur_mcr array contains the actual
+     * values. The disadvantage is that any BIOS tweaks are thus undone.
+     */
+    for (i = 0; i < 8; ++i)
+    {
+        centaur_mcr[i].high = 0;
+	centaur_mcr[i].low = 0;
+	wrmsr (0x110 + i , 0, 0);
+    }
+    /*  Throw the main write-combining switch...  */
+    wrmsr (0x120, 0x01f0001f, 0);
+    set_mtrr_done (&ctxt);
+}   /*  End Function centaur_mcr_init  */
+
 __initfunc(static void mtrr_setup (void))
 {
     printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
@@ -1582,7 +1662,6 @@
 	set_mtrr_up = intel_set_mtrr_up;
 	break;
       case X86_VENDOR_CYRIX:
-	printk ("mtrr: Using Cyrix style ARRs\n");
 	get_mtrr = cyrix_get_arr;
 	set_mtrr_up = cyrix_set_arr_up;
 	get_free_region = cyrix_get_free_region;
@@ -1591,6 +1670,10 @@
 	get_mtrr = amd_get_mtrr;
 	set_mtrr_up = amd_set_mtrr_up;
 	break;
+     case X86_VENDOR_CENTAUR:
+        get_mtrr = centaur_get_mcr;
+        set_mtrr_up = centaur_set_mcr_up;
+        break;
     }
 }   /*  End Function mtrr_setup  */
 
@@ -1611,6 +1694,9 @@
       case X86_VENDOR_CYRIX:
 	cyrix_arr_init ();
 	break;
+      case X86_VENDOR_CENTAUR:
+        centaur_mcr_init ();
+        break;
     }
 }   /*  End Function mtrr_init_boot_cpu  */
 
@@ -1675,6 +1761,9 @@
       case X86_VENDOR_CYRIX:
 	cyrix_arr_init ();
 	break;
+      case X86_VENDOR_CENTAUR:
+        centaur_mcr_init ();
+        break;
     }
 #  endif  /*  !__SMP__  */
 
diff -u --recursive --new-file v2.2.9/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.2.9/linux/arch/i386/kernel/setup.c	Tue May 11 13:10:27 1999
+++ linux/arch/i386/kernel/setup.c	Tue Jun  8 10:43:21 1999
@@ -9,6 +9,11 @@
  *  Force Cyrix 6x86(MX) and M II processors to report MTRR capability
  *  and fix against Cyrix "coma bug" by
  *      Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
+ * 
+ *  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.
  */
 
 /*
@@ -685,7 +690,7 @@
 	    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",
@@ -791,13 +796,19 @@
 			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)";
+			    	}
+                        }
+                    }
 		}
 			
 	}
@@ -861,6 +872,8 @@
 		/* lv|=(1<<6);	- may help too if the board can cope */
 		printk("now 0x%X", lv);
 		wrmsr(0x107, lv, hv);
+		/* Emulate MTRRs using Centaur's MCR. */
+		c->x86_capability |= X86_FEATURE_MTRR;	   	
 	}
 	printk("\n");
 }
diff -u --recursive --new-file v2.2.9/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.2.9/linux/arch/i386/kernel/signal.c	Wed Dec 16 10:32:54 1998
+++ linux/arch/i386/kernel/signal.c	Mon Jun  7 16:14:20 1999
@@ -698,6 +698,7 @@
 			default:
 				lock_kernel();
 				sigaddset(&current->signal, signr);
+				recalc_sigpending(current);
 				current->flags |= PF_SIGNALED;
 				do_exit(exit_code);
 				/* NOTREACHED */
diff -u --recursive --new-file v2.2.9/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.2.9/linux/arch/i386/kernel/smp.c	Tue May 11 13:10:27 1999
+++ linux/arch/i386/kernel/smp.c	Wed Jun  2 11:29:27 1999
@@ -2,7 +2,7 @@
  *	Intel MP v1.1/v1.4 specification support routines for multi-pentium
  *	hosts.
  *
- *	(c) 1995 Alan Cox, CymruNET Ltd  <alan@cymru.net>
+ *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
  *	(c) 1998 Ingo Molnar
  *
  *	Supported by Caldera http://www.caldera.com.
diff -u --recursive --new-file v2.2.9/linux/arch/i386/lib/checksum.S linux/arch/i386/lib/checksum.S
--- v2.2.9/linux/arch/i386/lib/checksum.S	Tue Jan 19 11:32:51 1999
+++ linux/arch/i386/lib/checksum.S	Tue Jun  1 14:05:46 1999
@@ -369,7 +369,7 @@
 
 #define ROUND1(x) \
 	SRC(movl x(%esi), %ebx	)	;	\
-	addl %ebx, %eax\n		;	\
+	addl %ebx, %eax			;	\
 	DST(movl %ebx, x(%edi)	)	; 
 
 #define ROUND(x) \
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.2.9/linux/arch/ppc/Makefile	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/Makefile	Fri Jun  4 13:30:47 1999
@@ -29,6 +29,10 @@
 CFLAGS := $(CFLAGS) -mcpu=860
 endif
 
+ifdef CONFIG_PPC64
+CFLAGS := $(CFLAGS) -Wa,-mppc64bridge #-Wa,-mppc64
+#CFLAGS := $(CFLAGS) -Wa,-mppc64 -mpowerpc64
+endif
 
 HEAD := arch/ppc/kernel/head.o
 
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.2.9/linux/arch/ppc/boot/Makefile	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/boot/Makefile	Fri Jun  4 13:30:47 1999
@@ -26,9 +26,15 @@
 ISZ = 0
 
 ifeq ($(CONFIG_SMP),y)
-TFTPIMAGE=/tftpboot/zImage.prep.smp
+TFTPIMAGE=/tftpboot/zImage.prep.smp$(MSIZE)
 else
-TFTPIMAGE=/tftpboot/zImage.prep
+TFTPIMAGE=/tftpboot/zImage.prep$(MSIZE)
+endif
+
+ifeq ($(CONFIG_PPC64),y)
+MSIZE=.64
+else
+MSIZE=
 endif
 
 ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c
--- v2.2.9/linux/arch/ppc/boot/misc.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/boot/misc.c	Fri Jun  4 13:30:47 1999
@@ -1,7 +1,7 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.64 1999/04/30 05:52:46 cort Exp $
+ * $Id: misc.c,v 1.64.2.2 1999/05/29 19:09:29 cort Exp $
  * 
  * Adapted for PowerPC by Gary Thomas
  *
@@ -363,7 +363,7 @@
 			if (board_type == 0xe0) {	
 				base_mod = inb(0x803);
 				/* if a MVME2300/2400 or a Sitka then no keyboard */
-				if((base_mod == 0x9) || (base_mod == 0xF9) ||
+				if((base_mod == 0xFA) || (base_mod == 0xF9) ||
 				   (base_mod == 0xE1)) {
 					keyb_present = 0;	/* no keyboard */
 				}
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile
--- v2.2.9/linux/arch/ppc/chrpboot/Makefile	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/chrpboot/Makefile	Fri Jun  4 13:30:47 1999
@@ -17,21 +17,27 @@
 	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
 
 CFLAGS	= -O -fno-builtin -DSTDC_HEADERS -I$(TOPDIR)/include
-LD_ARGS = -T ../vmlinux.lds -Ttext 0x00800000
+LD_ARGS = -Ttext 0x00400000
 OBJCOPY = $(CROSS_COMPILE)objcopy
 
 OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o # initrd.o
 LIBS = $(TOPDIR)/lib/lib.a
 
+ifeq ($(CONFIG_PPC64),y)
+MSIZE=.64
+else
+MSIZE=
+endif
+
 ifeq ($(CONFIG_ALL_PPC),y)
 # yes, we want to build chrp stuff
 CONFIG_CHRP = y
 endif
 
 ifeq ($(CONFIG_SMP),y)
-TFTPIMAGE=/tftpboot/zImage.chrp.smp
+TFTPIMAGE=/tftpboot/zImage.chrp.smp$(MSIZE)
 else
-TFTPIMAGE=/tftpboot/zImage.chrp
+TFTPIMAGE=/tftpboot/zImage.chrp$(MSIZE)
 endif
 
 all:	$(TOPDIR)/zImage
@@ -59,9 +65,10 @@
 initrd.o: ramdisk.image.gz piggyback
 	./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o
 
-zImage: $(OBJS) no_initrd.o
+zImage: $(OBJS) no_initrd.o mknote
 	$(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS)
-	objcopy zImage zImage
+	./mknote > note
+	$(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
 
 zImage.initrd: $(OBJS) initrd.o
 	$(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS)
@@ -86,8 +93,7 @@
 
 
 clean:
-	rm -f piggyback
-	rm -f $(OBJS) zImage
+	rm -f piggyback note mknote $(OBJS) zImage
 
 fastdep:
 	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c
--- v2.2.9/linux/arch/ppc/chrpboot/main.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/chrpboot/main.c	Fri Jun  4 13:30:47 1999
@@ -17,9 +17,9 @@
 #define get_32be(x)	(*(unsigned *)(x))
 
 #define RAM_START	0x00000000
-#define RAM_END		0x00800000	/* only 8M mapped with BATs */
+#define RAM_END		(8<<20)
 
-#define RAM_FREE	0x00540000	/* after image of chrpboot */
+#define RAM_FREE	(6<<20)		/* after image of chrpboot */
 #define PROG_START	0x00010000
 
 char *avail_ram;
@@ -38,16 +38,16 @@
     void *dst;
     unsigned char *im;
     unsigned initrd_start, initrd_size;
+    extern char _start;
     
-    printf("chrpboot starting\n\r");
-    /* setup_bats(); */
+    printf("chrpboot starting: loaded at 0x%x\n\r", &_start);
 
     if (initrd_len) {
 	initrd_size = initrd_len;
 	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
 	a1 = initrd_start;
 	a2 = initrd_size;
-	printf("initial ramdisk at %x (%u bytes)\n\r", initrd_start,
+	printf("initial ramdisk at 0x%x (%u bytes)\n\r", initrd_start,
 	       initrd_size);
 	memcpy((char *)initrd_start, initrd_data, initrd_size);
 	end_avail = (char *)initrd_start;
@@ -58,25 +58,19 @@
     dst = (void *) PROG_START;
 
     if (im[0] == 0x1f && im[1] == 0x8b) {
-	void *cp = (void *) RAM_FREE;
-	avail_ram = (void *) (RAM_FREE + ((len + 7) & -8));
-	memcpy(cp, im, len);
-	printf("gunzipping... ");
-	gunzip(dst, 0x400000, cp, &len);
-	printf("done\n\r");
-
+	avail_ram = (char *)RAM_FREE;
+	printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+	gunzip(dst, 0x400000, im, &len);
+	printf("done %u bytes\n\r", len);
     } else {
 	memmove(dst, im, len);
     }
 
     flush_cache(dst, len);
-
-    sa = PROG_START+12;
+    
+    sa = *(unsigned long *)PROG_START+PROG_START;
     printf("start address = 0x%x\n\r", sa);
 
-#if 0
-    pause();
-#endif
     (*(void (*)())sa)(a1, a2, prom, 0, 0);
 
     printf("returned?\n\r");
@@ -150,7 +144,7 @@
     s.avail_out = dstlen;
     r = inflate(&s, Z_FINISH);
     if (r != Z_OK && r != Z_STREAM_END) {
-	printf("inflate returned %d\n\r", r);
+	printf("inflate returned %d msg: %s\n\r", r, s.msg);
 	exit();
     }
     *lenp = s.next_out - (unsigned char *) dst;
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile
--- v2.2.9/linux/arch/ppc/coffboot/Makefile	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/coffboot/Makefile	Fri Jun  4 13:30:47 1999
@@ -23,10 +23,16 @@
 CONFIG_PMAC = y
 endif
 
+ifeq ($(CONFIG_PPC64),y)
+MSIZE=.64
+else
+MSIZE=
+endif
+
 ifeq ($(CONFIG_SMP),y)
-TFTPIMAGE=/tftpboot/zImage.pmac.smp
+TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE)
 else
-TFTPIMAGE=/tftpboot/zImage.pmac
+TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE)
 endif
 
 ifeq ($(CONFIG_PMAC),y)
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/coffboot/zlib.c linux/arch/ppc/coffboot/zlib.c
--- v2.2.9/linux/arch/ppc/coffboot/zlib.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/coffboot/zlib.c	Fri Jun  4 13:30:47 1999
@@ -11,7 +11,7 @@
  * - added Z_PACKET_FLUSH (see zlib.h for details)
  * - added inflateIncomp
  *
- * $Id: zlib.c,v 1.2 1998/09/03 17:40:53 cort Exp $
+ * $Id: zlib.c,v 1.2.2.1 1999/05/29 19:09:42 cort Exp $
  */
 
 /*+++++*/
@@ -649,6 +649,11 @@
 /*   load local pointers */
 #define LOAD {LOADIN LOADOUT}
 
+/*
+ * The IBM 150 firmware munges the data right after _etext[].  This
+ * protects it. -- Cort
+ */
+local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0};
 /* And'ing with mask[n] masks the lower n bits */
 local uInt inflate_mask[] = {
     0x0000,
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.2.9/linux/arch/ppc/common_defconfig	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/common_defconfig	Fri Jun  4 13:30:47 1999
@@ -7,6 +7,7 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
+# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
 # CONFIG_PMAC is not set
 # CONFIG_PREP is not set
@@ -15,13 +16,14 @@
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
+CONFIG_6xx=y
 
 #
 # General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -32,7 +34,7 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
+# CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
 CONFIG_VGA_CONSOLE=y
@@ -58,7 +60,7 @@
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -73,15 +75,17 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDE_PMAC=y
-# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -110,7 +114,7 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
 
 #
 # (it is safe to leave these untouched)
@@ -151,12 +155,12 @@
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -191,13 +195,14 @@
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
-# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
 # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
@@ -301,27 +306,17 @@
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
 CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
+# CONFIG_FB_MATROX_MILLENIUM is not set
 CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_G100 is not set
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-# CONFIG_FBCON_MFB is not set
-# CONFIG_FBCON_CFB2 is not set
-# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
-# CONFIG_FBCON_AFB is not set
-# CONFIG_FBCON_ILBM is not set
-# CONFIG_FBCON_IPLAN2P2 is not set
-# CONFIG_FBCON_IPLAN2P4 is not set
-# CONFIG_FBCON_IPLAN2P8 is not set
-# CONFIG_FBCON_MAC is not set
-# CONFIG_FBCON_VGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -355,7 +350,7 @@
 # CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
+CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 
 #
@@ -390,10 +385,10 @@
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+CONFIG_VFAT_FS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -470,7 +465,34 @@
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
+CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+CONFIG_SOUND_CS4232=m
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.2.9/linux/arch/ppc/config.in	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/config.in	Fri Jun  4 13:30:47 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.92 1999/04/30 05:41:43 cort Exp $
+# $Id: config.in,v 1.92.2.1 1999/05/29 19:09:16 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -8,8 +8,9 @@
 comment 'Platform support'
 define_bool CONFIG_PPC y
 choice 'Processor type' \
-	"6xx/7xx	CONFIG_6xx \
-	 860/821	CONFIG_8xx" 6xx/7xx
+	"6xx/7xx		CONFIG_6xx \
+	 630/Power3(64-Bit) 	CONFIG_PPC64 \
+	 860/821		CONFIG_8xx" 6xx/7xx
 
 choice 'Machine Type' \
 	"PowerMac	CONFIG_PMAC \
@@ -22,6 +23,10 @@
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_ALL_PPC" != "y" ];then
   define_bool CONFIG_MACH_SPECIFIC y
+fi
+
+if [ "$CONFIG_PPC64" != "y" ];then
+  define_bool CONFIG_6xx y
 fi
 endmenu
 
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.2.9/linux/arch/ppc/defconfig	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/defconfig	Fri Jun  4 13:30:47 1999
@@ -8,12 +8,13 @@
 CONFIG_PPC=y
 CONFIG_6xx=y
 # CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+CONFIG_MACH_SPECIFIC=y
 # CONFIG_SMP is not set
 
 #
@@ -35,20 +36,20 @@
 CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
-CONFIG_VGA_CONSOLE=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_ADBMOUSE=y
+CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_PROC_DEVICETREE=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
-# CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -75,13 +76,15 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
-# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -116,6 +119,7 @@
 # (it is safe to leave these untouched)
 #
 CONFIG_INET_RARP=y
+CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 
@@ -151,12 +155,12 @@
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -184,28 +188,16 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_G_NCR5380_PORT is not set
-# CONFIG_SCSI_G_NCR5380_MEM 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=y
-# CONFIG_SCSI_SYM53C8XX is not set
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_NCR53C8XX 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 is not set
-# 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
@@ -236,7 +228,7 @@
 # CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -283,7 +275,7 @@
 # CONFIG_ISDN is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
 #
 # CONFIG_CD_NO_IDESCSI is not set
 
@@ -291,37 +283,22 @@
 # Console drivers
 #
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_PM2 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-# CONFIG_FB_ATY is not set
+CONFIG_FB_ATY=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
+# CONFIG_FB_MATROX is not set
+CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-# CONFIG_FBCON_MFB is not set
-# CONFIG_FBCON_CFB2 is not set
-# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
-# CONFIG_FBCON_AFB is not set
-# CONFIG_FBCON_ILBM is not set
-# CONFIG_FBCON_IPLAN2P2 is not set
-# CONFIG_FBCON_IPLAN2P4 is not set
-# CONFIG_FBCON_IPLAN2P8 is not set
-# CONFIG_FBCON_MAC is not set
-# CONFIG_FBCON_VGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -337,25 +314,15 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 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_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
+CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 
 #
@@ -367,20 +334,11 @@
 # Joystick support
 #
 # CONFIG_JOYSTICK is not set
-# CONFIG_DTLK is not set
 
 #
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
-# CONFIG_FT_NORMAL_DEBUG is not set
-# CONFIG_FT_FULL_DEBUG is not set
-# CONFIG_FT_NO_TRACE is not set
-# CONFIG_FT_NO_TRACE_AT_ALL is not set
-# CONFIG_FT_STD_FDC is not set
-# CONFIG_FT_MACH2 is not set
-# CONFIG_FT_PROBE_FC10 is not set
-# CONFIG_FT_ALT_FDC is not set
 
 #
 # Filesystems
@@ -471,10 +429,3 @@
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
-
-#
-# Kernel hacking
-#
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.2.9/linux/arch/ppc/kernel/Makefile	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/Makefile	Fri Jun  4 13:30:47 1999
@@ -65,7 +65,7 @@
 	$(HOSTCC) -o find_name find_name.c
 
 checks: checks.c
-	$(HOSTCC) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
+	$(HOSTCC) ${CFLAGS} -D__KERNEL__ -o checks checks.c
 	./checks
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.2.9/linux/arch/ppc/kernel/chrp_pci.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Fri Jun  4 13:30:47 1999
@@ -166,6 +166,62 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
+
+int rtas_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned char *val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 1 ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int rtas_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned short *val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 2 ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int rtas_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+				     unsigned char offset, unsigned int *val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 4 ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int rtas_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+				     unsigned char offset, unsigned char val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "write-pci-config", 3, 1, NULL, addr, 1, (ulong)val ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int rtas_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+				     unsigned char offset, unsigned short val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "write-pci-config", 3, 1, NULL, addr, 2, (ulong)val ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int rtas_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+				      unsigned char offset, unsigned int val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "write-pci-config", 3, 1, NULL, addr, 4, (ulong)val ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
     /*
      *  Temporary fixes for PCI devices. These should be replaced by OF query
      *  code -- Geert
@@ -255,6 +311,7 @@
 
 decl_config_access_method(grackle);
 decl_config_access_method(indirect);
+decl_config_access_method(rtas);
 
 void __init
 chrp_setup_pci_ptrs(void)
@@ -275,7 +332,7 @@
 		{
 			/* find out how many pythons */
 			while ( (py = py->next) ) python_busnr++;
-                        set_config_access_method(python);
+			set_config_access_method(python);
 			/*
 			 * We base these values on the machine type but should
 			 * try to read them from the python controller itself.
@@ -296,10 +353,22 @@
                 }
                 else
                 {
-			pci_dram_offset = 0;
-			isa_mem_base = 0xf7000000;
-			isa_io_base = 0xf8000000;
-			set_config_access_method(gg2);
+			if ( !strncmp("IBM,7043-150", get_property(find_path_device("/"), "name", NULL),12) )
+			{
+				pci_dram_offset = 0;
+				isa_mem_base = 0x80000000;
+				isa_io_base = 0xfe000000;
+				pci_config_address = (unsigned int *)0xfec00000;
+				pci_config_data = (unsigned char *)0xfee00000;
+				set_config_access_method(indirect);
+			}
+			else
+			{
+				pci_dram_offset = 0;
+				isa_mem_base = 0xf7000000;
+				isa_io_base = 0xf8000000;
+				set_config_access_method(gg2);
+			}
                 }
         }
 	
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.2.9/linux/arch/ppc/kernel/chrp_setup.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/chrp_setup.c	Fri Jun  4 13:30:47 1999
@@ -32,6 +32,7 @@
 #include <linux/console.h>
 #include <linux/pci.h>
 #include <linux/openpic.h>
+#include <linux/version.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -64,6 +65,7 @@
 
 unsigned long chrp_get_rtc_time(void);
 int chrp_set_rtc_time(unsigned long nowtime);
+unsigned long rtas_event_scan_rate = 0, rtas_event_scan_ct = 0;
 void chrp_calibrate_decr(void);
 void chrp_time_init(void);
 
@@ -179,6 +181,7 @@
 	return len;
 }
 
+#if 0
 /*
      *  Fixes for the National Semiconductor PC78308VUL SuperI/O
      *
@@ -228,12 +231,13 @@
 	/* select logical device 1 (KBC/Mouse) */
 	sio_fixup_irq("mouse", 1, 12, 2);
 }
-
+#endif
 
 __initfunc(void
 	   chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	extern char cmd_line[];
+	struct device_node *device;
 
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_sec = 50000000;
@@ -273,80 +277,73 @@
 			find_path_device("/"), "platform-open-pic", NULL);
 		OpenPIC = ioremap((unsigned long)OpenPIC, sizeof(struct OpenPIC));
 	}
-	
+
 	/*
 	 *  Fix the Super I/O configuration
 	 */
-	sio_init();
+	/*sio_init();*/
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
-	/* my starmax 6000 needs this but the longtrail shouldn't do it -- Cort */
-	if ( !strncmp("MOT", get_property(find_path_device("/"),
-					  "model", NULL),3) )
-		*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
-	/*
-	 * The f50 has a lot of IO space - we need to map some in that
-	 * isn't covered by the BAT mappings in MMU_init() -- Cort
+	*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+
+	/* Get the event scan rate for the rtas so we know how
+	 * often it expects a heartbeat. -- Cort
 	 */
-	if ( !strncmp("F5", get_property(find_path_device("/"),
-					 "ibm,model-class", NULL),2) )
+	if ( rtas_data )
 	{
-#if 0		
-		/*
-		 * This ugly hack allows us to force ioremap() to
-		 * create a 1-to-1 mapping for us, even though
-		 * the address is < ioremap_base.  This is necessary
-		 * since we want our PCI IO space to have contiguous
-		 * virtual addresses and I think it's worse to have
-		 * calls to map_page() here.
-		 * -- Cort
-		 */
-		unsigned long hold = ioremap_base;
-		ioremap_base = 0;
-		__ioremap(0x90000000, 0x10000000, _PAGE_NO_CACHE);
-		ioremap_base = hold;
-#endif		
+		struct property *p;
+		device = find_devices("rtas");
+		for ( p = device->properties;
+		      strncmp(p->name, "rtas-event-scan-rate", 20) && p ;
+		      p = p->next )
+			/* nothing */ ;
+		if ( p && *(unsigned long *)p->value )
+		{
+			rtas_event_scan_rate = (HZ/(*(unsigned long *)p->value)*30)-1;
+			rtas_event_scan_ct = 1;
+			printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n",
+			       *(unsigned long *)p->value, rtas_event_scan_rate );
+		}
 	}
 }
 
 void
+chrp_event_scan(void)
+{
+	unsigned char log[1024];
+	if ( rtas_event_scan_rate && (rtas_event_scan_ct-- <= 0) )
+	{
+		call_rtas( "event-scan", 4, 1, NULL, 0x0, 1, __pa(log), 1024 );
+		rtas_event_scan_ct = rtas_event_scan_rate;
+	}
+}
+	
+void
 chrp_restart(char *cmd)
 {
-#if 0
-	extern unsigned int rtas_entry, rtas_data, rtas_size;
 	printk("RTAS system-reboot returned %d\n",
 	       call_rtas("system-reboot", 0, 1, NULL));
-	printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
-	       rtas_entry,rtas_data,rtas_size);
 	for (;;);
-#else
-	printk("System Halted\n");
-	while(1);
-#endif
 }
 
 void
 chrp_power_off(void)
 {
-	/* RTAS doesn't seem to work on Longtrail.
-	   For now, do it the same way as the PReP. */
-#if 0
-	extern unsigned int rtas_entry, rtas_data, rtas_size;
+	/* allow power on only with power button press */
+#define	PWR_FIELD(x) (0x8000000000000000 >> ((x)-96))
 	printk("RTAS power-off returned %d\n",
-	       call_rtas("power-off", 2, 1, NULL, 0, 0));
-	printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
-	       rtas_entry,rtas_data,rtas_size);
+	       call_rtas("power-off", 2, 1, NULL,
+			 ((PWR_FIELD(96)|PWR_FIELD(97))>>32)&0xffffffff,
+			 (PWR_FIELD(96)|PWR_FIELD(97))&0xffffffff));
+#undef PWR_FIELD	
 	for (;;);
-#else
-	chrp_restart(NULL);
-#endif
 }
 
 void
 chrp_halt(void)
 {
-	chrp_restart(NULL);
+	chrp_power_off();
 }
 
 u_int
@@ -668,5 +665,21 @@
         ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
 
         ppc_ide_md.io_base = _IO_BASE;
-#endif		
+#endif
+	/*
+	 * Print the banner, then scroll down so boot progress
+	 * can be printed.  -- Cort 
+	 */
+	chrp_progress("Linux/PPC "UTS_RELEASE"\n");
+}
+
+void chrp_progress(char *s)
+{
+	extern unsigned int rtas_data;
+	
+	if ( (_machine != _MACH_chrp) || !rtas_data )
+		return;
+	call_rtas( "display-character", 1, 1, NULL, '\r' );
+	while ( *s )
+		call_rtas( "display-character", 1, 1, NULL, *s++ );
 }
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.2.9/linux/arch/ppc/kernel/head.S	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/head.S	Fri Jun  4 13:30:47 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.130 1999/05/09 19:16:43 cort Exp $
+ *  $Id: head.S,v 1.130.2.1 1999/05/29 19:09:59 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -97,18 +97,32 @@
 	bdnz	0b
 #endif
 
+#ifdef CONFIG_PPC64
+#define LOAD_BAT(n, offset, reg, RA, RB) \
+	ld	RA,offset+0(reg);	\
+	ld	RB,offset+8(reg);	\
+	mtspr	IBAT##n##U,RA;		\
+	mtspr	IBAT##n##L,RB;		\
+	ld	RA,offset+16(reg);	\
+	ld	RB,offset+24(reg);	\
+	mtspr	DBAT##n##U,RA;		\
+	mtspr	DBAT##n##L,RB;		\
+	
+#else /* CONFIG_PPC64 */
+	
 /* 601 only have IBAT cr0.eq is set on 601 when using this macro */ 
 #define LOAD_BAT(n, offset, reg, RA, RB) \
-	lwz	RA,offset+0(reg); \
+	lwz	RA,offset+0(reg);	\
 	lwz	RB,offset+4(reg);	\
-	mtspr	IBAT##n##U,RA;	\
-	mtspr	IBAT##n##L,RB;	\
-	beq	1f;		\
+	mtspr	IBAT##n##U,RA;		\
+	mtspr	IBAT##n##L,RB;		\
+	beq	1f;			\
 	lwz	RA,offset+8(reg);	\
 	lwz	RB,offset+12(reg);	\
-	mtspr	DBAT##n##U,RA;	\
-	mtspr	DBAT##n##L,RB;	\
-1:	 
+	mtspr	DBAT##n##U,RA;		\
+	mtspr	DBAT##n##L,RB;		\
+1:	
+#endif /* CONFIG_PPC64 */	 
 
 #ifndef CONFIG_APUS
 #define tophys(rd,rs,rt)	addis	rd,rs,-KERNELBASE@h
@@ -206,6 +220,16 @@
 	
 	.globl	__start
 __start:
+#ifdef CONFIG_PPC64
+/* 
+ * Go into 32-bit mode to boot.  OF should do this for
+ * us already but just in case...
+ * -- Cort 
+ */
+	mfmsr	r10
+	clrldi	r10,r10,3
+	mtmsr	r10
+#endif	
 /*
  * We have to do any OF calls before we map ourselves to KERNELBASE,
  * because OF may have I/O devices mapped in in that area
@@ -226,10 +250,11 @@
  * of RAM to KERNELBASE.  From this point on we can't safely
  * call OF any more.
  */
+	lis	r11,KERNELBASE@h
+#ifndef CONFIG_PPC64
 	mfspr	r9,PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpi	0,r9,1
-	lis	r11,KERNELBASE@h
 	bne	4f
 	ori	r11,r11,4		/* set up BAT registers for 601 */
 	li	r8,0x7f			/* valid, block length = 8MB */
@@ -240,6 +265,7 @@
 	mtspr	IBAT1U,r9
 	mtspr	IBAT1L,r10
 	b	5f
+#endif /* CONFIG_PPC64 */
 4:
 #ifdef CONFIG_APUS
 	ori	r11,r11,BL_8M<<2|0x2	/* set up an 8MB mapping */
@@ -248,9 +274,17 @@
 	lwz	r8,0(r8)
 	addis	r8,r8,KERNELBASE@h
 	addi	r8,r8,2
-#else
+#else	
 	ori	r11,r11,BL_256M<<2|0x2	/* set up BAT registers for 604 */
 	li	r8,2			/* R/W access */
+#ifdef CONFIG_PPC64
+	/* clear out the high 32 bits in the BAT */
+	clrldi	r11,r11,32
+	clrldi	r8,r8,32
+	/* turn off the pagetable mappings just in case */
+	clrldi	r16,r16,63
+	mtsdr1	r16
+#else /* CONFIG_PPC64 */
 	/* 
 	 * allow secondary cpus to get at all of ram in early bootup
 	 * since their init_task may be up there -- Cort
@@ -268,6 +302,7 @@
 	mtspr	DBAT2U,r21		/* bit in upper BAT register */
 	mtspr	IBAT2L,r28
 	mtspr	IBAT2U,r21
+#endif /* CONFIG_PPC64 */
 #endif
 	mtspr	DBAT0L,r8		/* N.B. 6xx (not 601) have valid */
 	mtspr	DBAT0U,r11		/* bit in upper BAT register */
@@ -1246,7 +1281,7 @@
 	eieio
 	lis	r2,hash_table_lock@h
 	ori	r2,r2,hash_table_lock@l
-	tophys(r2,r2,r6)
+ 	tophys(r2,r2,r6)
 	lis	r6,100000000@h
 	mtctr	r6
 	lwz	r0,PROCESSOR-TSS(r5)
@@ -1294,6 +1329,11 @@
 	stw	r6,0(r2)		/* update PTE (accessed/dirty bits) */
 
 	/* Convert linux-style PTE to low word of PPC-style PTE */
+#ifdef CONFIG_PPC64
+	/* clear the high 32 bits just in case */
+	clrldi	r6,r6,32
+	clrldi	r4,r4,32
+#endif /* CONFIG_PPC64 */
 	rlwinm	r4,r6,32-9,31,31	/* _PAGE_HWWRITE -> PP lsb */
 	rlwimi	r6,r6,32-1,31,31	/* _PAGE_USER -> PP (both bits now) */
 	ori	r4,r4,0xe04		/* clear out reserved bits */
@@ -1301,16 +1341,34 @@
 
 	/* Construct the high word of the PPC-style PTE */
 	mfsrin	r5,r3			/* get segment reg for segment */
+#ifdef CONFIG_PPC64
+	sldi	r5,r5,12
+#else /* CONFIG_PPC64 */
 	rlwinm	r5,r5,7,1,24		/* put VSID in 0x7fffff80 bits */
+#endif /* CONFIG_PPC64 */
+	
 #ifndef __SMP__				/* do this later for SMP */
+#ifdef CONFIG_PPC64
+	ori	r5,r5,1			/* set V (valid) bit */
+#else /* CONFIG_PPC64 */
 	oris	r5,r5,0x8000		/* set V (valid) bit */
+#endif /* CONFIG_PPC64 */
 #endif
+	
+#ifdef CONFIG_PPC64
+/* XXX:	 does this insert the api correctly? -- Cort */
+	rlwimi	r5,r3,17,21,25		/* put in API (abbrev page index) */
+#else /* CONFIG_PPC64 */
 	rlwimi	r5,r3,10,26,31		/* put in API (abbrev page index) */
-
+#endif /* CONFIG_PPC64 */
 	/* Get the address of the primary PTE group in the hash table */
 	.globl	hash_page_patch_A
 hash_page_patch_A:
 	lis	r4,Hash_base@h		/* base address of hash table */
+#ifdef CONFIG_PPC64
+	/* just in case */
+	clrldi	r4,r4,32
+#endif	
 	rlwimi	r4,r5,32-1,26-Hash_bits,25	/* (VSID & hash_mask) << 6 */
 	rlwinm	r0,r3,32-6,26-Hash_bits,25	/* (PI & hash_mask) << 6 */
 	xor	r4,r4,r0		/* make primary hash */
@@ -1799,7 +1857,11 @@
  */
 #ifndef CONFIG_8xx
 	lis	r6,_SDR1@ha
+#ifdef CONFIG_PPC64	
+	ld	r6,_SDR1@l(r6)
+#else
 	lwz	r6,_SDR1@l(r6)
+#endif		
 #else
 	/* The right way to do this would be to track it down through
 	 * init's TSS like the context switch code does, but this is
@@ -1828,6 +1890,14 @@
 #endif
 #ifndef CONFIG_8xx
 	mtspr	SDR1,r6
+#ifdef CONFIG_PPC64
+	/* clear the v bit in the ASR so we can
+	 * behave as if we have segment registers 
+	 * -- Cort
+	 */
+	clrldi	r6,r6,63
+	mtasr	r6
+#endif /* CONFIG_PPC64 */
 	li	r0,16		/* load up segment register values */
 	mtctr	r0		/* for context 0 */
 	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
@@ -1844,10 +1914,17 @@
 	lis	r3,BATS@ha
 	addi	r3,r3,BATS@l
 	tophys(r3,r3,r4)
+#ifdef CONFIG_PPC64
+	LOAD_BAT(0,0,r3,r4,r5)
+	LOAD_BAT(1,32,r3,r4,r5)
+	LOAD_BAT(2,64,r3,r4,r5)
+	LOAD_BAT(3,96,r3,r4,r5)
+#else /* CONFIG_PPC64 */
 	LOAD_BAT(0,0,r3,r4,r5)
 	LOAD_BAT(1,16,r3,r4,r5)
 	LOAD_BAT(2,32,r3,r4,r5)
 	LOAD_BAT(3,48,r3,r4,r5)
+#endif /* CONFIG_PPC64 */
 #endif /* CONFIG_8xx */
 /* Set up for using our exception vectors */
 	/* ptr to phys current tss */
@@ -2538,7 +2615,6 @@
  */
 	.globl	enter_rtas
 enter_rtas:
-	stwu	r1,-16(r1)
 	mflr	r0
 	stw	r0,20(r1)
 	lis	r4,rtas_data@ha
@@ -2559,7 +2635,6 @@
 	andi.	r9,r9,MSR_ME|MSR_RI
 	sync			/* disable interrupts so SRR0/1 */
 	mtmsr	r0		/* don't get trashed */
-	li	r6,0	
 	mtlr	r6
 	mtspr	SPRG2,r7
 	mtspr	SRR0,r8
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.2.9/linux/arch/ppc/kernel/idle.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/idle.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.61 1999/03/18 04:15:45 cort Exp $
+ * $Id: idle.c,v 1.61.2.1 1999/05/29 19:10:02 cort Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
@@ -50,6 +50,7 @@
 	/* endless loop with no priority at all */
 	current->priority = 0;
 	current->counter = -100;
+	init_idle();	
 	for (;;)
 	{
 		__sti();
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.2.9/linux/arch/ppc/kernel/irq.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/irq.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $
+ * $Id: irq.c,v 1.105.2.1 1999/05/29 19:10:05 cort Exp $
  *
  *  arch/ppc/kernel/irq.c
  *
@@ -65,7 +65,6 @@
 void enable_irq(unsigned int irq_nr);
 void disable_irq(unsigned int irq_nr);
 
-/* Fixme - Need to figure out a way to get rid of this - Corey */
 volatile unsigned char *chrp_int_ack_special;
 
 #ifdef CONFIG_APUS
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.2.9/linux/arch/ppc/kernel/misc.S	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/misc.S	Fri Jun  4 13:30:47 1999
@@ -649,15 +649,6 @@
         blr
 
 /*
- * Fetch the current SR register
- *   get_SR(int index)
- */
-_GLOBAL(get_SR)
-	mfsrin	r4,r3
-	mr	r3,r4
-	blr
-
-/*
  * Create a kernel thread
  *   __kernel_thread(flags, fn, arg)
  */
@@ -875,7 +866,11 @@
 	.long sys_getresuid	/* 165 */
 	.long sys_query_module
 	.long sys_poll
+#ifdef CONFIG_NFS	
 	.long sys_nfsservctl
+#else
+	.long sys_ni_syscall
+#endif		
 	.long sys_setresgid
 	.long sys_getresgid	/* 170 */
 	.long sys_prctl
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.2.9/linux/arch/ppc/kernel/prep_pci.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/prep_pci.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prep_pci.c,v 1.33 1999/05/09 20:15:54 cort Exp $
+ * $Id: prep_pci.c,v 1.35 1999/05/10 23:31:03 cort Exp $
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -38,6 +38,8 @@
 /* Used for Motorola to store system config register */
 static unsigned long	*ProcInfo;
 
+extern void chrp_do_IRQ(struct pt_regs *,int , int);
+
 /* Tables for known hardware */   
 
 /* Motorola PowerStackII - Utah */
@@ -731,6 +733,8 @@
 	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
 	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
 
+	ppc_md.do_IRQ = chrp_do_IRQ;
+	
 	/* If raven is present on Motorola store the system config register
 	 * for later use.
 	 */
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.2.9/linux/arch/ppc/kernel/prep_setup.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/prep_setup.c	Fri Jun  4 13:30:47 1999
@@ -249,7 +249,7 @@
 		ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
 		break;
 	case _PREP_Radstone:
-		ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+		ROOT_DEV = to_kdev_t(0x0802); /* sda2 */
 
 		/*
 		 * Determine system type
@@ -767,10 +767,8 @@
 	ppc_md.get_cpuinfo    = prep_get_cpuinfo;
 	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
 	ppc_md.init_IRQ       = prep_init_IRQ;
-	if ( !OpenPIC )
-		ppc_md.do_IRQ         = prep_do_IRQ;
-	else
-		ppc_md.do_IRQ         = chrp_do_IRQ;
+	/* this gets changed later on if we have an OpenPIC -- Cort */
+	ppc_md.do_IRQ         = prep_do_IRQ;
 	ppc_md.init           = NULL;
 
 	ppc_md.restart        = prep_restart;
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.2.9/linux/arch/ppc/kernel/prom.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/prom.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.54 1999/05/10 04:43:46 cort Exp $
+ * $Id: prom.c,v 1.54.2.1 1999/05/29 19:10:12 cort Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -24,6 +24,7 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/bootx.h>
+#include <asm/system.h>
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -412,6 +413,9 @@
 	mem = copy_device_tree(mem, mem + (1<<20));
 	prom_print(RELOC("done\n"));
 
+
+	RELOC(klimit) = (char *) (mem - offset);
+	
 	prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
 	if (prom_rtas != (void *) -1) {
 		RELOC(rtas_size) = 0;
@@ -421,9 +425,19 @@
 		if (RELOC(rtas_size) == 0) {
 			RELOC(rtas_data) = 0;
 		} else {
-			mem = (mem + 4095) & -4096; /* round to page bdry */
+			/*
+			 * We do _not_ want the rtas_data inside the klimit
+			 * boundry since it'll be squashed when we do the
+			 * relocate of the kernel on chrp right after prom_init()
+			 * in head.S.  So, we just pick a spot in memory.
+			 * -- Cort
+			 */
+#if 0
+			mem = (mem + 4095) & -4096;
 			RELOC(rtas_data) = mem + KERNELBASE;
 			mem += RELOC(rtas_size);
+#endif
+			RELOC(rtas_data) = (6<<20) + KERNELBASE;
 		}
 		prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));
 		{
@@ -448,7 +462,7 @@
 		else
 			prom_print(RELOC(" done\n"));
 	}
-	RELOC(klimit) = (char *) (mem - offset);
+
 #ifdef CONFIG_SMP
 	/*
 	 * With CHRP SMP we need to use the OF to start the other
@@ -1289,7 +1303,7 @@
 	  unsigned long *outputs, ...)
 {
 	va_list list;
-	int i;
+	int i, s;
 	struct device_node *rtas;
 	int *tokp;
 	union {
@@ -1305,16 +1319,19 @@
 		printk(KERN_ERR "No RTAS service called %s\n", service);
 		return -1;
 	}
-	u.words[0] = __pa(*tokp);
+	u.words[0] = *tokp;
 	u.words[1] = nargs;
 	u.words[2] = nret;
 	va_start(list, outputs);
 	for (i = 0; i < nargs; ++i)
 		u.words[i+3] = va_arg(list, unsigned long);
 	va_end(list);
+	
+	s = _disable_interrupts();
 	spin_lock(&rtas_lock);
 	enter_rtas((void *)__pa(&u));
 	spin_unlock(&rtas_lock);
+	_enable_interrupts(s);
 	if (nret > 1 && outputs != NULL)
 		for (i = 0; i < nret-1; ++i)
 			outputs[i] = u.words[i+nargs+4];
@@ -1326,8 +1343,7 @@
 abort()
 {
 #ifdef CONFIG_XMON
-	extern void xmon(void *);
-	xmon(0);
+	xmon(NULL);
 #endif
 	prom_exit();
 }
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.2.9/linux/arch/ppc/kernel/ptrace.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/ptrace.c	Fri Jun  4 13:30:47 1999
@@ -330,8 +330,12 @@
 		if ((!child->dumpable ||
 		    (current->uid != child->euid) ||
 		    (current->uid != child->uid) ||
+		    (current->uid != child->suid) ||
 	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+	 	    (current->gid != child->gid) ||
+		    (current->gid != child->sgid) ||
+		    (!cap_issubset(child->cap_permitted, current->cap_permitted)))
+		    && !capable(CAP_SYS_PTRACE))
 			goto out;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c
--- v2.2.9/linux/arch/ppc/kernel/residual.c	Thu Nov 19 09:56:27 1998
+++ linux/arch/ppc/kernel/residual.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: residual.c,v 1.14 1998/10/11 17:38:10 cort Exp $
+ * $Id: residual.c,v 1.14.2.1 1999/05/29 19:10:17 cort Exp $
  *
  * Code to deal with the PReP residual data.
  *
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.2.9/linux/arch/ppc/kernel/setup.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/setup.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.132 1999/03/24 00:32:19 cort Exp $
+ * $Id: setup.c,v 1.132.2.1 1999/06/03 03:03:45 paulus Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -375,7 +375,6 @@
 			else
 			{
 				_machine = _MACH_Pmac;
-				is_prep = 1;
 			}
 		}
 
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.2.9/linux/arch/ppc/kernel/smp.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/smp.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: smp.c,v 1.49 1999/03/18 04:16:31 cort Exp $
+ * $Id: smp.c,v 1.49.2.1 1999/05/29 19:10:20 cort Exp $
  *
  * Smp support for ppc.
  *
@@ -388,9 +388,12 @@
 
 void __init smp_callin(void)
 {
+	int i;
+	
 	printk("SMP %d: smp_callin()\n",current->processor);
         smp_store_cpu_info(current->processor);
 	set_dec(decrementer_count);
+	
 #if 0
 	current->mm->mmap->vm_page_prot = PAGE_SHARED;
 	current->mm->mmap->vm_start = PAGE_OFFSET;
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/softemu8xx.c linux/arch/ppc/kernel/softemu8xx.c
--- v2.2.9/linux/arch/ppc/kernel/softemu8xx.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/softemu8xx.c	Fri Jun  4 13:30:47 1999
@@ -34,6 +34,7 @@
 
 /* Eventually we may need a look-up table, but this works for now.
 */
+#define LFS	48
 #define LFD	50
 #define LFDU	51
 #define STFD	54
@@ -82,6 +83,12 @@
 			retval = EFAULT;
 		else
 			regs->gpr[idxreg] = (uint)ea;
+		break;
+	case LFS:
+		sdisp = (instword & 0xffff);
+		ea = (uint *)(regs->gpr[idxreg] + sdisp);
+		if (copy_from_user(ip, ea, sizeof(float)))
+			retval = EFAULT;
 		break;
 	case STFD:
 		/* this is a 16 bit quantity that is sign extended
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.2.9/linux/arch/ppc/kernel/syscalls.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/syscalls.c	Fri Jun  4 13:30:47 1999
@@ -182,18 +182,14 @@
 	int fd[2];
 	int error;
 
-	error = verify_area(VERIFY_WRITE, fildes, 8);
-	if (error)
-		return error;
 	lock_kernel();
 	error = do_pipe(fd);
 	unlock_kernel();
-	if (error)
-		return error;
-	if (__put_user(fd[0],0+fildes)
-	    || __put_user(fd[1],1+fildes))
-		return -EFAULT;	/* should we close the fds? */
-	return 0;
+	if (!error) {
+		if (copy_to_user(fildes, fd, 2*sizeof(int)))
+			error = -EFAULT;
+	}
+	return error;
 }
 
 asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
@@ -205,15 +201,12 @@
 
 	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
-		file = fget(fd);
-		if (!file)
+		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 			goto out;
 	}
 	
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	ret = do_mmap(file, addr, len, prot, flags, offset);
-	if (file)
-		fput(file);
 out:
 	unlock_kernel();
 	return ret;
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.2.9/linux/arch/ppc/kernel/time.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/time.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: time.c,v 1.47 1999/03/18 05:11:11 cort Exp $
+ * $Id: time.c,v 1.47.2.1 1999/05/29 19:10:23 cort Exp $
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -126,13 +126,17 @@
 	smp_local_timer_interrupt(regs);
 #endif		
 
-	/* Fixme - make this more generic - Corey */
 #ifdef CONFIG_APUS
 	{
 		extern void apus_heartbeat (void);
 		apus_heartbeat ();
 	}
 #endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
+	if ( _machine == _MACH_chrp )
+		chrp_event_scan();
+#endif	
+
 	hardirq_exit(cpu);
 }
 
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.2.9/linux/arch/ppc/kernel/traps.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/traps.c	Fri Jun  4 13:30:47 1999
@@ -79,7 +79,6 @@
 		debugger(regs);
 #endif
 		print_backtrace((unsigned long *)regs->gpr[1]);
-		instruction_dump((unsigned long *)regs->nip);
 		panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
 	}
 	force_sig(signr, current);
@@ -127,7 +126,6 @@
 		debugger(regs);
 #endif
 		print_backtrace((unsigned long *)regs->gpr[1]);
-		instruction_dump((unsigned long *)regs->nip);
 		panic("machine check");
 	}
 	_exception(SIGSEGV, regs);	
@@ -216,7 +214,6 @@
 #endif
 	show_regs(regs);
 	print_backtrace((unsigned long *)regs->gpr[1]);
-	instruction_dump((unsigned long *)regs->nip);
 	panic("kernel stack overflow");
 }
 
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.2.9/linux/arch/ppc/mm/fault.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/mm/fault.c	Fri Jun  4 13:30:47 1999
@@ -89,7 +89,6 @@
 			printk("page fault in interrupt handler, addr=%lx\n",
 			       address);
 			show_regs(regs);
-			instruction_dump((unsigned long *)regs->nip);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 			if (debugger_kernel_faults)
 				debugger(regs);
@@ -176,7 +175,6 @@
 	/* kernel has accessed a bad area */
 	show_regs(regs);
 	print_backtrace( (unsigned long *)regs->gpr[1] );
-	instruction_dump((unsigned long *)regs->nip);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_kernel_faults)
 		debugger(regs);
diff -u --recursive --new-file v2.2.9/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.2.9/linux/arch/ppc/mm/init.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/mm/init.c	Fri Jun  4 13:30:47 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.164 1999/05/05 17:33:55 cort Exp $
+ *  $Id: init.c,v 1.164.2.2 1999/06/03 03:03:53 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -371,7 +371,7 @@
 	 * same virt address (and this is contiguous).
 	 *  -- Cort
 	 */
-	if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ )
+	if ( (v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )
 		goto out;
 #endif /* CONFIG_8xx */
 	
@@ -402,7 +402,7 @@
 	for (i = 0; i < size; i += PAGE_SIZE)
 		map_page(&init_task, v+i, p+i, flags);
 out:	
-	return (void *) (v + (p & ~PAGE_MASK));
+	return (void *) (v + (addr & ~PAGE_MASK));
 }
 
 void iounmap(void *addr)
@@ -1510,7 +1510,7 @@
 	for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++)
 		;
 	Hash_size = h;
-	Hash_mask << 10;  /* so setting _SDR1 works the same -- Cort */
+	Hash_mask <<= 10;  /* so setting _SDR1 works the same -- Cort */
 #else
 	for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2)
 		;
diff -u --recursive --new-file v2.2.9/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.2.9/linux/arch/sparc/defconfig	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc/defconfig	Wed Jun  2 09:55:38 1999
@@ -62,6 +62,7 @@
 CONFIG_SUN_MOSTEK_RTC=y
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
+CONFIG_SUN_AURORA=m
 
 #
 # Linux/SPARC audio subsystem (EXPERIMENTAL)
diff -u --recursive --new-file v2.2.9/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.2.9/linux/arch/sparc/kernel/sys_sunos.c	Sun Nov  8 14:02:45 1998
+++ linux/arch/sparc/kernel/sys_sunos.c	Wed Jun  2 09:55:38 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $
+/* $Id: sys_sunos.c,v 1.94.2.1 1999/05/24 19:42:30 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1198,7 +1198,7 @@
 
 	lock_kernel();
 	ret = check_nonblock(sys_readv(fd,vector,count),fd);
-	lock_kernel();
+	unlock_kernel();
 	return ret;
 }
 
diff -u --recursive --new-file v2.2.9/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.2.9/linux/arch/sparc64/defconfig	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc64/defconfig	Wed Jun  2 09:55:38 1999
@@ -68,6 +68,7 @@
 CONFIG_OBP_FLASH=m
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
+CONFIG_SUN_AURORA=m
 
 #
 # Linux/SPARC audio subsystem (EXPERIMENTAL)
diff -u --recursive --new-file v2.2.9/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.2.9/linux/arch/sparc64/kernel/setup.c	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc64/kernel/setup.c	Sat May 29 11:10:15 1999
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.43 1999/04/12 08:08:24 davem Exp $
+/*  $Id: setup.c,v 1.43.2.1 1999/05/28 02:18:13 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -550,7 +550,9 @@
 			ic_servaddr = sv;
 			if (gw)
 				ic_gateway = gw;
+#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
 			ic_proto_enabled = 0;
+#endif
 		}
 	}
 #endif
diff -u --recursive --new-file v2.2.9/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.2.9/linux/arch/sparc64/kernel/sys_sparc32.c	Tue Mar 23 14:35:47 1999
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Wed Jun  2 09:55:38 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.107 1999/03/05 13:21:02 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.1 1999/05/16 10:48:44 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -2363,6 +2363,94 @@
 	__scm_destroy(scm);
 }
 
+/* In these cases we (currently) can just copy to data over verbatim
+ * because all CMSGs created by the kernel have well defined types which
+ * have the same layout in both the 32-bit and 64-bit API.  One must add
+ * some special cased conversions here if we start sending control messages
+ * with incompatible types.
+ *
+ * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
+ * we do our work.  The remaining cases are:
+ *
+ * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean
+ *		IP_TTL		int			32-bit clean
+ *		IP_TOS		__u8			32-bit clean
+ *		IP_RECVOPTS	variable length		32-bit clean
+ *		IP_RETOPTS	variable length		32-bit clean
+ *		(these last two are clean because the types are defined
+ *		 by the IPv4 protocol)
+ *		IP_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in	32-bit clean
+ * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in6	32-bit clean
+ *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean
+ *		IPV6_HOPLIMIT	int			32-bit clean
+ *		IPV6_FLOWINFO	u32			32-bit clean
+ *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean
+ *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean
+ *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean
+ *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean
+ */
+static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
+{
+	unsigned char *workbuf, *wp;
+	unsigned long bufsz, space_avail;
+	struct cmsghdr *ucmsg;
+
+	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
+	space_avail = kmsg->msg_controllen + bufsz;
+	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
+	if(workbuf == NULL)
+		goto fail;
+
+	/* To make this more sane we assume the kernel sends back properly
+	 * formatted control messages.  Because of how the kernel will truncate
+	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
+	 */
+	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
+	while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) {
+		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
+		int clen64, clen32;
+
+		/* UCMSG is the 64-bit format CMSG entry in user-space.
+		 * KCMSG32 is within the kernel space temporary buffer
+		 * we use to convert into a 32-bit style CMSG.
+		 */
+		__get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
+		__get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
+		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+
+		clen64 = kcmsg32->cmsg_len;
+		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		kcmsg32->cmsg_len = clen32;
+
+		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
+		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
+	}
+
+	/* Copy back fixed up data, and adjust pointers. */
+	bufsz = (wp - workbuf);
+	copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz);
+
+	kmsg->msg_control = (struct cmsghdr *)
+		(((char *)orig_cmsg_uptr) + bufsz);
+	kmsg->msg_controllen = space_avail - bufsz;
+
+	kfree(workbuf);
+	return;
+
+fail:
+	/* If we leave the 64-bit format CMSG chunks in there,
+	 * the application could get confused and crash.  So to
+	 * ensure greater recovery, we report no CMSGs.
+	 */
+	kmsg->msg_controllen += bufsz;
+	kmsg->msg_control = (void *) orig_cmsg_uptr;
+}
+
 asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
 {
 	struct socket *sock;
@@ -2455,6 +2543,14 @@
 				if(scm.fp)
 					__scm_destroy(&scm);
 			} else {
+				/* If recvmsg processing itself placed some
+				 * control messages into user space, it's is
+				 * using 64-bit CMSG processing, so we need
+				 * to fix it up before we tack on more stuff.
+				 */
+				if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+					cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
+
 				/* Wheee... */
 				if(sock->passcred)
 					put_cmsg32(&kern_msg,
@@ -2471,9 +2567,9 @@
 	if(uaddr != NULL && err >= 0)
 		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
 	if(cmsg_ptr != 0 && err >= 0) {
-		u32 ucmsg_ptr = ((u32)(unsigned long)kern_msg.msg_control);
-		err  = __put_user(ucmsg_ptr, &user_msg->msg_control);
-		err |= __put_user(kern_msg.msg_controllen, &user_msg->msg_controllen);
+		unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
+		__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr);
+		err |= __put_user(uclen, &user_msg->msg_controllen);
 	}
 	if(err >= 0)
 		err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
diff -u --recursive --new-file v2.2.9/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.2.9/linux/arch/sparc64/kernel/sys_sunos32.c	Sun Nov  8 14:02:48 1998
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Wed Jun  2 09:55:38 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.22 1998/10/26 20:01:13 davem Exp $
+/* $Id: sys_sunos32.c,v 1.22.2.1 1999/05/24 19:42:36 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -1347,7 +1347,7 @@
 
 	lock_kernel();
 	ret = check_nonblock(sys32_readv(fd, vector, count), fd);
-	lock_kernel();
+	unlock_kernel();
 	return ret;
 }
 
diff -u --recursive --new-file v2.2.9/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- v2.2.9/linux/arch/sparc64/solaris/fs.c	Tue Mar 23 14:35:47 1999
+++ linux/arch/sparc64/solaris/fs.c	Wed Jun  2 09:55:38 1999
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.12 1999/01/02 16:46:06 davem Exp $
+/* $Id: fs.c,v 1.12.2.1 1999/05/29 04:03:23 davem Exp $
  * fs.c: fs related syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -410,7 +410,11 @@
 	mm_segment_t old_fs = get_fs();
 	int error;
 	struct sol_statvfs *ss = (struct sol_statvfs *)A(buf);
-			
+
+	if (!inode->i_sb)
+		return -ENODEV;
+	if (!inode->i_sb->s_op->statfs)
+		return -ENOSYS;
 	set_fs (KERNEL_DS);
 	error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
 	set_fs (old_fs);
@@ -448,6 +452,10 @@
 	int error;
 	struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf);
 			
+	if (!inode->i_sb)
+		return -ENODEV;
+	if (!inode->i_sb->s_op->statfs)
+		return -ENOSYS;
 	set_fs (KERNEL_DS);
 	error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
 	set_fs (old_fs);
@@ -489,9 +497,7 @@
 	if (!IS_ERR(dentry)) {
 		struct inode * inode = dentry->d_inode;
 
-		error = -ENOSYS;
-		if (inode->i_sb->s_op->statfs)
-			error = report_statvfs(inode, buf);
+		error = report_statvfs(inode, buf);
 		dput(dentry);
 	}
 	unlock_kernel();
@@ -515,10 +521,6 @@
 		error = -ENOENT;
 	else if (!(inode = dentry->d_inode))
 		error = -ENOENT;
-	else if (!inode->i_sb)
-		error = -ENODEV;
-	else if (!inode->i_sb->s_op->statfs)
-		error = -ENOSYS;
 	else
 		error = report_statvfs(inode, buf);
 	fput(file);
@@ -538,9 +540,7 @@
 	if (!IS_ERR(dentry)) {
 		struct inode * inode = dentry->d_inode;
 
-		error = -ENOSYS;
-		if (inode->i_sb->s_op->statfs)
-			error = report_statvfs64(inode, buf);
+		error = report_statvfs64(inode, buf);
 		dput(dentry);
 	}
 	unlock_kernel();
@@ -564,10 +564,6 @@
 		error = -ENOENT;
 	else if (!(inode = dentry->d_inode))
 		error = -ENOENT;
-	else if (!inode->i_sb)
-		error = -ENODEV;
-	else if (!inode->i_sb->s_op->statfs)
-		error = -ENOSYS;
 	else
 		error = report_statvfs64(inode, buf);
 	fput(file);
diff -u --recursive --new-file v2.2.9/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.2.9/linux/drivers/block/floppy.c	Mon Mar 29 11:09:11 1999
+++ linux/drivers/block/floppy.c	Wed Jun  9 16:42:49 1999
@@ -1924,8 +1924,6 @@
 
 static void floppy_ready(void)
 {
-	unsigned long flags;
-	
 	CHECK_RESET;
 	if (start_motor(floppy_ready)) return;
 	if (fdc_dtr()) return;
@@ -1945,7 +1943,7 @@
 	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);
diff -u --recursive --new-file v2.2.9/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.2.9/linux/drivers/block/ide.c	Thu May 13 23:10:29 1999
+++ linux/drivers/block/ide.c	Sun Jun 13 10:40:27 1999
@@ -272,7 +272,8 @@
 	if (drive->removable && id != NULL) {
 		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
 		 || !strncmp(id->model, "Hitachi CV", 10)		/* Hitachi */
-		 || !strncmp(id->model, "SunDisk SDCFB", 13))	/* SunDisk */
+		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
+		 || !strncmp(id->model, "HAGIWARA HPC", 12))	/* Hagiwara */
 		{
 			return 1;	/* yes, it is a flash memory card */
 		}
@@ -926,6 +927,7 @@
 int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
 {
 	byte stat;
+	int i;
 	unsigned long flags;
 
 	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
@@ -942,9 +944,18 @@
 		}
 		__restore_flags(flags);	/* local CPU only */
 	}
-	udelay(1);	/* allow status to settle, then read it again */
-	if (OK_STAT((stat = GET_STAT()), good, bad))
-		return 0;
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = GET_STAT()), good, bad))
+			return 0;
+	}
 	ide_error(drive, "status error", stat);
 	return 1;
 }
@@ -1722,6 +1733,8 @@
 	sti();
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		drive = &hwif->drives[unit];
+		if (!drive->present)
+			continue;
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
diff -u --recursive --new-file v2.2.9/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.2.9/linux/drivers/block/loop.c	Tue Jan 19 11:32:51 1999
+++ linux/drivers/block/loop.c	Sun May 30 10:17:03 1999
@@ -504,6 +504,8 @@
 	if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
 		return -EINVAL;
 	type = info.lo_encrypt_type; 
+	if (info.lo_encrypt_key_size == 0 && type == LO_CRYPT_XOR)
+		return -EINVAL;
 	if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL)
 		return -EINVAL;
 	err = loop_release_xfer(lo);
diff -u --recursive --new-file v2.2.9/linux/drivers/block/ns87415.c linux/drivers/block/ns87415.c
--- v2.2.9/linux/drivers/block/ns87415.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/block/ns87415.c	Sat May 29 11:10:15 1999
@@ -49,8 +49,25 @@
 	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
 
 	if (new != *old) {
+		unsigned char stat;
+
+		/*
+		 * Don't change DMA engine settings while Write Buffers
+		 * are busy.
+		 */
+		(void) pci_read_config_byte(dev, 0x43, &stat);
+		while (stat & 0x03) {
+			udelay(1);
+			(void) pci_read_config_byte(dev, 0x43, &stat);
+		}
+
 		*old = new;
 		(void) pci_write_config_dword(dev, 0x40, new);
+
+		/*
+		 * And let things settle...
+		 */
+		udelay(10);
 	}
 
 	__restore_flags(flags);	/* local CPU only */
diff -u --recursive --new-file v2.2.9/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c
--- v2.2.9/linux/drivers/char/acquirewdt.c	Wed Aug 26 11:37:36 1998
+++ linux/drivers/char/acquirewdt.c	Wed Jun  2 11:29:28 1999
@@ -3,8 +3,8 @@
  *
  *      Based on wdt.c. Original copyright messages:
  *
- *	(c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
- *				http://www.cymru.net
+ *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.com
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -15,7 +15,7 @@
  *	warranty for any of this software. This material is provided 
  *	"AS-IS" and at no charge.	
  *
- *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
  */
 
diff -u --recursive --new-file v2.2.9/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.2.9/linux/drivers/char/bttv.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/char/bttv.c	Mon Jun  7 16:18:17 1999
@@ -1,3 +1,4 @@
+
 /* 
     bttv - Bt848 frame grabber driver
 
@@ -543,6 +544,10 @@
         { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
         /* Pixelview PlayTV (bt878) */
         { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},
+        /* "Leadtek WinView 601", */
+        { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
+        /* AVEC Intercapture */
+        { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
 
@@ -2036,6 +2041,41 @@
 				I2CWrite(&(btv->i2c), I2C_TDA9850,
 					TDA9850_CON3, con3, 1);
 			}
+		   
+		       /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
+		        if (btv->type == BTTV_WINVIEW_601) { 
+			   int bits_out, loops, vol, data;
+
+			   /* 32 levels logarithmic */
+			   vol = 32 - ((v.volume>>11));
+			   /* units */
+                           bits_out = (PT2254_DBS_IN_2>>(vol%5));
+			   /* tens */
+                           bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+			   bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL;
+			   data = btread(BT848_GPIO_DATA);
+			   data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+				      WINVIEW_PT2254_STROBE);
+			   for (loops = 17; loops >= 0 ; loops--) {
+				if (bits_out & (1<<loops))
+				   data |=  WINVIEW_PT2254_DATA;
+				else
+				   data &= ~WINVIEW_PT2254_DATA;
+			       btwrite(data, BT848_GPIO_DATA);
+			       udelay(5);
+			       data |= WINVIEW_PT2254_CLK;
+			       btwrite(data, BT848_GPIO_DATA);
+			       udelay(5);
+			       data &= ~WINVIEW_PT2254_CLK;
+			       btwrite(data, BT848_GPIO_DATA);
+			   }
+			   data |=  WINVIEW_PT2254_STROBE;
+			   data &= ~WINVIEW_PT2254_DATA;
+			   btwrite(data, BT848_GPIO_DATA);
+			   udelay(10);			   
+			   data &= ~WINVIEW_PT2254_STROBE;
+			   btwrite(data, BT848_GPIO_DATA);
+			}
 			if (btv->have_msp3400) 
 			{
                                 i2c_control_device(&(btv->i2c),
@@ -2863,6 +2903,18 @@
         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  */
@@ -2990,9 +3042,16 @@
         
         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);
 
@@ -3033,6 +3092,12 @@
 		case BTTV_VHX:
 			strcpy(btv->video_dev.name,"BT848(Aimslab-VHX)");
  			break;
+	        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);
diff -u --recursive --new-file v2.2.9/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.2.9/linux/drivers/char/bttv.h	Wed Apr 28 11:37:30 1999
+++ linux/drivers/char/bttv.h	Mon Jun  7 16:18:17 1999
@@ -210,6 +210,8 @@
 #define BTTV_VHX           0x0e
 #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
@@ -224,6 +226,7 @@
 #define TDA8425            0x02
 #define TDA9840            0x03
 #define TEA6300            0x04
+#define TEA6320            0x05
 
 #define I2C_TSA5522        0xc2
 #define I2C_TDA9840	   0x84
@@ -232,7 +235,7 @@
 #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
@@ -259,5 +262,29 @@
 #define TEA6300_TR         0x03		/* treble control */
 #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
+#define PT2254_DBS_IN_10 0x20000
+#define WINVIEW_PT2254_CLK  0x40
+#define WINVIEW_PT2254_DATA 0x20
+#define WINVIEW_PT2254_STROBE 0x80
 
 #endif
diff -u --recursive --new-file v2.2.9/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.2.9/linux/drivers/char/cyclades.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/char/cyclades.c	Mon May 24 22:38:02 1999
@@ -1,7 +1,7 @@
 #define BLOCKMOVE
 #define	Z_WAKE
 static char rcsid[] =
-"$Revision: 2.2.2.1 $$Date: 1999/04/08 16:17:43 $";
+"$Revision: 2.2.2.2 $$Date: 1999/05/21 17:18:15 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -21,7 +21,7 @@
  * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
  * and then fixed as suggested by Michael K. Johnson 12/12/92.
  *
- * This version does not support shared irq's.
+ * This version supports shared IRQ's (only for PCI boards).
  *
  * This module exports the following rs232 io functions:
  *   int cy_init(void);
@@ -31,6 +31,17 @@
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.2.2.2  1999/05/14 17:18:15 ivan
+ * /proc entry location changed to /proc/tty/driver/cyclades;
+ * Added support to shared IRQ's (only for PCI boards);
+ * Added support for Cobalt Qube2 systems;
+ * IRQ [de]allocation scheme revisited;
+ * BREAK implementation changed in order to make use of the 'break_ctl'
+ * TTY facility;
+ * Fixed typo in TTY structure field 'driver_name';
+ * Included a PCI bridge reset and EEPROM reload in the board 
+ * initialization code (for both Y and Z series).
+ *
  * Revision 2.2.2.1  1999/04/08 16:17:43 ivan
  * Fixed a bug in cy_wait_until_sent that was preventing the port to be 
  * closed properly after a SIGINT;
@@ -536,7 +547,7 @@
 #undef	CY_16Y_HACK
 #undef	CY_ENABLE_MONITORING
 #undef	CY_PCI_DEBUG
-#define	CY_PROC
+#undef	CY_PROC
 
 #if 0
 #define PAUSE __asm__("nop");
@@ -600,6 +611,14 @@
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
+#ifdef CONFIG_COBALT_27
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#define	CACHED_TO_UNCACHED(x)	(((unsigned long)(x) & \
+				  (unsigned long)0x1fffffff) + KSEG1)
+#endif
+
 #define cy_put_user	put_user
 
 static unsigned long cy_get_user(unsigned long *addr)
@@ -638,6 +657,7 @@
 static struct tty_driver cy_serial_driver, cy_callout_driver;
 static int serial_refcount;
 
+#ifndef CONFIG_COBALT_27
 static volatile int cy_irq_triggered;
 static volatile int cy_triggered;
 static int cy_wild_int_mask;
@@ -665,6 +685,8 @@
 };
 #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
 
+#endif /* CONFIG_COBALT_27 */
+
 /* This is the per-card data structure containing address, irq, number of
    channels, etc. This driver supports a maximum of NR_CARDS cards.
 */
@@ -681,11 +703,6 @@
 static struct termios *serial_termios[NR_PORTS];
 static struct termios *serial_termios_locked[NR_PORTS];
 
-/* This is the per-irq data structure,
-   it maps an irq to the corresponding card */
-
-static struct cyclades_card     *IRQ_cards[NR_IRQS];
-
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
  * lock it in case the copy_from_user blocks while swapping in a page,
@@ -790,7 +807,9 @@
 
 static void cy_start(struct tty_struct *);
 static void set_line_char(struct cyclades_port *);
+#ifndef CONFIG_COBALT_27
 static void cy_probe(int, void *, struct pt_regs *);
+#endif /* CONFIG_COBALT_27 */
 static void cyz_poll(unsigned long);
 #ifdef CYCLOM_SHOW_STATUS
 static void show_status(int);
@@ -959,6 +978,8 @@
     return(0);
 } /* cyy_issue_cmd */
 
+#ifndef CONFIG_COBALT_27	/* ISA interrupt detection code */
+
 static int probe_ready;
 
 /*
@@ -1149,6 +1170,8 @@
     return;
 } /* cy_probe */
 
+#endif /* CONFIG_COBALT_27 */
+
 /* The real interrupt service routine is called
    whenever the card wants its hand held--chars
    received, out buffer empty, modem change, etc.
@@ -1172,9 +1195,9 @@
   int mdm_change;
   int mdm_status;
 
-    if((cinfo = IRQ_cards[irq]) == 0){
+    if((cinfo = (struct cyclades_card *)dev_id) == 0){
 #ifdef CY_DEBUG_INTERRUPTS
-printk("cy_interrupt: spurious interrupt %d\n\r", irq);
+	printk("cy_interrupt: spurious interrupt %d\n\r", irq);
 #endif
         return; /* spurious interrupt */
     }
@@ -1206,7 +1229,7 @@
                 }
                 if (status & CySRReceive) { /* reception interrupt */
 #ifdef CY_DEBUG_INTERRUPTS
-printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
+		    printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
 #endif
                     /* determine the channel & change to that context */
                     save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index));
@@ -1333,7 +1356,7 @@
                        is empty, we know we can always stuff a dozen
                        characters. */
 #ifdef CY_DEBUG_INTERRUPTS
-printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
+		    printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
 #endif
 
                     /* determine the channel & change to that context */
@@ -1368,37 +1391,19 @@
                         info->x_char = 0;
                     }
 
-                    if (info->x_break){
-                        /*  The Cirrus chip requires the "Embedded
-			    Transmit Commands" of start break, delay,
-			    and end break sequences to be sent.  The
-			    duration of the break is given in TICs,
-			    which runs at HZ (typically 100) and the
-			    PPR runs at 200 Hz, so the delay is
-			    duration * 200/HZ, and thus a break can
-			    run from 1/100 sec to about 5/4 sec.
-			    For CD1400 J or later, replace the 200 Hz
-			    by 500 Hz.
-                         */
-			/* start break */
-                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
-                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0x81);
-			/* delay a bit */
-                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
-                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0x82);
-                        if (info->chip_rev >= CD1400_REV_J ) {
-			    /* It is a CD1400 rev. J or later */
-                            cy_writeb((u_long)base_addr + (CyTDR<<index), 
-				      info->x_break*500/HZ);
-			} else {
-                            cy_writeb((u_long)base_addr + (CyTDR<<index), 
-				      info->x_break*200/HZ);
+                    if (info->breakon || info->breakoff) {
+			if (info->breakon) {
+			    cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
+			    cy_writeb((u_long)base_addr + (CyTDR<<index), 0x81);
+			    info->breakon = 0;
+                            char_count -= 2;
+			}
+			if (info->breakoff) {
+			    cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
+			    cy_writeb((u_long)base_addr + (CyTDR<<index), 0x83);
+			    info->breakoff = 0;
+                            char_count -= 2;
 			}
-			/* finish break */
-                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
-                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0x83);
-                        char_count -= 7;
-                        info->x_break = 0;
                     }
 
                     while (char_count-- > 0){
@@ -1871,12 +1876,6 @@
 		    info->last_active = jiffies;
 		    info->jiffies[2] = jiffies;
 		}
-		if (info->x_break){
-		    printk("cyc cyz_poll shouldn't see x_break\n");
-		    info->x_break = 0;
-		    info->last_active = jiffies;
-		    info->jiffies[2] = jiffies;
-		}
 #ifdef BLOCKMOVE
 		while(0 < (small_count
 		    = cy_min((tx_bufsize - tx_put),
@@ -1946,26 +1945,35 @@
 startup(struct cyclades_port * info)
 {
   unsigned long flags;
+  int retval = 0;
   unsigned char *base_addr;
   int card,chip,channel,index;
+  unsigned long page;
+
+    page = get_free_page(GFP_KERNEL);
+    if (!page)
+	return -ENOMEM;
+
+    save_flags(flags); cli();
 
     if (info->flags & ASYNC_INITIALIZED){
-        return 0;
+	free_page(page);
+	goto errout;
     }
 
     if (!info->type){
         if (info->tty){
             set_bit(TTY_IO_ERROR, &info->tty->flags);
         }
-        return 0;
-    }
-    if (!info->xmit_buf){
-        info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
-        if (!info->xmit_buf){
-            return -ENOMEM;
-        }
+	free_page(page);
+	goto errout;
     }
 
+    if (info->xmit_buf)
+	free_page(page);
+    else
+	info->xmit_buf = (unsigned char *) page;
+
     set_line_char(info);
 
     card = info->card;
@@ -1982,39 +1990,40 @@
 	     card, chip, channel, (long)base_addr);/**/
 #endif
 
-	save_flags(flags); cli();
-	    cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
+	cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
 
-	    cy_writeb((ulong)base_addr+(CyRTPR<<index), (info->default_timeout
-				 ? info->default_timeout
-				 : 0x02)); /* 10ms rx timeout */
+	cy_writeb((ulong)base_addr+(CyRTPR<<index), (info->default_timeout
+		 ? info->default_timeout : 0x02)); /* 10ms rx timeout */
 
-	    cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+	cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
 
-	    cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
-	    cy_writeb((ulong)base_addr+(CyMSVR1<<index), CyRTS);
-	    cy_writeb((ulong)base_addr+(CyMSVR2<<index), CyDTR);
+	cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
+	cy_writeb((ulong)base_addr+(CyMSVR1<<index), CyRTS);
+	cy_writeb((ulong)base_addr+(CyMSVR2<<index), CyDTR);
 
 #ifdef CY_DEBUG_DTR
-	    printk("cyc:startup raising DTR\n");
-	    printk("     status: 0x%x, 0x%x\n",
-		   cy_readb(base_addr+(CyMSVR1<<index)), 
-                   cy_readb(base_addr+(CyMSVR2<<index)));
+	printk("cyc:startup raising DTR\n");
+	printk("     status: 0x%x, 0x%x\n",
+		cy_readb(base_addr+(CyMSVR1<<index)), 
+                cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
 
-	    cy_writeb((u_long)base_addr+(CySRER<<index),
-               cy_readb(base_addr+(CySRER<<index)) | CyRxData);
-	    info->flags |= ASYNC_INITIALIZED;
+	cy_writeb((u_long)base_addr+(CySRER<<index),
+		cy_readb(base_addr+(CySRER<<index)) | CyRxData);
+	info->flags |= ASYNC_INITIALIZED;
+
+	if (info->tty){
+	    clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	}
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	info->breakon = info->breakoff = 0;
+	memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+	info->idle_stats.in_use    =
+	info->idle_stats.recv_idle =
+	info->idle_stats.xmit_idle = jiffies;
 
-	    if (info->tty){
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-	    }
-	    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	    memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
-	    info->idle_stats.in_use    =
-	    info->idle_stats.recv_idle =
-	    info->idle_stats.xmit_idle = jiffies;
 	restore_flags(flags);
+
     } else {
       struct FIRM_ID *firm_id;
       struct ZFW_CTRL *zfw_ctrl;
@@ -2022,6 +2031,8 @@
       struct CH_CTRL *ch_ctrl;
       int retval;
 
+	restore_flags(flags);
+
 	base_addr = (unsigned char*) (cy_card[card].base_addr);
 
         firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
@@ -2074,7 +2085,7 @@
 	    clear_bit(TTY_IO_ERROR, &info->tty->flags);
 	}
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
+	info->breakon = info->breakoff = 0;
 	memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
 	info->idle_stats.in_use    =
 	info->idle_stats.recv_idle =
@@ -2085,6 +2096,10 @@
 	printk(" cyc startup done\n");
 #endif
 	return 0;
+
+errout:
+	restore_flags(flags);
+	return retval;
 } /* startup */
 
 
@@ -3763,36 +3778,62 @@
     return 0;
 } /* set_modem_info */
 
+/*
+ * cy_break() --- routine which turns the break handling on or off
+ */
 static void
-send_break( struct cyclades_port * info, int duration)
+cy_break(struct tty_struct *tty, int break_state)
 {
+    struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+    unsigned long flags;
 
+    if (serial_paranoia_check(info, tty->device, "cy_break"))
+	return;
+
+    save_flags(flags); cli();
     if (!IS_CYC_Z(cy_card[info->card])) {
         /* Let the transmit ISR take care of this (since it
 	   requires stuffing characters into the output stream).
         */
-	info->x_break = duration;
-	if (!info->xmit_cnt ) {
-	    start_xmit(info);
+	if (break_state == -1) {
+	    if (!info->breakon) {
+		info->breakon = 1;
+		if (!info->xmit_cnt ) {
+		    start_xmit(info);
+		}
+	    }
+	} else {
+	    if (!info->breakoff) {
+		info->breakoff = 1;
+		if (!info->xmit_cnt ) {
+		    start_xmit(info);
+		}
+	    }
 	}
     } else {
-	/* For the moment we ignore the duration parameter!!!
-	   A better implementation will use C_CM_SET_BREAK
-	   and C_CM_CLR_BREAK with the appropriate delay.
-	 */
-#if 1
-// this appears to wedge the output data stream
-int retval;
-        retval = cyz_issue_cmd(&cy_card[info->card],
+	int retval;
+
+	if (break_state == -1) {
+	    retval = cyz_issue_cmd(&cy_card[info->card],
 		(info->line) - (cy_card[info->card].first_line),
-		C_CM_SENDBRK, 0L);
-	if (retval != 0){
-	    printk("cyc:send_break retval at %d was %x\n",
-	        __LINE__, retval);
+		C_CM_SET_BREAK, 0L);
+	    if (retval != 0) {
+		printk("cyc:cy_break (set) retval at %d was %x\n",
+		        __LINE__, retval);
+	    }
+	} else {
+	    retval = cyz_issue_cmd(&cy_card[info->card],
+		(info->line) - (cy_card[info->card].first_line),
+		C_CM_CLR_BREAK, 0L);
+	    if (retval != 0) {
+		printk("cyc:cy_break (clr) retval at %d was %x\n",
+		        __LINE__, retval);
+	    }
 	}
-#endif
     }
-} /* send_break */
+    restore_flags(flags);
+
+} /* cy_break */
 
 static int
 get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
@@ -4026,21 +4067,6 @@
 	case CYGETWAIT:
 	    ret_val = info->closing_wait / (HZ/100);
 	    break;
-	case TCSBRK:    /* SVID version: non-zero arg --> no break */
-	    ret_val = tty_check_change(tty);
-	    if (ret_val)
-		return ret_val;
-	    tty_wait_until_sent(tty,0);
-	    if (!arg)
-		send_break(info, HZ/4); /* 1/4 second */
-	    break;
-	case TCSBRKP:   /* support for POSIX tcsendbreak() */
-	    ret_val = tty_check_change(tty);
-	    if (ret_val)
-		return ret_val;
-	    tty_wait_until_sent(tty,0);
-	    send_break(info, arg ? arg*(HZ/10) : HZ/4);
-	    break;
         case TIOCMGET:
             ret_val = get_modem_info(info, (unsigned int *) arg);
             break;
@@ -4091,7 +4117,13 @@
             tty->stopped = 0;
             cy_start(tty);
     }
-#ifdef tytso_patch_94Nov25_1726
+#if 0
+    /*
+     * No need to wake up processes in open wait, since they
+     * sample the CLOCAL flag once, and don't recheck it.
+     * XXX  It's not clear whether the current behavior is correct
+     * or not.  Hence, this may change.....
+     */
     if (!(old_termios->c_cflag & CLOCAL) &&
         (tty->termios->c_cflag & CLOCAL))
             wake_up_interruptible(&info->open_wait);
@@ -4100,16 +4132,6 @@
     return;
 } /* cy_set_termios */
 
-
-/*
- * void (*set_ldisc)(struct tty_struct *tty);
- *
- * 	This routine allows the tty driver to be notified when the
- * 	device's termios settings have changed.
- * 
- */
-
-
 /* This routine is called by the upper-layer tty layer to signal
    that incoming characters should be throttled because the input
    buffers are close to full.
@@ -4467,6 +4489,7 @@
     return chip_number;
 } /* cyy_init_card */
 
+#ifndef CONFIG_COBALT_27
 /*
  * ---------------------------------------------------------------------
  * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
@@ -4530,7 +4553,7 @@
 
                 /* allocate IRQ */
                 if(request_irq(cy_isa_irq, cyy_interrupt,
-				   SA_INTERRUPT, "cyclomY", NULL))
+				   SA_INTERRUPT, "Cyclom-Y", &cy_card[j]))
                 {
                         printk("Cyclom-Y/ISA found at 0x%lx ",
                                 (unsigned long) cy_isa_address);
@@ -4546,7 +4569,6 @@
                 cy_card[j].bus_index = 0;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = cy_isa_nchan/4;
-                IRQ_cards[cy_isa_irq] = &cy_card[j];
                 nboard++;
                         
                 /* print message */
@@ -4561,6 +4583,20 @@
         return(nboard);
 
 } /* cy_detect_isa */
+#endif /* CONFIG_COBALT_27 */
+
+static void plx_init(uclong addr, uclong initctl)
+{
+    /* Reset PLX */
+    cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
+    udelay(100L);
+    cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
+
+    /* Reload Config. Registers from EEPROM */
+    cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
+    udelay(100L);
+    cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
+}
 
 /*
  * ---------------------------------------------------------------------
@@ -4621,6 +4657,12 @@
 		cy_pci_addr0  &= PCI_BASE_ADDRESS_MEM_MASK;
 		cy_pci_addr2  &= PCI_BASE_ADDRESS_MEM_MASK;
 
+		if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) {
+		    printk("  Warning: PCI I/O bit incorrectly set. "
+			   "Ignoring it...\n");
+		    cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK;
+		}
+
 #if defined(__alpha__)
                 if (device_id  == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
 		    printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
@@ -4673,7 +4715,7 @@
 
                 /* allocate IRQ */
                 if(request_irq(cy_pci_irq, cyy_interrupt,
-		        SA_INTERRUPT, "cyclomY", NULL))
+		        SA_SHIRQ, "Cyclom-Y", &cy_card[j]))
                 {
                         printk("Cyclom-Y/PCI found at 0x%lx ",
 			    (ulong) cy_pci_addr2);
@@ -4689,13 +4731,14 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = cy_pci_nchan/4;
-                IRQ_cards[cy_pci_irq] = &cy_card[j];
 
                 /* enable interrupts in the PCI interface */
 		plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
 		switch (plx_ver) {
 		    case PLX_9050:
 
+		    plx_init(cy_pci_addr0, 0x50);
+
 		    cy_writew(cy_pci_addr0+0x4c, 
 			cy_readw(cy_pci_addr0+0x4c)|0x0040);
 		    break;
@@ -4704,6 +4747,8 @@
 		    case PLX_9080:
 		    default: /* Old boards, use PLX_9060 */
 
+		    plx_init(cy_pci_addr0, 0x6c);
+
 		    cy_writew(cy_pci_addr0+0x68, 
 			cy_readw(cy_pci_addr0+0x68)|0x0900);
 		    break;
@@ -4742,9 +4787,18 @@
 #if !defined(__alpha__)
                 cy_pci_addr0 = (ulong)ioremap(cy_pci_addr0, CyPCI_Zctl);
 #endif
+
+		plx_init(cy_pci_addr0, 0x6c);
+
 		mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) 
 			   cy_pci_addr0)->mail_box_0);
                 cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
+
+		if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) {
+		    printk("  Warning: PCI I/O bit incorrectly set. "
+			   "Ignoring it...\n");
+		    cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK;
+		}
 		if (mailbox == ZE_V1) {
 #if !defined(__alpha__)
                	    cy_pci_addr2 = (ulong)ioremap(cy_pci_addr2, CyPCI_Ze_win);
@@ -4821,7 +4875,7 @@
                 /* allocate IRQ only if board has an IRQ */
 		if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
 		    if(request_irq(cy_pci_irq,cyz_interrupt,
-			SA_INTERRUPT,"cyclomZ",NULL))
+			SA_SHIRQ,"Cyclades-Z",&cy_card[j]))
 		    {
 			printk("Could not allocate IRQ%d ",
 			    cy_pci_irq);
@@ -4839,7 +4893,6 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
-                IRQ_cards[cy_pci_irq] = &cy_card[j];
 
                 /* print message */
 		/* don't report IRQ if board is no IRQ */
@@ -4905,7 +4958,7 @@
                 /* allocate IRQ only if board has an IRQ */
 		if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
 		    if(request_irq(cy_pci_irq,cyz_interrupt,
-			SA_INTERRUPT,"cyclomZ",NULL))
+			SA_SHIRQ,"Cyclades-Z",&cy_card[j]))
 		    {
 			printk("Could not allocate IRQ%d ",
 			    cy_pci_irq);
@@ -4922,7 +4975,6 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
-                IRQ_cards[cy_pci_irq] = &cy_card[j];
 
                 /* print message */
 		/* don't report IRQ if board is no IRQ */
@@ -4971,7 +5023,6 @@
 	__DATE__, __TIME__);
 } /* show_version */
 
-#ifdef CY_PROC
 static int 
 cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
 		       int *eof, void *data)
@@ -5028,7 +5079,6 @@
 	len = 0;
     return len;
 }
-#endif
 
 /* The serial driver boot-time initialization code!
     Hardware I/O ports are mapped to character special devices on a
@@ -5062,13 +5112,15 @@
   struct proc_dir_entry *ent;
 #endif
 
+    init_bh(CYCLADES_BH, do_cyclades_bh);
+
     show_version();
 
     /* Initialize the tty_driver structure */
     
     memset(&cy_serial_driver, 0, sizeof(struct tty_driver));
     cy_serial_driver.magic = TTY_DRIVER_MAGIC;
-    cy_serial_driver.name = "cyclades";
+    cy_serial_driver.driver_name = "cyclades";
     cy_serial_driver.name = "ttyC";
     cy_serial_driver.major = CYCLADES_MAJOR;
     cy_serial_driver.minor_start = 0;
@@ -5083,6 +5135,7 @@
     cy_serial_driver.table = serial_table;
     cy_serial_driver.termios = serial_termios;
     cy_serial_driver.termios_locked = serial_termios_locked;
+
     cy_serial_driver.open = cy_open;
     cy_serial_driver.close = cy_close;
     cy_serial_driver.write = cy_write;
@@ -5098,7 +5151,9 @@
     cy_serial_driver.stop = cy_stop;
     cy_serial_driver.start = cy_start;
     cy_serial_driver.hangup = cy_hangup;
+    cy_serial_driver.break_ctl = cy_break;
     cy_serial_driver.wait_until_sent = cy_wait_until_sent;
+    cy_serial_driver.read_proc = cyclades_get_proc_info;
 
     /*
      * The callout device is just like normal device except for
@@ -5117,12 +5172,6 @@
     if (tty_register_driver(&cy_callout_driver))
             panic("Couldn't register Cyclades callout driver\n");
 
-    init_bh(CYCLADES_BH, do_cyclades_bh);
-
-    for (i = 0; i < NR_IRQS; i++) {
-            IRQ_cards[i] = 0;
-    }
-
     for (i = 0; i < NR_CARDS; i++) {
             /* base_addr=0 indicates board not found */
             cy_card[i].base_addr = 0;
@@ -5135,9 +5184,11 @@
        availability of cy_card and cy_port data structures and updating
        the cy_next_channel. */
 
+#ifndef CONFIG_COBALT_27
     /* look for isa boards */
     cy_isa_nboard = cy_detect_isa();
-    
+#endif /* CONFIG_COBALT_27 */
+
     /* look for pci boards */
     cy_pci_nboard = cy_detect_pci();
 
@@ -5323,6 +5374,7 @@
 cleanup_module(void)
 {
     int i;
+    int e1, e2;
     unsigned long flags;
 
     if (cyz_timeron){
@@ -5333,11 +5385,12 @@
     save_flags(flags); cli();
     remove_bh(CYCLADES_BH);
 
-    free_page((unsigned long)tmp_buf);
-    if (tty_unregister_driver(&cy_callout_driver))
-            printk("Couldn't unregister Cyclades callout driver\n");
-    if (tty_unregister_driver(&cy_serial_driver))
-            printk("Couldn't unregister Cyclades serial driver\n");
+    if ((e1 = tty_unregister_driver(&cy_serial_driver)))
+            printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
+		e1);
+    if ((e2 = tty_unregister_driver(&cy_callout_driver)))
+            printk("cyc: failed to unregister Cyclades callout driver (%d)\n", 
+		e2);
 
     restore_flags(flags);
 
@@ -5345,9 +5398,13 @@
         if (cy_card[i].base_addr != 0
 	    && cy_card[i].irq)
         {
-            free_irq(cy_card[i].irq,NULL);
+            free_irq(cy_card[i].irq, &cy_card[i]);
         }
     }
+    if (tmp_buf) {
+	free_page((unsigned long) tmp_buf);
+	tmp_buf = NULL;
+    }
 #ifdef CY_PROC
     remove_proc_entry("cyclades", 0);
 #endif
@@ -5358,6 +5415,7 @@
 void
 cy_setup(char *str, int *ints)
 {
+#ifndef CONFIG_COBALT_27
   int i, j;
 
     for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
@@ -5368,6 +5426,7 @@
             cy_isa_addresses[i++] = (unsigned char *)(ints[j]);
         }
     }
+#endif /* CONFIG_COBALT_27 */
 
 } /* cy_setup */
 #endif
diff -u --recursive --new-file v2.2.9/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c
--- v2.2.9/linux/drivers/char/n_hdlc.c	Mon Mar 29 11:09:11 1999
+++ linux/drivers/char/n_hdlc.c	Fri Jun 11 13:08:47 1999
@@ -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 @@
 {
 	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 @@
 
 	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;
diff -u --recursive --new-file v2.2.9/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c
--- v2.2.9/linux/drivers/char/pc110pad.c	Wed Sep  9 14:51:07 1998
+++ linux/drivers/char/pc110pad.c	Wed Jun  2 11:29:28 1999
@@ -9,11 +9,11 @@
  *	This is read internally and used to synthesize a stream of
  *	triples in the form expected from a PS/2 device.
  *
- *	0.0 1997-05-16 Alan Cox <alan@cymru.net> - Pad reader
+ *	0.0 1997-05-16 Alan Cox <alan@redhat.com> - Pad reader
  *	0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
  *	0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
- *	0.3 1997-06-27 Alan Cox <alan@cymru.net> - 2.1 commit
- *	0.4 1997-11-09 Alan Cox <alan@cymru.net> - Single Unix VFS API changes
+ *	0.3 1997-06-27 Alan Cox <alan@redhat.com> - 2.1 commit
+ *	0.4 1997-11-09 Alan Cox <alan@redhat.com> - Single Unix VFS API changes
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.2.9/linux/drivers/char/pms.c linux/drivers/char/pms.c
--- v2.2.9/linux/drivers/char/pms.c	Fri Jan  1 12:58:20 1999
+++ linux/drivers/char/pms.c	Wed Jun  2 11:29:28 1999
@@ -10,7 +10,7 @@
  *	14478 Potsdam, Germany
  *
  *	Most of this code is directly derived from his userspace driver.
- *	His driver works so send any reports to alan@cymru.net unless the
+ *	His driver works so send any reports to alan@redhat.com unless the
  *	userspace driver also doesnt work for you...
  */
 
diff -u --recursive --new-file v2.2.9/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c
--- v2.2.9/linux/drivers/char/radio-cadet.c	Tue May 11 13:10:29 1999
+++ linux/drivers/char/radio-cadet.c	Mon Jun  7 16:18:17 1999
@@ -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 @@
 		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 @@
 
 	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;
diff -u --recursive --new-file v2.2.9/linux/drivers/char/softdog.c linux/drivers/char/softdog.c
--- v2.2.9/linux/drivers/char/softdog.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/char/softdog.c	Wed Jun  2 11:29:28 1999
@@ -1,8 +1,8 @@
 /*
  *	SoftDog	0.05:	A Software Watchdog Device
  *
- *	(c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
- *				http://www.cymru.net
+ *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.com
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
diff -u --recursive --new-file v2.2.9/linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- v2.2.9/linux/drivers/char/synclink.c	Mon Mar 29 11:09:11 1999
+++ linux/drivers/char/synclink.c	Fri Jun 11 13:08:47 1999
@@ -1,6 +1,8 @@
 /*
  * linux/drivers/char/synclink.c
  *
+ * ==FILEDATE 19990610==
+ *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
  *
@@ -43,14 +45,15 @@
  * 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 @@
 } 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 @@
 	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 @@
 	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 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_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 @@
 #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 @@
 
 	/* 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 @@
 		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 @@
 		}
 	}
 
-	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_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 @@
 		}
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 	
 	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 @@
 	              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 @@
 #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 @@
 		}
 	}
 
+	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 @@
 	/* 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 @@
 		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 @@
 		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 @@
 
 	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 @@
 			
 	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 @@
 			
 	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 @@
 /* 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 @@
 	
 	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 @@
 		}
 			
 		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;
+		
+		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 (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;
 		
-		rc = 0;		
-		
-		if (cnow.dsr != cprev.dsr)
-			rc |= (mask & ((s & SerialSignal_DSR) ?
-				MgslEvent_DsrActive:MgslEvent_DsrInactive));
-		
-		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 @@
 		}
 		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 @@
 
 	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 @@
 		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 @@
 	}
 	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 @@
 			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 @@
 					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 @@
 {
 	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 @@
 		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 @@
 		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 @@
 		/*  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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	/**********************************/
 	/* WAIT FOR TRANSMIT FIFO TO FILL */
 	/**********************************/
-															 
+	
 	/* Wait 100ms */
 	EndTime = jiffies + jiffies_from_ms(100);
 
@@ -6720,7 +6961,7 @@
 
 	if ( rc == TRUE ){
 		/* CHECK FOR TRANSMIT ERRORS */
-		if ( status & (BIT5 + BIT1) )
+		if ( status & (BIT5 + BIT1) ) 
 			rc = FALSE;
 	}
 
@@ -6977,13 +7218,90 @@
 	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 ;
+}			  
 
diff -u --recursive --new-file v2.2.9/linux/drivers/char/tuner.c linux/drivers/char/tuner.c
--- v2.2.9/linux/drivers/char/tuner.c	Tue Jan 19 11:32:51 1999
+++ linux/drivers/char/tuner.c	Mon Jun  7 16:18:17 1999
@@ -84,7 +84,9 @@
 	      //  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},
 };
 
 /* ---------------------------------------------------------------------- */
diff -u --recursive --new-file v2.2.9/linux/drivers/char/tuner.h linux/drivers/char/tuner.h
--- v2.2.9/linux/drivers/char/tuner.h	Thu Nov 12 16:21:19 1998
+++ linux/drivers/char/tuner.h	Mon Jun  7 16:18:17 1999
@@ -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
diff -u --recursive --new-file v2.2.9/linux/drivers/char/videodev.c linux/drivers/char/videodev.c
--- v2.2.9/linux/drivers/char/videodev.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/char/videodev.c	Wed Jun  2 11:29:28 1999
@@ -9,7 +9,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Author:	Alan Cox, <alan@cymru.net>
+ * Author:	Alan Cox, <alan@redhat.com>
  *
  * Fixes:
  */
diff -u --recursive --new-file v2.2.9/linux/drivers/char/wdt.c linux/drivers/char/wdt.c
--- v2.2.9/linux/drivers/char/wdt.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/char/wdt.c	Wed Jun  2 11:29:28 1999
@@ -1,8 +1,8 @@
 /*
  *	Industrial Computer Source WDT500/501 driver for Linux 2.1.x
  *
- *	(c) Copyright 1996-1997 Alan Cox <alan@cymru.net>, All Rights Reserved.
- *				http://www.cymru.net
+ *	(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.com
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -15,7 +15,7 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
- *	Release 0.07.
+ *	Release 0.08.
  *
  *	Fixes
  *		Dave Gregorich	:	Modularisation and minor bugs
@@ -24,6 +24,8 @@
  *					Matt Crocker).
  *		Alan Cox	:	Added wdt= boot option
  *		Alan Cox	:	Cleaned up copy/user stuff
+ *		Tim Hockin	:	Added insmod parameters, comment cleanup
+ *					Parameterized timeout
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.2.9/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.2.9/linux/drivers/misc/parport_pc.c	Tue May 11 13:10:29 1999
+++ linux/drivers/misc/parport_pc.c	Tue Jun  1 16:43:43 1999
@@ -371,12 +371,12 @@
 	 * copy. Some ports _do_ allow reads, so bypass the software
 	 * copy here.  In addition, some bits aren't writable. */
 	r = inb (pb->base+CONTROL);
-	if ((r & 0x3f) == w) {
+	if ((r & 0xf) == w) {
 		w = 0xe;
 		parport_pc_write_control (pb, w);
 		r = inb (pb->base+CONTROL);
 		parport_pc_write_control (pb, 0xc);
-		if ((r & 0x3f) == w)
+		if ((r & 0xf) == w)
 			return PARPORT_MODE_PCSPP;
 	}
 
@@ -832,8 +832,11 @@
 		 * Put the ECP detected port in the more SPP like mode.
 		 */
 		parport_pc_write_econtrol(p, 0x0);
-	parport_pc_write_control(p, 0xc);
+	parport_pc_write_control(p, 0x8);
 	parport_pc_write_data(p, 0);
+	udelay (50);
+	parport_pc_write_control(p, 0xc);
+	udelay (50);
 
 	if (parport_probe_hook)
 		(*parport_probe_hook)(p);
diff -u --recursive --new-file v2.2.9/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.2.9/linux/drivers/misc/parport_share.c	Sun Nov  8 14:02:59 1998
+++ linux/drivers/misc/parport_share.c	Mon Jun  7 14:49:10 1999
@@ -298,9 +298,9 @@
 	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);
diff -u --recursive --new-file v2.2.9/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.2.9/linux/drivers/net/3c515.c	Fri Jan  8 22:36:06 1999
+++ linux/drivers/net/3c515.c	Mon Jun  7 16:19:58 1999
@@ -1009,6 +1009,7 @@
 			outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
 		}
 	}
+	vp->stats.tx_bytes+=skb->len;
 	return 0;
 }
 
@@ -1209,6 +1210,7 @@
 				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 @@
 			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);
diff -u --recursive --new-file v2.2.9/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.2.9/linux/drivers/net/Config.in	Tue Mar 23 14:35:47 1999
+++ linux/drivers/net/Config.in	Mon Jun  7 14:35:22 1999
@@ -109,6 +109,7 @@
   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
diff -u --recursive --new-file v2.2.9/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.2.9/linux/drivers/net/Makefile	Fri Apr 16 14:47:30 1999
+++ linux/drivers/net/Makefile	Mon Jun  7 14:35:22 1999
@@ -486,6 +486,14 @@
   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
diff -u --recursive --new-file v2.2.9/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.2.9/linux/drivers/net/Space.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/net/Space.c	Mon Jun  7 14:35:22 1999
@@ -69,6 +69,7 @@
 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 @@
 #endif
 #ifdef CONFIG_ELMC		/* 3c523 */
 	{elmc_probe, 0},
+#endif
+#ifdef CONFIG_SKMC              /* SKnet Microchannel */
+        {skmca_probe, 0},
 #endif
 	{NULL, 0},
 };
diff -u --recursive --new-file v2.2.9/linux/drivers/net/cosa.c linux/drivers/net/cosa.c
--- v2.2.9/linux/drivers/net/cosa.c	Wed Mar 10 15:29:46 1999
+++ linux/drivers/net/cosa.c	Mon Jun  7 16:19:58 1999
@@ -1,7 +1,10 @@
-/* $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>
+ * 
+ * 	5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br>
+ * 		fixed a deadlock in cosa_sppp_open 
  *
  *  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
@@ -72,6 +75,10 @@
  * 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
+ */
 
 /* ---------- Headers, macros, data structures ---------- */
 
@@ -598,6 +605,7 @@
 	if (chan->usage != 0) {
 		printk(KERN_WARNING "%s: sppp_open called with usage count %d\n",
 			chan->name, chan->usage);
+		spin_unlock_irqrestore(&chan->cosa->lock, flags);
 		return -EBUSY;
 	}
 	chan->setup_rx = sppp_setup_rx;
@@ -749,8 +757,13 @@
 
 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,
@@ -1260,8 +1273,10 @@
 			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
 	}
@@ -1654,6 +1669,7 @@
 				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;
diff -u --recursive --new-file v2.2.9/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.2.9/linux/drivers/net/cs89x0.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/net/cs89x0.c	Mon Jun  7 16:19:58 1999
@@ -739,7 +739,7 @@
 		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;
diff -u --recursive --new-file v2.2.9/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.2.9/linux/drivers/net/eexpress.c	Tue May 11 13:10:29 1999
+++ linux/drivers/net/eexpress.c	Sun May 30 10:17:03 1999
@@ -81,7 +81,20 @@
  * ftp's, which is significantly better than I get in DOS, so the overhead of
  * stopping and restarting the CU with each transmit is not prohibitive in
  * practice.
+ *
+ * Update by David Woodhouse 11/5/99:
+ *
+ * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
+ * I assume that this is because 16-bit accesses are actually handled as two
+ * 8-bit accesses.
  */
+
+#ifdef __alpha__
+#define LOCKUP16 1
+#endif
+#ifndef LOCKUP16
+#define LOCKUP16 0
+#endif
   
 #include <linux/config.h>
 #include <linux/module.h>
@@ -297,7 +310,7 @@
 	outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
 }
 
-static inline short int SHADOW(short int addr)
+static inline unsigned short int SHADOW(short int addr)
 {
 	addr &= 0x1f;
 	if (addr > 0xf) addr += 0x3ff0;
@@ -400,7 +413,10 @@
 	outb(0,ioaddr+SIGNAL_CA);
 	free_irq(irq,dev);
 	outb(i586_RST,ioaddr+EEPROM_Ctrl);
-	release_region(ioaddr,16);
+	release_region(ioaddr, EEXP_IO_EXTENT);
+	release_region(ioaddr+0x4000, 16);
+	release_region(ioaddr+0x8000, 16);
+	release_region(ioaddr+0xc000, 16);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -887,7 +903,7 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short ioaddr = dev->base_addr;
 
-	if (lp->width) {
+	if (LOCKUP16 || lp->width) {
 		/* Stop the CU so that there is no chance that it
 		   jumps off to a bogus address while we are writing the
 		   pointer to the next transmit packet in 8-bit mode -- 
@@ -927,7 +943,7 @@
 	if (lp->tx_head != lp->tx_reap)
 		dev->tbusy = 0;
 
-	if (lp->width) {
+	if (LOCKUP16 || lp->width) {
 		/* Restart the CU so that the packet can actually
 		   be transmitted. (Zoltan Szilagyi 10-12-96) */
 		scb_command(dev, SCB_CUresume);
diff -u --recursive --new-file v2.2.9/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.2.9/linux/drivers/net/ibmtr.c	Tue May 11 13:10:29 1999
+++ linux/drivers/net/ibmtr.c	Sun Jun 13 10:48:21 1999
@@ -513,7 +513,7 @@
 	/* How much shared RAM is on adapter ? */
 #ifdef PCMCIA
 	ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
-	ibmtr_mem_base = ti->sram_base ; 
+	ibmtr_mem_base = ti->sram_base << 12 ; 
 #else
 	ti->avail_shared_ram = get_sram_size(ti);
 #endif
@@ -833,6 +833,9 @@
 			(int)readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
 
         dev->start = 0;
+#ifdef PCMCIA
+	ti->sram = 0 ;
+#endif
 	DPRINTK("Adapter closed.\n");
 	MOD_DEC_USE_COUNT;
 
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in
--- v2.2.9/linux/drivers/net/irda/Config.in	Wed Mar 10 15:29:46 1999
+++ linux/drivers/net/irda/Config.in	Mon Jun  7 16:19:58 1999
@@ -1,18 +1,25 @@
 mainmenu_option next_comment
 comment 'Infrared-port device drivers'
 
-dep_tristate 'IrTTY (uses serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA
-if [ "$CONFIG_IRTTY_SIR" != "n" ]; then
-  comment '   Dongle support' 
-  bool '   Serial dongle support' CONFIG_DONGLE
-  if [ "$CONFIG_DONGLE" != "n" ]; then
-    dep_tristate '   ESI JetEye PC dongle' CONFIG_ESI_DONGLE $CONFIG_IRTTY_SIR
-    dep_tristate '   ACTiSYS IR-220L and IR220L+ dongle' CONFIG_ACTISYS_DONGLE $CONFIG_IRTTY_SIR
-    dep_tristate '   Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRTTY_SIR
-    dep_tristate '   Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRTTY_SIR
-  fi
+comment 'SIR device drivers'
+dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA
+dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA
+
+comment 'FIR device drivers'
+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
+if [ "$CONFIG_DONGLE" != "n" ]; then
+  dep_tristate '   ESI JetEye PC dongle' CONFIG_ESI_DONGLE $CONFIG_IRDA
+  dep_tristate '   ACTiSYS IR-220L and IR220L+ dongle' CONFIG_ACTISYS_DONGLE $CONFIG_IRDA
+  dep_tristate '   Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA
+  dep_tristate '   Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA
+  dep_tristate '   Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA
 fi
-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
+
 endmenu
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile
--- v2.2.9/linux/drivers/net/irda/Makefile	Fri Apr 16 14:47:30 1999
+++ linux/drivers/net/irda/Makefile	Mon Jun  7 16:19:58 1999
@@ -20,6 +20,30 @@
   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_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
@@ -44,6 +68,38 @@
   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_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
@@ -73,6 +129,30 @@
 else
   ifeq ($(CONFIG_GIRBIL_DONGLE),m)
   M_OBJS += girbil.o
+  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
+
+ifeq ($(CONFIG_LITELINK_DONGLE),y)
+L_OBJS += litelink.o
+else
+  ifeq ($(CONFIG_LITELINK_DONGLE),m)
+  M_OBJS += litelink.o
   endif
 endif
 
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/actisys.c linux/drivers/net/irda/actisys.c
--- v2.2.9/linux/drivers/net/irda/actisys.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/actisys.c	Mon Jun  7 16:19:58 1999
@@ -1,16 +1,16 @@
 /*********************************************************************
  *                
  * Filename:      actisys.c
- * Version:       0.5
+ * Version:       0.8
  * Description:   Implementation for the ACTiSYS IR-220L and IR-220L+ 
  *                dongles
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Mon Apr 12 11:56:35 1999
+ * Modified at:   Sun May 16 14:35:11 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 
@@ -29,22 +29,16 @@
 #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 actisys_reset( struct irda_device *dev, int unused);
-static void actisys_open( struct irda_device *idev, int type);
-static void actisys_close( struct irda_device *dev);
+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);
+static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos);
 
 /* These are the baudrates supported */
 static int baud_rates[] = { 9600, 19200, 57600, 115200, 38400};
@@ -58,17 +52,37 @@
 	actisys_init_qos,
 };
 
-__initfunc(void actisys_init(void))
+static struct dongle dongle_plus = {
+	ACTISYS_PLUS_DONGLE,
+	actisys_open,
+	actisys_close,
+	actisys_reset,
+	actisys_change_speed,
+	actisys_init_qos,
+};
+
+__initfunc(int actisys_init(void))
 {
-	irtty_register_dongle(&dongle);
+	int ret;
+
+	ret = irda_device_register_dongle(&dongle);
+	if (ret < 0)
+		return ret;
+	ret = irda_device_register_dongle(&dongle_plus);
+	if (ret < 0) {
+		irda_device_unregister_dongle(&dongle);
+		return ret;
+	}	
+	return 0;
 }
 
 void actisys_cleanup(void)
 {
-	irtty_unregister_dongle(&dongle);
+	irda_device_unregister_dongle(&dongle);
+	irda_device_unregister_dongle(&dongle_plus);
 }
 
-static void actisys_open( struct irda_device *idev, int type)
+static void actisys_open(struct irda_device *idev, int type)
 {
 	strcat(idev->description, " <-> actisys");
 
@@ -78,8 +92,11 @@
 	MOD_INC_USE_COUNT;
 }
 
-static void actisys_close( struct irda_device *dev)
+static void actisys_close(struct irda_device *idev)
 {
+	/* Power off dongle */
+	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
 	MOD_DEC_USE_COUNT;
 }
 
@@ -90,25 +107,16 @@
  *    To cycle through the available baud rates, pulse RTS low for a few
  *    ms.  
  */
-static void actisys_change_speed( struct irda_device *idev, int baudrate)
+static void actisys_change_speed(struct irda_device *idev, int baudrate)
 {
-        struct irtty_cb *self;
-        struct tty_struct *tty;
-        struct termios old_termios;
-	int cflag;
         int current_baudrate;
         int index = 0;
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 	
-	self = (struct irtty_cb *) idev->priv;
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
-
 	current_baudrate = idev->qos.baud_rate.value;
 
 	/* Find the correct baudrate index for the currently used baudrate */
@@ -117,69 +125,34 @@
 
         DEBUG( 4, __FUNCTION__ "(), index=%d\n", index);
 
-	if ( !self->tty)
-		return;
-
-	tty = self->tty;
-
 	/* Cycle through avaiable baudrates until we reach the correct one */
-        while ( current_baudrate != baudrate) {	
-                DEBUG( 4, __FUNCTION__ "(), current baudrate = %d\n",
-                       baud_rates[index]);
+        while (current_baudrate != baudrate) {	
+                DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n",
+		      baud_rates[index]);
 		
 		/* Set DTR, clear RTS */
-		irtty_set_dtr_rts(tty, TRUE, FALSE);
+		irda_device_set_dtr_rts(idev, TRUE, FALSE);
 		
 		/* Wait at a few ms */
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(2);
 
 		/* Set DTR, Set RTS */
-		irtty_set_dtr_rts(tty, TRUE, TRUE);
+		irda_device_set_dtr_rts(idev, TRUE, TRUE);
 		
 		/* Wait at a few ms again */
 		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout( 2);
+		schedule_timeout(2);
 
                 /* Go to next baudrate */
-		if ( idev->io.dongle_id == ACTISYS_DONGLE)
+		if (idev->io.dongle_id == ACTISYS_DONGLE)
                         index = (index+1) % 4; /* IR-220L */
 		else
                         index = (index+1) % 5; /* IR-220L+ */
 
                 current_baudrate = baud_rates[index];
         }
-	DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", 
-	      baud_rates[index]);
-
-	/* Now change the speed of the serial port */
-	old_termios = *(tty->termios);
-	cflag = tty->termios->c_cflag;
-
-	cflag &= ~CBAUD;
-
-        switch ( baudrate) {
-        case 9600:
-        default:
-		cflag |= B9600;
-		break;
-	case 19200:
-		cflag |= B19200;
-		break;
-	case 38400:
-		cflag |= B38400;
-		break;
-	case 57600:
-		cflag |= B57600;
-		break;
-	case 115200:
-		cflag |= B115200;
-		break;
-	}
-
-	/* Change speed of serial port */
-	tty->termios->c_cflag = cflag;
-	tty->driver.set_termios( tty, &old_termios);
+	DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n",baud_rates[index]);
 }
 
 /*
@@ -191,32 +164,20 @@
  *    	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)
 {
-	struct irtty_cb *self;
-        struct tty_struct *tty;
-
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	self = (struct irtty_cb *) idev->priv;
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
-
-	tty = self->tty;
-	if ( !tty)
-		return;
-
 	/* Clear DTR */
-	irtty_set_dtr_rts(tty, FALSE, TRUE);
+	irda_device_set_dtr_rts(idev, FALSE, TRUE);
 
 	/* Sleep 10-20 ms*/
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(2);
 	
 	/* Go back to normal mode */
-	irtty_set_dtr_rts(tty, TRUE, TRUE);
+	irda_device_set_dtr_rts(idev, TRUE, TRUE);
 	
 	idev->qos.baud_rate.value = 9600;
 }
@@ -227,12 +188,12 @@
  *    Initialize QoS capabilities
  *
  */
-static void actisys_init_qos( struct irda_device *idev, struct qos_info *qos)
+static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos)
 {
 	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
 
 	/* Remove support for 38400 if this is not a 220L+ dongle */
-	if ( idev->io.dongle_id == ACTISYS_DONGLE)
+	if (idev->io.dongle_id == ACTISYS_DONGLE)
 		qos->baud_rate.bits &= ~IR_38400;
 	
 	qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */
@@ -251,8 +212,7 @@
  */
 int init_module(void)
 {
-	actisys_init();
-	return(0);
+	return actisys_init();
 }
 
 /*
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/esi.c linux/drivers/net/irda/esi.c
--- v2.2.9/linux/drivers/net/irda/esi.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/esi.c	Mon Jun  7 16:19:59 1999
@@ -1,17 +1,17 @@
 /*********************************************************************
  *                
  * Filename:      esi.c
- * Version:       1.2
+ * Version:       1.4
  * Description:   Driver for the Extended Systems JetEye PC dongle
  * Status:        Experimental.
  * Author:        Thomas Davis, <ratbert@radiks.net>
  * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Mon Apr 12 11:55:30 1999
+ * Modified at:   Sun May 16 14:35:21 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:	  esi.c
  *
+ *     Copyright (c) 1998-1999, Dag Brattli, <dagb@cs.uit.no>
  *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>,
- *     Copyright (c) 1998, Dag Brattli,  <dagb@cs.uit.no>
  *     All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
@@ -31,21 +31,17 @@
 #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 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_qos_init( struct irda_device *idev, struct qos_info *qos);
+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);
+static void esi_qos_init(struct irda_device *idev, struct qos_info *qos);
 
 static struct dongle dongle = {
 	ESI_DONGLE,
@@ -58,17 +54,17 @@
 
 __initfunc(int esi_init(void))
 {
-	return irtty_register_dongle(&dongle);
+	return irda_device_register_dongle(&dongle);
 }
 
 void esi_cleanup(void)
 {
-	irtty_unregister_dongle( &dongle);
+	irda_device_unregister_dongle(&dongle);
 }
 
-static void esi_open( struct irda_device *idev, int type)
+static void esi_open(struct irda_device *idev, int type)
 {
-	strcat( idev->description, " <-> esi");
+	strcat(idev->description, " <-> esi");
 
 	idev->io.dongle_id = type;
 	idev->flags |= IFF_DONGLE;
@@ -76,8 +72,11 @@
 	MOD_INC_USE_COUNT;
 }
 
-static void esi_close( struct irda_device *driver)
-{
+static void esi_close(struct irda_device *idev)
+{		
+	/* Power off dongle */
+	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
 	MOD_DEC_USE_COUNT;
 }
 
@@ -87,57 +86,33 @@
  *    Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle
  *
  */
-static void esi_change_speed( struct irda_device *idev, int baud)
+static void esi_change_speed(struct irda_device *idev, int baud)
 {
-	struct irtty_cb *self;
-	struct tty_struct *tty;
 	int dtr, rts;
-        struct termios old_termios;
-	int cflag;
 	
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 	
-	self = (struct irtty_cb *) idev->priv;
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
-
-	if ( !self->tty)
-		return;
-
-	tty = self->tty;
-	
-	old_termios = *(tty->termios);
-	cflag = tty->termios->c_cflag;
-
-	cflag &= ~CBAUD;
-
 	switch (baud) {
 	case 19200:
-		cflag |= B19200;
 		dtr = TRUE;
 		rts = FALSE;
 		break;
 	case 115200:
-		cflag |= B115200;
 		dtr = rts = TRUE;
 		break;
 	case 9600:
 	default:
-		cflag |= B9600;
 		dtr = FALSE;
 		rts = TRUE;
 		break;
 	}
-	/* Change speed of serial driver */
-	tty->termios->c_cflag = cflag;
-	tty->driver.set_termios(tty, &old_termios);
 
-	irtty_set_dtr_rts(tty, dtr, rts);
+	/* Change speed of dongle */
+	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 */
 }
@@ -148,14 +123,17 @@
  *    Init QoS capabilities for the dongle
  *
  */
-static void esi_qos_init( struct irda_device *idev, struct qos_info *qos)
+static void esi_qos_init(struct irda_device *idev, struct qos_info *qos)
 {
 	qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
 	qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */
 }
 
 #ifdef MODULE
-		
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver");
+
 /*
  * Function init_module (void)
  *
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/girbil.c linux/drivers/net/irda/girbil.c
--- v2.2.9/linux/drivers/net/irda/girbil.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/girbil.c	Mon Jun  7 16:19:59 1999
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      girbil.c
- * Version:       1.0
+ * Version:       1.1
  * Description:   Implementation for the Greenwich GIrBIL dongle
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Feb  6 21:02:33 1999
- * Modified at:   Sat Apr 10 19:53:12 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.
@@ -28,17 +28,13 @@
 #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);
@@ -80,19 +76,19 @@
 	girbil_init_qos,
 };
 
-__initfunc(void girbil_init(void))
+__initfunc(int girbil_init(void))
 {
-	irtty_register_dongle(&dongle);
+	return irda_device_register_dongle(&dongle);
 }
 
 void girbil_cleanup(void)
 {
-	irtty_unregister_dongle(&dongle);
+	irda_device_unregister_dongle(&dongle);
 }
 
 static void girbil_open(struct irda_device *idev, int type)
 {
-	strcat( idev->description, " <-> girbil");
+	strcat(idev->description, " <-> girbil");
 
 	idev->io.dongle_id = type;
 	idev->flags |= IFF_DONGLE;
@@ -100,8 +96,11 @@
 	MOD_INC_USE_COUNT;
 }
 
-static void girbil_close(struct irda_device *dev)
+static void girbil_close(struct irda_device *idev)
 {
+	/* Power off dongle */
+	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
 	MOD_DEC_USE_COUNT;
 }
 
@@ -114,71 +113,42 @@
  */
 static void girbil_change_speed(struct irda_device *idev, int speed)
 {
-	struct irtty_cb *self;
-	struct tty_struct *tty;
-	struct termios old_termios;
-	int cflag;
 	__u8 control[2];
 	
 	ASSERT(idev != NULL, return;);
 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 	
-	self = (struct irtty_cb *) idev->priv;
-	
-	ASSERT(self != NULL, return;); 
-	ASSERT(self->magic == IRTTY_MAGIC, return;);
-	
-	if (!self->tty)
-		return;
-
-	tty = self->tty;
-	
-	old_termios = *(tty->termios);
-	cflag = tty->termios->c_cflag;
-
-	cflag &= ~CBAUD;
-
 	switch (speed) {
 	case 9600:
 	default:
-		cflag |= B9600;
 		control[0] = GIRBIL_9600;
 		break;
 	case 19200:
-		cflag |= B19200;
 		control[0] = GIRBIL_19200;
 		break;
 	case 34800:
-		cflag |= B38400;
 		control[0] = GIRBIL_38400;
 		break;
 	case 57600:
-		cflag |= B57600;
 		control[0] = GIRBIL_57600;
 		break;
 	case 115200:
-		cflag |= B115200;
 		control[0] = GIRBIL_115200;
 		break;
 	}
 	control[1] = GIRBIL_LOAD;
 
 	/* Set DTR and Clear RTS to enter command mode */
-	irtty_set_dtr_rts(tty, FALSE, TRUE);
+	irda_device_set_dtr_rts(idev, FALSE, TRUE);
 
 	/* Write control bytes */
-	if (tty->driver.write)
-		tty->driver.write(self->tty, 0, control, 2);
+	irda_device_raw_write(idev, control, 2);
 
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(2);
 	
 	/* Go back to normal mode */
-	irtty_set_dtr_rts(tty, TRUE, TRUE);
-
-	/* Now change the speed of the serial port */
-	tty->termios->c_cflag = cflag;
-	tty->driver.set_termios(tty, &old_termios);	
+	irda_device_set_dtr_rts(idev, TRUE, TRUE);
 }
 
 /*
@@ -191,46 +161,38 @@
  *    	  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)
 {
-	struct irtty_cb *self;
-	struct tty_struct *tty;
 	__u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
 
 	ASSERT(idev != NULL, return;);
 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 	
-	self = (struct irtty_cb *) idev->priv;
-	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRTTY_MAGIC, return;);
-
-	tty = self->tty;
-	if (!tty)
-		return;
-
 	/* Reset dongle */
-	irtty_set_dtr_rts(tty, TRUE, FALSE);
+	irda_device_set_dtr_rts(idev, TRUE, FALSE);
 
 	/* 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 */
-	irtty_set_dtr_rts(tty, FALSE, TRUE);
+	irda_device_set_dtr_rts(idev, FALSE, TRUE);
 
 	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(2);
+	schedule_timeout(MSECS_TO_JIFFIES(20));
 
 	/* Write control byte */
-	if (tty->driver.write)
-		tty->driver.write(self->tty, 0, &control, 1);
+	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 */
-	irtty_set_dtr_rts(tty, TRUE, TRUE);
+	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);
 }
 
 /*
@@ -242,7 +204,7 @@
 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
@@ -258,8 +220,7 @@
  */
 int init_module(void)
 {
-	girbil_init();
-	return(0);
+	return girbil_init();
 }
 
 /*
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
--- v2.2.9/linux/drivers/net/irda/irport.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/irport.c	Sun Jun 13 10:48:21 1999
@@ -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.
  *
  ********************************************************************/
 
@@ -48,14 +43,15 @@
 #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>
@@ -64,105 +60,254 @@
 
 #define IO_EXTENT 8
 
-/* static unsigned int io[]  = { 0x3e8, ~0, ~0, ~0 }; */
-/* static unsigned int irq[] = { 11, 0, 0, 0 }; */
+/* 
+ * Currently you'll need to set these values using insmod like this:
+ * insmod irport io=0x3e8 irq=11
+ */
+static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = { 0, 0, 0, 0 };
+
+static unsigned int qos_mtt_bits = 0x03;
+
+static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL};
+static char *driver_name = "irport";
+
+static int irport_open(int i, unsigned int iobase, unsigned int irq);
+static int irport_close(struct irda_device *idev);
 
 static void irport_write_wakeup(struct irda_device *idev);
 static int  irport_write(int iobase, int fifo_size, __u8 *buf, int len);
 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 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);
+
 __initfunc(int irport_init(void))
 {
-/* 	int i; */
+ 	int i;
 
-/* 	for ( i=0; (io[i] < 2000) && (i < 4); i++) { */
-/* 		int ioaddr = io[i]; */
-/* 		if (check_region(ioaddr, IO_EXTENT)) */
-/* 			continue; */
-/* 		if (irport_open( i, io[i], io2[i], irq[i], dma[i]) == 0) */
-/* 			return 0; */
-/* 	} */
-/* 	return -ENODEV; */
-	return 0;
+ 	for (i=0; (io[i] < 2000) && (i < 4); i++) {
+ 		int ioaddr = io[i];
+ 		if (check_region(ioaddr, IO_EXTENT))
+ 			continue;
+ 		if (irport_open(i, io[i], irq[i]) == 0)
+ 			return 0;
+ 	}
+	/* 
+	 * Maybe something failed, but we can still be usable for FIR drivers 
+	 */
+ 	return 0;
 }
 
 /*
- * Function pc87108_cleanup ()
+ * Function irport_cleanup ()
  *
- *    Close all configured chips
+ *    Close all configured ports
  *
  */
 #ifdef MODULE
 static void irport_cleanup(void)
 {
-/* 	int i; */
+ 	int i;
 
         DEBUG( 4, __FUNCTION__ "()\n");
 
-	/* for ( i=0; i < 4; i++) { */
-/* 		if ( dev_self[i]) */
-/* 			irport_close( &(dev_self[i]->idev)); */
-/* 	} */
+	for (i=0; i < 4; i++) {
+ 		if (dev_self[i])
+ 			irport_close(dev_self[i]);
+ 	}
 }
 #endif /* MODULE */
 
-/*
- * Function irport_open (void)
- *
- *    Start IO port 
- *
- */
-int irport_open(int iobase)
+static int irport_open(int i, unsigned int iobase, unsigned int irq)
 {
-	DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
+	struct irda_device *idev;
+	int ret;
+
+	DEBUG( 0, __FUNCTION__ "()\n");
+
+/* 	if (irport_probe(iobase, irq) == -1) */
+/* 		return -1; */
+
+	/*
+	 *  Allocate new instance of the driver
+	 */
+	idev = kmalloc(sizeof(struct irda_device), GFP_KERNEL);
+	if (idev == NULL) {
+		printk( KERN_ERR "IrDA: Can't allocate memory for "
+			"IrDA control block!\n");
+		return -ENOMEM;
+	}
+	memset(idev, 0, sizeof(struct irda_device));
+   
+	/* Need to store self somewhere */
+	dev_self[i] = idev;
+
+	/* Initialize IO */
+	idev->io.iobase2   = iobase;
+        idev->io.irq2      = 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);
+		/* irport_cleanup(self->idev);  */
+		return -ENODEV;
+	}
+	request_region(idev->io.iobase2, idev->io.io_ext, idev->name);
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&idev->qos);
+	
+	idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+		IR_115200;
+
+	idev->qos.min_turn_time.bits = qos_mtt_bits;
+	irda_qos_bits_to_value(&idev->qos);
+	
+	idev->flags = IFF_SIR|IFF_PIO;
+
+	/* Specify which buffer allocation policy we need */
+	idev->rx_buff.flags = GFP_KERNEL;
+	idev->tx_buff.flags = GFP_KERNEL;
+
+	idev->rx_buff.truesize = 4000; 
+	idev->tx_buff.truesize = 4000;
+	
+	/* Initialize callbacks */
+	idev->change_speed    = irport_change_speed;
+	idev->wait_until_sent = irport_wait_until_sent;
+        idev->is_receiving    = irport_is_receiving;
+	idev->set_dtr_rts     = irport_set_dtr_rts;
+	idev->raw_write       = irport_raw_write;
+
+	/* Override the network functions we need to use */
+	idev->netdev.init            = irport_net_init;
+	idev->netdev.hard_start_xmit = irport_hard_xmit;
+	idev->netdev.open            = irport_net_open;
+	idev->netdev.stop            = irport_net_close;
+
+	/* Open the IrDA device */
+	irda_device_open(idev, driver_name, NULL);
+	
+	return 0;
+}
+
+static int irport_close(struct irda_device *idev)
+{
+	ASSERT(idev != NULL, return -1;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+	/* 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);
+
+	irda_device_close(idev);
+
+	kfree(idev);
+
+	return 0;
+}
+
+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);
 
-	return 0;
+	spin_unlock_irqrestore(&idev->lock, flags);
 }
 
-/*
- * Function irport_cleanup ()
- *
- *    Stop IO port
- *
- */
-void irport_close(int iobase) 
+void irport_stop(struct irda_device *idev, int iobase)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	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);
+}
+
+/*
+ * Function irport_probe (void)
+ *
+ *    Start IO port 
+ *
+ */
+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( int iobase, int speed) 
+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;);
+
+	iobase = idev->io.iobase2;
+	
+	/* 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;
@@ -173,8 +318,10 @@
 	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(&idev->lock, flags);
 }
 
 /*
@@ -188,10 +335,13 @@
 {
 	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 */
@@ -211,9 +361,18 @@
 		/* 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); 
@@ -223,7 +382,7 @@
 /*
  * Function irport_write (driver)
  *
- *    
+ *    Fill Tx FIFO with transmit data
  *
  */
 static int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
@@ -232,21 +391,18 @@
 
 	/* 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;
 }
 
@@ -260,11 +416,10 @@
 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;
@@ -275,8 +430,19 @@
 	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;
@@ -291,6 +457,8 @@
 	/* 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;
@@ -307,10 +475,7 @@
 	int iobase;
 	int boguscount = 0;
 
-	if (!idev)
-		return;
-
-	DEBUG(4, __FUNCTION__ "()\n");
+	ASSERT(idev != NULL, return;);
 
 	iobase = idev->io.iobase2;
 
@@ -342,27 +507,42 @@
 	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)
@@ -371,10 +551,175 @@
  	        iir = inb(iobase + UART_IIR) & UART_IIR_ID;
 	}
 	idev->netdev.interrupt = 0;
+
+	spin_unlock(&idev->lock);
+}
+
+static int irport_net_init(struct device *dev)
+{
+	/* Set up to be a normal IrDA network device driver */
+	irda_device_setup(dev);
+
+	/* Insert overrides below this line! */
+
+	return 0;
+}
+
+/*
+ * Function irport_net_open (dev)
+ *
+ *    
+ *
+ */
+static int irport_net_open(struct device *dev)
+{
+	struct irda_device *idev;
+	int iobase;
+
+	ASSERT(dev != NULL, return -1;);
+	idev = (struct irda_device *) dev->priv;
+
+	iobase = idev->io.iobase2;
+
+	if (request_irq(idev->io.irq2, irport_interrupt, 0, idev->name, 
+			(void *) idev))
+		return -EAGAIN;
+
+	irport_start(idev, iobase);
+
+	MOD_INC_USE_COUNT;
+
+	/* Ready to play! */
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* Change speed to make sure dongles follow us again */
+	if (idev->change_speed)
+		idev->change_speed(idev, 9600);
+
+	return 0;
+}
+
+/*
+ * Function irport_net_close (idev)
+ *
+ *    
+ *
+ */
+static int irport_net_close(struct device *dev)
+{
+	struct irda_device *idev;
+	int iobase;
+
+	ASSERT(dev != NULL, return -1;);
+	idev = (struct irda_device *) dev->priv;
+
+	DEBUG(4, __FUNCTION__ "()\n");
+
+	iobase = idev->io.iobase2;
+
+	/* Stop device */
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	irport_stop(idev, iobase);
+
+	free_irq(idev->io.irq2, idev);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Function irport_wait_until_sent (idev)
+ *
+ *    Delay exectution until finished transmitting
+ *
+ */
+void irport_wait_until_sent(struct irda_device *idev)
+{
+	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);
+}
+
+/*
+ * Function irtty_set_dtr_rts (tty, dtr, rts)
+ *
+ *    This function can be used by dongles etc. to set or reset the status
+ *    of the dtr and rts lines
+ */
+static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts)
+{
+	int iobase;
+
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+	iobase = idev->io.iobase2;
+
+	if (dtr)
+		dtr = UART_MCR_DTR;
+	if (rts)
+		rts = UART_MCR_RTS;
+
+	outb(dtr|rts|UART_MCR_OUT2, iobase+UART_MCR);
+}
+
+static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len)
+{
+	int iobase;
+	int actual = 0;
+
+	ASSERT(idev != NULL, return -1;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+	iobase = idev->io.iobase2;
+
+	/* Tx FIFO should be empty! */
+	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+		DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		return -1;
+	}
+        
+	/* Fill FIFO with current frame */
+	while (actual < len) {
+		/* Transmit next byte */
+		outb(buf[actual], iobase+UART_TX);
+		actual++;
+	}
+
+	return actual;
 }
 
 #ifdef MODULE
 
+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)
  *
@@ -393,11 +738,7 @@
  */
 int init_module(void)
 {
-	if (irport_init() < 0) {
-		cleanup_module();
-		return 1;
-	}
-	return(0);
+	return irport_init();
 }
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- v2.2.9/linux/drivers/net/irda/irtty.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/irtty.c	Wed Jun  2 11:31:36 1999
@@ -6,12 +6,12 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:18:38 1997
- * Modified at:   Thu Apr 22 09:20:24 1999
+ * Modified at:   Mon May 10 15:45:50 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  * 
- *     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 
@@ -24,7 +24,6 @@
  *     
  ********************************************************************/    
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <linux/kernel.h>
@@ -38,19 +37,21 @@
 #include <net/irda/irlap.h>
 #include <net/irda/timer.h>
 #include <net/irda/irda_device.h>
-#include <linux/kmod.h>
 
 static hashbin_t *irtty = NULL;
-static hashbin_t *dongles = NULL;
 
 static struct tty_ldisc irda_ldisc;
 
-static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev);
+static int qos_mtt_bits = 0x03;      /* 5 ms or more */
+
+static int  irtty_hard_xmit(struct sk_buff *skb, struct device *dev);
 static void irtty_wait_until_sent(struct irda_device *driver);
-static int irtty_is_receiving(struct irda_device *idev);
-static int irtty_net_init(struct device *dev);
-static int irtty_net_open(struct device *dev);
-static int irtty_net_close(struct device *dev);
+static int  irtty_is_receiving(struct irda_device *idev);
+static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts);
+static int  irtty_raw_write(struct irda_device *idev, __u8 *buf, int len);
+static int  irtty_net_init(struct device *dev);
+static int  irtty_net_open(struct device *dev);
+static int  irtty_net_close(struct device *dev);
 
 static int  irtty_open(struct tty_struct *tty);
 static void irtty_close(struct tty_struct *tty);
@@ -73,13 +74,6 @@
 		return -ENOMEM;
 	}
 
-	dongles = hashbin_new(HB_LOCAL);
-	if (dongles == NULL) {
-		printk(KERN_WARNING 
-		       "IrDA: Can't allocate dongles hashbin!\n");
-		return -ENOMEM;
-	}
-
 	/* Fill in our line protocol discipline, and register it */
 	memset(&irda_ldisc, 0, sizeof( irda_ldisc));
 
@@ -132,7 +126,6 @@
 	 *  function to hashbin_destroy().
 	 */
 	hashbin_delete(irtty, NULL);
-	hashbin_delete(dongles, NULL);
 }
 #endif /* MODULE */
 
@@ -201,7 +194,7 @@
 	/* The only value we must override it the baudrate */
 	self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
 		IR_115200;
-	self->idev.qos.min_turn_time.bits = 0x0f;
+	self->idev.qos.min_turn_time.bits = qos_mtt_bits;
 	self->idev.flags = IFF_SIR | IFF_PIO;
 	irda_qos_bits_to_value(&self->idev.qos);
 
@@ -216,7 +209,8 @@
 	/* Initialize callbacks */
 	self->idev.change_speed    = irtty_change_speed;
  	self->idev.is_receiving    = irtty_is_receiving;
-	/* self->idev.is_tbusy        = irtty_is_tbusy; */
+	self->idev.set_dtr_rts     = irtty_set_dtr_rts;
+	self->idev.raw_write       = irtty_raw_write;
 	self->idev.wait_until_sent = irtty_wait_until_sent;
 
 	/* Override the network functions we need to use */
@@ -248,10 +242,6 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRTTY_MAGIC, return;);
 
-	/* We are not using any dongle anymore! */
-	if (self->dongle_q)
-		self->dongle_q->dongle->close(&self->idev);
-
 	/* Remove driver */
 	irda_device_close(&self->idev);
 
@@ -359,68 +349,6 @@
 }
 
 /*
- * Function irtty_init_dongle (self, type)
- *
- *    Initialize attached dongle. Warning, must be called with a process
- *    context!
- */
-static void irtty_init_dongle(struct irtty_cb *self, int type)
-{
-	struct dongle_q *node;
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRTTY_MAGIC, return;);
-
-#ifdef CONFIG_KMOD
-	/* Try to load the module needed */
-	switch( type) {
-	case ESI_DONGLE:
-		MESSAGE("IrDA: Trying to initialize ESI dongle!\n");
-		request_module("esi");
-		break;
-	case TEKRAM_DONGLE:
-		MESSAGE("IrDA: Trying to initialize Tekram dongle!\n");
-		request_module("tekram");
-		break;
-	case ACTISYS_DONGLE:     /* FALLTHROUGH */
-	case ACTISYS_PLUS_DONGLE:
-		MESSAGE("IrDA: Trying to initialize ACTiSYS dongle!\n");
-		request_module("actisys");
-		break;
-	case GIRBIL_DONGLE:
-		MESSAGE("IrDA: Trying to initialize GIrBIL dongle!\n");
-		request_module("girbil");
-		break;
-	default:
-		ERROR("Unknown dongle type!\n");
-		return;
-	}
-#endif /* CONFIG_KMOD */
-
-	node = hashbin_find(dongles, type, NULL);
-	if ( !node) {
-		ERROR("Unable to find requested dongle\n");
-		return;
-	}
-	self->dongle_q = node;
-
-	/* Use this change speed function instead of the default */
-	self->idev.change_speed = node->dongle->change_speed;
-
-	/*
-	 * Now initialize the dongle!
-	 */
-	node->dongle->open(&self->idev, type);
-	node->dongle->qos_init(&self->idev, &self->idev.qos);
-	
-	/* Reset dongle */
-	node->dongle->reset(&self->idev, 0);
-
-	/* Set to default baudrate */
-	node->dongle->change_speed(&self->idev, 9600);
-}
-
-/*
  * Function irtty_ioctl (tty, file, cmd, arg)
  *
  *     The Swiss army knife of system calls :-)
@@ -452,7 +380,7 @@
 		break;
 	case IRTTY_IOCTDONGLE:
 		/* Initialize dongle */
-		irtty_init_dongle(self, (int) arg);
+		irda_device_init_dongle(&self->idev, (int) arg);
 		break;
 	default:
 		return -ENOIOCTLCMD;
@@ -645,54 +573,23 @@
 	tty_wait_until_sent(self->tty, 0);
 }
 
-int irtty_register_dongle(struct dongle *dongle)
-{
-	struct dongle_q *new;
-	
-	/* Check if this compressor has been registred before */
-	if ( hashbin_find ( dongles, dongle->type, NULL)) {
-		DEBUG( 0, __FUNCTION__ "(), Dongle already registered\n");
-                return 0;
-        }
-	
-	/* Make new IrDA dongle */
-        new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
-        if (new == NULL)
-                return -1;
-		
-	memset(new, 0, sizeof( struct dongle_q));
-        new->dongle = dongle;
-
-	/* Insert IrDA dongle into hashbin */
-	hashbin_insert(dongles, (QUEUE *) new, dongle->type, NULL);
-	
-        return 0;
-}
-
-void irtty_unregister_dongle(struct dongle *dongle)
-{
-	struct dongle_q *node;
-
-	node = hashbin_remove(dongles, dongle->type, NULL);
-	if (!node) {
-		ERROR(__FUNCTION__ "(), dongle not found!\n");
-		return;
-	}
-	kfree(node);
-}
-
-
 /*
  * Function irtty_set_dtr_rts (tty, dtr, rts)
  *
  *    This function can be used by dongles etc. to set or reset the status
  *    of the dtr and rts lines
  */
-void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts)
+static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts)
 {
+	struct tty_struct *tty;
+	struct irtty_cb *self;
 	mm_segment_t fs;
 	int arg = 0;
 
+	self = (struct irtty_cb *) idev->priv;
+
+	tty = self->tty;
+
 #ifdef TIOCM_OUT2 /* Not defined for ARM */
 	arg = TIOCM_OUT2;
 #endif
@@ -718,6 +615,25 @@
 	set_fs(fs);
 }
 
+static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len)
+{
+	struct irtty_cb *self;
+	int actual = 0;
+
+	ASSERT(idev != NULL, return 0;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+	
+	self = (struct irtty_cb *) idev->priv;
+
+	ASSERT(self != NULL, return 0;);
+	ASSERT(self->magic == IRTTY_MAGIC, return 0;);
+
+	if (self->tty->driver.write)
+		actual = self->tty->driver.write(self->tty, 0, buf, len);
+
+	return actual;
+}
+
 static int irtty_net_init(struct device *dev)
 {
 	/* Set up to be a normal IrDA network device driver */
@@ -759,6 +675,8 @@
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("IrDA TTY device driver");
+
+MODULE_PARM(qos_mtt_bits, "i");
 
 /*
  * Function init_module (void)
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/litelink.c linux/drivers/net/irda/litelink.c
--- v2.2.9/linux/drivers/net/irda/litelink.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/litelink.c	Mon Jun  7 16:19:59 1999
@@ -0,0 +1,206 @@
+/*********************************************************************
+ *                
+ * Filename:      litelink.c
+ * Version:       1.0
+ * Description:   Driver for the Parallax LiteLink dongle
+ * Status:        Stable
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Fri May  7 12:50:33 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.
+ *     
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License 
+ *     along with this program; if not, write to the Free Software 
+ *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *     MA 02111-1307 USA
+ *     
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/dongle.h>
+
+#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);
+static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos);
+
+/* These are the baudrates supported */
+static int baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
+
+static struct dongle dongle = {
+	LITELINK_DONGLE,
+	litelink_open,
+	litelink_close,
+	litelink_reset,
+	litelink_change_speed,
+	litelink_init_qos,
+};
+
+__initfunc(int litelink_init(void))
+{
+	return irda_device_register_dongle(&dongle);
+}
+
+void litelink_cleanup(void)
+{
+	irda_device_unregister_dongle(&dongle);
+}
+
+static void litelink_open(struct irda_device *idev, int type)
+{
+	strcat(idev->description, " <-> litelink");
+
+        idev->io.dongle_id = type;
+	idev->flags |= IFF_DONGLE;
+
+	MOD_INC_USE_COUNT;
+}
+
+static void litelink_close(struct irda_device *idev)
+{
+	/* Power off dongle */
+	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Function litelink_change_speed (tty, baud)
+ *
+ *    Change speed of the Litelink dongle. To cycle through the available 
+ *    baud rates, pulse RTS low for a few ms.  
+ */
+static void litelink_change_speed(struct irda_device *idev, int baudrate)
+{
+        int i;
+	
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	
+	/* Clear RTS to reset dongle */
+	irda_device_set_dtr_rts(idev, TRUE, FALSE);
+
+	/* Sleep a minimum of 15 us */
+	udelay(MIN_DELAY);
+
+	/* Go back to normal mode */
+	irda_device_set_dtr_rts(idev, TRUE, TRUE);
+	
+	/* Sleep a minimum of 15 us */
+	udelay(MIN_DELAY);
+	
+	/* Cycle through avaiable baudrates until we reach the correct one */
+	for (i=0; i<5 && baud_rates[i] != baudrate; i++) {
+
+		/* Set DTR, clear RTS */
+		irda_device_set_dtr_rts(idev, FALSE, TRUE);
+		
+		/* Sleep a minimum of 15 us */
+		udelay(MIN_DELAY);
+		
+		/* Set DTR, Set RTS */
+		irda_device_set_dtr_rts(idev, TRUE, TRUE);
+		
+		/* Sleep a minimum of 15 us */
+		udelay(MIN_DELAY);
+        }
+}
+
+/*
+ * Function litelink_reset (dev)
+ *
+ *      Reset the Litelink type dongle. Warning, this function must only be
+ *      called with a process context!
+ *
+ */
+static void litelink_reset(struct irda_device *idev)
+{
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	
+	/* Power on dongle */
+	irda_device_set_dtr_rts(idev, TRUE, TRUE);
+
+	/* Sleep a minimum of 15 us */
+	udelay(MIN_DELAY);
+
+	/* Clear RTS to reset dongle */
+	irda_device_set_dtr_rts(idev, TRUE, FALSE);
+
+	/* Sleep a minimum of 15 us */
+	udelay(MIN_DELAY);
+
+	/* Go back to normal mode */
+	irda_device_set_dtr_rts(idev, TRUE, TRUE);
+	
+	/* Sleep a minimum of 15 us */
+	udelay(MIN_DELAY);
+
+	/* This dongles speed defaults to 115200 bps */
+	idev->qos.baud_rate.value = 115200;
+}
+
+/*
+ * Function litelink_init_qos (qos)
+ *
+ *    Initialize QoS capabilities
+ *
+ */
+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 */
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Parallax Litelink dongle driver");	
+		
+/*
+ * Function init_module (void)
+ *
+ *    Initialize Litelink module
+ *
+ */
+int init_module(void)
+{
+	return litelink_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup Litelink module
+ *
+ */
+void cleanup_module(void)
+{
+	litelink_cleanup();
+}
+
+#endif
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/pc87108.c linux/drivers/net/irda/pc87108.c
--- v2.2.9/linux/drivers/net/irda/pc87108.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/pc87108.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Tue Apr 20 11:11:39 1999
+ * Modified at:   Mon May 24 15:19:21 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
  *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
  *     Copyright (c) 1998 Actisys Corp., www.actisys.com
  *     All Rights Reserved
@@ -67,11 +67,12 @@
 #define BROKEN_DONGLE_ID
 
 static char *driver_name = "pc87108";
+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 };
 
@@ -97,28 +98,28 @@
 };
 
 /* 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 int  pc87108_net_init( struct device *dev);
-static int  pc87108_net_open( struct device *dev);
-static int  pc87108_net_close( struct device *dev);
+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);
 
 /*
  * Function pc87108_init ()
@@ -130,11 +131,11 @@
 {
 	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;
@@ -166,29 +167,29 @@
  *    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;
@@ -203,24 +204,24 @@
         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 = 0x07;
-	irda_qos_bits_to_value( &idev->qos);
+	idev->qos.min_turn_time.bits = qos_mtt_bits;
+	irda_qos_bits_to_value(&idev->qos);
 	
 	idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
 
@@ -244,10 +245,10 @@
 	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;
 }
@@ -259,23 +260,26 @@
  *    Close driver instance
  *
  */
-static int pc87108_close( struct irda_device *idev)
+static int pc87108_close(struct irda_device *idev)
 {
+	struct pc87108 *self;
 	int iobase;
 
 	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);
-	release_region( idev->io.iobase, idev->io.io_ext);
+	DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase);
+	release_region(idev->io.iobase, idev->io.io_ext);
 
-	irda_device_close( idev);
+	irda_device_close(idev);
+
+	kfree(self);
 
 	return 0;
 }
@@ -287,22 +291,22 @@
  *    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 */
@@ -314,74 +318,73 @@
 	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;
 }
@@ -404,10 +407,10 @@
 	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);
@@ -416,16 +419,16 @@
 	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;
 }
@@ -438,7 +441,7 @@
  *     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;
 
@@ -805,7 +808,6 @@
 	setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
 		  DMA_MODE_WRITE);
 	
-	/* idev->media_busy = TRUE; */
 	idev->io.direction = IO_XMIT;
 	
 	/* Choose transmit DMA channel  */ 
@@ -814,11 +816,11 @@
 	      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);
 }
 
 /*
@@ -828,7 +830,7 @@
  *    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;
@@ -847,16 +849,16 @@
 	}
 
 	/* 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;
 }
@@ -973,7 +975,7 @@
  *
  *    
  */
-static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase)
+static int pc87108_dma_receive_complete(struct irda_device *idev, int iobase)
 {
 	struct sk_buff *skb;
 	struct pc87108 *self;
@@ -988,8 +990,6 @@
 	/* Save current bank */
 	bank = inb( iobase+BSR);
 	
-	iobase = idev->io.iobase;
-
 	/* Read status FIFO */
 	switch_bank(iobase, BANK5);
 	while (( status = inb( iobase+FRM_ST)) & FRM_ST_VLD) {
@@ -1003,18 +1003,18 @@
 	}
 	
 	/* Try to process all entries in status FIFO */
-	switch_bank( iobase, BANK0);
-	while ( st_fifo->len) {
+	switch_bank(iobase, BANK0);
+	while (st_fifo->len) {
       
 		/* Get first entry */
-		status = st_fifo->entries[ st_fifo->head].status;
-		len    = st_fifo->entries[ st_fifo->head].len;
+		status = st_fifo->entries[st_fifo->head].status;
+		len    = st_fifo->entries[st_fifo->head].len;
 		st_fifo->head++;
 		st_fifo->len--;
 
 		/* Check for errors */
-		if ( status & FRM_ST_ERR_MSK) {
-			if ( status & FRM_ST_LOST_FR) {
+		if (status & FRM_ST_ERR_MSK) {
+			if (status & FRM_ST_LOST_FR) {
 				/* Add number of lost frames to stats */
 				idev->stats.rx_errors += len;	
 			} else {
@@ -1188,8 +1188,8 @@
 	bank = inb( iobase+BSR);
 	
 	/* Status event, or end of frame detected in FIFO */
-	if ( eir & (EIR_SFIF_EV|EIR_LS_EV)) {
-		if ( pc87108_dma_receive_complete( idev, iobase)) {
+	if (eir & (EIR_SFIF_EV|EIR_LS_EV)) {
+		if (pc87108_dma_receive_complete( idev, iobase)) {
 
 			/* Wait for next status FIFO interrupt */
 			new_ier |= IER_SFIF_IE;
@@ -1459,6 +1459,14 @@
 }
 
 #ifdef MODULE
+
+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 -u --recursive --new-file v2.2.9/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
--- v2.2.9/linux/drivers/net/irda/smc-ircc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/smc-ircc.c	Mon Jun  7 16:19:59 1999
@@ -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
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/tekram.c linux/drivers/net/irda/tekram.c
--- v2.2.9/linux/drivers/net/irda/tekram.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/tekram.c	Mon Jun  7 16:19:59 1999
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      tekram.c
- * Version:       1.0
+ * 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:   Tue Apr 13 16:33:54 1999
+ * Modified at:   Sun May 16 14:33:42 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 
@@ -28,16 +28,12 @@
 #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 @@
 #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,
@@ -62,15 +58,15 @@
 
 __initfunc(int tekram_init(void))
 {
-	return irtty_register_dongle(&dongle);
+	return irda_device_register_dongle(&dongle);
 }
 
 void tekram_cleanup(void)
 {
-	irtty_unregister_dongle( &dongle);
+	irda_device_unregister_dongle(&dongle);
 }
 
-static void tekram_open( struct irda_device *idev, int type)
+static void tekram_open(struct irda_device *idev, int type)
 {
 	strcat(idev->description, " <-> tekram");
 
@@ -80,8 +76,11 @@
 	MOD_INC_USE_COUNT;
 }
 
-static void tekram_close( struct irda_device *dev)
-{
+static void tekram_close(struct irda_device *idev)
+{		
+	/* Power off dongle */
+	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
 	MOD_DEC_USE_COUNT;
 }
 
@@ -101,79 +100,52 @@
  *    6. wait at least 50 us, new setting (baud rate, etc) takes effect here 
  *       after
  */
-static void tekram_change_speed( struct irda_device *dev, int baud)
+static void tekram_change_speed(struct irda_device *idev, int baud)
 {
-	struct irtty_cb *self;
-	struct tty_struct *tty;
-	struct termios old_termios;
-	int cflag;
 	__u8 byte;
 	
 	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT(dev != NULL, return;);
-	ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	self = (struct irtty_cb *) dev->priv;
-	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRTTY_MAGIC, return;);
-	
-	if (!self->tty)
-		return;
-
-	tty = self->tty;
-	
-	old_termios = *(tty->termios);
-	cflag = tty->termios->c_cflag;
-
-	cflag &= ~CBAUD;
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 
 	switch (baud) {
 	default:
-		/* FALLTHROUGH */
 	case 9600:
-		cflag |= B9600;
 		byte = TEKRAM_PW|TEKRAM_9600;
 		break;
 	case 19200:
-		cflag |= B19200;
 		byte = TEKRAM_PW|TEKRAM_19200;
 		break;
-	case 34800:
-		cflag |= B38400;
+	case 38400:
 		byte = TEKRAM_PW|TEKRAM_38400;
 		break;
 	case 57600:
-		cflag |= B57600;
 		byte = TEKRAM_PW|TEKRAM_57600;
 		break;
 	case 115200:
-		cflag |= B115200;
 		byte = TEKRAM_PW|TEKRAM_115200;
 		break;
 	}
 
+	/* Need to reset the dongle and go to 9600 bps before programming */
+	tekram_reset(idev);
+	
 	/* Set DTR, Clear RTS */
-	irtty_set_dtr_rts(tty, TRUE, FALSE);
+	irda_device_set_dtr_rts(idev, TRUE, FALSE);
 	
 	/* Wait at least 7us */
 	udelay(7);
 
 	/* Write control byte */
-	if (tty->driver.write)
-		tty->driver.write(self->tty, 0, &byte, 1);
+	irda_device_raw_write(idev, &byte, 1);
 	
 	/* Wait at least 100 ms */
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(MSECS_TO_JIFFIES(100));
         
 	/* Set DTR, Set RTS */
-	irtty_set_dtr_rts(tty, TRUE, TRUE);
-
-	/* Now change the speed of the serial port */
-	tty->termios->c_cflag = cflag;
-	tty->driver.set_termios(tty, &old_termios);	
+	irda_device_set_dtr_rts(idev, TRUE, TRUE);
 }
 
 /*
@@ -189,45 +161,33 @@
  *        3. clear DTR to SPACE state, wait at least 50 us for further 
  *         operation
  */
-void tekram_reset(struct irda_device *dev, int unused)
+void tekram_reset(struct irda_device *idev)
 {
-	struct irtty_cb *self;
-	struct tty_struct *tty;
-
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(dev != NULL, return;);
-	ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 	
-	self = (struct irtty_cb *) dev->priv;
-	
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRTTY_MAGIC, return;);
-
-	tty = self->tty;
-	if (!tty)
-		return;
-
 	/* Power off dongle */
-	irtty_set_dtr_rts(tty, FALSE, FALSE);
+	irda_device_set_dtr_rts(idev, FALSE, FALSE);
 
 	/* Sleep 50 ms */
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(MSECS_TO_JIFFIES(50));
 
 	/* Clear DTR, Set RTS */
-	irtty_set_dtr_rts(tty, FALSE, TRUE); 
+	irda_device_set_dtr_rts(idev, FALSE, TRUE); 
 
 	/* Should sleep 1 ms, but 10-20 should not do any harm */
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(MSECS_TO_JIFFIES(20));
 
 	/* Set DTR, Set RTS */
-	irtty_set_dtr_rts(tty, TRUE, TRUE);
+	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);
 }
 
 /*
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- v2.2.9/linux/drivers/net/irda/toshoboe.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/toshoboe.c	Sun May 30 10:17:03 1999
@@ -0,0 +1,901 @@
+/*********************************************************************
+ *                
+ * Filename:      toshoboe.c
+ * Version:       0.1
+ * Description:   Driver for the Toshiba OBOE (or type-O or 700 or 701)
+ *                FIR Chipset. 
+ * Status:        Experimental.
+ * Author:        James McKenzie <james@fishsoup.dhs.org>
+ * Created at:    Sat May 8  12:35:27 1999
+ * 
+ *     Copyright (c) 1999 James McKenzie, 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 James McKenzie nor Cambridge University admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *
+ *     Applicable Models : Libretto 100CT. and many more
+ *     Toshiba refers to this chip as the type-O IR port.
+ *
+ ********************************************************************/
+
+/* This driver is experimental, I have only three ir devices */
+/* an olivetti notebook which doesn't have FIR, a toshiba libretto, and */
+/* an hp printer, this works fine at 4MBPS with my HP printer */
+
+static char *rcsid = "$Id: toshoboe.c,v 1.5 1999/05/12 12:24:39 root Exp root $";
+
+/* 
+ * $Log: toshoboe.c,v $
+ * Revision 1.5  1999/05/12 12:24:39  root
+ * *** empty log message ***
+ *
+ * Revision 1.4  1999/05/12 11:55:08  root
+ * *** empty log message ***
+ *
+ * Revision 1.3  1999/05/09 01:33:12  root
+ * *** empty log message ***
+ *
+ * Revision 1.2  1999/05/09 01:30:38  root
+ * *** empty log message ***
+ *
+ * Revision 1.1  1999/05/09 01:25:04  root
+ * Initial revision
+ * 
+ */
+
+/* Define this to have only one frame in the XMIT or RECV queue */
+/* Toshiba's drivers do this, but it disables back to back tansfers */
+/* I think that the chip may have some problems certainly, I have */
+/* seen it jump over tasks in the taskfile->xmit with this turned on */
+#define ONETASK
+
+/* To adjust the number of tasks in use edit toshoboe.h */
+
+/* Define this to enable FIR and MIR support */
+#define ENABLE_FAST
+
+/* Number of ports this driver can support, you also need to edit dev_self below */
+#define NSELFS 4
+
+/* Size of IO window */
+#define CHIP_IO_EXTENT	0x1f
+
+/* Transmit and receive buffer sizes, adjust at your peril */
+#define RX_BUF_SZ 	4196
+#define TX_BUF_SZ	4196
+
+/* No user servicable parts below here */
+
+#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/init.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.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/toshoboe.h>
+
+static char *driver_name = "toshoboe";
+
+static struct toshoboe_cb *dev_self[NSELFS + 1] =
+{NULL, NULL, NULL, NULL, NULL};
+
+/* Shutdown the chip and point the taskfile reg somewhere else */
+static void 
+toshoboe_stopchip (struct toshoboe_cb *self)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  outb_p (0x0e, OBOE_REG_11);
+
+  outb_p (0x00, OBOE_RST);
+  outb_p (0x3f, OBOE_TFP2);     /*Write the taskfile address */
+  outb_p (0xff, OBOE_TFP1);
+  outb_p (0xff, OBOE_TFP0);
+  outb_p (0x0f, OBOE_REG_1B);
+  outb_p (0xff, OBOE_REG_1A);
+  outb_p (0x00, OBOE_ISR);      /*FIXME: should i do this to disbale ints */
+  outb_p (0x80, OBOE_RST);
+  outb_p (0xe, OBOE_LOCK);
+}
+
+/*Set the baud rate */
+static void 
+toshoboe_setbaud (struct toshoboe_cb *self, int baud)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  printk (KERN_WARNING "ToshOboe: seting baud to %d\n", baud);
+
+  cli ();
+  switch (baud)
+    {
+    case 2400:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0xbf, OBOE_UDIV);
+      break;
+    case 4800:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x5f, OBOE_UDIV);
+      break;
+    case 9600:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x2f, OBOE_UDIV);
+      break;
+    case 19200:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x17, OBOE_UDIV);
+      break;
+    case 38400:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0xb, OBOE_UDIV);
+      break;
+    case 57600:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x7, OBOE_UDIV);
+      break;
+    case 115200:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x3, OBOE_UDIV);
+      break;
+    case 1152000:
+      outb_p (OBOE_PMDL_MIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_MIR, OBOE_SMDL);
+      outb_p (0x1, OBOE_UDIV);
+      break;
+    case 4000000:
+      outb_p (OBOE_PMDL_FIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_FIR, OBOE_SMDL);
+      outb_p (0x0, OBOE_UDIV);
+      break;
+    }
+
+  sti ();
+
+  outb_p (0x00, OBOE_RST);
+  outb_p (0x80, OBOE_RST);
+  outb_p (0x01, OBOE_REG_9);
+
+}
+
+/* Wake the chip up and get it looking at the taskfile */
+static void 
+toshoboe_startchip (struct toshoboe_cb *self)
+{
+  __u32 physaddr;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+
+  outb_p (0, OBOE_LOCK);
+  outb_p (0, OBOE_RST);
+  outb_p (OBOE_NTR_VAL, OBOE_NTR);
+  outb_p (0xf0, OBOE_REG_D);
+  outb_p (0xff, OBOE_ISR);
+  outb_p (0x0f, OBOE_REG_1A);
+  outb_p (0xff, OBOE_REG_1B);
+
+
+  physaddr = virt_to_bus (self->taskfile);
+
+  outb_p ((physaddr >> 0x0a) & 0xff, OBOE_TFP0);
+  outb_p ((physaddr >> 0x12) & 0xff, OBOE_TFP1);
+  outb_p ((physaddr >> 0x1a) & 0x3f, OBOE_TFP2);
+
+  outb_p (0x0e, OBOE_REG_11);
+  outb_p (0x80, OBOE_RST);
+
+  toshoboe_setbaud (self, 9600);
+
+}
+
+/*Let the chip look at memory */
+static void 
+toshoboe_enablebm (struct toshoboe_cb *self)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+  pci_set_master (self->pdev);
+}
+
+/*Don't let the chip look at memory */
+static void 
+toshoboe_disablebm (struct toshoboe_cb *self)
+{
+  __u8 command;
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  pci_read_config_byte (self->pdev, PCI_COMMAND, &command);
+  command &= ~PCI_COMMAND_MASTER;
+  pci_write_config_byte (self->pdev, PCI_COMMAND, command);
+
+}
+
+/*setup the taskfile */
+static void 
+toshoboe_initbuffs (struct toshoboe_cb *self)
+{
+  int i;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  cli ();
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      self->taskfile->xmit[i].len = 0;
+      self->taskfile->xmit[i].control = 0x00;
+      self->taskfile->xmit[i].buffer = virt_to_bus (self->xmit_bufs[i]);
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      self->taskfile->recv[i].len = 0;
+      self->taskfile->recv[i].control = 0x83;
+      self->taskfile->recv[i].buffer = virt_to_bus (self->recv_bufs[i]);
+    }
+
+  sti ();
+}
+
+
+/*Transmit something */
+static int 
+toshoboe_hard_xmit (struct sk_buff *skb, struct device *dev)
+{
+  struct irda_device *idev;
+  struct toshoboe_cb *self;
+  int mtt, len;
+
+  idev = (struct irda_device *) dev->priv;
+  ASSERT (idev != NULL, return 0;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+  self = idev->priv;
+  ASSERT (self != NULL, return 0;);
+
+
+#ifdef ONETASK
+  if (self->txpending)
+    return -EBUSY;
+
+  self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET;
+
+  self->txs &= 0x3f;
+
+#endif
+
+  if (self->taskfile->xmit[self->txs].control)
+    return -EBUSY;
+
+
+  if (inb_p (OBOE_RST) & OBOE_RST_WRAP)
+    {
+      len = async_wrap_skb (skb, self->xmit_bufs[self->txs], TX_BUF_SZ);
+    }
+  else
+    {
+      len = skb->len;
+      memcpy (self->xmit_bufs[self->txs], skb->data, len);
+    }
+  self->taskfile->xmit[self->txs].len = len & 0x0fff;
+
+
+
+  outb_p (0, OBOE_RST);
+  outb_p (0x1e, OBOE_REG_11);
+
+  self->taskfile->xmit[self->txs].control = 0x84;
+
+  mtt = irda_get_mtt (skb);
+  if (mtt)
+    udelay (mtt);
+
+  self->txpending++;
+
+  /*FIXME: ask about tbusy,media_busy stuff, for the moment */
+  /*tbusy means can't queue any more */
+#ifndef ONETASK
+  if (self->txpending == TX_SLOTS)
+    {
+#else
+  {
+#endif
+    if (irda_lock ((void *) &dev->tbusy) == FALSE)
+      return -EBUSY;
+  }
+
+  outb_p (0x80, OBOE_RST);
+  outb_p (1, OBOE_REG_9);
+
+  self->txs++;
+  self->txs %= TX_SLOTS;
+
+  dev_kfree_skb (skb);
+
+  return 0;
+}
+
+/*interrupt handler */
+static void 
+toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct irda_device *idev = (struct irda_device *) dev_id;
+  struct toshoboe_cb *self;
+  __u8 irqstat;
+  struct sk_buff *skb;
+
+  if (idev == NULL)
+    {
+      printk (KERN_WARNING "%s: irq %d for unknown device.\n",
+              driver_name, irq);
+      return;
+    }
+
+  self = idev->priv;
+
+  if (!self)
+    return;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  irqstat = inb_p (OBOE_ISR);
+
+/* woz it us */
+  if (!(irqstat & 0xf8))
+    return;
+
+  outb_p (irqstat, OBOE_ISR);   /*Acknologede it */
+
+
+/* Txdone */
+  if (irqstat & OBOE_ISR_TXDONE)
+    {
+      self->txpending--;
+
+      idev->stats.tx_packets++;
+
+      idev->media_busy = FALSE;
+      idev->netdev.tbusy = 0;
+
+      mark_bh (NET_BH);
+    }
+
+  if (irqstat & OBOE_ISR_RXDONE)
+    {
+
+#ifdef ONETASK
+      self->rxs = inb_p (OBOE_RCVT);
+      self->rxs += (RX_SLOTS - 1);
+      self->rxs %= RX_SLOTS;
+#else
+      while (self->taskfile->recv[self->rxs].control == 0)
+#endif
+        {
+          int len = self->taskfile->recv[self->rxs].len;
+	
+	  if (len>2) len-=2;
+
+          skb = dev_alloc_skb (len + 1);
+          if (skb)
+            {
+              skb_reserve (skb, 1);
+
+              skb_put (skb, len);
+              memcpy (skb->data, self->recv_bufs[self->rxs], len);
+
+              idev->stats.rx_packets++;
+              skb->dev = &idev->netdev;
+              skb->mac.raw = skb->data;
+              skb->protocol = htons (ETH_P_IRDA);
+            }
+          else
+            {
+              printk (KERN_INFO __FUNCTION__
+                      "(), memory squeeze, dropping frame.\n");
+            }
+
+
+
+          self->taskfile->recv[self->rxs].control = 0x83;
+          self->taskfile->recv[self->rxs].len = 0x0;
+
+          self->rxs++;
+          self->rxs %= RX_SLOTS;
+
+          if (skb)
+            netif_rx (skb);
+
+        }
+
+    }
+
+  if (irqstat & OBOE_ISR_20)
+    {
+      printk (KERN_WARNING "Oboe_irq: 20\n");
+    }
+  if (irqstat & OBOE_ISR_10)
+    {
+      printk (KERN_WARNING "Oboe_irq: 10\n");
+    }
+  if (irqstat & 0x8)
+    {
+      /*FIXME: I think this is a TX or RX error of some sort */
+
+      idev->stats.tx_errors++;
+      idev->stats.rx_errors++;
+
+    }
+
+
+}
+
+
+
+/* Change the baud rate */
+static void 
+toshoboe_change_speed (struct irda_device *idev, int speed)
+{
+  struct toshoboe_cb *self;
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (idev != NULL, return;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+  self = idev->priv;
+  ASSERT (self != NULL, return;);
+
+  idev->io.baudrate = speed;
+
+  toshoboe_setbaud (self, speed);
+
+}
+
+
+/* Check all xmit_tasks finished */
+static void 
+toshoboe_wait_until_sent (struct irda_device *idev)
+{
+  struct toshoboe_cb *self;
+  int i;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (idev != NULL, return;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+  self = idev->priv;
+  ASSERT (self != NULL, return;);
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      while (self->taskfile->xmit[i].control)
+        {
+          current->state = TASK_INTERRUPTIBLE;
+          schedule_timeout (6);
+        }
+    }
+
+}
+
+static int 
+toshoboe_is_receiving (struct irda_device *idev)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+
+/*FIXME Can't tell! */
+  return (FALSE);
+}
+
+
+static int 
+toshoboe_net_init (struct device *dev)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  /* Setup to be a normal IrDA network device driver */
+  irda_device_setup (dev);
+
+  /* Insert overrides below this line! */
+  return 0;
+}
+
+
+
+
+static int 
+toshoboe_net_open (struct device *dev)
+{
+  struct irda_device *idev;
+  struct toshoboe_cb *self;
+
+  DEBUG (4, __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;);
+
+  self = idev->priv;
+  ASSERT (self != NULL, return 0;);
+
+  if (request_irq (idev->io.irq, toshoboe_interrupt,
+                   SA_SHIRQ | SA_INTERRUPT, idev->name, (void *) idev))
+    {
+
+      return -EAGAIN;
+    }
+
+  toshoboe_initbuffs (self);
+  toshoboe_enablebm (self);
+  toshoboe_startchip (self);
+
+
+  cli ();
+
+  /*FIXME: need to test this carefully to check which one */
+  /*of the two possible startup logics the chip uses */
+  /*although it won't make any difference if no-one xmits durining init */
+  /*and none what soever if using ONETASK */
+
+  self->rxs = inb_p (OBOE_RCVT);
+  self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET;
+
+#ifdef 0
+  self->rxs = 0;
+  self->txs = 0;
+#endif
+#ifdef 0
+  self->rxs = RX_SLOTS - 1;
+  self->txs = 0;
+#endif
+
+
+  self->txpending = 0;
+
+  sti ();
+
+
+  dev->tbusy = 0;
+  dev->interrupt = 0;
+  dev->start = 1;
+
+  MOD_INC_USE_COUNT;
+
+  return 0;
+
+}
+
+static int 
+toshoboe_net_close (struct device *dev)
+{
+  struct irda_device *idev;
+  struct toshoboe_cb *self;
+
+  DEBUG (4, __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;);
+
+  dev->tbusy = 1;
+  dev->start = 0;
+
+
+  self = idev->priv;
+
+  ASSERT (self != NULL, return 0;);
+
+  free_irq (idev->io.irq, (void *) idev);
+
+  toshoboe_stopchip (self);
+  toshoboe_disablebm (self);
+
+  MOD_DEC_USE_COUNT;
+
+  return 0;
+
+}
+
+
+
+#ifdef MODULE
+
+static int 
+toshoboe_close (struct irda_device *idev)
+{
+  struct toshoboe_cb *self;
+  int i;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (idev != NULL, return -1;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+  self = idev->priv;
+
+  ASSERT (self != NULL, return -1;);
+
+  toshoboe_stopchip (self);
+
+  release_region (idev->io.iobase, idev->io.io_ext);
+
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      kfree (self->xmit_bufs[i]);
+      self->xmit_bufs[i] = NULL;
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      kfree (self->recv_bufs[i]);
+      self->recv_bufs[i] = NULL;
+    }
+
+
+  kfree (self->taskfilebuf);
+  self->taskfilebuf = NULL;
+  self->taskfile = NULL;
+
+
+  irda_device_close (idev);
+
+  return (0);
+
+}
+
+#endif
+
+
+
+static int 
+toshoboe_open (struct pci_dev *pci_dev)
+{
+  struct toshoboe_cb *self;
+  struct irda_device *idev;
+  int i = 0;
+  int ok=0;
+
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  while (dev_self[i])
+    i++;
+
+  if (i == NSELFS)
+    {
+      printk (KERN_ERR "Oboe: No more instances available");
+      return -ENOMEM;
+    }
+
+  self = kmalloc (sizeof (struct toshoboe_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 toshoboe_cb));
+
+
+  dev_self[i] = self;
+
+  self->pdev = pci_dev;
+  self->base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+
+  idev = &self->idev;
+
+  /*Setup idev */
+
+  idev->io.iobase = self->base;
+  idev->io.irq = pci_dev->irq;
+  idev->io.io_ext = CHIP_IO_EXTENT;
+
+  /* Lock the port that we need */
+  i = check_region (idev->io.iobase, idev->io.io_ext);
+  if (i < 0)
+    {
+      DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+             idev->io.iobase);
+
+      dev_self[i] = NULL;
+      kfree (self);
+
+      return -ENODEV;
+    }
+
+  request_region (idev->io.iobase, idev->io.io_ext, driver_name);
+
+  irda_init_max_qos_capabilies (&idev->qos);
+
+  idev->qos.baud_rate.bits = IR_2400 | /*IR_4800 | */ IR_9600 | IR_19200 |
+    IR_115200;
+#ifdef ENABLE_FAST
+ idev->qos.baud_rate.bits|= IR_576000 | IR_1152000 | (IR_4000000 << 8);
+#endif
+
+  idev->qos.min_turn_time.bits = 0xff;  /*FIXME: what does this do? */
+
+  irda_qos_bits_to_value (&idev->qos);
+
+  idev->flags = IFF_SIR | IFF_DMA | IFF_PIO;
+
+#ifdef ENABLE_FAST
+  idev->flags |= IFF_FIR;
+#endif
+
+  /* These aren't much use as we need to have a whole panoply of
+   * buffers running */
+
+  idev->rx_buff.flags = 0;
+  idev->tx_buff.flags = 0;
+  idev->rx_buff.truesize = 0;
+  idev->rx_buff.truesize = 0;
+
+  idev->change_speed = toshoboe_change_speed;
+  idev->wait_until_sent = toshoboe_wait_until_sent;
+  idev->is_receiving = toshoboe_is_receiving;
+
+  idev->netdev.init = toshoboe_net_init;
+  idev->netdev.hard_start_xmit = toshoboe_hard_xmit;
+  idev->netdev.open = toshoboe_net_open;
+  idev->netdev.stop = toshoboe_net_close;
+
+
+  /* Now setup the endless buffers we need */
+
+  self->txs = 0;
+  self->rxs = 0;
+
+  self->taskfilebuf = kmalloc (OBOE_TASK_BUF_LEN, GFP_KERNEL | GFP_DMA);
+  if (!self->taskfilebuf) {
+	printk(KERN_ERR "toshoboe: kmalloc for DMA failed()\n");
+	kfree(self);
+	return -ENOMEM;
+  }
+
+
+  memset (self->taskfilebuf, 0, OBOE_TASK_BUF_LEN);
+
+  /*We need to align the taskfile on a taskfile size boundary */
+  {
+    __u32 addr;
+
+    addr = (__u32) self->taskfilebuf;
+    addr &= ~(sizeof (struct OboeTaskFile) - 1);
+    addr += sizeof (struct OboeTaskFile);
+
+    self->taskfile = (struct OboeTaskFile *) addr;
+  }
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      self->xmit_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA);
+      if (self->xmit_bufs[i]) ok++;
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      self->recv_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA);
+      if (self->recv_bufs[i]) ok++;
+    }
+
+  if (ok!=RX_SLOTS+TX_SLOTS) {
+	printk(KERN_ERR  "toshoboe: kmalloc for buffers failed()\n");
+
+
+  for (i = 0; i < TX_SLOTS; ++i) if (self->xmit_bufs[i]) kfree(self->xmit_bufs[i]);
+  for (i = 0; i < RX_SLOTS; ++i) if (self->recv_bufs[i]) kfree(self->recv_bufs[i]);
+
+	kfree(self);
+	return -ENOMEM;
+
+  }
+
+
+  irda_device_open (idev, driver_name, self);
+
+  printk (KERN_WARNING "ToshOboe: Using ");
+#ifdef ONETASK
+  printk ("single");
+#else
+  printk ("multiple");
+#endif
+  printk (" tasks, version %s\n", rcsid);
+
+  return (0);
+}
+
+__initfunc (int toshoboe_init (void))
+{
+  struct pci_dev *pci_dev = NULL;
+  int found = 0;
+
+  do
+    {
+      pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA,
+                                 PCI_DEVICE_ID_FIR701, pci_dev);
+      if (pci_dev)
+        {
+          printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n",
+                  pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK,
+                  pci_dev->irq);
+
+          if (!toshoboe_open (pci_dev))
+            found++;
+        }
+
+    }
+  while (pci_dev);
+
+  if (found)
+    return 0;
+
+  return -ENODEV;
+}
+
+#ifdef MODULE
+
+static void 
+toshoboe_cleanup (void)
+{
+  int i;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  for (i = 0; i < 4; i++)
+    {
+      if (dev_self[i])
+        toshoboe_close (&(dev_self[i]->idev));
+    }
+}
+
+
+
+int 
+init_module (void)
+{
+  return toshoboe_init ();
+}
+
+
+void 
+cleanup_module (void)
+{
+  toshoboe_cleanup ();
+}
+
+
+#endif
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/uircc.c linux/drivers/net/irda/uircc.c
--- v2.2.9/linux/drivers/net/irda/uircc.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/uircc.c	Mon Jun  7 16:19:59 1999
@@ -7,10 +7,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Dec 26 10:59:03 1998
- * Modified at:   Tue Apr 20 11:15:52 1999
+ * Modified at:   Wed May 19 15:29:56 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 
@@ -216,7 +216,7 @@
 	idev->netdev.open            = uircc_net_open;
 	idev->netdev.stop            = uircc_net_close;
 
-	irport_open(iobase2);
+	irport_start(idev, iobase2);
 
 	/* Open the IrDA device */
 	irda_device_open(idev, driver_name, self);
@@ -233,6 +233,7 @@
 #ifdef MODULE
 static int uircc_close(struct irda_device *idev)
 {
+	struct uircc_cb *self;
 	int iobase;
 	int status;
 
@@ -242,6 +243,7 @@
 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
 
         iobase = idev->io.iobase;
+	self = (struct uircc_cb *) idev->priv;
 
 	/* Some magic to disable FIR and enable SIR */
 	uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000);
@@ -249,7 +251,7 @@
 	/* Disable modem */
 	outb(0x00, iobase+UIRCC_CR10);
 
-	irport_close(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);
@@ -262,6 +264,8 @@
 	}
 	irda_device_close(idev);
 
+	kfree(self);
+
 	return 0;
 }
 #endif /* MODULE */
@@ -346,8 +350,8 @@
 	case 37600:
 	case 57600:
 	case 115200:
- 		irport_open(idev->io.iobase2);
-		irport_change_speed( idev->io.iobase2, speed);
+ 		irport_start(idev, idev->io.iobase2);
+		irport_change_speed(idev, speed);
 
 		/* Some magic to disable FIR and enable SIR */
 		uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000);
@@ -363,7 +367,7 @@
 		DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
 		break;
 	case 4000000:
-		irport_close(idev->io.iobase2);
+		irport_stop(idev, idev->io.iobase2);
 
 		/* Some magic to disable SIR and enable FIR */
 		uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001);
diff -u --recursive --new-file v2.2.9/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- v2.2.9/linux/drivers/net/irda/w83977af_ir.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/irda/w83977af_ir.c	Mon Jun  7 16:19:59 1999
@@ -1,16 +1,16 @@
 /*********************************************************************
  *                
  * Filename:      w83977af_ir.c
- * Version:       0.8
- * Description:   FIR/MIR driver for the Winbond W83977AF Super I/O chip
+ * Version:       1.0
+ * Description:   FIR driver for the Winbond W83977AF Super I/O chip
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Tue Apr 20 11:15:00 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>
  *     Copyright (c) 1998 Corel Computer Corp.
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -40,7 +40,7 @@
  ********************************************************************/
 
 #include <linux/module.h>
-
+ 
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/skbuff.h>
@@ -61,44 +61,43 @@
 #include <net/irda/w83977af.h>
 #include <net/irda/w83977af_ir.h>
 
-#define NETWINDER
+#define CONFIG_NETWINDER                 /* Adjust to NetWinder differences */
+#undef  CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */
+#define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */
+#undef  CONFIG_USE_INTERNAL_TIMER        /* Just cannot make that timer work */
+#define CONFIG_USE_W977_PNP              /* Currently needed */
+#define PIO_MAX_SPEED       115200 
 
 static char *driver_name = "w83977af_ir";
+static int  qos_mtt_bits = 0x07;           /* 1 ms or more */
 
 #define CHIP_IO_EXTENT 8
 
 static unsigned int io[] = { 0x180, ~0, ~0, ~0 };
 static unsigned int irq[] = { 6, 0, 0, 0 };
-static unsigned int dma[] = { 0, 0, 0, 0 };
-
-static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL};
+static unsigned int dma[] = 
+{ 1, 0, 0, 0 };
 
-/* For storing entries in the status FIFO */
-struct st_fifo_entry {
-	int status;
-	int len;
-};
-
-static struct st_fifo_entry prev;
+static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL};
 
 /* Some prototypes */
-static int  w83977af_open( int i, unsigned int iobase, unsigned int irq, 
-			   unsigned int dma);
-static int  w83977af_close( struct irda_device *idev);
-static int  w83977af_probe( int iobase, int irq, int dma);
+static int  w83977af_open(int i, unsigned int iobase, unsigned int irq, 
+                          unsigned int dma);
+static int  w83977af_close(struct irda_device *idev);
+static int  w83977af_probe(int iobase, int irq, int dma);
 static int  w83977af_dma_receive(struct irda_device *idev); 
 static int  w83977af_dma_receive_complete(struct irda_device *idev);
-static int  w83977af_hard_xmit( struct sk_buff *skb, struct device *dev);
-static int  w83977af_pio_write( int iobase, __u8 *buf, int len, int fifo_size);
-static void w83977af_dma_write( struct irda_device *idev, int iobase);
-static void w83977af_change_speed( struct irda_device *idev, int baud);
+static int  w83977af_hard_xmit(struct sk_buff *skb, struct device *dev);
+static int  w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void w83977af_dma_write(struct irda_device *idev, int iobase);
+static void w83977af_change_speed(struct irda_device *idev, int baud);
 static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void w83977af_wait_until_sent( struct irda_device *idev);
-static int w83977af_is_receiving( struct irda_device *idev);
+static void w83977af_wait_until_sent(struct irda_device *idev);
+static int  w83977af_is_receiving(struct irda_device *idev);
 
-static int w83977af_net_init( struct device *dev);
-static int w83977af_net_open( struct device *dev);
-static int w83977af_net_close( struct device *dev);
+static int  w83977af_net_init(struct device *dev);
+static int  w83977af_net_open(struct device *dev);
+static int  w83977af_net_close(struct device *dev);
 
 /*
  * Function w83977af_init ()
@@ -108,13 +107,11 @@
  */
 __initfunc(int w83977af_init(void))
 {
-	int i;
+        int i;
 
-	DEBUG( 0, __FUNCTION__ "()\n");
-
-	prev.status = 0;
+	DEBUG(0, __FUNCTION__ "()\n");
 
-	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;
@@ -135,11 +132,11 @@
 {
 	int i;
 
-        DEBUG( 4, __FUNCTION__ "()\n");
+        DEBUG(4, __FUNCTION__ "()\n");
 
-	for ( i=0; i < 4; i++) {
-		if ( dev_self[i])
-			w83977af_close( dev_self[i]);
+	for (i=0; i < 4; i++) {
+		if (dev_self[i])
+			w83977af_close(&(dev_self[i]->idev));
 	}
 }
 #endif /* MODULE */
@@ -154,26 +151,29 @@
 		   unsigned int dma)
 {
 	struct irda_device *idev;
+        struct w83977af_ir *self;
 	int ret;
 
 	DEBUG( 0, __FUNCTION__ "()\n");
 
-	if ( w83977af_probe( iobase, irq, dma) == -1)
+	if (w83977af_probe(iobase, irq, dma) == -1)
 		return -1;
 
 	/*
 	 *  Allocate new instance of the driver
 	 */
-	idev = kmalloc( sizeof(struct irda_device), GFP_KERNEL);
-	if ( idev == NULL) {
+	self = kmalloc(sizeof(struct w83977af_ir), GFP_KERNEL);
+	if (self == NULL) {
 		printk( KERN_ERR "IrDA: Can't allocate memory for "
 			"IrDA control block!\n");
 		return -ENOMEM;
 	}
-	memset( idev, 0, sizeof(struct irda_device));
+	memset(self, 0, sizeof(struct w83977af_ir));
    
 	/* Need to store self somewhere */
-	dev_self[i] = idev;
+	dev_self[i] = self;
+
+	idev = &self->idev;
 
 	/* Initialize IO */
 	idev->io.iobase    = iobase;
@@ -183,17 +183,17 @@
         idev->io.fifo_size = 32;
 
 	/* Lock the port that we need */
-	ret = check_region( idev->io.iobase, idev->io.io_ext);
-	if ( ret < 0) { 
+	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);
 		/* w83977af_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 */
 
@@ -202,8 +202,8 @@
 		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
 
 	/* The HP HDLS-1100 needs 1 ms according to the specs */
-	idev->qos.min_turn_time.bits = 0x03; /* 1ms and more */
-	irda_qos_bits_to_value( &idev->qos);
+	idev->qos.min_turn_time.bits = qos_mtt_bits;
+	irda_qos_bits_to_value(&idev->qos);
 	
 	idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
 
@@ -221,13 +221,13 @@
         idev->is_receiving    = w83977af_is_receiving;
 
 	/* Override the network functions we need to use */
-	idev->netdev.init = w83977af_net_init;
+	idev->netdev.init            = w83977af_net_init;
 	idev->netdev.hard_start_xmit = w83977af_hard_xmit;
-	idev->netdev.open = w83977af_net_open;
-	idev->netdev.stop = w83977af_net_close;
+	idev->netdev.open            = w83977af_net_open;
+	idev->netdev.stop            = w83977af_net_close;
 
 	/* Open the IrDA device */
-	irda_device_open( idev, driver_name, NULL);
+	irda_device_open(idev, driver_name, self);
 	
 	return 0;
 }
@@ -240,15 +240,18 @@
  */
 static int w83977af_close( struct irda_device *idev)
 {
+	struct w83977af_ir *self;
 	int iobase;
 
-	DEBUG( 0, __FUNCTION__ "()\n");
+	DEBUG(0, __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 w83977af_ir *) idev->priv;
 
+#ifdef CONFIG_USE_W977_PNP
 	/* enter PnP configuration mode */
 	w977_efm_enter();
 
@@ -258,13 +261,15 @@
 	w977_write_reg(0x30, 0x00);
 
 	w977_efm_exit();
-
+#endif /* CONFIG_USE_W977_PNP */
 	/* Release the PORT that this driver is using */
 	DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
 	      idev->io.iobase);
-	release_region( idev->io.iobase, idev->io.io_ext);
+	release_region(idev->io.iobase, idev->io.io_ext);
+
+	irda_device_close(idev);
 
-	irda_device_close( idev);
+	kfree(self);
 
 	return 0;
 }
@@ -280,7 +285,7 @@
 	int version;
 	
 	DEBUG( 0, __FUNCTION__ "()\n");
-
+#ifdef CONFIG_USE_W977_PNP
 	/* Enter PnP configuration mode */
 	w977_efm_enter();
 
@@ -289,14 +294,14 @@
 	/* Configure PnP port, IRQ, and DMA channel */
 	w977_write_reg(0x60, (iobase >> 8) & 0xff);
 	w977_write_reg(0x61, (iobase) & 0xff);
-	/* w977_write_reg(0x70, 0x06); */
+
 	w977_write_reg(0x70, irq);
-#ifdef NETWINDER
-	w977_write_reg(0x74, dma+1); /* Netwinder uses one higher than Linux */
+#ifdef CONFIG_NETWINDER
+	w977_write_reg(0x74, dma+1); /* Netwinder uses 1 higher than Linux */
 #else
 	w977_write_reg(0x74, dma);   
 #endif
-	w977_write_reg(0x75, dma);   /* Disable Tx DMA */
+	w977_write_reg(0x75, 0x04);  /* Disable Tx DMA */
 	
 	/* Set append hardware CRC, enable IR bank selection */	
 	w977_write_reg(0xf0, APEDCRC|ENBNKSEL);
@@ -305,26 +310,26 @@
 	w977_write_reg(0x30, 0x01);
 
 	w977_efm_exit();
-
+#endif
  	/* Disable Advanced mode */
- 	switch_bank( iobase, SET2);
+ 	switch_bank(iobase, SET2);
  	outb(iobase+2, 0x00);  
 
 	/* Turn on UART (global) interrupts */
-	switch_bank( iobase, SET0);
-	outb( HCR_EN_IRQ, iobase+HCR);
+	switch_bank(iobase, SET0);
+	outb(HCR_EN_IRQ, iobase+HCR);
 	
 	/* Switch to advanced mode */
-	switch_bank( iobase, SET2);
-	outb( inb( iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1);
+	switch_bank(iobase, SET2);
+	outb(inb(iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1);
 
 	/* Set default IR-mode */
-	switch_bank( iobase, SET0);
-	outb( HCR_SIR, iobase+HCR);
+	switch_bank(iobase, SET0);
+	outb(HCR_SIR, iobase+HCR);
 
 	/* Read the Advanced IR ID */
 	switch_bank(iobase, SET3);
-	version =  inb( iobase+AUID);
+	version = inb(iobase+AUID);
 	
 	/* Should be 0x1? */
 	if (0x10 != (version & 0xf0)) {
@@ -333,18 +338,17 @@
 	}
 	
 	/* Set FIFO size to 32 */
-	switch_bank( iobase, SET2);
-	outb( ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2);	
+	switch_bank(iobase, SET2);
+	outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2);	
 	
 	/* Set FIFO threshold to TX17, RX16 */
 	switch_bank(iobase, SET0);	
 	outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO,iobase+UFR);
-/* 	outb( 0xa7, iobase+UFR); */
 
 	/* Receiver frame length */
-	switch_bank( iobase, SET4);
-	outb( 2048 & 0xff, iobase+6);
-	outb(( 2048 >> 8) & 0x1f, iobase+7);
+	switch_bank(iobase, SET4);
+	outb(2048 & 0xff, iobase+6);
+	outb((2048 >> 8) & 0x1f, iobase+7);
 
 	/* 
 	 * Init HP HSDL-1100 transceiver. 
@@ -358,8 +362,8 @@
 	 *   FIRRX pin 39 connected to receiver      (IRSL0) 
 	 *   CIRRX pin 40 connected to pin 37
 	 */
-	switch_bank( iobase, SET7);
-	outb( 0x40, iobase+7);
+	switch_bank(iobase, SET7);
+	outb(0x40, iobase+7);
 		
 	DEBUG(0, "W83977AF (IR) driver loaded. Version: 0x%02x\n", version);
 	
@@ -372,16 +376,14 @@
  *    Change the speed of the device
  *
  */
-void w83977af_change_speed( struct irda_device *idev, int speed)
+void w83977af_change_speed(struct irda_device *idev, int speed)
 {
 	int ir_mode = HCR_SIR;
 	int iobase; 
 	__u8 set;
 
-	DEBUG( 0, __FUNCTION__ "()\n");
-
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 
 	iobase = idev->io.iobase;
 
@@ -389,22 +391,22 @@
 	idev->io.baudrate = speed;
 
 	/* Save current bank */
-	set = inb( iobase+SSR);
+	set = inb(iobase+SSR);
 
 	/* Disable interrupts */
-	switch_bank( iobase, SET0);
-	outb( 0, iobase+ICR);
+	switch_bank(iobase, SET0);
+	outb(0, iobase+ICR);
 
 	/* Select Set 2 */
-	switch_bank( iobase, SET2);
+	switch_bank(iobase, SET2);
+	outb(0x00, iobase+ABHL);
 
-	outb( 0x00, iobase+ABHL);
-	switch ( speed) {
-	case 9600:   outb( 0x0c, iobase+ABLL); break;
-	case 19200:  outb( 0x06, iobase+ABLL); break;
-	case 37600:  outb( 0x03, iobase+ABLL); break;
-	case 57600:  outb( 0x02, iobase+ABLL); break;
-	case 115200: outb( 0x01, iobase+ABLL); break;
+	switch (speed) {
+	case 9600:   outb(0x0c, iobase+ABLL); break;
+	case 19200:  outb(0x06, iobase+ABLL); break;
+	case 37600:  outb(0x03, iobase+ABLL); break;
+	case 57600:  outb(0x02, iobase+ABLL); break;
+	case 115200: outb(0x01, iobase+ABLL); break;
 	case 576000:
 		ir_mode = HCR_MIR_576;
 		DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
@@ -419,34 +421,37 @@
 		break;
 	default:
 		ir_mode = HCR_FIR;
-		DEBUG( 0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
+		DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
 		break;
 	}
 
 	/* Set speed mode */
 	switch_bank(iobase, SET0);
-	outb( ir_mode, iobase+HCR);
+	outb(ir_mode, iobase+HCR);
 
 	/* set FIFO size to 32 */
-	switch_bank( iobase, SET2);
-	outb( ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2);	
+	switch_bank(iobase, SET2);
+	outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2);	
 	
 	/* set FIFO threshold to TX17, RX16 */
 	switch_bank(iobase, SET0);
-	outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR);
-	
+
+	outb(0x00, iobase+UFR);        /* Reset */
+	outb(UFR_EN_FIFO, iobase+UFR); /* First we must enable FIFO */
+	outb(0xa7, iobase+UFR);
+
 	idev->netdev.tbusy = 0;
 	
 	/* Enable some interrupts so we can receive frames */
 	switch_bank(iobase, SET0);
-	if ( speed > 115200) {
-		outb( ICR_EFSFI, iobase+ICR);
-		w83977af_dma_receive( idev);
+	if (speed > PIO_MAX_SPEED) {
+		outb(ICR_EFSFI, iobase+ICR);
+		w83977af_dma_receive(idev);
 	} else
-		outb( ICR_ERBRI, iobase+ICR);
+		outb(ICR_ERBRI, iobase+ICR);
     	
 	/* Restore SSR */
-	outb( set, iobase+SSR);
+	outb(set, iobase+SSR);
 }
 
 /*
@@ -455,7 +460,7 @@
  *    Sets up a DMA transfer to send the current frame.
  *
  */
-int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev)
+int w83977af_hard_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct irda_device *idev;
 	int iobase;
@@ -474,20 +479,21 @@
 	/* Lock transmit buffer */
 	if (irda_lock((void *) &dev->tbusy) == FALSE)
 		return -EBUSY;
-	
+
 	/* Save current set */
 	set = inb(iobase+SSR);
 	
 	/* Decide if we should use PIO or DMA transfer */
-	if (idev->io.baudrate > 115200) {
+	if (idev->io.baudrate > PIO_MAX_SPEED) {
+		idev->tx_buff.data = idev->tx_buff.head;
 		memcpy(idev->tx_buff.data, skb->data, skb->len);
 		idev->tx_buff.len = skb->len;
-		idev->tx_buff.data = idev->tx_buff.head;
 		
 		mtt = irda_get_mtt(skb);
+#ifdef CONFIG_USE_INTERNAL_TIMER
 	        if (mtt > 50) {
 			/* Adjust for timer resolution */
-			mtt = mtt / 1000 + 1;
+			mtt /= 1000+1;
 
 			/* Setup timer */
 			switch_bank(iobase, SET4);
@@ -502,6 +508,8 @@
 			switch_bank(iobase, SET0);
 			outb(ICR_ETMRI, iobase+ICR);
 		} else {
+#endif
+			DEBUG(4,__FUNCTION__ "(%ld), mtt=%d\n", jiffies, mtt);
 			if (mtt)
 				udelay(mtt);
 
@@ -509,7 +517,9 @@
 			switch_bank(iobase, SET0);
 	 		outb(ICR_EDMAI, iobase+ICR);
 	     		w83977af_dma_write(idev, iobase);
+#ifdef CONFIG_USE_INTERNAL_TIMER
 		}
+#endif
 	} else {
 		idev->tx_buff.data = idev->tx_buff.head;
 		idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
@@ -527,41 +537,57 @@
 	return 0;
 }
 
-
 /*
  * Function w83977af_dma_write (idev, iobase)
  *
- *    
+ *    Send frame using DMA
  *
  */
-static void w83977af_dma_write( struct irda_device *idev, int iobase)
+static void w83977af_dma_write(struct irda_device *idev, int iobase)
 {
 	__u8 set;
-
-        DEBUG( 4, __FUNCTION__ "()\n");
+#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+	unsigned long flags;
+	__u8 hcr;
+#endif
+        DEBUG(4, __FUNCTION__ "(), len=%d\n", idev->tx_buff.len);
 
 	/* Save current set */
-	set = inb( iobase+SSR);
+	set = inb(iobase+SSR);
 
 	/* Disable DMA */
 	switch_bank(iobase, SET0);
-	outb( inb( iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);
-	
-	setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
-		  DMA_MODE_WRITE);
-	
-	/* idev->media_busy = TRUE; */
-	idev->io.direction = IO_XMIT;
-	
+	outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);
+
 	/* Choose transmit DMA channel  */ 
 	switch_bank(iobase, SET2);
-	outb(inb(iobase+ADCR1) | ADCR1_D_CHSW|ADCR1_DMA_F|ADCR1_ADV_SL, 
-	     iobase+ADCR1);
+	outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1);
+#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+	save_flags(flags);
+	cli();
+
+	disable_dma(idev->io.dma);
+	clear_dma_ff(idev->io.dma);
+	set_dma_mode(idev->io.dma, DMA_MODE_READ);
+	set_dma_addr(idev->io.dma, virt_to_bus(idev->tx_buff.data));
+	set_dma_count(idev->io.dma, idev->tx_buff.len);
+#else
+	setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
+		  DMA_MODE_WRITE);	
+#endif
+	idev->io.direction = IO_XMIT;
 	
 	/* Enable DMA */
  	switch_bank(iobase, SET0);
-	outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR);
-	
+#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+	hcr = inb(iobase+HCR);
+	outb(hcr | HCR_EN_DMA, iobase+HCR);
+	enable_dma(idev->io.dma);
+	restore_flags(flags);
+#else	
+	outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR);
+#endif
+
 	/* Restore set register */
 	outb(set, iobase+SSR);
 }
@@ -577,17 +603,17 @@
 	int actual = 0;
 	__u8 set;
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
 	/* Save current bank */
-	set = inb( iobase+SSR);
+	set = inb(iobase+SSR);
 
-	switch_bank( iobase, SET0);
+	switch_bank(iobase, SET0);
 	if (!(inb_p(iobase+USR) & USR_TSRE)) {
-		DEBUG( 4, __FUNCTION__ "(), warning, FIFO not empty yet!\n");
+		DEBUG(4, __FUNCTION__ "(), warning, FIFO not empty yet!\n");
 
 		fifo_size -= 17;
-		DEBUG( 4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size);
+		DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size);
 	}
 
 	/* Fill FIFO with current frame */
@@ -597,7 +623,7 @@
 	}
         
 	DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-	      fifo_size, actual, len);
+	       fifo_size, actual, len);
 
 	/* Restore bank */
 	outb(set, iobase+SSR);
@@ -617,7 +643,7 @@
 	int iobase;
 	__u8 set;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "(%ld)\n", jiffies);
 
 	ASSERT(idev != NULL, return;);
 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
@@ -663,9 +689,10 @@
  */
 int w83977af_dma_receive(struct irda_device *idev) 
 {
+	struct w83977af_ir *self;
 	int iobase;
 	__u8 set;
-#ifdef NETWINDER
+#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
 	unsigned long flags;
 	__u8 hcr;
 #endif
@@ -673,62 +700,60 @@
 	ASSERT(idev != NULL, return -1;);
 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
 
-	DEBUG(0, __FUNCTION__ "\n");
+	DEBUG(4, __FUNCTION__ "\n");
 
+	self = idev->priv;
 	iobase= idev->io.iobase;
 
 	/* Save current set */
-	set = inb( iobase+SSR);
+	set = inb(iobase+SSR);
 
 	/* Disable DMA */
-	switch_bank( iobase, SET0);
-	outb( inb( iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);
+	switch_bank(iobase, SET0);
+	outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);
+
+	/* Choose DMA Rx, DMA Fairness, and Advanced mode */
+	switch_bank(iobase, SET2);
+	outb((inb(iobase+ADCR1) & ~ADCR1_D_CHSW)/*|ADCR1_DMA_F*/|ADCR1_ADV_SL,
+	     iobase+ADCR1);
+
+	idev->io.direction = IO_RECV;
+	idev->rx_buff.data = idev->rx_buff.head;
 
-#ifdef NETWINDER
+#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
 	save_flags(flags);
 	cli();
 
-	disable_dma( idev->io.dma);
-	clear_dma_ff( idev->io.dma);
-	set_dma_mode( idev->io.dma, DMA_MODE_READ);
-	set_dma_addr( idev->io.dma, virt_to_bus(idev->rx_buff.data));
-	set_dma_count( idev->io.dma, idev->rx_buff.truesize);
+	disable_dma(idev->io.dma);
+	clear_dma_ff(idev->io.dma);
+	set_dma_mode(idev->io.dma, DMA_MODE_READ);
+	set_dma_addr(idev->io.dma, virt_to_bus(idev->rx_buff.data));
+	set_dma_count(idev->io.dma, idev->rx_buff.truesize);
 #else
-	setup_dma(idev->io.dma, idev->rx_buff.data, 
-		  idev->rx_buff.truesize, DMA_MODE_READ);
+	setup_dma(idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, 
+		  DMA_MODE_READ);
 #endif
-	/* driver->media_busy = FALSE; */
-	idev->io.direction = IO_RECV;
-	idev->rx_buff.data = idev->rx_buff.head;
-
 	/* 
 	 * Reset Rx FIFO. This will also flush the ST_FIFO, it's very 
 	 * important that we don't reset the Tx FIFO since it might not
 	 * be finished transmitting yet
 	 */
-	outb( UFR_RXTL|UFR_TXTL|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR);
-	prev.status = 0;
-
-	/* Choose DMA Rx, DMA Fairness, and Advanced mode */
-	switch_bank(iobase, SET2);
-	outb(( inb( iobase+ADCR1) & ~ADCR1_D_CHSW)|ADCR1_DMA_F|ADCR1_ADV_SL,
-	     iobase+ADCR1);
+	switch_bank(iobase, SET0);
+	outb(UFR_RXTL|UFR_TXTL|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR);
+	self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0;
 	
 	/* Enable DMA */
 	switch_bank(iobase, SET0);
-#ifdef NETWINDER
-	hcr = inb( iobase+HCR);
-	enable_dma( idev->io.dma);
-	outb( hcr | HCR_EN_DMA, iobase+HCR);
+#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
+	hcr = inb(iobase+HCR);
+	outb(hcr | HCR_EN_DMA, iobase+HCR);
+	enable_dma(idev->io.dma);
 	restore_flags(flags);
 #else	
-	outb( inb( iobase+HCR) | HCR_EN_DMA, iobase+HCR);
+	outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR);
 #endif
-	
 	/* Restore set */
-	outb( set, iobase+SSR);
-
-	DEBUG( 4, __FUNCTION__ "(), done!\n");	
+	outb(set, iobase+SSR);
 
 	return 0;
 }
@@ -742,12 +767,17 @@
 int w83977af_dma_receive_complete(struct irda_device *idev)
 {
 	struct sk_buff *skb;
+	struct w83977af_ir *self;
+	struct st_fifo *st_fifo;
 	int len;
 	int iobase;
 	__u8 set;
 	__u8 status;
 
-	DEBUG(0, __FUNCTION__ "\n");
+	DEBUG(4, __FUNCTION__ "\n");
+
+	self = idev->priv;
+	st_fifo = &self->st_fifo;
 
 	iobase = idev->io.iobase;
 
@@ -756,22 +786,28 @@
 	
 	iobase = idev->io.iobase;
 
+	/* Read status FIFO */
 	switch_bank(iobase, SET5);
-	if (prev.status & FS_FO_FSFDR) {
-		status = prev.status;
-		len = prev.len;
+	while ((status = inb(iobase+FS_FO)) & FS_FO_FSFDR) {
+		st_fifo->entries[st_fifo->tail].status = status;
 		
-		prev.status = 0;
-	} else {
-		status = inb(iobase+FS_FO);
-		len = inb(iobase+RFLFL);
-		len |= inb(iobase+RFLFH) << 8;
+		st_fifo->entries[st_fifo->tail].len  = inb(iobase+RFLFL);
+		st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8;
+		
+		st_fifo->tail++;
+		st_fifo->len++;
 	}
+	
+	while (st_fifo->len) {
+		/* Get first entry */
+		status = st_fifo->entries[st_fifo->head].status;
+		len    = st_fifo->entries[st_fifo->head].len;
+		st_fifo->head++;
+		st_fifo->len--;
 
-	while (status & FS_FO_FSFDR) {
 		/* Check for errors */
 		if (status & FS_FO_ERR_MSK) {
-			if ( status & FS_FO_LST_FR) {
+			if (status & FS_FO_LST_FR) {
 				/* Add number of lost frames to stats */
 				idev->stats.rx_errors += len;	
 			} else {
@@ -800,14 +836,20 @@
 			/* Check if we have transfered all data to memory */
 			switch_bank(iobase, SET0);
 			if (inb(iobase+USR) & USR_RDR) {
+#ifdef CONFIG_USE_INTERNAL_TIMER
 				/* Put this entry back in fifo */
-				prev.status = status;
-				prev.len = len;
-
+				st_fifo->head--;
+				st_fifo->len++;
+				st_fifo->entries[st_fifo->head].status = status;
+				st_fifo->entries[st_fifo->head].len = len;
+				
 				/* Restore set register */
-				outb( set, iobase+SSR);
+				outb(set, iobase+SSR);
 			
 				return FALSE; 	/* I'll be back! */
+#else
+				udelay(80); /* Should be enough!? */
+#endif
 			}
 						
 			skb = dev_alloc_skb(len+1);
@@ -824,28 +866,23 @@
 			skb_reserve(skb, 1); 
 			
 			/* Copy frame without CRC */
-			if ( idev->io.baudrate < 4000000) {
-				skb_put( skb, len-2);
-				memcpy( skb->data, idev->rx_buff.data, len-2);
+			if (idev->io.baudrate < 4000000) {
+				skb_put(skb, len-2);
+				memcpy(skb->data, idev->rx_buff.data, len-2);
 			} else {
-				skb_put( skb, len-4);
-				memcpy( skb->data, idev->rx_buff.data, len-4);
+				skb_put(skb, len-4);
+				memcpy(skb->data, idev->rx_buff.data, len-4);
 			}
 
 			/* Move to next frame */
 			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);
-			idev->stats.rx_packets++;
+			netif_rx(skb);
 		}
-		/* Read next entry in ST_FIFO */
-		switch_bank(iobase, SET5);
-		status = inb( iobase+FS_FO);
-		len = inb( iobase+RFLFL);
-		len |= inb( iobase+RFLFH) << 8;
 	}
 	/* Restore set register */
 	outb(set, iobase+SSR);
@@ -875,7 +912,6 @@
 	do {
 		byte = inb(iobase+RBR);
 		async_unwrap_char(idev, byte);
-
 	} while (inb(iobase+USR) & USR_RDR); /* Data available */	
 }
 
@@ -889,9 +925,12 @@
 {
 	int actual;
 	__u8 new_icr = 0;
+	__u8 set;
+	int iobase;
 
 	DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr);
 	
+	iobase = idev->io.iobase;
 	/* Transmit FIFO low on data */
 	if (isr & ISR_TXTH_I) {
 		/* Write data left in transmit buffer */
@@ -899,16 +938,21 @@
 					    idev->tx_buff.data, 
 					    idev->tx_buff.len, 
 					    idev->io.fifo_size);
+
 		idev->tx_buff.data += actual;
 		idev->tx_buff.len  -= actual;
 		
 		idev->io.direction = IO_XMIT;
 
 		/* Check if finished */
-		if (idev->tx_buff.len > 0)
+		if (idev->tx_buff.len > 0) {
 			new_icr |= ICR_ETXTHI;
-		else { 
-			DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
+		} else {
+			set = inb(iobase+SSR);
+			switch_bank(iobase, SET0);
+			outb(AUDR_SFEND, iobase+AUDR);
+			outb(set, iobase+SSR); 
+
 			idev->netdev.tbusy = 0; /* Unlock */
 			idev->stats.tx_packets++;
 
@@ -917,7 +961,6 @@
 
 			new_icr |= ICR_ETBREI;
 		}
-		
 	}
 	/* Check if transmission has completed */
 	if (isr & ISR_TXEMP_I) {
@@ -943,22 +986,20 @@
  *    Handle MIR/FIR interrupt
  *
  */
-static __u8 w83977af_fir_interrupt( struct irda_device *idev, int isr)
+static __u8 w83977af_fir_interrupt(struct irda_device *idev, int isr)
 {
 	__u8 new_icr = 0;
 	__u8 set;
 	int iobase;
 
-	DEBUG( 4, __FUNCTION__ "(), isr=%#x\n", isr);
-
 	iobase = idev->io.iobase;
-
 	set = inb(iobase+SSR);
 	
 	/* End of frame detected in FIFO */
 	if (isr & (ISR_FEND_I|ISR_FSF_I)) {
 		if (w83977af_dma_receive_complete(idev)) {
 			
+			/* Wait for next status FIFO interrupt */
 			new_icr |= ICR_EFSFI;
 		} else {
 			/* DMA not finished yet */
@@ -982,7 +1023,7 @@
 
 		/* Clear timer event */
 		/* switch_bank(iobase, SET0); */
-/* 		outb( ASCR_CTE, iobase+ASCR); */
+/* 		outb(ASCR_CTE, iobase+ASCR); */
 
 		/* Check if this is a TX timer interrupt */
 		if (idev->io.direction == IO_XMIT) {
@@ -998,15 +1039,18 @@
 	}	
 	/* Finished with DMA */
 	if (isr & ISR_DMA_I) {
-		w83977af_dma_xmit_complete( idev);
-		
+		w83977af_dma_xmit_complete(idev);
+
 		/* Check if there are more frames to be transmitted */
-		if (irda_device_txqueue_empty( idev)) {
+		/* if (irda_device_txqueue_empty(idev)) { */
 		
-			/* Prepare for receive */
-			w83977af_dma_receive(idev);
-			new_icr = ICR_EFSFI;
-		}
+		/* Prepare for receive 
+		 * 
+		 * ** Netwinder Tx DMA likes that we do this anyway **
+		 */
+		w83977af_dma_receive(idev);
+		new_icr = ICR_EFSFI;
+	       /* } */
 	}
 	
 	/* Restore set */
@@ -1030,7 +1074,7 @@
 
 	if (idev == NULL) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n", 
-		       driver_name, irq);
+			driver_name, irq);
 		return;
 	}
 
@@ -1049,7 +1093,7 @@
 	
 	if (isr) {
 		/* Dispatch interrupt handler for the current speed */
-		if ( idev->io.baudrate > 115200)
+		if (idev->io.baudrate > PIO_MAX_SPEED )
 			icr = w83977af_fir_interrupt(idev, isr);
 		else
 			icr = w83977af_sir_interrupt(idev, isr);
@@ -1070,7 +1114,7 @@
 static void w83977af_wait_until_sent(struct irda_device *idev)
 {
 	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(6);
+	schedule_timeout(60*HZ/1000);
 }
 
 /*
@@ -1085,16 +1129,16 @@
 	int iobase;
 	__u8 set;
 
-	ASSERT( idev != NULL, return FALSE;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	ASSERT(idev != NULL, return FALSE;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
 
-	if ( idev->io.baudrate > 115200) {
+	if (idev->io.baudrate > 115200) {
 		iobase = idev->io.iobase;
 
 		/* Check if rx FIFO is not empty */
 		set = inb(iobase+SSR);
-		switch_bank( iobase, SET2);
-		if (( inb( iobase+RXFDTH) & 0x3f) != 0) {
+		switch_bank(iobase, SET2);
+		if ((inb(iobase+RXFDTH) & 0x3f) != 0) {
 			/* We are receiving something */
 			status =  TRUE;
 		}
@@ -1111,12 +1155,12 @@
  *    
  *
  */
-static int w83977af_net_init( struct device *dev)
+static int w83977af_net_init(struct device *dev)
 {
 	DEBUG(0, __FUNCTION__ "()\n");
 
 	/* Set up to be a normal IrDA network device driver */
-	irda_device_setup( dev);
+	irda_device_setup(dev);
 
 	/* Insert overrides below this line! */
 
@@ -1130,7 +1174,7 @@
  *    Start the device
  *
  */
-static int w83977af_net_open( struct device *dev)
+static int w83977af_net_open(struct device *dev)
 {
 	struct irda_device *idev;
 	int iobase;
@@ -1147,7 +1191,7 @@
 	iobase = idev->io.iobase;
 
 	if (request_irq(idev->io.irq, w83977af_interrupt, 0, idev->name, 
-			(void *) idev)) {
+			 (void *) idev)) {
 		return -EAGAIN;
 	}
 	/*
@@ -1170,13 +1214,13 @@
  	/* Enable some interrupts so we can receive frames again */
  	switch_bank(iobase, SET0);
  	if (idev->io.baudrate > 115200) {
- 		outb( ICR_EFSFI, iobase+ICR);
- 		w83977af_dma_receive( idev);
+ 		outb(ICR_EFSFI, iobase+ICR);
+ 		w83977af_dma_receive(idev);
  	} else
- 		outb( ICR_ERBRI, iobase+ICR);
+ 		outb(ICR_ERBRI, iobase+ICR);
 
 	/* Restore bank register */
-	outb( set, iobase+SSR);
+	outb(set, iobase+SSR);
 
 	MOD_INC_USE_COUNT;
 
@@ -1195,34 +1239,34 @@
 	int iobase;
 	__u8 set;
 
-	DEBUG( 0, __FUNCTION__ "()\n");
+	DEBUG(0, __FUNCTION__ "()\n");
 	
 	/* Stop device */
 	dev->tbusy = 1;
 	dev->start = 0;
 
-	ASSERT( dev != NULL, return -1;);
+	ASSERT(dev != NULL, return -1;);
 	idev = (struct irda_device *) dev->priv;
 	
-	ASSERT( idev != NULL, return 0;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+	ASSERT(idev != NULL, return 0;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);
 	
 	iobase = idev->io.iobase;
 
-	disable_dma( idev->io.dma);
+	disable_dma(idev->io.dma);
 
 	/* Save current set */
-	set = inb( iobase+SSR);
+	set = inb(iobase+SSR);
 	
 	/* Disable interrupts */
-	switch_bank( iobase, SET0);
-	outb( 0, iobase+ICR); 
+	switch_bank(iobase, SET0);
+	outb(0, iobase+ICR); 
 
-	free_irq( idev->io.irq, idev);
-	free_dma( idev->io.dma);
+	free_irq(idev->io.irq, idev);
+	free_dma(idev->io.dma);
 
 	/* Restore bank register */
-	outb( set, iobase+SSR);
+	outb(set, iobase+SSR);
 
 	MOD_DEC_USE_COUNT;
 
@@ -1230,6 +1274,11 @@
 }
 
 #ifdef MODULE
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver");
+
+MODULE_PARM(qos_mtt_bits, "i");
 
 /*
  * Function init_module (void)
diff -u --recursive --new-file v2.2.9/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.2.9/linux/drivers/net/ni52.c	Fri Oct  9 13:27:09 1998
+++ linux/drivers/net/ni52.c	Tue Jun  8 10:27:27 1999
@@ -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!)
diff -u --recursive --new-file v2.2.9/linux/drivers/net/ni52.h linux/drivers/net/ni52.h
--- v2.2.9/linux/drivers/net/ni52.h	Thu Apr 11 23:49:38 1996
+++ linux/drivers/net/ni52.h	Tue Jun  8 10:27:27 1999
@@ -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
diff -u --recursive --new-file v2.2.9/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.2.9/linux/drivers/net/ni65.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/ni65.c	Tue Jun  8 10:27:27 1999
@@ -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 @@
 				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 @@
 				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 -u --recursive --new-file v2.2.9/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.2.9/linux/drivers/net/shaper.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/net/shaper.c	Wed Jun  2 11:29:28 1999
@@ -1,8 +1,8 @@
 /*
  *			Simple traffic shaper for Linux NET3.
  *
- *	(c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
- *				http://www.cymru.net
+ *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.com
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
diff -u --recursive --new-file v2.2.9/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c
--- v2.2.9/linux/drivers/net/sk_mca.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/sk_mca.c	Mon Jun  7 14:34:54 1999
@@ -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 -u --recursive --new-file v2.2.9/linux/drivers/net/sk_mca.h linux/drivers/net/sk_mca.h
--- v2.2.9/linux/drivers/net/sk_mca.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/sk_mca.h	Mon Jun  7 14:34:54 1999
@@ -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
diff -u --recursive --new-file v2.2.9/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v2.2.9/linux/drivers/net/smc-ultra.c	Wed Mar 10 15:29:46 1999
+++ linux/drivers/net/smc-ultra.c	Wed May 26 09:33:02 1999
@@ -483,9 +483,9 @@
 			/* NB: ultra_close_card() does free_irq + irq2dev */
 			int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
 			kfree(dev->priv);
-			dev->priv = NULL;
 			release_region(ioaddr, ULTRA_IO_EXTENT);
 			unregister_netdev(dev);
+			dev->priv = NULL;
 		}
 	}
 }
diff -u --recursive --new-file v2.2.9/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.2.9/linux/drivers/net/sunhme.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/net/sunhme.c	Sat May 29 11:10:15 1999
@@ -1834,7 +1834,7 @@
 #define RXD(x)
 #endif
 
-/* Originally I use to handle the allocation failure by just giving back just
+/* Originally I used to handle the allocation failure by just giving back just
  * that one ring buffer to the happy meal.  Problem is that usually when that
  * condition is triggered, the happy meal expects you to do something reasonable
  * with all of the packets it has DMA'd in.  So now I just drop the entire
diff -u --recursive --new-file v2.2.9/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.2.9/linux/drivers/pci/oldproc.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/pci/oldproc.c	Wed Jun  9 16:59:34 1999
@@ -102,6 +102,7 @@
 	DEVICE( DEC,		DEC_21150,	"DC21150"),
 	DEVICE( DEC,		DEC_21152,	"DC21152"),
 	DEVICE( DEC,		DEC_21153,	"DC21153"),
+	DEVICE( DEC,		DEC_21154,	"DC21154"),
 	DEVICE( CIRRUS,		CIRRUS_7548,	"GD 7548"),
 	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430"),
 	DEVICE( CIRRUS,		CIRRUS_5434_4,	"GD 5434"),
@@ -202,6 +203,8 @@
 	DEVICE( MOTOROLA,	MOTOROLA_MPC105,"MPC105 Eagle"),
 	DEVICE( MOTOROLA,	MOTOROLA_MPC106,"MPC106 Grackle"),
 	DEVICE( MOTOROLA,	MOTOROLA_RAVEN,	"Raven"),
+	DEVICE( MOTOROLA,	MOTOROLA_FALCON,"Falcon"),
+	DEVICE( MOTOROLA,	MOTOROLA_CPX8216,"CPX8216"),
 	DEVICE( PROMISE,        PROMISE_20246,	"IDE UltraDMA/33"),
 	DEVICE( PROMISE,	PROMISE_5300,	"DC5030"),
 	DEVICE( N9,		N9_I128,	"Imagine 128"),
@@ -462,6 +465,7 @@
 	DEVICE( PICTUREL,	PICTUREL_PCIVST,"PCIVST"),
 	DEVICE( NVIDIA_SGS,	NVIDIA_SGS_RIVA128,	"Riva 128"),
 	DEVICE( CBOARDS,	CBOARDS_DAS1602_16,"DAS1602/16"),
+	DEVICE( MOTOROLA_OOPS,	MOTOROLA_FALCON,"Falcon"),
 	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101"),
 	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290"),
 	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
@@ -531,9 +535,11 @@
  	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"),
@@ -547,13 +553,26 @@
 	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"),
@@ -671,6 +690,8 @@
 	      case PCI_CLASS_SERIAL_USB:		return "USB Controller";
 	      case PCI_CLASS_SERIAL_FIBER:		return "Fiber Channel";
 
+	      case PCI_CLASS_HOT_SWAP_CONTROLLER:	return "Hot Swap Controller";
+
 	      default:					return "Unknown class";
 	}
 }
@@ -710,6 +731,7 @@
 	      case PCI_VENDOR_ID_OAK: 		return "OAK";
 	      case PCI_VENDOR_ID_WINBOND2:	return "Winbond";
 	      case PCI_VENDOR_ID_MOTOROLA:	return "Motorola";
+	      case PCI_VENDOR_ID_MOTOROLA_OOPS:	return "Motorola";
 	      case PCI_VENDOR_ID_PROMISE:	return "Promise Technology";
 	      case PCI_VENDOR_ID_N9:		return "Number Nine";
 	      case PCI_VENDOR_ID_UMC:		return "UMC";
diff -u --recursive --new-file v2.2.9/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in
--- v2.2.9/linux/drivers/sbus/char/Config.in	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/Config.in	Wed Jun  2 09:55:38 1999
@@ -11,4 +11,5 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Bidirectional parallel port support (EXPERIMENTAL)' CONFIG_SUN_BPP
   tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX
+  tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA
 fi
diff -u --recursive --new-file v2.2.9/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile
--- v2.2.9/linux/drivers/sbus/char/Makefile	Thu Nov 19 09:56:28 1998
+++ linux/drivers/sbus/char/Makefile	Wed Jun  2 09:55:38 1999
@@ -87,6 +87,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SUN_AURORA),y)
+O_OBJS += aurora.o
+else
+  ifeq ($(CONFIG_SUN_AURORA),m)
+  M_OBJS += aurora.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 sunkbdmap.o: sunkeymap.c
diff -u --recursive --new-file v2.2.9/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- v2.2.9/linux/drivers/sbus/char/aurora.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/aurora.c	Wed Jun  9 14:43:53 1999
@@ -0,0 +1,2370 @@
+/*
+ *	linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
+ *
+ *	Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
+ *
+ *	This code is based on the RISCom/8 multiport serial driver written
+ *	by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial
+ *	driver, written by Linus Torvalds, Theodore T'so and others.
+ *	The Aurora multiport programming info was obtained mainly from the
+ *	Cirrus Logic CD180 documentation (available on the web), and by
+ *	doing heavy tests on the board. Many thanks to Eddie C. Dost for the
+ *	help on the sbus interface.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *	Revision 1.0
+ *
+ *	This is the first public release.
+ *
+ *	Most of the information you need is in the aurora.h file. Please
+ *	read that file before reading this one.
+ *
+ *	Several parts of the code do not have comments yet.
+ */
+
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#ifdef AURORA_INT_DEBUG
+#include <linux/timer.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tqueue.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/kdebug.h>
+#include <asm/sbus.h>
+#include <asm/uaccess.h>
+
+#include "aurora.h"
+#include "cd180.h"
+
+unsigned char irqs[4] = {
+	0, 0, 0, 0
+	};
+
+#ifdef AURORA_INT_DEBUG
+int irqhit=0;
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define AURORA_TYPE_NORMAL	1
+
+static struct tty_driver aurora_driver;
+static struct Aurora_board aurora_board[AURORA_NBOARD] = {
+	{0,},
+};
+
+static struct Aurora_port aurora_port[AURORA_TNPORTS] =  {
+	{ 0, },
+};
+
+/* no longer used. static struct Aurora_board * IRQ_to_board[16] = { NULL, } ;*/
+static unsigned char * tmp_buf = NULL;
+static struct semaphore tmp_buf_sem = MUTEX;
+static int    aurora_refcount = 0;
+static struct tty_struct * aurora_table[AURORA_TNPORTS] = { NULL, };
+static struct termios * aurora_termios[AURORA_TNPORTS] = { NULL, };
+static struct termios * aurora_termios_locked[AURORA_TNPORTS] = { NULL, };
+
+DECLARE_TASK_QUEUE(tq_aurora);
+
+/* Yes, the board can support 115.2 bit rates, but only on a few ports. The
+ * total badwidth of one chip (ports 0-7 or 8-15) is equal to OSC_FREQ div
+ * 16. In case of my board, each chip can take 6 channels of 115.2 kbaud.
+ * This information is not well-tested.
+ */
+static unsigned long baud_table[] =  {
+        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+        9600, 19200, 38400, 57600, 115200, 0,
+        };
+
+static inline int aurora_paranoia_check(struct Aurora_port const * port,
+				    kdev_t device, const char *routine)
+{
+#ifdef AURORA_PARANOIA_CHECK
+	static const char *badmagic =
+		KERN_DEBUG "aurora: Warning: bad aurora port magic number for device %s in %s\n";
+	static const char *badinfo =
+		KERN_DEBUG "aurora: Warning: null aurora port for device %s in %s\n";
+
+	if (!port) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (port->magic != AURORA_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * 
+ *  Service functions for aurora driver.
+ * 
+ */
+
+/* Get board number from pointer */
+extern inline int board_No (struct Aurora_board const * bp)
+{
+	return bp - aurora_board;
+}
+
+/* Get port number from pointer */
+extern inline int port_No (struct Aurora_port const * port)
+{
+	return AURORA_PORT(port - aurora_port); 
+}
+
+/* Get pointer to board from pointer to port */
+extern inline struct Aurora_board * port_Board(struct Aurora_port const * port)
+{
+	return &aurora_board[AURORA_BOARD(port - aurora_port)];
+}
+
+/* Wait for Channel Command Register ready */
+extern inline void aurora_wait_CCR(struct aurora_reg128 * r)
+{
+	unsigned long delay;
+
+#ifdef AURORA_DEBUG
+printk("aurora_wait_CCR\n");
+#endif
+	/* FIXME: need something more descriptive than 100000 :) */
+	for (delay = 100000; delay; delay--) 
+		if (!r->r[CD180_CCR])
+			return;
+	printk(KERN_DEBUG "aurora: Timeout waiting for CCR.\n");
+}
+
+/*
+ *  aurora probe functions.
+ */
+
+/* Must be called with enabled interrupts */
+extern inline void aurora_long_delay(unsigned long delay)
+{
+	unsigned long i;
+#ifdef AURORA_DEBUG
+printk("aurora_long_delay: start\n");
+#endif
+	for (i = jiffies + delay; i > jiffies; ) ;
+#ifdef AURORA_DEBUG
+printk("aurora_long_delay: end\n");
+#endif
+}
+
+/* Reset and setup CD180 chip */
+static int aurora_init_CD180(struct Aurora_board * bp, int chip)
+{
+	unsigned long flags;
+	int id;
+	
+#ifdef AURORA_DEBUG
+printk("aurora_init_CD180: start %d:%d\n",board_No(bp),chip);
+#endif
+	save_flags(flags); cli();
+	bp->r[chip]->r[CD180_CAR]=0;
+	bp->r[chip]->r[CD180_GSVR]=0;
+	aurora_wait_CCR(bp->r[chip]);			/* Wait for CCR ready        */
+	bp->r[chip]->r[CD180_CCR]=CCR_HARDRESET;      /* Reset CD180 chip          */
+	udelay(1);
+	sti();
+	id=1000;
+	while((--id)&&(bp->r[chip]->r[CD180_GSVR]!=0xff))udelay(100);
+	if(!id) {
+		printk(KERN_ERR "aurora%d: Chip %d failed init.\n",board_No(bp),chip);
+		restore_flags(flags);
+		return(-1);
+		}
+	cli();
+	bp->r[chip]->r[CD180_GSVR]=(board_No(bp)<<5)|((chip+1)<<3); /* Set ID for this chip      */
+	bp->r[chip]->r[CD180_MSMR]=0x80|bp->ACK_MINT;      /* Prio for modem intr       */
+	bp->r[chip]->r[CD180_TSMR]=0x80|bp->ACK_TINT;      /* Prio for transmitter intr */
+	bp->r[chip]->r[CD180_RSMR]=0x80|bp->ACK_RINT;      /* Prio for receiver intr    */
+	/* Setting up prescaler. We need 4 tick per 1 ms */
+	bp->r[chip]->r[CD180_PPRH]=(bp->oscfreq/(1000000/AURORA_TPS)) >> 8;
+	bp->r[chip]->r[CD180_PPRL]=(bp->oscfreq/(1000000/AURORA_TPS)) & 0xff;
+
+	bp->r[chip]->r[CD180_SRCR]=SRCR_AUTOPRI|SRCR_GLOBPRI;
+
+	id=bp->r[chip]->r[CD180_GFRCR];
+	printk(KERN_INFO "aurora%d: Chip %d id %02x: ",board_No(bp),chip,id);
+	if(bp->r[chip]->r[CD180_SRCR]&128)
+		switch(id){
+			case 0x82:printk("CL-CD1864 rev A\n");break;
+			case 0x83:printk("CL-CD1865 rev A\n");break;
+			case 0x84:printk("CL-CD1865 rev B\n");break;
+			case 0x85:printk("CL-CD1865 rev C\n");break;
+			default:printk("Unknown.\n");
+		}else
+		switch(id){
+			case 0x81:printk("CL-CD180 rev B\n");break;
+			case 0x82:printk("CL-CD180 rev C\n");break;
+			default:printk("Unknown.\n");
+		};
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_init_CD180: end\n");
+#endif
+	return 0;
+}
+
+static int valid_irq(unsigned char irq)
+{
+int i;
+for(i=0;i<TYPE_1_IRQS;i++)
+	if (type_1_irq[i]==irq) return 1;
+return 0;
+}
+
+static void aurora_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+
+/* Main probing routine, also sets irq. */
+static int aurora_probe(void) {
+	struct linux_sbus *sbus;
+	struct linux_sbus_device *sdev;
+	int grrr;
+	char buf[30];
+	int bn=0;
+	struct Aurora_board *bp;
+
+	for_each_sbus(sbus) {
+		for_each_sbusdev(sdev, sbus) {
+/*			printk("Try: %x %s\n",sdev,sdev->prom_name);*/
+			if (!strcmp(sdev->prom_name, "sio16")) {
+				#ifdef AURORA_DEBUG
+				printk(KERN_INFO "aurora: sio16 at %p\n",sdev);
+				#endif
+				prom_apply_sbus_ranges(sdev->my_bus, sdev->reg_addrs, sdev->num_registers, sdev);
+				if((sdev->reg_addrs[0].reg_size!=1)&&(sdev->reg_addrs[1].reg_size!=128)&&
+				   (sdev->reg_addrs[2].reg_size!=128)&&(sdev->reg_addrs[3].reg_size!=4)){
+				   	printk(KERN_ERR "aurora%d: registers' sizes do not match.\n",bn);
+				   	break;
+				   	}
+				bp=&aurora_board[bn];
+				bp->r0 = (struct aurora_reg1 *) sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
+					sdev->reg_addrs[0].reg_size, "sio16",sdev->reg_addrs[0].which_io, 0x0);
+				if (!bp->r0) {
+					printk(KERN_ERR "aurora%d: can't map reg_addrs[0]\n",bn);
+					break;
+				}
+				#ifdef AURORA_DEBUG
+				printk("Map reg 0: %x\n",bp->r0);
+				#endif
+				bp->r[0] = (struct aurora_reg128 *) sparc_alloc_io(sdev->reg_addrs[1].phys_addr, 0,
+					sdev->reg_addrs[1].reg_size, "sio16", sdev->reg_addrs[1].which_io, 0x0);
+				if (!bp->r[0]) {
+					printk(KERN_ERR "aurora%d: can't map reg_addrs[1]\n",bn);
+					break;
+				}
+				#ifdef AURORA_DEBUG
+				printk("Map reg 1: %x\n",bp->r[0]);
+				#endif
+				bp->r[1] = (struct aurora_reg128 *) sparc_alloc_io(sdev->reg_addrs[2].phys_addr, 0,
+					sdev->reg_addrs[2].reg_size, "sio16", sdev->reg_addrs[2].which_io, 0x0);
+				if (!bp->r[1]) {
+					printk(KERN_ERR "aurora%d: can't map reg_addrs[2]\n",bn);
+					break;
+				}
+				#ifdef AURORA_DEBUG
+				printk("Map reg 2: %x\n",bp->r[1]);
+				#endif
+				bp->r3 = (struct aurora_reg4 *) sparc_alloc_io(sdev->reg_addrs[3].phys_addr, 0,
+					sdev->reg_addrs[3].reg_size, "sio16", sdev->reg_addrs[3].which_io, 0x0);
+				if (!bp->r3) {
+					printk(KERN_ERR "aurora%d: can't map reg_addrs[3]\n",bn);
+					break;
+				}
+				#ifdef AURORA_DEBUG
+				printk("Map reg 3: %x\n",bp->r3);
+				#endif
+				/* Variables setup */
+				bp->flags = 0;
+				#ifdef AURORA_DEBUG
+				grrr=prom_getint(sdev->prom_node,"intr");
+				printk("intr pri %d\n",grrr);
+				#endif
+				if ((bp->irq=irqs[bn]) && valid_irq(bp->irq) &&
+				    !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {
+					free_irq(bp->irq|0x30, bp);
+				} else
+				if ((bp->irq=prom_getint(sdev->prom_node, "bintr")) && valid_irq(bp->irq) &&
+				    !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {
+					free_irq(bp->irq|0x30, bp);
+				} else
+				if ((bp->irq=prom_getint(sdev->prom_node, "intr")) && valid_irq(bp->irq) &&
+				    !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {
+					free_irq(bp->irq|0x30, bp);
+				} else
+				for(grrr=0;grrr<TYPE_1_IRQS;grrr++) {
+					if ((bp->irq=type_1_irq[grrr])&&!request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {
+						free_irq(bp->irq|0x30, bp);
+						break;
+					} else {
+					printk(KERN_ERR "aurora%d: Could not get an irq for this board !!!\n",bn);
+					bp->flags=0xff;
+					}
+				}
+				if(bp->flags==0xff)break;
+				printk(KERN_INFO "aurora%d: irq %d\n",bn,bp->irq&0x0f);
+				buf[0]=0;
+				grrr=prom_getproperty(sdev->prom_node,"dtr_rts",buf,sizeof(buf));
+				if(!strcmp(buf,"swapped")){
+					printk(KERN_INFO "aurora%d: Swapped DTR and RTS\n",bn);
+					bp->DTR=MSVR_RTS;
+					bp->RTS=MSVR_DTR;
+					bp->MSVDTR=CD180_MSVRTS;
+					bp->MSVRTS=CD180_MSVDTR;
+					bp->flags|=AURORA_BOARD_DTR_FLOW_OK;
+					}else{
+					#ifdef AURORA_FORCE_DTR_FLOW
+					printk(KERN_INFO "aurora%d: Forcing swapped DTR-RTS\n",bn);
+					bp->DTR=MSVR_RTS;
+					bp->RTS=MSVR_DTR;
+					bp->MSVDTR=CD180_MSVRTS;
+					bp->MSVRTS=CD180_MSVDTR;
+					bp->flags|=AURORA_BOARD_DTR_FLOW_OK;
+					#else
+					printk(KERN_INFO "aurora%d: Normal DTR and RTS\n",bn);
+					bp->DTR=MSVR_DTR;
+					bp->RTS=MSVR_RTS;
+					bp->MSVDTR=CD180_MSVDTR;
+					bp->MSVRTS=CD180_MSVRTS;
+					#endif
+				}
+				bp->oscfreq=prom_getint(sdev->prom_node,"clk")*100;
+				printk(KERN_INFO "aurora%d: Oscillator: %d Hz\n",bn,bp->oscfreq);
+				grrr=prom_getproperty(sdev->prom_node,"chip",buf,sizeof(buf));
+				printk(KERN_INFO "aurora%d: Chips: %s\n",bn,buf);
+				grrr=prom_getproperty(sdev->prom_node,"manu",buf,sizeof(buf));
+				printk(KERN_INFO "aurora%d: Manufacturer: %s\n",bn,buf);
+				grrr=prom_getproperty(sdev->prom_node,"model",buf,sizeof(buf));
+				printk(KERN_INFO "aurora%d: Model: %s\n",bn,buf);
+				grrr=prom_getproperty(sdev->prom_node,"rev",buf,sizeof(buf));
+				printk(KERN_INFO "aurora%d: Revision: %s\n",bn,buf);
+				grrr=prom_getproperty(sdev->prom_node,"mode",buf,sizeof(buf));
+				printk(KERN_INFO "aurora%d: Mode: %s\n",bn,buf);
+				#ifdef MODULE
+				bp->count=0;
+				#endif
+				bp->flags = AURORA_BOARD_PRESENT;
+				/* hardware ack */
+				bp->ACK_MINT=1;
+				bp->ACK_TINT=2;
+				bp->ACK_RINT=3;
+				bn++;
+			}
+		}
+	}
+	return bn;
+}
+
+static void aurora_release_io_range(struct Aurora_board *bp)
+{
+sparc_free_io(bp->r0,1);
+sparc_free_io(bp->r[0],128);
+sparc_free_io(bp->r[1],128);
+sparc_free_io(bp->r3,4);
+}
+
+extern inline void aurora_mark_event(struct Aurora_port * port, int event)
+{
+#ifdef AURORA_DEBUG
+printk("aurora_mark_event: start\n");
+#endif
+	set_bit(event, &port->event);
+	queue_task(&port->tqueue, &tq_aurora);
+	mark_bh(AURORA_BH);
+#ifdef AURORA_DEBUG
+printk("aurora_mark_event: end\n");
+#endif
+}
+
+extern inline struct Aurora_port * aurora_get_port(struct Aurora_board const * bp,
+					int chip, unsigned char const * what)
+{
+	unsigned char channel;
+	struct Aurora_port * port;
+
+	channel = (chip<<3)|((bp->r[chip]->r[CD180_GSCR]&GSCR_CHAN)>>GSCR_CHAN_OFF);
+	port = &aurora_port[board_No(bp) * AURORA_NPORT * AURORA_NCD180 + channel];
+	if (port->flags & ASYNC_INITIALIZED)  {
+		return port;
+	}
+	printk(KERN_DEBUG "aurora%d: %s interrupt from invalid port %d\n",
+	       board_No(bp), what, channel);
+	return NULL;
+}
+
+extern inline void aurora_receive_exc(struct Aurora_board const * bp, int chip)
+{
+	struct Aurora_port *port;
+	struct tty_struct *tty;
+	unsigned char status;
+	unsigned char ch;
+	
+	if (!(port = aurora_get_port(bp, chip, "Receive_x")))
+		return;
+
+	tty = port->tty;
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
+	#ifdef AURORA_INTNORM
+		printk("aurora%d: port %d: Working around flip buffer overflow.\n",
+		       board_No(bp), port_No(port));
+	#endif
+		return;
+	}
+	
+#ifdef AURORA_REPORT_OVERRUN	
+	status = bp->r[chip]->r[CD180_RCSR];
+	if (status & RCSR_OE)  {
+		port->overrun++;
+#if 1
+		printk("aurora%d: port %d: Overrun. Total %ld overruns.\n",
+		       board_No(bp), port_No(port), port->overrun);
+#endif		
+	}
+	status &= port->mark_mask;
+#else	
+	status = bp->r[chip]->r[CD180_RCSR] & port->mark_mask;
+#endif	
+	ch = bp->r[chip]->r[CD180_RDR];
+	if (!status)  {
+		return;
+	}
+	if (status & RCSR_TOUT)  {
+/*		printk("aurora%d: port %d: Receiver timeout. Hardware problems ?\n",
+		       board_No(bp), port_No(port));*/
+		return;
+		
+	} else if (status & RCSR_BREAK)  {
+		printk(KERN_DEBUG "aurora%d: port %d: Handling break...\n",
+		       board_No(bp), port_No(port));
+		*tty->flip.flag_buf_ptr++ = TTY_BREAK;
+		if (port->flags & ASYNC_SAK)
+			do_SAK(tty);
+		
+	} else if (status & RCSR_PE) 
+		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+	
+	else if (status & RCSR_FE) 
+		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+	
+        else if (status & RCSR_OE)
+		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+	
+	else
+		*tty->flip.flag_buf_ptr++ = 0;
+	
+	*tty->flip.char_buf_ptr++ = ch;
+	tty->flip.count++;
+	queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+extern inline void aurora_receive(struct Aurora_board const * bp, int chip)
+{
+	struct Aurora_port *port;
+	struct tty_struct *tty;
+	unsigned char count,cnt;
+
+	if (!(port = aurora_get_port(bp, chip, "Receive")))
+		return;
+	
+	tty = port->tty;
+	
+	count = bp->r[chip]->r[CD180_RDCR];
+
+#ifdef AURORA_REPORT_FIFO
+	port->hits[count > 8 ? 9 : count]++;
+#endif
+
+	while (count--)  {
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
+		#ifdef AURORA_INTNORM
+			printk("aurora%d: port %d: Working around flip buffer overflow.\n",
+			       board_No(bp), port_No(port));
+		#endif
+			break;
+		}
+		cnt=bp->r[chip]->r[CD180_RDR];
+		*tty->flip.char_buf_ptr++ = cnt;
+		*tty->flip.flag_buf_ptr++ = 0;
+		tty->flip.count++;
+	}
+	queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+extern inline void aurora_transmit(struct Aurora_board const * bp, int chip)
+{
+	struct Aurora_port *port;
+	struct tty_struct *tty;
+	unsigned char count;
+	
+	
+	if (!(port = aurora_get_port(bp, chip, "Transmit")))
+		return;
+		
+	tty = port->tty;
+	
+	if (port->SRER & SRER_TXEMPTY)  {
+		/* FIFO drained */
+		bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+		udelay(1);
+		port->SRER &= ~SRER_TXEMPTY;
+		bp->r[chip]->r[CD180_SRER]=port->SRER;
+		return;
+	}
+	
+	if ((port->xmit_cnt <= 0 && !port->break_length)
+	    || tty->stopped || tty->hw_stopped)  {
+		bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+		udelay(1);
+		port->SRER &= ~SRER_TXRDY;
+		bp->r[chip]->r[CD180_SRER]=port->SRER;
+		return;
+	}
+	
+	if (port->break_length)  {
+		if (port->break_length > 0)  {
+			if (port->COR2 & COR2_ETC)  {
+				bp->r[chip]->r[CD180_TDR]=CD180_C_ESC;
+				bp->r[chip]->r[CD180_TDR]=CD180_C_SBRK;
+				port->COR2 &= ~COR2_ETC;
+			}
+			count = MIN(port->break_length, 0xff);
+			bp->r[chip]->r[CD180_TDR]=CD180_C_ESC;
+			bp->r[chip]->r[CD180_TDR]=CD180_C_DELAY;
+			bp->r[chip]->r[CD180_TDR]=count;
+			if (!(port->break_length -= count))
+				port->break_length--;
+		} else  {
+			bp->r[chip]->r[CD180_TDR]=CD180_C_ESC;
+			bp->r[chip]->r[CD180_TDR]=CD180_C_EBRK;
+			bp->r[chip]->r[CD180_COR2]=port->COR2;
+			aurora_wait_CCR(bp->r[chip]);
+			bp->r[chip]->r[CD180_CCR]=CCR_CORCHG2;
+			port->break_length = 0;
+		}
+		return;
+	}
+	
+	count = CD180_NFIFO;
+	do {
+		bp->r[chip]->r[CD180_TDR]=port->xmit_buf[port->xmit_tail++];
+		port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		if (--port->xmit_cnt <= 0)
+			break;
+	} while (--count > 0);
+	
+	if (port->xmit_cnt <= 0)  {
+		bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+		udelay(1);
+		port->SRER &= ~SRER_TXRDY;
+		bp->r[chip]->r[CD180_SRER]=port->SRER;
+	}
+	if (port->xmit_cnt <= port->wakeup_chars)
+		aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+}
+
+extern inline void aurora_check_modem(struct Aurora_board const * bp, int chip)
+{
+	struct Aurora_port *port;
+	struct tty_struct *tty;
+	unsigned char mcr;
+	
+	if (!(port = aurora_get_port(bp, chip, "Modem")))
+		return;
+		
+	tty = port->tty;
+	
+	mcr = bp->r[chip]->r[CD180_MCR];
+	if (mcr & MCR_CDCHG)  {
+		if (bp->r[chip]->r[CD180_MSVR] & MSVR_CD) 
+			wake_up_interruptible(&port->open_wait);
+		else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (port->flags & ASYNC_CALLOUT_NOHUP)))
+			queue_task(&port->tqueue_hangup,  
+					   &tq_scheduler);      
+	}
+	
+/* We don't have such things yet. My aurora board has DTR and RTS swapped, but that doesn't count in this driver. Let's hope
+ * Aurora didn't made any boards with CTS or DSR broken...
+ */
+/* #ifdef AURORA_BRAIN_DAMAGED_CTS
+	if (mcr & MCR_CTSCHG)  {
+		if (aurora_in(bp, CD180_MSVR) & MSVR_CTS)  {
+			tty->hw_stopped = 0;
+			port->SRER |= SRER_TXRDY;
+			if (port->xmit_cnt <= port->wakeup_chars)
+				aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+		} else  {
+			tty->hw_stopped = 1;
+			port->SRER &= ~SRER_TXRDY;
+		}
+		bp->r[chip]->r[CD180_SRER, port->SRER);
+	}
+	if (mcr & MCR_DSRCHG)  {
+		if (aurora_in(bp, CD180_MSVR) & MSVR_DSR)  {
+			tty->hw_stopped = 0;
+			port->SRER |= SRER_TXRDY;
+			if (port->xmit_cnt <= port->wakeup_chars)
+				aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+		} else  {
+			tty->hw_stopped = 1;
+			port->SRER &= ~SRER_TXRDY;
+		}
+		bp->r[chip]->r[CD180_SRER, port->SRER);
+	}
+#endif AURORA_BRAIN_DAMAGED_CTS */
+	
+	/* Clear change bits */
+	bp->r[chip]->r[CD180_MCR]=0;
+}
+
+/* The main interrupt processing routine */
+static void aurora_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+{
+	unsigned char status;
+	unsigned char ack,chip/*,chip_id*/;
+	struct Aurora_board * bp = (struct Aurora_board *) dev_id;
+	unsigned long loop=0;
+
+	#ifdef AURORA_INT_DEBUG
+	printk("IRQ%d %d\n",irq,++irqhit);
+	#ifdef AURORA_FLOODPRO
+	if (irqhit>=AURORA_FLOODPRO)
+		bp->r0->r=8;
+	#endif
+	#endif
+	
+/* old	bp = IRQ_to_board[irq&0x0f];*/
+	
+	if (!bp || !(bp->flags & AURORA_BOARD_ACTIVE))  {
+		return;
+	}
+
+/*	The while() below takes care of this.
+	status=bp->r[0]->r[CD180_SRSR];
+	#ifdef AURORA_INT_DEBUG
+	printk("mumu: %02x\n",status);
+	#endif
+	if (!(status&SRSR_ANYINT)) return; * Nobody has anything to say, so exit *
+*/
+	while ((loop++ < 48)&&(status=bp->r[0]->r[CD180_SRSR]&SRSR_ANYINT)){
+		#ifdef AURORA_INT_DEBUG
+		printk("SRSR: %02x\n",status);
+		#endif
+		if (status&SRSR_REXT) {
+			ack=bp->r3->r[bp->ACK_RINT];
+			#ifdef AURORA_INT_DEBUG
+			printk("R-ACK %02x\n",ack);
+			#endif
+			if ((ack>>5)==board_No(bp)) {
+				if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
+					if ((ack&GSVR_ITMASK)==GSVR_IT_RGD) {
+						aurora_receive(bp,chip);
+						bp->r[chip]->r[CD180_EOSRR]=0;
+					} else
+					if ((ack&GSVR_ITMASK)==GSVR_IT_REXC) {
+						aurora_receive_exc(bp,chip);
+						bp->r[chip]->r[CD180_EOSRR]=0;
+					}
+				}
+			}
+		} else
+		if (status&SRSR_TEXT) {
+			ack=bp->r3->r[bp->ACK_TINT];
+			#ifdef AURORA_INT_DEBUG
+			printk("T-ACK %02x\n",ack);
+			#endif
+			if ((ack>>5)==board_No(bp)) {
+				if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
+					if ((ack&GSVR_ITMASK)==GSVR_IT_TX) {
+						aurora_transmit(bp,chip);
+						bp->r[chip]->r[CD180_EOSRR]=0;
+					}
+				}
+			}
+		} else
+		if (status&SRSR_MEXT) {
+			ack=bp->r3->r[bp->ACK_MINT];
+			#ifdef AURORA_INT_DEBUG
+			printk("M-ACK %02x\n",ack);
+			#endif
+			if ((ack>>5)==board_No(bp)) {
+				if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
+					if ((ack&GSVR_ITMASK)==GSVR_IT_MDM) {
+						aurora_check_modem(bp,chip);
+						bp->r[chip]->r[CD180_EOSRR]=0;
+					}
+				}
+			}
+		}
+	}
+/* I guess this faster code can be used with CD1865, using AUROPRI and GLOBPRI.
+	while ((loop++ < 48)&&(status=bp->r[0]->r[CD180_SRSR]&SRSR_ANYINT)){
+		#ifdef AURORA_INT_DEBUG
+		printk("SRSR: %02x\n",status);
+		#endif
+		ack=bp->r3->r[0];
+		#ifdef AURORA_INT_DEBUG
+		printk("ACK: %02x\n",ack);
+		#endif
+		if ((ack>>5)==board_No(bp)) {
+			if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
+				ack&=GSVR_ITMASK;
+				if (ack==GSVR_IT_RGD) {
+					aurora_receive(bp,chip);
+					bp->r[chip]->r[CD180_EOSRR]=0;
+				} else
+				if (ack==GSVR_IT_REXC) {
+					aurora_receive_exc(bp,chip);
+					bp->r[chip]->r[CD180_EOSRR]=0;
+				} else
+				if (ack==GSVR_IT_TX) {
+					aurora_transmit(bp,chip);
+					bp->r[chip]->r[CD180_EOSRR]=0;
+				} else
+				if (ack==GSVR_IT_MDM) {
+					aurora_check_modem(bp,chip);
+					bp->r[chip]->r[CD180_EOSRR]=0;
+				}
+			}
+		}
+	}
+*/
+/* This is the old handling routine, used in riscom8 for only one CD180. I keep it here for reference.
+for(chip=0;chip<AURORA_NCD180;chip++){
+	chip_id=(board_No(bp)<<5)|((chip+1)<<3);
+	loop=0;
+	while ((loop++ < 1) && ((status = bp->r[chip]->r[CD180_SRSR]) &
+			 (SRSR_TEXT | SRSR_MEXT | SRSR_REXT))) {
+
+		if (status & SRSR_REXT) {
+			ack = bp->r3->r[bp->ACK_RINT];
+			if (ack == (chip_id | GSVR_IT_RGD)){
+				#ifdef AURORA_INTMSG
+				printk("RX ACK\n");
+				#endif
+				aurora_receive(bp,chip);
+				}
+			else if (ack == (chip_id | GSVR_IT_REXC)){
+				#ifdef AURORA_INTMSG
+				printk("RXC ACK\n");
+				#endif
+				aurora_receive_exc(bp,chip);
+				}
+			else
+				#ifdef AURORA_INTNORM
+				printk("aurora%d-%d: Bad receive ack 0x%02x.\n",
+				       board_No(bp), chip, ack)
+				#endif
+				;
+
+		} else if (status & SRSR_TEXT) {
+			ack = bp->r3->r[bp->ACK_TINT];
+			if (ack == (chip_id | GSVR_IT_TX)){
+				#ifdef AURORA_INTMSG
+				printk("TX ACK\n");
+				#endif
+				aurora_transmit(bp,chip);
+				}
+			else{
+				#ifdef AURORA_INTNORM
+				printk("aurora%d-%d: Bad transmit ack 0x%02x.\n",
+				       board_No(bp), chip, ack);
+				#endif
+				       }
+
+		} else  if (status & SRSR_MEXT)  {
+			ack = bp->r3->r[bp->ACK_MINT];
+			if (ack == (chip_id | GSVR_IT_MDM)){
+				#ifdef AURORA_INTMSG
+				printk("MDM ACK\n");
+				#endif
+				aurora_check_modem(bp,chip);
+				}
+			else
+				#ifdef AURORA_INTNORM
+				printk("aurora%d-%d: Bad modem ack 0x%02x.\n",
+				       board_No(bp), chip, ack)
+				#endif
+				;
+		
+		}
+		bp->r[chip]->r[CD180_EOSRR]=0;
+	}
+    }
+*/
+}
+
+
+#ifdef AURORA_INT_DEBUG
+static void aurora_timer (unsigned long ignored);
+
+static struct timer_list
+aurora_poll_timer = { NULL, NULL, 0, 0, aurora_timer };
+
+static void
+aurora_timer (unsigned long ignored)
+{
+	unsigned long flags;
+	int i;
+
+	save_flags(flags); cli();
+
+printk("SRSR: %02x,%02x - ",aurora_board[0].r[0]->r[CD180_SRSR],aurora_board[0].r[1]->r[CD180_SRSR]);
+for(i=0;i<4;i++){
+	udelay(1);
+	printk("%02x ",aurora_board[0].r3->r[i]);
+	}
+printk("\n");
+
+	aurora_poll_timer.expires = jiffies + 300;
+	add_timer (&aurora_poll_timer);
+
+	restore_flags(flags);
+}
+#endif
+
+/*
+ *  Routines for open & close processing.
+ */
+
+/* Called with disabled interrupts */
+extern inline int aurora_setup_board(struct Aurora_board * bp)
+{
+	int error;
+	
+#ifdef AURORA_ALLIRQ
+	int i;
+	for(i=0;i<AURORA_ALLIRQ;i++){
+		error = request_irq(allirq[i]|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp);
+		if (error){
+			printk(KERN_ERR "IRQ%d request error %d\n",allirq[i],error);
+		}
+	}
+#else
+	error = request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp);
+	if (error){
+		printk(KERN_ERR "IRQ request error %d\n",error);
+		return error;
+	}
+#endif
+	/* Board reset */
+	bp->r0->r=0;
+	udelay(1);
+	if(bp->flags&AURORA_BOARD_TYPE_2){
+		/* unknown yet */
+	} else {
+		bp->r0->r=AURORA_CFG_ENABLE_IO|AURORA_CFG_ENABLE_IRQ|(((bp->irq)&0x0f)>>2);
+	}
+	udelay(10000);
+
+	if (aurora_init_CD180(bp,0))error=1;error=0;
+	if (aurora_init_CD180(bp,1))error++;
+	if (error==AURORA_NCD180) {
+		printk(KERN_ERR "Both chips failed initialisation.\n");
+		return -EIO;
+		}
+
+#ifdef AURORA_INT_DEBUG
+	aurora_poll_timer.expires=jiffies+1;
+	add_timer(&aurora_poll_timer);
+#endif
+#ifdef AURORA_DEBUG
+printk("aurora_setup_board: end\n");
+#endif
+	return 0;
+}
+
+/* Called with disabled interrupts */
+extern inline void aurora_shutdown_board(struct Aurora_board *bp)
+{
+	int i;
+
+#ifdef AURORA_DEBUG
+printk("aurora_shutdown_board: start\n");
+#endif
+
+#ifdef AURORA_INT_DEBUG
+	del_timer(&aurora_poll_timer);
+#endif
+
+#ifdef AURORA_ALLIRQ
+for(i=0;i<AURORA_ALLIRQ;i++){
+	free_irq(allirq[i]|0x30, bp);
+/*	IRQ_to_board[allirq[i]&0xf] = NULL;*/
+	}
+#else
+	free_irq(bp->irq|0x30, bp);
+/*	IRQ_to_board[bp->irq&0xf] = NULL;*/
+#endif	
+	/* Drop all DTR's */
+	for(i=0;i<16;i++){
+		bp->r[i>>3]->r[CD180_CAR]=i&7;
+		udelay(1);
+		bp->r[i>>3]->r[CD180_MSVR]=0;
+		udelay(1);
+		}
+	/* Board shutdown */
+	bp->r0->r=0;
+
+#ifdef AURORA_DEBUG
+printk("aurora_shutdown_board: end\n");
+#endif
+}
+
+/*
+ * Setting up port characteristics. 
+ * Must be called with disabled interrupts
+ */
+static void aurora_change_speed(struct Aurora_board *bp, struct Aurora_port *port)
+{
+	struct tty_struct *tty;
+	unsigned long baud;
+	long tmp;
+	unsigned char cor1 = 0, cor3 = 0;
+	unsigned char mcor1 = 0, mcor2 = 0,chip;
+	
+#ifdef AURORA_DEBUG
+printk("aurora_change_speed: start\n");
+#endif
+	if (!(tty = port->tty) || !tty->termios)
+		return;
+		
+	chip=AURORA_CD180(port_No(port));
+
+	port->SRER  = 0;
+	port->COR2 = 0;
+	port->MSVR = MSVR_RTS|MSVR_DTR;
+	
+	baud = C_BAUD(tty);
+	
+	if (baud & CBAUDEX) {
+		baud &= ~CBAUDEX;
+		if (baud < 1 || baud > 2) 
+			port->tty->termios->c_cflag &= ~CBAUDEX;
+		else
+			baud += 15;
+	}
+	if (baud == 15)  {
+		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			baud ++;
+		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			baud += 2;
+	}
+	
+	/* Select port on the board */
+	bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	
+	if (!baud_table[baud])  {
+		/* Drop DTR & exit */
+		port->MSVR &= ~(bp->DTR|bp->RTS);
+		bp->r[chip]->r[CD180_MSVR]=port->MSVR;
+		return;
+	} else  {
+		/* Set DTR on */
+		port->MSVR |= bp->DTR;
+		bp->r[chip]->r[CD180_MSVR]=port->MSVR;
+	}
+	
+	/*
+	 * Now we must calculate some speed depended things 
+	 */
+	
+	/* Set baud rate for port */
+	tmp = (((bp->oscfreq + baud_table[baud]/2) / baud_table[baud] +
+		CD180_TPC/2) / CD180_TPC);
+
+/*	tmp = (bp->oscfreq/7)/baud_table[baud];
+	if((tmp%10)>4)tmp=tmp/10+1;else tmp=tmp/10;*/
+/*	printk("Prescaler period: %d\n",tmp);*/
+
+	bp->r[chip]->r[CD180_RBPRH]=(tmp >> 8) & 0xff;
+	bp->r[chip]->r[CD180_TBPRH]=(tmp >> 8) & 0xff;
+	bp->r[chip]->r[CD180_RBPRL]=tmp & 0xff;
+	bp->r[chip]->r[CD180_TBPRL]=tmp & 0xff;
+	
+	baud = (baud_table[baud] + 5) / 10;   /* Estimated CPS */
+	
+	/* Two timer ticks seems enough to wakeup something like SLIP driver */
+	tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;		
+	port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
+					      SERIAL_XMIT_SIZE - 1 : tmp);
+	
+	/* Receiver timeout will be transmission time for 1.5 chars */
+	tmp = (AURORA_TPS + AURORA_TPS/2 + baud/2) / baud;
+	tmp = (tmp > 0xff) ? 0xff : tmp;
+	bp->r[chip]->r[CD180_RTPR]=tmp;
+	
+	switch (C_CSIZE(tty))  {
+	 case CS5:
+		cor1 |= COR1_5BITS;
+		break;
+	 case CS6:
+		cor1 |= COR1_6BITS;
+		break;
+	 case CS7:
+		cor1 |= COR1_7BITS;
+		break;
+	 case CS8:
+		cor1 |= COR1_8BITS;
+		break;
+	}
+	
+	if (C_CSTOPB(tty)) 
+		cor1 |= COR1_2SB;
+	
+	cor1 |= COR1_IGNORE;
+	if (C_PARENB(tty))  {
+		cor1 |= COR1_NORMPAR;
+		if (C_PARODD(tty)) 
+			cor1 |= COR1_ODDP;
+		if (I_INPCK(tty)) 
+			cor1 &= ~COR1_IGNORE;
+	}
+	/* Set marking of some errors */
+	port->mark_mask = RCSR_OE | RCSR_TOUT;
+	if (I_INPCK(tty)) 
+		port->mark_mask |= RCSR_FE | RCSR_PE;
+	if (I_BRKINT(tty) || I_PARMRK(tty)) 
+		port->mark_mask |= RCSR_BREAK;
+	if (I_IGNPAR(tty)) 
+		port->mark_mask &= ~(RCSR_FE | RCSR_PE);
+	if (I_IGNBRK(tty))  {
+		port->mark_mask &= ~RCSR_BREAK;
+		if (I_IGNPAR(tty)) 
+			/* Real raw mode. Ignore all */
+			port->mark_mask &= ~RCSR_OE;
+	}
+	/* Enable Hardware Flow Control */
+	if (C_CRTSCTS(tty))  {
+/*#ifdef AURORA_BRAIN_DAMAGED_CTS
+		port->SRER |= SRER_DSR | SRER_CTS;
+		mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
+		mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
+		tty->hw_stopped = !(aurora_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
+#else*/
+		port->COR2 |= COR2_CTSAE;
+/*#endif*/
+		if (bp->flags&AURORA_BOARD_DTR_FLOW_OK) {
+			mcor1 |= AURORA_RXTH;
+		}
+	}
+	/* Enable Software Flow Control. FIXME: I'm not sure about this */
+	/* Some people reported that it works, but I still doubt */
+	if (I_IXON(tty))  {
+		port->COR2 |= COR2_TXIBE;
+		cor3 |= (COR3_FCT | COR3_SCDE);
+		if (I_IXANY(tty))
+			port->COR2 |= COR2_IXM;
+		bp->r[chip]->r[CD180_SCHR1]=START_CHAR(tty);
+		bp->r[chip]->r[CD180_SCHR2]=STOP_CHAR(tty);
+		bp->r[chip]->r[CD180_SCHR3]=START_CHAR(tty);
+		bp->r[chip]->r[CD180_SCHR4]=STOP_CHAR(tty);
+	}
+	if (!C_CLOCAL(tty))  {
+		/* Enable CD check */
+		port->SRER |= SRER_CD;
+		mcor1 |= MCOR1_CDZD;
+		mcor2 |= MCOR2_CDOD;
+	}
+	
+	if (C_CREAD(tty)) 
+		/* Enable receiver */
+		port->SRER |= SRER_RXD;
+	
+	/* Set input FIFO size (1-8 bytes) */
+	cor3 |= AURORA_RXFIFO; 
+	/* Setting up CD180 channel registers */
+	bp->r[chip]->r[CD180_COR1]=cor1;
+	bp->r[chip]->r[CD180_COR2]=port->COR2;
+	bp->r[chip]->r[CD180_COR3]=cor3;
+	/* Make CD180 know about registers change */
+	aurora_wait_CCR(bp->r[chip]);
+	bp->r[chip]->r[CD180_CCR]=CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3;
+	/* Setting up modem option registers */
+	bp->r[chip]->r[CD180_MCOR1]=mcor1;
+	bp->r[chip]->r[CD180_MCOR2]=mcor2;
+	/* Enable CD180 transmitter & receiver */
+	aurora_wait_CCR(bp->r[chip]);
+	bp->r[chip]->r[CD180_CCR]=CCR_TXEN | CCR_RXEN;
+	/* Enable interrupts */
+	bp->r[chip]->r[CD180_SRER]=port->SRER;
+	/* And finally set RTS on */
+	bp->r[chip]->r[CD180_MSVR]=port->MSVR;
+#ifdef AURORA_DEBUG
+printk("aurora_change_speed: end\n");
+#endif
+}
+
+/* Must be called with interrupts enabled */
+static int aurora_setup_port(struct Aurora_board *bp, struct Aurora_port *port)
+{
+	unsigned long flags;
+	
+#ifdef AURORA_DEBUG
+printk("aurora_setup_port: start %d\n",port_No(port));
+#endif
+	if (port->flags & ASYNC_INITIALIZED)
+		return 0;
+		
+	if (!port->xmit_buf) {
+		/* We may sleep in get_free_page() */
+		unsigned long tmp;
+		
+		if (!(tmp = get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		    
+		if (port->xmit_buf) {
+			free_page(tmp);
+			return -ERESTARTSYS;
+		}
+		port->xmit_buf = (unsigned char *) tmp;
+	}
+		
+	save_flags(flags); cli();
+		
+	if (port->tty) 
+		clear_bit(TTY_IO_ERROR, &port->tty->flags);
+		
+#ifdef MODULE
+	if (port->count == 1) {
+		MOD_INC_USE_COUNT;
+		if((++bp->count)==1)
+			bp->flags|=AURORA_BOARD_ACTIVE;
+	}
+#endif
+
+	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+	aurora_change_speed(bp, port);
+	port->flags |= ASYNC_INITIALIZED;
+		
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_setup_port: end\n");
+#endif
+	return 0;
+}
+
+/* Must be called with interrupts disabled */
+static void aurora_shutdown_port(struct Aurora_board *bp, struct Aurora_port *port)
+{
+	struct tty_struct *tty;
+	unsigned char chip;
+
+#ifdef AURORA_DEBUG
+printk("aurora_shutdown_port: start\n");
+#endif
+	if (!(port->flags & ASYNC_INITIALIZED)) 
+		return;
+	
+	chip=AURORA_CD180(port_No(port));
+	
+#ifdef AURORA_REPORT_OVERRUN
+	printk("aurora%d: port %d: Total %ld overruns were detected.\n",
+	       board_No(bp), port_No(port), port->overrun);
+#endif	
+#ifdef AURORA_REPORT_FIFO
+	{
+		int i;
+		
+		printk("aurora%d: port %d: FIFO hits [ ",
+		       board_No(bp), port_No(port));
+		for (i = 0; i < 10; i++)  {
+			printk("%ld ", port->hits[i]);
+		}
+		printk("].\n");
+	}
+#endif	
+	if (port->xmit_buf)  {
+		free_page((unsigned long) port->xmit_buf);
+		port->xmit_buf = NULL;
+	}
+
+	if (!(tty = port->tty) || C_HUPCL(tty))  {
+		/* Drop DTR */
+		port->MSVR &= ~(bp->DTR|bp->RTS);
+		bp->r[chip]->r[CD180_MSVR]=port->MSVR;
+	}
+	
+        /* Select port */
+	bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	/* Reset port */
+	aurora_wait_CCR(bp->r[chip]);
+	bp->r[chip]->r[CD180_CCR]=CCR_SOFTRESET;
+	/* Disable all interrupts from this port */
+	port->SRER = 0;
+	bp->r[chip]->r[CD180_SRER]=port->SRER;
+	
+	if (tty)  
+		set_bit(TTY_IO_ERROR, &tty->flags);
+	port->flags &= ~ASYNC_INITIALIZED;
+
+#ifdef MODULE
+	if (--bp->count < 0)  {
+		printk(KERN_DEBUG "aurora%d: aurora_shutdown_port: bad board count: %d\n",
+		       board_No(bp), bp->count);
+		bp->count = 0;
+	}
+	
+	MOD_DEC_USE_COUNT;
+	if (!bp->count)
+		bp->flags&=~AURORA_BOARD_ACTIVE;
+#endif
+
+#ifdef AURORA_DEBUG
+printk("aurora_shutdown_port: end\n");
+#endif
+}
+
+	
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct Aurora_port *port)
+{
+	struct wait_queue wait = { current, NULL };
+	struct Aurora_board *bp = port_Board(port);
+	int    retval;
+	int    do_clocal = 0;
+	int    CD;
+	unsigned char chip;
+	
+#ifdef AURORA_DEBUG
+printk("block_til_ready: start\n");
+#endif
+	chip=AURORA_CD180(port_No(port));
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&port->close_wait);
+		if (port->flags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+	}
+
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (port->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		port->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (port->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (port->normal_termios.c_cflag & CLOCAL) 
+			do_clocal = 1;
+	} else {
+		if (C_CLOCAL(tty))  
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&port->open_wait, &wait);
+	cli();
+	if (!tty_hung_up_p(filp))
+		port->count--;
+	sti();
+	port->blocked_open++;
+	while (1) {
+		cli();
+		bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+		udelay(1);
+		CD = bp->r[chip]->r[CD180_MSVR] & MSVR_CD;
+		if (!(port->flags & ASYNC_CALLOUT_ACTIVE))  {
+			port->MSVR=bp->RTS;
+			bp->r[chip]->r[CD180_MSVR]=port->MSVR;/* auto drops DTR */
+		}
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(port->flags & ASYNC_INITIALIZED)) {
+			if (port->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+			break;
+		}
+		if (/*!(port->flags & ASYNC_CALLOUT_ACTIVE) &&*/
+		    !(port->flags & ASYNC_CLOSING) &&
+		    (do_clocal || CD))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&port->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		port->count++;
+	port->blocked_open--;
+	if (retval)
+		return retval;
+	
+	port->flags |= ASYNC_NORMAL_ACTIVE;
+#ifdef AURORA_DEBUG
+printk("block_til_ready: end\n");
+#endif
+	return 0;
+}	
+
+static int aurora_open(struct tty_struct * tty, struct file * filp)
+{
+	int board;
+	int error;
+	struct Aurora_port * port;
+	struct Aurora_board * bp;
+	unsigned long flags;
+	
+	#ifdef AURORA_DEBUG
+	printk("aurora_open: start\n");
+	#endif
+	
+	board = AURORA_BOARD(MINOR(tty->device));
+	if (board > AURORA_NBOARD || !(aurora_board[board].flags & AURORA_BOARD_PRESENT)){
+		#ifdef AURORA_DEBUG
+		printk("aurora_open: error board %d present %d\n",board,aurora_board[board].flags &AURORA_BOARD_PRESENT);
+		#endif
+		return -ENODEV;
+		}
+	
+	bp = &aurora_board[board];
+	port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(MINOR(tty->device));
+	if (aurora_paranoia_check(port, tty->device, "aurora_open")){
+		#ifdef AURORA_DEBUG
+		printk("aurora_open: error paranoia check\n");
+		#endif
+		return -ENODEV;
+		}
+	
+	port->count++;
+	tty->driver_data = port;
+	port->tty = tty;
+	
+	if ((error = aurora_setup_port(bp, port))) {
+		#ifdef AURORA_DEBUG
+		printk("aurora_open: error aurora_setup_port ret %d\n",error);
+		#endif
+		return error;
+		}
+
+	if ((error = block_til_ready(tty, filp, port))){
+		#ifdef AURORA_DEBUG
+		printk("aurora_open: error block_til_ready ret %d\n",error);
+		#endif
+		return error;
+		}
+	
+	if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {
+		*tty->termios = port->normal_termios;
+		save_flags(flags); cli();
+		aurora_change_speed(bp, port);
+		restore_flags(flags);
+	}
+
+	port->session = current->session;
+	port->pgrp = current->pgrp;
+	#ifdef AURORA_DEBUG
+	printk("aurora_open: end\n");
+	#endif
+	return 0;
+}
+
+static void aurora_close(struct tty_struct * tty, struct file * filp)
+{
+	struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
+	struct Aurora_board *bp;
+	unsigned long flags;
+	unsigned long timeout;
+	unsigned char chip;
+	
+	#ifdef AURORA_DEBUG
+	printk("aurora_close: start\n");
+	#endif
+	
+	if (!port || aurora_paranoia_check(port, tty->device, "close"))
+		return;
+	
+	chip=AURORA_CD180(port_No(port));
+
+	save_flags(flags); cli();
+	if (tty_hung_up_p(filp))  {
+		restore_flags(flags);
+		return;
+	}
+	
+	bp = port_Board(port);
+	if ((tty->count == 1) && (port->count != 1))  {
+		printk(KERN_DEBUG "aurora%d: aurora_close: bad port count; tty->count is 1, port count is %d\n",
+		       board_No(bp), port->count);
+		port->count = 1;
+	}
+	if (--port->count < 0)  {
+		printk(KERN_DEBUG "aurora%d: aurora_close: bad port count for tty%d: %d\n",
+		       board_No(bp), port_No(port), port->count);
+		port->count = 0;
+	}
+	if (port->count)  {
+		restore_flags(flags);
+		return;
+	}
+	port->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (port->flags & ASYNC_NORMAL_ACTIVE)
+		port->normal_termios = *tty->termios;
+/*	if (port->flags & ASYNC_CALLOUT_ACTIVE)
+		port->callout_termios = *tty->termios;*/
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE){
+		#ifdef AURORA_DEBUG
+		printk("aurora_close: waiting to flush...\n");
+		#endif
+		tty_wait_until_sent(tty, port->closing_wait);
+		}
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	port->SRER &= ~SRER_RXD;
+	if (port->flags & ASYNC_INITIALIZED) {
+		port->SRER &= ~SRER_TXRDY;
+		port->SRER |= SRER_TXEMPTY;
+		bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+		udelay(1);
+		bp->r[chip]->r[CD180_SRER]=port->SRER;
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		timeout = jiffies+HZ;
+		while(port->SRER & SRER_TXEMPTY)  {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(port->timeout);
+			if (time_after(jiffies, timeout))
+				break;
+		}
+	}
+	#ifdef AURORA_DEBUG
+	printk("aurora_close: shutdown_port\n");
+	#endif
+	aurora_shutdown_port(bp, port);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	port->event = 0;
+	port->tty = 0;
+	if (port->blocked_open) {
+		if (port->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(port->close_delay);
+		}
+		wake_up_interruptible(&port->open_wait);
+	}
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&port->close_wait);
+	restore_flags(flags);
+	#ifdef AURORA_DEBUG
+	printk("aurora_close: end\n");
+	#endif
+}
+
+static int aurora_write(struct tty_struct * tty, int from_user, 
+		    const unsigned char *buf, int count)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	struct Aurora_board *bp;
+	int c, total = 0;
+	unsigned long flags;
+	unsigned char chip;
+
+#ifdef AURORA_DEBUG
+printk("aurora_write: start %d\n",count);
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_write"))
+		return 0;
+		
+	chip=AURORA_CD180(port_No(port));
+	
+	bp = port_Board(port);
+
+	if (!tty || !port->xmit_buf || !tmp_buf)
+		return 0;
+
+	if (from_user)
+		down(&tmp_buf_sem);
+
+	save_flags(flags);
+	while (1) {
+		cli();		
+		c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - port->xmit_head));
+		if (c <= 0)
+			break;
+
+		if (from_user) {
+			copy_from_user(tmp_buf, buf, c);
+			c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - port->xmit_head));
+			memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
+		} else
+			memcpy(port->xmit_buf + port->xmit_head, buf, c);
+		port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+		port->xmit_cnt += c;
+		restore_flags(flags);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+	if (from_user)
+		up(&tmp_buf_sem);
+	if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+	    !(port->SRER & SRER_TXRDY)) {
+		port->SRER |= SRER_TXRDY;
+		bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+		udelay(1);
+		bp->r[chip]->r[CD180_SRER]=port->SRER;
+	}
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_write: end %d\n",total);
+#endif
+	return total;
+}
+
+static void aurora_put_char(struct tty_struct * tty, unsigned char ch)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	unsigned long flags;
+
+#ifdef AURORA_DEBUG
+printk("aurora_put_char: start %c\n",ch);
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_put_char"))
+		return;
+
+	if (!tty || !port->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	
+	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+		restore_flags(flags);
+		return;
+	}
+
+	port->xmit_buf[port->xmit_head++] = ch;
+	port->xmit_head &= SERIAL_XMIT_SIZE - 1;
+	port->xmit_cnt++;
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_put_char: end\n");
+#endif
+}
+
+static void aurora_flush_chars(struct tty_struct * tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	unsigned long flags;
+	unsigned char chip;
+
+/*#ifdef AURORA_DEBUG
+printk("aurora_flush_chars: start\n");
+#endif*/
+	if (aurora_paranoia_check(port, tty->device, "aurora_flush_chars"))
+		return;
+		
+	chip=AURORA_CD180(port_No(port));
+	
+	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !port->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	port->SRER |= SRER_TXRDY;
+	port_Board(port)->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	port_Board(port)->r[chip]->r[CD180_SRER]=port->SRER;
+	restore_flags(flags);
+/*#ifdef AURORA_DEBUG
+printk("aurora_flush_chars: end\n");
+#endif*/
+}
+
+static int aurora_write_room(struct tty_struct * tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	int	ret;
+
+#ifdef AURORA_DEBUG
+printk("aurora_write_room: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_write_room"))
+		return 0;
+
+	ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+#ifdef AURORA_DEBUG
+printk("aurora_write_room: end\n");
+#endif
+	return ret;
+}
+
+static int aurora_chars_in_buffer(struct tty_struct *tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+				
+	if (aurora_paranoia_check(port, tty->device, "aurora_chars_in_buffer"))
+		return 0;
+	
+	return port->xmit_cnt;
+}
+
+static void aurora_flush_buffer(struct tty_struct *tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	unsigned long flags;
+
+#ifdef AURORA_DEBUG
+printk("aurora_flush_buffer: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_flush_buffer"))
+		return;
+
+	save_flags(flags); cli();
+	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+	restore_flags(flags);
+	
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+#ifdef AURORA_DEBUG
+printk("aurora_flush_buffer: end\n");
+#endif
+}
+
+static int aurora_get_modem_info(struct Aurora_port * port, unsigned int *value)
+{
+	struct Aurora_board * bp;
+	unsigned char status,chip;
+	unsigned int result;
+	unsigned long flags;
+
+#ifdef AURORA_DEBUG
+printk("aurora_get_modem_info: start\n");
+#endif
+	chip=AURORA_CD180(port_No(port));
+
+	bp = port_Board(port);
+	save_flags(flags); cli();
+	bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	status = bp->r[chip]->r[CD180_MSVR];
+	result = 0/*bp->r[chip]->r[AURORA_RI] & (1u << port_No(port)) ? 0 : TIOCM_RNG*/;
+	restore_flags(flags);
+	result |= ((status & bp->RTS) ? TIOCM_RTS : 0)
+		| ((status & bp->DTR) ? TIOCM_DTR : 0)
+		| ((status & MSVR_CD)  ? TIOCM_CAR : 0)
+		| ((status & MSVR_DSR) ? TIOCM_DSR : 0)
+		| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
+	put_user(result,(unsigned long *) value);
+#ifdef AURORA_DEBUG
+printk("aurora_get_modem_info: end\n");
+#endif
+	return 0;
+}
+
+static int aurora_set_modem_info(struct Aurora_port * port, unsigned int cmd,
+			     unsigned int *value)
+{
+	int error;
+	unsigned int arg;
+	unsigned long flags;
+	struct Aurora_board *bp = port_Board(port);
+	unsigned char chip;
+
+#ifdef AURORA_DEBUG
+printk("aurora_set_modem_info: start\n");
+#endif
+	error = get_user(arg, value);
+	if (error) 
+		return error;
+	chip=AURORA_CD180(port_No(port));
+	switch (cmd) {
+	 case TIOCMBIS: 
+		if (arg & TIOCM_RTS) 
+			port->MSVR |= bp->RTS;
+		if (arg & TIOCM_DTR)
+			port->MSVR |= bp->DTR;
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			port->MSVR &= ~bp->RTS;
+		if (arg & TIOCM_DTR)
+			port->MSVR &= ~bp->DTR;
+		break;
+	case TIOCMSET:
+		port->MSVR = (arg & TIOCM_RTS) ? (port->MSVR | bp->RTS) : 
+					         (port->MSVR & ~bp->RTS);
+		port->MSVR = (arg & TIOCM_DTR) ? (port->MSVR | bp->RTS) :
+						 (port->MSVR & ~bp->RTS);
+		break;
+	 default:
+		return -EINVAL;
+	}
+	save_flags(flags); cli();
+	bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	bp->r[chip]->r[CD180_MSVR]=port->MSVR;
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_set_modem_info: end\n");
+#endif
+	return 0;
+}
+
+extern inline void aurora_send_break(struct Aurora_port * port, unsigned long length)
+{
+	struct Aurora_board *bp = port_Board(port);
+	unsigned long flags;
+	unsigned char chip;
+	
+#ifdef AURORA_DEBUG
+printk("aurora_send_break: start\n");
+#endif
+	chip=AURORA_CD180(port_No(port));
+	
+	save_flags(flags); cli();
+	port->break_length = AURORA_TPS / HZ * length;
+	port->COR2 |= COR2_ETC;
+	port->SRER  |= SRER_TXRDY;
+	bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	bp->r[chip]->r[CD180_COR2]=port->COR2;
+	bp->r[chip]->r[CD180_SRER]=port->SRER;
+	aurora_wait_CCR(bp->r[chip]);
+	bp->r[chip]->r[CD180_CCR]=CCR_CORCHG2;
+	aurora_wait_CCR(bp->r[chip]);
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_send_break: end\n");
+#endif
+}
+
+extern inline int aurora_set_serial_info(struct Aurora_port * port,
+				     struct serial_struct * newinfo)
+{
+	struct serial_struct tmp;
+	struct Aurora_board *bp = port_Board(port);
+	int change_speed;
+	unsigned long flags;
+	int error;
+
+#ifdef AURORA_DEBUG
+printk("aurora_set_serial_info: start\n");
+#endif
+	error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
+	if (error)
+		return error;
+	copy_from_user(&tmp, newinfo, sizeof(tmp));
+	
+#if 0	
+	if ((tmp.irq != bp->irq) ||
+	    (tmp.port != bp->base) ||
+	    (tmp.type != PORT_CIRRUS) ||
+	    (tmp.baud_base != (bp->oscfreq + CD180_TPC/2) / CD180_TPC) ||
+	    (tmp.custom_divisor != 0) ||
+	    (tmp.xmit_fifo_size != CD180_NFIFO) ||
+	    (tmp.flags & ~AURORA_LEGAL_FLAGS))
+		return -EINVAL;
+#endif	
+	
+	change_speed = ((port->flags & ASYNC_SPD_MASK) !=
+			(tmp.flags & ASYNC_SPD_MASK));
+	
+	if (!suser()) {
+		if ((tmp.close_delay != port->close_delay) ||
+		    (tmp.closing_wait != port->closing_wait) ||
+		    ((tmp.flags & ~ASYNC_USR_MASK) !=
+		     (port->flags & ~ASYNC_USR_MASK)))  
+			return -EPERM;
+		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+			       (tmp.flags & ASYNC_USR_MASK));
+	} else  {
+		port->flags = ((port->flags & ~ASYNC_FLAGS) |
+			       (tmp.flags & ASYNC_FLAGS));
+		port->close_delay = tmp.close_delay;
+		port->closing_wait = tmp.closing_wait;
+	}
+	if (change_speed)  {
+		save_flags(flags); cli();
+		aurora_change_speed(bp, port);
+		restore_flags(flags);
+	}
+#ifdef AURORA_DEBUG
+printk("aurora_set_serial_info: end\n");
+#endif
+	return 0;
+}
+
+extern inline int aurora_get_serial_info(struct Aurora_port * port,
+				     struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+	struct Aurora_board *bp = port_Board(port);
+	int error;
+	
+#ifdef AURORA_DEBUG
+printk("aurora_get_serial_info: start\n");
+#endif
+	error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));
+	if (error)
+		return error;
+	
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = PORT_CIRRUS;
+	tmp.line = port - aurora_port;
+	tmp.port = 0;
+	tmp.irq  = bp->irq;
+	tmp.flags = port->flags;
+	tmp.baud_base = (bp->oscfreq + CD180_TPC/2) / CD180_TPC;
+	tmp.close_delay = port->close_delay * HZ/100;
+	tmp.closing_wait = port->closing_wait * HZ/100;
+	tmp.xmit_fifo_size = CD180_NFIFO;
+	copy_to_user(retinfo, &tmp, sizeof(tmp));
+#ifdef AURORA_DEBUG
+printk("aurora_get_serial_info: end\n");
+#endif
+	return 0;
+}
+
+static int aurora_ioctl(struct tty_struct * tty, struct file * filp, 
+		    unsigned int cmd, unsigned long arg)
+		    
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	int error;
+	int retval;
+
+#ifdef AURORA_DEBUG
+printk("aurora_ioctl: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_ioctl"))
+		return -ENODEV;
+	
+	switch (cmd) {
+	 case TCSBRK:	/* SVID version: non-zero arg --> no break */
+		retval = tty_check_change(tty);
+		if (retval)
+			return retval;
+		tty_wait_until_sent(tty, 0);
+		if (!arg)
+			aurora_send_break(port, HZ/4);	/* 1/4 second */
+		return 0;
+	 case TCSBRKP:	/* support for POSIX tcsendbreak() */
+		retval = tty_check_change(tty);
+		if (retval)
+			return retval;
+		tty_wait_until_sent(tty, 0);
+		aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4);
+		return 0;
+	 case TIOCGSOFTCAR:
+		error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+		if (error)
+			return error;
+		put_user(C_CLOCAL(tty) ? 1 : 0,
+			    (unsigned long *) arg);
+		return 0;
+	 case TIOCSSOFTCAR:
+		retval = get_user(arg,(unsigned long *) arg);
+		if (retval)
+			return retval;
+		tty->termios->c_cflag =
+			((tty->termios->c_cflag & ~CLOCAL) |
+			(arg ? CLOCAL : 0));
+		return 0;
+	 case TIOCMGET:
+		error = verify_area(VERIFY_WRITE, (void *) arg,
+				    sizeof(unsigned int));
+		if (error)
+			return error;
+		return aurora_get_modem_info(port, (unsigned int *) arg);
+	 case TIOCMBIS:
+	 case TIOCMBIC:
+	 case TIOCMSET:
+		return aurora_set_modem_info(port, cmd, (unsigned int *) arg);
+	 case TIOCGSERIAL:	
+		return aurora_get_serial_info(port, (struct serial_struct *) arg);
+	 case TIOCSSERIAL:	
+		return aurora_set_serial_info(port, (struct serial_struct *) arg);
+	 default:
+		return -ENOIOCTLCMD;
+	}
+#ifdef AURORA_DEBUG
+printk("aurora_ioctl: end\n");
+#endif
+	return 0;
+}
+
+static void aurora_throttle(struct tty_struct * tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	struct Aurora_board *bp;
+	unsigned long flags;
+	unsigned char chip;
+
+#ifdef AURORA_DEBUG
+printk("aurora_throttle: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_throttle"))
+		return;
+	
+	bp = port_Board(port);
+	chip=AURORA_CD180(port_No(port));
+	
+	save_flags(flags); cli();
+	port->MSVR &= ~bp->RTS;
+	bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	if (I_IXOFF(tty))  {
+		aurora_wait_CCR(bp->r[chip]);
+		bp->r[chip]->r[CD180_CCR]=CCR_SSCH2;
+		aurora_wait_CCR(bp->r[chip]);
+	}
+	bp->r[chip]->r[CD180_MSVR]=port->MSVR;
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_throttle: end\n");
+#endif
+}
+
+static void aurora_unthrottle(struct tty_struct * tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	struct Aurora_board *bp;
+	unsigned long flags;
+	unsigned char chip;
+
+#ifdef AURORA_DEBUG
+printk("aurora_unthrottle: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_unthrottle"))
+		return;
+	
+	bp = port_Board(port);
+	
+	chip=AURORA_CD180(port_No(port));
+	
+	save_flags(flags); cli();
+	port->MSVR |= bp->RTS;
+	bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	if (I_IXOFF(tty))  {
+		aurora_wait_CCR(bp->r[chip]);
+		bp->r[chip]->r[CD180_CCR]=CCR_SSCH1;
+		aurora_wait_CCR(bp->r[chip]);
+	}
+	bp->r[chip]->r[CD180_MSVR]=port->MSVR;
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_unthrottle: end\n");
+#endif
+}
+
+static void aurora_stop(struct tty_struct * tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	struct Aurora_board *bp;
+	unsigned long flags;
+	unsigned char chip;
+
+#ifdef AURORA_DEBUG
+printk("aurora_stop: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_stop"))
+		return;
+	
+	bp = port_Board(port);
+	
+	chip=AURORA_CD180(port_No(port));
+	
+	save_flags(flags); cli();
+	port->SRER &= ~SRER_TXRDY;
+	bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+	udelay(1);
+	bp->r[chip]->r[CD180_SRER]=port->SRER;
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_stop: end\n");
+#endif
+}
+
+static void aurora_start(struct tty_struct * tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	struct Aurora_board *bp;
+	unsigned long flags;
+	unsigned char chip;
+
+#ifdef AURORA_DEBUG
+printk("aurora_start: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_start"))
+		return;
+	
+	bp = port_Board(port);
+	
+	chip=AURORA_CD180(port_No(port));
+	
+	save_flags(flags); cli();
+	if (port->xmit_cnt && port->xmit_buf && !(port->SRER & SRER_TXRDY))  {
+		port->SRER |= SRER_TXRDY;
+		bp->r[chip]->r[CD180_CAR]=port_No(port)&7;
+		udelay(1);
+		bp->r[chip]->r[CD180_SRER]=port->SRER;
+	}
+	restore_flags(flags);
+#ifdef AURORA_DEBUG
+printk("aurora_start: end\n");
+#endif
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ * 	serial interrupt routine -> (scheduler tqueue) ->
+ * 	do_aurora_hangup() -> tty->hangup() -> aurora_hangup()
+ * 
+ */
+static void do_aurora_hangup(void *private_)
+{
+	struct Aurora_port	*port = (struct Aurora_port *) private_;
+	struct tty_struct	*tty;
+
+#ifdef AURORA_DEBUG
+printk("do_aurora_hangup: start\n");
+#endif
+	tty = port->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+#ifdef AURORA_DEBUG
+printk("do_aurora_hangup: end\n");
+#endif
+}
+
+static void aurora_hangup(struct tty_struct * tty)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	struct Aurora_board *bp;
+				
+#ifdef AURORA_DEBUG
+printk("aurora_hangup: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_hangup"))
+		return;
+	
+	bp = port_Board(port);
+	
+	aurora_shutdown_port(bp, port);
+	port->event = 0;
+	port->count = 0;
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	port->tty = 0;
+	wake_up_interruptible(&port->open_wait);
+#ifdef AURORA_DEBUG
+printk("aurora_hangup: end\n");
+#endif
+}
+
+static void aurora_set_termios(struct tty_struct * tty, struct termios * old_termios)
+{
+	struct Aurora_port *port = (struct Aurora_port *)tty->driver_data;
+	unsigned long flags;
+
+#ifdef AURORA_DEBUG
+printk("aurora_set_termios: start\n");
+#endif
+	if (aurora_paranoia_check(port, tty->device, "aurora_set_termios"))
+		return;
+	
+	if (tty->termios->c_cflag == old_termios->c_cflag &&
+	    tty->termios->c_iflag == old_termios->c_iflag)
+		return;
+
+	save_flags(flags); cli();
+	aurora_change_speed(port_Board(port), port);
+	restore_flags(flags);
+
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		aurora_start(tty);
+	}
+#ifdef AURORA_DEBUG
+printk("aurora_set_termios: end\n");
+#endif
+}
+
+static void do_aurora_bh(void)
+{
+	 run_task_queue(&tq_aurora);
+}
+
+static void do_softint(void *private_)
+{
+	struct Aurora_port	*port = (struct Aurora_port *) private_;
+	struct tty_struct	*tty;
+
+#ifdef AURORA_DEBUG
+printk("do_softint: start\n");
+#endif
+	if(!(tty = port->tty)) 
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+#ifdef AURORA_DEBUG
+printk("do_softint: end\n");
+#endif
+}
+
+static int aurora_init_drivers(void)
+{
+	int error;
+	int i;
+
+#ifdef AURORA_DEBUG
+printk("aurora_init_drivers: start\n");
+#endif
+	if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) {
+		printk(KERN_ERR "aurora: Couldn't get free page.\n");
+		return 1;
+	}
+	init_bh(AURORA_BH, do_aurora_bh);
+/*	memset(IRQ_to_board, 0, sizeof(IRQ_to_board));*/
+	memset(&aurora_driver, 0, sizeof(aurora_driver));
+	aurora_driver.magic = TTY_DRIVER_MAGIC;
+	aurora_driver.name = "ttyA";
+	aurora_driver.major = AURORA_MAJOR;
+	aurora_driver.num = AURORA_TNPORTS;
+	aurora_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	aurora_driver.subtype = AURORA_TYPE_NORMAL;
+	aurora_driver.init_termios = tty_std_termios;
+	aurora_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	aurora_driver.flags = TTY_DRIVER_REAL_RAW;
+	aurora_driver.refcount = &aurora_refcount;
+	aurora_driver.table = aurora_table;
+	aurora_driver.termios = aurora_termios;
+	aurora_driver.termios_locked = aurora_termios_locked;
+
+	aurora_driver.open  = aurora_open;
+	aurora_driver.close = aurora_close;
+	aurora_driver.write = aurora_write;
+	aurora_driver.put_char = aurora_put_char;
+	aurora_driver.flush_chars = aurora_flush_chars;
+	aurora_driver.write_room = aurora_write_room;
+	aurora_driver.chars_in_buffer = aurora_chars_in_buffer;
+	aurora_driver.flush_buffer = aurora_flush_buffer;
+	aurora_driver.ioctl = aurora_ioctl;
+	aurora_driver.throttle = aurora_throttle;
+	aurora_driver.unthrottle = aurora_unthrottle;
+	aurora_driver.set_termios = aurora_set_termios;
+	aurora_driver.stop = aurora_stop;
+	aurora_driver.start = aurora_start;
+	aurora_driver.hangup = aurora_hangup;
+
+	if ((error = tty_register_driver(&aurora_driver)))  {
+		free_page((unsigned long)tmp_buf);
+		printk(KERN_ERR "aurora: Couldn't register aurora driver, error = %d\n",
+		       error);
+		return 1;
+	}
+	
+	memset(aurora_port, 0, sizeof(aurora_port));
+	for (i = 0; i < AURORA_TNPORTS; i++)  {
+		aurora_port[i].normal_termios  = aurora_driver.init_termios;
+		aurora_port[i].magic = AURORA_MAGIC;
+		aurora_port[i].tqueue.routine = do_softint;
+		aurora_port[i].tqueue.data = &aurora_port[i];
+		aurora_port[i].tqueue_hangup.routine = do_aurora_hangup;
+		aurora_port[i].tqueue_hangup.data = &aurora_port[i];
+		aurora_port[i].close_delay = 50 * HZ/100;
+		aurora_port[i].closing_wait = 3000 * HZ/100;
+	}
+#ifdef AURORA_DEBUG
+printk("aurora_init_drivers: end\n");
+#endif
+	return 0;
+}
+
+static void aurora_release_drivers(void)
+{
+#ifdef AURORA_DEBUG
+printk("aurora_release_drivers: start\n");
+#endif
+	free_page((unsigned long)tmp_buf);
+	tty_unregister_driver(&aurora_driver);
+#ifdef AURORA_DEBUG
+printk("aurora_release_drivers: end\n");
+#endif
+}
+
+#ifndef MODULE
+/*
+ * Called at boot time.
+ *
+ * You can specify IO base for up to RC_NBOARD cards,
+ * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
+ * Note that there will be no probing at default
+ * addresses in this case.
+ *
+ */
+__init_func(void aurora_setup(char *str, int *ints))
+{
+	int i;
+
+	for(i=0;(i<ints[0])&&(i<4);i++) {
+		if (ints[i+1]) irqs[i]=ints[i+1];
+		}
+}
+
+__init_func(int aurora_init(void))
+#else
+int aurora_init(void)
+#endif
+{
+int found;
+int grrr,i;
+
+printk(KERN_INFO "aurora: Driver starting.\n");
+if(aurora_init_drivers())return -EIO;
+found=aurora_probe();
+if(!found){
+  aurora_release_drivers();
+  printk(KERN_INFO "aurora: No Aurora Multiport boards detected.\n");
+  return -EIO;
+  } else {
+  printk(KERN_INFO "aurora: %d boards found.\n",found);
+  }
+for(i=0;i<found;i++){
+	if ((grrr = aurora_setup_board(&aurora_board[i]))) {
+		#ifdef AURORA_DEBUG
+		printk(KERN_ERR "aurora_init: error aurora_setup_board ret %d\n",grrr);
+		#endif
+		return grrr;
+	}
+}
+return 0;
+}
+
+#ifdef MODULE
+int irq  = 0;
+int irq1 = 0;
+int irq2 = 0;
+int irq3 = 0;
+MODULE_PARM(irq , "i");
+MODULE_PARM(irq1, "i");
+MODULE_PARM(irq2, "i");
+MODULE_PARM(irq3, "i");
+
+int init_module(void) 
+{
+	if (irq ) irqs[0]=irq ;
+	if (irq1) irqs[1]=irq1;
+	if (irq2) irqs[2]=irq2;
+	if (irq3) irqs[3]=irq3;
+	return aurora_init();
+}
+	
+void cleanup_module(void)
+{
+	int i;
+	
+#ifdef AURORA_DEBUG
+printk("cleanup_module: aurora_release_drivers\n");
+#endif;
+
+	aurora_release_drivers();
+	for (i = 0; i < AURORA_NBOARD; i++)
+		if (aurora_board[i].flags & AURORA_BOARD_PRESENT) {
+			aurora_shutdown_board(&aurora_board[i]);
+			aurora_release_io_range(&aurora_board[i]);
+		}
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.2.9/linux/drivers/sbus/char/aurora.h linux/drivers/sbus/char/aurora.h
--- v2.2.9/linux/drivers/sbus/char/aurora.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/aurora.h	Wed Jun  2 09:55:38 1999
@@ -0,0 +1,278 @@
+/*
+ *	linux/drivers/sbus/char/aurora.h -- Aurora multiport driver
+ *
+ *	Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
+ *
+ *	This code is based on the RISCom/8 multiport serial driver written
+ *	by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial
+ *	driver, written by Linus Torvalds, Theodore T'so and others.
+ *	The Aurora multiport programming info was obtained mainly from the
+ *	Cirrus Logic CD180 documentation (available on the web), and by
+ *	doing heavy tests on the board. Many thanks to Eddie C. Dost for the
+ *	help on the sbus interface.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *	Revision 1.0
+ *
+ *	This is the first public release.
+ *
+ *	This version needs a lot of feedback. This is the version that works
+ *	with _my_ board. My board is model 1600se, revision '@(#)1600se.fth
+ *	1.2 3/28/95 1'. The driver might work with your board, but I do not
+ *	guarantee it. If you have _any_ type of board, I need to know if the
+ *	driver works or not, I need to know exactly your board parameters
+ *	(get them with 'cd /proc/openprom/iommu/sbus/sio16/; ls *; cat *')
+ *	Also, I need your board revision code, which is written on the board.
+ *	Send me the output of my driver too (it outputs through klogd).
+ *
+ *	If the driver does not work, you can try enabling the debug options
+ *	to see what's wrong or what should be done.
+ *
+ *	I'm sorry about the alignment of the code. It was written in a
+ *	128x48 environment.
+ *
+ *	I must say that I do not like Aurora Technologies' policy. I asked
+ *	them to help me do this driver faster, but they ended by something
+ *	like "don't call us, we'll call you", and I never heard anything
+ *	from them. They told me "knowing the way the board works, I don't
+ *	doubt you and others on the net will make the driver."
+ *	The truth about this board is that it has nothing intelligent on it.
+ *	If you want to say to somebody what kind of board you have, say that
+ *	it uses Cirrus Logic processors (CD180). The power of the board is
+ *	in those two chips. The rest of the board is the interface to the
+ *	sbus and to the peripherals. Still, they did something smart: they
+ *	reversed DTR and RTS to make on-board automatic hardware flow
+ *	control usable.
+ *	Thanks to Aurora Technologies for wasting my time, nerves and money.
+ */
+
+#ifndef __LINUX_AURORA_H
+#define __LINUX_AURORA_H
+
+#include <linux/serial.h>
+
+#ifdef __KERNEL__
+
+/* This is the number of boards to support. I've only tested this driver with
+ * one board, so it might not work.
+ */
+#define AURORA_NBOARD 1
+
+/* Useful ? Yes. But you can safely comment the warnings if they annoy you
+ * (let me say that again: the warnings in the code, not this define). 
+ */
+#define AURORA_PARANOIA_CHECK
+
+/* Well, after many lost nights, I found that the IRQ for this board is
+ * selected from four built-in values by writing some bits in the
+ * configuration register. This causes a little problem to occur: which
+ * IRQ to select ? Which one is the best for the user ? Well, I finally
+ * decided for the following algorithm: if the "bintr" value is not acceptable
+ * (not within type_1_irq[], then test the "intr" value, if that fails too,
+ * try each value from type_1_irq until succeded. Hope it's ok.
+ * You can safely reorder the irq's.
+ */
+#define TYPE_1_IRQS 4
+unsigned char type_1_irq[TYPE_1_IRQS] = {
+	3, 5, 9, 13
+	};
+/* I know something about another method of interrupt setting, but not enough.
+ * Also, this is for another type of board, so I first have to learn how to
+ * detect it.
+#define TYPE_2_IRQS 3
+unsigned char type_2_irq[TYPE_2_IRQS] = {
+	0, 0, 0 ** could anyone find these for me ? (see AURORA_ALLIRQ below) **
+	};
+unsigned char type_2_mask[TYPE_2_IRQS] = {
+	32, 64, 128
+	};
+*/
+
+/* The following section should only be modified by those who know what
+ * they're doing (or don't, but want to help with some feedback). Modifying
+ * anything raises a _big_ probability for your system to hang, but the
+ * sacrifice worths. (I sacrificed my ext2fs many, many times...)
+ */
+
+/* This one tries to dump to console the name of almost every function called,
+ * and many other debugging info.
+ */
+#undef AURORA_DEBUG
+
+/* These are the most dangerous and useful defines. They do printk() during
+ * the interrupt processing routine(s), so if you manage to get "flooded" by
+ * irq's, start thinking about the "Power off/on" button...
+ */
+#undef AURORA_INTNORM	/* This one enables the "normal" messages, but some
+			 * of them cause flood, so I preffered putting
+			 * them under a define */
+#undef AURORA_INT_DEBUG /* This one is really bad. */
+
+/* Here's something helpful: after n irq's, the board will be disabled. This
+ * prevents irq flooding during debug (no need to think about power
+ * off/on anymore...)
+ */
+#define AURORA_FLOODPRO	10
+
+/* This one helps finding which irq the board calls, in case of a strange/
+ * unsupported board. AURORA_INT_DEBUG should be enabled, because I don't
+ * think /proc/interrupts or any command will be available in case of an irq
+ * flood... "allirq" is the list of all free irq's.
+ */
+/*
+#define AURORA_ALLIRQ 6
+int allirq[AURORA_ALLIRQ]={
+	2,3,5,7,9,13
+	};
+*/
+
+/* These must not be modified. These values are assumed during the code for
+ * performance optimisations.
+ */
+#define AURORA_NCD180 2 /* two chips per board */
+#define AURORA_NPORT 8  /* 8 ports per chip */
+
+/* several utilities */
+#define AURORA_BOARD(line)	(((line) >> 4) & 0x01)
+#define AURORA_CD180(line)	(((line) >> 3) & 0x01)
+#define AURORA_PORT(line)	((line) & 15)
+
+#define AURORA_TNPORTS (AURORA_NBOARD*AURORA_NCD180*AURORA_NPORT)
+
+/* Ticks per sec. Used for setting receiver timeout and break length */
+#define AURORA_TPS		4000
+
+#define AURORA_MAGIC	0x0A18
+
+/* Yeah, after heavy testing I decided it must be 6.
+ * Sure, You can change it if needed.
+ */
+#define AURORA_RXFIFO		6	/* Max. receiver FIFO size (1-8) */
+
+#define AURORA_RXTH		7
+
+struct aurora_reg1 {
+	__volatile__ unsigned char r;
+	};
+
+struct aurora_reg128 {
+	__volatile__ unsigned char r[128];
+	};
+	
+struct aurora_reg4 {
+	__volatile__ unsigned char r[4];
+	};
+
+struct Aurora_board {
+	unsigned long		flags;
+	struct aurora_reg1	* r0;	/* This is the board configuration
+					 * register (write-only). */
+	struct aurora_reg128	* r[2];	/* These are the registers for the
+					 * two chips. */
+	struct aurora_reg4	* r3;	/* These are used for hardware-based
+					 * acknowledge. Software-based ack is
+					 * not supported by CD180. */
+	unsigned int		oscfreq; /* The on-board oscillator
+					  * frequency, in Hz. */
+	unsigned char		irq;
+#ifdef MODULE
+	signed char		count;	/* counts the use of the board */
+#endif
+	/* Values for the dtr_rts swapped mode. */
+	unsigned char		DTR;
+	unsigned char		RTS;
+	unsigned char		MSVDTR;
+	unsigned char		MSVRTS;
+	/* Values for hardware acknowledge. */
+	unsigned char		ACK_MINT,ACK_TINT,ACK_RINT;
+};
+
+/* Board configuration register */
+#define AURORA_CFG_ENABLE_IO	8
+#define AURORA_CFG_ENABLE_IRQ	4
+
+/* Board flags */
+#define AURORA_BOARD_PRESENT		0x00000001
+#define AURORA_BOARD_ACTIVE		0x00000002
+#define AURORA_BOARD_TYPE_2		0x00000004	/* don't know how to
+							 * detect this yet */
+#define AURORA_BOARD_DTR_FLOW_OK	0x00000008
+
+/* The story goes like this: Cirrus programmed the CD-180 chip to do automatic
+ * hardware flow control, and do it using CTS and DTR. CTS is ok, but, if you
+ * have a modem and the chip drops DTR, then the modem will drop the carrier
+ * (ain't that cute...). Luckily, the guys at Aurora decided to swap DTR and
+ * RTS, which makes the flow control usable. I hope that all the boards made
+ * by Aurora have these two signals swapped. If your's doesn't but you have a
+ * breakout box, you can try to reverse them yourself, then set the following
+ * flag.
+ */
+#undef AURORA_FORCE_DTR_FLOW
+
+/* In fact, a few more words have to be said about hardware flow control.
+ * This driver handles "output" flow control through the on-board facility
+ * CTS Auto Enable. For the "input" flow control there are two cases when
+ * the flow should be controlled. The first case is when the kernel is so
+ * busy that it cannot process IRQ's in time; this flow control can only be
+ * activated by the on-board chip, and if the board has RTS and DTR swapped,
+ * this facility is usable. The second case is when the application is so
+ * busy that it cannot receive bytes from the kernel, and this flow must be
+ * activated by software. This second case is not yet implemented in this
+ * driver. Unfortunately, I estimate that the second case is the one that
+ * occurs the most.
+ */
+
+
+struct Aurora_port {
+	int			magic;
+	int			baud_base;
+	int			flags;
+	struct tty_struct 	* tty;
+	int			count;
+	int			blocked_open;
+	int			event;
+	int			timeout;
+	int			close_delay;
+	long			session;
+	long			pgrp;
+	unsigned char 		* xmit_buf;
+	int			custom_divisor;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct termios          normal_termios;
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+	struct tq_struct	tqueue;
+	struct tq_struct	tqueue_hangup;
+	short			wakeup_chars;
+	short			break_length;
+	unsigned short		closing_wait;
+	unsigned char		mark_mask;
+	unsigned char		SRER;
+	unsigned char		MSVR;
+	unsigned char		COR2;
+#ifdef AURORA_REPORT_OVERRUN
+	unsigned long		overrun;
+#endif	
+#ifdef AURORA_REPORT_FIFO
+	unsigned long		hits[10];
+#endif
+};
+
+#endif
+#endif /*__LINUX_AURORA_H*/
+
diff -u --recursive --new-file v2.2.9/linux/drivers/sbus/char/cd180.h linux/drivers/sbus/char/cd180.h
--- v2.2.9/linux/drivers/sbus/char/cd180.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/cd180.h	Wed Jun  2 09:55:38 1999
@@ -0,0 +1,240 @@
+
+/* Definitions for Cirrus Logic CL-CD180 8-port async mux chip */
+#define CD180_NCH       8       /* Total number of channels                */
+#define CD180_TPC       16      /* Ticks per character                     */
+#define CD180_NFIFO	8	/* TX FIFO size                            */
+
+/* Global registers */
+#define CD180_GFRCR	0x6b	/* Global Firmware Revision Code Register  */
+#define CD180_SRCR	0x66	/* Service Request Configuration Register  */
+#define CD180_PPRH	0x70	/* Prescaler Period Register High	   */
+#define CD180_PPRL	0x71	/* Prescaler Period Register Low	   */
+#define CD180_MSMR	0x61	/* Modem Service Match Register		   */
+#define CD180_TSMR	0x62	/* Transmit Service Match Register	   */
+#define CD180_RSMR	0x63	/* Receive Service Match Register	   */
+#define CD180_GSVR	0x40	/* Global Service Vector Register	   */
+#define CD180_SRSR	0x65	/* Service Request Status Register	   */
+#define CD180_GSCR	0x41	/* Global Service Channel Register	   */
+#define CD180_CAR	0x64	/* Channel Access Register		   */
+
+/* Indexed registers */
+#define CD180_RDCR	0x07	/* Receive Data Count Register		   */
+#define CD180_RDR	0x78	/* Receiver Data Register		   */
+#define CD180_RCSR	0x7a	/* Receiver Character Status Register	   */
+#define CD180_TDR	0x7b	/* Transmit Data Register		   */
+#define CD180_EOSRR	0x7f	/* End of Service Request Register	   */
+
+/* Channel Registers */
+#define CD180_SRER      0x02    /* Service Request Enable Register         */
+#define CD180_CCR       0x01    /* Channel Command Register                */
+#define CD180_COR1      0x03    /* Channel Option Register 1               */
+#define CD180_COR2      0x04    /* Channel Option Register 2               */
+#define CD180_COR3      0x05    /* Channel Option Register 3               */
+#define CD180_CCSR      0x06    /* Channel Control Status Register         */
+#define CD180_RTPR      0x18    /* Receive Timeout Period Register         */
+#define CD180_RBPRH     0x31    /* Receive Bit Rate Period Register High  */
+#define CD180_RBPRL     0x32    /* Receive Bit Rate Period Register Low   */
+#define CD180_TBPRH     0x39    /* Transmit Bit Rate Period Register High */
+#define CD180_TBPRL     0x3a    /* Transmit Bit Rate Period Register Low  */
+#define CD180_SCHR1     0x09    /* Special Character Register 1            */
+#define CD180_SCHR2     0x0a    /* Special Character Register 2            */
+#define CD180_SCHR3     0x0b    /* Special Character Register 3            */
+#define CD180_SCHR4     0x0c    /* Special Character Register 4            */
+#define CD180_MCR       0x12    /* Modem Change Register                   */
+#define CD180_MCOR1     0x10    /* Modem Change Option 1 Register          */
+#define CD180_MCOR2     0x11    /* Modem Change Option 2 Register          */
+#define CD180_MSVR      0x28    /* Modem Signal Value Register             */
+#define CD180_MSVRTS    0x29    /* Modem Signal Value RTS                  */
+#define CD180_MSVDTR    0x2a    /* Modem Signal Value DTR                  */
+
+/* Global Interrupt Vector Register (R/W) */
+
+#define GSVR_ITMASK     0x07     /* Interrupt type mask                     */
+#define  GSVR_IT_MDM     0x01    /* Modem Signal Change Interrupt           */
+#define  GSVR_IT_TX      0x02    /* Transmit Data Interrupt                 */
+#define  GSVR_IT_RGD     0x03    /* Receive Good Data Interrupt             */
+#define  GSVR_IT_REXC    0x07    /* Receive Exception Interrupt             */
+
+
+/* Global Interrupt Channel Register (R/W) */
+ 
+#define GSCR_CHAN       0x1c    /* Channel Number Mask                     */
+#define GSCR_CHAN_OFF   2       /* Channel Number Offset                   */
+
+
+/* Channel Address Register (R/W) */
+
+#define CAR_CHAN        0x07    /* Channel Number Mask                     */
+
+
+/* Receive Character Status Register (R/O) */
+
+#define RCSR_TOUT       0x80    /* Rx Timeout                              */
+#define RCSR_SCDET      0x70    /* Special Character Detected Mask         */
+#define  RCSR_NO_SC      0x00   /* No Special Characters Detected          */
+#define  RCSR_SC_1       0x10   /* Special Char 1 (or 1 & 3) Detected      */
+#define  RCSR_SC_2       0x20   /* Special Char 2 (or 2 & 4) Detected      */
+#define  RCSR_SC_3       0x30   /* Special Char 3 Detected                 */
+#define  RCSR_SC_4       0x40   /* Special Char 4 Detected                 */
+#define RCSR_BREAK      0x08    /* Break has been detected                 */
+#define RCSR_PE         0x04    /* Parity Error                            */
+#define RCSR_FE         0x02    /* Frame Error                             */
+#define RCSR_OE         0x01    /* Overrun Error                           */
+
+
+/* Channel Command Register (R/W) (commands in groups can be OR-ed) */
+
+#define CCR_HARDRESET   0x81    /* Reset the chip                          */
+
+#define CCR_SOFTRESET   0x80    /* Soft Channel Reset                      */
+
+#define CCR_CORCHG1     0x42    /* Channel Option Register 1 Changed       */
+#define CCR_CORCHG2     0x44    /* Channel Option Register 2 Changed       */
+#define CCR_CORCHG3     0x48    /* Channel Option Register 3 Changed       */
+
+#define CCR_SSCH1       0x21    /* Send Special Character 1                */
+
+#define CCR_SSCH2       0x22    /* Send Special Character 2                */
+
+#define CCR_SSCH3       0x23    /* Send Special Character 3                */
+
+#define CCR_SSCH4       0x24    /* Send Special Character 4                */
+
+#define CCR_TXEN        0x18    /* Enable Transmitter                      */
+#define CCR_RXEN        0x12    /* Enable Receiver                         */
+
+#define CCR_TXDIS       0x14    /* Disable Transmitter                     */
+#define CCR_RXDIS       0x11    /* Disable Receiver                        */
+
+
+/* Service Request Enable Register (R/W) */
+
+#define SRER_DSR         0x80    /* Enable interrupt on DSR change          */
+#define SRER_CD          0x40    /* Enable interrupt on CD change           */
+#define SRER_CTS         0x20    /* Enable interrupt on CTS change          */
+#define SRER_RXD         0x10    /* Enable interrupt on Receive Data        */
+#define SRER_RXSC        0x08    /* Enable interrupt on Receive Spec. Char  */
+#define SRER_TXRDY       0x04    /* Enable interrupt on TX FIFO empty       */
+#define SRER_TXEMPTY     0x02    /* Enable interrupt on TX completely empty */
+#define SRER_RET         0x01    /* Enable interrupt on RX Exc. Timeout     */
+
+
+/* Channel Option Register 1 (R/W) */
+
+#define COR1_ODDP       0x80    /* Odd Parity                              */
+#define COR1_PARMODE    0x60    /* Parity Mode mask                        */
+#define  COR1_NOPAR      0x00   /* No Parity                               */
+#define  COR1_FORCEPAR   0x20   /* Force Parity                            */
+#define  COR1_NORMPAR    0x40   /* Normal Parity                           */
+#define COR1_IGNORE     0x10    /* Ignore Parity on RX                     */
+#define COR1_STOPBITS   0x0c    /* Number of Stop Bits                     */
+#define  COR1_1SB        0x00   /* 1 Stop Bit                              */
+#define  COR1_15SB       0x04   /* 1.5 Stop Bits                           */
+#define  COR1_2SB        0x08   /* 2 Stop Bits                             */
+#define COR1_CHARLEN    0x03    /* Character Length                        */
+#define  COR1_5BITS      0x00   /* 5 bits                                  */
+#define  COR1_6BITS      0x01   /* 6 bits                                  */
+#define  COR1_7BITS      0x02   /* 7 bits                                  */
+#define  COR1_8BITS      0x03   /* 8 bits                                  */
+
+
+/* Channel Option Register 2 (R/W) */
+
+#define COR2_IXM        0x80    /* Implied XON mode                        */
+#define COR2_TXIBE      0x40    /* Enable In-Band (XON/XOFF) Flow Control  */
+#define COR2_ETC        0x20    /* Embedded Tx Commands Enable             */
+#define COR2_LLM        0x10    /* Local Loopback Mode                     */
+#define COR2_RLM        0x08    /* Remote Loopback Mode                    */
+#define COR2_RTSAO      0x04    /* RTS Automatic Output Enable             */
+#define COR2_CTSAE      0x02    /* CTS Automatic Enable                    */
+#define COR2_DSRAE      0x01    /* DSR Automatic Enable                    */
+
+
+/* Channel Option Register 3 (R/W) */
+
+#define COR3_XONCH      0x80    /* XON is a pair of characters (1 & 3)     */
+#define COR3_XOFFCH     0x40    /* XOFF is a pair of characters (2 & 4)    */
+#define COR3_FCT        0x20    /* Flow-Control Transparency Mode          */
+#define COR3_SCDE       0x10    /* Special Character Detection Enable      */
+#define COR3_RXTH       0x0f    /* RX FIFO Threshold value (1-8)           */
+
+
+/* Channel Control Status Register (R/O) */
+
+#define CCSR_RXEN       0x80    /* Receiver Enabled                        */
+#define CCSR_RXFLOFF    0x40    /* Receive Flow Off (XOFF was sent)        */
+#define CCSR_RXFLON     0x20    /* Receive Flow On (XON was sent)          */
+#define CCSR_TXEN       0x08    /* Transmitter Enabled                     */
+#define CCSR_TXFLOFF    0x04    /* Transmit Flow Off (got XOFF)            */
+#define CCSR_TXFLON     0x02    /* Transmit Flow On (got XON)              */
+
+
+/* Modem Change Option Register 1 (R/W) */
+
+#define MCOR1_DSRZD     0x80    /* Detect 0->1 transition of DSR           */
+#define MCOR1_CDZD      0x40    /* Detect 0->1 transition of CD            */
+#define MCOR1_CTSZD     0x20    /* Detect 0->1 transition of CTS           */
+#define MCOR1_DTRTH     0x0f    /* Auto DTR flow control Threshold (1-8)   */
+#define  MCOR1_NODTRFC   0x0     /* Automatic DTR flow control disabled     */
+
+
+/* Modem Change Option Register 2 (R/W) */
+
+#define MCOR2_DSROD     0x80    /* Detect 1->0 transition of DSR           */
+#define MCOR2_CDOD      0x40    /* Detect 1->0 transition of CD            */
+#define MCOR2_CTSOD     0x20    /* Detect 1->0 transition of CTS           */
+
+
+/* Modem Change Register (R/W) */
+
+#define MCR_DSRCHG      0x80    /* DSR Changed                             */
+#define MCR_CDCHG       0x40    /* CD Changed                              */
+#define MCR_CTSCHG      0x20    /* CTS Changed                             */
+
+
+/* Modem Signal Value Register (R/W) */
+
+#define MSVR_DSR        0x80    /* Current state of DSR input              */
+#define MSVR_CD         0x40    /* Current state of CD input               */
+#define MSVR_CTS        0x20    /* Current state of CTS input              */
+#define MSVR_DTR        0x02    /* Current state of DTR output             */
+#define MSVR_RTS        0x01    /* Current state of RTS output             */
+
+
+/* Service Request Status Register */
+
+#define SRSR_CMASK	0xC0	/* Current Service Context Mask            */
+#define  SRSR_CNONE	0x00	/* Not in a service context		   */
+#define  SRSR_CRX	0x40	/* Rx Context				   */
+#define  SRSR_CTX	0x80	/* Tx Context				   */
+#define  SRSR_CMDM	0xC0	/* Modem Context			   */
+#define SRSR_ANYINT	0x6F	/* Any interrupt flag			   */
+#define SRSR_RINT	0x10	/* Receive Interrupt			   */
+#define SRSR_TINT	0x04	/* Transmit Interrupt			   */
+#define SRSR_MINT	0x01	/* Modem Interrupt			   */
+#define SRSR_REXT	0x20	/* Receive External Interrupt		   */
+#define SRSR_TEXT	0x08	/* Transmit External Interrupt		   */
+#define SRSR_MEXT	0x02	/* Modem External Interrupt		   */
+
+
+/* Service Request Configuration Register */
+
+#define SRCR_PKGTYPE    0x80
+#define SRCR_REGACKEN   0x40
+#define SRCR_DAISYEN    0x20
+#define SRCR_GLOBPRI    0x10
+#define SRCR_UNFAIR     0x08
+#define SRCR_AUTOPRI    0x02
+#define SRCR_PRISEL     0x01
+
+/* Values for register-based Interrupt ACKs */
+#define CD180_ACK_MINT	0x75	/* goes to MSMR				   */
+#define CD180_ACK_TINT	0x76	/* goes to TSMR				   */
+#define CD180_ACK_RINT	0x77	/* goes to RSMR				   */
+
+/* Escape characters */
+
+#define CD180_C_ESC     0x00    /* Escape character                        */
+#define CD180_C_SBRK    0x81    /* Start sending BREAK                     */
+#define CD180_C_DELAY   0x82    /* Delay output                            */
+#define CD180_C_EBRK    0x83    /* Stop sending BREAK                      */
diff -u --recursive --new-file v2.2.9/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.2.9/linux/drivers/sbus/sbus.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/sbus/sbus.c	Wed Jun  2 09:55:38 1999
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.76 1998/12/17 11:11:26 davem Exp $
+/* $Id: sbus.c,v 1.76.2.1 1999/05/29 06:17:26 davem Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -207,6 +207,9 @@
 #ifdef CONFIG_OBP_FLASH
 extern int flash_init(void);
 #endif
+#ifdef CONFIG_SUN_AURORA
+extern int aurora_init(void);
+#endif
 
 __initfunc(static void
 sbus_do_child_siblings(int start_node, struct linux_sbus_device *child,
@@ -440,6 +443,9 @@
 #endif
 #ifdef CONFIG_OBP_FLASH
 	flash_init();
+#endif
+#ifdef CONFIG_SUN_AURORA
+	aurora_init();
 #endif
 #ifdef __sparc_v9__
 	if (sparc_cpu_model == sun4u) {
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.2.9/linux/drivers/scsi/Config.in	Tue May 11 13:10:29 1999
+++ linux/drivers/scsi/Config.in	Wed Jun  9 16:59:34 1999
@@ -25,10 +25,8 @@
 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
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
--- v2.2.9/linux/drivers/scsi/README.aic7xxx	Thu Jan  7 15:11:37 1999
+++ linux/drivers/scsi/README.aic7xxx	Wed Jun  9 16:59:34 1999
@@ -17,6 +17,10 @@
     AHA-274xT               
     AHA-2842
     AHA-2910B               
+    AHA-2920C
+    AHA-2930
+    AHA-2930U
+    AHA-2930U2
     AHA-2940               
     AHA-2940W              
     AHA-2940U              
@@ -77,8 +81,8 @@
     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 @@
     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 @@
 	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 @@
     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
   ------------------------------
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v2.2.9/linux/drivers/scsi/README.st	Wed Mar 10 15:29:47 1999
+++ linux/drivers/scsi/README.st	Sat May 22 14:51:26 1999
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Sun Jan 17 10:57:41 1999 by makisara@home
+Last modified: Sun Apr 18 13:24:43 1999 by makisara@home
 
 
 BASICS
@@ -348,15 +348,6 @@
 	The GMT_xxx status bits reflect the drive status. GMT_DR_OPEN
 	is set if there is no tape in the drive. GMT_EOD means either
 	end of recorded data or end of tape. GMT_EOT means end of tape.
-
-The following ioctls use the structure mtlocation that contains both
-the block number and the partition number. These ioctls are available
-only for SCSI-2 tape drives and the block number is the
-device-independent logical block number defined by the standard.
-
-MTGETLOC Returns the current block and partition number.
-MTSETLOC Sets the tape to the block and partition specified by the
-	arguments.
 
 
 MISCELLANEOUS COMPILE OPTIONS
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg
--- v2.2.9/linux/drivers/scsi/aic7xxx/aic7xxx.reg	Fri Jan  8 22:36:09 1999
+++ linux/drivers/scsi/aic7xxx/aic7xxx.reg	Wed Jun  9 16:59:34 1999
@@ -214,6 +214,25 @@
 }
 
 /*
+ * 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 @@
 	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 @@
 	bit	SQPARERR	0x08
 	bit	ILLOPCODE	0x04
 	bit	ILLSADDR	0x02
+	bit	DSCTMOUT	0x02	/* Ultra3 only */
 	bit	ILLHADDR	0x01
 }
 
@@ -788,6 +814,17 @@
 }
 
 /*
+ * 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
  */
@@ -797,6 +834,21 @@
 }
 
 /*
+ * 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
  */
@@ -806,11 +858,27 @@
 }
 
 /*
+ * 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 @@
 	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
 }
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
--- v2.2.9/linux/drivers/scsi/aic7xxx/aic7xxx.seq	Fri Oct  9 13:27:10 1998
+++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Wed Jun  9 16:59:34 1999
@@ -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 @@
 	}
 
 	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 @@
 	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 @@
  * 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 @@
 	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 @@
 	 */
 	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 @@
  */
 	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_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 @@
 		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 @@
 		 * };
 		 */
 		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 @@
 	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_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_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 @@
 /*
  * 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 @@
  * 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 @@
  * 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_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 @@
 	}
 	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 @@
 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 @@
  * 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 @@
 	 * 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 @@
 	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 @@
 
 /*
  * 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 @@
 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 @@
 	mov	DINDIR, SINDIR;
 	mov	DINDIR, SINDIR;
 	mov	DINDIR, SINDIR ret;
+}
 
 /*
  * Setup addr assuming that A is an index into
@@ -1407,12 +1436,14 @@
  * 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 @@
 	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 @@
  * 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;
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/aic7xxx/scsi_message.h linux/drivers/scsi/aic7xxx/scsi_message.h
--- v2.2.9/linux/drivers/scsi/aic7xxx/scsi_message.h	Tue Apr 14 14:29:21 1998
+++ linux/drivers/scsi/aic7xxx/scsi_message.h	Wed Jun  9 16:59:34 1999
@@ -38,4 +38,12 @@
 #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
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.2.9/linux/drivers/scsi/aic7xxx.c	Tue Jan 19 11:32:51 1999
+++ linux/drivers/scsi/aic7xxx.c	Wed Jun  9 16:59:34 1999
@@ -171,91 +171,6 @@
  */
 
 /*
- * 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
  *   sane and proper values, or should we be anal about our PCI config
@@ -336,6 +251,7 @@
 #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 @@
     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 @@
  * 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 @@
  *
  * *** 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 @@
  * 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 @@
 };
 */
 
+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 @@
   "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 @@
         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 @@
   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 @@
   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 @@
                          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 @@
   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 @@
   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 @@
 #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 @@
 #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 @@
   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 @@
   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 @@
  * 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 @@
   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 @@
 
 #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 @@
       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 @@
  *-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 @@
     /*
      * Use async transfers for this target
      */
+    *options = 0;
     *period = 0;
     syncrate = NULL;
   }
@@ -2135,7 +2142,7 @@
 {
   struct aic7xxx_syncrate *syncrate;
 
-  if ((p->features & AHC_ULTRA2) != 0)
+  if (p->features & AHC_ULTRA2)
   {
     scsirate &= SXFR_ULTRA2;
   }
@@ -2147,12 +2154,14 @@
   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 @@
 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 @@
 
   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 @@
       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 @@
     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 @@
         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 @@
   {
     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 @@
 {
   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 @@
 
     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 @@
   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 @@
   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 @@
  *   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 @@
     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 @@
          * 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 @@
   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 @@
     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 @@
       }
 #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 @@
         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 @@
         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 @@
 
     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 @@
             "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 @@
     }
     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 @@
             "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 @@
   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 @@
 #endif /* AIC7XXX_PROC_STATS */
       }
 #ifdef AIC7XXX_PROC_STATS
-      x = -10;
+      x = -11;
       while(actual)
       {
         actual >>= 1;
@@ -3429,11 +3466,10 @@
       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 @@
   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 @@
         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 @@
    * 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 @@
     {
       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 @@
   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;
+      }
     }
   }
 
@@ -4188,6 +4230,30 @@
 
 /*+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
  *
  * Description:
@@ -4304,10 +4370,10 @@
   /*
    * 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 @@
   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 @@
                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 @@
             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_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 @@
             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 @@
            */
           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 @@
           */
           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 @@
                  * 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 @@
                     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 @@
                 }
               }
 #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 @@
 #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,10 +5019,28 @@
                       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 if (p->dev_active_cmds[tindex] == 0)
+                {
+                  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 @@
          */
 
         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 @@
             printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
               CTL_OF_SCB(scb));
         }
-        else if (scb->flags & SCB_MSGOUT_WDTR)
+        else if (scb->flags & SCB_MSGOUT_PPR)
         {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-          if (aic7xxx_verbose > 0xffff)
+          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)
+        {
+          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 @@
             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 @@
 #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 @@
       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 @@
 
         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 @@
         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 @@
              */
             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 @@
          * 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 @@
             {
               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 @@
               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 @@
              */
             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 @@
               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 @@
          * 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) )
         {
-          p->needsdtr |= target_mask;
-          if ( !reject && !reply )
+          if(p->features & AHC_ULTRA3)
+          {
+            maxsync = AHC_SYNCRATE_ULTRA3;
+          }
+          else
           {
-            scb->flags &= ~SCB_MSGOUT_WDTR;
-            if (p->transinfo[tindex].goal_period)
+            maxsync = AHC_SYNCRATE_ULTRA2;
+          }
+        }
+        else
+        {
+          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))
+          {
+            /*
+             * 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 @@
     } /* 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 @@
     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 @@
             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 @@
         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 @@
           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 @@
         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 @@
     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 @@
         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 @@
       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 @@
     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 @@
  *   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 @@
   {
     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 @@
   }
   printk("\n");
 #endif
-  if (checksum != scarray[len - 1])
+  if ( (checksum != scarray[len - 1]) || (checksum == 0) )
   {
     return (0);
   }
@@ -7371,7 +7814,6 @@
       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_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 @@
     {
       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 @@
    */
   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 @@
     {
       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 @@
    * 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 @@
     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 @@
         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 @@
     }
     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 @@
       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 @@
       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 @@
   }
   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 @@
     {
       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 @@
       {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 @@
       {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 @@
        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 @@
           }
 #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 @@
           {
             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 @@
           }
 #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 @@
           {
             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 @@
 
             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 @@
            */
           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);
+              /*
+               * 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);
               /*
-              aic_outb(temp_p, aic_inb(temp_p, DSCOMMAND0) |
-                               CACHETHEN | DPARCKEN | MPARCKEN |
-                               USCBSIZE32 | CIOPARCKEN,
-                               DSCOMMAND0);
+               * 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 @@
               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 @@
           {
             case AHC_AIC7895:
             case AHC_AIC7896:
+            case AHC_AIC7899:
               current_p = list_p;
               while(current_p != NULL)
               {
@@ -9315,6 +9853,7 @@
               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 @@
            */
           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 @@
               }
             }
             /*
-             * 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 @@
   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 @@
 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 @@
   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 @@
 {
   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 @@
   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 @@
           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 @@
     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 @@
       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 @@
     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 @@
      * 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 @@
   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 @@
       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 @@
       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 @@
 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 @@
           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 @@
     { 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} }
   };
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
--- v2.2.9/linux/drivers/scsi/aic7xxx_proc.c	Thu Jan  7 15:11:37 1999
+++ linux/drivers/scsi/aic7xxx_proc.c	Wed Jun  9 16:59:34 1999
@@ -160,21 +160,17 @@
   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 @@
     }
     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 @@
   }
   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 @@
     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 @@
       }
     }
     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);
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
--- v2.2.9/linux/drivers/scsi/aic7xxx_reg.h	Fri Oct  9 13:27:11 1998
+++ linux/drivers/scsi/aic7xxx_reg.h	Wed Jun  9 16:59:34 1999
@@ -63,6 +63,16 @@
 
 #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
@@ -102,8 +112,14 @@
 
 #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
@@ -412,6 +428,7 @@
 #define		DPARERR         	0x10
 #define		SQPARERR        	0x08
 #define		ILLOPCODE       	0x04
+#define		DSCTMOUT        	0x02
 #define		ILLSADDR        	0x02
 #define		ILLHADDR        	0x01
 
@@ -436,11 +453,30 @@
 
 #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
@@ -525,14 +561,20 @@
 
 #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
 
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_seq.c
--- v2.2.9/linux/drivers/scsi/aic7xxx_seq.c	Fri Oct  9 13:27:11 1998
+++ linux/drivers/scsi/aic7xxx_seq.c	Wed Jun  9 16:59:34 1999
@@ -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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 			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 },
 
 };
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.2.9/linux/drivers/scsi/scsi.c	Tue May 11 13:10:30 1999
+++ linux/drivers/scsi/scsi.c	Mon Jun  7 10:53:03 1999
@@ -109,6 +109,7 @@
 #define BLIST_SINGLELUN 0x10
 #define BLIST_NOTQ	0x20
 #define BLIST_SPARSELUN 0x40
+#define BLIST_MAX5LUN	0x80
 
 /*
  * Data declarations.
@@ -262,6 +263,7 @@
 {"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */
 {"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
 {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* extra reset */
+{"RELISYS", "Scorpio", "*", BLIST_NOLUN},	/* responds to all LUN */
 
 /*
  * Other types of devices that have special flags.
@@ -273,6 +275,7 @@
 {"INSITE","I325VM","*", BLIST_KEY},
 {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN},
+{"REGAL","CDC-4X","*", BLIST_MAX5LUN | BLIST_SINGLELUN},
 {"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -932,6 +935,15 @@
     *max_dev_lun = 8;
     return 1;
   }
+
+  /*
+   * REGAL CDC-4X: avoid hang after LUN 4
+   */
+  if (bflags & BLIST_MAX5LUN) {
+    *max_dev_lun = 5;
+    return 1;
+  }
+
   /*
    * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI
    * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.2.9/linux/drivers/scsi/scsi.h	Tue Mar 23 14:35:48 1999
+++ linux/drivers/scsi/scsi.h	Wed Jun  9 16:59:34 1999
@@ -296,6 +296,7 @@
 #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.
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- v2.2.9/linux/drivers/scsi/scsi_proc.c	Mon Jan  4 15:08:17 1999
+++ linux/drivers/scsi/scsi_proc.c	Wed Jun  9 16:59:34 1999
@@ -298,7 +298,7 @@
 		     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
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c
--- v2.2.9/linux/drivers/scsi/scsi_syms.c	Mon Jan  4 15:08:17 1999
+++ linux/drivers/scsi/scsi_syms.c	Wed Jun  9 16:59:34 1999
@@ -27,13 +27,11 @@
 #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_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);
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- v2.2.9/linux/drivers/scsi/scsicam.c	Thu Nov 12 16:21:21 1998
+++ linux/drivers/scsi/scsicam.c	Wed Jun  9 16:59:34 1999
@@ -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 @@
 	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 @@
 }
 
 /*
- * 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 @@
  *
  */
 
-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;
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.2.9/linux/drivers/scsi/sd.c	Tue May 11 13:10:30 1999
+++ linux/drivers/scsi/sd.c	Mon Jun  7 16:51:01 1999
@@ -1729,7 +1729,7 @@
 static void sd_detach(Scsi_Device * SDp)
 {
     Scsi_Disk * dpnt;
-    int i;
+    int i, j;
     int max_p;
     int start;
 
@@ -1741,8 +1741,8 @@
 	    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 @@
 	    SDp->attached--;
 	    sd_template.dev_noticed--;
 	    sd_template.nr_dev--;
-	    SD_GENDISK(start).nr_real--;
+	    SD_GENDISK(i).nr_real--;
 	    return;
 	}
     return;
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.2.9/linux/drivers/scsi/sg.c	Tue May 11 13:10:30 1999
+++ linux/drivers/scsi/sg.c	Mon Jun  7 16:27:06 1999
@@ -16,12 +16,10 @@
  *
  *  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
@@ -34,13 +32,27 @@
  *        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.
  *
  */
@@ -67,11 +79,11 @@
 #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_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 @@
 {
     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 @@
     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 @@
     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 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 @@
     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 @@
         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;
-    }
-    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;
-        }
+        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 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 @@
     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 @@
     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 @@
     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 @@
         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 @@
     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 @@
     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 @@
     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 @@
         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 @@
     {
     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 @@
     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 @@
         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 @@
            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 @@
         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 @@
 }
 
 /* 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 @@
     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 @@
       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 @@
 /* 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 @@
         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 @@
             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 @@
 
     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 @@
         }
         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 @@
 #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 @@
         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 @@
             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 @@
             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(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;
+            }
         }
-        sg_free(srp, srp->data.buffer, srp->data.sglist_len, 
-                srp->data.mem_src);
+    }
+    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);
-    }
-    if (0 == sg_remove_request(srp->parentfp, srp)) {
-        SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n", 
-                                   srp));
+        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;
     }
-    return 0;
+    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")); 
+    }
+    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 @@
     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 @@
                    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 @@
            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 @@
         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 @@
                 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 @@
     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 @@
     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 @@
     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 @@
                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);
 }
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.2.9/linux/drivers/scsi/sr_ioctl.c	Tue May 11 13:10:30 1999
+++ linux/drivers/scsi/sr_ioctl.c	Fri May 14 16:04:16 1999
@@ -122,11 +122,9 @@
             if (!quiet)
 		printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
 		       "REQUEST.\n", target);
-            if ((SCpnt->sense_buffer[12] == 0x20 ||
-	        SCpnt->sense_buffer[12] == 0x24) &&
+            if (SCpnt->sense_buffer[12] == 0x20 &&
                 SCpnt->sense_buffer[13] == 0x00) {
                 /* sense: Invalid command operation code */
-                /* or Invalid field in cdb */
                 err = -EDRIVE_CANT_DO_THIS;
             } else {
                 err = -EINVAL;
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.2.9/linux/drivers/scsi/st.c	Wed Mar 10 15:29:47 1999
+++ linux/drivers/scsi/st.c	Sat May 22 14:51:26 1999
@@ -11,7 +11,7 @@
   Copyright 1992 - 1999 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Sun Mar  7 09:03:17 1999 by makisara@home
+  Last modified: Tue May 18 09:29:52 1999 by makisara@home
   Some small formal changes - aeb, 950809
 */
 
@@ -164,8 +164,6 @@
 	   SCpnt->request_bufflen);
     if (driver_byte(result) & DRIVER_SENSE)
       print_sense("st", SCpnt);
-    else
-      printk("\n");
   }
   else
 #endif
@@ -289,6 +287,7 @@
   }
   else
       bp = (STp->buffer)->b_data;
+  SCpnt->cmd_len = 0;
   SCpnt->request.sem = &(STp->sem);
   SCpnt->request.rq_status = RQ_SCSI_BUSY;
   SCpnt->request.rq_dev = STp->devt;
@@ -3380,7 +3379,6 @@
 
    tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
    tpnt->dirty = 0;
-   tpnt->waiting = NULL;
    tpnt->in_use = 0;
    tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
    tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v2.2.9/linux/drivers/scsi/st.h	Wed Sep  9 14:51:09 1998
+++ linux/drivers/scsi/st.h	Sat May 22 14:51:26 1999
@@ -65,7 +65,6 @@
 typedef struct {
   kdev_t devt;
   unsigned capacity;
-  struct wait_queue * waiting;
   Scsi_Device* device;
   struct semaphore sem;
   ST_buffer * buffer;
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.2.9/linux/drivers/scsi/sym53c8xx.c	Fri Apr 16 14:47:31 1999
+++ linux/drivers/scsi/sym53c8xx.c	Sat May 22 13:42:53 1999
@@ -572,6 +572,8 @@
 #define remap_pci_mem(base, size)	((u_long) __va(base))
 #define unmap_pci_mem(vaddr, size)
 #define pcivtobus(p)			((p) & pci_dvma_mask)
+#elif defined(__alpha__)
+#define pcivtobus(p)			((p) & 0xfffffffful)
 #else	/* __sparc__ */
 #define pcivtobus(p)			(p)
 
diff -u --recursive --new-file v2.2.9/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.2.9/linux/drivers/sound/es1370.c	Fri Apr 16 14:47:31 1999
+++ linux/drivers/sound/es1370.c	Sat May 22 13:05:43 1999
@@ -33,8 +33,8 @@
  *            to make the card a four channel one: use dsp to output two
  *            channels to LINE and dac to output the other two channels to
  *            SPKR. Set the mixer to only output synth to SPKR.
- *   micz     it looks like this changes the MIC input impedance. I don't know
- *            any detail though.
+ *   micbias  sets the +5V bias to the mic if using an electretmic.
+ *            
  *
  *  Note: sync mode is not yet supported (i.e. running dsp and dac from the same
  *  clock source)
@@ -92,6 +92,12 @@
  *                     Alpha fixes reported by Peter Jones <pjones@redhat.com>
  *                     Note: joystick address handling might still be wrong on archs
  *                     other than i386
+ *    10.05.99   0.21  Added support for an electret mic for SB PCI64
+ *                     to the Linux kernel sound driver. This mod also straighten
+ *                     out the question marks around the mic impedance setting
+ *                     (micz). From Kim.Berts@fisub.mail.abb.com
+ *    11.05.99   0.22  Implemented the IMIX call to mute recording monitor.
+ *                     Guenter Geiger <geiger@epy.co.at>
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -107,8 +113,8 @@
  * The card uses a 22.5792 MHz crystal.
  * The LINEIN jack may be converted to an AOUT jack by
  * setting pin 47 (XCTL0) of the ES1370 to high.
- * Pin 48 (XCTL1) of the ES1370 presumably changes the input impedance of the
- * MIC jack.
+ * Pin 48 (XCTL1) of the ES1370 sets the +5V bias for an electretmic
+ * 
  *
  */
 
@@ -190,7 +196,7 @@
 #define DAC2_DIVTOSR(x) (1411200/((x)+2))
 
 #define CTRL_ADC_STOP   0x80000000  /* 1 = ADC stopped */
-#define CTRL_XCTL1      0x40000000  /* ? mic impedance */
+#define CTRL_XCTL1      0x40000000  /* electret mic bias */
 #define CTRL_OPEN       0x20000000  /* no function, can be read and written */
 #define CTRL_PCLKDIV    0x1fff0000  /* ADC/DAC2 clock divider */
 #define CTRL_SH_PCLKDIV 16
@@ -301,6 +307,7 @@
 		unsigned int recsrc;
 		unsigned int modcnt;
 		unsigned short micpreamp;
+	        unsigned int imix;
 	} mix;
 
 	/* wave stuff */
@@ -839,7 +846,8 @@
 			return put_user(s->mix.recsrc, (int *)arg);
 			
                 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+			val = SOUND_MASK_IMIX;
+			for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 				if (mixtable[i].avail)
 					val |= 1 << i;
 			return put_user(val, (int *)arg);
@@ -858,6 +866,9 @@
 			
                 case SOUND_MIXER_CAPS:
 			return put_user(0, (int *)arg);
+		
+		case SOUND_MIXER_IMIX:
+			return put_user(s->mix.imix, (int *)arg);
 
 		default:
 			i = _IOC_NR(cmd);
@@ -870,6 +881,14 @@
 		return -EINVAL;
 	s->mix.modcnt++;
 	switch (_IOC_NR(cmd)) {
+
+	case SOUND_MIXER_IMIX:
+		if (arg == 0) 
+			return -EFAULT;
+		get_user_ret(s->mix.imix,(int *)arg, -EFAULT);
+		val = s->mix.recsrc;
+		/* fall through */
+
 	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
 		get_user_ret(val, (int *)arg, -EFAULT);
 		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
@@ -886,7 +905,10 @@
 		wrcodec(s, 0x13, j & 0xaa);
 		wrcodec(s, 0x14, (j >> 8) & 0x17);
 		wrcodec(s, 0x15, (j >> 8) & 0x0f);
-		i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc30;
+		i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
+		if (!s->mix.imix) {
+		     i &= 0xff60;  /* mute record and line monitor */
+		}
 		wrcodec(s, 0x10, i);
 		wrcodec(s, 0x11, i >> 8);
 		return 0;
@@ -2262,7 +2284,7 @@
 static int joystick[NR_DEVICE] = { 0, };
 #endif
 static int lineout[NR_DEVICE] = { 0, };
-static int micz[NR_DEVICE] = { 0, };
+static int micbias[NR_DEVICE] = { 0, };
 
 /* --------------------------------------------------------------------- */
 
@@ -2295,7 +2317,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.20 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.22 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
@@ -2328,8 +2350,10 @@
 			goto err_irq;
 		}
 		/* initialize codec registers */
-		s->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
-		if (joystick[index]) {
+		/* note: setting CTRL_SERR_DIS is reported to break
+		 * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
+	        s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
+	        if (joystick[index]) {
 			if (check_region(0x200, JOY_EXTENT))
 				printk(KERN_ERR "es1370: io port 0x200 in use\n");
 			else
@@ -2337,7 +2361,7 @@
 		}
 		if (lineout[index])
 			s->ctrl |= CTRL_XCTL0;
-		if (micz[index])
+		if (micbias[index])
 			s->ctrl |= CTRL_XCTL1;
 		s->sctrl = 0;
 		printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n"
@@ -2361,6 +2385,7 @@
 		wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!!  */
 		wrcodec(s, 0x18, 0); /* recording source is mixer */
 		wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */
+		s->mix.imix = 1;
 		fs = get_fs();
 		set_fs(KERNEL_DS);
 		val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD;
@@ -2403,8 +2428,8 @@
 MODULE_PARM_DESC(joystick, "if 1 enables joystick interface (still need separate driver)");
 MODULE_PARM(lineout, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out");
-MODULE_PARM(micz, "1-" __MODULE_STRING(NR_DEVICE) "i");
-MODULE_PARM_DESC(micz, "changes (??) the microphone impedance");
+MODULE_PARM(micbias, "1-" __MODULE_STRING(NR_DEVICE) "i");
+MODULE_PARM_DESC(micbias, "sets the +5V bias for an electret microphone");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("ES1370 AudioPCI Driver");
diff -u --recursive --new-file v2.2.9/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- v2.2.9/linux/drivers/sound/sound_core.c	Wed Mar 10 15:29:47 1999
+++ linux/drivers/sound/sound_core.c	Mon Jun  7 11:06:06 1999
@@ -52,6 +52,22 @@
 	struct sound_unit *next;
 };
 
+#ifdef CONFIG_SOUND_SONICVIBES
+extern int init_sonicvibes(void);
+#endif
+#ifdef CONFIG_SOUND_ES1370
+extern int init_es1370(void);
+#endif
+#ifdef CONFIG_SOUND_ES1371
+extern int init_es1371(void);
+#endif
+#ifdef CONFIG_SOUND_MSNDCLAS
+extern int msnd_classic_init(void);
+#endif
+#ifdef CONFIG_SOUND_MSNDPIN
+extern int msnd_pinnacle_init(void);
+#endif
+
 /*
  *	Low level list operator. Scan the ordered list, find a hole and
  *	join into it. Called with the lock asserted
@@ -132,7 +148,7 @@
  *	This lock guards the sound loader list.
  */
 
-static spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  *	Allocate the controlling structure and add it to the sound driver
diff -u --recursive --new-file v2.2.9/linux/drivers/video/cgsixfb.c linux/drivers/video/cgsixfb.c
--- v2.2.9/linux/drivers/video/cgsixfb.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/video/cgsixfb.c	Sat May 29 11:10:15 1999
@@ -1,4 +1,4 @@
-/* $Id: cgsixfb.c,v 1.16 1999/03/09 14:01:49 davem Exp $
+/* $Id: cgsixfb.c,v 1.16.2.1 1999/05/25 00:59:35 davem Exp $
  * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -588,7 +588,7 @@
 	p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin);
 }
 
-static char idstring[60] __initdata = { 0 };
+static char idstring[70] __initdata = { 0 };
 
 __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb))
 {
@@ -599,6 +599,7 @@
 	unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
 	u32 conf;
 	char *p;
+	char *cardtype;
 	struct bt_regs *bt;
 
 	strcpy(fb->info.modename, "CGsix");
@@ -656,15 +657,29 @@
 	case CG6_FHC_CPU_68020: p = "68020"; break;
 	default: p = "i386"; break;
 	}
+
+	if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
+		if (fix->smem_len <= 0x100000) {
+			cardtype = "TurboGX";
+		} else {
+			cardtype = "TurboGX+";
+		}
+	} else {
+		if (fix->smem_len <= 0x100000) {
+			cardtype = "GX";
+		} else {
+			cardtype = "GX+";
+		}
+	}
 	                                                                        
 	sprintf(idstring, 
 #ifdef __sparc_v9__
-		    "cgsix at %016lx TEC Rev %x CPU %s Rev %x", phys, 
+		    "cgsix at %016lx TEC Rev %x CPU %s Rev %x [%s]", phys, 
 #else	
-		    "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys, 
+		    "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x [%s]", fb->iospace, phys, 
 #endif
 		    (fb->s.cg6.thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) & CG6_THC_MISC_REV_MASK,
-		    p, conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK);
+		    p, conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK, cardtype);
 		    
 	cg6_reset(fb);
 		    
diff -u --recursive --new-file v2.2.9/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.2.9/linux/drivers/video/fbcon.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/video/fbcon.c	Fri May 14 12:49:59 1999
@@ -2300,3 +2300,4 @@
 EXPORT_SYMBOL(fb_display);
 EXPORT_SYMBOL(fbcon_redraw_bmove);
 EXPORT_SYMBOL(fbcon_dummy);
+EXPORT_SYMBOL(fb_con);
diff -u --recursive --new-file v2.2.9/linux/drivers/video/mdacon.c linux/drivers/video/mdacon.c
--- v2.2.9/linux/drivers/video/mdacon.c	Wed Mar 10 15:29:48 1999
+++ linux/drivers/video/mdacon.c	Fri May 14 17:46:16 1999
@@ -597,7 +597,7 @@
 	if (mda_first_vc > mda_last_vc)
 		return;
 
-	take_over_console(&mda_con, mda_first_vc, mda_last_vc, 0);
+	take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.2.9/linux/fs/Config.in linux/fs/Config.in
--- v2.2.9/linux/fs/Config.in	Wed Mar 10 15:29:48 1999
+++ linux/fs/Config.in	Wed Jun  9 18:42:05 1999
@@ -69,9 +69,9 @@
   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
diff -u --recursive --new-file v2.2.9/linux/fs/adfs/dir.c linux/fs/adfs/dir.c
--- v2.2.9/linux/fs/adfs/dir.c	Thu May 13 23:10:30 1999
+++ linux/fs/adfs/dir.c	Thu May 13 23:25:58 1999
@@ -138,9 +138,6 @@
 	struct super_block *sb;
 	int i, size;
 
-	if (!inode)
-		return 0;
-
 	sb = inode->i_sb;
 
 	size = 2048 >> sb->s_blocksize_bits;
diff -u --recursive --new-file v2.2.9/linux/fs/adfs/namei.c linux/fs/adfs/namei.c
--- v2.2.9/linux/fs/adfs/namei.c	Tue May 11 13:10:30 1999
+++ linux/fs/adfs/namei.c	Thu May 13 23:25:58 1999
@@ -46,9 +46,6 @@
 	unsigned long parent_object_id, dir_object_id;
 	int buffers, pos;
 
-	if (!S_ISDIR(dir->i_mode))
-		return 0;
-
 	sb = dir->i_sb;
 
 	if (adfs_inode_validate (dir)) {
@@ -56,9 +53,6 @@
 			    "invalid inode number: %lu", dir->i_ino);
 		return 0;
 	}
-
-	if (namelen > ADFS_NAME_LEN)
-		return 0;
 
 	if (!(buffers = adfs_dir_read (dir, bh))) {
 		adfs_error (sb, "adfs_find_entry", "unable to read directory");
diff -u --recursive --new-file v2.2.9/linux/fs/autofs/dir.c linux/fs/autofs/dir.c
--- v2.2.9/linux/fs/autofs/dir.c	Wed Apr 28 11:37:30 1999
+++ linux/fs/autofs/dir.c	Thu May 13 23:25:58 1999
@@ -16,8 +16,6 @@
 			       void *dirent, filldir_t filldir)
 {
 	struct inode *inode=filp->f_dentry->d_inode;
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -ENOTDIR;
 
 	switch((unsigned long) filp->f_pos)
 	{
diff -u --recursive --new-file v2.2.9/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.2.9/linux/fs/autofs/root.c	Tue May 11 13:10:30 1999
+++ linux/fs/autofs/root.c	Thu May 13 23:25:58 1999
@@ -72,9 +72,6 @@
 	struct inode * inode = filp->f_dentry->d_inode;
 	off_t onr, nr;
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -ENOTDIR;
-
 	sbi = autofs_sbi(inode->i_sb);
 	dirhash = &sbi->dirhash;
 	nr = filp->f_pos;
diff -u --recursive --new-file v2.2.9/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.2.9/linux/fs/binfmt_elf.c	Tue May 11 13:10:30 1999
+++ linux/fs/binfmt_elf.c	Sun Jun 13 10:50:04 1999
@@ -449,6 +449,8 @@
 
 	retval = -ENOMEM;
 	size = elf_ex.e_phentsize * elf_ex.e_phnum;
+	if (size > 65536)
+		goto out;
 	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
 	if (!elf_phdata)
 		goto out;
diff -u --recursive --new-file v2.2.9/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.2.9/linux/fs/block_dev.c	Thu Nov 19 09:56:28 1998
+++ linux/fs/block_dev.c	Fri May 28 09:20:36 1999
@@ -273,6 +273,8 @@
 			if (++bhe == &buflist[NBUF])
 				bhe = buflist;
 		} while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
+		if (bhe == bhb && !blocks)
+			break;
 	} while (left > 0);
 
 /* Release the read-ahead blocks */
diff -u --recursive --new-file v2.2.9/linux/fs/coda/inode.c linux/fs/coda/inode.c
--- v2.2.9/linux/fs/coda/inode.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/coda/inode.c	Mon Jun  7 16:27:06 1999
@@ -145,7 +145,7 @@
         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));
diff -u --recursive --new-file v2.2.9/linux/fs/coda/psdev.c linux/fs/coda/psdev.c
--- v2.2.9/linux/fs/coda/psdev.c	Fri Jan  8 22:36:13 1999
+++ linux/fs/coda/psdev.c	Wed Jun  2 11:29:28 1999
@@ -2,7 +2,7 @@
  *      	An implementation of a loadable kernel mode driver providing
  *		multiple kernel/user space bidirectional communications links.
  *
- * 		Author: 	Alan Cox <alan@cymru.net>
+ * 		Author: 	Alan Cox <alan@redhat.com>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
diff -u --recursive --new-file v2.2.9/linux/fs/exec.c linux/fs/exec.c
--- v2.2.9/linux/fs/exec.c	Tue May 11 13:10:30 1999
+++ linux/fs/exec.c	Sun Jun 13 10:50:04 1999
@@ -257,7 +257,11 @@
 			set_fs(KERNEL_DS);
 		get_user(str, argv+argc);
 		if (!str)
-			panic("VFS: argc is wrong");
+		{
+			set_fs(old_fs);
+			return 0;
+//			panic("VFS: argc is wrong");
+		}
 		if (from_kmem == 1)
 			set_fs(old_fs);
 		len = strlen_user(str);	/* includes the '\0' */
diff -u --recursive --new-file v2.2.9/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.2.9/linux/fs/ext2/file.c	Tue Dec 22 14:16:57 1998
+++ linux/fs/ext2/file.c	Tue Jun  1 12:43:35 1999
@@ -162,7 +162,7 @@
 	struct buffer_head * bh, *bufferlist[NBUF];
 	struct super_block * sb;
 	int err;
-	int i,buffercount,write_error;
+	int i,buffercount,write_error, new_buffer;
 
 	/* POSIX: mtime/ctime may not change for 0 count */
 	if (!count)
@@ -247,30 +247,59 @@
 		}
 		if (c > count)
 			c = count;
-		if (c != sb->s_blocksize && !buffer_uptodate(bh)) {
-			ll_rw_block (READ, 1, &bh);
-			wait_on_buffer (bh);
-			if (!buffer_uptodate(bh)) {
-				brelse (bh);
+
+		/* Tricky: what happens if we are writing the complete
+		 * contents of a block which is not currently
+		 * initialised?  We have to obey the same
+		 * synchronisation rules as the IO code, to prevent some
+		 * other process from stomping on the buffer contents by
+		 * refreshing them from disk while we are setting up the
+		 * buffer.  The copy_from_user() can page fault, after
+		 * all.  We also have to throw away partially successful
+		 * copy_from_users to such buffers, since we can't trust
+		 * the rest of the buffer_head in that case.  --sct */
+
+		new_buffer = (!buffer_uptodate(bh) && !buffer_locked(bh) &&
+			      c == sb->s_blocksize);
+
+		if (new_buffer) {
+			set_bit(BH_Lock, &bh->b_state);
+			c -= copy_from_user (bh->b_data + offset, buf, c);
+			if (c != sb->s_blocksize) {
+				c = 0;
+				unlock_buffer(bh);
+				brelse(bh);
 				if (!written)
-					written = -EIO;
+					written = -EFAULT;
 				break;
 			}
+			mark_buffer_uptodate(bh, 1);
+			unlock_buffer(bh);
+		} else {
+			if (!buffer_uptodate(bh)) {
+				ll_rw_block (READ, 1, &bh);
+				wait_on_buffer (bh);
+				if (!buffer_uptodate(bh)) {
+					brelse (bh);
+					if (!written)
+						written = -EIO;
+					break;
+				}
+			}
+			c -= copy_from_user (bh->b_data + offset, buf, c);
 		}
-		c -= copy_from_user (bh->b_data + offset, buf, c);
 		if (!c) {
 			brelse(bh);
 			if (!written)
 				written = -EFAULT;
 			break;
 		}
+		mark_buffer_dirty(bh, 0);
 		update_vm_cache(inode, pos, bh->b_data + offset, c);
 		pos += c;
 		written += c;
 		buf += c;
 		count -= c;
-		mark_buffer_uptodate(bh, 1);
-		mark_buffer_dirty(bh, 0);
 
 		if (filp->f_flags & O_SYNC)
 			bufferlist[buffercount++] = bh;
diff -u --recursive --new-file v2.2.9/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.2.9/linux/fs/ext2/namei.c	Tue May 11 13:10:31 1999
+++ linux/fs/ext2/namei.c	Thu May 13 23:25:58 1999
@@ -869,7 +869,8 @@
 		if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
 			goto end_rename;
 		retval = -EMLINK;
-		if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX)
+		if (!new_inode && new_dir!=old_dir &&
+				new_dir->i_nlink >= EXT2_LINK_MAX)
 			goto end_rename;
 	}
 	if (!new_bh) {
diff -u --recursive --new-file v2.2.9/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c
--- v2.2.9/linux/fs/ext2/truncate.c	Fri Oct  9 13:27:13 1998
+++ linux/fs/ext2/truncate.c	Thu May 13 17:37:23 1999
@@ -407,7 +407,8 @@
 			break;
 		if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
 			ext2_sync_inode (inode);
-		current->counter = 0;
+		run_task_queue(&tq_disk);
+		current->policy |= SCHED_YIELD;
 		schedule ();
 	}
 	/*
diff -u --recursive --new-file v2.2.9/linux/fs/hfs/dir_cap.c linux/fs/hfs/dir_cap.c
--- v2.2.9/linux/fs/hfs/dir_cap.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/hfs/dir_cap.c	Thu May 13 23:25:58 1999
@@ -237,10 +237,6 @@
         struct hfs_cat_entry *entry;
 	struct inode *dir = filp->f_dentry->d_inode;
 
-	if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
-		return -EBADF;
-	}
-
 	entry = HFS_I(dir)->entry;
 	type = HFS_ITYPE(dir->i_ino);
 	skip_dirs = (type == HFS_CAP_RDIR);
diff -u --recursive --new-file v2.2.9/linux/fs/hfs/dir_dbl.c linux/fs/hfs/dir_dbl.c
--- v2.2.9/linux/fs/hfs/dir_dbl.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/hfs/dir_dbl.c	Thu May 13 23:25:58 1999
@@ -202,10 +202,6 @@
         struct hfs_cat_entry *entry;
 	struct inode *dir = filp->f_dentry->d_inode;
 
-	if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
-		return -EBADF;
-	}
-
 	entry = HFS_I(dir)->entry;
 
 	if (filp->f_pos == 0) {
diff -u --recursive --new-file v2.2.9/linux/fs/hfs/dir_nat.c linux/fs/hfs/dir_nat.c
--- v2.2.9/linux/fs/hfs/dir_nat.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/hfs/dir_nat.c	Thu May 13 23:25:58 1999
@@ -225,10 +225,6 @@
         struct hfs_cat_entry *entry;
 	struct inode *dir = filp->f_dentry->d_inode;
 
-	if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
-		return -EBADF;
-	}
-
 	entry = HFS_I(dir)->entry;
 	type = HFS_ITYPE(dir->i_ino);
 	skip_dirs = (type == HFS_NAT_HDIR);
diff -u --recursive --new-file v2.2.9/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.2.9/linux/fs/minix/namei.c	Tue May 11 13:10:31 1999
+++ linux/fs/minix/namei.c	Thu May 13 23:25:58 1999
@@ -45,8 +45,6 @@
 	struct minix_dir_entry *de;
 
 	*res_dir = NULL;
-	if (!dir->i_sb)
-		return NULL;
 	info = &dir->i_sb->u.minix_sb;
 	if (namelen > info->s_namelen) {
 #ifdef NO_TRUNCATE
@@ -161,8 +159,6 @@
 
 	*res_buf = NULL;
 	*res_dir = NULL;
-	if (!dir || !dir->i_sb)
-		return -ENOENT;
 	info = &dir->i_sb->u.minix_sb;
 	if (namelen > info->s_namelen) {
 #ifdef NO_TRUNCATE
@@ -342,8 +338,6 @@
 	struct minix_dir_entry * de;
 	struct minix_sb_info * info;
 
-	if (!inode || !inode->i_sb)
-		return 1;
 	info = &inode->i_sb->u.minix_sb;
 	block = 0;
 	bh = NULL;
@@ -442,26 +436,12 @@
 	struct buffer_head * bh;
 	struct minix_dir_entry * de;
 
-repeat:
 	retval = -ENOENT;
-	inode = NULL;
+	inode = dentry->d_inode;
 	bh = minix_find_entry(dir, dentry->d_name.name,
 			      dentry->d_name.len, &de);
-	if (!bh)
-		goto end_unlink;
-	inode = dentry->d_inode;
-
-	retval = -EPERM;
-	if (de->inode != inode->i_ino) {
-		brelse(bh);
-		current->counter = 0;
-		schedule();
-		goto repeat;
-	}
-	if (de->inode != inode->i_ino) {
-		retval = -ENOENT;
+	if (!bh || de->inode != inode->i_ino)
 		goto end_unlink;
-	}
 	if (!inode->i_nlink) {
 		printk("Deleting nonexistent file (%s:%lu), %d\n",
 			kdevname(inode->i_dev),
@@ -562,12 +542,6 @@
 (((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode)
 
 /*
- * rename uses retrying to avoid race-conditions: at least they should be minimal.
- * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
- * checks fail, it tries to restart itself again. Very practical - no changes
- * are done until we know everything works ok.. and then all the changes can be
- * done in one fell swoop when we have claimed all the buffers needed.
- *
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
@@ -581,24 +555,15 @@
 	int retval;
 
 	info = &old_dir->i_sb->u.minix_sb;
-	goto start_up;
-try_again:
-	brelse(old_bh);
-	brelse(new_bh);
-	brelse(dir_bh);
-	current->counter = 0;
-	schedule();
-start_up:
-	old_inode = new_inode = NULL;
-	old_bh = new_bh = dir_bh = NULL;
+	new_bh = dir_bh = NULL;
+	old_inode = old_dentry->d_inode;
+	new_inode = new_dentry->d_inode;
 	old_bh = minix_find_entry(old_dir, old_dentry->d_name.name,
 				  old_dentry->d_name.len, &old_de);
 	retval = -ENOENT;
-	if (!old_bh)
+	if (!old_bh || old_de->inode != old_inode->i_ino)
 		goto end_rename;
-	old_inode = old_dentry->d_inode;
 	retval = -EPERM;
-	new_inode = new_dentry->d_inode;
 	new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
 				  new_dentry->d_name.len, &new_de);
 	if (new_bh) {
@@ -620,7 +585,8 @@
 		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 			goto end_rename;
 		retval = -EMLINK;
-		if (!new_inode && new_dir->i_nlink >= info->s_link_max)
+		if (!new_inode && new_dir != old_dir &&
+				new_dir->i_nlink >= info->s_link_max)
 			goto end_rename;
 	}
 	if (!new_bh) {
@@ -631,22 +597,15 @@
 		if (retval)
 			goto end_rename;
 	}
-/* sanity checking before doing the rename - avoid races */
-	if (new_inode && (new_de->inode != new_inode->i_ino))
-		goto try_again;
-	if (new_de->inode && !new_inode)
-		goto try_again;
-	if (old_de->inode != old_inode->i_ino)
-		goto try_again;
 /* ok, that's it */
-	old_de->inode = 0;
 	new_de->inode = old_inode->i_ino;
+	old_de->inode = 0;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	mark_inode_dirty(old_dir);
 	old_dir->i_version = ++event;
+	mark_inode_dirty(old_dir);
 	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
-	mark_inode_dirty(new_dir);
 	new_dir->i_version = ++event;
+	mark_inode_dirty(new_dir);
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME;
diff -u --recursive --new-file v2.2.9/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.2.9/linux/fs/ncpfs/dir.c	Tue May 11 13:10:31 1999
+++ linux/fs/ncpfs/dir.c	Fri May 14 12:43:13 1999
@@ -38,8 +38,7 @@
 static int c_seen_eof;
 static int c_last_returned_index;
 static struct ncp_dirent *c_entry = NULL;
-static int c_lock = 0;
-static struct wait_queue *c_wait = NULL;
+static struct semaphore c_sem = MUTEX;
 
 static int ncp_read_volume_list(struct ncp_server *, int, int,
 					struct ncp_dirent *);
@@ -230,15 +229,12 @@
 
 static inline void ncp_lock_dircache(void)
 {
-	while (c_lock)
-		sleep_on(&c_wait);
-	c_lock = 1;
+	down(&c_sem);
 }
 
 static inline void ncp_unlock_dircache(void)
 {
-	c_lock = 0;
-	wake_up(&c_wait);
+	up(&c_sem);
 }
 
 
@@ -354,16 +350,7 @@
 	int len = dentry->d_name.len;      
 	struct ncpfs_inode_info finfo;
 	__u8 __name[dentry->d_name.len + 1];
-
-        if (!dentry->d_inode) {
-                DPRINTK(KERN_DEBUG "ncp_lookup_validate: called with dentry->d_inode already NULL.\n");
-                return 0;
-        }
         
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk(KERN_WARNING "ncp_lookup_validate: inode is NULL or not a directory.\n");
-		goto finished;
-	}
 	server = NCP_SERVER(dir);
 
 	if (!ncp_conn_valid(server))
diff -u --recursive --new-file v2.2.9/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c
--- v2.2.9/linux/fs/ncpfs/file.c	Wed Aug 26 11:37:41 1998
+++ linux/fs/ncpfs/file.c	Wed Jun  2 11:30:30 1999
@@ -21,7 +21,7 @@
 #include <linux/ncp_fs.h>
 #include "ncplib_kernel.h"
 
-static inline int min(int a, int b)
+static inline unsigned int min(unsigned int a, unsigned int b)
 {
 	return a < b ? a : b;
 }
@@ -99,7 +99,10 @@
 	struct inode *inode = dentry->d_inode;
 	size_t already_read = 0;
 	off_t pos;
-	int bufsize, error;
+	size_t bufsize;
+	int error;
+	void* freepage;
+	size_t freelen;
 
 	DPRINTK(KERN_DEBUG "ncp_file_read: enter %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -119,10 +122,12 @@
 		goto out;
 	}
 
-	pos = file->f_pos;
+	pos = *ppos;
+/* leave it out on server ...
 	if (pos + count > inode->i_size) {
 		count = inode->i_size - pos;
 	}
+*/
 	error = 0;
 	if (!count)	/* size_t is never < 0 */
 		goto out;
@@ -135,16 +140,24 @@
 
 	bufsize = NCP_SERVER(inode)->buffer_size;
 
+	error = -EIO;
+	freelen = ncp_read_bounce_size(bufsize);
+	freepage = kmalloc(freelen, GFP_NFS);
+	if (!freepage)
+		goto out;
+	error = 0;
 	/* First read in as much as possible for each bufsize. */
 	while (already_read < count) {
 		int read_this_time;
-		int to_read = min(bufsize - (pos % bufsize),
+		size_t to_read = min(bufsize - (pos % bufsize),
 				  count - already_read);
 
-		error = ncp_read(NCP_SERVER(inode),
+		error = ncp_read_bounce(NCP_SERVER(inode),
 			 	NCP_FINFO(inode)->file_handle,
-				pos, to_read, buf, &read_this_time);
+				pos, to_read, buf, &read_this_time, 
+				freepage, freelen);
 		if (error) {
+			kfree(freepage);
 			error = -EIO;	/* This is not exact, i know.. */
 			goto out;
 		}
@@ -152,12 +165,13 @@
 		buf += read_this_time;
 		already_read += read_this_time;
 
-		if (read_this_time < to_read) {
+		if (read_this_time != to_read) {
 			break;
 		}
 	}
+	kfree(freepage);
 
-	file->f_pos = pos;
+	*ppos = pos;
 
 	if (!IS_RDONLY(inode)) {
 		inode->i_atime = CURRENT_TIME;
@@ -176,7 +190,9 @@
 	struct inode *inode = dentry->d_inode;
 	size_t already_written = 0;
 	off_t pos;
-	int bufsize, errno;
+	size_t bufsize;
+	int errno;
+	void* bouncebuffer;
 
 	DPRINTK(KERN_DEBUG "ncp_file_write: enter %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -201,7 +217,7 @@
 		printk(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
 		return errno;
 	}
-	pos = file->f_pos;
+	pos = *ppos;
 
 	if (file->f_flags & O_APPEND) {
 		pos = inode->i_size;
@@ -210,27 +226,36 @@
 
 	already_written = 0;
 
+	bouncebuffer = kmalloc(bufsize, GFP_NFS);
+	if (!bouncebuffer)
+		return -EIO;	/* -ENOMEM */
 	while (already_written < count) {
 		int written_this_time;
-		int to_write = min(bufsize - (pos % bufsize),
+		size_t to_write = min(bufsize - (pos % bufsize),
 				   count - already_written);
 
-		if (ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
-			  pos, to_write, buf, &written_this_time) != 0) {
-			return -EIO;
+		if (copy_from_user(bouncebuffer, buf, to_write)) {
+			errno = -EFAULT;
+			break;
+		}
+		if (ncp_write_kernel(NCP_SERVER(inode), 
+		    NCP_FINFO(inode)->file_handle,
+		    pos, to_write, buf, &written_this_time) != 0) {
+			errno = -EIO;
+			break;
 		}
 		pos += written_this_time;
 		buf += written_this_time;
 		already_written += written_this_time;
 
-		if (written_this_time < to_write) {
+		if (written_this_time != to_write) {
 			break;
 		}
 	}
-
+	kfree(bouncebuffer);
 	inode->i_mtime = inode->i_atime = CURRENT_TIME;
 	
-	file->f_pos = pos;
+	*ppos = pos;
 
 	if (pos > inode->i_size) {
 		inode->i_size = pos;
diff -u --recursive --new-file v2.2.9/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.2.9/linux/fs/ncpfs/inode.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/ncpfs/inode.c	Fri May 14 12:43:13 1999
@@ -346,11 +346,12 @@
 						   GFP_KERNEL);
 	if (server == NULL)
 		goto out_no_server;
+	memset(server, 0, sizeof(*server));
 	NCP_SBP(sb) = server;
 
 	server->ncp_filp = ncp_filp;
 	server->lock = 0;
-	server->wait = NULL;
+	sema_init(&server->sem, 1);
 	server->packet = NULL;
 	server->buffer_size = 0;
 	server->conn_status = 0;
@@ -687,7 +688,7 @@
 		if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
 			return -EACCES;
 		}
-		ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
+		ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
 			  attr->ia_size, 0, "", &written);
 
 		/* According to ndir, the changes only take effect after
diff -u --recursive --new-file v2.2.9/linux/fs/ncpfs/ioctl.c linux/fs/ncpfs/ioctl.c
--- v2.2.9/linux/fs/ncpfs/ioctl.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/ncpfs/ioctl.c	Wed May 26 09:27:46 1999
@@ -33,6 +33,7 @@
 	int result;
 	struct ncp_ioctl_request request;
 	struct ncp_fs_info info;
+	char* bouncebuffer;
 
 #ifdef NCP_IOC_GETMOUNTUID_INT
 	/* remove after ncpfs-2.0.13/2.2.0 gets released */
@@ -57,12 +58,9 @@
 		    && (current->uid != server->m.mounted_uid)) {
 			return -EACCES;
 		}
-		if ((result = verify_area(VERIFY_READ, (char *) arg,
-					  sizeof(request))) != 0) {
-			return result;
-		}
-		copy_from_user(&request, (struct ncp_ioctl_request *) arg,
-			       sizeof(request));
+		if (copy_from_user(&request, (struct ncp_ioctl_request *) arg,
+			       sizeof(request)))
+			return -EFAULT;
 
 		if ((request.function > 255)
 		    || (request.size >
@@ -73,6 +71,13 @@
 					  NCP_PACKET_SIZE)) != 0) {
 			return result;
 		}
+		bouncebuffer = kmalloc(NCP_PACKET_SIZE, GFP_NFS);
+		if (!bouncebuffer)
+			return -ENOMEM;
+		if (copy_from_user(bouncebuffer, request.data, request.size)) {
+			kfree(bouncebuffer);
+			return -EFAULT;
+		}
 		ncp_lock_server(server);
 
 		/* FIXME: We hack around in the server's structures
@@ -80,17 +85,22 @@
 
 		server->has_subfunction = 0;
 		server->current_size = request.size;
-		copy_from_user(server->packet, request.data, request.size);
-
-		ncp_request(server, request.function);
-
-		DPRINTK(KERN_DEBUG "ncp_ioctl: copy %d bytes\n",
-			server->reply_size);
-		copy_to_user(request.data, server->packet, server->reply_size);
+		memcpy(server->packet, bouncebuffer, request.size);
 
+		result = ncp_request2(server, request.function, 
+			bouncebuffer, NCP_PACKET_SIZE);
+		if (result < 0)
+			result = -EIO;
+		else
+			result = server->reply_size;
 		ncp_unlock_server(server);
-
-		return server->reply_size;
+		DPRINTK(KERN_DEBUG "ncp_ioctl: copy %d bytes\n",
+			result);
+		if (result >= 0)
+			if (copy_to_user(request.data, bouncebuffer, result))
+				result = -EFAULT;
+		kfree(bouncebuffer);
+		return result;
 
 	case NCP_IOC_CONN_LOGGED_IN:
 
diff -u --recursive --new-file v2.2.9/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- v2.2.9/linux/fs/ncpfs/mmap.c	Wed Mar 10 15:29:49 1999
+++ linux/fs/ncpfs/mmap.c	Fri May 14 12:43:13 1999
@@ -37,11 +37,10 @@
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	unsigned long page;
-	unsigned int clear;
-	unsigned long tmp;
+	unsigned int already_read;
+	unsigned int count;
 	int bufsize;
 	int pos;
-	mm_segment_t fs;
 
 	page = __get_free_page(GFP_KERNEL);
 	if (!page)
@@ -49,35 +48,24 @@
 	address &= PAGE_MASK;
 	pos = address - area->vm_start + area->vm_offset;
 
-	clear = 0;
+	count = PAGE_SIZE;
 	if (address + PAGE_SIZE > area->vm_end) {
-		clear = address + PAGE_SIZE - area->vm_end;
+		count = area->vm_end - address;
 	}
 	/* what we can read in one go */
 	bufsize = NCP_SERVER(inode)->buffer_size;
 
-	fs = get_fs();
-	set_fs(get_ds());
-
-	if (ncp_make_open(inode, O_RDONLY) < 0) {
-		clear = PAGE_SIZE;
-	} else {
-		int already_read = 0;
-		int count = PAGE_SIZE - clear;
-		int to_read;
-
+	already_read = 0;
+	if (ncp_make_open(inode, O_RDONLY) >= 0) {
 		while (already_read < count) {
 			int read_this_time;
+			int to_read;
 
-			if ((pos % bufsize) != 0) {
-				to_read = bufsize - (pos % bufsize);
-			} else {
-				to_read = bufsize;
-			}
+			to_read = bufsize - (pos % bufsize);
 
 			to_read = min(to_read, count - already_read);
 
-			if (ncp_read(NCP_SERVER(inode),
+			if (ncp_read_kernel(NCP_SERVER(inode),
 				     NCP_FINFO(inode)->file_handle,
 				     pos, to_read,
 				     (char *) (page + already_read),
@@ -94,12 +82,9 @@
 
 	}
 
-	set_fs(fs);
-
-	tmp = page + PAGE_SIZE;
-	while (clear--) {
-		*(char *) --tmp = 0;
-	}
+	if (already_read < PAGE_SIZE)
+		memset((char*)(page + already_read), 0, 
+		       PAGE_SIZE - already_read);
 	return page;
 }
 
diff -u --recursive --new-file v2.2.9/linux/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c
--- v2.2.9/linux/fs/ncpfs/ncplib_kernel.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/ncpfs/ncplib_kernel.c	Fri May 14 12:43:13 1999
@@ -754,7 +754,7 @@
 
 /* We have to transfer to/from user space */
 int
-ncp_read(struct ncp_server *server, const char *file_id,
+ncp_read_kernel(struct ncp_server *server, const char *file_id,
 	     __u32 offset, __u16 to_read, char *target, int *bytes_read)
 {
 	char *source;
@@ -772,18 +772,27 @@
 	*bytes_read = ntohs(ncp_reply_word(server, 0));
 	source = ncp_reply_data(server, 2 + (offset & 1));
 
-	result = -EFAULT;
-	if (!copy_to_user(target, source, *bytes_read))
-		result = 0;
+	memcpy(target, source, *bytes_read);
 out:
 	ncp_unlock_server(server);
 	return result;
 }
 
+/* There is a problem... egrep and some other silly tools do:
+	x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
+	read(<ncpfs fd>, x, 32768);
+   Now copying read result by copy_to_user causes pagefault. This pagefault
+   could not be handled because of server was locked due to read. So we have
+   to use temporary buffer. So ncp_unlock_server must be done before
+   copy_to_user (and for write, copy_from_user must be done before 
+   ncp_init_request... same applies for send raw packet ioctl). Because of
+   file is normally read in bigger chunks, caller provides kmalloced 
+   (vmalloced) chunk of memory with size >= to_read...
+ */
 int
-ncp_write(struct ncp_server *server, const char *file_id,
-	      __u32 offset, __u16 to_write,
-		const char *source, int *bytes_written)
+ncp_read_bounce(struct ncp_server *server, const char *file_id,
+	 __u32 offset, __u16 to_read, char *target, int *bytes_read,
+	 void* bounce, __u32 bufsize)
 {
 	int result;
 
@@ -791,46 +800,47 @@
 	ncp_add_byte(server, 0);
 	ncp_add_mem(server, file_id, 6);
 	ncp_add_dword(server, htonl(offset));
-	ncp_add_word(server, htons(to_write));
-	ncp_add_mem_fromfs(server, source, to_write);
-
-	if ((result = ncp_request(server, 73)) != 0)
-		goto out;
-	*bytes_written = to_write;
-	result = 0;
-out:
+	ncp_add_word(server, htons(to_read));
+	result = ncp_request2(server, 72, bounce, bufsize);
 	ncp_unlock_server(server);
+	if (!result) {
+		int len = be16_to_cpu(get_unaligned((__u16*)((char*)bounce + 
+			  sizeof(struct ncp_reply_header))));
+		result = -EIO;
+		if (len <= to_read) {
+			char* source;
+
+			source = (char*)bounce + 
+			         sizeof(struct ncp_reply_header) + 2 + 
+			         (offset & 1);
+			*bytes_read = len;
+			result = 0;
+			if (copy_to_user(target, source, len))
+				result = -EFAULT;
+		}
+	}
 	return result;
 }
 
-#ifdef CONFIG_NCPFS_EXTRAS
-int
-ncp_read_kernel(struct ncp_server *server, const char *file_id,
-		__u32 offset, __u16 to_read, char *target, int *bytes_read) {
-	int error;
-	mm_segment_t old_fs;
-	
-	old_fs = get_fs();
-	set_fs(get_ds());
-	error = ncp_read(server, file_id, offset, to_read, target, bytes_read);
-	set_fs(old_fs);
-	return error;
-}
-
 int
 ncp_write_kernel(struct ncp_server *server, const char *file_id,
 		 __u32 offset, __u16 to_write,
-		 const char *source, int *bytes_written) {
-	int error;
-	mm_segment_t old_fs;
+		 const char *source, int *bytes_written)
+{
+	int result;
+
+	ncp_init_request(server);
+	ncp_add_byte(server, 0);
+	ncp_add_mem(server, file_id, 6);
+	ncp_add_dword(server, htonl(offset));
+	ncp_add_word(server, htons(to_write));
+	ncp_add_mem(server, source, to_write);
 	
-	old_fs = get_fs();
-	set_fs(get_ds());
-	error = ncp_write(server, file_id, offset, to_write, source, bytes_written);
-	set_fs(old_fs);
-	return error;
+	if ((result = ncp_request(server, 73)) == 0)
+		*bytes_written = to_write;
+	ncp_unlock_server(server);
+	return result;
 }
-#endif
 
 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
 int
@@ -876,4 +886,5 @@
 	return 0;
 }
 #endif	/* CONFIG_NCPFS_IOCTL_LOCKING */
+
 
diff -u --recursive --new-file v2.2.9/linux/fs/ncpfs/ncplib_kernel.h linux/fs/ncpfs/ncplib_kernel.h
--- v2.2.9/linux/fs/ncpfs/ncplib_kernel.h	Wed Apr 28 11:37:31 1999
+++ linux/fs/ncpfs/ncplib_kernel.h	Fri May 14 12:43:13 1999
@@ -32,20 +32,24 @@
 #include <linux/ncp_fs.h>
 #include <linux/ncp_fs_sb.h>
 
+#define NCP_MIN_SYMLINK_SIZE	8
+#define NCP_MAX_SYMLINK_SIZE	512
+
 int ncp_negotiate_buffersize(struct ncp_server *, int, int *);
 int ncp_negotiate_size_and_options(struct ncp_server *server, int size,
   			  int options, int *ret_size, int *ret_options);
 int ncp_get_volume_info_with_number(struct ncp_server *, int,
 				struct ncp_volume_info *);
 int ncp_close_file(struct ncp_server *, const char *);
-int ncp_read(struct ncp_server *, const char *, __u32, __u16, char *, int *);
-int ncp_write(struct ncp_server *, const char *, __u32, __u16,
-		const char *, int *);
-#ifdef CONFIG_NCPFS_EXTRAS
-int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16, char *, int *);
+static inline int ncp_read_bounce_size(__u32 size) {
+	return sizeof(struct ncp_reply_header) + 2 + 2 + size + 8;
+};
+int ncp_read_bounce(struct ncp_server *, const char *, __u32, __u16, 
+		char *, int *, void* bounce, __u32 bouncelen);
+int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16, 
+		char *, int *);
 int ncp_write_kernel(struct ncp_server *, const char *, __u32, __u16,
 		const char *, int *);
-#endif
 
 int ncp_obtain_info(struct ncp_server *server, struct inode *, char *,
 		struct nw_info_struct *target);
diff -u --recursive --new-file v2.2.9/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.2.9/linux/fs/ncpfs/sock.c	Mon Mar 29 11:09:12 1999
+++ linux/fs/ncpfs/sock.c	Fri May 14 12:43:13 1999
@@ -83,7 +83,8 @@
 
 #define NCP_SLACK_SPACE 1024
 
-static int do_ncp_rpc_call(struct ncp_server *server, int size)
+static int do_ncp_rpc_call(struct ncp_server *server, int size,
+		struct ncp_reply_header* reply_buf, int max_reply_size)
 {
 	struct file *file;
 	struct inode *inode;
@@ -276,7 +277,7 @@
 	 * we have the correct reply, so read into the correct place and
 	 * return it
 	 */
-	result = _recv(sock, (void *) start, server->packet_size, MSG_DONTWAIT);
+	result = _recv(sock, (void *)reply_buf, max_reply_size, MSG_DONTWAIT);
 	if (result < 0) {
 		printk(KERN_WARNING "NCP: notice message: result=%d\n", result);
 	} else if (result < sizeof(struct ncp_reply_header)) {
@@ -299,7 +300,8 @@
  * We need the server to be locked here, so check!
  */
 
-static int ncp_do_request(struct ncp_server *server, int size)
+static int ncp_do_request(struct ncp_server *server, int size,
+		void* reply, int max_reply_size)
 {
 	int result;
 
@@ -316,7 +318,7 @@
 		sign_packet(server, &size);
 	}
 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
-	result = do_ncp_rpc_call(server, size);
+	result = do_ncp_rpc_call(server, size, reply, max_reply_size);
 
 	DDPRINTK(KERN_DEBUG "do_ncp_rpc_call returned %d\n", result);
 
@@ -332,10 +334,11 @@
  * received. It assumes that server->current_size contains the ncp
  * request size
  */
-int ncp_request(struct ncp_server *server, int function)
+int ncp_request2(struct ncp_server *server, int function, 
+		void* rpl, int size)
 {
 	struct ncp_request_header *h;
-	struct ncp_reply_header *reply;
+	struct ncp_reply_header* reply = rpl;
 	int request_size = server->current_size
 			 - sizeof(struct ncp_request_header);
 	int result;
@@ -357,12 +360,11 @@
 	h->task = 2; /* (current->pid) & 0xff; */
 	h->function = function;
 
-	result = ncp_do_request(server, request_size + sizeof(*h));
+	result = ncp_do_request(server, request_size + sizeof(*h), reply, size);
 	if (result < 0) {
 		DPRINTK(KERN_WARNING "ncp_request_error: %d\n", result);
 		goto out;
 	}
-	reply = (struct ncp_reply_header *) (server->packet);
 	server->completion = reply->completion_code;
 	server->conn_status = reply->connection_state;
 	server->reply_size = result;
@@ -393,7 +395,7 @@
 	h->task		= 2; /* see above */
 	h->function	= 0;
 
-	result = ncp_do_request(server, sizeof(*h));
+	result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
 	if (result < 0)
 		goto out;
 	server->sequence = 0;
@@ -417,7 +419,7 @@
 	h->task		= 2; /* see above */
 	h->function	= 0;
 
-	return ncp_do_request(server, sizeof(*h));
+	return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
 }
 
 void ncp_lock_server(struct ncp_server *server)
@@ -428,16 +430,18 @@
 		DPRINTK(KERN_WARNING "ncpfs: server locked!!!\n");
 	}
 #endif
-	while (server->lock)
-		sleep_on(&server->wait);
+	down(&server->sem);
+	if (server->lock)
+		printk(KERN_WARNING "ncp_lock_server: was locked!\n");
 	server->lock = 1;
 }
 
 void ncp_unlock_server(struct ncp_server *server)
 {
-	if (server->lock != 1) {
+	if (!server->lock) {
 		printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
+		return;
 	}
 	server->lock = 0;
-	wake_up(&server->wait);
+	up(&server->sem);
 }
diff -u --recursive --new-file v2.2.9/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.2.9/linux/fs/nfs/read.c	Tue Dec 22 14:16:57 1998
+++ linux/fs/nfs/read.c	Mon Jun  7 13:25:57 1999
@@ -257,6 +257,7 @@
 
 out_error:
 	clear_bit(PG_locked, &page->flags);
+	wake_up(&page->wait);
 out_free:
 	free_page(page_address(page));
 out:
diff -u --recursive --new-file v2.2.9/linux/fs/select.c linux/fs/select.c
--- v2.2.9/linux/fs/select.c	Wed Jan 20 23:14:06 1999
+++ linux/fs/select.c	Sun May 23 23:54:52 1999
@@ -268,8 +268,12 @@
 	}
 
 	ret = -EINVAL;
-	if (n < 0 || n > KFDS_NR)
+	if (n < 0)
 		goto out_nofds;
+
+	if (n > KFDS_NR)
+		n = KFDS_NR;
+
 	/*
 	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
 	 * since we used fdset we need to allocate memory in units of
diff -u --recursive --new-file v2.2.9/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.2.9/linux/fs/smbfs/inode.c	Mon Dec 28 15:00:53 1998
+++ linux/fs/smbfs/inode.c	Sat May 29 11:11:02 1999
@@ -36,6 +36,7 @@
 static void smb_delete_inode(struct inode *);
 static void smb_put_super(struct super_block *);
 static int  smb_statfs(struct super_block *, struct statfs *, int);
+static void smb_set_inode_attr(struct inode *, struct smb_fattr *);
 
 static struct super_operations smb_sops =
 {
@@ -67,9 +68,7 @@
 	return ino;
 }
 
-static struct smb_fattr *read_fattr = NULL;
-static struct semaphore read_semaphore = MUTEX;
-
+/* We are always generating a new inode here */
 struct inode *
 smb_iget(struct super_block *sb, struct smb_fattr *fattr)
 {
@@ -77,11 +76,19 @@
 
 	pr_debug("smb_iget: %p\n", fattr);
 
-	down(&read_semaphore);
-	read_fattr = fattr;
-	result = iget(sb, fattr->f_ino);
-	read_fattr = NULL;
-	up(&read_semaphore);
+	result = get_empty_inode();
+	result->i_sb = sb;
+	result->i_dev = sb->s_dev;
+	result->i_ino = fattr->f_ino;
+	memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i));
+	smb_set_inode_attr(result, fattr);
+	if (S_ISREG(result->i_mode))
+		result->i_op = &smb_file_inode_operations;
+	else if (S_ISDIR(result->i_mode))
+		result->i_op = &smb_dir_inode_operations;
+	else
+		result->i_op = NULL;
+	insert_inode_hash(result);
 	return result;
 }
 
@@ -147,24 +154,9 @@
 static void
 smb_read_inode(struct inode *inode)
 {
-	pr_debug("smb_iget: %p\n", read_fattr);
-
-	if (!read_fattr || inode->i_ino != read_fattr->f_ino)
-	{
-		printk("smb_read_inode called from invalid point\n");
-		return;
-	}
-
-	inode->i_dev = inode->i_sb->s_dev;
-	memset(&(inode->u.smbfs_i), 0, sizeof(inode->u.smbfs_i));
-	smb_set_inode_attr(inode, read_fattr);
-
-	if (S_ISREG(inode->i_mode))
-		inode->i_op = &smb_file_inode_operations;
-	else if (S_ISDIR(inode->i_mode))
-		inode->i_op = &smb_dir_inode_operations;
-	else
-		inode->i_op = NULL;
+	/* Now it can be called only by NFS */
+	printk("smb_read_inode called from invalid point\n");
+	return;
 }
 
 /*
@@ -608,8 +600,6 @@
 	smb_current_kmalloced = 0;
 	smb_current_vmalloced = 0;
 #endif
-
-	read_semaphore = MUTEX;
 
 	return init_smb_fs();
 }
diff -u --recursive --new-file v2.2.9/linux/fs/super.c linux/fs/super.c
--- v2.2.9/linux/fs/super.c	Tue May 11 13:10:31 1999
+++ linux/fs/super.c	Thu May 13 23:25:58 1999
@@ -952,16 +952,19 @@
 	if (!IS_ERR(dentry)) {
 		struct super_block * sb = dentry->d_inode->i_sb;
 
-		retval = -EINVAL;
-		if (dentry == sb->s_root) {
-			/*
-			 * Shrink the dcache and sync the device.
-			 */
-			shrink_dcache_sb(sb);
-			fsync_dev(sb->s_dev);
-			if (flags & MS_RDONLY)
-				acct_auto_close(sb->s_dev);
-			retval = do_remount_sb(sb, flags, data);
+		retval = -ENODEV;
+		if (sb) {
+			retval = -EINVAL;
+			if (dentry == sb->s_root) {
+				/*
+				 * Shrink the dcache and sync the device.
+				 */
+				shrink_dcache_sb(sb);
+				fsync_dev(sb->s_dev);
+				if (flags & MS_RDONLY)
+					acct_auto_close(sb->s_dev);
+				retval = do_remount_sb(sb, flags, data);
+			}
 		}
 		dput(dentry);
 	}
diff -u --recursive --new-file v2.2.9/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.2.9/linux/fs/sysv/namei.c	Tue May 11 13:10:31 1999
+++ linux/fs/sysv/namei.c	Thu May 13 23:25:58 1999
@@ -144,8 +144,6 @@
 
 	*res_buf = NULL;
 	*res_dir = NULL;
-	if (!dir)
-		return -ENOENT;
 	sb = dir->i_sb;
 	if (namelen > SYSV_NAMELEN) {
 		if (sb->sv_truncate)
@@ -334,8 +332,6 @@
 	struct buffer_head * bh;
 	struct sysv_dir_entry * de;
 
-	if (!inode)
-		return 1;
 	block = 0;
 	bh = NULL;
 	pos = offset = 2*SYSV_DIRSIZE;
@@ -391,22 +387,16 @@
 	struct buffer_head * bh;
 	struct sysv_dir_entry * de;
 
-	inode = NULL;
-	bh = sysv_find_entry(dir, dentry->d_name.name,
-                             dentry->d_name.len, &de);
+	inode = dentry->d_inode;
+	bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
 	retval = -ENOENT;
-	if (!bh)
+	if (!bh || de->inode != inode->i_ino)
 		goto end_rmdir;
-	inode = dentry->d_inode;
 
 	if (!empty_dir(inode)) {
 		retval = -ENOTEMPTY;
 		goto end_rmdir;
 	}
-	if (de->inode != inode->i_ino) {
-		retval = -ENOENT;
-		goto end_rmdir;
-	}
 	if (!list_empty(&dentry->d_hash)) {
 		retval = -EBUSY;
 		goto end_rmdir;
@@ -416,9 +406,9 @@
 	de->inode = 0;
 	mark_buffer_dirty(bh, 1);
 	inode->i_nlink=0;
-	mark_inode_dirty(inode);
 	dir->i_nlink--;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(inode);
 	mark_inode_dirty(dir);
 	d_delete(dentry);
 	retval = 0;
@@ -434,26 +424,11 @@
 	struct buffer_head * bh;
 	struct sysv_dir_entry * de;
 
-repeat:
 	retval = -ENOENT;
-	inode = NULL;
-	bh = sysv_find_entry(dir, dentry->d_name.name,
-                             dentry->d_name.len, &de);
-	if (!bh)
-		goto end_unlink;
 	inode = dentry->d_inode;
-
-	retval = -EPERM;
-	if (de->inode != inode->i_ino) {
-		brelse(bh);
-		current->counter = 0;
-		schedule();
-		goto repeat;
-	}
-	if (de->inode != inode->i_ino) {
-		retval = -ENOENT;
+	bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+	if (!bh || de->inode != inode->i_ino)
 		goto end_unlink;
-	}
 	if (!inode->i_nlink) {
 		printk("Deleting nonexistent file (%s:%lu), %d\n",
 		        kdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
@@ -572,12 +547,6 @@
 (((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode)
 
 /*
- * rename uses retrying to avoid race-conditions: at least they should be minimal.
- * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
- * checks fail, it tries to restart itself again. Very practical - no changes
- * are done until we know everything works ok.. and then all the changes can be
- * done in one fell swoop when we have claimed all the buffers needed.
- *
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
@@ -589,24 +558,15 @@
 	struct sysv_dir_entry * old_de, * new_de;
 	int retval;
 
-	goto start_up;
-try_again:
-	brelse(old_bh);
-	brelse(new_bh);
-	brelse(dir_bh);
-	current->counter = 0;
-	schedule();
-start_up:
-	old_inode = new_inode = NULL;
-	old_bh = new_bh = dir_bh = NULL;
+	old_inode = old_dentry->d_inode;
+	new_inode = new_dentry->d_inode;
+	new_bh = dir_bh = NULL;
 	old_bh = sysv_find_entry(old_dir, old_dentry->d_name.name,
 				old_dentry->d_name.len, &old_de);
 	retval = -ENOENT;
-	if (!old_bh)
+	if (!old_bh || old_de->inode != old_inode->i_ino)
 		goto end_rename;
-	old_inode = old_dentry->d_inode;	/* don't cross mnt-points */
 	retval = -EPERM;
-	new_inode = new_dentry->d_inode;
 	new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name,
 				new_dentry->d_name.len, &new_de);
 	if (new_bh) {
@@ -628,7 +588,8 @@
 		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 			goto end_rename;
 		retval = -EMLINK;
-		if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
+		if (!new_inode && new_dir != old_dir &&
+				new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
 			goto end_rename;
 	}
 	if (!new_bh) {
@@ -637,16 +598,8 @@
 		if (retval)
 			goto end_rename;
 	}
-/* sanity checking before doing the rename - avoid races */
-	if (new_inode && (new_de->inode != new_inode->i_ino))
-		goto try_again;
-	if (new_de->inode && !new_inode)
-		goto try_again;
-	if (old_de->inode != old_inode->i_ino)
-		goto try_again;
-/* ok, that's it */
-	old_de->inode = 0;
 	new_de->inode = old_inode->i_ino;
+	old_de->inode = 0;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(old_dir);
 	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h
--- v2.2.9/linux/include/asm-alpha/atomic.h	Mon Dec 28 15:00:53 1998
+++ linux/include/asm-alpha/atomic.h	Sat May 22 13:42:53 1999
@@ -75,6 +75,7 @@
 	"	mov %0,%2\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,2f\n"
+	"	mb\n"
 	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
 	".previous"
@@ -92,6 +93,7 @@
 	"	mov %0,%2\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,2f\n"
+	"	mb\n"
 	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
 	".previous"
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h
--- v2.2.9/linux/include/asm-alpha/bitops.h	Wed Sep  9 14:51:09 1998
+++ linux/include/asm-alpha/bitops.h	Sat May 22 13:42:53 1999
@@ -90,6 +90,7 @@
 	"	xor %0,%3,%0\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,3f\n"
+	"	mb\n"
 	"2:\n"
 	".section .text2,\"ax\"\n"
 	"3:	br 1b\n"
@@ -114,6 +115,7 @@
 	"	xor %0,%3,%0\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,3f\n"
+	"	mb\n"
 	"2:\n"
 	".section .text2,\"ax\"\n"
 	"3:	br 1b\n"
@@ -137,6 +139,7 @@
 	"	xor %0,%3,%0\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,3f\n"
+	"	mb\n"
 	".section .text2,\"ax\"\n"
 	"3:	br 1b\n"
 	".previous"
@@ -172,7 +175,10 @@
 
 extern inline unsigned long ffz(unsigned long word)
 {
-#ifdef __alpha_cix__
+#if 0 && defined(__alpha_cix__)
+	/* Swine architects -- a year after they publish v3 of the
+	   handbook, in the 21264 data sheet they quietly change CIX
+	   to FIX and remove the spiffy counting instructions.  */
 	/* Whee.  EV6 can calculate it directly.  */
 	unsigned long result;
 	__asm__("ctlz %1,%0" : "=r"(result) : "r"(~word));
@@ -208,7 +214,10 @@
  * of bits set) of a N-bit word
  */
 
-#ifdef __alpha_cix__
+#if 0 && defined(__alpha_cix__)
+/* Swine architects -- a year after they publish v3 of the handbook, in
+   the 21264 data sheet they quietly change CIX to FIX and remove the
+   spiffy counting instructions.  */
 /* Whee.  EV6 can calculate it directly.  */
 extern __inline__ unsigned long hweight64(unsigned long w)
 {
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/init.h linux/include/asm-alpha/init.h
--- v2.2.9/linux/include/asm-alpha/init.h	Thu Dec 31 10:29:02 1998
+++ linux/include/asm-alpha/init.h	Sat Jun 12 11:52:52 1999
@@ -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,7 +12,8 @@
 #define __INIT		.section	.text.init,"ax"
 #define __FINIT		.previous
 #define __INITDATA	.section	.data.init,"a"
+#endif
 
-#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+#define __cacheline_aligned __attribute__((__aligned__(32)))
 
 #endif
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.2.9/linux/include/asm-alpha/io.h	Fri Apr 16 14:47:31 1999
+++ linux/include/asm-alpha/io.h	Sat Jun 12 11:52:52 1999
@@ -29,15 +29,16 @@
  */
 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)
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/irq.h linux/include/asm-alpha/irq.h
--- v2.2.9/linux/include/asm-alpha/irq.h	Wed Jan 13 15:00:43 1999
+++ linux/include/asm-alpha/irq.h	Sat May 22 13:42:57 1999
@@ -92,7 +92,11 @@
 }
 
 extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
 extern void enable_irq(unsigned int);
+
+extern void irq_enter(int cpu, int irq);
+extern void irq_exit(int cpu, int irq);
 
 struct pt_regs;
 extern void (*perf_irq)(unsigned long, struct pt_regs *);
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/mmu_context.h linux/include/asm-alpha/mmu_context.h
--- v2.2.9/linux/include/asm-alpha/mmu_context.h	Mon Mar 29 11:09:12 1999
+++ linux/include/asm-alpha/mmu_context.h	Sat Jun 12 11:52:52 1999
@@ -107,7 +107,8 @@
 
 	if (mm) {
 		unsigned long asn = asn_cache;
-		/* Check if our ASN is of an older version and thus invalid */
+		/* Check if our ASN is of an older version,
+		   or on a different CPU, and thus invalid.  */
 		if ((mm->context ^ asn) & ~HARDWARE_ASN_MASK)
 			get_new_mmu_context(p, mm);
 	}
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- v2.2.9/linux/include/asm-alpha/smp.h	Thu Dec 31 10:29:02 1998
+++ linux/include/asm-alpha/smp.h	Sat May 22 13:42:59 1999
@@ -4,22 +4,30 @@
 #ifdef __SMP__
 
 #include <linux/tasks.h>
+#include <asm/init.h>
 #include <asm/pal.h>
 
 struct cpuinfo_alpha {
 	unsigned long loops_per_sec;
-	unsigned int next;
 	unsigned long *pgd_cache;
 	unsigned long *pte_cache;
 	unsigned long pgtable_cache_sz;
 	unsigned long ipi_count;
-} __attribute__((aligned(32)));
+	unsigned long prof_multiplier;
+	unsigned long prof_counter;
+} __cacheline_aligned;
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
 
 #define PROC_CHANGE_PENALTY     20
 
-extern __volatile__ int cpu_number_map[NR_CPUS];
+/* Map from cpu id to sequential logical cpu number.  This will only
+   not be idempotent when cpus failed to come on-line.  */
+extern int cpu_number_map[NR_CPUS];
+
+/* The reverse map from sequential logical cpu number to cpu id.  */
+extern int __cpu_logical_map[NR_CPUS];
+#define cpu_logical_map(cpu)  __cpu_logical_map[cpu]
 
 /* HACK: Cabrio WHAMI return value is bogus if more than 8 bits used.. :-( */
 
@@ -35,7 +43,6 @@
 }
 
 #define smp_processor_id()	(current->processor)
-#define cpu_logical_map(cpu)	(cpu)
 
 #endif /* __SMP__ */
 
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/spinlock.h linux/include/asm-alpha/spinlock.h
--- v2.2.9/linux/include/asm-alpha/spinlock.h	Wed Jan 13 15:00:43 1999
+++ linux/include/asm-alpha/spinlock.h	Sat May 22 13:42:59 1999
@@ -79,19 +79,20 @@
  */
 
 typedef struct {
-	volatile unsigned int lock;
+	volatile unsigned int lock /*__attribute__((aligned(32))) */;
 #if DEBUG_SPINLOCK
-	char debug_state, target_ipl, saved_ipl, on_cpu;
+	int on_cpu;
+	int line_no;
 	void *previous;
 	struct task_struct * task;
+	const char *base_file;
 #endif
 } spinlock_t;
 
 #if DEBUG_SPINLOCK
-#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, 1, 0, 0, 0, 0}
+#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, -1, 0, 0, 0, 0}
 #define spin_lock_init(x)						\
-	((x)->lock = 0, (x)->target_ipl = 0, (x)->debug_state = 1,	\
-	 (x)->previous = 0, (x)->task = 0)
+	((x)->lock = 0, (x)->on_cpu = -1, (x)->previous = 0, (x)->task = 0)
 #else
 #define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
 #define spin_lock_init(x)	((x)->lock = 0)
@@ -105,8 +106,11 @@
 
 #if DEBUG_SPINLOCK
 extern void spin_unlock(spinlock_t * lock);
-extern void spin_lock(spinlock_t * lock);
-extern int spin_trylock(spinlock_t * lock);
+extern void debug_spin_lock(spinlock_t * lock, const char *, int);
+extern int debug_spin_trylock(spinlock_t * lock, const char *, int);
+
+#define spin_lock(LOCK) debug_spin_lock(LOCK, __BASE_FILE__, __LINE__)
+#define spin_trylock(LOCK) debug_spin_trylock(LOCK, __BASE_FILE__, __LINE__)
 
 #define spin_lock_own(LOCK, LOCATION)					\
 do {									\
@@ -161,7 +165,9 @@
 
 /***********************************************************/
 
-typedef struct { volatile int write_lock:1, read_counter:31; } rwlock_t;
+typedef struct {
+	volatile int write_lock:1, read_counter:31;
+} /*__attribute__((aligned(32)))*/ rwlock_t;
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
diff -u --recursive --new-file v2.2.9/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.2.9/linux/include/asm-alpha/system.h	Tue May 11 13:10:31 1999
+++ linux/include/asm-alpha/system.h	Sat Jun 12 11:52:52 1999
@@ -86,16 +86,6 @@
         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)			\
@@ -147,78 +137,98 @@
 #endif
 #endif
 
+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__
 
@@ -282,6 +292,7 @@
 	"	bis $31,%3,%1\n"
 	"	stl_c %1,%2\n"
 	"	beq %1,2f\n"
+	"	mb\n"
 	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
 	".previous"
@@ -300,6 +311,7 @@
 	"	bis $31,%3,%1\n"
 	"	stq_c %1,%2\n"
 	"	beq %1,2f\n"
+	"	mb\n"
 	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
 	".previous"
diff -u --recursive --new-file v2.2.9/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.2.9/linux/include/asm-arm/arch-ebsa285/irq.h	Thu May 13 23:10:30 1999
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Thu May 13 23:16:21 1999
@@ -10,6 +10,7 @@
  *  26-Jan-1999	PJB	Don't use IACK on CATS
  *  16-Mar-1999	RMK	Added autodetect of ISA PICs
  */
+#include <linux/config.h>
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.2.9/linux/include/asm-arm/arch-ebsa285/memory.h linux/include/asm-arm/arch-ebsa285/memory.h
--- v2.2.9/linux/include/asm-arm/arch-ebsa285/memory.h	Thu May 13 23:10:30 1999
+++ linux/include/asm-arm/arch-ebsa285/memory.h	Thu May 13 23:16:21 1999
@@ -15,6 +15,8 @@
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
+#include <linux/config.h>
+
 #if defined(CONFIG_HOST_FOOTBRIDGE)
 
 /*
diff -u --recursive --new-file v2.2.9/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.2.9/linux/include/asm-i386/bugs.h	Tue May 11 13:10:32 1999
+++ linux/include/asm-i386/bugs.h	Tue Jun  8 10:44:08 1999
@@ -357,10 +357,18 @@
 __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");
 	}
diff -u --recursive --new-file v2.2.9/linux/include/asm-i386/locks.h linux/include/asm-i386/locks.h
--- v2.2.9/linux/include/asm-i386/locks.h	Wed Jan 13 15:00:43 1999
+++ linux/include/asm-i386/locks.h	Wed Jun  2 11:29:28 1999
@@ -2,7 +2,7 @@
  *	SMP locks primitives for building ix86 locks
  *	(not yet used).
  *
- *		Alan Cox, alan@cymru.net, 1995
+ *		Alan Cox, alan@redhat.com, 1995
  */
  
 /*
diff -u --recursive --new-file v2.2.9/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.2.9/linux/include/asm-ppc/system.h	Tue May 11 13:10:32 1999
+++ linux/include/asm-ppc/system.h	Fri Jun  4 13:30:47 1999
@@ -58,7 +58,6 @@
 extern int _disable_interrupts(void);
 extern void _enable_interrupts(int);
 
-extern void instruction_dump(unsigned long *);
 extern void print_backtrace(unsigned long *);
 extern void show_regs(struct pt_regs * regs);
 extern void flush_instruction_cache(void);
@@ -75,6 +74,9 @@
 extern void enable_kernel_fp(void);
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
+extern int call_rtas(const char *, int, int, unsigned long *, ...);
+extern void chrp_progress(char *);
+void chrp_event_scan(void);
 
 struct device_node;
 extern void note_scsi_host(struct device_node *, void *);
@@ -88,6 +90,8 @@
 extern struct task_struct *_switch(struct thread_struct *prev,
 				     struct thread_struct *next,
 				     unsigned long context);
+
+extern unsigned int rtas_data;
 
 struct pt_regs;
 extern void dump_regs(struct pt_regs *);
diff -u --recursive --new-file v2.2.9/linux/include/linux/cyclades.h linux/include/linux/cyclades.h
--- v2.2.9/linux/include/linux/cyclades.h	Fri Apr 16 14:47:31 1999
+++ linux/include/linux/cyclades.h	Mon May 24 22:38:02 1999
@@ -557,7 +557,8 @@
 	unsigned long		event;
 	unsigned long		last_active;
 	int			count;	/* # of fd on device */
-	int                     x_break;
+	int                     breakon;
+	int                     breakoff;
 	int			blocked_open; /* # of blocked opens */
 	long			session; /* Session of opening process */
 	long			pgrp; /* pgrp of opening process */
diff -u --recursive --new-file v2.2.9/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v2.2.9/linux/include/linux/if_ether.h	Tue Dec 22 14:16:58 1998
+++ linux/include/linux/if_ether.h	Wed Jun  2 11:29:28 1999
@@ -9,7 +9,7 @@
  *
  * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@super.org>
- *		Alan Cox, <alan@cymru.net>
+ *		Alan Cox, <alan@redhat.com>
  *		Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
  *
  *		This program is free software; you can redistribute it and/or
diff -u --recursive --new-file v2.2.9/linux/include/linux/if_fddi.h linux/include/linux/if_fddi.h
--- v2.2.9/linux/include/linux/if_fddi.h	Fri May  8 23:14:56 1998
+++ linux/include/linux/if_fddi.h	Wed Jun  2 11:29:28 1999
@@ -12,7 +12,7 @@
  *		if_fddi.h is based on previous if_ether.h and if_tr.h work by
  *			Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *			Donald Becker, <becker@super.org>
- *			Alan Cox, <alan@cymru.net>
+ *			Alan Cox, <alan@redhat.com>
  *			Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
  *			Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
  *
diff -u --recursive --new-file v2.2.9/linux/include/linux/if_hippi.h linux/include/linux/if_hippi.h
--- v2.2.9/linux/include/linux/if_hippi.h	Fri Jul 31 17:07:27 1998
+++ linux/include/linux/if_hippi.h	Wed Jun  2 11:29:28 1999
@@ -9,7 +9,7 @@
  *
  * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Donald Becker, <becker@super.org>
- *		Alan Cox, <alan@cymru.net>
+ *		Alan Cox, <alan@redhat.com>
  *		Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
  *		Jes Sorensen, <Jes.Sorensen@cern.ch>
  *
diff -u --recursive --new-file v2.2.9/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v2.2.9/linux/include/linux/interrupt.h	Tue Dec 22 14:16:58 1998
+++ linux/include/linux/interrupt.h	Wed Jun  2 09:55:38 1999
@@ -35,6 +35,7 @@
 	SERIAL_BH,
 	RISCOM8_BH,
 	SPECIALIX_BH,
+	AURORA_BH,
 	ESP_BH,
 	NET_BH,
 	SCSI_BH,
diff -u --recursive --new-file v2.2.9/linux/include/linux/lp.h linux/include/linux/lp.h
--- v2.2.9/linux/include/linux/lp.h	Wed Dec 16 10:32:56 1998
+++ linux/include/linux/lp.h	Mon Jun  7 11:05:31 1999
@@ -7,12 +7,6 @@
  * Interrupt support added 1993 Nigel Gamble
  */
 
-/* Magic numbers for defining port-device mappings */
-#define LP_PARPORT_UNSPEC -4
-#define LP_PARPORT_AUTO -3
-#define LP_PARPORT_OFF -2
-#define LP_PARPORT_NONE -1
-
 /*
  * Per POSIX guidelines, this module reserves the LP and lp prefixes
  * These are the lp_table[minor].flags flags...
@@ -87,6 +81,14 @@
 #define LP_TIMEOUT_INTERRUPT	(60 * HZ)
 #define LP_TIMEOUT_POLLED	(10 * HZ)
 
+#ifdef __KERNEL__
+
+/* Magic numbers for defining port-device mappings */
+#define LP_PARPORT_UNSPEC -4
+#define LP_PARPORT_AUTO -3
+#define LP_PARPORT_OFF -2
+#define LP_PARPORT_NONE -1
+
 #define LP_F(minor)	lp_table[(minor)].flags		/* flags for busy, etc. */
 #define LP_CHAR(minor)	lp_table[(minor)].chars		/* busy timeout */
 #define LP_TIME(minor)	lp_table[(minor)].time		/* wait time */
@@ -180,5 +182,7 @@
  */
 
 extern int lp_init(void);
+
+#endif
 
 #endif
diff -u --recursive --new-file v2.2.9/linux/include/linux/major.h linux/include/linux/major.h
--- v2.2.9/linux/include/linux/major.h	Fri Oct 23 22:01:26 1998
+++ linux/include/linux/major.h	Wed Jun  2 09:55:38 1999
@@ -92,6 +92,8 @@
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
+#define AURORA_MAJOR 79
+
 #define UNIX98_PTY_MASTER_MAJOR	128
 #define UNIX98_PTY_MAJOR_COUNT	8
 #define UNIX98_PTY_SLAVE_MAJOR	(UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
diff -u --recursive --new-file v2.2.9/linux/include/linux/ncp.h linux/include/linux/ncp.h
--- v2.2.9/linux/include/linux/ncp.h	Wed Apr 28 11:37:31 1999
+++ linux/include/linux/ncp.h	Fri May 14 12:43:13 1999
@@ -72,9 +72,6 @@
 #define aDELETEINHIBIT	 (ntohl(1L<<(18-8)))
 #define aDONTCOMPRESS	 (nothl(1L<<(27-24)))
 
-#define NCP_MIN_SYMLINK_SIZE	8
-#define NCP_MAX_SYMLINK_SIZE	512
-
 #define AR_READ      (ntohs(0x0100))
 #define AR_WRITE     (ntohs(0x0200))
 #define AR_EXCLUSIVE (ntohs(0x2000))
diff -u --recursive --new-file v2.2.9/linux/include/linux/ncp_fs.h linux/include/linux/ncp_fs.h
--- v2.2.9/linux/include/linux/ncp_fs.h	Wed Apr 28 11:37:31 1999
+++ linux/include/linux/ncp_fs.h	Fri May 14 12:43:13 1999
@@ -248,7 +248,11 @@
 int ncp_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
 /* linux/fs/ncpfs/sock.c */
-int ncp_request(struct ncp_server *server, int function);
+int ncp_request2(struct ncp_server *server, int function,
+	void* reply, int max_reply_size);
+static int inline ncp_request(struct ncp_server *server, int function) {
+	return ncp_request2(server, function, server->packet, server->packet_size);
+}
 int ncp_connect(struct ncp_server *server);
 int ncp_disconnect(struct ncp_server *server);
 void ncp_lock_server(struct ncp_server *server);
diff -u --recursive --new-file v2.2.9/linux/include/linux/ncp_fs_sb.h linux/include/linux/ncp_fs_sb.h
--- v2.2.9/linux/include/linux/ncp_fs_sb.h	Wed Apr 28 11:37:31 1999
+++ linux/include/linux/ncp_fs_sb.h	Fri May 14 12:43:13 1999
@@ -8,6 +8,7 @@
 #ifndef _NCP_FS_SB
 #define _NCP_FS_SB
 
+#include <asm/semaphore.h>
 #include <linux/ncp_mount.h>
 #include <linux/types.h>
 
@@ -44,7 +45,7 @@
 				   receive replies */
 
 	int lock;		/* To prevent mismatch in protocols. */
-	struct wait_queue *wait;
+	struct semaphore sem;
 
 	int current_size;	/* for packet preparation */
 	int has_subfunction;
diff -u --recursive --new-file v2.2.9/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.2.9/linux/include/linux/netdevice.h	Tue Mar 23 14:35:48 1999
+++ linux/include/linux/netdevice.h	Sun May 16 18:28:41 1999
@@ -405,7 +405,7 @@
 extern __inline__ void dev_lock_wait(void)
 {
 	while (atomic_read(&dev_lockct)) {
-		current->counter = 0;
+		current->policy |= SCHED_YIELD;
 		schedule();
 	}
 }
diff -u --recursive --new-file v2.2.9/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.2.9/linux/include/linux/pci.h	Wed Apr 28 11:37:31 1999
+++ linux/include/linux/pci.h	Wed Jun  9 16:59:34 1999
@@ -273,6 +273,8 @@
 #define PCI_CLASS_SERIAL_USB		0x0c03
 #define PCI_CLASS_SERIAL_FIBER		0x0c04
 
+#define PCI_CLASS_HOT_SWAP_CONTROLLER	0xff00
+
 #define PCI_CLASS_OTHERS		0xff
 
 /*
@@ -365,6 +367,7 @@
 #define PCI_DEVICE_ID_DEC_21150		0x0022
 #define PCI_DEVICE_ID_DEC_21152		0x0024
 #define PCI_DEVICE_ID_DEC_21153		0x0025
+#define PCI_DEVICE_ID_DEC_21154		0x0026
 
 #define PCI_VENDOR_ID_CIRRUS		0x1013
 #define PCI_DEVICE_ID_CIRRUS_7548	0x0038
@@ -510,9 +513,12 @@
 #define PCI_DEVICE_ID_WINBOND2_89C940	0x0940
 
 #define PCI_VENDOR_ID_MOTOROLA		0x1057
+#define PCI_VENDOR_ID_MOTOROLA_OOPS	0x1507
 #define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
 #define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
 #define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
+#define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
+#define PCI_DEVICE_ID_MOTOROLA_CPX8216	0x4806
 
 #define PCI_VENDOR_ID_PROMISE		0x105a
 #define PCI_DEVICE_ID_PROMISE_20246	0x4d33
@@ -1058,9 +1064,11 @@
 
 #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
@@ -1075,15 +1083,28 @@
 #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
diff -u --recursive --new-file v2.2.9/linux/include/linux/smp.h linux/include/linux/smp.h
--- v2.2.9/linux/include/linux/smp.h	Tue May 11 13:10:32 1999
+++ linux/include/linux/smp.h	Wed Jun  2 11:29:28 1999
@@ -3,7 +3,7 @@
 
 /*
  *	Generic SMP support
- *		Alan Cox. <alan@cymru.net>
+ *		Alan Cox. <alan@redhat.com>
  */
 
 #ifdef __SMP__
diff -u --recursive --new-file v2.2.9/linux/include/linux/synclink.h linux/include/linux/synclink.h
--- v2.2.9/linux/include/linux/synclink.h	Mon Mar 29 11:09:12 1999
+++ linux/include/linux/synclink.h	Fri Jun 11 13:08:47 1999
@@ -1,6 +1,8 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
+ * ==FILEDATE 19990523==
+ *
  * Copyright (C) 1998 by Microgate Corporation
  * 
  * Redistribution of this file is permitted under 
@@ -66,11 +68,16 @@
 #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 @@
  * 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_ */
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/crc.h linux/include/net/irda/crc.h
--- v2.2.9/linux/include/net/irda/crc.h	Wed Jan 20 23:14:06 1999
+++ linux/include/net/irda/crc.h	Sun May 30 10:17:03 1999
@@ -6,25 +6,28 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Tue Dec 15 22:18:53 1998
+ * Modified at:   Sun May  2 20:25:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  ********************************************************************/
 
-#ifndef IR_CRC_H
-#define IR_CRC_H
+#ifndef IRDA_CRC_H
+#define IRDA_CRC_H
 
 #include <linux/types.h>
 
 #define INIT_FCS  0xffff   /* Initial FCS value */
 #define GOOD_FCS  0xf0b8   /* Good final FCS value */
 
+extern __u16 const irda_crc16_table[];
+
 /* Recompute the FCS with one more character appended. */
-#define IR_FCS(fcs, c) (((fcs) >> 8) ^ irda_crc16_table[((fcs) ^ (c)) & 0xff])
+static inline __u16 irda_fcs(__u16 fcs, __u8 c)
+{
+	return (((fcs) >> 8) ^ irda_crc16_table[((fcs) ^ (c)) & 0xff]);
+}
 
 /* Recompute the FCS with len bytes appended. */
 unsigned short crc_calc( __u16 fcs, __u8 const *buf, size_t len);
-
-extern __u16 const irda_crc16_table[];
 
 #endif
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/dongle.h linux/include/net/irda/dongle.h
--- v2.2.9/linux/include/net/irda/dongle.h	Wed Mar 10 15:29:50 1999
+++ linux/include/net/irda/dongle.h	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 22:47:12 1998
- * Modified at:   Sat Feb  6 07:37:49 1999
+ * Modified at:   Sun May 16 13:40:03 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 
@@ -26,7 +26,6 @@
 #define DONGLE_H
 
 #include <net/irda/qos.h>
-#include <net/irda/irda_device.h>
 
 /* These are the currently known dongles */
 typedef enum {
@@ -35,13 +34,16 @@
 	ACTISYS_DONGLE,
 	ACTISYS_PLUS_DONGLE,
 	GIRBIL_DONGLE,
-} DONGLE_T;
+	LITELINK_DONGLE,
+} 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 *);
 };
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/ircomm_common.h linux/include/net/irda/ircomm_common.h
--- v2.2.9/linux/include/net/irda/ircomm_common.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/ircomm_common.h	Mon Jun  7 16:19:59 1999
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
  *
- *     Copyright (c) 1998, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
+ *     Copyright (c) 1998-1999, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
  *     All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
@@ -77,9 +77,9 @@
 
 #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        (LAP_HEADER+LMP_HEADER+TTP_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 */
 
 
@@ -167,7 +167,7 @@
 #define LSR_BI     0x01    /* Break interrupt indicator */
 
 
-struct ircomm_cb{
+struct ircomm_cb {
 	int magic;
 	int state;          /* Current state of IrCOMM layer: 
 			     *  DISCOVERY,COMM_IDLE, COMM_WAITR,
@@ -177,8 +177,9 @@
 	int null_modem_mode;     /* switch for null modem emulation */
 	int ttp_stop;
 
-	int max_txbuff_size;          
-	__u32 maxsdusize;
+	__u32 tx_max_sdu_size;          
+	__u32 rx_max_sdu_size;
+	__u8 max_header_size;
 
  	__u32 daddr;        /* Device address of the peer device */ 
 	__u32 saddr;
@@ -211,8 +212,6 @@
 	int                 pending_control_tuples;
 	int                 ignored_control_tuples;
 
-
-
 	__u8 pi ;            /* instruction of control channel*/ 
 
 	__u8 port_type;
@@ -252,8 +251,6 @@
 	char port_name[33];
 	int port_name_critical;
 };
-
-
 
 void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype);
 void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irda.h linux/include/net/irda/irda.h
--- v2.2.9/linux/include/net/irda/irda.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/irda.h	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Wed Apr 21 17:49:00 1999
+ * Modified at:   Mon May 10 09:51:13 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 
@@ -109,6 +109,8 @@
 	
 	__u32 max_sdu_size_rx;
 	__u32 max_sdu_size_tx;
+	__u32 max_data_size;
+	__u8  max_header_size;
 	struct qos_info qos_tx;
 
 	__u16 mask;           /* Hint bits mask */
@@ -225,10 +227,10 @@
 	int (*udata_indication)(void *priv, void *sap, struct sk_buff *skb);
 	void (*connect_confirm)(void *instance, void *sap, 
 				struct qos_info *qos, __u32 max_sdu_size,
-				struct sk_buff *skb);
+				__u8 max_header_size, struct sk_buff *skb);
 	void (*connect_indication)(void *instance, void *sap, 
 				   struct qos_info *qos, __u32 max_sdu_size,
-				   struct sk_buff *skb);
+				   __u8 max_header_size, struct sk_buff *skb);
 	void (*disconnect_indication)(void *instance, void *sap, 
 				      LM_REASON reason, struct sk_buff *);
 	void (*flow_indication)(void *instance, void *sap, LOCAL_FLOW flow);
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irda_device.h linux/include/net/irda/irda_device.h
--- v2.2.9/linux/include/net/irda/irda_device.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/irda_device.h	Mon Jun  7 16:19:59 1999
@@ -4,24 +4,29 @@
  * Version:       
  * Description:   
  * Status:        Experimental.
- * Author:        Haris Zukanovic <haris@stud.cs.uit.no>
+ * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr 14 12:41:42 1998
- * Modified at:   Tue Apr 20 11:06:28 1999
+ * Modified at:   Wed May 19 08:44:48 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Haris Zukanovic, <haris@stud.cs.uit.no>
- *     Copyright (c) 1998 Dag Brattli, <dagb@cs.uit.no>
+ *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
  *     Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
- *     All Rights Reserved.
- *      
+ *     Copyright (c) 1998 Haris Zukanovic, <haris@stud.cs.uit.no>
+ *
  *     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 Haris Zukanovic 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
  *     
  ********************************************************************/
 
@@ -35,6 +40,7 @@
 
 #include <net/irda/irda.h>
 #include <net/irda/qos.h>
+#include <net/irda/dongle.h>
 #include <net/irda/irqueue.h>
 #include <net/irda/irlap_frame.h>
 
@@ -52,6 +58,11 @@
 #define IO_XMIT 0x01
 #define IO_RECV 0x02
 
+struct dongle_q {
+	QUEUE q;
+	struct dongle *dongle;
+};
+
 /* Chip specific info */
 struct chipio_t {
         int iobase, iobase2;  /* IO base */
@@ -111,16 +122,19 @@
 	struct iobuff_t tx_buff;
 	struct iobuff_t rx_buff;
 
-	/* spinlock_t lock; */ /* For serializing operations */
+	struct dongle *dongle; /* Dongle driver */
+
+	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? */
-	/* int (*is_tbusy)(struct irda_device *); */   /* transmitting? */
+	void (*set_dtr_rts)(struct irda_device *idev, int dtr, int rts);
+	int  (*raw_write)(struct irda_device *idev, __u8 *buf, int len);
 	void (*wait_until_sent)(struct irda_device *);
 	void (*set_caddr)(struct irda_device *);      /* Set connection addr */
 };
@@ -142,6 +156,9 @@
 
 inline struct qos_info *irda_device_get_qos(struct irda_device *self);
 int irda_device_txqueue_empty(struct irda_device *self);
+void irda_device_init_dongle(struct irda_device *self, int type);
+void irda_device_unregister_dongle(struct dongle *dongle);
+int irda_device_register_dongle(struct dongle *dongle);
 
 int irda_device_setup(struct device *dev);
 
@@ -153,7 +170,7 @@
  *    Utility function for getting the minimum turnaround time out of 
  *    the skb, where it has been hidden in the cb field.
  */
-inline static __u16 irda_get_mtt(struct sk_buff *skb)
+extern inline __u16 irda_get_mtt(struct sk_buff *skb)
 {
 	__u16 mtt;
 
@@ -165,6 +182,23 @@
 	ASSERT(mtt <= 10000, return 10000;);
 	
 	return mtt;
+}
+
+extern inline void irda_device_set_dtr_rts(struct irda_device *self, int dtr,
+					   int rts)
+{
+	if (self->set_dtr_rts)
+		self->set_dtr_rts(self, dtr, rts);
+}
+
+extern inline int irda_device_raw_write(struct irda_device *self, __u8 *buf,
+					int len)
+{
+	int ret = -1;
+
+	if (self->raw_write)
+		ret = self->raw_write(self, buf, len);
+	return ret;
 }
 
 #endif
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/iriap.h linux/include/net/irda/iriap.h
--- v2.2.9/linux/include/net/irda/iriap.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/iriap.h	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Wed Apr 21 16:37:21 1999
+ * Modified at:   Sun May  9 10:56:57 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, 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 
@@ -81,6 +81,8 @@
 	CONFIRM_CALLBACK confirm;
 	void *priv;
 
+	__u8 max_header_size;
+	
 	struct timer_list watchdog_timer;
 };
 
@@ -92,8 +94,6 @@
 void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb);
 
 void iriap_send_ack( struct iriap_cb *self);
-void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-			   __u32 max_sdu_size, struct sk_buff *skb);
 void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb);
 
 void iriap_register_server(void);
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irlan_common.h linux/include/net/irda/irlan_common.h
--- v2.2.9/linux/include/net/irda/irlan_common.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/irlan_common.h	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 14:30:37 1999
+ * Modified at:   Mon May 31 13:54:20 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 <dagb@cs.uit.no>, 
+ *     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 
@@ -98,7 +99,7 @@
 #define IRLAN_SHORT  1
 #define IRLAN_ARRAY  2
 
-#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER)
+#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_MAX_HEADER)
 
 /*
  *  IrLAN client
@@ -109,7 +110,10 @@
 	int open_retries;
 
 	struct tsap_cb *tsap_ctrl;
+	__u32 max_sdu_size;
+	__u8  max_header_size;
 	
+	int access_type;         /* Access type of provider */
 	__u8 reconnect_key[255];
 	__u8 key_len;
 	
@@ -120,6 +124,9 @@
 	int unicast_open;
 	int broadcast_open;
 
+	int tx_busy;
+	struct sk_buff_head txq; /* Transmit control queue */
+
 	struct timer_list kick_timer;
 };
 
@@ -130,6 +137,8 @@
 	int state;
 	
 	struct tsap_cb *tsap_ctrl;
+	__u32 max_sdu_size;
+	__u8  max_header_size;
 
 	/*
 	 *  Store some values here which are used by the provider to parse
@@ -140,42 +149,45 @@
 	int filter_mode;
 	int filter_operation;
 	int filter_entry;
-
+	int access_type;     /* Access type */
 	__u16 send_arb_val;
 
 	__u8 mac_address[6]; /* Generated MAC address for peer device */
 };
 
 /*
- *  IrLAN
+ *  IrLAN control block
  */
 struct irlan_cb {
 	QUEUE queue; /* Must be first */
 
 	int    magic;
 	char   ifname[9];
-	struct device dev;  /* Ethernet device structure*/
+	struct device dev;        /* Ethernet device structure*/
 	struct enet_statistics stats;
 
-	__u32 saddr;        /* Source devcie address */
-	__u32 daddr;        /* Destination device address */
+	__u32 saddr;              /* Source device address */
+	__u32 daddr;              /* Destination device address */
 	int   netdev_registered;
 	int   notify_irmanager;
 	
-	int media;          /* Media type */
-	int access_type;    /* Currently used access type */
-	__u8 version[2];    /* IrLAN version */
+	int media;                /* Media type */
+	__u8 version[2];          /* IrLAN version */
 	
 	struct tsap_cb *tsap_data;
 
-	int  use_udata;  /* Use Unit Data transfers */
+	int  master;              /* Master instance? */
+	int  use_udata;           /* Use Unit Data transfers */
 
-	__u8 stsap_sel_data; /* Source data TSAP selector */
-	__u8 dtsap_sel_data; /* Destination data TSAP selector */
-	__u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */
+	__u8 stsap_sel_data;      /* Source data TSAP selector */
+	__u8 dtsap_sel_data;      /* Destination data TSAP selector */
+	__u8 dtsap_sel_ctrl;      /* Destination ctrl TSAP selector */
 
-	struct irlan_client_cb client;     /* Client specific fields */
+	struct irlan_client_cb   client;   /* Client specific fields */
 	struct irlan_provider_cb provider; /* Provider specific fields */
+
+	__u32 max_sdu_size;
+	__u8  max_header_size;
 	
 	struct timer_list watchdog_timer;
 };
@@ -191,6 +203,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);
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irlan_eth.h linux/include/net/irda/irlan_eth.h
--- v2.2.9/linux/include/net/irda/irlan_eth.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/irlan_eth.h	Mon Jun  7 16:19:59 1999
@@ -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_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);
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irlan_provider.h linux/include/net/irda/irlan_provider.h
--- v2.2.9/linux/include/net/irda/irlan_provider.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/irlan_provider.h	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 14:29:16 1999
+ * Modified at:   Sun May  9 12:26:11 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 <dagb@cs.uit.no>, 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 
@@ -36,13 +36,7 @@
 					       LM_REASON reason, 
 					       struct sk_buff *skb);
 
-void irlan_provider_ctrl_data_indication(void *instance, void *sap,
-					 struct sk_buff *skb);
 
-void irlan_provider_connect_indication(void *instance, void *sap, 
-				       struct qos_info *qos, 
-				       __u32 max_sdu_size,
-				       struct sk_buff *skb);
 void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *);
 
 int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb);
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irlap.h linux/include/net/irda/irlap.h
--- v2.2.9/linux/include/net/irda/irlap.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/irlap.h	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Apr 23 09:51:15 1999
+ * Modified at:   Sun May  9 11:38:18 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 <dagb@cs.uit.no>, 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 
@@ -42,11 +42,11 @@
 #define LAP_COMP_HEADER 1  /* IrLAP Compression Header */
 
 #ifdef CONFIG_IRDA_COMPRESSION
-#  define LAP_HEADER  (LAP_ADDR_HEADER + LAP_CTRL_HEADER + LAP_COMP_HEADER)
+#  define LAP_MAX_HEADER  (LAP_ADDR_HEADER + LAP_CTRL_HEADER + LAP_COMP_HEADER)
 #  define IRDA_COMPRESSED 1
 #  define IRDA_NORMAL     0
 #else
-#define LAP_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
+#define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
 #endif
 
 #define BROADCAST  0xffffffff /* Broadcast device address */
@@ -138,7 +138,7 @@
 
 	__u8    vs;           /* Next frame to be sent */
 	__u8    vr;           /* Next frame to be received */
-	int     tmp;
+/* 	int     tmp; */
 	__u8    va;           /* Last frame acked */
  	int     window;       /* Nr of I-frames allowed to send */
 	int     window_size;  /* Current negotiated window size */
@@ -155,8 +155,7 @@
  	__u8    s;           /* Current slot */
 	int     frame_sent;  /* Have we sent reply? */
 
-	int discovery_count;
-	hashbin_t *discovery_log;
+	hashbin_t   *discovery_log;
  	discovery_t *discovery_cmd;
 
 	struct qos_info qos_tx;    /* QoS requested by peer */
@@ -226,5 +225,10 @@
 void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *);
 void irlap_apply_default_connection_parameters(struct irlap_cb *self);
 void irlap_apply_connection_parameters(struct irlap_cb *, struct qos_info *);
+
+extern inline __u8 irlap_get_header_size(struct irlap_cb *self)
+{
+	return 2;
+}
 
 #endif
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irlmp.h linux/include/net/irda/irlmp.h
--- v2.2.9/linux/include/net/irda/irlmp.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/irlmp.h	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Fri Apr 23 09:15:07 1999
+ * Modified at:   Sun May  9 11:01:34 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 <dagb@cs.uit.no>, 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 
@@ -52,7 +52,7 @@
 
 #define LMP_HEADER          2    /* Dest LSAP + Source LSAP */
 #define LMP_CONTROL_HEADER  4
-#define LMP_MAX_HEADER      (LAP_HEADER+LMP_HEADER)
+#define LMP_MAX_HEADER      (LMP_CONTROL_HEADER+LAP_MAX_HEADER)
 
 #define LM_MAX_CONNECTIONS  10
 
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irlpt_common.h linux/include/net/irda/irlpt_common.h
--- v2.2.9/linux/include/net/irda/irlpt_common.h	Wed Mar 10 15:29:50 1999
+++ linux/include/net/irda/irlpt_common.h	Sun May 30 10:17:03 1999
@@ -158,7 +158,8 @@
 	struct miscdevice ir_dev; /* used to register the misc device. */
 
 	int count;                /* open count */
-	int irlap_data_size;	/* max frame size we can send */
+	int max_data_size;	/* max frame size we can send */
+	int max_header_size;    /* how much header space is needed */
 	int pkt_count;		/* how many packets are queued up */
 
 	struct wait_queue *read_wait;	/* wait queues */
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irport.h linux/include/net/irda/irport.h
--- v2.2.9/linux/include/net/irda/irport.h	Wed Jan 20 23:14:06 1999
+++ linux/include/net/irda/irport.h	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug  3 13:49:59 1997
- * Modified at:   Thu Jan  7 14:17:31 1999
+ * Modified at:   Wed May 19 15:31:16 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997, 1998 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -49,13 +49,14 @@
 
 #define FRAME_MAX_SIZE 2048
 
-void irport_close( int iobase);
-int  irport_open( int iobase);
-int  irport_detect(struct irda_device *idev);
+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( int iobase, int speed);
+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);
+int  irport_hard_xmit(struct sk_buff *skb, struct device *dev);
+void irport_wait_until_sent(struct irda_device *idev);
 
 #endif
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irqueue.h linux/include/net/irda/irqueue.h
--- v2.2.9/linux/include/net/irda/irqueue.h	Fri Apr 16 14:47:31 1999
+++ linux/include/net/irda/irqueue.h	Mon Jun  7 16:19:59 1999
@@ -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>
@@ -29,8 +29,6 @@
 
 #include <linux/types.h>
 #include <asm/spinlock.h>
-
-/* #include <net/irda/irda.h> */
 
 #ifndef QUEUE_H
 #define QUEUE_H
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irttp.h linux/include/net/irda/irttp.h
--- v2.2.9/linux/include/net/irda/irttp.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/irda/irttp.h	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Sat Apr 10 10:19:56 1999
+ * Modified at:   Mon May 10 19:14:51 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 <dagb@cs.uit.no>, 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 
@@ -36,7 +36,8 @@
 
 #define TTP_MAX_CONNECTIONS    LM_MAX_CONNECTIONS
 #define TTP_HEADER             1
-#define TTP_HEADER_WITH_SAR    6
+#define TTP_MAX_HEADER         (TTP_HEADER + LMP_MAX_HEADER)
+#define TTP_SAR_HEADER         5
 #define TTP_PARAMETERS         0x80
 #define TTP_MORE               0x80
 
@@ -61,8 +62,6 @@
 	QUEUE queue;          /* For linking it into the hashbin */
 	int  magic;           /* Just in case */
 
-	int max_seg_size;     /* Max data that fit into an IrLAP frame */
-
 	__u8 stsap_sel;       /* Source TSAP */
 	__u8 dtsap_sel;       /* Destination TSAP */
 
@@ -88,6 +87,9 @@
 	struct irda_statistics stats;
 	struct timer_list todo_timer; 
 	
+	__u32 max_seg_size;     /* Max data that fit into an IrLAP frame */
+	__u8  max_header_size;
+
 	int   rx_sdu_busy;     /* RxSdu.busy */
 	__u32 rx_sdu_size;     /* Current size of a partially received frame */
 	__u32 rx_max_sdu_size; /* Max receive user data size */
@@ -120,8 +122,6 @@
 			  __u32 saddr, __u32 daddr,
 			  struct qos_info *qos, __u32 max_sdu_size, 
 			  struct sk_buff *userdata);
-void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-			   __u32 max_sdu_size, struct sk_buff *skb);
 void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, 
 			    struct sk_buff *userdata);
 struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irtty.h linux/include/net/irda/irtty.h
--- v2.2.9/linux/include/net/irda/irtty.h	Wed Mar 10 15:29:50 1999
+++ linux/include/net/irda/irtty.h	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Sun Feb  7 01:57:33 1999
+ * Modified at:   Mon May 10 13:22:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  *  
- *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 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 
@@ -33,8 +33,6 @@
 #include <net/irda/irqueue.h>
 #include <net/irda/irda_device.h>
 
-#include <net/irda/dongle.h>
-
 #define IRTTY_IOC_MAGIC 'e'
 #define IRTTY_IOCTDONGLE  _IO(IRTTY_IOC_MAGIC, 1)
 #define IRTTY_IOC_MAXNR   1
@@ -43,28 +41,21 @@
 #define N_IRDA         11   /* This one should go in </asm/termio.h> */
 #endif
 
-struct dongle_q {
-	QUEUE q;
-
-	struct dongle *dongle;
-};
-
 struct irtty_cb {
 	QUEUE q; /* Must be first */
 
-/* 	char name[16]; */
-
 	int	magic;
 	
 	struct  tty_struct  *tty;  /* Ptr to TTY structure */
 	struct  irda_device idev;
-
-	struct dongle_q *dongle_q; /* Has this tty got a dongle attached? */
 };
  
-int irtty_register_dongle( struct dongle *dongle);
-void irtty_unregister_dongle( struct dongle *dongle);
-
-void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts);
+int irtty_register_dongle(struct dongle *dongle);
+void irtty_unregister_dongle(struct dongle *dongle);
 
 #endif
+
+
+
+
+
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/irvtd.h linux/include/net/irda/irvtd.h
--- v2.2.9/linux/include/net/irda/irvtd.h	Fri Apr 16 14:47:31 1999
+++ linux/include/net/irda/irvtd.h	Mon Jun  7 16:19:59 1999
@@ -53,6 +53,8 @@
 	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 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 -u --recursive --new-file v2.2.9/linux/include/net/irda/smc-ircc.h linux/include/net/irda/smc-ircc.h
--- v2.2.9/linux/include/net/irda/smc-ircc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/smc-ircc.h	Mon Jun  7 16:19:59 1999
@@ -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 -u --recursive --new-file v2.2.9/linux/include/net/irda/smc_ircc.h linux/include/net/irda/smc_ircc.h
--- v2.2.9/linux/include/net/irda/smc_ircc.h	Tue Dec 22 14:16:58 1998
+++ linux/include/net/irda/smc_ircc.h	Wed Dec 31 16:00:00 1969
@@ -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
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/toshoboe.h linux/include/net/irda/toshoboe.h
--- v2.2.9/linux/include/net/irda/toshoboe.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/toshoboe.h	Sun May 30 10:17:03 1999
@@ -0,0 +1,165 @@
+/*********************************************************************
+ *                
+ * Filename:      toshoboe.h
+ * Version:       0.1
+ * Description:   Driver for the Toshiba OBOE (or type-O)
+ *                FIR Chipset. 
+ * Status:        Experimental.
+ * Author:        James McKenzie <james@fishsoup.dhs.org>
+ * Created at:    Sat May 8  12:35:27 1999
+ * 
+ *     Copyright (c) 1999 James McKenzie, 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 James McKenzie nor Cambridge University admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *
+ *     Applicable Models : Libretto 100CT. and many more
+ *
+ ********************************************************************/
+
+/*
+ * $Log: toshoboe.h,v $
+ * Revision 1.2  1999/05/09 01:43:08  root
+ * *** empty log message ***
+ *
+ * Revision 1.1  1999/05/09 01:25:58  root
+ * Initial revision
+ *
+ */
+
+#ifndef TOSHOBOE_H
+#define TOSHOBOE_H
+
+/* Registers */
+/*Receive and transmit task registers (read only) */
+#define OBOE_RCVT	(0x00+(self->base))
+#define OBOE_XMTT	(0x01+(self->base))
+#define OBOE_XMTT_OFFSET	0x40
+
+/*Page pointers to the TaskFile structure */
+#define OBOE_TFP2	(0x02+(self->base))
+#define OBOE_TFP0	(0x04+(self->base))
+#define OBOE_TFP1	(0x05+(self->base))
+
+/*Dunno */
+#define OBOE_REG_3	(0x03+(self->base))
+
+/*Number of tasks to use in Xmit and Recv queues */
+#define OBOE_NTR	(0x07+(self->base))
+#define OBOE_NTR_XMIT4	0x00
+#define OBOE_NTR_XMIT8	0x10
+#define OBOE_NTR_XMIT16	0x30
+#define OBOE_NTR_XMIT32	0x70
+#define OBOE_NTR_XMIT64	0xf0
+#define OBOE_NTR_RECV4	0x00
+#define OBOE_NTR_RECV8	0x01
+#define OBOE_NTR_RECV6	0x03
+#define OBOE_NTR_RECV32	0x07
+#define OBOE_NTR_RECV64	0x0f
+
+/* Dunno */
+#define OBOE_REG_9	(0x09+(self->base))
+
+/* Interrupt Status Register */
+#define OBOE_ISR	(0x0c+(self->base))
+#define OBOE_ISR_TXDONE	0x80
+#define OBOE_ISR_RXDONE	0x40
+#define OBOE_ISR_20	0x20
+#define OBOE_ISR_10	0x10
+#define OBOE_ISR_8	0x08         /*This is collision or parity or something */
+#define OBOE_ISR_4	0x08
+#define OBOE_ISR_2	0x08
+#define OBOE_ISR_1	0x08
+
+/*Dunno */
+#define OBOE_REG_D	(0x0d+(self->base))
+
+/*Register Lock Register */
+#define OBOE_LOCK	((self->base)+0x0e)
+
+
+
+/*Speed control registers */
+#define OBOE_PMDL	(0x10+(self->base))
+#define OBOE_PMDL_SIR	0x18
+#define OBOE_PMDL_MIR	0xa0
+#define OBOE_PMDL_FIR	0x40
+
+#define OBOE_SMDL	(0x18+(self->base))
+#define OBOE_SMDL_SIR	0x20
+#define OBOE_SMDL_MIR	0x01
+#define OBOE_SMDL_FIR	0x0f
+
+#define OBOE_UDIV	(0x19+(self->base))
+
+/*Dunno */
+#define OBOE_REG_11	(0x11+(self->base))
+
+/*Chip Reset Register */
+#define OBOE_RST	(0x15+(self->base))
+#define OBOE_RST_WRAP	0x8
+
+/*Dunno */
+#define OBOE_REG_1A	(0x1a+(self->base))
+#define OBOE_REG_1B	(0x1b+(self->base))
+
+/* The PCI ID of the OBOE chip */
+#ifndef PCI_DEVICE_ID_FIR701
+#define PCI_DEVICE_ID_FIR701 	0x0701
+#endif
+
+typedef unsigned int dword;
+typedef unsigned short int word;
+typedef unsigned char byte;
+typedef dword Paddr;
+
+struct OboeTask
+  {
+    __u16 len;
+    __u8 unused;
+    __u8 control;
+    __u32 buffer;
+  };
+
+#define OBOE_NTASKS 64
+
+struct OboeTaskFile
+  {
+    struct OboeTask recv[OBOE_NTASKS];
+    struct OboeTask xmit[OBOE_NTASKS];
+  };
+
+#define OBOE_TASK_BUF_LEN (sizeof(struct OboeTaskFile) << 1)
+
+/*These set the number of slots in use */
+#define TX_SLOTS	4
+#define RX_SLOTS	4
+
+/* You need also to change this, toshiba uses 4,8 and 4,4 */
+/* It makes no difference if you are only going to use ONETASK mode */
+/* remember each buffer use XX_BUF_SZ more _PHYSICAL_ memory */
+#define OBOE_NTR_VAL 	(OBOE_NTR_XMIT4 | OBOE_NTR_RECV4)
+
+struct toshoboe_cb
+  {
+    struct irda_device idev;    /*IRDA device */
+    struct pci_dev *pdev;       /*PCI device */
+    int base;                   /*IO base */
+    int txpending;              /*how many tx's are pending */
+    int txs, rxs;               /*Which slots are we at  */
+    void *taskfilebuf;          /*The unaligned taskfile buffer */
+    struct OboeTaskFile *taskfile;  /*The taskfile   */
+    void *xmit_bufs[TX_SLOTS];  /*The buffers   */
+    void *recv_bufs[RX_SLOTS];
+  };
+
+
+#endif
+
+
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/w83977af_ir.h linux/include/net/irda/w83977af_ir.h
--- v2.2.9/linux/include/net/irda/w83977af_ir.h	Tue Dec 22 14:16:58 1998
+++ linux/include/net/irda/w83977af_ir.h	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Thu Nov 19 13:55:34 1998
- * Modified at:   Thu Dec 10 14:06:18 1998
+ * Modified at:   Mon May  3 12:07:25 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 
@@ -149,6 +149,29 @@
 #define IRM_CR		0x07 /* Infrared module control register */
 #define IRM_CR_IRX_MSL	0x40
 #define IRM_CR_AF_MNT   0x80 /* Automatic format */
+
+/* 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 w83977af_ir {
+	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;
+};
 
 static inline void switch_bank( int iobase, int set)
 {
diff -u --recursive --new-file v2.2.9/linux/include/net/irda/wrapper.h linux/include/net/irda/wrapper.h
--- v2.2.9/linux/include/net/irda/wrapper.h	Wed Mar 10 15:29:50 1999
+++ linux/include/net/irda/wrapper.h	Sun May 30 10:17:03 1999
@@ -1,15 +1,16 @@
 /*********************************************************************
  *                
  * Filename:      wrapper.h
- * Version:       1.0
- * Description:   IrDA Wrapper layer
+ * Version:       1.2
+ * Description:   IrDA SIR async wrapper layer
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Jan 29 10:15:46 1999
+ * Modified at:   Mon May  3 09:02:36 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 <dagb@cs.uit.no>, 
+ *     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 
@@ -38,17 +39,18 @@
 #define STA BOF  /* Start flag */
 #define STO EOF  /* End flag */
 
-#define IR_TRANS 0x20    /* Asynchronous transparency modifier */       
+#define IRDA_TRANS 0x20    /* Asynchronous transparency modifier */       
 
+/* States for receving a frame in async mode */
 enum {
-	OUTSIDE_FRAME = 1, 
+	OUTSIDE_FRAME, 
 	BEGIN_FRAME, 
 	LINK_ESCAPE, 
 	INSIDE_FRAME
 };
 
 /* Proto definitions */
-int  async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize);
-void async_unwrap_char( struct irda_device *, __u8 byte);
+int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize);
+inline void async_unwrap_char(struct irda_device *idev, __u8 byte);
 
 #endif
diff -u --recursive --new-file v2.2.9/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.2.9/linux/include/net/tcp.h	Thu May 13 23:10:31 1999
+++ linux/include/net/tcp.h	Thu Jun  3 08:26:38 1999
@@ -290,7 +290,7 @@
 #define TCP_PROBEWAIT_LEN (1*HZ)/* time to wait between probes when
 				 * I've got something to write and
 				 * there is no window			*/
-#define TCP_KEEPALIVE_TIME (180*60*HZ)		/* two hours */
+#define TCP_KEEPALIVE_TIME (120*60*HZ)		/* two hours */
 #define TCP_KEEPALIVE_PROBES	9		/* Max of 9 keepalive probes	*/
 #define TCP_KEEPALIVE_PERIOD ((75*HZ)>>2)	/* period of keepalive check	*/
 
diff -u --recursive --new-file v2.2.9/linux/include/scsi/scsicam.h linux/include/scsi/scsicam.h
--- v2.2.9/linux/include/scsi/scsicam.h	Thu Jun 12 15:29:27 1997
+++ linux/include/scsi/scsicam.h	Wed Jun  9 16:59:34 1999
@@ -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 */
diff -u --recursive --new-file v2.2.9/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.2.9/linux/include/scsi/sg.h	Tue May 11 13:10:32 1999
+++ linux/include/scsi/sg.h	Mon Jun  7 16:27:06 1999
@@ -12,10 +12,16 @@
 *       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 @@
     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 @@
         - 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 @@
  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.
+ 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 can be found at www.torque.net/sg
+ 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 @@
     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 @@
     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 @@
 #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 @@
 /* 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
diff -u --recursive --new-file v2.2.9/linux/kernel/signal.c linux/kernel/signal.c
--- v2.2.9/linux/kernel/signal.c	Tue May 11 13:10:32 1999
+++ linux/kernel/signal.c	Mon Jun  7 16:14:21 1999
@@ -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 @@
 
 		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 @@
 	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);
diff -u --recursive --new-file v2.2.9/linux/kernel/sys.c linux/kernel/sys.c
--- v2.2.9/linux/kernel/sys.c	Fri Nov 27 13:09:30 1998
+++ linux/kernel/sys.c	Mon Jun  7 16:18:16 1999
@@ -900,6 +900,8 @@
 		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)) &&
diff -u --recursive --new-file v2.2.9/linux/mm/memory.c linux/mm/memory.c
--- v2.2.9/linux/mm/memory.c	Fri Apr 16 14:47:31 1999
+++ linux/mm/memory.c	Tue Jun  8 12:47:16 1999
@@ -622,7 +622,7 @@
 	
 	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 @@
 		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;
diff -u --recursive --new-file v2.2.9/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.2.9/linux/mm/swapfile.c	Wed Mar 10 15:29:50 1999
+++ linux/mm/swapfile.c	Mon Jun  7 16:27:06 1999
@@ -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 @@
 	} 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;
diff -u --recursive --new-file v2.2.9/linux/net/core/datagram.c linux/net/core/datagram.c
--- v2.2.9/linux/net/core/datagram.c	Mon Oct  5 13:13:47 1998
+++ linux/net/core/datagram.c	Wed Jun  2 11:29:28 1999
@@ -6,7 +6,7 @@
  *	This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and NetROM layer all have identical poll code and mostly
  *	identical recvmsg() code. So we share it here. The poll was shared before but buried in udp.c so I moved it.
  *
- *	Authors:	Alan Cox <alan@cymru.net>. (datagram_poll() from old udp.c code)
+ *	Authors:	Alan Cox <alan@redhat.com>. (datagram_poll() from old udp.c code)
  *
  *	Fixes:
  *		Alan Cox	:	NULL return from skb_peek_copy() understood
diff -u --recursive --new-file v2.2.9/linux/net/core/filter.c linux/net/core/filter.c
--- v2.2.9/linux/net/core/filter.c	Mon Mar 29 11:09:12 1999
+++ linux/net/core/filter.c	Sat May 15 17:43:52 1999
@@ -106,7 +106,7 @@
 				continue;
 
 			case BPF_ALU|BPF_MUL|BPF_K:
-				A *= X;
+				A *= fentry->k;
 				continue;
 
 			case BPF_ALU|BPF_DIV|BPF_X:
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.2.9/linux/net/ipv4/af_inet.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/af_inet.c	Wed Jun  2 09:55:22 1999
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.87 1999/04/22 10:07:33 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.87.2.1 1999/05/29 04:32:01 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -147,14 +147,8 @@
 	struct sk_buff *skb;
 
 	/* First the read buffer. */
-	while((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-		/* This will take care of closing sockets that were
-		 * listening and didn't accept everything.
-		 */
-		if (skb->sk != NULL && skb->sk != sk)
-			skb->sk->prot->close(skb->sk, 0);
+	while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
 		kfree_skb(skb);
-	}
 
 	/* Next, the error queue. */
 	while((skb = skb_dequeue(&sk->error_queue)) != NULL)
@@ -213,12 +207,6 @@
 
 	kill_sk_queues(sk);
 
-	/* Now if it has a half accepted/ closed socket. */
-	if (sk->pair) {
-		sk->pair->prot->close(sk->pair, 0);
-		sk->pair = NULL;
-  	}
-
 	/* Now if everything is gone we can free the socket
 	 * structure, otherwise we need to keep it around until
 	 * everything is gone.
@@ -684,14 +672,8 @@
 	if (sk1->prot->accept == NULL)
 		goto do_err;
 
-	/* Restore the state if we have been interrupted, and then returned. */
-	if (sk1->pair != NULL) {
-		sk2 = sk1->pair;
-		sk1->pair = NULL;
-	} else {
-		if((sk2 = sk1->prot->accept(sk1,flags)) == NULL)
-			goto do_sk1_err;
-	}
+	if((sk2 = sk1->prot->accept(sk1,flags)) == NULL)
+		goto do_sk1_err;
 
 	/*
 	 *	We've been passed an extra socket.
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.2.9/linux/net/ipv4/icmp.c	Tue Mar 23 14:35:48 1999
+++ linux/net/ipv4/icmp.c	Tue Jun  8 20:33:07 1999
@@ -1,9 +1,9 @@
 /*
  *	NET3:	Implementation of the ICMP protocol layer. 
  *	
- *		Alan Cox, <alan@cymru.net>
+ *		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
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v2.2.9/linux/net/ipv4/ip_fw.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/ip_fw.c	Tue Jun  8 20:33:07 1999
@@ -34,6 +34,9 @@
  *              Marc Santoro <ultima@snicker.emoti.com>
  * 29-Jan-1999: Locally generated bogus IPs dealt with, rather than crash
  *              during dump_packet. --RR.
+ * 19-May-1999: Star Wars: The Phantom Menace opened.  Rule num
+ *		printed in log (modified from Michael Hasenstein's patch).
+ *		Added SYN in log message. --RR
  */
 
 /*
@@ -400,7 +403,9 @@
 			struct ip_fwkernel *f, 
 			const ip_chainlabel chainlabel,
 			__u16 src_port, 
-			__u16 dst_port)
+			__u16 dst_port,
+			unsigned int count,
+			int syn)
 {
 	__u32 *opt = (__u32 *) (ip + 1);
 	int opti;
@@ -432,7 +437,7 @@
 
 	for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
 		printk(" O=0x%8.8X", *opt++);
-	printk("\n");
+	printk(" %s(#%d)\n", syn ? "SYN " : /* "PENANCE" */ "", count);
 }
 
 /* function for checking chain labels for user space. */
@@ -520,12 +525,14 @@
 	      const ip_chainlabel label,
 	      struct sk_buff *skb,
 	      unsigned int slot,
-	      __u16 src_port, __u16 dst_port)
+	      __u16 src_port, __u16 dst_port, 
+	      unsigned int count,
+	      int tcpsyn)
 {
 	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);
+		dump_packet(ip,rif,f,label,src_port,dst_port,count,tcpsyn);
 	}
 	ip->tos = (ip->tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor;
 
@@ -590,6 +597,7 @@
 	unsigned char		oldtos;
 	struct ip_fwkernel	*f;	
 	int			ret = FW_SKIP+2;
+	unsigned int		count;
 
 	/* We handle fragments by dealing with the first fragment as
 	 * if it was a normal packet.  All other fragments are treated
@@ -610,7 +618,7 @@
 	if (offset == 1 && ip->protocol == IPPROTO_TCP)	{
 		if (!testing && net_ratelimit()) {
 			printk("Suspect TCP fragment.\n");
-			dump_packet(ip,rif,NULL,NULL,0,0);
+			dump_packet(ip,rif,NULL,NULL,0,0,0,0);
 		}
 		return FW_BLOCK;
 	}
@@ -702,13 +710,16 @@
 
 	f = chain->chain;
 	do {
+		count = 0;
 		for (; f; f = f->next) {
+			count++;
 			if (ip_rule_match(f,rif,ip,
 					  tcpsyn,src_port,dst_port,offset)) {
 				if (!testing
 				    && !ip_fw_domatch(f, ip, rif, chain->label,
 						      skb, slot, 
-						      src_port, dst_port)) {
+						      src_port, dst_port,
+						      count, tcpsyn)) {
 					ret = FW_BLOCK;
 					goto out;
 				}
@@ -1408,8 +1419,10 @@
 		else if ((chain = find_label(new->fwc_label)) == NULL)
 			ret = ENOENT;
 		else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret))
-			 != NULL)
+			 != NULL) {
 			ret = del_rule_from_chain(chain, ip_fwkern);
+			kfree(ip_fwkern);
+		}
 	}
 	break;
 
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/ip_options.c linux/net/ipv4/ip_options.c
--- v2.2.9/linux/net/ipv4/ip_options.c	Tue Mar 23 14:35:48 1999
+++ linux/net/ipv4/ip_options.c	Wed Jun  2 09:55:22 1999
@@ -5,7 +5,7 @@
  *
  *		The options processing module for ip.c
  *
- * Version:	$Id: ip_options.c,v 1.16 1999/03/21 05:22:40 davem Exp $
+ * Version:	$Id: ip_options.c,v 1.16.2.1 1999/06/02 04:06:19 davem Exp $
  *
  * Authors:	A.N.Kuznetsov
  *		
@@ -452,7 +452,6 @@
 error:
 	if (skb) {
 		icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24));
-		kfree_skb(skb);
 	}
 	return -EINVAL;
 }
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.2.9/linux/net/ipv4/ipmr.c	Mon Mar 29 11:09:12 1999
+++ linux/net/ipv4/ipmr.c	Tue Jun  8 20:33:07 1999
@@ -1,7 +1,7 @@
 /*
  *	IP multicast routing support for mrouted 3.6/3.8
  *
- *		(c) 1995 Alan Cox, <alan@cymru.net>
+ *		(c) 1995 Alan Cox, <alan@redhat.com>
  *	  Linux Consultancy and Custom Driver Development
  *
  *	This program is free software; you can redistribute it and/or
@@ -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.
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.2.9/linux/net/ipv4/tcp.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp.c	Wed Jun  2 09:55:22 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.140 1999/04/22 10:34:31 davem Exp $
+ * Version:	$Id: tcp.c,v 1.140.2.1 1999/05/29 04:16:48 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -896,6 +896,7 @@
 					err = -ERESTARTSYS;
 					goto do_interrupted;
 				}
+				tcp_push_pending_frames(sk, tp);
 				wait_for_tcp_memory(sk);
 
 				/* If SACK's were formed or PMTU events happened,
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.2.9/linux/net/ipv4/tcp_input.c	Tue May 11 13:10:32 1999
+++ linux/net/ipv4/tcp_input.c	Wed Jun  2 09:55:22 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.164 1999/05/08 21:09:52 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.164.2.3 1999/06/02 04:15:06 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -748,7 +748,6 @@
 static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
 {
 	struct sk_buff *skb = skb_peek(&sk->write_queue);
-	__u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
 
 	/* Some data was ACK'd, if still retransmitting (due to a
 	 * timeout), resend more of the retransmit queue.  The
@@ -758,6 +757,9 @@
 		tcp_xmit_retransmit_queue(sk);
 		tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
 	} else {
+		__u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
+		if ((__s32)when < 0)
+			when = 1;
 		tcp_reset_xmit_timer(sk, TIME_RETRANS, when);
 	}
 }
@@ -785,8 +787,6 @@
 	if (after(ack, tp->snd_nxt) || before(ack, tp->snd_una))
 		goto uninteresting_ack;
 
-	dst_confirm(sk->dst_cache);
-
 	/* If there is data set flag 1 */
 	if (len != th->doff*4) {
 		flag |= FLAG_DATA;
@@ -882,6 +882,24 @@
 		/* Clear any aborted fast retransmit starts. */
 		tp->dup_acks = 0;
 	}
+	/* It is not a brain fart, I thought a bit now. 8)
+	 *
+	 * Forward progress is indicated, if:
+	 *   1. the ack acknowledges new data.
+	 *   2. or the ack is duplicate, but it is caused by new segment
+	 *      arrival. This case is filtered by:
+	 *      - it contains no data, syn or fin.
+	 *      - it does not update window.
+	 *   3. or new SACK. It is difficult to check, so that we ignore it.
+	 *
+	 * Forward progress is also indicated by arrival new data,
+	 * which was caused by window open from our side. This case is more
+	 * difficult and it is made (alas, incorrectly) in tcp_data_queue().
+	 *                                              --ANK (990513)
+	 */
+	if (ack != tp->snd_una || (flag == 0 && !th->fin))
+		dst_confirm(sk->dst_cache);
+
 	/* Remember the highest ack received. */
 	tp->snd_una = ack;
 	return 1;
@@ -1801,7 +1819,7 @@
 		}
 	}
 
-	flg = *(((u32 *)th) + 3) & ~htonl(0x8 << 16);
+	flg = *(((u32 *)th) + 3) & ~htonl(0xFC8 << 16);
 
 	/*	pred_flags is 0xS?10 << 16 + snd_wnd
 	 *	if header_predition is to be made
@@ -2067,21 +2085,81 @@
 		 * not be in line code. [AC]
 		 */
 		if(th->ack) {
-			tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
-
-			/* We got an ack, but it's not a good ack. */
-			if(!tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
-				    TCP_SKB_CB(skb)->ack_seq, len)) 
+			/* rfc793:
+			 * "If the state is SYN-SENT then
+			 *    first check the ACK bit
+			 *      If the ACK bit is set
+			 *	  If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send
+			 *        a reset (unless the RST bit is set, if so drop
+			 *        the segment and return)"
+			 *
+			 *  I cite this place to emphasize one essential
+			 *  detail, this check is different of one
+			 *  in established state: SND.UNA <= SEG.ACK <= SND.NXT.
+			 *  SEG_ACK == SND.UNA == ISS is invalid in SYN-SENT,
+			 *  because we have no previous data sent before SYN.
+			 *                                        --ANK(990513)
+			 *
+			 *  We do not send data with SYN, so that RFC-correct
+			 *  test reduces to:
+			 */
+			if (sk->zapped ||
+			    TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
 				return 1;
 
-			if(th->rst) {
+			/* Now ACK is acceptable.
+			 *
+			 * "If the RST bit is set
+			 *    If the ACK was acceptable then signal the user "error:
+			 *    connection reset", drop the segment, enter CLOSED state,
+			 *    delete TCB, and return."
+			 */
+
+			if (th->rst) {
 				tcp_reset(sk);
 				goto discard;
 			}
 
-			if(!th->syn) 
+			/* rfc793:
+			 *   "fifth, if neither of the SYN or RST bits is set then
+			 *    drop the segment and return."
+			 *
+			 *    See note below!
+			 *                                        --ANK(990513)
+		         */
+			
+			if (!th->syn)
 				goto discard;
 
+			/* rfc793:
+			 *   "If the SYN bit is on ...
+			 *    are acceptable then ...
+			 *    (our SYN has been ACKed), change the connection
+			 *    state to ESTABLISHED..."
+			 *
+			 * Do you see? SYN-less ACKs in SYN-SENT state are
+			 * completely ignored.
+			 *
+			 * The bug causing stalled SYN-SENT sockets
+			 * was here: tcp_ack advanced snd_una and canceled
+			 * retransmit timer, so that bare ACK received
+			 * in SYN-SENT state (even with invalid ack==ISS,
+			 * because tcp_ack check is too weak for SYN-SENT)
+			 * causes moving socket to invalid semi-SYN-SENT,
+			 * semi-ESTABLISHED state and connection hangs.
+			 *
+			 * There exist buggy stacks, which really send
+			 * such ACKs: f.e. 202.226.91.94 (okigate.oki.co.jp)
+			 * Actually, if this host did not try to get something
+			 * from ftp.inr.ac.ru I'd never find this bug 8)
+			 *
+			 *                                     --ANK (990514)
+			 */
+
+			tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+			tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
+				TCP_SKB_CB(skb)->ack_seq, len);
+
 			/* Ok.. it's good. Set up sequence numbers and
 			 * move to established.
 			 */
@@ -2206,8 +2284,8 @@
 	    !(th->fin && TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt)) {
 		if (!th->rst) {
 			tcp_send_ack(sk);
-			goto discard;
 		}
+		goto discard;
 	}
 
 	/* step 2: check RST bit */
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.2.9/linux/net/ipv4/tcp_ipv4.c	Tue May 11 13:10:32 1999
+++ linux/net/ipv4/tcp_ipv4.c	Wed Jun  2 09:55:22 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.175 1999/05/08 21:09:54 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.175.2.2 1999/06/02 04:06:15 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -1328,7 +1328,6 @@
 
 		newsk->done = 0;
 		newsk->proc = 0;
-		newsk->pair = NULL;
 		skb_queue_head_init(&newsk->back_log);
 		skb_queue_head_init(&newsk->error_queue);
 #ifdef CONFIG_FILTER
@@ -1648,6 +1647,7 @@
 	/* Count it even if it's bad */
 	tcp_statistics.TcpInSegs++;
 
+	len = skb->len;
 	if (len < sizeof(struct tcphdr))
 		goto bad_packet;
 
@@ -1673,6 +1673,10 @@
 	default:
 		/* CHECKSUM_UNNECESSARY */
 	}
+
+	if((th->doff * 4) < sizeof(struct tcphdr) ||
+	   len < (th->doff * 4))
+		goto bad_packet;
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	if (IPCB(skb)->redirport)
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.2.9/linux/net/ipv4/tcp_output.c	Tue May 11 13:10:32 1999
+++ linux/net/ipv4/tcp_output.c	Wed Jun  2 09:55:22 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.108 1999/05/08 21:48:59 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.108.2.1 1999/05/14 23:07:36 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -239,6 +239,11 @@
 
 	/* Rechecksum original buffer. */
 	skb->csum = csum_partial(skb->data, skb->len, 0);
+
+	/* Looks stupid, but our code really uses when of
+	 * skbs, which it never sent before. --ANK
+	 */
+	TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
 
 	/* Link BUFF into the send queue. */
 	__skb_append(skb, buff);
diff -u --recursive --new-file v2.2.9/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.2.9/linux/net/ipv4/tcp_timer.c	Tue May 11 13:10:32 1999
+++ linux/net/ipv4/tcp_timer.c	Wed Jun  2 09:55:22 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.62 1999/05/08 21:09:55 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.62.2.2 1999/06/02 04:06:21 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -537,14 +537,11 @@
 					conn = req;
 					req = req->dl_next;
 
-					if (conn->sk) {
+					if (conn->sk ||
+					    ((long)(now - conn->expires)) <= 0) {
 						prev = conn; 
 						continue; 
 					}
-
-					if ((long)(now - conn->expires) <= 0)
-						break;
-
 
 					tcp_synq_unlink(tp, conn, prev);
 					if (conn->retrans >= sysctl_tcp_retries1) {
diff -u --recursive --new-file v2.2.9/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c
--- v2.2.9/linux/net/ipv6/icmp.c	Tue Mar 23 14:35:48 1999
+++ linux/net/ipv6/icmp.c	Sat May 29 11:10:33 1999
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: icmp.c,v 1.21 1999/03/21 05:22:51 davem Exp $
+ *	$Id: icmp.c,v 1.21.2.1 1999/05/19 22:07:36 davem Exp $
  *
  *	Based on net/ipv4/icmp.c
  *
@@ -315,6 +315,7 @@
 	fl.nl_u.ip6_u.daddr = &hdr->saddr;
 	fl.nl_u.ip6_u.saddr = saddr;
 	fl.oif = iif;
+	fl.fl6_flowlabel = 0;
 	fl.uli_u.icmpt.type = type;
 	fl.uli_u.icmpt.code = code;
 
@@ -388,6 +389,7 @@
 	fl.nl_u.ip6_u.daddr = &hdr->saddr;
 	fl.nl_u.ip6_u.saddr = saddr;
 	fl.oif = skb->dev->ifindex;
+	fl.fl6_flowlabel = 0;
 	fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY;
 	fl.uli_u.icmpt.code = 0;
 
diff -u --recursive --new-file v2.2.9/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.2.9/linux/net/ipv6/tcp_ipv6.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv6/tcp_ipv6.c	Wed Jun  2 09:55:22 1999
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.104 1999/04/24 00:27:25 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.104.2.2 1999/06/02 04:06:27 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -551,7 +551,7 @@
 
 failure:
 	dst_release(xchg(&sk->dst_cache, NULL));
-	memcpy(&np->daddr, 0, sizeof(struct in6_addr));
+	memset(&np->daddr, 0, sizeof(struct in6_addr));
 	sk->daddr = 0;
 	return err;
 }
@@ -1362,6 +1362,7 @@
 
 	tcp_statistics.TcpInSegs++;
 
+	len = skb->len;
 	if (len < sizeof(struct tcphdr))
 		goto bad_packet;
 
@@ -1382,6 +1383,10 @@
 	default:
 		/* CHECKSUM_UNNECESSARY */
 	};
+
+	if((th->doff * 4) < sizeof(struct tcphdr) ||
+	   len < (th->doff * 4))
+		goto bad_packet;
 
 	sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
 
diff -u --recursive --new-file v2.2.9/linux/net/irda/Config.in linux/net/irda/Config.in
--- v2.2.9/linux/net/irda/Config.in	Fri Apr 16 14:47:31 1999
+++ linux/net/irda/Config.in	Mon Jun  7 16:19:59 1999
@@ -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
 
diff -u --recursive --new-file v2.2.9/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- v2.2.9/linux/net/irda/af_irda.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/af_irda.c	Mon Jun  7 16:19:59 1999
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 31 10:12:43 1998
- * Modified at:   Thu Apr 22 12:08:04 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.
  * 
@@ -30,6 +30,7 @@
 #include <linux/if_arp.h>
 #include <linux/net.h>
 #include <linux/irda.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 
@@ -46,11 +47,12 @@
 extern int  irlap_driver_rcv(struct sk_buff *, struct device *, 
 			     struct packet_type *);
 
-static struct proto_ops irda_proto_ops;
+static struct proto_ops irda_stream_ops;
+static struct proto_ops irda_dgram_ops;
 static hashbin_t *cachelog = NULL;
 static struct wait_queue *discovery_wait; /* Wait for discovery */
 
-#define IRDA_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER)
+#define IRDA_MAX_HEADER (TTP_MAX_HEADER)
 
 /*
  * Function irda_data_indication (instance, sap, skb)
@@ -121,7 +123,8 @@
  */
 static void irda_connect_confirm(void *instance, void *sap, 
 				 struct qos_info *qos,
-				 __u32 max_sdu_size, struct sk_buff *skb)
+				 __u32 max_sdu_size, __u8 max_header_size, 
+				 struct sk_buff *skb)
 {
 	struct irda_sock *self;
 	struct sock *sk;
@@ -130,13 +133,28 @@
 
 	self = (struct irda_sock *) instance;
 
+	/* How much header space do we need to reserve */
+	self->max_header_size = max_header_size;
+
+	/* IrTTP max SDU size in transmit direction */
 	self->max_sdu_size_tx = max_sdu_size;
+
+	/* Find out what the largest chunk of data that we can transmit is */
+	if (max_sdu_size == SAR_DISABLE)
+		self->max_data_size = qos->data_size.value - max_header_size;
+	else
+		self->max_data_size = max_sdu_size;
+
+	DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+
 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
 
 	sk = self->sk;
 	if (sk == NULL)
 		return;
 
+	skb_queue_tail(&sk->receive_queue, skb);
+
 	/* We are now connected! */
 	sk->state = TCP_ESTABLISHED;
 	sk->state_change(sk);
@@ -150,7 +168,7 @@
  */
 static void irda_connect_indication(void *instance, void *sap, 
 				    struct qos_info *qos, __u32 max_sdu_size,
-				    struct sk_buff *skb)
+				    __u8 max_header_size, struct sk_buff *skb)
 {
 	struct irda_sock *self;
 	struct sock *sk;
@@ -158,8 +176,21 @@
 	DEBUG(1, __FUNCTION__ "()\n");
 
 	self = (struct irda_sock *) instance;
-	
-	self->max_sdu_size_tx = max_sdu_size;
+
+	/* How much header space do we need to reserve */
+	self->max_header_size = max_header_size;
+
+	/* IrTTP max SDU size in transmit direction */
+	self->max_sdu_size_tx = max_sdu_size;	
+
+	/* Find out what the largest chunk of data that we can transmit is */
+	if (max_sdu_size == SAR_DISABLE)
+		self->max_data_size = qos->data_size.value - max_header_size;
+	else
+		self->max_data_size = max_sdu_size;
+
+	DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+
 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
 
 	sk = self->sk;
@@ -187,12 +218,12 @@
 
 	skb = dev_alloc_skb(64);
 	if (skb == NULL) {
-		DEBUG( 0, __FUNCTION__ "() Could not allocate sk_buff!\n");
+		DEBUG(0, __FUNCTION__ "() Unable to allocate sk_buff!\n");
 		return;
 	}
 
 	/* Reserve space for MUX_CONTROL and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER);
+	skb_reserve(skb, IRDA_MAX_HEADER);
 
 	irttp_connect_response(self->tsap, self->max_sdu_size_rx, skb);
 }
@@ -219,12 +250,12 @@
 	
 	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:
@@ -514,10 +545,13 @@
 	new->stsap_sel = new->tsap->stsap_sel;
 	new->dtsap_sel = new->tsap->dtsap_sel;
 	new->saddr = irttp_get_saddr(new->tsap);
-	new->saddr = irttp_get_saddr(new->tsap);
+	new->daddr = irttp_get_daddr(new->tsap);
 
 	new->max_sdu_size_tx = self->max_sdu_size_tx;
 	new->max_sdu_size_rx = self->max_sdu_size_rx;
+	new->max_data_size   = self->max_data_size;
+	new->max_header_size = self->max_header_size;
+
 	memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info));
 
 	/* Clean up the original one to keep it in listen state */
@@ -669,7 +703,11 @@
 
 	sock_init_data(sock, sk);
 
-	sock->ops    = &irda_proto_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 */
@@ -786,12 +824,20 @@
 			return -ENOTCONN;
 	}
 
-	skb = sock_alloc_send_skb(sk, len + IRDA_MAX_HEADER, 0, 
+	/* Check that we don't send out to big frames */
+	if (len > self->max_data_size) {
+		DEBUG(0, __FUNCTION__ "(), Warning to much data! "
+		      "Chopping frame from %d to %d bytes!\n", len, 
+		      self->max_data_size);
+		len = self->max_data_size;
+	}
+
+	skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, 
 				  msg->msg_flags & MSG_DONTWAIT, &err);
 	if (!skb)
 		return -ENOBUFS;
 
-	skb_reserve(skb, IRDA_MAX_HEADER);
+	skb_reserve(skb, self->max_header_size);
 	
 	DEBUG(4, __FUNCTION__ "(), appending user data\n");
 	asmptr = skb->h.raw = skb_put(skb, len);
@@ -815,8 +861,8 @@
  *    Try to receive message and copy it to user
  *
  */
-static int irda_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-			int flags, struct scm_cookie *scm)
+static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg, 
+			      int size, int flags, struct scm_cookie *scm)
 {
 	struct irda_sock *self;
 	struct sock *sk = sock->sk;
@@ -862,6 +908,161 @@
 }
 
 /*
+ * Function irda_data_wait (sk)
+ *
+ *    Sleep until data has arrive. But check for races..
+ *
+ */
+static void irda_data_wait(struct sock *sk)
+{
+	if (!skb_peek(&sk->receive_queue)) {
+		sk->socket->flags |= SO_WAITDATA;
+		interruptible_sleep_on(sk->sleep);
+		sk->socket->flags &= ~SO_WAITDATA;
+	}
+}
+
+/*
+ * Function irda_recvmsg_stream (sock, msg, size, flags, scm)
+ *
+ *    
+ *
+ */
+static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg, 
+			       int size, int flags, struct scm_cookie *scm)
+{
+	struct irda_sock *self;
+	struct sock *sk = sock->sk;
+	int noblock = flags & MSG_DONTWAIT;
+	int copied = 0;
+	int target = 1;
+
+	DEBUG(3, __FUNCTION__ "()\n");
+
+	self = sk->protinfo.irda;
+	ASSERT(self != NULL, return -1;);
+
+	if (sock->flags & SO_ACCEPTCON) 
+		return(-EINVAL);
+
+	if (flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	if (flags & MSG_WAITALL)
+		target = size;
+		
+		
+	msg->msg_namelen = 0;
+
+	/* Lock the socket to prevent queue disordering
+	 * while sleeps in memcpy_tomsg
+	 */
+/* 	down(&self->readsem); */
+
+	do {
+		int chunk;
+		struct sk_buff *skb;
+
+		skb=skb_dequeue(&sk->receive_queue);
+		if (skb==NULL) {
+			if (copied >= target)
+				break;
+			
+			/*
+			 *	POSIX 1003.1g mandates this order.
+			 */
+			
+			if (sk->err) {
+				/* up(&self->readsem); */
+				return sock_error(sk);
+			}
+
+			if (sk->shutdown & RCV_SHUTDOWN)
+				break;
+
+		/* 	up(&self->readsem); */
+
+			if (noblock)
+				return -EAGAIN;
+			irda_data_wait(sk);
+			if (signal_pending(current))
+				return -ERESTARTSYS;
+		/* 	down(&self->readsem); */
+			continue;
+		}
+
+		/* Never glue messages from different writers */
+/* 		if (check_creds && */
+/* 		    memcmp(UNIXCREDS(skb), &scm->creds, sizeof(scm->creds)) != 0) */
+/* 		{ */
+/* 			skb_queue_head(&sk->receive_queue, skb); */
+/* 			break; */
+/* 		} */
+
+		chunk = min(skb->len, size);
+		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
+			skb_queue_head(&sk->receive_queue, skb);
+			if (copied == 0)
+				copied = -EFAULT;
+			break;
+		}
+		copied += chunk;
+		size -= chunk;
+
+ 		/* Copy credentials */
+/* 		scm->creds = *UNIXCREDS(skb); */
+/* 		check_creds = 1; */
+
+		/* Mark read part of skb as used */
+		if (!(flags & MSG_PEEK)) {
+			skb_pull(skb, chunk);
+
+/* 			if (UNIXCB(skb).fp) */
+/* 				unix_detach_fds(scm, skb); */
+
+			/* put the skb back if we didn't use it up.. */
+			if (skb->len) {
+				DEBUG(1, __FUNCTION__ "(), back on q!\n");
+				skb_queue_head(&sk->receive_queue, skb);
+				break;
+			}
+
+			kfree_skb(skb);
+			
+/* 			if (scm->fp) */
+/* 				break; */
+		} else {
+			DEBUG(0, __FUNCTION__ "() questionable!?\n");
+			/* It is questionable, see note in unix_dgram_recvmsg. */
+/* 			if (UNIXCB(skb).fp) */
+/* 				scm->fp = scm_fp_dup(UNIXCB(skb).fp); */
+
+			/* put message back and return */
+			skb_queue_head(&sk->receive_queue, skb);
+			break;
+		}
+	} while (size);
+
+	/*
+	 *  Check if we have previously stopped IrTTP and we know
+	 *  have more free space in our rx_queue. If so tell IrTTP
+	 *  to start delivering frames again before our rx_queue gets
+	 *  empty
+	 */
+	if (self->rx_flow == FLOW_STOP) {
+		if ((atomic_read(&sk->rmem_alloc) << 2) <= sk->rcvbuf) {
+			DEBUG(2, __FUNCTION__ "(), Starting IrTTP\n");
+			self->rx_flow = FLOW_START;
+			irttp_flow_request(self->tsap, FLOW_START);
+		}
+	}
+
+	/* up(&self->readsem); */
+
+	return copied;
+}
+
+/*
  * Function irda_shutdown (sk, how)
  *
  *    
@@ -875,19 +1076,45 @@
         return -EOPNOTSUPP;
 }
 
-
 /*
  * Function irda_poll (file, sock, wait)
  *
  *    
  *
  */
-unsigned int irda_poll(struct file *file, struct socket *sock, 
-		       struct poll_table_struct *wait)
+static unsigned int irda_poll(struct file * file, struct socket *sock, 
+			      poll_table *wait)
 {
-	DEBUG(0, __FUNCTION__ "()\n");
+	struct sock *sk = sock->sk;
+	unsigned int mask;
 
-	return 0;
+	DEBUG(1, __FUNCTION__ "()\n");
+
+	poll_wait(file, sk->sleep, wait);
+	mask = 0;
+
+	/* exceptional events? */
+	if (sk->err)
+		mask |= POLLERR;
+	if (sk->shutdown & RCV_SHUTDOWN)
+		mask |= POLLHUP;
+
+	/* readable? */
+	if (!skb_queue_empty(&sk->receive_queue))
+		mask |= POLLIN | POLLRDNORM;
+
+	/* Connection-based need to check for termination and startup */
+	if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)
+		mask |= POLLHUP;
+
+	/*
+	 * we set writable also when the other side has shut down the
+	 * connection. This prevents stuck sockets.
+	 */
+	if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= MIN_WRITE_SPACE)
+			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+
+	return mask;
 }
 
 /*
@@ -900,7 +1127,7 @@
 {
 	struct sock *sk = sock->sk;
 
-	DEBUG(0, __FUNCTION__ "(), cmd=%#x\n", cmd);
+	DEBUG(4, __FUNCTION__ "(), cmd=%#x\n", cmd);
 	
 	switch (cmd) {
 	case TIOCOUTQ: {
@@ -947,6 +1174,7 @@
 		return -EINVAL;
 		
 	default:
+		DEBUG(1, __FUNCTION__ "(), doing device ioctl!\n");
 		return dev_ioctl(cmd, (void *) arg);
 	}
 
@@ -1082,13 +1310,7 @@
 			return -EFAULT;
 		break;
 	case IRTTP_MAX_SDU_SIZE:
-		if (self->max_sdu_size_tx != SAR_DISABLE)
-			val = self->max_sdu_size_tx;
-		else
-			/* SAR is disabled, so use the IrLAP data size
-			 * instead */
-			val = self->qos_tx.data_size.value - IRDA_MAX_HEADER;
-
+		val = self->max_data_size;
 		DEBUG(0, __FUNCTION__ "(), getting max_sdu_size = %d\n", val);
 		len = sizeof(int);
 		if (put_user(len, optlen))
@@ -1110,7 +1332,7 @@
 	irda_create
 };
 
-static struct proto_ops irda_proto_ops = {
+static struct proto_ops irda_stream_ops = {
 	PF_IRDA,
 	
 	sock_no_dup,
@@ -1128,7 +1350,28 @@
 	irda_getsockopt,
 	sock_no_fcntl,
 	irda_sendmsg,
-	irda_recvmsg
+	irda_recvmsg_stream
+};
+
+static struct proto_ops irda_dgram_ops = {
+	PF_IRDA,
+	
+	sock_no_dup,
+	irda_release,
+	irda_bind,
+	irda_connect,
+	sock_no_socketpair,
+	irda_accept,
+	irda_getname,
+	datagram_poll,
+	irda_ioctl,
+	irda_listen,
+	irda_shutdown,
+	irda_setsockopt,
+	irda_getsockopt,
+	sock_no_fcntl,
+	irda_sendmsg,
+	irda_recvmsg_dgram
 };
 
 /*
@@ -1215,7 +1458,7 @@
 	irda_packet_type.type = htons(ETH_P_IRDA);
         dev_remove_pack(&irda_packet_type);
 
-        unregister_netdevice_notifier( &irda_dev_notifier);
+        unregister_netdevice_notifier(&irda_dev_notifier);
 	
 	sock_unregister(PF_IRDA);
 	irda_cleanup();
diff -u --recursive --new-file v2.2.9/linux/net/irda/crc.c linux/net/irda/crc.c
--- v2.2.9/linux/net/irda/crc.c	Tue Dec 22 14:16:59 1998
+++ linux/net/irda/crc.c	Sun May 30 10:17:03 1999
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Sat Dec 12 09:56:35 1998
+ * Modified at:   Sun May  2 20:28:08 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       ppp.c by Michael Callahan <callahan@maths.ox.ac.uk>
  *                Al Longyear <longyear@netcom.com>
@@ -59,7 +59,7 @@
 
 unsigned short crc_calc( __u16 fcs, __u8 const *buf, size_t len) 
 {
-    while ( len--)
-		fcs = IR_FCS(fcs, *buf++);
-    return fcs;
+	while (len--)
+                fcs = irda_fcs(fcs, *buf++);
+	return fcs;
 }
diff -u --recursive --new-file v2.2.9/linux/net/irda/discovery.c linux/net/irda/discovery.c
--- v2.2.9/linux/net/irda/discovery.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/discovery.c	Mon Jun  7 16:19:59 1999
@@ -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 Apr 11 00:41:58 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.
@@ -39,28 +39,51 @@
 /*
  * Function irlmp_add_discovery (cachelog, discovery)
  *
- *    
- *
+ *    Add a new discovery to the cachelog, and remove any old discoveries
+ *    from the same device
  */
-void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery)
+void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new)
 {
-	discovery_t *old;
+	discovery_t *discovery, *node;
+	unsigned long flags;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	spin_lock_irqsave(&irlmp->lock, flags);
+
+	/* 
+	 * Remove all discoveries of devices that has previously been 
+	 * discovered on the same link with the same name (info), or the 
+	 * same daddr. We do this since some devices (mostly PDAs) change
+	 * their device address between every discovery.
+	 */
+	discovery = (discovery_t *) hashbin_get_first(cachelog);
+	while (discovery != NULL ) {
+			node = discovery;
+
+			/* Be sure to stay one item ahead */
+			discovery = (discovery_t *) hashbin_get_next(cachelog);
+			
+			if ((node->daddr == new->daddr) || 
+			    (strcmp(node->info, new->info) == 0))
+			{
+				/* This discovery is a previous discovery 
+				 * from the same device, so just remove it
+				 */
+				hashbin_remove(cachelog, node->daddr, NULL);
+				kfree(node);
+			}
+		}
 
-	/* Check if we have discovered this device before */
-	old = hashbin_remove(cachelog, discovery->daddr, NULL);
-	if (old)
-		kfree(old);
 
 	/* Insert the new and updated version */
-	hashbin_insert(cachelog, (QUEUE *) discovery, discovery->daddr, NULL);
+	hashbin_insert(cachelog, (QUEUE *) new, new->daddr, NULL);
+
+	spin_unlock_irqrestore(&irlmp->lock, flags);
 }
 
 /*
  * Function irlmp_add_discovery_log (cachelog, log)
  *
- *    
+ *    Merge a disovery log into the cachlog.
  *
  */
 void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log)
@@ -201,10 +224,12 @@
 	
 	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)
@@ -228,14 +253,14 @@
 			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);
 	}
diff -u --recursive --new-file v2.2.9/linux/net/irda/ircomm/ircomm_common.c linux/net/irda/ircomm/ircomm_common.c
--- v2.2.9/linux/net/irda/ircomm/ircomm_common.c	Tue May 11 13:10:32 1999
+++ linux/net/irda/ircomm/ircomm_common.c	Mon Jun  7 16:19:59 1999
@@ -8,7 +8,7 @@
  * Author:        Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
  * Source:        irlpt_event.c
  *
- *     Copyright (c) 1998, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
+ *     Copyright (c) 1998-1999, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
  *     All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
@@ -41,21 +41,20 @@
 
 #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, 
-			       struct sk_buff *skb );
-
-static void ircomm_state_discoverywait( struct ircomm_cb *self, IRCOMM_EVENT event, 
+static void ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			      struct sk_buff *skb );
+static void ircomm_state_discoverywait(struct ircomm_cb *self, 
+				       IRCOMM_EVENT event, 
+				       struct sk_buff *skb );
+static void ircomm_state_queryparamwait(struct ircomm_cb *self, 
+					IRCOMM_EVENT event, 
 					struct sk_buff *skb );
-
-static void ircomm_state_queryparamwait( struct ircomm_cb *self, IRCOMM_EVENT event, 
-					 struct sk_buff *skb );
-
-static void ircomm_state_querylsapwait( struct ircomm_cb *self, IRCOMM_EVENT event, 
-					struct sk_buff *skb );
-
+static void ircomm_state_querylsapwait(struct ircomm_cb *self, 
+				       IRCOMM_EVENT event, 
+				       struct sk_buff *skb );
 static void ircomm_state_waiti( struct ircomm_cb *self, IRCOMM_EVENT event, 
 				struct sk_buff *skb );
 static void ircomm_state_waitr( struct ircomm_cb *self, IRCOMM_EVENT event, 
@@ -206,15 +205,17 @@
 		ircomm[i]->enq_char = 0x05;
 		ircomm[i]->ack_char = 0x06;  
 
-		ircomm[i]->max_txbuff_size = COMM_DEFAULT_DATA_SIZE;   /* 64 */
-		ircomm[i]->maxsdusize = 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);
 
 	}
 
@@ -226,7 +227,6 @@
 	create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
 #endif /* CONFIG_PROC_FS */
 
-
 	discovering_instance = NULL;
 	return 0;
 }
@@ -275,51 +275,55 @@
 static int ircomm_accept_data_indication(void *instance, void *sap, 
 					 struct sk_buff *skb)
 {
-	
-	struct ircomm_cb *self = (struct ircomm_cb *)instance;
+	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return -1;);
-	ASSERT( skb != NULL, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+	ASSERT(skb != NULL, return -1;);
        
 	DEBUG(4,__FUNCTION__"():\n");
-	ircomm_do_event( self, TTP_DATA_INDICATION, skb);
+	ircomm_do_event(self, TTP_DATA_INDICATION, skb);
 	self->rx_packets++;
 	
 	return 0;
 }
 
 static void ircomm_accept_connect_confirm(void *instance, void *sap,
-				   struct qos_info *qos, 
-				   __u32 maxsdusize, struct sk_buff *skb)
+					  struct qos_info *qos, 
+					  __u32 max_sdu_size, 
+					  __u8 max_header_size,
+					  struct sk_buff *skb)
 {
+	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 
-	struct ircomm_cb *self = (struct ircomm_cb *)instance;
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-	ASSERT( qos != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+	ASSERT(qos != NULL, return;);
 
 	DEBUG(0,__FUNCTION__"(): got connected!\n");
 
-	if(maxsdusize == SAR_DISABLE)
-		self->max_txbuff_size = qos->data_size.value; 
+	if (max_sdu_size == SAR_DISABLE)
+		self->tx_max_sdu_size =(qos->data_size.value - max_header_size
+					- COMM_HEADER_SIZE);
 	else {
-		ASSERT(maxsdusize >= COMM_DEFAULT_DATA_SIZE, return;);
-		self->max_txbuff_size = maxsdusize; /* 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->null_modem_mode = 0;            	/* disable null modem emulation */
+	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);
+	ircomm_do_event(self, TTP_CONNECT_CONFIRM, skb);
 }
 
 static void ircomm_accept_connect_indication(void *instance, void *sap,
-				      struct qos_info *qos,
-				      __u32 maxsdusize,
-				      struct sk_buff *skb )
+					     struct qos_info *qos,
+					     __u32 max_sdu_size,
+					     __u8 max_header_size,
+					     struct sk_buff *skb)
 {
 	struct ircomm_cb *self = (struct ircomm_cb *)instance;
 
@@ -330,12 +334,15 @@
 
 	DEBUG(0,__FUNCTION__"()\n");
 
-	if(maxsdusize == SAR_DISABLE)
-		self->max_txbuff_size = qos->data_size.value;
+	if (max_sdu_size == SAR_DISABLE)
+		self->tx_max_sdu_size =(qos->data_size.value - max_header_size
+					- COMM_HEADER_SIZE);
 	else
-		self->max_txbuff_size = maxsdusize;
+		self->tx_max_sdu_size = max_sdu_size - COMM_HEADER_SIZE;
 
 	self->qos = qos;
+	self->max_header_size = max_header_size + COMM_HEADER_SIZE;
+
 	ircomm_do_event( self, TTP_CONNECT_INDICATION, skb);
 
 	/* stop connecting */
@@ -556,7 +563,7 @@
 
 		irttp_connect_request(self->tsap, self->dlsap, 
 				      self->saddr, self->daddr, 
-				      NULL, self->maxsdusize, userdata); 
+				      NULL, self->rx_max_sdu_size, userdata); 
 		break;
 
 	default:
@@ -588,9 +595,10 @@
 /* 	if( !ircomm_parse_controlchannel( self, data)) */
 /* 		self->servicetype = DEFAULT;     TODOD:fix this! TH */
 
-	if(self->notify.connect_indication)
+	if (self->notify.connect_indication)
 		self->notify.connect_indication(self->notify.instance, self, 
-						qos, 0, skb);
+						qos, self->tx_max_sdu_size,
+						self->max_header_size, skb);
 }
     
 #if 0
@@ -602,28 +610,27 @@
 #endif 
 
 
-static void connect_confirmation(struct ircomm_cb *self, struct sk_buff *skb)
+static void connect_confirm(struct ircomm_cb *self, struct sk_buff *skb)
 {
 	DEBUG(4 ,__FUNCTION__"()\n");
 
 	/* give a connect_confirm to the client */
 	if( self->notify.connect_confirm )
 		self->notify.connect_confirm(self->notify.instance,
-					     self, NULL, SAR_DISABLE, skb);
+					     self, NULL, self->tx_max_sdu_size,
+					     self->max_header_size, skb);
 }
 
 static void issue_connect_response(struct ircomm_cb *self,
 				   struct sk_buff *skb)
 {
-
 	DEBUG(0,__FUNCTION__"()\n");
 	
 	if( self->servicetype == THREE_WIRE_RAW){
 		DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented yet\n");
 		/* irlmp_connect_rsp(); */
-	} else {
-		irttp_connect_response(self->tsap, self->maxsdusize, skb);
-	}
+	} else
+		irttp_connect_response(self->tsap, self->rx_max_sdu_size, skb);
 }
 
 static void issue_disconnect_request(struct ircomm_cb *self,
@@ -642,30 +649,29 @@
 {
 	int err;
 
-	if(self->servicetype == THREE_WIRE_RAW){
+	if (self->servicetype == THREE_WIRE_RAW){
 		/* irlmp_data_request(self->lmhandle,userdata); */
 		DEBUG(0,__FUNCTION__"():not implemented!");
 		return;
 	}
 
 	DEBUG(4,__FUNCTION__"():sending frame\n");
-	err = irttp_data_request(self->tsap , userdata  );
-	if(err){
+	err = irttp_data_request(self->tsap, userdata);
+	if (err){
 		printk(KERN_ERR __FUNCTION__":ttp_data_request failed\n");
-		if(userdata)
+		if (userdata)
 			dev_kfree_skb( userdata);
 	}
 	self->tx_packets++;
 }
 
 static void issue_control_request(struct ircomm_cb *self,
-				  struct sk_buff *userdata )
+				  struct sk_buff *userdata)
 {
 	int err;
 
 	DEBUG(4,__FUNCTION__"()\n"); 
-	if(self->servicetype == THREE_WIRE_RAW)
-	{
+	if (self->servicetype == THREE_WIRE_RAW) {
 		DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented\n");
 		
 	}
@@ -676,7 +682,7 @@
 		{
 			printk( __FUNCTION__"():ttp_data_request failed\n");
 			if(userdata)
-				dev_kfree_skb( userdata);
+				dev_kfree_skb(userdata);
 		}
 		else
 			self->tx_controls++;
@@ -701,7 +707,7 @@
 
  	/* ircomm_parse_control(self, skb, CONTROL_CHANNEL); */
 
-	if(self->notify.data_indication && skb->len)
+	if (self->notify.data_indication && skb->len)
 		self->notify.data_indication(self->notify.instance, self,
 					     skb);
 }
@@ -728,7 +734,7 @@
 	
 	DEBUG( 4, __FUNCTION__": STATE = %s, EVENT = %s\n",
 	       ircommstate[self->state], ircommevent[event]);
-	(*state[ self->state ]) ( self, event, skb);
+	(*state[self->state])(self, event, skb);
 }
 
 static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state) 
@@ -747,7 +753,7 @@
 static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, 
 			       struct sk_buff *skb )
 {
-	switch(event){
+	switch (event){
 	case IRCOMM_CONNECT_REQUEST:
 
 		/* ircomm_next_state(self, COMM_WAITI); */
@@ -779,7 +785,8 @@
 /*
  * ircomm_state_discoverywait
  */
-static void ircomm_state_discoverywait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+static void ircomm_state_discoverywait(struct ircomm_cb *self, 
+				       IRCOMM_EVENT event, 
 				       struct sk_buff *skb )
 {
 	switch(event){
@@ -817,11 +824,11 @@
  * ircomm_state_queryparamwait
  */
 
-static void ircomm_state_queryparamwait(struct ircomm_cb *self, IRCOMM_EVENT event, 
-					struct sk_buff *skb )
+static void ircomm_state_queryparamwait(struct ircomm_cb *self, 
+					IRCOMM_EVENT event, 
+					struct sk_buff *skb)
 {
-	switch(event){
-
+	switch (event) {
 	case TTP_CONNECT_INDICATION:
 
 		ircomm_next_state(self, COMM_WAITR);
@@ -855,10 +862,11 @@
  * ircomm_state_querylsapwait
  */
 
-static void ircomm_state_querylsapwait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+static void ircomm_state_querylsapwait(struct ircomm_cb *self, 
+				       IRCOMM_EVENT event, 
 				       struct sk_buff *skb )
 {
-	switch(event){
+	switch (event) {
 
 	case TTP_CONNECT_INDICATION:
 
@@ -898,10 +906,10 @@
 static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, 
 			  struct sk_buff *skb )
 {
-	switch(event){
+	switch (event) {
 	case TTP_CONNECT_CONFIRM:
 		ircomm_next_state(self, COMM_CONN);
-		connect_confirmation( self, skb );
+		connect_confirm(self, skb );
 		break;
 	case TTP_DISCONNECT_INDICATION:
 		ircomm_next_state(self, COMM_IDLE);
@@ -921,21 +929,18 @@
 	}
 }
 
-
-
 /*
  * ircomm_state_waitr
  */
 static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, 
-			  struct sk_buff *skb ) 
+			       struct sk_buff *skb ) 
 {
-	
-	switch(event){
+	switch (event) {
 	case IRCOMM_CONNECT_RESPONSE:
 
 	        /* issue_connect_response */
 		
-		if(self->servicetype==THREE_WIRE_RAW){
+		if (self->servicetype==THREE_WIRE_RAW) {
 			DEBUG(0,__FUNCTION__"():3WIRE_RAW is not implemented\n");
 			/* irlmp_connect_response(Vpeersap,
 			 *                         ACCEPT,null);
@@ -987,7 +992,7 @@
 static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, 
 			      struct sk_buff *skb )
 {
-	switch(event){
+	switch (event) {
 	case TTP_DATA_INDICATION:
 		process_data(self, skb);
 		break;
@@ -1033,8 +1038,6 @@
 	}
 }
 
-
-
 /*
  *  ----------------------------------------------------------------------
  *  IrCOMM service interfaces and supporting functions
@@ -1042,12 +1045,12 @@
  *  ----------------------------------------------------------------------
  */
 
-/* 
- * start_discovering()
+/*
+ * Function start_discovering (self)
+ *
+ *    Start discovering and enter DISCOVERY_WAIT state
  *
- * start discovering and enter DISCOVERY_WAIT state
  */
-
 static void start_discovering(struct ircomm_cb *self)
 {
 	__u16  hints; 
@@ -1058,7 +1061,7 @@
 
 	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;
@@ -1092,19 +1095,26 @@
 /*
  * queryias_done(self)
  *
- * called when discovery process got wrong results, completed, or terminated.
+ * 
  */
 
+/*
+ * Function queryias_done (self)
+ *
+ *    Called when discovery process got wrong results, completed, or
+ *    terminated.
+ * 
+ */
 static void queryias_done(struct ircomm_cb *self)
 {
 	DEBUG(0, __FUNCTION__"():\n");
-	if(self->queryias_lock){
+	if (self->queryias_lock){
 		self->queryias_lock = 0;
 		discovering_instance = NULL;
 		MOD_DEC_USE_COUNT;
 		irlmp_unregister_client(self->ckey);
 	}
-	if(ircomm_cs != 1)
+	if (ircomm_cs != 1)
 		irlmp_unregister_service(self->skey);
 	return;
 }
@@ -1120,7 +1130,6 @@
 				       ircomm_getvalue_confirm, self );
 }
 
-
 static void query_lsapsel(struct ircomm_cb * self)
 {
 	DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
@@ -1135,13 +1144,13 @@
 	}
 }
 
-/* 
- * ircomm_connect_request()
- * Impl. of this function is differ from one of the reference.
- * This functin does discovery as well as sending connect request
+/*
+ * Function ircomm_connect_request (self, servicetype)
+ *
+ *    Impl. of this function is differ from one of the reference. This
+ *    function does discovery as well as sending connect request
+ * 
  */
-
-
 void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype)
 {
 	/*
@@ -1153,17 +1162,17 @@
 	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->maxsdusize = SAR_DISABLE;
-	ircomm_do_event( self, IRCOMM_CONNECT_REQUEST, NULL);
+	self->rx_max_sdu_size = SAR_DISABLE;
+	ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, NULL);
 }
 
 void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
-			     __u32 maxsdusize)
+			     __u32 max_sdu_size)
 {
 
 	ASSERT( self != NULL, return;);
@@ -1177,20 +1186,20 @@
 	 * and send it with connect_response
 	 */
 
-	if(!userdata){
+	if (!userdata){
 		/* FIXME: check for errors and initialize? DB */
-		userdata = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
-		ASSERT(userdata != NULL, return;);
+		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->maxsdusize = maxsdusize;
-	if(maxsdusize != SAR_DISABLE)
-		self->max_txbuff_size = maxsdusize;
+	self->rx_max_sdu_size = max_sdu_size;
+	
 	ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata);
 }	
 
@@ -1303,10 +1312,10 @@
 	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;
 }
 
@@ -1341,14 +1350,13 @@
 	self->control_ch_pending = 1;
 }
 
-
-
 /*
- * ircomm_control_request();
- * this function is exported as a request to send some control-channel tuples
- * to peer device
+ * Function ircomm_control_request (self, instruction)
+ *
+ *    This function is exported as a request to send some control-channel
+ *    tuples * to peer device
+ * 
  */
-
 void ircomm_control_request(struct ircomm_cb *self,  __u8 instruction)
 {
 
diff -u --recursive --new-file v2.2.9/linux/net/irda/ircomm/irvtd_driver.c linux/net/irda/ircomm/irvtd_driver.c
--- v2.2.9/linux/net/irda/ircomm/irvtd_driver.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/ircomm/irvtd_driver.c	Mon Jun  7 16:19:59 1999
@@ -8,7 +8,7 @@
  * Source:        serial.c by Linus Torvalds
  *                isdn_tty.c by Fritz Elfert
  *
- *     Copyright (c) 1998, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
+ *     Copyright (c) 1998-1999, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
  *     All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
@@ -51,7 +51,7 @@
 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_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 @@
 	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 @@
 	
 	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 @@
 	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 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 @@
 	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;
+
+	ASSERT(driver != NULL,return;);
+	ASSERT(driver->magic == IRVTD_MAGIC,return;);
+	DEBUG(4, __FUNCTION__"()\n");
 
-	/* start our timer again and again */
-	irvtd_start_timer(driver);
+	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 @@
 	}
 #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);
@@ -341,20 +383,23 @@
  ***********************************************************************
  */
 
-
 /*
  * Function irvtd_connect_confirm (instance, sap, qos, max_sdu_size, skb)
  *
- *    ircomm_connect_request which we have send have succeed!
+ *    ircomm_connect_request which we have send, has succeeded!
  *
  */
 void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
-			   __u32 max_sdu_size, struct sk_buff *skb)
+			   __u32 max_sdu_size, __u8 max_header_size, 
+			   struct sk_buff *skb)
 {
 	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
 	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
 	 */
@@ -364,7 +409,7 @@
 	/*
 	 * sending initial control parameters here
 	 */
-	if(driver->comm->servicetype ==	THREE_WIRE_RAW)
+	if (driver->comm->servicetype ==	THREE_WIRE_RAW)
 		return;                /* do nothing */
 
 	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
@@ -376,7 +421,7 @@
 	ircomm_control_request(driver->comm, XON_XOFF_CHAR);
 	/* ircomm_control_request(driver->comm, ENQ_ACK_CHAR); */
 
-	switch(driver->comm->servicetype){
+	switch (driver->comm->servicetype) {
 	case CENTRONICS:
 		break;
 
@@ -397,17 +442,20 @@
  *
  */
 void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
-			      __u32 max_sdu_size, struct sk_buff *skb)
+			      __u32 max_sdu_size, __u8 max_header_size, 
+			      struct sk_buff *skb)
 {
-
 	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
 	struct ircomm_cb *comm = (struct ircomm_cb *)sap;
+
 	ASSERT(driver != NULL, return;);
 	ASSERT(driver->magic == IRVTD_MAGIC, return;);
 	ASSERT(comm != NULL, return;);
 	ASSERT(comm->magic == IRCOMM_MAGIC, return;);
 
-	DEBUG(4,"irvtd_connect_indication:sending connect_response...\n");
+	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 );
 
@@ -416,7 +464,7 @@
 	/*
 	 * send initial control parameters
 	 */
-	if(driver->comm->servicetype ==	THREE_WIRE_RAW)
+	if (driver->comm->servicetype == THREE_WIRE_RAW)
 		return;                /* do nothing */
 
 	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
@@ -426,6 +474,7 @@
 		ircomm_control_request(driver->comm, DTELINE_STATE);
 		break;
 	default:
+		DEBUG(0, __FUNCTION__ "(), not implemented!\n");
 	}
 
 
@@ -479,11 +528,12 @@
 	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.
@@ -498,7 +548,7 @@
 
 	if(cmd == TX_BUSY){
 		driver->ttp_stoptx = driver->tty->hw_stopped = 1;
-		del_timer( &driver->timer);
+		del_timer( &driver->tx_timer);
 		return;
 	}
 
@@ -576,6 +626,7 @@
 	case DATA_RATE:
 	case XON_XOFF_CHAR:
 	case DTELINE_STATE:
+	case ENQ_ACK_CHAR:	/* got this from win95 */
 		/* (maybe) nothing to do  */
 		break;
 	default:
@@ -678,7 +729,7 @@
 
 	driver->blocked_open--;
 
-	DEBUG(0, __FUNCTION__"():after blocking\n");
+	DEBUG(1, __FUNCTION__"():after blocking\n");
 
 	if (retval)
 		return retval;
@@ -765,7 +816,7 @@
 	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)
@@ -776,12 +827,12 @@
 	 */
 
 	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");
+		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;
@@ -793,9 +844,8 @@
 	irvtd_notify.instance = driver;
 
 	driver->comm = ircomm_open_instance(irvtd_notify);
-	if(!driver->comm){
+	if (!driver->comm)
 		return -ENODEV;
-	}
 
 
 	/* 
@@ -811,22 +861,20 @@
 
 	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;
@@ -989,7 +1037,8 @@
 	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");
 
@@ -1144,13 +1193,21 @@
 	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 */
 
@@ -1164,9 +1221,9 @@
 		wrote += c;
 		count -= c;
 		buf += c;
-		irvtd_send_data_request(driver);
 	}
 	restore_flags(flags);
+	irvtd_send_data_request(driver);
 	return (wrote);
 }
 
@@ -1199,19 +1256,27 @@
 	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;
 }
 
@@ -1635,6 +1700,7 @@
 	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);
 }
 
@@ -1649,6 +1715,7 @@
 	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);
 }
 
@@ -1858,6 +1925,12 @@
                 ret += sprintf(buf+ret, "|CD");
 	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");
diff -u --recursive --new-file v2.2.9/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
--- v2.2.9/linux/net/irda/irda_device.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irda_device.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Sep  2 20:22:08 1998
- * Modified at:   Wed Apr 21 09:48:19 1999
+ * Modified at:   Tue Jun  1 09:05:13 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 
@@ -31,6 +31,8 @@
 #include <linux/netdevice.h>
 #include <linux/init.h>
 #include <linux/tty.h>
+#include <linux/kmod.h>
+#include <linux/wireless.h>
 
 #include <asm/ioctls.h>
 #include <asm/segment.h>
@@ -53,7 +55,8 @@
 extern int actisys_init(void);
 extern int girbil_init(void);
 
-hashbin_t *irda_device = NULL;
+static hashbin_t *irda_device = NULL;
+static hashbin_t *dongles = NULL;
 
 /* Netdevice functions */
 static int irda_device_net_rebuild_header(struct sk_buff *skb);
@@ -61,9 +64,9 @@
 				       struct device *dev,
 				       unsigned short type, void *daddr, 
 				       void *saddr, unsigned len);
-static int irda_device_net_set_config( struct device *dev, struct ifmap *map);
-static int irda_device_net_change_mtu( struct device *dev, int new_mtu);
-
+static int irda_device_net_set_config(struct device *dev, struct ifmap *map);
+static int irda_device_net_change_mtu(struct device *dev, int new_mtu);
+static int irda_device_net_ioctl(struct device *dev, struct ifreq *rq,int cmd);
 #ifdef CONFIG_PROC_FS
 int irda_device_proc_read( char *buf, char **start, off_t offset, int len, 
 			   int unused);
@@ -74,8 +77,15 @@
 {
 	/* Allocate master array */
 	irda_device = hashbin_new( HB_LOCAL);
-	if ( irda_device == NULL) {
-		printk( KERN_WARNING "IrDA: Can't allocate irda_device hashbin!\n");
+	if (irda_device == NULL) {
+		WARNING("IrDA: Can't allocate irda_device hashbin!\n");
+		return -ENOMEM;
+	}
+
+	dongles = hashbin_new(HB_LOCAL);
+	if (dongles == NULL) {
+		printk(KERN_WARNING 
+		       "IrDA: Can't allocate dongles hashbin!\n");
 		return -ENOMEM;
 	}
 
@@ -92,6 +102,12 @@
 #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
@@ -104,6 +120,10 @@
 #ifdef CONFIG_GIRBIL_DONGLE
 	girbil_init();
 #endif
+#ifdef CONFIG_GIRBIL_DONGLE
+	litelink_init();
+#endif
+
 	return 0;
 }
 
@@ -113,6 +133,7 @@
 
 	ASSERT(irda_device != NULL, return;);
 
+	hashbin_delete(dongles, NULL);
 	hashbin_delete(irda_device, (FREE_FUNC) irda_device_close);
 }
 
@@ -155,6 +176,8 @@
 	/* Initialize timers */
 	init_timer(&self->media_busy_timer);	
 
+	self->lock = SPIN_LOCK_UNLOCKED;
+
 	/* A pointer to the low level implementation */
 	self->priv = priv;
 
@@ -186,7 +209,7 @@
 	/* 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);
 
@@ -238,7 +261,7 @@
 /*
  * Function irda_device_close (self)
  *
- *    
+ *    Close the device
  *
  */
 void irda_device_close(struct irda_device *self)
@@ -248,6 +271,10 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
 
+	/* We are not using any dongle anymore! */
+	if (self->dongle)
+		self->dongle->close(self);
+
 	/* Stop and remove instance of IrLAP */
 	if (self->irlap)
 		irlap_close(self->irlap);
@@ -289,6 +316,8 @@
  */
 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;);
 	
@@ -296,18 +325,37 @@
 	 *  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->change_speed) {
-			self->change_speed(self, 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);
 
-			/* Update the QoS value only */
-			self->qos.baud_rate.value = speed;
+	/* 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 {
-		printk(KERN_WARNING "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;
 }
 
 /*
@@ -318,8 +366,6 @@
  */
 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;);
 
@@ -330,27 +376,27 @@
 
 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;
 }
@@ -372,8 +418,6 @@
 {
 	struct irda_device *self;
 
-	DEBUG(4, __FUNCTION__ "()\n");
-
 	ASSERT(dev != NULL, return -1;);
 
 	self = (struct irda_device *) dev->priv;
@@ -386,6 +430,7 @@
 	dev->set_config      = irda_device_net_set_config;
 	dev->change_mtu      = irda_device_net_change_mtu;
 /*  	dev->hard_header     = irda_device_net_hard_header; */
+	dev->do_ioctl        = irda_device_net_ioctl;
         dev->hard_header_len = 0;
         dev->addr_len        = 0;
 
@@ -444,6 +489,131 @@
      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 */
+{
+	unsigned long flags;
+	int			ret = 0;
+#ifdef WIRELESS_EXT
+	struct iwreq *wrq = (struct iwreq *) rq;
+#endif
+	struct irda_device *self;
+
+	DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = (struct irda_device *) dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+	DEBUG(0, "%s: ->irda_device_net_ioctl(cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	/* Look what is the request */
+	switch (cmd) {
+#ifdef WIRELESS_EXT
+	case SIOCGIWNAME:
+		/* Get name */
+		strcpy(wrq->u.name, self->name);
+		break;
+	case SIOCSIWNWID:
+		/* Set domain */
+		if (wrq->u.nwid.on) {
+			
+		} break;
+	case SIOCGIWNWID:
+		/* Read domain*/
+/* 		wrq->u.nwid.nwid = domain; */
+/* 		wrq->u.nwid.on = 1; */
+		break;
+	case SIOCGIWENCODE:
+		/* Get scramble key */
+		/* 	wrq->u.encoding.code = scramble_key; */
+/* 		wrq->u.encoding.method = 1; */
+		break;
+	case SIOCSIWENCODE:
+		/* Set  scramble key */
+		/* scramble_key = wrq->u.encoding.code; */
+		break;
+	case SIOCGIWRANGE:
+		/* Basic checking... */
+		if(wrq->u.data.pointer != (caddr_t) 0) {
+			struct iw_range	range;
+			
+			/* Verify the user buffer */
+			ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
+					  sizeof(struct iw_range));
+			if(ret)
+				break;
+			
+			/* Set the length (useless : its constant...) */
+			wrq->u.data.length = sizeof(struct iw_range);
+			
+			/* Set information in the range struct */
+			range.throughput = 1.6 * 1024 * 1024;	/* don't argue on this ! */
+			range.min_nwid = 0x0000;
+			range.max_nwid = 0x01FF;
+			
+			range.num_channels = range.num_frequency = 0;
+			
+			range.sensitivity = 0x3F;
+			range.max_qual.qual = 255;
+			range.max_qual.level = 255;
+			range.max_qual.noise = 0;
+			
+			/* Copy structure to the user buffer */
+			copy_to_user(wrq->u.data.pointer, &range,
+				     sizeof(struct iw_range));
+		}
+		break;
+	case SIOCGIWPRIV:
+		/* Basic checking... */
+#if 0
+		if (wrq->u.data.pointer != (caddr_t) 0) {
+			struct iw_priv_args	priv[] =
+			{	/* cmd,		set_args,	get_args,	name */
+				{ SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, 
+				  sizeof(struct site_survey), 
+				  "getsitesurvey" },
+			};
+			
+			/* Verify the user buffer */
+			ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
+					  sizeof(priv));
+			if (ret)
+				break;
+			
+			/* Set the number of ioctl available */
+			wrq->u.data.length = 1;
+			
+			/* Copy structure to the user buffer */
+			copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+				     sizeof(priv));
+		}
+#endif 
+		break;
+#endif
+	case SIOCSDONGLE: /* Set dongle */
+		/* Initialize dongle */
+		irda_device_init_dongle(self, (int) rq->ifr_data);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
+
 /*
  * Function irda_device_transmit_finished (void)
  *
@@ -451,7 +621,7 @@
  *    device. Maybe we should use: q->q.qlen == 0.
  *
  */
-int irda_device_txqueue_empty( struct irda_device *self)
+int irda_device_txqueue_empty(struct irda_device *self)
 {
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);	
@@ -463,6 +633,122 @@
 }
 
 /*
+ * Function irda_device_init_dongle (self, type)
+ *
+ *    Initialize attached dongle. Warning, must be called with a process
+ *    context!
+ */
+void irda_device_init_dongle(struct irda_device *self, int type)
+{
+	struct dongle_q *node;
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+
+#ifdef CONFIG_KMOD
+	/* Try to load the module needed */
+	switch (type) {
+	case ESI_DONGLE:
+		MESSAGE("IrDA: Initializing ESI dongle!\n");
+		request_module("esi");
+		break;
+	case TEKRAM_DONGLE:
+		MESSAGE("IrDA: Initializing Tekram dongle!\n");
+		request_module("tekram");
+		break;
+	case ACTISYS_DONGLE:     /* FALLTHROUGH */
+	case ACTISYS_PLUS_DONGLE:
+		MESSAGE("IrDA: Initializing ACTiSYS dongle!\n");
+		request_module("actisys");
+		break;
+	case GIRBIL_DONGLE:
+		MESSAGE("IrDA: Initializing GIrBIL dongle!\n");
+		request_module("girbil");
+		break;
+	case LITELINK_DONGLE:
+		MESSAGE("IrDA: Initializing Litelink dongle!\n");
+		request_module("litelink");
+		break;
+	default:
+		ERROR("Unknown dongle type!\n");
+		return;
+	}
+#endif /* CONFIG_KMOD */
+
+	node = hashbin_find(dongles, type, NULL);
+	if (!node) {
+		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;
+
+	/* Now initialize the dongle!  */
+	node->dongle->open(self, type);
+	node->dongle->qos_init(self, &self->qos);
+	
+	/* Reset dongle */
+	node->dongle->reset(self);
+
+	/* Set to default baudrate */
+	irda_device_change_speed(self, 9600);
+}
+
+/*
+ * Function irda_device_register_dongle (dongle)
+ *
+ *    
+ *
+ */
+int irda_device_register_dongle(struct dongle *dongle)
+{
+	struct dongle_q *new;
+	
+	/* Check if this dongle has been registred before */
+	if (hashbin_find(dongles, dongle->type, NULL)) {
+		MESSAGE(__FUNCTION__ "(), Dongle already registered\n");
+                return 0;
+        }
+	
+	/* Make new IrDA dongle */
+        new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
+        if (new == NULL)
+                return -1;
+		
+	memset(new, 0, sizeof( struct dongle_q));
+        new->dongle = dongle;
+
+	/* Insert IrDA dongle into hashbin */
+	hashbin_insert(dongles, (QUEUE *) new, dongle->type, NULL);
+	
+        return 0;
+}
+
+/*
+ * Function irda_device_unregister_dongle (dongle)
+ *
+ *    
+ *
+ */
+void irda_device_unregister_dongle(struct dongle *dongle)
+{
+	struct dongle_q *node;
+
+	node = hashbin_remove(dongles, dongle->type, NULL);
+	if (!node) {
+		ERROR(__FUNCTION__ "(), dongle not found!\n");
+		return;
+	}
+	kfree(node);
+}
+
+/*
  * Function setup_dma (idev, buffer, count, mode)
  *
  *    Setup the DMA channel
@@ -536,7 +822,7 @@
 
 	self = (struct irda_device *) hashbin_get_first(irda_device);
 	while ( self != NULL) {
-		len += sprintf(buf+len, "%s,", self->name);
+		len += sprintf(buf+len, "\n%s,", self->name);
 		len += sprintf(buf+len, "\tbinding: %s\n", 
 			       self->description);
 		
diff -u --recursive --new-file v2.2.9/linux/net/irda/iriap.c linux/net/irda/iriap.c
--- v2.2.9/linux/net/irda/iriap.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/iriap.c	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Fri Apr 23 09:57:12 1999
+ * Modified at:   Sun May  9 15:59:05 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -62,12 +62,17 @@
 extern char *lmp_reasons[];
 
 static struct iriap_cb *iriap_open( __u8 slsap, int mode);
-static void __iriap_close( struct iriap_cb *self);
+static void __iriap_close(struct iriap_cb *self);
 static void iriap_disconnect_indication(void *instance, void *sap, 
 					LM_REASON reason, struct sk_buff *skb);
 static void iriap_connect_indication(void *instance, void *sap, 
 				     struct qos_info *qos, __u32 max_sdu_size,
+				     __u8 max_header_size, 
 				     struct sk_buff *skb);
+static void iriap_connect_confirm(void *instance, void *sap, 
+				  struct qos_info *qos, 
+				  __u32 max_sdu_size, __u8 max_header_size,
+				  struct sk_buff *skb);
 static int iriap_data_indication(void *instance, void *sap, 
 				 struct sk_buff *skb);
 
@@ -181,7 +186,7 @@
 	self->slsap_sel = slsap_sel;
 	self->mode = mode;
 
-	init_timer( &self->watchdog_timer);
+	init_timer(&self->watchdog_timer);
 
 	hashbin_insert( iriap, (QUEUE*) self, slsap_sel, NULL);
 	
@@ -206,7 +211,7 @@
 	ASSERT( self != NULL, return;);
 	ASSERT( self->magic == IAS_MAGIC, return;);
 
-	del_timer( &self->watchdog_timer);
+	del_timer(&self->watchdog_timer);
 
 	self->magic = 0;
 
@@ -260,7 +265,7 @@
 
 	ASSERT( iriap != NULL, return;);
 
-	del_timer( &self->watchdog_timer);
+	del_timer(&self->watchdog_timer);
 
 	if ( self->mode == IAS_CLIENT) {
 		DEBUG( 4, __FUNCTION__ "(), disconnect as client\n");
@@ -284,9 +289,8 @@
 				       NULL);
 	}
 
-	if ( userdata) {
+	if (userdata)
 		dev_kfree_skb( userdata);
-	}
 }
 
 /*
@@ -295,28 +299,28 @@
  *    
  *
  */
-void iriap_disconnect_request( struct iriap_cb *self)
+void iriap_disconnect_request(struct iriap_cb *self)
 {
 	struct sk_buff *skb;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	skb = dev_alloc_skb( 64);
+	skb = dev_alloc_skb(64);
 	if (skb == NULL) {
-		DEBUG( 0, __FUNCTION__
-		       "(), Could not allocate an sk_buff of length %d\n", 64);
+		DEBUG(0, __FUNCTION__
+		      "(), Could not allocate an sk_buff of length %d\n", 64);
 		return;
 	}
 
 	/* 
-	 *  Reserve space for MUX and LAP header 
+	 *  Reserve space for MUX control and LAP header 
 	 */
- 	skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER);
+ 	skb_reserve(skb, LMP_MAX_HEADER);
 
-	irlmp_disconnect_request( self->lsap, skb);
+	irlmp_disconnect_request(self->lsap, skb);
 }
 
 void iriap_getinfobasedetails_request(void) 
@@ -381,7 +385,7 @@
 	/* Give ourselves 10 secs to finish this operation */
 	iriap_start_watchdog_timer(self, 10*HZ);
 	
-	skb = dev_alloc_skb( 64);
+	skb = dev_alloc_skb(64);
 	if (!skb)
 		return;
 
@@ -389,7 +393,7 @@
 	attr_len = strlen(attr);
 
 	/* Reserve space for MUX and LAP header */
- 	skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+ 	skb_reserve(skb, self->max_header_size);
 	skb_put(skb, 3+name_len+attr_len);
 	frame = skb->data;
 
@@ -535,13 +539,13 @@
 	 *  value. We add 9 bytes because of the 6 bytes for the frame and
 	 *  max 3 bytes for the value coding.
 	 */
-	skb = dev_alloc_skb(value->len + LMP_HEADER + LAP_HEADER + 9);
+	skb = dev_alloc_skb(value->len + self->max_header_size + 9);
 	if (!skb)
 		return;
 
 	/* Reserve space for MUX and LAP header */
- 	skb_reserve( skb, LMP_HEADER+LAP_HEADER);
-	skb_put( skb, 6);
+ 	skb_reserve(skb, self->max_header_size);
+	skb_put(skb, 6);
 	
 	fp = skb->data;
 
@@ -666,7 +670,7 @@
 /*
  * Function iriap_send_ack (void)
  *
- *    
+ *    Currently not used
  *
  */
 void iriap_send_ack( struct iriap_cb *self) 
@@ -679,13 +683,13 @@
 	ASSERT( self != NULL, return;);
 	ASSERT( self->magic == IAS_MAGIC, return;);
 
-	skb = dev_alloc_skb( 64);
+	skb = dev_alloc_skb(64);
 	if (!skb)
 		return;
 
 	/* Reserve space for MUX and LAP header */
- 	skb_reserve( skb, 4);
-	skb_put( skb, 3);
+ 	skb_reserve(skb, self->max_header_size);
+	skb_put(skb, 1);
 	frame = skb->data;
 
 	/* Build frame */
@@ -698,8 +702,10 @@
  *    LSAP connection confirmed!
  *
  */
-void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-			   __u32 max_sdu_size, struct sk_buff *userdata)
+static void iriap_connect_confirm(void *instance, void *sap, 
+				  struct qos_info *qos, 
+				  __u32 max_sdu_size, __u8 header_size, 
+				  struct sk_buff *userdata)
 {
 	struct iriap_cb *self;
 	
@@ -711,7 +717,7 @@
 	
 	DEBUG(4, __FUNCTION__ "()\n");
 	
-	/* del_timer( &self->watchdog_timer); */
+	del_timer(&self->watchdog_timer);
 
 	iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata);
 }
@@ -724,19 +730,17 @@
  */
 static void iriap_connect_indication(void *instance, void *sap, 
 				     struct qos_info *qos, __u32 max_sdu_size,
+				     __u8 header_size, 
 				     struct sk_buff *userdata)
 {
 	struct iriap_cb *self;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	self = ( struct iriap_cb *) instance;
+	self = (struct iriap_cb *) instance;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
-	ASSERT( self->mode == IAS_SERVER, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	iriap_do_server_event( self, IAP_LM_CONNECT_INDICATION, userdata);
+	iriap_do_server_event(self, IAP_LM_CONNECT_INDICATION, userdata);
 }
  
 /*
@@ -856,7 +860,7 @@
 	}
 	opcode &= 0x7f; /* Mask away LST bit */
 	
-	switch( opcode) {
+	switch (opcode) {
 	case GET_INFO_BASE:
 		DEBUG( 0, "IrLMP GetInfoBaseDetails not implemented!\n");
 		break;
diff -u --recursive --new-file v2.2.9/linux/net/irda/iriap_event.c linux/net/irda/iriap_event.c
--- v2.2.9/linux/net/irda/iriap_event.c	Wed Mar 10 15:29:52 1999
+++ linux/net/irda/iriap_event.c	Sun May 30 10:17:03 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Tue Jan 26 12:29:36 1999
+ * Modified at:   Sun May  9 11:01:47 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, 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 
@@ -387,9 +387,9 @@
 		}
 
 		/* Reserve space for MUX_CONTROL and LAP header */
-		skb_reserve( tx_skb, LMP_CONTROL_HEADER+LAP_HEADER);
+		skb_reserve(tx_skb, LMP_MAX_HEADER);
 		
-		irlmp_connect_response( self->lsap, tx_skb);
+		irlmp_connect_response(self->lsap, tx_skb);
 		/*LM_Idle_request(idle); */
 		
 		iriap_next_server_state( self, R_CALL);
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_client.c linux/net/irda/irlan/irlan_client.c
--- v2.2.9/linux/net/irda/irlan/irlan_client.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlan/irlan_client.c	Mon Jun  7 16:19:59 1999
@@ -6,13 +6,14 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 23:03:55 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>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     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 
@@ -61,6 +62,7 @@
 static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, 
 					      struct qos_info *qos, 
 					      __u32 max_sdu_size,
+					      __u8 max_header_size,
 					      struct sk_buff *);
 static void irlan_check_response_param(struct irlan_cb *self, char *param, 
 				       char *value, int val_len);
@@ -79,7 +81,7 @@
 	 * indication it needs to make progress. If the client is still in 
 	 * IDLE state, we must kick it to, but only if the provider is not IDLE
  	 */
-	if ((self->access_type == ACCESS_PEER) && 
+	if ((self->provider.access_type == ACCESS_PEER) && 
 	    (self->client.state == IRLAN_IDLE) &&
 	    (self->provider.state != IRLAN_IDLE)) {
 		irlan_client_wakeup(self, self->saddr, self->daddr);
@@ -105,23 +107,29 @@
 {
 	struct irmanager_event mgr_event;
 
-	DEBUG(0, __FUNCTION__ "()\n");
+	DEBUG(1, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
-	/* Check if we are already awake */
-	if (self->client.state != IRLAN_IDLE)
+	/* 
+	 * Check if we are already awake, or if we are a provider in direct
+	 * mode (in that case we must leave the client idle
+	 */
+	if ((self->client.state != IRLAN_IDLE) || 
+	    (self->provider.access_type == ACCESS_DIRECT))
 		return;
 
 	/* saddr may have changed! */
 	self->saddr = saddr;
 	
-	/* Check if network device is up */
+	/* Before we try to connect, we check if network device is up. If it
+	 * is up, that means that the "user" really wants to connect. If not
+	 * we notify the user about the possibility of an IrLAN connection
+	 */
 	if (self->dev.start) {
 		/* Open TSAPs */
 		irlan_client_open_ctrl_tsap(self);
- 		irlan_provider_open_ctrl_tsap(self);
  		irlan_open_data_tsap(self);
 		
 		irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
@@ -161,7 +169,7 @@
 	struct irlan_cb *self, *entry;
 	__u32 saddr, daddr;
 	
-	DEBUG(0, __FUNCTION__"()\n");
+	DEBUG(1, __FUNCTION__"()\n");
 
 	ASSERT(irlan != NULL, return;);
 	ASSERT(discovery != NULL, return;);
@@ -176,7 +184,8 @@
       	if (self) {
 		ASSERT(self->magic == IRLAN_MAGIC, return;);
 
-		DEBUG(2, __FUNCTION__ "(), Found instance!\n");
+		DEBUG(1, __FUNCTION__ "(), Found instance (%08x)!\n",
+		      daddr);
 		
 		irlan_client_wakeup(self, saddr, daddr);
 
@@ -184,30 +193,13 @@
 	}
 	
 	/* 
-	 * We have no instance for daddr, so try and find an unused one
+	 * We have no instance for daddr, so start a new one
 	 */
-	self = hashbin_find(irlan, DEV_ADDR_ANY, NULL);
-	if (self) {
-		DEBUG(0, __FUNCTION__ "(), Found instance with DEV_ADDR_ANY!\n");
-		/*
-		 * Rehash instance, now we have a client (daddr) to serve.
-		 */
-		entry = hashbin_remove(irlan, self->daddr, NULL);
-		ASSERT(entry == self, return;);
+	DEBUG(1, __FUNCTION__ "(), starting new instance!\n");
+	self = irlan_open(saddr, daddr, TRUE);
 
-		self->daddr = daddr;
-		self->saddr = saddr;
-
-		DEBUG(0, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
-		hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
-		
-		/* Check if network device has been registered */
-		if (!self->netdev_registered)
-			irlan_register_netdev(self);
-		
-		/* Restart watchdog timer */
-		irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
-	}
+	/* Restart watchdog timer */
+	irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
 }
 	
 /*
@@ -221,7 +213,7 @@
 {
 	struct irlan_cb *self;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
 	
 	self = (struct irlan_cb *) instance;
 	
@@ -231,6 +223,12 @@
 	
 	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;
 }
 
@@ -302,6 +300,7 @@
 static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, 
 					      struct qos_info *qos, 
 					      __u32 max_sdu_size,
+					      __u8 max_header_size,
 					      struct sk_buff *skb) 
 {
 	struct irlan_cb *self;
@@ -313,6 +312,9 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
+	self->client.max_sdu_size = max_sdu_size;
+	self->client.max_header_size = max_header_size;
+
 	/* TODO: we could set the MTU depending on the max_sdu_size */
 
 	irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL);
@@ -339,7 +341,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -410,11 +412,11 @@
 	/* For all parameters */
  	for (i=0; i<count;i++) {
 		ret = irlan_extract_param(ptr, name, value, &val_len);
-		if (ret == -1) {
+		if (ret < 0) {
 			DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
 			break;
 		}
-		ptr+=ret;
+		ptr += ret;
 		irlan_check_response_param(self, name, value, val_len);
  	}
 	/* Cleanup */
@@ -423,9 +425,9 @@
 }
 
 /*
- * Function check_param (param, value)
+ * Function irlan_check_response_param (self, param, value, val_len)
  *
- *    Check which parameter is received and update local variables
+ *     Check which parameter is received and update local variables
  *
  */
 static void irlan_check_response_param(struct irlan_cb *self, char *param, 
@@ -469,11 +471,11 @@
 	}
 	if (strcmp(param, "ACCESS_TYPE") == 0) {
 		if (strcmp(value, "DIRECT") == 0)
-			self->access_type = ACCESS_DIRECT;
+			self->client.access_type = ACCESS_DIRECT;
 		else if (strcmp(value, "PEER") == 0)
-			self->access_type = ACCESS_PEER;
+			self->client.access_type = ACCESS_PEER;
 		else if (strcmp(value, "HOSTED") == 0)
-			self->access_type = ACCESS_HOSTED;
+			self->client.access_type = ACCESS_HOSTED;
 		else {
 			DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
 		}
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_client_event.c linux/net/irda/irlan/irlan_client_event.c
--- v2.2.9/linux/net/irda/irlan/irlan_client_event.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlan/irlan_client_event.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 12:23:22 1999
+ * Modified at:   Fri May 14 23:08:15 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -97,7 +97,7 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 	
-	switch(event) {
+	switch (event) {
 	case IRLAN_DISCOVERY_INDICATION:
 		/* Get some values from peer IAS */
 		iriap_getvaluebyclass_request(
@@ -152,7 +152,7 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 
 		/* Give the client a kick! */
-		if ((self->access_type == ACCESS_PEER) && 
+		if ((self->provider.access_type == ACCESS_PEER) && 
 		    (self->provider.state != IRLAN_IDLE))
 			irlan_client_wakeup(self, self->saddr, self->daddr);
 		break;
@@ -222,7 +222,7 @@
 
 	ASSERT(self != NULL, return -1;);
 	
-	switch(event) {
+	switch (event) {
 	case IRLAN_DATA_INDICATION:
 		ASSERT(skb != NULL, return -1;);
 	
@@ -314,7 +314,7 @@
 	  	ASSERT(self->dtsap_sel_data != 0, return -1;);
 
 		/* Check which access type we are dealing with */
-		switch(self->access_type) {
+		switch (self->client.access_type) {
 		case ACCESS_PEER:
 		    if (self->provider.state == IRLAN_OPEN) {
 			    
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- v2.2.9/linux/net/irda/irlan/irlan_common.c	Tue May 11 13:10:32 1999
+++ linux/net/irda/irlan/irlan_common.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 23:13:47 1999
+ * Modified at:   Mon May 31 14:25:19 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     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 
@@ -93,19 +94,25 @@
 static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, 
 				__u8 value_byte, __u16 value_short, 
 				__u8 *value_array, __u16 value_len);
-static void irlan_close_tsaps(struct irlan_cb *self);
+void irlan_close_tsaps(struct irlan_cb *self);
 
 #ifdef CONFIG_PROC_FS
 static int irlan_proc_read(char *buf, char **start, off_t offset, int len, 
 			   int unused);
 
 extern struct proc_dir_entry *proc_irda;
-#endif
+#endif /* CONFIG_PROC_FS */
 
+/*
+ * Function irlan_watchdog_timer_expired (data)
+ *
+ *    
+ *
+ */
 void irlan_watchdog_timer_expired(unsigned long data)
 {
 	struct irmanager_event mgr_event;
-	struct irlan_cb *self, *entry;
+	struct irlan_cb *self;
 	
 	DEBUG(0, __FUNCTION__ "()\n");
 
@@ -116,6 +123,7 @@
 
 	/* Check if device still configured */
 	if (self->dev.start) {
+		DEBUG(0, __FUNCTION__ "(), notifying irmanager to stop irlan!\n");
 		mgr_event.event = EVENT_IRLAN_STOP;
 		sprintf(mgr_event.devname, "%s", self->ifname);
 		irmanager_notify(&mgr_event);
@@ -128,22 +136,13 @@
 		 */
 		self->notify_irmanager = FALSE;
 	} else {
-		DEBUG(0, __FUNCTION__ "(), recycling instance!\n");
+		DEBUG(0, __FUNCTION__ "(), closing instance!\n");
 		if (self->netdev_registered) {
 			DEBUG(0, __FUNCTION__ "(), removing netdev!\n");
 			unregister_netdev(&self->dev);
 			self->netdev_registered = FALSE;
 		}
-
-		/* Unbind from daddr */
-		entry = hashbin_remove(irlan, self->daddr, NULL);
-		ASSERT(entry == self, return;);
-
-		self->daddr = DEV_ADDR_ANY;
-		self->saddr = DEV_ADDR_ANY;
-
-		DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
-		hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
+		irlan_close(self);
 	}
 }
 
@@ -195,12 +194,12 @@
 	/* Register with IrLMP as a service */
  	skey = irlmp_register_service(hints);
 
-	/* Start the first IrLAN instance */
+	/* Start the master IrLAN instance */
  	new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
 
-	irlan_open_data_tsap(new);
- 	irlan_client_open_ctrl_tsap(new);
+	/* The master will only open its (listen) control TSAP */
 	irlan_provider_open_ctrl_tsap(new);
+	new->master = TRUE;
 
 	/* Do some fast discovery! */
 	irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
@@ -293,7 +292,7 @@
 	self->daddr = daddr;
 
 	/* Provider access can only be PEER, DIRECT, or HOSTED */
-	self->access_type = access;
+	self->provider.access_type = access;
 	self->media = MEDIA_802_3;
 
 	self->notify_irmanager = TRUE;
@@ -302,7 +301,9 @@
 	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);
 
@@ -322,7 +323,7 @@
  */
 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;);
@@ -359,8 +360,11 @@
 
 	/* Check if device is still configured */
 	if (self->dev.start) {
-		DEBUG(2, __FUNCTION__ 
+		DEBUG(0, __FUNCTION__ 
 		       "(), Device still configured, closing later!\n");
+
+		/* Give it a chance to reconnect */
+		irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
 		return;
 	}
 	DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
@@ -371,8 +375,15 @@
         __irlan_close(self);
 }
 
+/*
+ * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb)
+ *
+ *    Here we receive the connect indication for the data channel
+ *
+ */
 void irlan_connect_indication(void *instance, void *sap, struct qos_info *qos,
-			      __u32 max_sdu_size, struct sk_buff *skb)
+			      __u32 max_sdu_size, __u8 max_header_size, 
+			      struct sk_buff *skb)
 {
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
@@ -386,13 +397,17 @@
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 	ASSERT(tsap == self->tsap_data,return;);
 
-	DEBUG(2, "IrLAN, We are now connected!\n");
+	self->max_sdu_size = max_sdu_size;
+	self->max_header_size = max_header_size;
+
+	DEBUG(0, "IrLAN, We are now connected!\n");
+
 	del_timer(&self->watchdog_timer);
 
 	irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, skb);
 	irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, skb);
 
-	if (self->access_type == ACCESS_PEER) {
+	if (self->provider.access_type == ACCESS_PEER) {
 		/* 
 		 * Data channel is open, so we are now allowed to
 		 * configure the remote filter 
@@ -400,22 +415,24 @@
 		irlan_get_unicast_addr(self);
 		irlan_open_unicast_addr(self);
 	}
-	/* Ready to transfer Ethernet frames */
+	/* Ready to transfer Ethernet frames (at last) */
 	self->dev.tbusy = 0;
 }
 
 void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-			   __u32 max_sdu_size, struct sk_buff *skb) 
+			   __u32 max_sdu_size, __u8 max_header_size, 
+			   struct sk_buff *skb) 
 {
 	struct irlan_cb *self;
 
-	DEBUG(2, __FUNCTION__ "()\n");
-
 	self = (struct irlan_cb *) instance;
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
+	self->max_sdu_size = max_sdu_size;
+	self->max_header_size = max_header_size;
+
 	/* TODO: we could set the MTU depending on the max_sdu_size */
 
 	DEBUG(2, "IrLAN, We are now connected!\n");
@@ -427,9 +444,15 @@
 	 */
 	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);
 }
 
 /*
@@ -444,7 +467,7 @@
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
 
-	DEBUG(2, __FUNCTION__ "(), reason=%d\n", reason);
+	DEBUG(0, __FUNCTION__ "(), reason=%d\n", reason);
 	
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -460,7 +483,7 @@
 
 	switch(reason) {
 	case LM_USER_REQUEST: /* User request */
-		//irlan_close(self);
+		irlan_close(self);
 		break;
 	case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
 		irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
@@ -478,9 +501,6 @@
 		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);
 }
@@ -490,7 +510,7 @@
 	struct notify_t notify;
 	struct tsap_cb *tsap;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -500,12 +520,12 @@
 		return;
 
 	irda_notify_init(&notify);
-
+	
 	notify.data_indication       = irlan_eth_receive;
 	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);
@@ -538,7 +558,6 @@
 		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, 
@@ -591,15 +610,60 @@
 		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)
  *
  *    Send Get Provider Information command to peer IrLAN layer
@@ -620,7 +684,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -628,7 +692,8 @@
  	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);
 }
 
 /*
@@ -651,7 +716,7 @@
 	if (!skb)
 		return;
 
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -666,7 +731,8 @@
 
 /* 	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) 
@@ -679,11 +745,15 @@
 	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;
 
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -694,7 +764,8 @@
 
 	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);
 }
 
 /*
@@ -719,7 +790,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -730,7 +801,8 @@
  	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);
 }
 
 /*
@@ -757,7 +829,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -770,8 +842,9 @@
 		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);
 }
 
 /*
@@ -796,7 +869,7 @@
 		return;
 	
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -809,8 +882,9 @@
 		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);
 }
 
 /*
@@ -836,7 +910,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -847,7 +921,8 @@
  	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);
 }
 
 /*
@@ -871,7 +946,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -882,7 +957,8 @@
 	
 	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);
 }
 
 /*
@@ -1033,7 +1109,7 @@
 	
 	/* get parameter name */
 	memcpy(name, buf+n, name_len);
-	name[ name_len] = '\0';
+	name[name_len] = '\0';
 	n+=name_len;
 	
 	/*  
@@ -1051,7 +1127,7 @@
 
 	/* get parameter value */
 	memcpy(value, buf+n, val_len);
-	value[ val_len] = '\0';
+	value[val_len] = '\0';
 	n+=val_len;
 	
 	DEBUG(4, "Parameter: %s ", name); 
@@ -1085,31 +1161,35 @@
 	while (self != NULL) {
 		ASSERT(self->magic == IRLAN_MAGIC, return len;);
 		
-		len += sprintf(buf+len, "ifname: %s,\n",
-			       self->ifname);
-		len += sprintf(buf+len, "client state: %s, ",
-			       irlan_state[ self->client.state]);
-		len += sprintf(buf+len, "provider state: %s,\n",
-			       irlan_state[ self->provider.state]);
-		len += sprintf(buf+len, "saddr: %#08x, ",
-			       self->saddr);
-		len += sprintf(buf+len, "daddr: %#08x\n",
-			       self->daddr);
-		len += sprintf(buf+len, "version: %d.%d,\n",
-			       self->version[1], self->version[0]);
-		len += sprintf(buf+len, "access type: %s\n", 
-			       irlan_access[ self->access_type]);
-		len += sprintf(buf+len, "media: %s\n", 
-			       irlan_media[ self->media]);
-
-		len += sprintf(buf+len, "local filter:\n");
-		len += sprintf(buf+len, "remote filter: ");
-		len += irlan_print_filter(self->client.filter_type, buf+len);
-
-		len += sprintf(buf+len, "tx busy: %s\n", self->dev.tbusy ? 
-			       "TRUE" : "FALSE");
-
-		len += sprintf(buf+len, "\n");
+		/* Don't display the master server */
+		if (self->master == 0) {
+			len += sprintf(buf+len, "ifname: %s,\n",
+				       self->ifname);
+			len += sprintf(buf+len, "client state: %s, ",
+				       irlan_state[ self->client.state]);
+			len += sprintf(buf+len, "provider state: %s,\n",
+				       irlan_state[ self->provider.state]);
+			len += sprintf(buf+len, "saddr: %#08x, ",
+				       self->saddr);
+			len += sprintf(buf+len, "daddr: %#08x\n",
+				       self->daddr);
+			len += sprintf(buf+len, "version: %d.%d,\n",
+				       self->version[1], self->version[0]);
+			len += sprintf(buf+len, "access type: %s\n", 
+				       irlan_access[self->client.access_type]);
+			len += sprintf(buf+len, "media: %s\n", 
+				       irlan_media[self->media]);
+			
+			len += sprintf(buf+len, "local filter:\n");
+			len += sprintf(buf+len, "remote filter: ");
+			len += irlan_print_filter(self->client.filter_type, 
+						  buf+len);
+			
+			len += sprintf(buf+len, "tx busy: %s\n", 
+				       self->dev.tbusy ? "TRUE" : "FALSE");
+			
+			len += sprintf(buf+len, "\n");
+		}
 
 		self = (struct irlan_cb *) hashbin_get_next(irlan);
  	} 
@@ -1132,34 +1212,34 @@
 		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;
 	}
 }
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_eth.c linux/net/irda/irlan/irlan_eth.c
--- v2.2.9/linux/net/irda/irlan/irlan_eth.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlan/irlan_eth.c	Mon Jun  7 16:19:59 1999
@@ -6,13 +6,13 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:37:58 1998
- * Modified at:   Thu Apr 22 14:26:39 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>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  * 
- *     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 
@@ -29,6 +29,7 @@
 #include <linux/etherdevice.h>
 #include <linux/inetdevice.h>
 #include <linux/if_arp.h>
+#include <linux/random.h>
 #include <net/arp.h>
 
 #include <net/irda/irda.h>
@@ -49,7 +50,7 @@
 	struct irmanager_event mgr_event;
 	struct irlan_cb *self;
 
-	DEBUG(0, __FUNCTION__"()\n");
+	DEBUG(2, __FUNCTION__"()\n");
 
 	ASSERT(dev != NULL, return -1;);
        
@@ -65,21 +66,26 @@
 	
 	ether_setup(dev);
 	
-	dev->tx_queue_len = TTP_MAX_QUEUE;
-
-#if 0
-	/*  
-	 *  OK, since we are emulating an IrLAN sever we will have to give
-	 *  ourself an ethernet address!
-	 *  FIXME: this must be more dynamically
+	/* 
+	 * 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->dev_addr[0] = 0x40;
-	dev->dev_addr[1] = 0x00;
-	dev->dev_addr[2] = 0x00;
-	dev->dev_addr[3] = 0x00;
-	dev->dev_addr[4] = 0x23;
-	dev->dev_addr[5] = 0x45;
-#endif
+	dev->tx_queue_len = 0;
+
+	if (self->provider.access_type == ACCESS_DIRECT) {
+		/*  
+		 * Since we are emulating an IrLAN sever we will have to
+		 * give ourself an ethernet address!  
+		 */
+		dev->dev_addr[0] = 0x40;
+		dev->dev_addr[1] = 0x00;
+		dev->dev_addr[2] = 0x00;
+		dev->dev_addr[3] = 0x00;
+		get_random_bytes(dev->dev_addr+4, 1);
+		get_random_bytes(dev->dev_addr+5, 1);
+	}
+
 	/* 
 	 * Network device has now been registered, so tell irmanager about
 	 * it, so it can be configured with network parameters
@@ -109,7 +115,7 @@
 {
 	struct irlan_cb *self;
 	
-	DEBUG(0, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(dev != NULL, return -1;);
 
@@ -144,7 +150,7 @@
 {
 	struct irlan_cb *self = (struct irlan_cb *) dev->priv;
 
-	DEBUG(0, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
 	
 	/* Stop device */
 	dev->tbusy = 1;
@@ -179,76 +185,58 @@
 int irlan_eth_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct irlan_cb *self;
+	int ret;
 
-	DEBUG(4, __FUNCTION__ "()\n");
-	
 	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;
-	}
-	
-	DEBUG(4, "Room left at head: %d\n", skb_headroom(skb));
-	DEBUG(4, "Room left at tail: %d\n", skb_tailroom(skb));
-	DEBUG(4, "Required room: %d\n", IRLAN_MAX_HEADER);
+	/* Check if IrTTP can accept more frames */
+	if (dev->tbusy)
+		return -EBUSY;
 	
-	/* skb headroom large enough to contain IR-headers? */
-	if ((skb_headroom(skb) < IRLAN_MAX_HEADER) || (skb_shared(skb))) {
+	/* skb headroom large enough to contain all IrDA-headers? */
+	if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
 		struct sk_buff *new_skb = 
-			skb_realloc_headroom(skb, IRLAN_MAX_HEADER);
-		ASSERT(new_skb != NULL, return 0;);
-		ASSERT(skb_headroom(new_skb) >= IRLAN_MAX_HEADER, return 0;);
+			skb_realloc_headroom(skb, self->max_header_size);
 
-		/*  Free original skb, and use the new one */
+		/*  We have to free the original skb anyway */
 		dev_kfree_skb(skb);
+
+		/* Did the realloc succeed? */
+		if (new_skb == NULL)
+			return 0;
+
+		/* Use the new skb instead */
 		skb = new_skb;
 	} 
 
 	dev->trans_start = jiffies;
-	self->stats.tx_packets++;
-	self->stats.tx_bytes += skb->len; 
 
-	/*
-	 *  Now queue the packet in the transport layer
-	 *  FIXME: clean up the code below! DB
-	 */
-	if (self->use_udata) {
-		irttp_udata_request(self->tsap_data, skb);
-		dev->tbusy = 0;
-	
-		return 0;
-	}
+	/* Now queue the packet in the transport layer */
+	if (self->use_udata)
+		ret = irttp_udata_request(self->tsap_data, skb);
+	else
+		ret = irttp_data_request(self->tsap_data, skb);
 
-	if (irttp_data_request(self->tsap_data, skb) == -1) {
-		/*  
-		 *  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
+	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;
-		
-		return 0;
+		self->stats.tx_dropped++;
+	} else {
+		self->stats.tx_packets++;
+		self->stats.tx_bytes += skb->len; 
 	}
-	dev->tbusy = 0; /* Finished! */
 	
 	return 0;
 }
@@ -282,11 +270,11 @@
 	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;
 }
 
@@ -301,8 +289,6 @@
 	struct irlan_cb *self;
 	struct device *dev;
 
-	DEBUG(4, __FUNCTION__ "()\n");
-
 	self = (struct irlan_cb *) instance;
 
 	ASSERT(self != NULL, return;);
@@ -314,26 +300,16 @@
 	
 	switch (flow) {
 	case FLOW_STOP:
-		DEBUG(4, "IrLAN, stopping Ethernet layer\n");
-
 		dev->tbusy = 1;
 		break;
 	case FLOW_START:
-		/* 
-		 *  Tell upper layers that its time to transmit frames again
-		 */
-		DEBUG(4, "IrLAN, starting Ethernet layer\n");
-
+	default:
+		/* Tell upper layers that its time to transmit frames again */
 		dev->tbusy = 0;
 
-		/* 
-		 *  Ready to receive more frames, so schedule the network
-		 *  layer
-		 */
+		/* Schedule network layer */
 		mark_bh(NET_BH);		
 		break;
-	default:
-		DEBUG(0, __FUNCTION__ "(), Unknown flow command!\n");
 	}
 }
 
@@ -360,7 +336,7 @@
  *    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;
 
@@ -373,7 +349,7 @@
 	in_dev = dev->ip_ptr;
 	arp_send(ARPOP_REQUEST, ETH_P_ARP, 
 		 in_dev->ifa_list->ifa_address,
-		 &dev, 
+		 dev, 
 		 in_dev->ifa_list->ifa_address,
 		 NULL, dev->dev_addr, NULL);
 }
@@ -391,16 +367,21 @@
 
  	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");
@@ -420,13 +401,10 @@
 		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);
-	}
 }
 
 /*
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_event.c linux/net/irda/irlan/irlan_event.c
--- v2.2.9/linux/net/irda/irlan/irlan_event.c	Wed Mar 10 15:29:52 1999
+++ linux/net/irda/irlan/irlan_event.c	Sun May 30 10:17:04 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Oct 20 09:10:16 1998
- * Modified at:   Wed Feb  3 21:42:27 1999
+ * Modified at:   Sun May  9 21:17:44 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 
@@ -38,22 +38,22 @@
 	"IRLAN_SYNC",
 };
 
-void irlan_next_client_state( struct irlan_cb *self, IRLAN_STATE state) 
+void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state) 
 {
 	DEBUG(2, __FUNCTION__"(), %s\n", irlan_state[state]);
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLAN_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	self->client.state = state;
 }
 
-void irlan_next_provider_state( struct irlan_cb *self, IRLAN_STATE state) 
+void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state) 
 {
 	DEBUG(2, __FUNCTION__"(), %s\n", irlan_state[state]);
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLAN_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	self->provider.state = state;
 }
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_filter.c linux/net/irda/irlan/irlan_filter.c
--- v2.2.9/linux/net/irda/irlan/irlan_filter.c	Fri Apr 16 14:47:31 1999
+++ linux/net/irda/irlan/irlan_filter.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Jan 29 11:16:38 1999
- * Modified at:   Thu Feb 25 15:10:54 1999
+ * Modified at:   Fri May 14 23:11:01 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 
@@ -23,6 +23,7 @@
  ********************************************************************/
 
 #include <linux/skbuff.h>
+#include <linux/random.h>
 
 #include <net/irda/irlan_common.h>
 
@@ -41,29 +42,29 @@
 	    (self->provider.filter_operation == DYNAMIC))
 	{
 		DEBUG(0, "Giving peer a dynamic Ethernet address\n");
-
 		self->provider.mac_address[0] = 0x40;
 		self->provider.mac_address[1] = 0x00;
 		self->provider.mac_address[2] = 0x00;
 		self->provider.mac_address[3] = 0x00;
 		
 		/* Use arbitration value to generate MAC address */
-		if (self->access_type == ACCESS_PEER) {
+		if (self->provider.access_type == ACCESS_PEER) {
 			self->provider.mac_address[4] = 
 				self->provider.send_arb_val & 0xff;
 			self->provider.mac_address[5] = 
 				(self->provider.send_arb_val >> 8) & 0xff;;
 		} else {
 			/* Just generate something for now */
-			self->provider.mac_address[4] = jiffies & 0xff;
-			self->provider.mac_address[5] = (jiffies >> 8) & 0xff;
+			get_random_bytes(self->provider.mac_address+4, 1);
+			get_random_bytes(self->provider.mac_address+5, 1);
 		}
 
 		skb->data[0] = 0x00; /* Success */
 		skb->data[1] = 0x03;
 		irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
 		irlan_insert_short_param(skb, "MAX_ENTRY", 0x0001);
-		irlan_insert_array_param(skb, "FILTER_ENTRY", self->provider.mac_address, 6);
+		irlan_insert_array_param(skb, "FILTER_ENTRY", 
+					 self->provider.mac_address, 6);
 		return;
 	}
 	
@@ -138,8 +139,7 @@
  *    Check parameters in request from peer device
  *
  */
-void irlan_check_command_param(struct irlan_cb *self, char *param, 
-			       char *value)
+void irlan_check_command_param(struct irlan_cb *self, char *param, char *value)
 {
 	__u8 *bytes;
 
@@ -210,6 +210,12 @@
 	}
 }
 
+/*
+ * Function irlan_print_filter (filter_type, buf)
+ *
+ *    Print status of filter. Used by /proc file system
+ *
+ */
 int irlan_print_filter(int filter_type, char *buf)
 {
 	int len = 0;
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_provider.c linux/net/irda/irlan/irlan_provider.c
--- v2.2.9/linux/net/irda/irlan/irlan_provider.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlan/irlan_provider.c	Sun May 30 10:17:04 1999
@@ -6,13 +6,14 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 14:28:52 1999
+ * Modified at:   Sun May  9 12:22:56 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>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     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 
@@ -31,6 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/random.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -50,14 +52,20 @@
 #include <net/irda/irlan_filter.h>
 #include <net/irda/irlan_client.h>
 
+static void irlan_provider_connect_indication(void *instance, void *sap, 
+					      struct qos_info *qos, 
+					      __u32 max_sdu_size,
+					      __u8 max_header_size,
+					      struct sk_buff *skb);
+
 /*
  * Function irlan_provider_control_data_indication (handle, skb)
  *
  *    This function gets the data that is received on the control channel
  *
  */
-int irlan_provider_data_indication(void *instance, void *sap, 
-				   struct sk_buff *skb) 
+static int irlan_provider_data_indication(void *instance, void *sap, 
+					  struct sk_buff *skb) 
 {
 	struct irlan_cb *self;
 	__u8 code;
@@ -111,14 +119,17 @@
  *    Got connection from peer IrLAN layer
  *
  */
-void irlan_provider_connect_indication(void *instance, void *sap, 
-				       struct qos_info *qos,
-				       __u32 max_sdu_size, struct sk_buff *skb)
+static void irlan_provider_connect_indication(void *instance, void *sap, 
+					      struct qos_info *qos,
+					      __u32 max_sdu_size, 
+					      __u8 max_header_size,
+					       struct sk_buff *skb)
 {
-	struct irlan_cb *self, *entry, *new;
+	struct irlan_cb *self, *new;
 	struct tsap_cb *tsap;
+	__u32 saddr, daddr;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	DEBUG(0, __FUNCTION__ "()\n");
 	
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -126,34 +137,69 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
+	self->provider.max_sdu_size = max_sdu_size;
+	self->provider.max_header_size = max_header_size;
+
 	ASSERT(tsap == self->provider.tsap_ctrl,return;);
 	ASSERT(self->provider.state == IRLAN_IDLE, return;);
 
-	/* Check if this provider is currently unused */
-	if (self->daddr == DEV_ADDR_ANY) {
-		/*
-		 * Rehash instance, now we have a client (daddr) to serve.
-		 */
-		entry = hashbin_remove(irlan, self->daddr, NULL);
-		ASSERT( entry == self, return;);
-		
-		self->daddr = irttp_get_daddr(tsap);
-		DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
-		hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
+	daddr = irttp_get_daddr(tsap);
+	saddr = irttp_get_saddr(tsap);
+
+	/* Check if we already dealing with this client or peer */
+	new = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL);
+      	if (new) {
+		ASSERT(new->magic == IRLAN_MAGIC, return;);
+		DEBUG(0, __FUNCTION__ "(), found instance!\n");
+
+		/* Update saddr, since client may have moved to a new link */
+		new->saddr = saddr;
+		DEBUG(2, __FUNCTION__ "(), saddr=%08x\n", new->saddr);
+
+		/* Make sure that any old provider control TSAP is removed */
+		if ((new != self) && new->provider.tsap_ctrl) {
+			irttp_disconnect_request(new->provider.tsap_ctrl, 
+						 NULL, P_NORMAL);
+			irttp_close_tsap(new->provider.tsap_ctrl);
+			new->provider.tsap_ctrl = NULL;
+		}
 	} else {
-		/*
-		 * If we already have the daddr set, this means that the
-		 * client must already have started (peer mode). We must
-		 * make sure that this connection attempt is from the same
-		 * device as the client is dealing with!  
+		/* This must be the master instance, so start a new instance */
+		DEBUG(0, __FUNCTION__ "(), starting new provider!\n");
+
+		new = irlan_open(saddr, daddr, TRUE); 
+	}
+
+	/*  
+	 * Check if the connection came in on the master server, or the
+	 * slave server. If it came on the slave, then everything is
+	 * really, OK (reconnect), if not we need to dup the connection and
+	 * hand it over to the slave.  
+	 */
+	if (new != self) {
+				
+		/* Now attach up the new "socket" */
+		new->provider.tsap_ctrl = irttp_dup(self->provider.tsap_ctrl, 
+						    new);
+		if (!new->provider.tsap_ctrl) {
+			DEBUG(0, __FUNCTION__ "(), dup failed!\n");
+			return;
+		}
+		
+		/* new->stsap_sel = new->tsap->stsap_sel; */
+		new->dtsap_sel_ctrl = new->provider.tsap_ctrl->dtsap_sel;
+
+		/* Clean up the original one to keep it in listen state */
+		self->provider.tsap_ctrl->dtsap_sel = LSAP_ANY;
+		self->provider.tsap_ctrl->lsap->dlsap_sel = LSAP_ANY;
+		self->provider.tsap_ctrl->lsap->lsap_state = LSAP_DISCONNECTED;
+		
+		/* 
+		 * Use the new instance from here instead of the master
+		 * struct! 
 		 */
-		ASSERT(self->daddr == irttp_get_daddr(tsap), return;);
+		self = new;
 	}
-	
-	/* Update saddr, since client may have moved to a new link */
-	self->saddr = irttp_get_saddr(tsap);
-	DEBUG(2, __FUNCTION__ "(), saddr=%08x\n", self->saddr);
-	
 	/* Check if network device has been registered */
 	if (!self->netdev_registered)
 		irlan_register_netdev(self);
@@ -165,9 +211,10 @@
 	 * indication it needs to make progress. If the client is still in 
 	 * IDLE state, we must kick it to 
 	 */
-	if ((self->access_type == ACCESS_PEER) && 
-	    (self->client.state == IRLAN_IDLE))
+	if ((self->provider.access_type == ACCESS_PEER) && 
+	    (self->client.state == IRLAN_IDLE)) {
 		irlan_client_wakeup(self, self->saddr, self->daddr);
+	}
 }
 
 /*
@@ -225,6 +272,9 @@
 	
 	ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb);
 
+	/* Open data channel */
+	irlan_open_data_tsap(self);
+
 	return ret;
 }
 
@@ -314,7 +364,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->provider.max_header_size);
 	skb_put(skb, 2);
        
 	switch (command) {
@@ -334,6 +384,7 @@
 		}
 		irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
 		break;
+
 	case CMD_GET_MEDIA_CHAR:
 		skb->data[0] = 0x00; /* Success */
 		skb->data[1] = 0x05; /* 5 parameters */
@@ -341,7 +392,7 @@
 		irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
 		irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
 
-		switch(self->access_type) {
+		switch (self->provider.access_type) {
 		case ACCESS_DIRECT:
 			irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
 			break;
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_provider_event.c linux/net/irda/irlan/irlan_provider_event.c
--- v2.2.9/linux/net/irda/irlan/irlan_provider_event.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlan/irlan_provider_event.c	Sun May 30 10:17:04 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 10:46:28 1999
+ * Modified at:   Fri May  7 10:53:58 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 <dagb@cs.uit.no>, 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 
@@ -108,7 +108,7 @@
 	switch(event) {
 	case IRLAN_GET_INFO_CMD:
 		/* Be sure to use 802.3 in case of peer mode */
-		if (self->access_type == ACCESS_PEER) {
+		if (self->provider.access_type == ACCESS_PEER) {
 			self->media = MEDIA_802_3;
 			
 			/* Check if client has started yet */
@@ -129,7 +129,7 @@
 		break;		
 	case IRLAN_OPEN_DATA_CMD:
 		ret = irlan_parse_open_data_cmd(self, skb);
-		if (self->access_type == ACCESS_PEER) {
+		if (self->provider.access_type == ACCESS_PEER) {
 			/* FIXME: make use of random functions! */
 			self->provider.send_arb_val = (jiffies & 0xffff);
 		}
@@ -205,8 +205,6 @@
 static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, 
 				     struct sk_buff *skb) 
 {
-	struct irmanager_event mgr_event;
-
 	DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
@@ -220,10 +218,6 @@
 		break;
 	case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
 	case IRLAN_LAP_DISCONNECT:
-		mgr_event.event = EVENT_IRLAN_STOP;
-		sprintf(mgr_event.devname, "%s", self->ifname);
-		irmanager_notify(&mgr_event);
-
 		irlan_next_provider_state(self, IRLAN_IDLE);
 		break;
 	default:
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlap.c linux/net/irda/irlap.c
--- v2.2.9/linux/net/irda/irlap.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlap.c	Mon Jun  7 16:19:59 1999
@@ -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 @@
 };
 
 #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 @@
 
 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 @@
  *    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 @@
 		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 @@
  *    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);
+	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);
+	irlap_flush_all_queues(self);
        
 	self->irdev = NULL;
 	self->magic = 0;
 	
-	kfree( self);
+	kfree(self);
 }
 
 /*
@@ -193,27 +198,27 @@
  *    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_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 @@
  *    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 @@
  *    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 @@
 	 *  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 @@
  *    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 @@
 {
 	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 @@
 
 		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 @@
  *    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 @@
 		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_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_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_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_confirm(void)
 {
- 	DEBUG( 1, __FUNCTION__ "()\n");
+ 	DEBUG(1, __FUNCTION__ "()\n");
 }
 
 /*
@@ -641,15 +641,15 @@
  *    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 @@
  *    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 @@
  *
  *    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 @@
  *    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 @@
 	 *  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 @@
  *    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 @@
  *    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 @@
 	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 @@
 	__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 @@
 	 *  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_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 @@
 	 *  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 @@
 	/* 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 @@
  *    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_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 @@
 	 */
 	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 @@
 	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 @@
 	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 @@
  *    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 @@
 
 	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);
 
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlap_comp.c linux/net/irda/irlap_comp.c
--- v2.2.9/linux/net/irda/irlap_comp.c	Wed Mar 10 15:29:52 1999
+++ linux/net/irda/irlap_comp.c	Sun May 30 10:17:04 1999
@@ -6,11 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Oct  9 09:18:07 1998
- * Modified at:   Mon Feb  8 01:23:52 1999
+ * Modified at:   Sun May  9 11:37:06 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       ppp.c, isdn_ppp.c
  * 
- *     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 
@@ -255,11 +255,11 @@
 	}
 
 	/* FIXME: Find out what is the max overhead (not 10) */
-	new_skb = dev_alloc_skb( skb->len+LAP_HEADER+10);
+	new_skb = dev_alloc_skb( skb->len+LAP_MAX_HEADER+10);
 	if(!new_skb)
 		return skb;
 
-	skb_reserve( new_skb, LAP_HEADER);
+	skb_reserve( new_skb, LAP_MAX_HEADER);
 	skb_put( new_skb, skb->len+10);
 	
 	count = (self->compressor.cp->compress)( self->compressor.state, 
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlap_event.c linux/net/irda/irlap_event.c
--- v2.2.9/linux/net/irda/irlap_event.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlap_event.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Fri Apr 23 11:55:12 1999
+ * Modified at:   Mon May 31 21:55:42 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>,
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
  *                        Thomas Davis <ratbert@radiks.net>
  *     All Rights Reserved.
  *     
@@ -209,8 +209,8 @@
  *    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 @@
 		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 @@
 		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,
@@ -274,22 +273,22 @@
  *    Switches state and provides debug information
  *
  */
-void irlap_next_state( struct irlap_cb *self, IRLAP_STATE state) 
+void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) 
 {	
-	if ( !self || self->magic != LAP_MAGIC)
+	if (!self || self->magic != LAP_MAGIC)
 		return;
 	
-	DEBUG( 4, "next LAP state = %s\n", irlap_state[ state]);
+	DEBUG(4, "next LAP state = %s\n", irlap_state[ state]);
 
 	self->state = state;
 
 	/*
 	 *  If we are swithing away from a XMIT state then we are allowed to 
 	 *  transmit a maximum number of bytes again when we enter the XMIT 
-	 *  state again. Since its possible to "switch" from XMIT to XMIT and
+	 *  state again. Since its possible to "switch" from XMIT to XMIT,
 	 *  we cannot do this when swithing into the XMIT state :-)
 	 */
-	if (( state != LAP_XMIT_P) && ( state != LAP_XMIT_S))
+	if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S))
 		self->bytes_left = self->window_bytes;
 }
 
@@ -310,7 +309,7 @@
 	ASSERT( self != NULL, return -1;);
 	ASSERT( self->magic == LAP_MAGIC, return -1;);
 
-	switch( event) {
+	switch(event) {
 	case CONNECT_REQUEST:
 		ASSERT( self->irdev != NULL, return -1;);
 
@@ -393,7 +392,6 @@
 			irlap_start_query_timer( self, QUERY_TIMEOUT);
 			irlap_next_state( self, LAP_REPLY);
 		}
-
 		dev_kfree_skb(skb);
 		break;
 
@@ -530,7 +528,7 @@
 			irlap_send_discovery_xid_frame(self, info->S,
 						       self->slot, FALSE,
 						       discovery_rsp);
-
+			
 			self->frame_sent = TRUE;
 			irlap_next_state(self, LAP_REPLY);
 		}
@@ -568,27 +566,28 @@
 
 	switch (event) {
 	case CONNECT_RESPONSE:
-		skb_pull( skb, 11);
+		/* skb_pull(skb, 11); */
+		skb_pull(skb, sizeof(struct snrm_frame));
 
-		ASSERT( self->irdev != NULL, return -1;);
-		irda_qos_negotiate( &self->qos_rx, &self->qos_tx, skb);
+		ASSERT(self->irdev != NULL, return -1;);
+		irda_qos_negotiate(&self->qos_rx, &self->qos_tx, skb);
 
 		irlap_initiate_connection_state( self);
 
 		/*
 		 * We are allowed to send two frames!
 		 */
-		irlap_send_ua_response_frame( self, &self->qos_rx);
-		irlap_send_ua_response_frame( self, &self->qos_rx);
+		irlap_send_ua_response_frame(self, &self->qos_rx);
+		irlap_send_ua_response_frame(self, &self->qos_rx);
 		
-		irlap_apply_connection_parameters( self, &self->qos_tx);
+		irlap_apply_connection_parameters(self, &self->qos_tx);
 
 		/*
 		 *  The WD-timer could be set to the duration of the P-timer 
-		 *  for this case, but it is recommomended to use twice the 
+		 *  for this case, but it is recommended to use twice the 
 		 *  value (note 3 IrLAP p. 60). 
 		 */
-		irlap_start_wd_timer( self, self->wd_timeout);
+		irlap_start_wd_timer(self, self->wd_timeout);
 		irlap_next_state( self, LAP_NRM_S);
 		break;
 
@@ -669,28 +668,30 @@
 		 *  The device with the largest device address wins the battle
 		 *  (both have sent a SNRM command!)
 		 */
-		if ( info->daddr > self->saddr) {
-			del_timer( &self->final_timer);
-			irlap_initiate_connection_state( self);
+		if (info->daddr > self->saddr) {
+			del_timer(&self->final_timer);
+			irlap_initiate_connection_state(self);
 
-			ASSERT( self->irdev != NULL, return -1;);
-			irda_qos_negotiate( &self->qos_rx, &self->qos_tx, skb);
+			ASSERT(self->irdev != NULL, return -1;);
+			/* skb_pull(skb, 11); */
+			skb_pull(skb, sizeof(struct snrm_frame));
+			irda_qos_negotiate(&self->qos_rx, &self->qos_tx, skb);
 			
 			irlap_send_ua_response_frame(self, &self->qos_rx);
-			irlap_apply_connection_parameters( self, &self->qos_tx);
-			irlap_connect_confirm( self, skb);
+			irlap_apply_connection_parameters(self, &self->qos_tx);
+			irlap_connect_confirm(self, skb);
 			
 			/* 
 			 *  The WD-timer could be set to the duration of the
-			 *  P-timer for this case, but it is recommomended
+			 *  P-timer for this case, but it is recommended
 			 *  to use twice the value (note 3 IrLAP p. 60).  
 			 */
-			irlap_start_wd_timer( self, self->wd_timeout);
+			irlap_start_wd_timer(self, self->wd_timeout);
 			
-			irlap_next_state( self, LAP_NRM_S);
+			irlap_next_state(self, LAP_NRM_S);
 		} else {
 			/* We just ignore the other device! */
-			irlap_next_state( self, LAP_SETUP);
+			irlap_next_state(self, LAP_SETUP);
 		}
 		break;
 	case RECV_UA_RSP:
@@ -702,9 +703,10 @@
 
 		/* Negotiate connection parameters */
 		ASSERT( skb->len > 10, return -1;);
-		skb_pull( skb, 10);
+		/* skb_pull(skb, 10); */
+		skb_pull(skb, sizeof(struct ua_frame));
 
-		ASSERT( self->irdev != NULL, return -1;);
+		ASSERT(self->irdev != NULL, return -1;);
 		irda_qos_negotiate( &self->qos_rx, &self->qos_tx, skb);
 
 		irlap_apply_connection_parameters( self, &self->qos_tx); 
@@ -758,36 +760,30 @@
  *    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
@@ -799,7 +795,7 @@
 				 */
 				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
@@ -808,11 +804,9 @@
 			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);
 				
@@ -930,9 +924,6 @@
 	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 */
@@ -944,7 +935,6 @@
 		 */
 		self->fast_RR = FALSE;
 #endif
-
 		ASSERT( info != NULL, return -1;);
 
 		ns_status = irlap_validate_ns_received(self, info->ns);
@@ -1138,13 +1128,6 @@
 		}
 		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 
@@ -1191,14 +1174,6 @@
 			/* 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 "
@@ -1207,8 +1182,7 @@
 
 			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)
@@ -1476,13 +1450,13 @@
 		/*
 		 *  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);
 				/*
@@ -1504,11 +1478,9 @@
 			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);
 
@@ -1570,7 +1542,7 @@
 			/* 
 			 *  poll bit cleared?
 			 */
-			if ( !info->pf) {
+			if (!info->pf) {
 				self->vr = (self->vr + 1) % 8;
 				
 				/* Update Nr received */
@@ -1600,35 +1572,39 @@
 				 *  also before changing to XMIT_S
 				 *  state. (note 1, IrLAP p. 82) 
 				 */
-				irlap_wait_min_turn_around( self, &self->qos_tx);
-				/*
-				 *  Any pending data requests?
+				irlap_wait_min_turn_around(self, &self->qos_tx);
+
+				/*  
+				 * Give higher layers a chance to
+				 * immediately reply with some data before
+				 * we decide if we should send a RR frame
+				 * or not
 				 */
-				if (( skb_queue_len( &self->tx_list) > 0) && 
-				    ( self->window > 0)) 
+				irlap_data_indication(self, skb);
+
+				/* Any pending data requests?  */
+				if ((skb_queue_len(&self->tx_list) > 0) && 
+				    (self->window > 0)) 
 				{
 					self->ack_required = TRUE;
 					
-					del_timer( &self->wd_timer);
+					del_timer(&self->wd_timer);
 					
-					irlap_next_state( self, LAP_XMIT_S);
+					irlap_next_state(self, LAP_XMIT_S);
 				} else {
-					irlap_send_rr_frame( self, RSP_FRAME);
-					irlap_start_wd_timer( self, self->wd_timeout);
+					irlap_send_rr_frame(self, RSP_FRAME);
+					irlap_start_wd_timer(self, self->wd_timeout);
 
 					/* Keep the state */
-					irlap_next_state( self, LAP_NRM_S);
+					irlap_next_state(self, LAP_NRM_S);
 				}
-				irlap_data_indication( self, skb);
-
 				break;
 			}
 		}
 		/*
 		 *  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) {
@@ -1651,8 +1627,7 @@
 		/* 
 		 *  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");
@@ -1748,20 +1723,20 @@
 				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);
@@ -1773,8 +1748,8 @@
 		} 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:
@@ -1886,7 +1861,7 @@
 	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);
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c
--- v2.2.9/linux/net/irda/irlap_frame.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlap_frame.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Fri Apr 23 09:30:42 1999
+ * Modified at:   Mon May 31 09:29:13 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -1001,10 +1001,6 @@
 {
 	__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 @@
 	/* 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);
 }
 
@@ -1056,8 +1043,8 @@
  *    Receive and parse an Unnumbered Information (UI) frame
  *
  */
-static void irlap_recv_ui_frame( struct irlap_cb *self, struct sk_buff *skb, 
-				 struct irlap_info *info)
+static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, 
+				struct irlap_info *info)
 {
 	__u8 *frame;
 
@@ -1240,7 +1227,7 @@
 	 *  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;
@@ -1254,7 +1241,7 @@
 		 *  Received S(upervisory) frame, check which frame type it is
 		 *  only the first nibble is of interest
 		 */
-		switch(control & 0x0f) {
+		switch (control & 0x0f) {
 		case RR:
 			irlap_recv_rr_frame( self, skb, &info, command);
 			self->stats.rx_packets++;
@@ -1279,7 +1266,7 @@
 	/* 
 	 *  This must be a C(ontrol) frame 
 	 */
-	switch(control) {
+	switch (control) {
 	case XID_RSP:
 		irlap_recv_discovery_xid_rsp(self, skb, &info);
 		break;
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlmp.c linux/net/irda/irlmp.c
--- v2.2.9/linux/net/irda/irlmp.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlmp.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Fri Apr 23 09:13:24 1999
+ * Modified at:   Mon May 31 21:49:41 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -197,7 +197,7 @@
 }
 
 /*
- * Function irlmp_close_lsap (self)
+ * Function __irlmp_close_lsap (self)
  *
  *    Remove an instance of LSAP
  */
@@ -369,11 +369,11 @@
 		if (!skb)
 			return -ENOMEM;
 
-		skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+		skb_reserve(skb, LMP_MAX_HEADER);
 	} else
 		skb = userdata;
 	
-	/* Make room for MUX control header ( 3 bytes) */
+	/* Make room for MUX control header (3 bytes) */
 	ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;);
 	skb_push(skb, LMP_CONTROL_HEADER);
 
@@ -443,25 +443,35 @@
 void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
 	int max_seg_size;
-
-	DEBUG(3, __FUNCTION__ "()\n");
+	int lap_header_size;
+	int max_header_size;
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 	ASSERT(skb != NULL, return;);
 	ASSERT(self->lap != NULL, return;);
 
+	DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+	      self->slsap_sel, self->dlsap_sel);
+
 	self->qos = *self->lap->qos;
 
-	max_seg_size = self->lap->qos->data_size.value;
-	DEBUG(4, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_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);
+
 	/* Hide LMP_CONTROL_HEADER header from layer above */
 	skb_pull(skb, LMP_CONTROL_HEADER);
 
 	if (self->notify.connect_indication)
 		self->notify.connect_indication(self->notify.instance, self, 
-						&self->qos, max_seg_size, skb);
+						&self->qos, max_seg_size, 
+						max_header_size, skb);
 }
 
 /*
@@ -470,24 +480,22 @@
  *    Service user is accepting connection
  *
  */
-void irlmp_connect_response( struct lsap_cb *self, struct sk_buff *userdata) 
+void irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) 
 {
-	DEBUG(3, __FUNCTION__ "()\n");
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT( userdata != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(userdata != NULL, return;);
 
 	self->connected = TRUE;
 
-	DEBUG( 4, "irlmp_connect_response: slsap_sel=%02x, dlsap_sel=%02x\n", 
-	       self->slsap_sel, self->dlsap_sel);
+	DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+	      self->slsap_sel, self->dlsap_sel);
 
 	/* Make room for MUX control header ( 3 bytes) */
-	ASSERT( skb_headroom( userdata) >= LMP_CONTROL_HEADER, return;);
-	skb_push( userdata, LMP_CONTROL_HEADER);
+	ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return;);
+	skb_push(userdata, LMP_CONTROL_HEADER);
 	
-	irlmp_do_lsap_event( self, LM_CONNECT_RESPONSE, userdata);
+	irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
 }
 
 /*
@@ -498,25 +506,34 @@
 void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) 
 {
 	int max_seg_size;
+	int max_header_size;
+	int lap_header_size;
 
 	DEBUG(3, __FUNCTION__ "()\n");
 	
-	ASSERT( skb != NULL, return;);
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 	
-	ASSERT( self->lap != NULL, return;);
+	ASSERT(self->lap != NULL, return;);
 	self->qos = *self->lap->qos;
 
-	max_seg_size = self->qos.data_size.value;
-	DEBUG( 4, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_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);
+
 	/* Hide LMP_CONTROL_HEADER header from layer above */
-	skb_pull( skb, LMP_CONTROL_HEADER);
+	skb_pull(skb, LMP_CONTROL_HEADER);
 
-	if ( self->notify.connect_confirm) {
-		self->notify.connect_confirm( self->notify.instance, self,
-					      &self->qos, max_seg_size, skb);
+	if (self->notify.connect_confirm) {
+		self->notify.connect_confirm(self->notify.instance, self,
+					     &self->qos, max_seg_size, 
+					     max_header_size, skb);
 	}
 }
 
@@ -620,8 +637,8 @@
  *
  *    LSAP is being closed!
  */
-void irlmp_disconnect_indication( struct lsap_cb *self, LM_REASON reason, 
-				  struct sk_buff *userdata) 
+void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, 
+				 struct sk_buff *userdata) 
 {
 	struct lsap_cb *lsap;
 
@@ -637,6 +654,10 @@
 	self->connected = FALSE;
 	self->dlsap_sel = LSAP_ANY;
 
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+	irlmp->cache.valid = FALSE;
+#endif
+
 	/* 
 	 *  Remove association between this LSAP and the link it used 
 	 */
@@ -975,7 +996,7 @@
 	DEBUG( 1, "irlmp_status_request(), Not implemented\n");
 }
 
-void irlmp_status_indication( LINK_STATUS link, LOCK_STATUS lock) 
+void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock) 
 {
 	DEBUG( 4, "irlmp_status_indication(), Not implemented\n");
 }
@@ -1418,14 +1439,14 @@
  *    Give some info to the /proc file system
  *
  */
-int irlmp_proc_read( char *buf, char **start, off_t offset, int len, 
-		     int unused)
+int irlmp_proc_read(char *buf, char **start, off_t offset, int len, 
+		    int unused)
 {
 	struct lsap_cb *self;
 	struct lap_cb *lap;
 	unsigned long flags;
 
-	ASSERT( irlmp != NULL, return 0;);
+	ASSERT(irlmp != NULL, return 0;);
 	
 	save_flags( flags);
 	cli();
@@ -1449,35 +1470,34 @@
  	} 
 
 	len += sprintf( buf+len, "\nRegistred Link Layers:\n");
-	lap = (struct lap_cb *) hashbin_get_first( irlmp->links);
-	while ( lap != NULL) {
-		ASSERT( lap->magic == LMP_LAP_MAGIC, return 0;);
 
-		len += sprintf( buf+len, "lap state: %s, ", 
-				irlmp_state[ lap->lap_state]);
+	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
+	while (lap != NULL) {
+		len += sprintf(buf+len, "lap state: %s, ", 
+			       irlmp_state[lap->lap_state]);
 
-		len += sprintf( buf+len, "saddr: %#08x, daddr: %#08x, ",
-				lap->saddr, lap->daddr); 
-		len += sprintf( buf+len, "\n");
+		len += sprintf(buf+len, "saddr: %#08x, daddr: %#08x, ",
+			       lap->saddr, lap->daddr); 
+		len += sprintf(buf+len, "\n");
 
 		len += sprintf( buf+len, "\nConnected LSAPs:\n");
 		self = (struct lsap_cb *) hashbin_get_first( lap->lsaps);
-		while ( self != NULL) {
-			ASSERT( self->magic == LMP_LSAP_MAGIC, return 0;);
-			len += sprintf( buf+len, "lsap state: %s, ", 
-					irlsap_state[ self->lsap_state]);
-			len += sprintf( buf+len, 
-					"slsap_sel: %#02x, dlsap_sel: %#02x, ",
-					self->slsap_sel, self->dlsap_sel);
-			len += sprintf( buf+len, "(%s)", self->notify.name);
-			len += sprintf( buf+len, "\n");
+		while (self != NULL) {
+			ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+			len += sprintf(buf+len, "lsap state: %s, ", 
+				       irlsap_state[ self->lsap_state]);
+			len += sprintf(buf+len, 
+				       "slsap_sel: %#02x, dlsap_sel: %#02x, ",
+				       self->slsap_sel, self->dlsap_sel);
+			len += sprintf(buf+len, "(%s)", self->notify.name);
+			len += sprintf(buf+len, "\n");
 			
-			self = ( struct lsap_cb *) hashbin_get_next( 
+			self = (struct lsap_cb *) hashbin_get_next( 
 				lap->lsaps);
 		} 
+		len += sprintf(buf+len, "\n");
 
-		lap = ( struct lap_cb *) hashbin_get_next( 
-			irlmp->links);
+		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
  	} 
 
 	restore_flags( flags);
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlmp_frame.c linux/net/irda/irlmp_frame.c
--- v2.2.9/linux/net/irda/irlmp_frame.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlmp_frame.c	Mon Jun  7 16:19:59 1999
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      irlmp_frame.c
- * Version:       0.8
+ * Version:       0.9
  * Description:   IrLMP frame implementation
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 02:09:59 1997
- * Modified at:   Fri Apr 23 09:12:23 1999
+ * Modified at:   Mon May 31 09:53:16 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -59,16 +59,16 @@
  *
  *    Send Link Control Frame to IrLAP
  */
-void irlmp_send_lcf_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap,
-			 __u8 opcode, struct sk_buff *skb) 
+void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
+			__u8 opcode, struct sk_buff *skb) 
 {
 	__u8 *frame;
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
 	
 	frame = skb->data;
 	
@@ -82,8 +82,8 @@
 	else
 		frame[3] = 0x00; /* rsvd */
 
-	ASSERT( self->irlap != NULL, return;);
-	irlap_data_request( self->irlap, skb, TRUE);
+	ASSERT(self->irlap != NULL, return;);
+	irlap_data_request(self->irlap, skb, TRUE);
 }
 
 /*
@@ -112,7 +112,7 @@
 	 */
 	slsap_sel = fp[0] & LSAP_MASK; 
 	dlsap_sel = fp[1];
-	
+
 	/*
 	 *  Check if this is an incoming connection, since we must deal with
 	 *  it in a different way than other established connections.
@@ -134,17 +134,17 @@
 				       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;
 	}
 
@@ -224,11 +224,11 @@
  *    Incoming LAP connection!
  *
  */
-void irlmp_link_connect_indication( struct lap_cb *self, __u32 saddr, 
-				    __u32 daddr, struct qos_info *qos,
-				    struct sk_buff *skb) 
+void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr, 
+				   __u32 daddr, struct qos_info *qos,
+				   struct sk_buff *skb) 
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
 	/* Copy QoS settings for this session */
 	self->qos = qos;
@@ -237,7 +237,7 @@
 	self->daddr = daddr;
 	ASSERT(self->saddr == saddr, return;);
 
-	irlmp_do_lap_event( self, LM_LAP_CONNECT_INDICATION, skb);
+	irlmp_do_lap_event(self, LM_LAP_CONNECT_INDICATION, skb);
 }
 
 /*
@@ -246,19 +246,19 @@
  *    LAP connection confirmed!
  *
  */
-void irlmp_link_connect_confirm( struct lap_cb *self, struct qos_info *qos, 
-				 struct sk_buff *userdata)
+void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, 
+				struct sk_buff *userdata)
 {
-	DEBUG( 4, "irlmp_link_connect_confirm()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT( qos != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT(qos != NULL, return;);
 
 	/* Copy QoS settings for this session */
 	self->qos = qos;
 
-	irlmp_do_lap_event( self, LM_LAP_CONNECT_CONFIRM, NULL);
+	irlmp_do_lap_event(self, LM_LAP_CONNECT_CONFIRM, NULL);
 }
 
 /*
@@ -276,7 +276,9 @@
 	irlmp_add_discovery(irlmp->cachelog, discovery);
 
 	/* Just handle it the same way as a discovery confirm */
+#if 0
 	irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
+#endif
 }
 
 /*
@@ -365,7 +367,7 @@
 #endif
 			return lsap;
 		}
-		lsap = ( struct lsap_cb *) hashbin_get_next(queue);
+		lsap = (struct lsap_cb *) hashbin_get_next(queue);
 	}
 
 	/* Sorry not found! */
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlpt/irlpt_cli.c linux/net/irda/irlpt/irlpt_cli.c
--- v2.2.9/linux/net/irda/irlpt/irlpt_cli.c	Tue May 11 13:10:32 1999
+++ linux/net/irda/irlpt/irlpt_cli.c	Sun May 30 10:17:04 1999
@@ -51,10 +51,11 @@
 static void irlpt_client_connect_confirm(void *instance, void *sap, 
 					 struct qos_info *qos, 
 					 __u32 max_seg_size, 
+					 __u8 max_header_size,
 					 struct sk_buff *skb);
-static void irlpt_client_disconnect_indication( void *instance, void *sap, 
-						LM_REASON reason,
-						struct sk_buff *userdata);
+static void irlpt_client_disconnect_indication(void *instance, void *sap, 
+					       LM_REASON reason,
+					       struct sk_buff *userdata);
 static void irlpt_client_expired(unsigned long data);
 
 #if 0
@@ -187,7 +188,7 @@
 
 #ifdef CONFIG_PROC_FS
 	create_proc_entry("irlpt_client", 0, proc_irda)->get_info
-			= irlpt_client_proc_read;
+		= irlpt_client_proc_read;
 #endif /* CONFIG_PROC_FS */
 
 	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
@@ -215,7 +216,6 @@
 #ifdef CONFIG_PROC_FS
 	remove_proc_entry("irlpt_client", proc_irda);
 #endif
-
 	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
 }
 #endif /* MODULE */
@@ -403,9 +403,8 @@
 
 	irlpt_client_do_event( self, LMP_DISCONNECT, NULL, NULL);
 
-	if (skb) {
+	if (skb)
 		dev_kfree_skb( skb);
-	}
 
 	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
 }
@@ -417,7 +416,8 @@
  */
 static void irlpt_client_connect_confirm(void *instance, void *sap, 
 					 struct qos_info *qos, 
-					 __u32 max_sdu_size,
+					 __u32 max_seg_size,
+					 __u8 max_header_size,
 					 struct sk_buff *skb)
 {
 	struct irlpt_info info;
@@ -443,14 +443,14 @@
 	}
 #endif
 
-	self->irlap_data_size = (qos->data_size.value - IRLPT_MAX_HEADER);
+	self->max_data_size = max_seg_size;
+	self->max_header_size = max_header_size;
 	self->connected = TRUE;
 	
 	irlpt_client_do_event( self, LMP_CONNECT, NULL, NULL);
 
-	if (skb) {
+	if (skb)
 		dev_kfree_skb( skb);
-	}
 
 	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
 }
@@ -603,7 +603,7 @@
 			return;
 		}
 
-		skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER);
+		skb_reserve(skb, LMP_MAX_HEADER);
 		irlmp_disconnect_request(self->lsap, skb);
 		DEBUG(irlpt_client_debug, __FUNCTION__
 		      ": irlmp_close_slap(self->lsap)\n");
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlpt/irlpt_cli_fsm.c linux/net/irda/irlpt/irlpt_cli_fsm.c
--- v2.2.9/linux/net/irda/irlpt/irlpt_cli_fsm.c	Wed Mar 10 15:29:53 1999
+++ linux/net/irda/irlpt/irlpt_cli_fsm.c	Sun May 30 10:17:04 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Jan 12 11:06:00 1999
- * Modified at:   Tue Jan 26 12:02:31 1999
+ * Modified at:   Sun May  9 13:36:13 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>
+ *     Copyright (c) 1998-1999, Thomas Davis, <ratbert@radiks.net>
  *     Copyright (c) 1998, Dag Brattli, <dagb@cs.uit.no>
  *     All Rights Reserved.
  *      
@@ -43,10 +43,10 @@
 				      IRLPT_EVENT event,
 				      struct sk_buff *skb, 
 				      struct irlpt_info *info);
-static int irlpt_client_state_ready  ( struct irlpt_cb *self, 
-				       IRLPT_EVENT event, 
-				       struct sk_buff *skb, 
-				       struct irlpt_info *info);
+static int irlpt_client_state_ready ( struct irlpt_cb *self, 
+				      IRLPT_EVENT event, 
+				      struct sk_buff *skb, 
+				      struct irlpt_info *info);
 static int irlpt_client_state_waiti ( struct irlpt_cb *self, 
 				      IRLPT_EVENT event,
 				      struct sk_buff *skb, 
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlpt/irlpt_common.c linux/net/irda/irlpt/irlpt_common.c
--- v2.2.9/linux/net/irda/irlpt/irlpt_common.c	Wed Mar 10 15:29:53 1999
+++ linux/net/irda/irlpt/irlpt_common.c	Sun May 30 10:17:04 1999
@@ -251,18 +251,18 @@
 	}
 
 	DEBUG( irlpt_common_debug, __FUNCTION__ 
-	       ": count = %d, irlap_data_size = %d, IRLPT_MAX_HEADER = %d\n",
-		count, self->irlap_data_size, IRLPT_MAX_HEADER);
+	       ": count = %d, max_data_size = %d, IRLPT_MAX_HEADER = %d\n",
+		count, self->max_data_size, IRLPT_MAX_HEADER);
 
- 	if (count > (self->irlap_data_size - IRLPT_MAX_HEADER)) {
- 		count = (self->irlap_data_size - IRLPT_MAX_HEADER);
+ 	if (count > self->max_data_size) {
+ 		count = self->max_data_size;
  		DEBUG(irlpt_common_debug, __FUNCTION__ 
 		      ": setting count to %d\n", count);
  	}
 
 	DEBUG( irlpt_common_debug, __FUNCTION__ ": count = %d\n", count);
 
-	skb = dev_alloc_skb(count + IRLPT_MAX_HEADER);
+	skb = dev_alloc_skb(count + self->max_header_size);
 	if ( skb == NULL) {
 		printk( KERN_INFO 
 			__FUNCTION__ ": couldn't allocate skbuff!\n");
@@ -417,7 +417,7 @@
 			return 0;
 		}
 
-		skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER);
+		skb_reserve( skb, LMP_MAX_HEADER);
 		irlmp_disconnect_request(self->lsap, skb);
 		DEBUG(irlpt_common_debug, __FUNCTION__
 		      ": irlmp_close_slap(self->lsap)\n");
diff -u --recursive --new-file v2.2.9/linux/net/irda/irlpt/irlpt_srvr.c linux/net/irda/irlpt/irlpt_srvr.c
--- v2.2.9/linux/net/irda/irlpt/irlpt_srvr.c	Tue May 11 13:10:32 1999
+++ linux/net/irda/irlpt/irlpt_srvr.c	Sun May 30 10:17:04 1999
@@ -51,15 +51,21 @@
 static void irlpt_server_disconnect_indication(void *instance, void *sap, 
 						LM_REASON reason,
 						struct sk_buff *skb);
+
+#if 0
 static void irlpt_server_connect_confirm(void *instance, void *sap, 
 					 struct qos_info *qos,  
 					 __u32 max_seg_size,
+					 __u8 max_header_size,
 					 struct sk_buff *skb);
 static void irlpt_server_connect_indication(void *instance, 
 					    void *sap, 
 					    struct qos_info *qos, 
 					    __u32 max_seg_size,
+					    __u8 max_header_size,
 					    struct sk_buff *skb);
+#endif
+
 static int irlpt_server_data_indication(void *instance, void *sap, 
 					struct sk_buff *skb);
 static void register_irlpt_server(void);
@@ -161,7 +167,6 @@
 }
 
 extern struct proc_dir_entry *proc_irda;
-
 #endif /* CONFIG_PROC_FS */
 
 /*
@@ -171,9 +176,9 @@
  *
  */
 
-/*int irlpt_init( struct device *dev) {*/
 __initfunc(int irlpt_server_init(void))
 {
+	struct irmanager_event mgr_event;
 	__u16 hints;
 
 	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
@@ -212,6 +217,10 @@
 		= irlpt_server_proc_read;
 #endif /* CONFIG_PROC_FS */
 
+	mgr_event.event = EVENT_IRLPT_START;
+        sprintf(mgr_event.devname, "%s", irlpt_server->ifname);
+        irmanager_notify(&mgr_event);
+
 	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
 
 	return 0;
@@ -225,6 +234,7 @@
  */
 static void irlpt_server_cleanup(void)
 {
+	struct irmanager_event mgr_event;
 	struct sk_buff *skb;
 
 	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
@@ -245,6 +255,10 @@
 	remove_proc_entry("irlpt_server", proc_irda);
 #endif
 
+        mgr_event.event = EVENT_IRLPT_STOP;
+        sprintf( mgr_event.devname, "%s", irlpt_server->ifname);
+        irmanager_notify( &mgr_event);
+ 
 	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
 }
 
@@ -304,6 +318,7 @@
 					 void *sap, 
 					 struct qos_info *qos,
 					 __u32 max_seg_size,
+					 __u8 max_header_size,
 					 struct sk_buff *skb)
 {
 	struct irlpt_cb *self;
@@ -314,6 +329,9 @@
 	ASSERT( self != NULL, return;);
 	ASSERT( self->magic == IRLPT_MAGIC, return;);
 
+	self->max_data_size = max_seg_size;
+	self->max_header_size = max_header_size;
+
 	self->connected = TRUE;
 
 	irlpt_server_do_event( self, LMP_CONNECT, NULL, NULL);
@@ -329,6 +347,7 @@
 					    void *sap, 
 					    struct qos_info *qos, 
 					    __u32 max_seg_size,
+					    __u8 max_header_size,
 					    struct sk_buff *skb)
 {
 	struct irlpt_cb *self;
@@ -343,14 +362,16 @@
 	ASSERT( self != NULL, return;);
 	ASSERT( self->magic == IRLPT_MAGIC, return;);
 
+	self->max_data_size = max_seg_size;
+	self->max_header_size = max_header_size;
+
 	self->connected = IRLPT_CONNECTED;
 	self->eof = FALSE;
 
 	irlpt_server_do_event( self, LMP_CONNECT, NULL, &info);
 
-	if (skb) {
+	if (skb)
 		dev_kfree_skb( skb);
-	}
 
 	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
 }
diff -u --recursive --new-file v2.2.9/linux/net/irda/irmod.c linux/net/irda/irmod.c
--- v2.2.9/linux/net/irda/irmod.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irmod.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:55:39 1997
- * Modified at:   Mon Apr 12 11:31:01 1999
+ * Modified at:   Fri May 14 13:46:02 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 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 
@@ -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 */
 
@@ -110,6 +110,7 @@
 EXPORT_SYMBOL(irttp_flow_request);
 EXPORT_SYMBOL(irttp_connect_request);
 EXPORT_SYMBOL(irttp_udata_request);
+EXPORT_SYMBOL(irttp_dup);
 
 /* Main IrDA module */
 #ifdef CONFIG_IRDA_DEBUG
@@ -151,6 +152,7 @@
 EXPORT_SYMBOL(irlmp_disconnect_request);
 EXPORT_SYMBOL(irlmp_get_daddr);
 EXPORT_SYMBOL(irlmp_get_saddr);
+EXPORT_SYMBOL(irlmp_dup);
 EXPORT_SYMBOL(lmp_reasons);
 
 /* Queue */
@@ -174,10 +176,15 @@
 EXPORT_SYMBOL(irda_device_setup);
 EXPORT_SYMBOL(irda_device_set_media_busy);
 EXPORT_SYMBOL(irda_device_txqueue_empty);
+
+EXPORT_SYMBOL(irda_device_init_dongle);
+EXPORT_SYMBOL(irda_device_register_dongle);
+EXPORT_SYMBOL(irda_device_unregister_dongle);
+
 EXPORT_SYMBOL(async_wrap_skb);
 EXPORT_SYMBOL(async_unwrap_char);
 EXPORT_SYMBOL(irda_start_timer);
-EXPORT_SYMBOL(irda_get_mtt);
+/* EXPORT_SYMBOL(irda_get_mtt); */
 EXPORT_SYMBOL(setup_dma);
 
 #ifdef CONFIG_IRTTY
@@ -505,19 +512,28 @@
 #endif
 }
 
-#ifdef MODULE
-#ifdef CONFIG_PROC_FS
+/*
+ * Function irda_proc_modcount (inode, fill)
+ *
+ *    Use by the proc file system functions to prevent the irda module
+ *    being removed while the use is standing in the net/irda directory
+ */
 void irda_proc_modcount(struct inode *inode, int fill)
 {
+#ifdef MODULE
+#ifdef CONFIG_PROC_FS
 	if (fill)
 		MOD_INC_USE_COUNT;
 	else
 		MOD_DEC_USE_COUNT;
-}
 #endif /* CONFIG_PROC_FS */
+#endif /* MODULE */
+}
+
+#ifdef MODULE
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("The Linux IrDA protocol subsystem"); 
+MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem"); 
 MODULE_PARM(irda_debug, "1l");
 
 /*
diff -u --recursive --new-file v2.2.9/linux/net/irda/irproc.c linux/net/irda/irproc.c
--- v2.2.9/linux/net/irda/irproc.c	Tue May 11 13:10:32 1999
+++ linux/net/irda/irproc.c	Sun May 30 10:17:04 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Thomas Davis, <ratbert@radiks.net>
  * Created at:    Sat Feb 21 21:33:24 1998
- * Modified at:   Tue Apr  6 19:07:06 1999
+ * Modified at:   Fri May  7 08:06:49 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>, 
+ *     Copyright (c) 1998-1999, Thomas Davis, <ratbert@radiks.net>, 
  *     All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
@@ -20,8 +20,6 @@
  *     I, Thomas Davis, provide no warranty for any of this software. 
  *     This material is provided "AS-IS" and at no charge. 
  *     
- *     Portions lifted from the linux/fs/procfs/ files.
- *
  ********************************************************************/
 
 #include <linux/miscdevice.h>
@@ -44,28 +42,27 @@
 			   int unused);
 extern int discovery_proc_read(char *buf, char **start, off_t offset, int len, 
 			       int unused);
+static int proc_discovery_read(char *buf, char **start, off_t offset, int len,
+			       int unused);
 
-enum irda_directory_inos {
-	PROC_IRDA_LAP = 1,
-	PROC_IRDA_LMP,
-	PROC_IRDA_TTP,
-	PROC_IRDA_LPT,
-	PROC_IRDA_COMM,
- 	PROC_IRDA_IRDA_DEVICE,
-	PROC_IRDA_IRIAS
-};
+/* enum irda_directory_inos { */
+/* 	PROC_IRDA_LAP = 1, */
+/* 	PROC_IRDA_LMP, */
+/* 	PROC_IRDA_TTP, */
+/* 	PROC_IRDA_LPT, */
+/* 	PROC_IRDA_COMM, */
+/*  	PROC_IRDA_IRDA_DEVICE, */
+/* 	PROC_IRDA_IRIAS */
+/* }; */
 
 struct irda_entry {
 	char *name;
-	int (*fn)(char*,char**,off_t,int,int);
+	int (*fn)(char*, char**, off_t, int, int);
 };
 
 struct proc_dir_entry *proc_irda;
-
+ 
 static struct irda_entry dir[] = {
-#if 0 
-	{"lpt", irlpt_proc_read},
-#endif
 	{"discovery",	discovery_proc_read},
 	{"irda_device",	irda_device_proc_read},
 	{"irttp",	irttp_proc_read},
@@ -75,19 +72,22 @@
 };
 
 #define IRDA_ENTRIES_NUM (sizeof(dir)/sizeof(dir[0]))
-
+ 
 /*
  * Function irda_proc_register (void)
  *
  *    Register irda entry in /proc file system
  *
  */
-void irda_proc_register(void) {
+void irda_proc_register(void) 
+{
 	int i;
+
 	proc_irda = create_proc_entry("net/irda", S_IFDIR, NULL);
 #ifdef MODULE
 	proc_irda->fill_inode = &irda_proc_modcount;
 #endif /* MODULE */
+
 	for (i=0;i<IRDA_ENTRIES_NUM;i++)
 		create_proc_entry(dir[i].name,0,proc_irda)->get_info=dir[i].fn;
 }
@@ -98,9 +98,14 @@
  *    Unregister irda entry in /proc file system
  *
  */
-void irda_proc_unregister(void) {
+void irda_proc_unregister(void) 
+{
 	int i;
+
 	for (i=0;i<IRDA_ENTRIES_NUM;i++)
 		remove_proc_entry(dir[i].name, proc_irda);
+
 	remove_proc_entry("net/irda", NULL);
 }
+
+
diff -u --recursive --new-file v2.2.9/linux/net/irda/irsysctl.c linux/net/irda/irsysctl.c
--- v2.2.9/linux/net/irda/irsysctl.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irsysctl.c	Sun May 30 10:17:04 1999
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      irsysctl.c
- * Version:       
- * Description:   
+ * Version:       1.0
+ * Description:   Sysctl interface for IrDA
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 24 22:12:06 1998
- * Modified at:   Fri Apr 23 09:46:38 1999
+ * Modified at:   Thu May  6 21:32:46 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 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 
diff -u --recursive --new-file v2.2.9/linux/net/irda/irttp.c linux/net/irda/irttp.c
--- v2.2.9/linux/net/irda/irttp.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irttp.c	Mon Jun  7 16:19:59 1999
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Sat Apr 10 10:32:21 1999
+ * Modified at:   Mon May 31 10:29:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -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,19 +44,20 @@
 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,
-				     struct sk_buff *skb);
-
+				     __u8 header_size, struct sk_buff *skb);
+static void irttp_connect_confirm(void *instance, void *sap, 
+				  struct qos_info *qos, __u32 max_sdu_size, 
+				  __u8 header_size, struct sk_buff *skb);
 static void irttp_run_tx_queue(struct tsap_cb *self);
 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)
@@ -296,7 +297,7 @@
 
 	/* 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;
 	}
 
@@ -305,8 +306,8 @@
 	 *  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;
 	}
 
@@ -318,8 +319,8 @@
 	    (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;
 	}
 	/* 
@@ -337,10 +338,10 @@
 	/* Queue frame, or queue frame segments */
 	if ((self->tx_max_sdu_size == 0) || (skb->len < self->max_seg_size)) {
 		/* Queue frame */
+		ASSERT(skb_headroom(skb) >= TTP_HEADER, return -1;);
 		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 {
 		/*
@@ -360,8 +361,8 @@
 		self->tx_sdu_busy = TRUE;
 		
 	 	if (self->notify.flow_indication) {
- 			self->notify.flow_indication(
-				self->notify.instance, self, FLOW_STOP);
+ 			self->notify.flow_indication(self->notify.instance, 
+						     self, FLOW_STOP);
 		}
  	}
 	
@@ -381,12 +382,8 @@
 {
 	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;
 
@@ -421,12 +418,7 @@
 		 *  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++;
@@ -434,12 +426,12 @@
 		/* 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);
 		}
 	}
@@ -472,7 +464,7 @@
 		return;
 
 	/* Reserve space for LMP, and LAP header */
-	skb_reserve(tx_skb, LMP_HEADER+LAP_HEADER);
+	skb_reserve(tx_skb, self->max_header_size);
 
 	/*
 	 *  Since we can transmit and receive frames concurrently, 
@@ -538,23 +530,14 @@
 				 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++;
 
@@ -562,10 +545,9 @@
 	 *  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--;
@@ -655,15 +637,14 @@
 			return -ENOMEM;
 		
 		/* Reserve space for MUX_CONTROL and LAP header */
-		skb_reserve(skb, (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER));
+		skb_reserve(skb, TTP_MAX_HEADER);
 	} else {
 		skb = userdata;
 		/*  
 		 *  Check that the client has reserved enough space for 
 		 *  headers
 		 */
-		ASSERT(skb_headroom(userdata) >= 
-		       (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return -1;);
+		ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER, return -1;);
 	}
 
 	/* Initialize connection parameters */
@@ -691,12 +672,11 @@
 
 	/* SAR enabled? */
 	if (max_sdu_size > 0) {
-		ASSERT(skb_headroom(skb) >= 
-			(TTP_HEADER_WITH_SAR+LMP_CONTROL_HEADER+LAP_HEADER), 
-			return -1;);
+		ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), 
+		       return -1;);
 
 		/* Insert SAR parameters */
-		frame = skb_push(skb, TTP_HEADER_WITH_SAR);
+		frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER);
 		
 		frame[0] = TTP_PARAMETERS | n; 
 		frame[1] = 0x04; /* Length */
@@ -724,8 +704,10 @@
  *    Sevice user confirms TSAP connection with peer. 
  *
  */
-void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos,
-			   __u32 max_seg_size, struct sk_buff *skb) 
+static void irttp_connect_confirm(void *instance, void *sap, 
+				  struct qos_info *qos,
+				  __u32 max_seg_size, __u8 max_header_size,
+				  struct sk_buff *skb) 
 {
 	struct tsap_cb *self;
 	int parameters;
@@ -741,7 +723,8 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 	ASSERT(skb != NULL, return;);
 
-	self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER;
+	self->max_seg_size = max_seg_size;
+	self->max_header_size = max_header_size + TTP_HEADER;
 
 	/*
 	 *  Check if we have got some QoS parameters back! This should be the
@@ -764,6 +747,10 @@
 	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];
@@ -789,17 +776,19 @@
 
 		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, 
-					     skb);
+		self->notify.connect_confirm(self->notify.instance, self, qos,
+					     self->tx_max_sdu_size, 
+					     self->max_header_size, skb);
 	}
 }
 
@@ -809,8 +798,8 @@
  *    Some other device is connecting to this TSAP
  *
  */
-void irttp_connect_indication(void *instance, void *sap, 
-			      struct qos_info *qos, __u32 max_seg_size, 
+void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
+			      __u32 max_seg_size, __u8 max_header_size, 
 			      struct sk_buff *skb) 
 {
 	struct tsap_cb *self;
@@ -828,7 +817,9 @@
 
 	lsap = (struct lsap_cb *) sap;
 
-	self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER;
+	self->max_seg_size = max_seg_size;
+
+	self->max_header_size = max_header_size+TTP_HEADER;
 
 	DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
 
@@ -841,7 +832,11 @@
 	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];
@@ -850,7 +845,7 @@
 
 		switch (pl) {
 		case 1:
-			self->tx_max_sdu_size = *(frame+4);
+			self->tx_max_sdu_size = frame[4];
 			break;
 		case 2:
 			self->tx_max_sdu_size = 
@@ -865,7 +860,10 @@
 			       "() 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);
@@ -873,12 +871,10 @@
 
 	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, 
-						skb);
+						self->max_header_size, skb);
 	}
 }
 
@@ -909,15 +905,14 @@
 			return;
 
 		/* Reserve space for MUX_CONTROL and LAP header */
-		skb_reserve(skb, (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER));
+		skb_reserve(skb, TTP_MAX_HEADER);
 	} else {
 		skb = userdata;
 		/*  
 		 *  Check that the client has reserved enough space for 
 		 *  headers
 		 */
-		ASSERT(skb_headroom(skb) >= 
-			(TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return;);
+		ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return;);
 	}
 	
 	self->avail_credit = 0;
@@ -939,12 +934,11 @@
 
 	/* SAR enabled? */
 	if (max_sdu_size > 0) {
-		ASSERT(skb_headroom(skb) >= 
-		       (TTP_HEADER_WITH_SAR+LMP_CONTROL_HEADER+LAP_HEADER), 
+		ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER), 
 		       return;);
 		
 		/* Insert TTP header with SAR parameters */
-		frame = skb_push(skb, TTP_HEADER_WITH_SAR);
+		frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER);
 		
 		frame[0] = TTP_PARAMETERS | n;
 		frame[1] = 0x04; /* Length */
@@ -1079,7 +1073,7 @@
 		/* 
 		 *  Reserve space for MUX and LAP header 
 		 */
-		skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+		skb_reserve(skb, TTP_MAX_HEADER);
 		
 		userdata = skb;
 	}
@@ -1357,13 +1351,11 @@
 		}
 		
 		/* Make new segment */
-		frag = dev_alloc_skb(self->max_seg_size+
-				      TTP_HEADER+LMP_HEADER+
-				      LAP_HEADER);
+		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
 		if (!frag)
 			return;
 
-		skb_reserve(frag, LMP_HEADER+LAP_HEADER);
+		skb_reserve(frag, self->max_header_size);
 
 		/*
 		 *  Copy data from the original skb into this fragment. We
@@ -1401,11 +1393,9 @@
 	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);
 	}
 
diff -u --recursive --new-file v2.2.9/linux/net/irda/qos.c linux/net/irda/qos.c
--- v2.2.9/linux/net/irda/qos.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/qos.c	Sun May 30 10:17:04 1999
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Sep  9 00:00:26 1997
- * Modified at:   Mon Apr 12 11:49:24 1999
+ * Modified at:   Mon May  3 21:15:08 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 <dagb@cs.uit.no>, 
+ *     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 
@@ -52,10 +53,10 @@
  *    Compute the intersection of the old QoS capabilites with new ones
  *
  */
-void irda_qos_compute_intersection( struct qos_info *qos, struct qos_info *new)
+void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
 {
-	ASSERT( qos != NULL, return;);
-	ASSERT( new != NULL, return;);
+	ASSERT(qos != NULL, return;);
+	ASSERT(new != NULL, return;);
 
 	/* Apply */
 	qos->baud_rate.bits       &= new->baud_rate.bits;
diff -u --recursive --new-file v2.2.9/linux/net/irda/wrapper.c linux/net/irda/wrapper.c
--- v2.2.9/linux/net/irda/wrapper.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/wrapper.c	Mon Jun  7 16:19:59 1999
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      wrapper.c
- * Version:       1.1
- * Description:   SIR wrapper layer
+ * Version:       1.2
+ * Description:   IrDA SIR async wrapper layer
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Wed Apr 21 12:45:55 1999
+ * Modified at:   Fri May 28 20:30:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -34,7 +34,20 @@
 #include <net/irda/irlap_frame.h>
 #include <net/irda/irda_device.h>
 
-inline static int stuff_byte(__u8 byte, __u8 *buf);
+static inline int stuff_byte(__u8 byte, __u8 *buf);
+
+static void state_outside_frame(struct irda_device *idev, __u8 byte);
+static void state_begin_frame(struct irda_device *idev, __u8 byte);
+static void state_link_escape(struct irda_device *idev, __u8 byte);
+static void state_inside_frame(struct irda_device *idev, __u8 byte);
+
+static void (*state[])(struct irda_device *idev, __u8 byte) = 
+{ 
+	state_outside_frame,
+	state_begin_frame,
+	state_link_escape,
+	state_inside_frame,
+};
 
 /*
  * Function async_wrap (skb, *tx_buff)
@@ -52,8 +65,6 @@
 		__u8 bytes[2];
 	} fcs;
 
-	ASSERT(skb != NULL, return 0;);
-
 	/* Initialize variables */
 	fcs.value = INIT_FCS;
 	n = 0;
@@ -74,13 +85,9 @@
 	} else
 		xbofs = ((struct irlap_skb_cb *)(skb->cb))->xbofs;
 
-#if 0
- 	for (i=0; i<xbofs; i++)
-  		tx_buff[n++] = XBOF;
-#else
 	memset(tx_buff+n, XBOF, xbofs);
 	n += xbofs;
-#endif
+
 	/* Start of packet character BOF */
 	tx_buff[n++] = BOF;
 
@@ -94,7 +101,7 @@
 		ASSERT(n < (buffsize-5), return n;);
 
 		n += stuff_byte(skb->data[i], tx_buff+n);
-		fcs.value = IR_FCS(fcs.value, skb->data[i]);
+		fcs.value = irda_fcs(fcs.value, skb->data[i]);
 	}
 	
 	/* Insert CRC in little endian format (LSB first) */
@@ -108,15 +115,6 @@
 #endif
 	tx_buff[n++] = EOF;
 
-#if 0
-	{
-		int i;
-		
-		for (i=0;i<n;i++)
-			printk("%02x", tx_buff[i]);
-		printk("\n");
-	}
-#endif
 	return n;
 }
 
@@ -155,147 +153,13 @@
 }
 
 /*
- * Function async_unwrap (skb)
- *
- *    Parse and de-stuff frame received from the IR-port
- *
- */
-void async_unwrap_char(struct irda_device *idev, __u8 byte) 
-{
-	/* State machine for receiving frames */	   
-	switch (idev->rx_buff.state) {
-	case OUTSIDE_FRAME:
-		switch(byte) {
-		case BOF:
-			idev->rx_buff.state = BEGIN_FRAME;
-			idev->rx_buff.in_frame = TRUE;
-			break;
-		case XBOF:
-			/* idev->xbofs++; */
-			break;
-		case EOF:
-			irda_device_set_media_busy( idev, TRUE);
-			break;
-		default:
-			break;
-		}
-		break;
-	case BEGIN_FRAME:
-		switch (byte) {
-		case BOF:
-			/* Continue */
-			break;
-		case CE:
-			/* Stuffed byte */
-			idev->rx_buff.state = LINK_ESCAPE;
-			break;
-		case EOF:
-			/* Abort frame */
-			idev->rx_buff.state = OUTSIDE_FRAME;
-
-			idev->stats.rx_errors++;
-			idev->stats.rx_frame_errors++;
-			break;
-		default:
-			/* Got first byte of frame */
-			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 = IR_FCS(INIT_FCS, byte);
-			idev->rx_buff.state = INSIDE_FRAME;
-			break;
-		}
-		break;
-	case LINK_ESCAPE:
-		switch (byte) {
-		case BOF:
-			/* New frame? */
-			idev->rx_buff.state = BEGIN_FRAME;
-			irda_device_set_media_busy(idev, TRUE);
-			break;
-		case CE:
-			DEBUG(4, "WARNING: State not defined\n");
-			break;
-		case EOF:
-			/* Abort frame */
-			idev->rx_buff.state = OUTSIDE_FRAME;
-			break;
-		default:
-			/* 
-			 *  Stuffed char, complement bit 5 of byte 
-			 *  following CE, IrLAP p.114 
-			 */
-			byte ^= IR_TRANS;
-			if (idev->rx_buff.len < idev->rx_buff.truesize)  {
-				idev->rx_buff.data[idev->rx_buff.len++] = byte;
-				idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs,
-							   byte);
-				idev->rx_buff.state = INSIDE_FRAME;
-			} else {
-				DEBUG(1, __FUNCTION__ 
-				       "(), Rx buffer overflow, aborting\n");
-				idev->rx_buff.state = OUTSIDE_FRAME;
-			}
-			break;
-		}
-		break;
-	case INSIDE_FRAME:
-		switch (byte) {
-		case BOF:
-			/* New frame? */
-			idev->rx_buff.state = BEGIN_FRAME;
-			irda_device_set_media_busy(idev, TRUE);
-			break;
-		case CE:
-			/* Stuffed char */
-			idev->rx_buff.state = LINK_ESCAPE;
-			break;
-		case EOF:
-			/* End of frame */
-			idev->rx_buff.state = OUTSIDE_FRAME;
-			idev->rx_buff.in_frame = FALSE;
-			
-			/* 
-			 *  Test FCS and deliver frame if it's good
-			 */			
-			if (idev->rx_buff.fcs == GOOD_FCS) {
-				async_bump(idev, idev->rx_buff.data, 
-					   idev->rx_buff.len);
-			} else {
-				/* Wrong CRC, discard frame!  */
-				irda_device_set_media_busy(idev, TRUE); 
-
-				idev->stats.rx_errors++;
-				idev->stats.rx_crc_errors++;
-			}			
-			break;
-		default:
-			/* Next byte of frame */
-			if (idev->rx_buff.len < idev->rx_buff.truesize)  {
-				idev->rx_buff.data[idev->rx_buff.len++] = byte;
-				idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs,
-							   byte);
-			} else {
-				DEBUG(1, __FUNCTION__ 
-				      "(), Rx buffer overflow, aborting\n");
-				idev->rx_buff.state = OUTSIDE_FRAME;
-			}
-			break;
-		}
-		break;
-	}
-}
- 
-/*
  * Function stuff_byte (byte, buf)
  *
  *    Byte stuff one single byte and put the result in buffer pointed to by
  *    buf. The buffer must at all times be able to have two bytes inserted.
  * 
  */
-inline static int stuff_byte(__u8 byte, __u8 *buf) 
+static inline int stuff_byte(__u8 byte, __u8 *buf) 
 {
 	switch (byte) {
 	case BOF: /* FALLTHROUGH */
@@ -303,7 +167,7 @@
 	case CE:
 		/* Insert transparently coded */
 		buf[0] = CE;               /* Send link escape */
-		buf[1] = byte^IR_TRANS;    /* Complement bit 5 */
+		buf[1] = byte^IRDA_TRANS;    /* Complement bit 5 */
 		return 2;
 		/* break; */
 	default:
@@ -313,7 +177,163 @@
 		/* break; */
 	}
 }
+
+/*
+ * Function async_unwrap (skb)
+ *
+ *    Parse and de-stuff frame received from the IrDA-port
+ *
+ */
+inline void async_unwrap_char(struct irda_device *idev, __u8 byte)
+{
+	(*state[idev->rx_buff.state]) (idev, byte);
+}
 	 
+/*
+ * Function state_outside_frame (idev, byte)
+ *
+ *    
+ *
+ */
+static void state_outside_frame(struct irda_device *idev, __u8 byte)
+{
+	switch (byte) {
+	case BOF:
+		idev->rx_buff.state = BEGIN_FRAME;
+		idev->rx_buff.in_frame = TRUE;
+		break;
+	case XBOF:
+		/* idev->xbofs++; */
+		break;
+	case EOF:
+		irda_device_set_media_busy( idev, TRUE);
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Function state_begin_frame (idev, byte)
+ *
+ *    Begin of frame detected
+ *
+ */
+static void state_begin_frame(struct irda_device *idev, __u8 byte)
+{
+	switch (byte) {
+	case BOF:
+		/* Continue */
+		break;
+	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 */
+		idev->rx_buff.state = OUTSIDE_FRAME;
+		
+		idev->stats.rx_errors++;
+		idev->stats.rx_frame_errors++;
+		break;
+	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);
+		idev->rx_buff.state = INSIDE_FRAME;
+		break;
+	}
+}
 
+/*
+ * Function state_link_escape (idev, byte)
+ *
+ *    
+ *
+ */
+static void state_link_escape(struct irda_device *idev, __u8 byte)
+{
+	switch (byte) {
+	case BOF: /* New frame? */
+		idev->rx_buff.state = BEGIN_FRAME;
+		irda_device_set_media_busy(idev, TRUE);
+		break;
+	case CE:
+		DEBUG(4, "WARNING: State not defined\n");
+		break;
+	case EOF: /* Abort frame */
+		idev->rx_buff.state = OUTSIDE_FRAME;
+		break;
+	default:
+		/* 
+		 *  Stuffed char, complement bit 5 of byte 
+		 *  following CE, IrLAP p.114 
+		 */
+		byte ^= IRDA_TRANS;
+		if (idev->rx_buff.len < idev->rx_buff.truesize)  {
+			idev->rx_buff.data[idev->rx_buff.len++] = byte;
+			idev->rx_buff.fcs = irda_fcs(idev->rx_buff.fcs, byte);
+			idev->rx_buff.state = INSIDE_FRAME;
+		} else {
+			DEBUG(1, __FUNCTION__ 
+			      "(), Rx buffer overflow, aborting\n");
+			idev->rx_buff.state = OUTSIDE_FRAME;
+		}
+		break;
+	}
+}
+
+/*
+ * Function state_inside_frame (idev, byte)
+ *
+ *    Handle bytes received within a frame
+ *
+ */
+static void state_inside_frame(struct irda_device *idev, __u8 byte)
+{
+	switch (byte) {
+	case BOF: /* New frame? */
+		idev->rx_buff.state = BEGIN_FRAME;
+		irda_device_set_media_busy(idev, TRUE);
+		break;
+	case CE: /* Stuffed char */
+		idev->rx_buff.state = LINK_ESCAPE;
+		break;
+	case EOF: /* End of frame */
+		idev->rx_buff.state = OUTSIDE_FRAME;
+		idev->rx_buff.in_frame = FALSE;
+		
+		/* Test FCS and deliver frame if it's good */
+		if (idev->rx_buff.fcs == GOOD_FCS) {
+			async_bump(idev, idev->rx_buff.data, 
+				   idev->rx_buff.len);
+		} else {
+			/* Wrong CRC, discard frame!  */
+			irda_device_set_media_busy(idev, TRUE); 
+			
+			idev->stats.rx_errors++;
+			idev->stats.rx_crc_errors++;
+		}			
+		break;
+	default: /* Must be the next byte of the frame */
+		if (idev->rx_buff.len < idev->rx_buff.truesize)  {
+			idev->rx_buff.data[idev->rx_buff.len++] = byte;
+			idev->rx_buff.fcs = irda_fcs(idev->rx_buff.fcs, byte);
+		} else {
+			DEBUG(1, __FUNCTION__ 
+			      "(), Rx buffer overflow, aborting\n");
+			idev->rx_buff.state = OUTSIDE_FRAME;
+		}
+		break;
+	}
+}
 
 
diff -u --recursive --new-file v2.2.9/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.2.9/linux/net/netlink/af_netlink.c	Fri Apr 16 14:47:31 1999
+++ linux/net/netlink/af_netlink.c	Wed Jun  2 11:29:28 1999
@@ -1,7 +1,7 @@
 /*
  * NETLINK      Kernel-user communication protocol.
  *
- * 		Authors:	Alan Cox <alan@cymru.net>
+ * 		Authors:	Alan Cox <alan@redhat.com>
  * 				Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  *
  *		This program is free software; you can redistribute it and/or
@@ -203,7 +203,7 @@
 	 */
 
 	while (netlink_locked(sk)) {
-		current->counter = 0;
+		current->policy |= SCHED_YIELD;
 		schedule();
 	}
 
diff -u --recursive --new-file v2.2.9/linux/net/netlink/netlink_dev.c linux/net/netlink/netlink_dev.c
--- v2.2.9/linux/net/netlink/netlink_dev.c	Sat Sep  5 16:46:42 1998
+++ linux/net/netlink/netlink_dev.c	Wed Jun  2 11:29:28 1999
@@ -2,7 +2,7 @@
  * NETLINK	An implementation of a loadable kernel mode driver providing
  *		multiple kernel/user space bidirectional communications links.
  *
- * 		Author: 	Alan Cox <alan@cymru.net>
+ * 		Author: 	Alan Cox <alan@redhat.com>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
