## Automatically generated incremental diff
## From:   linux-2.2.15-pre2
## To:     linux-2.2.15-pre3
## Robot:  $Id: make-incremental-diff,v 1.7 2001/12/04 05:19:54 hpa Exp $

diff -urN linux-2.2.15-pre2/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.15-pre2/Documentation/Configure.help	Mon Dec  3 21:57:48 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 21:57:53 2001
@@ -7539,11 +7539,11 @@
   If you don't know whether you need it, then you don't need it:
   answer N.
 
-QNX filesystem support (EXPERIMENTAL)
+QNX4 filesystem support (EXPERIMENTAL)
 CONFIG_QNX4FS_FS  
   This is the filesystem used by the operating system QNX 4. Say Y if
   you intend to mount QNX hard disks or floppies. Unless you say Y to
-  "QNXFS read-write support" below, you will only be able to read
+  "QNX4FS write support" below, you will only be able to read
   these filesystems.
 
   This filesystem support is also available as a module ( = code which
@@ -7551,11 +7551,12 @@
   want). The module is called qnx4.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt. 
 
-  If unsure, say N.
+  If you don't know whether you need it, then you don't need it:
+  answer N.
 
-QNXFS read-write support (FOR TESTING ONLY)
+QNX4FS write support (DANGEROUS)
 CONFIG_QNX4FS_RW
-  Say Y if you want to test write support for QNX filesystems.
+  Say Y if you want to test write support for QNX4 filesystems.
 
 Kernel automounter support
 CONFIG_AUTOFS_FS
@@ -8365,6 +8366,37 @@
   on, it will always be RTS. Read the file Documentation/specialix.txt
   for more information.
 
+Specialix SX card support
+CONFIG_SX
+  This is a driver for the Specialix SX multiport card (both the
+  ISA and the PCI version of both the older SI/XIO and the newer SX
+  variants of the card) which gives you many serial ports. You
+  would need something like this to connect more than two modems to 
+  your Linux box, for instance in order to become a dial-in server.
+  You will also need the specialix_sxtools package to be able to 
+  initialize and use the SX system. This driver does NOT support 
+  the rev 1 cards (+/- 1990), or the EISA version of the card. Sorry.
+
+  If you have one of these cards, say Y here and read the file
+  Documentation/sx.txt. Also it's possible to say M here and
+  compile this driver as kernel loadable module which will be called
+  sx.o.
+
+Specialix RIO system support
+CONFIG_RIO
+  This is a driver for the Specialix RIO hostcard (both the
+  ISA and the PCI versions of the card). This hostcard allows you
+  to connect many remote terminal adapters, each supporting 8 or 16
+  serial ports. These cards are ideal if you have more than 100 
+  terminals that need to be connected to your server. (But don't 
+  worry if you have only 32 ports.... That works too). You will 
+  also need the specialix_riotools to be able to initialize and
+  configure your rio system.  
+
+  If you have one of these cards, say Y here. Also it's possible to 
+  say M here and compile this driver as kernel loadable module which 
+  will be called rio.o.
+
 Cyclades async mux support
 CONFIG_CYCLADES
   This is a driver for a card that gives you many serial ports. You
@@ -11739,33 +11771,7 @@
   and makes it possible to use all existing applications that
   understands TTY's with an infrared link. Thus you should be able to
   use application like PPP, minicom and others. Enabling this option
-  will create two modules called ircomm and ircomm_tty. For more
-  information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/
-
-IrLPT Protocol
-CONFIG_IRLPT
-  Say Y here if you want to build support for the IrLPT protocol. If
-  you want to compile it as a module, say M here and read
-  Documentation/modules.txt. IrLPT makes it possible to print
-  documents to IrDA capable printers.
-
-IrLPT Client Protocol 
-CONFIG_IRLPT_CLIENT
-  Say Y here if you want to build support for the IrLPT client
-  protocol. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt. The IrLPT client protocol can be used to
-  print documents to IrDA compatible printers like the HP-5MP, or
-  IrLPT printer adapters like the ACTiSYS IR-100M.
-
-IrLPT Server Protocol 
-CONFIG_IRLPT_SERVER
-  Say Y here if you want to build support for the IrLPT server
-  protocol. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt. The IrLPT server protocol makes it
-  possible to use a Linux machine as an infrared printer server for
-  other laptops. So if your Linux machine has a cable connection to a
-  printer, then other laptops can use the Linux machine to print out 
-  documents using infrared communication.
+  will create two modules called ircomm and ircomm-tty.
 
 IrTTY IrDA Device Driver
 CONFIG_IRTTY_SIR
@@ -11802,20 +11808,12 @@
   used for the IrDA chipset in the Corel NetWinder. The driver
   supports SIR, MIR and FIR (4Mbps) speeds.
 
-NSC PC87108 IrDA Device Driver
+NSC IrDA Device Driver
 CONFIG_NSC_FIR
-  Say Y here if you want to build support for the NSC PC87108 IrDA
-  chipset. If you want to compile it as a module, say M here and
-  read Documentation/modules.txt. This drivers currently only supports
-  the ACTiSYS IR2000B ISA card and supports SIR, MIR and FIR (4Mbps)
-  speeds.
-
-Sharp UIRCC IrDA Device Driver
-CONFIG_SHARP_FIR
-  Say Y here if you want to build support for the Sharp UIRCC IrDA
-  chipset. If you want to compile it as a module, say M here and
-  read Documentation/modules.txt. This chipset is used by the Toshiba
-  Tecra laptops.
+  Say Y here if you want to build support for the NSC PC87108 and
+  PC87338 IrDA chipsets. If you want to compile it as a module, say M 
+  here and read Documentation/modules.txt. This driver supports SIR, 
+  MIR and FIR (4Mbps) speeds.
 
 Toshiba Type-O IR Port Device Driver
 CONFIG_TOSHIBA_FIR
@@ -11831,7 +11829,7 @@
   and read Documentation/modules.txt. The ESI dongle attaches to the
   normal 9-pin serial port connector, and can currently only be used
   by IrTTY. To activate support for ESI dongles you will have to
-  insert "irattach -d esi" in the /etc/irda/drivers script.
+  start irattach like this: "irattach -d esi".
 
 ACTiSYS IR-220L and IR220L+ dongle
 CONFIG_ACTISYS_DONGLE
@@ -11840,8 +11838,8 @@
   say M here and read Documentation/modules.txt. The ACTiSYS dongles
   attaches to the normal 9-pin serial port connector, and can
   currently only be used by IrTTY. To activate support for ACTiSYS
-  dongles you will have to insert "irattach -d actisys" or
-  "irattach -d actisys_plus" in the/etc/irda/drivers script.
+  dongles you will have to start irattach like this: 
+  "irattach -d actisys" or "irattach -d actisys+".
 
 Tekram IrMate 210B dongle
 CONFIG_TEKRAM_DONGLE
@@ -11850,7 +11848,7 @@
   and read Documentation/modules.txt. The Tekram dongle attaches to
   the normal 9-pin serial port connector, and can currently only be
   used by IrTTY. To activate support for Tekram dongles you will have
-  to insert "irattach -d tekram" in the /etc/irda/drivers script.
+  to start irattach like this: "irattach -d tekram".
 
 Greenwich GIrBIL dongle
 CONFIG_GIRBIL_DONGLE
@@ -11868,7 +11866,19 @@
   Documentation/modules.txt. The Parallax dongle attaches to the
   normal 9-pin serial port connector, and can currently only be used
   by IrTTY. To activate support for Parallax dongles you will have to
-  insert "irattach -d litelink" in the /etc/irda/drivers script.
+  start irattach like this "irattach -d litelink".
+
+Old Belking dongle
+CONFIG_OLD_BELKING_DONGLE
+  Say Y here if you want to build support for the old Belkin SmartBeam
+  dongle. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The Belkin SmartBeam dongle (F5F500) come 
+  in two variants. The only way to distinguish those is to open the 
+  dongle and check the presence of a jumper (the jumper, on the new 
+  dongle, toggle between IrDA and ASK modes). This driver only support 
+  the old dongle. The old dongle is also limited to 9600 b/s (which is 
+  not very fun). To activate support for old Belkin dongles you will 
+  have to start irattach like this: "irattach -d old_dongle".
 
 VME (Motorola and BVM) support
 CONFIG_VME
@@ -12268,6 +12278,6 @@
 # LocalWords:  ACTiSYS Dongle dongle dongles esi actisys IrMate tekram BVM MVME
 # LocalWords:  BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu
 # LocalWords:  alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid
-# LocalWords:  QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
+# LocalWords:  QNX4FS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
 # LocalWords:  IrLPT UIRCC Tecra
 
diff -urN linux-2.2.15-pre2/MAINTAINERS linux/MAINTAINERS
--- linux-2.2.15-pre2/MAINTAINERS	Mon Dec  3 21:57:48 2001
+++ linux/MAINTAINERS	Mon Dec  3 21:57:53 2001
@@ -694,6 +694,13 @@
 L:	linux-ppp@vger.rutgers.edu
 S:	Maintained
 
+QNX4 FILESYSTEM
+P:	Anders Larsen
+M:	al@alarsen.net
+L:	linux-kernel@vger.rutgers.edu
+W:	http://www.alarsen.net/linux/qnx4fs/
+S:	Maintained
+
 REAL TIME CLOCK DRIVER
 P:	Paul Gortmaker
 M:	p_gortmaker@yahoo.com
diff -urN linux-2.2.15-pre2/Makefile linux/Makefile
--- linux-2.2.15-pre2/Makefile	Mon Dec  3 21:57:48 2001
+++ linux/Makefile	Mon Dec  3 21:57:53 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 15
-EXTRAVERSION = pre2
+EXTRAVERSION = pre3
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.15-pre2/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- linux-2.2.15-pre2/arch/alpha/mm/fault.c	Tue Jan  4 10:12:11 2000
+++ linux/arch/alpha/mm/fault.c	Mon Dec  3 21:57:53 2001
@@ -150,8 +150,10 @@
 	if ((fixup = search_exception_table(regs->pc)) != 0) {
 		unsigned long newpc;
 		newpc = fixup_exception(dpf_reg, fixup, regs->pc);
+#if 0
 		printk("%s: Exception at [<%lx>] (%lx)\n",
 		       current->comm, regs->pc, newpc);
+#endif
 		regs->pc = newpc;
 		goto out_unlock;
 	}
diff -urN linux-2.2.15-pre2/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- linux-2.2.15-pre2/arch/i386/kernel/smp.c	Tue Jan  4 10:12:11 2000
+++ linux/arch/i386/kernel/smp.c	Mon Dec  3 21:57:53 2001
@@ -795,6 +795,208 @@
 	return memory_start;
 }
 
+#ifdef CONFIG_X86_TSC
+/*
+ * TSC synchronization.
+ *
+ * We first check wether all CPUs have their TSC's synchronized,
+ * then we print a warning if not, and always resync.
+ */
+
+static atomic_t tsc_start_flag = ATOMIC_INIT(0);
+static atomic_t tsc_count_start = ATOMIC_INIT(0);
+static atomic_t tsc_count_stop = ATOMIC_INIT(0);
+static unsigned long long tsc_values[NR_CPUS] = { 0, };
+
+#define NR_LOOPS 5
+
+extern unsigned long fast_gettimeoffset_quotient;
+
+/*
+ * accurate 64-bit division, expanded to 32-bit divisions. Not terribly
+ * optimized but we need it at boot time only anyway.
+ *
+ * result == a / b
+ *        == (a1 + a2*(2^32)) / b
+ *        == a1/b + a2*(2^32/b)
+ *        == a1/b + a2*((2^32-1)/b) + a2/b + (a2*((2^32-1) % b))/b
+ *                    ^---- (this multiplication can overflow)
+ */
+
+unsigned long long div64 (unsigned long long a, unsigned long long b)
+{
+	unsigned int a1, a2, b0;
+	unsigned long long res;
+
+	if (b > 0x00000000ffffffffULL)
+		return 0;
+	if (!b)
+		panic("huh?\n");
+
+	b0 = (unsigned int) b;
+	a1 = ((unsigned int*)&a)[0];
+	a2 = ((unsigned int*)&a)[1];
+
+	res = a1/b0 +
+		(unsigned long long)a2 * (unsigned long long)(0xffffffff/b0) +
+		a2 / b0 +
+		(a2 * (0xffffffff % b0)) / b0;
+
+        return res;
+}
+
+
+static void __init synchronize_tsc_bp (void)
+{
+	int i;
+	unsigned long long t0;
+	unsigned long long sum, avg;
+	long long delta;
+	unsigned long one_usec;
+	int buggy = 0;
+
+	printk("checking TSC synchronization across CPUs: ");
+
+	one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2);
+	
+	atomic_set(&tsc_start_flag, 1);
+	wmb();
+
+	/*
+	 * We loop a few times to get a primed instruction cache,
+	 * then the last pass is more or less synchronized and
+	 * the BP and APs set their cycle counters to zero all at
+	 * once. This reduces the chance of having random offsets
+	 * between the processors, and guarantees that the maximum
+	 * delay between the cycle counters is never bigger than
+	 * the latency of information-passing (cachelines) between
+	 * two CPUs.
+	 */
+	for (i = 0; i < NR_LOOPS; i++) {
+		/*
+		 * all APs synchronize but they loop on '== num_cpus'
+		 */
+		while (atomic_read(&tsc_count_start) != smp_num_cpus-1) mb();
+		atomic_set(&tsc_count_stop, 0);
+		wmb();
+		/*
+		 * this lets the APs save their current TSC:
+		 */
+		atomic_inc(&tsc_count_start);
+
+		rdtscll(tsc_values[smp_processor_id()]);
+		/*
+		 * We clear the TSC in the last loop:
+		 */
+		if (i == NR_LOOPS-1)
+			CLEAR_TSC;
+
+		/*
+		 * Wait for all APs to leave the synchronization point:
+		 */
+		while (atomic_read(&tsc_count_stop) != smp_num_cpus-1) mb();
+		atomic_set(&tsc_count_start, 0);
+		wmb();
+		atomic_inc(&tsc_count_stop);
+	}
+
+	sum = 0;
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!(cpu_online_map & (1 << i)))
+			continue;
+
+		t0 = tsc_values[i];
+		sum += t0;
+	}
+	avg = div64(sum, smp_num_cpus);
+
+	sum = 0;
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!(cpu_online_map & (1 << i)))
+			continue;
+
+		delta = tsc_values[i] - avg;
+		if (delta < 0)
+			delta = -delta;
+		/*
+		 * We report bigger than 2 microseconds clock differences.
+		 */
+		if (delta > 2*one_usec) {
+			long realdelta;
+			if (!buggy) {
+				buggy = 1;
+				printk("\n");
+			}
+			realdelta = div64(delta, one_usec);
+			if (tsc_values[i] < avg)
+				realdelta = -realdelta;
+		
+			printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n",
+				i, realdelta);
+		}
+				
+		sum += delta;
+	}
+	if (!buggy)
+		printk("passed.\n");
+
+#if 0
+	printk("CPU%d read locks\n", smp_processor_id());
+	read_lock_irq(&tasklist_lock);
+
+	printk("CPU%d delays 2 secs\n", smp_processor_id());
+	mdelay(1000);
+
+	printk("CPU%d does IRQ0 ...\n", smp_processor_id());
+	asm volatile ("int $0x51");
+
+	printk("CPU%d back from IRQ0 ???\n", smp_processor_id());
+	read_unlock(&tasklist_lock);
+#endif
+}
+
+static void __init synchronize_tsc_ap (void)
+{
+	int i;
+
+	/*
+	 * smp_num_cpus is not necessarily known at the time
+	 * this gets called, so we first wait for the BP to
+	 * finish SMP initialization:
+	 */
+	while (!atomic_read(&tsc_start_flag)) mb();
+
+	for (i = 0; i < NR_LOOPS; i++) {
+		atomic_inc(&tsc_count_start);
+		while (atomic_read(&tsc_count_start) != smp_num_cpus) mb();
+
+		rdtscll(tsc_values[smp_processor_id()]);
+		if (i == NR_LOOPS-1)
+			CLEAR_TSC;
+
+		atomic_inc(&tsc_count_stop);
+		while (atomic_read(&tsc_count_stop) != smp_num_cpus) mb();
+	}
+
+#if 0
+	printk("CPU%d clis\n", smp_processor_id());
+	cli();
+
+	printk("CPU%d delays 4 secs\n", smp_processor_id());
+	mdelay(4000);
+
+	printk("CPU%d does write_lock ...\n", smp_processor_id());
+	write_lock_irq(&tasklist_lock);
+
+	printk("CPU%d back from write lock???\n", smp_processor_id());
+	write_unlock_irq(&tasklist_lock);
+	sti();
+#endif
+}
+#undef NR_LOOPS
+
+#endif
+
 extern void calibrate_delay(void);
 
 void __init smp_callin(void)
@@ -880,6 +1082,13 @@
 	 *	Allow the master to continue.
 	 */
 	set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
+
+#ifdef CONFIG_X86_TSC
+	/*
+	 *	Synchronize the TSC with the BP
+	 */
+ 	synchronize_tsc_ap ();
+#endif
 }
 
 int cpucount = 0;
@@ -1401,7 +1610,9 @@
 		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
 	SMP_PRINTK(("Boot done.\n"));
 
+	ack_APIC_irq();
 	cache_APIC_registers();
+	ack_APIC_irq();
 #ifndef CONFIG_VISWS
 	/*
 	 * Here we can be sure that there is an IO-APIC in the system. Let's
@@ -1412,8 +1623,15 @@
 #endif
 
 smp_done:
-}
 
+#ifdef CONFIG_X86_TSC
+	/*
+	 * Synchronize the TSC with the AP
+	 */
+	if (cpucount)
+	 	synchronize_tsc_bp();
+#endif
+}
 
 /*
  * the following functions deal with sending IPIs between CPUs.
diff -urN linux-2.2.15-pre2/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- linux-2.2.15-pre2/arch/i386/kernel/time.c	Thu Apr 29 11:53:41 1999
+++ linux/arch/i386/kernel/time.c	Mon Dec  3 21:57:53 2001
@@ -74,7 +74,7 @@
  * Equal to 2^32 * (1 / (clocks per usec) ).
  * Initialized in time_init.
  */
-static unsigned long fast_gettimeoffset_quotient=0;
+unsigned long fast_gettimeoffset_quotient=0;
 
 extern rwlock_t xtime_lock;
 
diff -urN linux-2.2.15-pre2/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- linux-2.2.15-pre2/arch/sparc64/kernel/ioctl32.c	Tue Jan  4 10:12:13 2000
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 21:57:53 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.62.2.8 1999/11/16 23:59:31 davem Exp $
+/* $Id: ioctl32.c,v 1.62.2.9 2000/01/15 04:40:57 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -37,6 +37,7 @@
 #include <linux/ext2_fs.h>
 #include <linux/videodev.h>
 #include <linux/netdevice.h>
+#include <linux/smb_fs.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -1692,6 +1693,24 @@
 	return 0;
 }
 
+static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	__kernel_uid_t kuid;
+	int err;
+
+	cmd = SMB_IOC_GETMOUNTUID;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
+	set_fs(old_fs);
+
+	if (err >= 0)
+		err = put_user(kuid, (__kernel_uid_t32 *)arg);
+
+	return err;
+}
+
 asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct file * filp;
@@ -1878,6 +1897,11 @@
 		error = do_video_ioctl(fd, cmd, arg);
 		goto out;
 
+	/* One SMB ioctl needs translations. */
+	case _IOR('u', 1, __kernel_uid_t32): /* SMB_IOC_GETMOUNTUID */
+		error = do_smb_getmountuid(fd, cmd, arg);
+		goto out;
+
 	/* List here exlicitly which ioctl's are known to have
 	 * compatable types passed or none at all...
 	 */
@@ -2393,6 +2417,9 @@
 	/* Raw devices */
 	case _IO(0xac, 0): /* RAW_SETBIND */
 	case _IO(0xac, 1): /* RAW_GETBIND */
+
+	/* SMB ioctls which do not need any translations */
+	case SMB_IOC_NEWCONN:
 
 		error = sys_ioctl (fd, cmd, arg);
 		goto out;
diff -urN linux-2.2.15-pre2/drivers/char/Config.in linux/drivers/char/Config.in
--- linux-2.2.15-pre2/drivers/char/Config.in	Tue Jan  4 10:12:14 2000
+++ linux/drivers/char/Config.in	Mon Dec  3 21:57:53 2001
@@ -44,6 +44,7 @@
      bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
    fi 
    tristate 'Specialix SX (and SI) card support' CONFIG_SX
+   tristate 'Specialix RIO system support' CONFIG_RIO
    bool 'Stallion multiport serial support' CONFIG_STALDRV
    if [ "$CONFIG_STALDRV" = "y" ]; then
      tristate '  Stallion EasyIO or EC8/32 support' CONFIG_STALLION
diff -urN linux-2.2.15-pre2/drivers/char/Makefile linux/drivers/char/Makefile
--- linux-2.2.15-pre2/drivers/char/Makefile	Tue Jan  4 10:12:14 2000
+++ linux/drivers/char/Makefile	Mon Dec  3 21:57:53 2001
@@ -11,7 +11,7 @@
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) ftape joystick
+ALL_SUB_DIRS := $(SUB_DIRS) rio ftape joystick
 
 #
 # This file contains the font map for the default (hardware) font
@@ -202,7 +202,18 @@
 L_OBJS += sx.o generic_serial.o
 else
   ifeq ($(CONFIG_SX),m)
-  M_OBJS += sx.o
+  M_OBJS += sx.o  generic_serial.o
+  endif
+endif
+
+ifeq ($(CONFIG_RIO),y)
+L_OBJS += rio/rio.o  generic_serial.o
+SUB_DIRS += rio
+MOD_SUB_DIRS += rio
+else
+  ifeq ($(CONFIG_RIO),m)
+  M_OBJS += generic_serial.o
+  MOD_SUB_DIRS += rio
   endif
 endif
 
diff -urN linux-2.2.15-pre2/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c
--- linux-2.2.15-pre2/drivers/char/generic_serial.c	Wed Aug 25 17:29:47 1999
+++ linux/drivers/char/generic_serial.c	Mon Dec  3 21:57:53 2001
@@ -19,93 +19,11 @@
 #include <linux/mm.h>
 #include <asm/semaphore.h>
 #include <linux/version.h>
+#include <linux/module.h>
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
 
-
-#if LINUX_VERSION_CODE < 0x020100    /* Less than 2.1.0 */
-#define TWO_ZERO
-#else
-#if LINUX_VERSION_CODE < 0x020200   /* less than 2.2.x */
-#warning "Please use a 2.2.x kernel. "
-#else
-#if LINUX_VERSION_CODE < 0x020300   /* less than 2.2.x */
-#define TWO_TWO
-#else
-#define TWO_THREE
-#endif
-#endif
-#endif
-
-#ifdef TWO_ZERO
-
-/* Here is the section that makes the 2.2 compatible driver source 
-   work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, 
-   and provide for compatibility stuff here if possible. */
-
-/* Some 200 days (on intel) */
-#define MAX_SCHEDULE_TIMEOUT     ((long)(~0UL>>1))
-
-
-#ifndef MODULE
-
-#define copy_to_user(a,b,c)          memcpy_tofs(a,b,c)
-
-static inline int copy_from_user(void *to,const void *from, int c) 
-{
-	memcpy_fromfs(to, from, c);
-	return 0;
-}
-
-
-#define capable(x)                   suser()
-
-#define queue_task                   queue_task_irq_off
-#define tty_flip_buffer_push(tty)    queue_task(&tty->flip.tqueue, &tq_timer)
-#define signal_pending(current)      (current->signal & ~current->blocked)
-#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
-#define time_after(t1,t2)            (((long)t1-t2) > 0)
-
-#define test_and_set_bit(nr, addr)   set_bit(nr, addr)
-#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
-
-/* Not yet implemented on 2.0 */
-#define ASYNC_SPD_SHI  -1
-#define ASYNC_SPD_WARP -1
-
-
-
-/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
-   to the "name" field that does exist. As long as the assignments are
-   done in the right order, there is nothing to worry about. */
-#define driver_name           name 
-
-
-/* Should be in a header somewhere. */
-#define TTY_HW_COOK_OUT       14 /* Flag to tell ntty what we can handle */
-#define TTY_HW_COOK_IN        15 /* in hardware - output and input       */
-#endif
-
-#endif
-
-#ifndef TWO_ZERO
-/* This include is new with 2.2  (and required!) */
-#include <asm/uaccess.h>
-#endif
-
-#ifndef TWO_THREE
-/* These are new in 2.3. The source now uses 2.3 syntax, and here is 
-   the compatibility define... */
-#define wait_queue_head_t struct wait_queue *
-#define DECLARE_MUTEX(name) struct semaphore name = MUTEX
-#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL }
-
-#endif
-
-#include "generic_serial.h"
-
-
-#ifndef MODULE
-extern void my_hd (unsigned char *ptr, int n);
-#endif
+#define DEBUG 
 
 static char *                  tmp_buf; 
 static DECLARE_MUTEX(tmp_buf_sem);
@@ -119,8 +37,8 @@
 #define gs_dprintk(f, str...) /* nothing */
 #endif
 
-#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
-#define func_exit()  gs_dprintk (SX_DEBUG_FLOW, "gs: exit  " __FUNCTION__ "\n")
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
+#define func_exit()  gs_dprintk (GS_DEBUG_FLOW, "gs: exit  " __FUNCTION__ "\n")
 
 
 
@@ -135,6 +53,27 @@
 #endif
 
 
+#ifdef DEBUG
+static void my_hd (unsigned char *addr, int len)
+{
+	int i, j, ch;
+
+	for (i=0;i<len;i+=16) {
+		printk ("%08x ", (int) addr+i);
+		for (j=0;j<16;j++) {
+			printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+		}
+		for (j=0;j<16;j++) {
+			ch = addr[j+i];
+			printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+		}
+		printk ("\n");
+	}
+}
+#else
+#define my_hd(addr,len) 
+#endif
+
 
 void gs_put_char(struct tty_struct * tty, unsigned char ch)
 {
@@ -397,16 +336,19 @@
 	if (!tty) return 0;
 	port = tty->driver_data;
 
+	if (!port->rd) return 0;
+	if (!port->rd->chars_in_buffer) return 0;
+
 	func_exit ();
 	return port->xmit_cnt + port->rd->chars_in_buffer (port);
 }
 
 
-static void gs_wait_tx_flushed (void * ptr, int timeout) 
+static int gs_wait_tx_flushed (void * ptr, int timeout) 
 {
 	struct gs_port *port = ptr;
 	long end_jiffies;
-	int jiffies_to_transmit, charsleft;
+	int jiffies_to_transmit, charsleft = 0, rv = 0;
 	int to, rcib;
 
 	func_enter();
@@ -420,7 +362,7 @@
 	if (!port || port->xmit_cnt < 0 || !port->xmit_buf) {
 		gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n");
 	func_exit();
-		return;  /* This is an error which we don't know how to handle. */
+		return -EINVAL;  /* This is an error which we don't know how to handle. */
 	}
 	gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 1\n");
 
@@ -430,8 +372,8 @@
 
 	if(rcib <= 0) {
 		gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n");
-	func_exit();
-	return;
+		func_exit();
+		return rv;
 	}
 	gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 3\n");
 
@@ -464,14 +406,18 @@
 
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(jiffies_to_transmit);
-		if (signal_pending (current))
+		if (signal_pending (current)) {
+			gs_dprintk (GS_DEBUG_FLUSH, "Signal pending. Bombing out: "); 
+			rv = -EINTR;
 			break;
+		}
 	}
 
 	gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft); 
 	current->state = TASK_RUNNING;
 
 	func_exit();
+	return rv;
 }
 
 
@@ -750,8 +696,10 @@
 		func_exit();
 		return;
 	}
+
 	if (!port->tty) {
-		printk (KERN_WARNING "gs: Odd: port->tty is NULL\n");
+		/* This seems to happen when this is called from vhangup. */
+		gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->tty is NULL\n");
 		port->tty = tty;
 	}
 
@@ -775,6 +723,7 @@
 		port->count = 0;
 	}
 	if (port->count) {
+		gs_dprintk(GS_DEBUG_CLOSE, "gs_close: count: %d\n", port->count);
 		restore_flags(flags);
 		func_exit ();
 		return;
@@ -806,6 +755,7 @@
 
 	port->rd->disable_rx_interrupts (port);
 
+	/* close has no way of returning "EINTR", so discard return value */
 	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
 		gs_wait_tx_flushed (port, port->closing_wait); 
 
@@ -816,8 +766,12 @@
 	if (tty->ldisc.flush_buffer)
 		tty->ldisc.flush_buffer(tty);
 	tty->closing = 0;
+
 	port->event = 0;
+	port->rd->close (port);
+	port->rd->shutdown_port (port);
 	port->tty = 0;
+
 	if (port->blocked_open) {
 		if (port->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
@@ -829,8 +783,6 @@
 	                 ASYNC_CLOSING | ASYNC_INITIALIZED);
 	wake_up_interruptible(&port->close_wait);
 
-	port->rd->close (port);
-	port->rd->shutdown_port (port);
 	restore_flags(flags);
 	func_exit ();
 }
@@ -846,7 +798,7 @@
                      struct termios * old_termios)
 {
 	struct gs_port *port = tty->driver_data;
-	int baudrate, tmp;
+	int baudrate, tmp, rv;
 	struct termios *tiosp;
 
 	func_enter();
@@ -872,7 +824,7 @@
 		   && (tiosp->c_line  == old_termios->c_line)
 		   && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) {
 			gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n");
-			return;
+			return /* 0 */;
 		}
 	} else 
 		gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: "
@@ -928,9 +880,11 @@
 
 	/* We should really wait for the characters to be all sent before
 	   changing the settings. -- CAL */
-	gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT);
+	rv = gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT);
+	if (rv < 0) return /* rv */;
 
-	port->rd->set_real_termios(port);
+	rv = port->rd->set_real_termios(port);
+	if (rv < 0) return /* rv */;
 
 	if ((!old_termios || 
 	     (old_termios->c_cflag & CRTSCTS)) &&
@@ -948,7 +902,7 @@
 #endif
 
 	func_exit();
-	return;
+	return /* 0 */;
 }
 
 
@@ -1072,3 +1026,15 @@
 	copy_to_user(sp, &sio, sizeof(struct serial_struct));
 }
 
+
+#ifdef MODULE
+int init_module (void)
+{
+  return 0;
+}
+
+int cleanup_module (void)
+{
+  return 0;
+}
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/generic_serial.h linux/drivers/char/generic_serial.h
--- linux-2.2.15-pre2/drivers/char/generic_serial.h	Mon Aug  9 12:05:09 1999
+++ linux/drivers/char/generic_serial.h	Wed Dec 31 16:00:00 1969
@@ -1,101 +0,0 @@
-/*
- *  generic_serial.h
- *
- *  Copyright (C) 1998 R.E.Wolff@BitWizard.nl
- *
- *  written for the SX serial driver.
- *     Contains the code that should be shared over all the serial drivers.
- *
- *  Version 0.1 -- December, 1998.
- */
-
-#ifndef GENERIC_SERIAL_H
-#define GENERIC_SERIAL_H
-
-struct real_driver {
-  void                    (*disable_tx_interrupts) (void *);
-  void                    (*enable_tx_interrupts) (void *);
-  void                    (*disable_rx_interrupts) (void *);
-  void                    (*enable_rx_interrupts) (void *);
-  int                     (*get_CD) (void *);
-  void                    (*shutdown_port) (void*);
-  void                    (*set_real_termios) (void*);
-  int                     (*chars_in_buffer) (void*);
-  void                    (*close) (void*);
-  void                    (*hungup) (void*);
-  void                    (*getserial) (void*, struct serial_struct *sp);
-};
-
-
-
-struct gs_port {
-  int                     magic;
-  unsigned char           *xmit_buf; 
-  int                     xmit_head;
-  int                     xmit_tail;
-  int                     xmit_cnt;
-  /*  struct semaphore        port_write_sem; */
-  int                     flags;
-  struct termios          normal_termios;
-  struct termios          callout_termios;
-  wait_queue_head_t       open_wait;
-  wait_queue_head_t       close_wait;
-  long                    session;
-  long                    pgrp;
-  int                     count;
-  int                     blocked_open;
-  struct tty_struct       *tty;
-  int                     event;
-  unsigned short          closing_wait;
-  int                     close_delay;
-  struct real_driver      *rd;
-  int                     wakeup_chars;
-  int                     baud_base;
-  int                     baud;
-  int                     custom_divisor;
-};
-
-
-/* Flags */
-/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
-   used in serial.c, but they are also used in all other serial drivers. 
-   Make sure they don't clash with these here... */
-#define GS_TX_INTEN      0x00800000
-#define GS_RX_INTEN      0x00400000
-#define GS_ACTIVE        0x00200000
-
-
-
-#define GS_TYPE_NORMAL   1
-#define GS_TYPE_CALLOUT  2
-
-
-#define GS_DEBUG_FLUSH   0x00000001
-#define GS_DEBUG_BTR     0x00000002
-#define GS_DEBUG_TERMIOS 0x00000004
-#define GS_DEBUG_STUFF   0x00000008
-#define GS_DEBUG_CLOSE   0x00000010
-
-
-void gs_put_char(struct tty_struct *tty, unsigned char ch);
-int  gs_write(struct tty_struct *tty, int from_user, 
-             const unsigned char *buf, int count);
-int  gs_write_room(struct tty_struct *tty);
-int  gs_chars_in_buffer(struct tty_struct *tty);
-void gs_flush_buffer(struct tty_struct *tty);
-void gs_flush_chars(struct tty_struct *tty);
-void gs_stop(struct tty_struct *tty);
-void gs_start(struct tty_struct *tty);
-void gs_hangup(struct tty_struct *tty);
-void gs_do_softint(void *private_);
-int  block_til_ready(void *port, struct file *filp);
-void gs_close(struct tty_struct *tty, struct file *filp);
-void gs_set_termios (struct tty_struct * tty, 
-                     struct termios * old_termios);
-int  gs_init_port(struct gs_port *port);
-int  gs_setserial(struct gs_port *port, struct serial_struct *sp);
-void gs_getserial(struct gs_port *port, struct serial_struct *sp);
-
-extern int gs_debug;
-
-#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/Makefile linux/drivers/char/rio/Makefile
--- linux-2.2.15-pre2/drivers/char/rio/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/Makefile	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,22 @@
+#
+# Makefile for the linux rio-subsystem.
+#
+# (C) R.E.Wolff@BitWizard.nl 
+# 
+# This file is GPL. See other files for the full Blurb. I'm lazy today. 
+#
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := rio.o
+O_OBJS   := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \
+            rioparam.o riopcicopy.o rioroute.o riotable.o riotty.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+rio.o: $(O_OBJS)
\ No newline at end of file
diff -urN linux-2.2.15-pre2/drivers/char/rio/board.h linux/drivers/char/rio/board.h
--- linux-2.2.15-pre2/drivers/char/rio/board.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/board.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,143 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources. 
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: board.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:07
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)board.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_board_h__
+#define	__rio_board_h__
+
+#ifdef SCCS_LABELS
+static char *_board_h_sccs_ = "@(#)board.h	1.2";
+#endif
+
+/*
+** board.h contains the definitions for the *hardware* of the host cards.
+** It describes the memory overlay for the dual port RAM area.
+*/
+
+#define	DP_SRAM1_SIZE	0x7C00
+#define	DP_SRAM2_SIZE	0x0200
+#define	DP_SRAM3_SIZE	0x7000
+#define	DP_SCRATCH_SIZE	0x1000
+#define	DP_PARMMAP_ADDR	0x01FE	/* offset into SRAM2 */
+#define	DP_STARTUP_ADDR	0x01F8	/* offset into SRAM2 */
+
+/*
+**	The shape of the Host Control area, at offset 0x7C00, Write Only
+*/
+struct s_Ctrl
+{
+	BYTE	DpCtl;				/* 7C00 */
+	BYTE	Dp_Unused2_[127];
+	BYTE	DpIntSet;			/* 7C80 */
+	BYTE	Dp_Unused3_[127];
+	BYTE	DpTpuReset;			/* 7D00 */
+	BYTE	Dp_Unused4_[127];
+	BYTE	DpIntReset;			/* 7D80 */
+	BYTE	Dp_Unused5_[127];
+};
+
+/*
+** The PROM data area on the host (0x7C00), Read Only
+*/
+struct s_Prom
+{
+	WORD	DpSlxCode[2];
+	WORD	DpRev;
+	WORD	Dp_Unused6_;
+	WORD	DpUniq[4];
+	WORD	DpJahre;
+	WORD	DpWoche;
+	WORD	DpHwFeature[5];
+	WORD	DpOemId;
+	WORD	DpSiggy[16];
+};
+
+/*
+** Union of the Ctrl and Prom areas
+*/
+union u_CtrlProm	/* This is the control/PROM area (0x7C00) */
+{
+	struct s_Ctrl	DpCtrl;
+	struct s_Prom	DpProm;
+};
+
+/*
+** The top end of memory!
+*/
+struct s_ParmMapS		/* Area containing Parm Map Pointer */
+{
+	BYTE	Dp_Unused8_[DP_PARMMAP_ADDR];
+	WORD	DpParmMapAd;
+};
+
+struct s_StartUpS
+{
+	BYTE    Dp_Unused9_[DP_STARTUP_ADDR];
+	BYTE	Dp_LongJump[0x4];
+	BYTE	Dp_Unused10_[2];
+	BYTE	Dp_ShortJump[0x2];
+};
+
+union u_Sram2ParmMap	/* This is the top of memory (0x7E00-0x7FFF) */
+{
+	BYTE	DpSramMem[DP_SRAM2_SIZE];
+	struct s_ParmMapS DpParmMapS;
+	struct s_StartUpS DpStartUpS;
+};
+
+/*
+**	This is the DP RAM overlay.
+*/
+struct DpRam
+{
+    BYTE 		 DpSram1[DP_SRAM1_SIZE];     /* 0000 - 7BFF */
+    union u_CtrlProm     DpCtrlProm;                 /* 7C00 - 7DFF */
+    union u_Sram2ParmMap DpSram2ParmMap;             /* 7E00 - 7FFF */
+    BYTE		 DpScratch[DP_SCRATCH_SIZE]; /* 8000 - 8FFF */
+    BYTE		 DpSram3[DP_SRAM3_SIZE];     /* 9000 - FFFF */
+};
+
+#define	DpControl	DpCtrlProm.DpCtrl.DpCtl
+#define	DpSetInt	DpCtrlProm.DpCtrl.DpIntSet
+#define	DpResetTpu	DpCtrlProm.DpCtrl.DpTpuReset
+#define	DpResetInt	DpCtrlProm.DpCtrl.DpIntReset
+
+#define	DpSlx		DpCtrlProm.DpProm.DpSlxCode
+#define	DpRevision	DpCtrlProm.DpProm.DpRev
+#define	DpUnique	DpCtrlProm.DpProm.DpUniq
+#define	DpYear		DpCtrlProm.DpProm.DpJahre
+#define	DpWeek		DpCtrlProm.DpProm.DpWoche
+#define	DpSignature	DpCtrlProm.DpProm.DpSiggy
+
+#define	DpParmMapR	DpSram2ParmMap.DpParmMapS.DpParmMapAd
+#define	DpSram2		DpSram2ParmMap.DpSramMem
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/bootpkt.h linux/drivers/char/rio/bootpkt.h
--- linux-2.2.15-pre2/drivers/char/rio/bootpkt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/bootpkt.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,62 @@
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******        B O O T    P A C K E T   H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _pkt_h
+#define _pkt_h 1
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_bootpkt_h_sccs = "@(#)bootpkt.h	1.1" ;
+#endif
+#endif
+
+    /*************************************************
+     * Overlayed onto the Data fields of a regular
+     * Packet
+     ************************************************/
+typedef struct BOOT_PKT BOOT_PKT ;
+struct BOOT_PKT {
+                    short     seq_num ;
+                    char      data[10] ;
+                } ;
+
+
+#endif
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/brates.h linux/drivers/char/rio/brates.h
--- linux-2.2.15-pre2/drivers/char/rio/brates.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/brates.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,107 @@
+/****************************************************************************
+ *******                                                              *******
+ *******		BRATES.H				      *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    : 1 Nov 1990
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _brates_h
+#ifndef lint
+/* static char * _brates_h_sccs = "@(#)brates.h	1.4"; */
+#endif
+#define _brates_h 1
+/* List of baud rate defines. Most are borrowed from /usr/include/sys/termio.h
+*/
+#ifndef INKERNEL
+
+#define	B0	0x00
+#define	B50	0x01
+#define	B75	0x02
+#define	B110	0x03
+#define	B134	0x04
+#define	B150	0x05
+#define	B200	0x06
+#define	B300	0x07
+#define	B600	0x08
+#define	B1200	0x09
+#define	B1800	0x0a
+#define	B2400	0x0b
+#define	B4800	0x0c
+#define	B9600	0x0d
+#define	B19200	0x0e
+#define	B38400	0x0f
+
+#endif
+
+/*
+** The following baudrates may or may not be defined
+** on various UNIX systems.
+** If they are not then we define them.
+** If they are then we do not define them ;-)
+**
+** This is appalling that we use same definitions as UNIX
+** for our own download code as there is no garuntee that
+** B57600 will be defined as 0x11 by a UNIX system....
+** Arghhhhh!!!!!!!!!!!!!!
+*/
+#if !defined(B56000)
+#define	B56000	0x10
+#endif
+
+#if !defined(B57600)
+#define	B57600	0x11
+#endif
+
+#if !defined(B64000)
+#define	B64000	0x12
+#endif
+
+#if !defined(B115200)
+#define	B115200	0x13
+#endif
+
+
+#if !defined(B2000)
+#define B2000	0x14
+#endif
+
+
+#define MAX_RATE B2000
+
+struct    baud_rate            /* Tag for baud rates */
+{
+     /* short    host_rate,*/        /* As passed by the driver */
+     short    divisor,          /* The divisor */
+              prescaler;        /* The pre-scaler */
+};
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/cdproto.h linux/drivers/char/rio/cdproto.h
--- linux-2.2.15-pre2/drivers/char/rio/cdproto.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cdproto.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,55 @@
+/* 
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *
+ *      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.
+*/
+#ifndef _cirrusprots_h
+#define _cirrusprots_h
+
+#ifdef RTA
+extern void cd1400_reset ( int uart) ;
+extern void cd1400_init ( int uart ) ;
+extern void ccr_wait ( int priority, int port) ;
+extern void cd1400_txstart( int port) ;
+extern void cd1400_rxstart ( int port) ;
+extern void command_acknowledge ( PHB *port_header ) ;
+extern int close_port ( ushort port, PHB *port_header, ushort preemptive, int pseudo) ;
+extern void command_preemptive ( PKT *packet) ;
+extern void rup_service ( void ) ;
+extern ushort GetModemLines(struct PHB *, register short *);
+extern void cd1400_intr (Process *cirrus_p, ushort *RtaType) ;
+extern void cd1400_mdint ( short port) ;
+extern void cd1400_rxint ( short port) ;
+extern void cd1400_rxexcept ( short port) ;
+extern void cd1400_txdata ( short port, PHB *port_header, PKT *packet) ;
+extern void cd1400_fast_clock(void);
+extern void cd1400_map_baud ( ushort host_rate, ushort *prescaler, ushort *divisor) ;
+extern void cd1400_modem ( ushort port, ushort way) ;
+extern void cd1400_txcommand ( short port, PHB *port_header, PKT *packet) ;
+extern void cd1400_txint ( int port) ;
+void Rprintf( char *RIOPrBuf, char *Str, ... );
+#if defined(DCIRRUS)
+void debug_packet(PKT *pkt, int option, char *string, int channel);
+#endif	/* defined(DCIRRUS) */
+#endif
+
+#ifdef HOST
+extern void wflush (PHB *);
+extern void command_preemptive (PKT *);
+#endif
+
+#endif /* _cirrusprots_h */
diff -urN linux-2.2.15-pre2/drivers/char/rio/chan.h linux/drivers/char/rio/chan.h
--- linux-2.2.15-pre2/drivers/char/rio/chan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/chan.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,33 @@
+/*
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+*/
+#ifndef _chan_h
+#define _chan_h
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_chan_h_sccs = "@(#)chan.h	1.1" ;
+#endif
+#endif
+
+#define Link0   0
+#define Link1   1
+#define Link2   2
+#define Link3   3
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/cirrus.h linux/drivers/char/rio/cirrus.h
--- linux-2.2.15-pre2/drivers/char/rio/cirrus.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cirrus.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,463 @@
+/****************************************************************************
+ *******                                                              *******
+ *******		CIRRUS.H				      *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    : 3 Aug 1990
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _cirrus_h
+#ifndef lint
+/* static char* _cirrus_h_sccs = "@(#)cirrus.h	1.16"; */
+#endif
+#define _cirrus_h 1
+
+#ifdef RTA
+#define	TO_UART	RX
+#define TO_DRIVER TX
+#endif
+
+#ifdef HOST
+#define	TO_UART	TX
+#define TO_DRIVER RX
+#endif
+#ifdef RTA
+/* Miscellaneous defines for CIRRUS addresses and related logic for
+   interrupts etc.
+*/
+#define	MAP(a)		((short *)(cirrus_base + (a)))
+#define outp(a,b)	(*MAP (a) =(b))
+#define inp(a)		((*MAP (a)) & 0xff)
+#define	CIRRUS_FIRST	(short*)0x7300
+#define	CIRRUS_SECOND	(short*)0x7200
+#define	CIRRUS_THIRD	(short*)0x7100
+#define	CIRRUS_FOURTH	(short*)0x7000
+#define	PORTS_ON_CIRRUS	4
+#define	CIRRUS_FIFO_SIZE	12
+#define	SPACE		0x20
+#define	TAB		0x09
+#define	LINE_FEED	0x0a
+#define	CARRIAGE_RETURN	0x0d
+#define	BACKSPACE	0x08
+#define	SPACES_IN_TABS	8
+#define	SEND_ESCAPE	0x00
+#define START_BREAK	0x81
+#define	TIMER_TICK	0x82
+#define STOP_BREAK	0x83
+#define BASE(a) ((a) < 4 ? (short*)CIRRUS_FIRST : ((a) < 8 ? (short *)CIRRUS_SECOND : ((a) < 12 ? (short*)CIRRUS_THIRD : (short *)CIRRUS_FOURTH)))
+#define txack1	((short *)0x7104) 
+#define rxack1	((short *)0x7102) 
+#define mdack1  ((short *)0x7106)
+#define txack2  ((short *)0x7006) 
+#define rxack2	((short *)0x7004) 
+#define mdack2  ((short *)0x7100) 
+#define int_latch       ((short *) 0x7800)
+#define int_status      ((short *) 0x7c00) 
+#define tx1_pending     0x20 
+#define rx1_pending     0x10 
+#define md1_pending     0x40 
+#define tx2_pending     0x02 
+#define rx2_pending     0x01 
+#define md2_pending     0x40 
+#define module1_bits	0x07
+#define module1_modern	0x08
+#define module2_bits	0x70
+#define module2_modern	0x80
+#define module_blank	0xf
+#define rs232_d25	0x0
+#define	rs232_rj45	0x1
+#define rs422_d25	0x3
+#define parallel	0x5
+
+#define	CLK0	0x00
+#define CLK1	0x01
+#define CLK2	0x02
+#define CLK3	0x03
+#define CLK4	0x04
+
+#define CIRRUS_REVC    0x42
+#define CIRRUS_REVE    0x44
+
+#define	TURNON	1
+#define TURNOFF 0
+
+/* The list of CIRRUS registers. 
+   NB. These registers are relative values on 8 bit boundaries whereas
+   on the RTA's the CIRRUS registers are on word boundaries. Use pointer
+   arithmetic (short *) to obtain the real addresses required */
+#define ccr	0x05	/* Channel Command Register     */
+#define ier	0x06	/* Interrupt Enable Register    */
+#define cor1	0x08	/* Channel Option Register 1    */
+#define cor2	0x09	/* Channel Option Register 2    */
+#define cor3	0x0a	/* Channel Option Register 3    */
+#define cor4	0x1e	/* Channel Option Register 4    */
+#define	cor5	0x1f	/* Channel Option Register 5	*/
+
+#define ccsr	0x0b	/* Channel Control Status Register */
+#define rdcr	0x0e	/* Receive Data Count Register  */
+#define tdcr	0x12	/* Transmit Data Count Register */
+#define mcor1	0x15	/* Modem Change Option Register 1 */
+#define mcor2	0x16	/* Modem Change Option Regsiter 2 */
+
+#define livr	0x18	/* Local Interrupt Vector Register */
+#define schr1	0x1a	/* Special Character Register 1 */
+#define schr2	0x1b	/* Special Character Register 2 */
+#define schr3	0x1c	/* Special Character Register 3 */
+#define schr4	0x1d	/* Special Character Register 4 */
+
+#define rtr	0x20    /* Receive Timer Register */
+#define rtpr	0x21	/* Receive Timeout Period Register */
+#define lnc	0x24	/* Lnext character */
+
+#define rivr	0x43	/* Receive Interrupt Vector Register    */
+#define tivr	0x42	/* Transmit Interrupt Vector Register   */
+#define mivr	0x41	/* Modem Interrupt Vector Register      */
+#define gfrcr	0x40	/* Global Firmware Revision code Reg    */
+#define ricr	0x44	/* Receive Interrupting Channel Reg     */
+#define ticr	0x45	/* Transmit Interrupting Channel Reg    */
+#define micr	0x46	/* Modem Interrupting Channel Register  */
+
+#define gcr	0x4b	/* Global configuration register*/
+#define misr    0x4c    /* Modem interrupt status register */
+
+#define rbusr	0x59
+#define tbusr	0x5a
+#define mbusr	0x5b
+
+#define eoir	0x60	/* End Of Interrupt Register */
+#define rdsr	0x62	/* Receive Data / Status Register */
+#define tdr	0x63	/* Transmit Data Register */
+#define svrr	0x67	/* Service Request Register */
+
+#define car	0x68	/* Channel Access Register */
+#define mir	0x69	/* Modem Interrupt Register */
+#define tir	0x6a	/* Transmit Interrupt Register */
+#define rir	0x6b	/* Receive Interrupt Register */
+#define msvr1	0x6c	/* Modem Signal Value Register 1 */
+#define msvr2	0x6d	/* Modem Signal Value Register 2*/
+#define psvr	0x6f	/* Printer Signal Value Register*/
+
+#define tbpr	0x72	/* Transmit Baud Rate Period Register */
+#define tcor	0x76	/* Transmit Clock Option Register */
+
+#define rbpr	0x78	/* Receive Baud Rate Period Register */
+#define rber	0x7a	/* Receive Baud Rate Extension Register */
+#define rcor	0x7c	/* Receive Clock Option Register*/
+#define ppr	0x7e	/* Prescalar Period Register    */
+
+/* Misc registers used for forcing the 1400 out of its reset woes */
+#define airl	0x6d
+#define airm	0x6e
+#define airh	0x6f
+#define btcr	0x66
+#define mtcr	0x6c
+#define tber	0x74
+
+#endif				/* #ifdef RTA */
+
+
+/* Bit fields for particular registers */
+
+/* GCR */
+#define GCR_SERIAL	0x00	/* Configure as serial channel */
+#define GCR_PARALLEL	0x80	/* Configure as parallel channel */
+
+/* RDSR - when status read from FIFO */
+#define	RDSR_BREAK		0x08	/* Break received */
+#define RDSR_TIMEOUT    	0x80    /* No new data timeout */
+#define RDSR_SC1  	  	0x10    /* Special char 1 (tx XON) matched */
+#define RDSR_SC2  	  	0x20    /* Special char 2 (tx XOFF) matched */
+#define RDSR_SC12_MASK	  	0x30    /* Mask for special chars 1 and 2 */
+
+/* PPR */
+#define PPR_DEFAULT	0x31	/* Default value - for a 25Mhz clock gives
+				   a timeout period of 1ms */
+
+/* LIVR */
+#define	LIVR_EXCEPTION	0x07	/* Receive exception interrupt */
+
+/* CCR */
+#define	CCR_RESET	0x80	/* Reset channel */
+#define	CCR_CHANGE	0x4e	/* COR's have changed - NB always change all
+				   COR's */
+#define	CCR_WFLUSH	0x82	/* Flush transmit FIFO and TSR / THR */
+
+#define	CCR_SENDSC1	0x21	/* Send special character one */
+#define CCR_SENDSC2	0x22	/* Send special character two */
+#define CCR_SENDSC3	0x23	/* Send special character three */
+#define CCR_SENDSC4	0x24	/* Send special character four */
+
+#define CCR_TENABLE	0x18	/* Enable transmitter */
+#define	CCR_TDISABLE	0x14	/* Disable transmitter */
+#define CCR_RENABLE	0x12	/* Enable receiver */
+#define CCR_RDISABLE	0x11	/* Disable receiver */
+
+#define	CCR_READY	0x00	/* CCR is ready for another command */
+
+/* CCSR */
+#define CCSR_TXENABLE	0x08	/* Transmitter enable */
+#define CCSR_RXENABLE	0x80	/* Receiver enable */
+#define CCSR_TXFLOWOFF	0x04	/* Transmit flow off */
+#define CCSR_TXFLOWON	0x02	/* Transmit flow on */
+
+/* SVRR */
+#define	SVRR_RECEIVE	0x01	/* Receive interrupt pending */
+#define	SVRR_TRANSMIT	0x02	/* Transmit interrupt pending */
+#define	SVRR_MODEM	0x04	/* Modem interrupt pending */
+
+/* CAR */
+#define CAR_PORTS	0x03	/* Bit fields for ports */
+
+/* IER */
+#define	IER_MODEM	0x80	/* Change in modem status */
+#define	IER_RECEIVE	0x10	/* Good data / data exception */
+#define IER_TRANSMITR	0x04	/* Transmit ready (FIFO empty) */
+#define	IER_TRANSMITE	0x02	/* Transmit empty */
+#define IER_TIMEOUT	0x01	/* Timeout on no data */
+
+#define	IER_DEFAULT	0x94	/* Default values */
+#define IER_PARALLEL    0x84    /* Default for Parallel */
+#define	IER_EMPTY	0x92	/* Transmitter empty rather than ready */
+
+/* COR1 - Driver only */
+#define	COR1_INPCK	0x10	/* Check parity of received characters */
+
+/* COR1 - driver and RTA */
+#define	COR1_ODD	0x80	/* Odd parity */
+#define COR1_EVEN	0x00	/* Even parity */
+#define	COR1_NOP	0x00	/* No parity */
+#define	COR1_FORCE	0x20	/* Force parity */
+#define	COR1_NORMAL	0x40	/* With parity */
+#define	COR1_1STOP	0x00	/* 1 stop bit */
+#define	COR1_15STOP	0x04	/* 1.5 stop bits */
+#define	COR1_2STOP	0x08	/* 2 stop bits */
+#define	COR1_5BITS	0x00	/* 5 data bits */
+#define	COR1_6BITS	0x01	/* 6 data bits */
+#define	COR1_7BITS	0x02	/* 7 data bits */
+#define	COR1_8BITS	0x03	/* 8 data bits */
+
+#define COR1_HOST       0xef    /* Safe host bits */
+
+/* RTA only */
+#define COR1_CINPCK     0x00    /* Check parity of received characters */
+#define COR1_CNINPCK    0x10    /* Don't check parity */
+
+/* COR2 bits for both RTA and driver use */
+#define	COR2_IXANY	0x80	/* IXANY - any character is XON */
+#define	COR2_IXON	0x40	/* IXON - enable tx soft flowcontrol */
+#define	COR2_RTSFLOW	0x02	/* Enable tx hardware flow control */
+
+/* Additional driver bits */
+#define	COR2_HUPCL	0x20	/* Hang up on close */
+#define	COR2_CTSFLOW	0x04	/* Enable rx hardware flow control */
+#define	COR2_IXOFF	0x01	/* Enable rx software flow control */
+#define COR2_DTRFLOW	0x08	/* Enable tx hardware flow control */
+
+/* RTA use only */
+#define COR2_ETC	0x20	/* Embedded transmit options */
+#define	COR2_LOCAL	0x10	/* Local loopback mode */
+#define	COR2_REMOTE	0x08	/* Remote loopback mode */
+#define	COR2_HOST	0xc2	/* Safe host bits */
+
+/* COR3 - RTA use only */
+#define	COR3_SCDRNG	0x80	/* Enable special char detect for range */
+#define	COR3_SCD34	0x40	/* Special character detect for SCHR's 3 + 4 */
+#define	COR3_FCT	0x20	/* Flow control transparency */
+#define	COR3_SCD12	0x10	/* Special character detect for SCHR's 1 + 2 */
+#define	COR3_FIFO12	0x0c	/* 12 chars for receive FIFO threshold */
+#define COR3_FIFO10     0x0a    /* 10 chars for receive FIFO threshold */
+#define COR3_FIFO8      0x08    /* 8 chars for receive FIFO threshold */
+#define COR3_FIFO6      0x06    /* 6 chars for receive FIFO threshold */
+
+#define COR3_THRESHOLD  COR3_FIFO8	/* MUST BE LESS THAN MCOR_THRESHOLD */
+
+#define	COR3_DEFAULT	(COR3_FCT | COR3_THRESHOLD)
+				/* Default bits for COR3 */
+
+/* COR4 driver and RTA use */
+#define	COR4_IGNCR	0x80	/* Throw away CR's on input */
+#define	COR4_ICRNL	0x40	/* Map CR -> NL on input */
+#define	COR4_INLCR	0x20	/* Map NL -> CR on input */
+#define	COR4_IGNBRK	0x10	/* Ignore Break */
+#define	COR4_NBRKINT	0x08	/* No interrupt on break (-BRKINT) */
+#define COR4_RAISEMOD	0x01	/* Raise modem output lines on non-zero baud */
+
+
+/* COR4 driver only */
+#define COR4_IGNPAR	0x04	/* IGNPAR (ignore characters with errors) */
+#define COR4_PARMRK	0x02	/* PARMRK */
+
+#define COR4_HOST	0xf8	/* Safe host bits */
+
+/* COR4 RTA only */
+#define COR4_CIGNPAR	0x02	/* Thrown away bad characters */
+#define COR4_CPARMRK	0x04	/* PARMRK characters */
+#define COR4_CNPARMRK	0x03	/* Don't PARMRK */
+
+/* COR5 driver and RTA use */
+#define	COR5_ISTRIP	0x80	/* Strip input chars to 7 bits */
+#define	COR5_LNE	0x40	/* Enable LNEXT processing */
+#define	COR5_CMOE	0x20	/* Match good and errored characters */
+#define	COR5_ONLCR	0x02	/* NL -> CR NL on output */
+#define	COR5_OCRNL	0x01	/* CR -> NL on output */
+
+/*
+** Spare bits - these are not used in the CIRRUS registers, so we use
+** them to set various other features.
+*/
+/*
+** tstop and tbusy indication
+*/
+#define	COR5_TSTATE_ON	0x08	/* Turn on monitoring of tbusy and tstop */
+#define	COR5_TSTATE_OFF	0x04	/* Turn off monitoring of tbusy and tstop */
+/*
+** TAB3
+*/
+#define	COR5_TAB3	0x10	/* TAB3 mode */
+
+#define	COR5_HOST	0xc3	/* Safe host bits */
+
+/* CCSR */
+#define	CCSR_TXFLOFF	0x04	/* Tx is xoffed */
+
+/* MSVR1 */
+/* NB. DTR / CD swapped from Cirrus spec as the pins are also reversed on the
+   RTA. This is because otherwise DCD would get lost on the 1 parallel / 3
+   serial option.
+*/
+#define	MSVR1_CD	0x80	/* CD (DSR on Cirrus) */
+#define	MSVR1_RTS	0x40	/* RTS (CTS on Cirrus) */
+#define	MSVR1_RI	0x20	/* RI */
+#define	MSVR1_DTR	0x10	/* DTR (CD on Cirrus) */
+#define	MSVR1_CTS	0x01	/* CTS output pin (RTS on Cirrus) */
+/* Next two used to indicate state of tbusy and tstop to driver */
+#define	MSVR1_TSTOP	0x08	/* Set if port flow controlled */
+#define	MSVR1_TEMPTY	0x04	/* Set if port tx buffer empty */
+
+#define	MSVR1_HOST	0xf3	/* The bits the host wants */
+
+/* MSVR2 */
+#define	MSVR2_DSR	0x02	/* DSR output pin (DTR on Cirrus) */
+
+/* MCOR */
+#define	MCOR_CD	        0x80	/* CD (DSR on Cirrus) */
+#define	MCOR_RTS	0x40	/* RTS (CTS on Cirrus) */
+#define	MCOR_RI	        0x20	/* RI */
+#define	MCOR_DTR	0x10	/* DTR (CD on Cirrus) */
+
+#define MCOR_DEFAULT    (MCOR_CD | MCOR_RTS | MCOR_RI | MCOR_DTR)
+#define MCOR_FULLMODEM  MCOR_DEFAULT
+#define MCOR_RJ45       (MCOR_CD | MCOR_RTS | MCOR_DTR)
+#define MCOR_RESTRICTED (MCOR_CD | MCOR_RTS)
+
+/* More MCOR - H/W Handshake (flowcontrol) stuff */
+#define	MCOR_THRESH8	0x08	/* eight characters then we stop */
+#define	MCOR_THRESH9	0x09	/* nine characters then we stop */
+#define	MCOR_THRESH10	0x0A	/* ten characters then we stop */
+#define	MCOR_THRESH11	0x0B	/* eleven characters then we stop */
+
+#define	MCOR_THRESHBITS 0x0F	/* mask for ANDing out the above */
+
+#define	MCOR_THRESHOLD	MCOR_THRESH9 /* MUST BE GREATER THAN COR3_THRESHOLD */
+
+
+/* RTPR */
+#define RTPR_DEFAULT	0x02	/* Default */
+
+
+/* Defines for the subscripts of a CONFIG packet */
+#define	CONFIG_COR1	1	/* Option register 1 */
+#define	CONFIG_COR2	2	/* Option register 2 */
+#define	CONFIG_COR4	3	/* Option register 4 */
+#define	CONFIG_COR5	4	/* Option register 5 */
+#define	CONFIG_TXXON	5	/* Tx XON character */
+#define	CONFIG_TXXOFF	6	/* Tx XOFF character */
+#define	CONFIG_RXXON	7	/* Rx XON character */
+#define	CONFIG_RXXOFF	8	/* Rx XOFF character */
+#define CONFIG_LNEXT	9	/* LNEXT character */
+#define	CONFIG_TXBAUD	10	/* Tx baud rate */
+#define	CONFIG_RXBAUD	11	/* Rx baud rate */
+
+/* Port status stuff */
+#define	IDLE_CLOSED	0	/* Closed */
+#define IDLE_OPEN	1	/* Idle open */
+#define IDLE_BREAK	2	/* Idle on break */
+
+/* Subscript of MODEM STATUS packet */
+#define	MODEM_VALUE	3	/* Current values of handshake pins */
+/* Subscript of SBREAK packet */
+#define BREAK_LENGTH	1	/* Length of a break in slices of 0.01 seconds
+				   0 = stay on break until an EBREAK command
+				   is sent */
+
+
+#define	PRE_EMPTIVE	0x80	/* Pre-emptive bit in command field */
+
+/* Packet types going from Host to remote - with the exception of OPEN, MOPEN,
+   CONFIG, SBREAK and MEMDUMP the remaining bytes of the data array will not
+   be used 
+*/
+#define	OPEN		0x00	/* Open a port */
+#define CONFIG		0x01	/* Configure a port */
+#define	MOPEN		0x02	/* Modem open (block for DCD) */
+#define	CLOSE		0x03	/* Close a port */
+#define	WFLUSH		(0x04 | PRE_EMPTIVE) /* Write flush */
+#define	RFLUSH		(0x05 | PRE_EMPTIVE) /* Read flush */
+#define	RESUME		(0x06 | PRE_EMPTIVE) /* Resume if xoffed */
+#define	SBREAK		0x07 	/* Start break */
+#define	EBREAK		0x08	/* End break */
+#define	SUSPEND		(0x09 | PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
+#define FCLOSE          (0x0a | PRE_EMPTIVE) /* Force close */
+#define XPRINT          0x0b    /* Xprint packet */
+#define MBIS		(0x0c | PRE_EMPTIVE) /* Set modem lines */
+#define MBIC		(0x0d | PRE_EMPTIVE) /* Clear modem lines */
+#define MSET		(0x0e | PRE_EMPTIVE) /* Set modem lines */
+#define PCLOSE		0x0f	/* Pseudo close - Leaves rx/tx enabled */
+#define MGET		(0x10 | PRE_EMPTIVE) /* Force update of modem status */
+#define MEMDUMP		(0x11 | PRE_EMPTIVE) /* Send back mem from addr supplied */
+#define	READ_REGISTER	(0x12 | PRE_EMPTIVE) /* Read CD1400 register (debug) */
+
+/* "Command" packets going from remote to host COMPLETE and MODEM_STATUS
+   use data[4] / data[3] to indicate current state and modem status respectively
+*/ 
+
+#define	COMPLETE	(0x20 | PRE_EMPTIVE)
+				/* Command complete */
+#define BREAK_RECEIVED	(0x21 | PRE_EMPTIVE)
+				/* Break received */
+#define MODEM_STATUS	(0x22 | PRE_EMPTIVE)
+				/* Change in modem status */
+
+/* "Command" packet that could go either way - handshake wake-up */
+#define HANDSHAKE	(0x23 | PRE_EMPTIVE)
+				/* Wake-up to HOST / RTA */
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/cmd.h linux/drivers/char/rio/cmd.h
--- linux-2.2.15-pre2/drivers/char/rio/cmd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cmd.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,84 @@
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******           C O M M A N D   P A C K E T   H E A D E R S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+
+#ifndef _cmd_h
+#define _cmd_h
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_cmd_h_sccs = "@(#)cmd.h	1.1" ;
+#endif
+#endif
+
+
+#define PRE_EMPTIVE_CMD         0x80
+#define INLINE_CMD              ~PRE_EMPTIVE_CMD
+
+#define CMD_IGNORE_PKT          ( (ushort) 0)
+#define CMD_STATUS_REQ          ( (ushort) 1)
+#define CMD_UNIT_STATUS_REQ     ( (ushort) 2)     /* Is this needed ??? */
+#define CMD_CONF_PORT           ( (ushort) 3)
+#define CMD_CONF_UNIT           ( (ushort) 4)
+#define CMD_ROUTE_MAP_REQ       ( (ushort) 5)
+#define CMD_FLUSH_TX            ( (ushort) 6)
+#define CMD_FLUSH_RX            ( (ushort) 7)
+#define CMD_PARTION_PORT        ( (ushort) 8)
+#define CMD_RESET_PORT          ( (ushort) 0x0a)
+#define CMD_BOOT_UNIT           ( (ushort) 0x0b)
+#define CMD_FOUND_UNIT          ( (ushort) 0x0c)
+#define CMD_ATTACHED_RTA_2      ( (ushort) 0x0d)
+#define CMD_PROVIDE_BOOT        ( (ushort) 0x0e)
+#define CMD_CIRRUS              ( (ushort) 0x0f)
+
+#define FORM_STATUS_PKT         ( (ushort) 1 )
+#define FORM_POLL_PKT           ( (ushort) 2 )
+#define FORM_LINK_STATUS_PKT    ( (ushort) 3 )
+
+
+#define CMD_DATA_PORT           ( (ushort) 1 )
+#define CMD_DATA                ( (ushort) 2 )
+
+#define CMD_TX_PART             ( (ushort) 2 )
+#define CMD_RX_PART             ( (ushort) 3 )
+#define CMD_RX_LIMIT            ( (ushort) 4 )
+
+#endif
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/cmdblk.h linux/drivers/char/rio/cmdblk.h
--- linux-2.2.15-pre2/drivers/char/rio/cmdblk.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cmdblk.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,60 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: cmdblk.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)cmdblk.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_cmdblk_h__
+#define __rio_cmdblk_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_cmdblk_h_sccs_ = "@(#)cmdblk.h	1.2";
+#endif
+#endif
+
+/*
+** the structure of a command block, used to queue commands destined for
+** a rup.
+*/
+
+struct CmdBlk
+{
+ struct CmdBlk *NextP;          /* Pointer to next command block */
+ struct	PKT     Packet;         /* A packet, to copy to the rup */
+    	                        /* The func to call to check if OK */
+    	int     (*PreFuncP)(int, struct CmdBlk *);
+    	int     PreArg;         /* The arg for the func */
+    	                        /* The func to call when completed */
+    	int     (*PostFuncP)(int, struct CmdBlk *);
+    	int     PostArg;        /* The arg for the func */
+};
+
+#define NUM_RIO_CMD_BLKS (3 * (MAX_RUP * 4 + LINKS_PER_UNIT * 4))
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/cmdpkt.h linux/drivers/char/rio/cmdpkt.h
--- linux-2.2.15-pre2/drivers/char/rio/cmdpkt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cmdpkt.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,206 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: cmdpkt.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)cmdpkt.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifndef __rio_cmdpkt_h__
+#define __rio_cmdpkt_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_cmdpkt_h_sccs_ = "@(#)cmdpkt.h	1.2";
+#endif
+#endif
+
+/*
+** overlays for the data area of a packet. Used in both directions
+** (to build a packet to send, and to interpret a packet that arrives)
+** and is very inconvenient for MIPS, so they appear as two seperate
+** structures - those used for modifying/reading packets on the card
+** and those for modifying/reading packets in real memory, which have an _M
+** suffix.
+*/
+
+#define	RTA_BOOT_DATA_SIZE (PKT_MAX_DATA_LEN-2)
+
+/*
+** The boot information packet looks like this:
+** This structure overlays a PktCmd->CmdData structure, and so starts
+** at Data[2] in the actual pkt!
+*/
+struct BootSequence
+{
+    WORD	NumPackets;
+    WORD	LoadBase;
+    WORD	CodeSize;
+};
+
+#define	BOOT_SEQUENCE_LEN	8
+
+struct SamTop
+{
+    BYTE Unit;
+    BYTE Link;
+};
+
+struct CmdHdr
+{
+    BYTE PcCommand;
+    union
+    {
+    BYTE PcPhbNum;
+    BYTE PcLinkNum;
+    BYTE PcIDNum;
+    } U0;
+};
+
+
+struct PktCmd
+{
+    union
+    {
+	struct 
+	{
+	    struct CmdHdr CmdHdr;
+	    struct BootSequence PcBootSequence;
+	} S1;
+	struct
+	{
+	    WORD PcSequence;
+	    BYTE PcBootData[RTA_BOOT_DATA_SIZE];
+	} S2;
+	struct
+	{
+	    WORD  __crud__;
+	    BYTE  PcUniqNum[4];	        /* this is really a uint. */
+	    BYTE  PcModuleTypes;  	/* what modules are fitted */
+	} S3;
+	struct
+	{
+	    struct CmdHdr CmdHdr;
+	    BYTE   __undefined__;
+	    BYTE   PcModemStatus;
+	    BYTE   PcPortStatus;
+	    BYTE   PcSubCommand;	/* commands like mem or register dump */
+	    WORD   PcSubAddr;		/* Address for command */
+	    BYTE   PcSubData[64];	/* Date area for command */
+	} S4;
+	struct
+	{
+	    struct CmdHdr CmdHdr;
+	    BYTE   PcCommandText[1];
+	    BYTE   __crud__[20];
+	    BYTE   PcIDNum2;		/* It had to go somewhere! */
+	} S5;
+	struct
+	{
+	    struct CmdHdr CmdHdr;
+	    struct SamTop    Topology[LINKS_PER_UNIT];
+	} S6;
+    } U1;
+};
+
+struct PktCmd_M
+{
+    union
+    {
+	struct 
+	{
+	    struct
+	    {
+    		uchar PcCommand;
+    		union
+    		{
+    		    uchar PcPhbNum;
+    		    uchar PcLinkNum;
+    		    uchar PcIDNum;
+    		} U0;
+	    } CmdHdr;
+	    struct
+	    {
+                ushort	NumPackets;
+                ushort	LoadBase;
+                ushort	CodeSize;
+            } PcBootSequence;
+	} S1;
+	struct
+	{
+	    ushort PcSequence;
+	    uchar PcBootData[RTA_BOOT_DATA_SIZE];
+	} S2;
+	struct
+	{
+	    ushort  __crud__;
+	    uchar  PcUniqNum[4];	        /* this is really a uint. */
+	    uchar  PcModuleTypes;  	/* what modules are fitted */
+	} S3;
+	struct
+	{
+	    ushort  __cmd_hdr__;
+	    uchar   __undefined__;
+	    uchar   PcModemStatus;
+	    uchar   PcPortStatus;
+	    uchar   PcSubCommand;
+	    ushort  PcSubAddr;
+	    uchar   PcSubData[64];
+	} S4;
+	struct
+	{
+	    ushort  __cmd_hdr__;
+	    uchar   PcCommandText[1];
+	    uchar   __crud__[20];
+	    uchar   PcIDNum2;		/* Tacked on end */
+	} S5;
+	struct
+	{
+	    ushort  __cmd_hdr__;
+	    struct Top Topology[LINKS_PER_UNIT];
+	} S6;
+    } U1;
+};
+
+#define Command		U1.S1.CmdHdr.PcCommand
+#define PhbNum		U1.S1.CmdHdr.U0.PcPhbNum
+#define IDNum		U1.S1.CmdHdr.U0.PcIDNum
+#define IDNum2		U1.S5.PcIDNum2
+#define LinkNum		U1.S1.CmdHdr.U0.PcLinkNum
+#define Sequence	U1.S2.PcSequence
+#define BootData	U1.S2.PcBootData
+#define BootSequence	U1.S1.PcBootSequence
+#define UniqNum		U1.S3.PcUniqNum
+#define ModemStatus	U1.S4.PcModemStatus
+#define PortStatus	U1.S4.PcPortStatus
+#define SubCommand	U1.S4.PcSubCommand
+#define SubAddr		U1.S4.PcSubAddr
+#define SubData		U1.S4.PcSubData
+#define CommandText	U1.S5.PcCommandText
+#define RouteTopology	U1.S6.Topology
+#define ModuleTypes	U1.S3.PcModuleTypes
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/control.h linux/drivers/char/rio/control.h
--- linux-2.2.15-pre2/drivers/char/rio/control.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/control.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,62 @@
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******           C O N T R O L   P A C K E T   H E A D E R S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jon Brawn
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+
+#ifndef _control_h
+#define _control_h
+
+#ifndef lint
+/* static char *_rio_control_h_sccs = "@(#)control.h	1.4"; */
+#endif
+
+#define	CONTROL		'^'
+#define IFOAD		( CONTROL + 1 )
+#define	IDENTIFY	( CONTROL + 2 )
+#define	ZOMBIE		( CONTROL + 3 )
+#define	UFOAD		( CONTROL + 4 )
+#define IWAIT		( CONTROL + 5 )
+
+#define	IFOAD_MAGIC	0xF0AD		/* of course */
+#define	ZOMBIE_MAGIC	(~0xDEAD)	/* not dead -> zombie */
+#define	UFOAD_MAGIC	0xD1E		/* kill-your-neighbour */
+#define	IWAIT_MAGIC	0xB1DE		/* Bide your time */
+
+#endif
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/daemon.h linux/drivers/char/rio/daemon.h
--- linux-2.2.15-pre2/drivers/char/rio/daemon.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/daemon.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,334 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: daemon.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)daemon.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_daemon_h__
+#define	__rio_daemon_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_daemon_h_sccs_ = "@(#)daemon.h	1.3";
+#endif
+#endif
+
+
+/*
+** structures used on /dev/rio
+*/
+
+struct Error
+{
+	uint	Error;
+	uint	Entry;
+	uint	Other;
+};
+
+struct DownLoad
+{
+	char	*DataP;
+	uint	Count;
+	uint	ProductCode;
+};
+
+/*
+** A few constants....
+*/
+#ifndef MAX_VERSION_LEN
+#define	MAX_VERSION_LEN	256
+#endif
+
+#ifndef MAX_XP_CTRL_LEN
+#define	MAX_XP_CTRL_LEN 16		/* ALSO IN PORT.H */
+#endif
+
+struct	PortSetup
+{
+	uint	From;	/* Set/Clear XP & IXANY Control from this port.... */
+	uint	To;	/* .... to this port */
+	uint	XpCps;			/* at this speed */
+	char	XpOn[MAX_XP_CTRL_LEN];	/* this is the start string */
+	char	XpOff[MAX_XP_CTRL_LEN];	/* this is the stop string */
+	uchar	IxAny;			/* enable/disable IXANY */
+	uchar	IxOn;			/* enable/disable IXON */
+	uchar	Lock;			/* lock port params */
+	uchar	Store;			/* store params across closes */
+	uchar	Drain;			/* close only when drained */
+};
+
+struct	LpbReq
+{
+	uint	Host;
+	uint	Link;
+	struct  LPB     *LpbP;
+};
+
+struct	RupReq
+{
+	uint	HostNum;
+	uint	RupNum;
+	struct  RUP 	*RupP;
+};
+
+struct	PortReq
+{
+	uint	SysPort;
+	struct  Port 	*PortP;
+};
+
+struct  StreamInfo
+{
+	uint	SysPort;
+#if 0
+	queue_t RQueue;
+	queue_t WQueue;
+#else
+	int RQueue;
+	int WQueue;
+#endif
+};
+
+struct	HostReq
+{
+	uint	HostNum;
+	struct  Host 	*HostP;
+};
+
+struct	HostDpRam
+{
+	uint	HostNum;
+	struct	DpRam	*DpRamP;
+};
+
+struct	DebugCtrl
+{
+	uint	SysPort;
+	uint	Debug;
+	uint	Wait;
+};
+
+struct	MapInfo
+{
+	uint	FirstPort;	/* 8 ports, starting from this (tty) number */
+	uint	RtaUnique;	/* reside on this RTA (unique number) */
+};
+
+struct	MapIn
+{
+	uint	NumEntries;		/* How many port sets are we mapping? */
+	struct  MapInfo	*MapInfoP;	/* Pointer to (user space) info */
+};
+
+struct  SendPack
+{
+        unsigned int	PortNum;
+	unsigned char	Len;
+	unsigned char	Data[PKT_MAX_DATA_LEN];
+};
+
+struct SpecialRupCmd
+{
+	struct	PKT		Packet;
+	unsigned short	Host;
+	unsigned short	RupNum;
+};
+
+struct	IdentifyRta
+{
+	ulong	RtaUnique;
+	uchar	ID;
+};
+
+struct	KillNeighbour
+{
+	ulong	UniqueNum;
+	uchar	Link;
+};
+
+struct rioVersion {
+    char        version[MAX_VERSION_LEN];
+    char        relid[MAX_VERSION_LEN];
+    int         buildLevel;
+    char        buildDate[MAX_VERSION_LEN];
+};
+
+
+/*
+**	RIOC commands are for the daemon type operations
+**
+** 09.12.1998 ARG - ESIL 0776 part fix
+** Definition for 'RIOC' also appears in rioioctl.h, so we'd better do a
+** #ifndef here first.
+** rioioctl.h also now has #define 'RIO_QUICK_CHECK' as this ioctl is now
+** allowed to be used by customers.
+*/
+#ifndef RIOC
+#define	RIOC	('R'<<8)|('i'<<16)|('o'<<24)
+#endif
+
+/*
+** Boot stuff
+*/
+#define	RIO_GET_TABLE     (RIOC | 100)
+#define RIO_PUT_TABLE     (RIOC | 101)
+#define RIO_ASSIGN_RTA    (RIOC | 102)
+#define RIO_DELETE_RTA    (RIOC | 103)
+#define	RIO_HOST_FOAD	  (RIOC | 104)
+#define	RIO_QUICK_CHECK	  (RIOC | 105)
+#define RIO_SIGNALS_ON    (RIOC | 106)
+#define RIO_SIGNALS_OFF   (RIOC | 107)
+#define	RIO_CHANGE_NAME   (RIOC | 108)
+#define RIO_DOWNLOAD      (RIOC | 109)
+#define	RIO_GET_LOG	  (RIOC | 110)
+#define	RIO_SETUP_PORTS   (RIOC | 111)
+#define RIO_ALL_MODEM     (RIOC | 112)
+
+/*
+** card state, debug stuff
+*/
+#define	RIO_NUM_HOSTS	  (RIOC | 120)
+#define	RIO_HOST_LPB	  (RIOC | 121)
+#define	RIO_HOST_RUP	  (RIOC | 122)
+#define	RIO_HOST_PORT	  (RIOC | 123)
+#define	RIO_PARMS 	  (RIOC | 124)
+#define RIO_HOST_REQ	  (RIOC | 125)
+#define	RIO_READ_CONFIG	  (RIOC | 126)
+#define	RIO_SET_CONFIG	  (RIOC | 127)
+#define	RIO_VERSID	  (RIOC | 128)
+#define	RIO_FLAGS	  (RIOC | 129)
+#define	RIO_SETDEBUG	  (RIOC | 130)
+#define	RIO_GETDEBUG	  (RIOC | 131)
+#define	RIO_READ_LEVELS   (RIOC | 132)
+#define	RIO_SET_FAST_BUS  (RIOC | 133)
+#define	RIO_SET_SLOW_BUS  (RIOC | 134)
+#define	RIO_SET_BYTE_MODE (RIOC | 135)
+#define	RIO_SET_WORD_MODE (RIOC | 136)
+#define RIO_STREAM_INFO   (RIOC | 137)
+#define	RIO_START_POLLER  (RIOC | 138)
+#define	RIO_STOP_POLLER   (RIOC | 139)
+#define	RIO_LAST_ERROR    (RIOC | 140)
+#define	RIO_TICK	  (RIOC | 141)
+#define	RIO_TOCK	  (RIOC | 241)	/* I did this on purpose, you know. */
+#define	RIO_SEND_PACKET   (RIOC | 142)
+#define	RIO_SET_BUSY	  (RIOC | 143)
+#define	SPECIAL_RUP_CMD   (RIOC | 144)
+#define	RIO_FOAD_RTA      (RIOC | 145)
+#define	RIO_ZOMBIE_RTA    (RIOC | 146)
+#define RIO_IDENTIFY_RTA  (RIOC | 147)
+#define RIO_KILL_NEIGHBOUR (RIOC | 148)
+#define RIO_DEBUG_MEM     (RIOC | 149)
+/*
+** 150 - 167 used.....   See below
+*/
+#define RIO_GET_PORT_SETUP (RIOC | 168)
+#define RIO_RESUME        (RIOC | 169)
+#define	RIO_MESG	(RIOC | 170)
+#define	RIO_NO_MESG	(RIOC | 171)
+#define	RIO_WHAT_MESG	(RIOC | 172)
+#define RIO_HOST_DPRAM	(RIOC | 173)
+#define RIO_MAP_B50_TO_50	(RIOC | 174)
+#define RIO_MAP_B50_TO_57600	(RIOC | 175)
+#define RIO_MAP_B110_TO_110	(RIOC | 176)
+#define RIO_MAP_B110_TO_115200	(RIOC | 177)
+#define RIO_GET_PORT_PARAMS	(RIOC | 178)
+#define RIO_SET_PORT_PARAMS	(RIOC | 179)
+#define RIO_GET_PORT_TTY	(RIOC | 180)
+#define RIO_SET_PORT_TTY	(RIOC | 181)
+#define RIO_SYSLOG_ONLY	(RIOC | 182)
+#define RIO_SYSLOG_CONS	(RIOC | 183)
+#define RIO_CONS_ONLY	(RIOC | 184)
+#define RIO_BLOCK_OPENS	(RIOC | 185)
+
+/*
+** 02.03.1999 ARG - ESIL 0820 fix :
+** RIOBootMode is no longer use by the driver, so these ioctls
+** are now obsolete :
+**
+#define RIO_GET_BOOT_MODE	(RIOC | 186)
+#define RIO_SET_BOOT_MODE	(RIOC | 187)
+**
+*/
+
+#define RIO_MEM_DUMP	(RIOC | 189)
+#define RIO_READ_REGISTER	(RIOC | 190)
+#define RIO_GET_MODTYPE	(RIOC | 191)
+#define RIO_SET_TIMER	(RIOC | 192)
+#define RIO_READ_CHECK	(RIOC | 196)
+#define RIO_WAITING_FOR_RESTART	(RIOC | 197)
+#define RIO_BIND_RTA	(RIOC | 198)
+#define RIO_GET_BINDINGS	(RIOC | 199)
+#define RIO_PUT_BINDINGS	(RIOC | 200)
+
+#define	RIO_MAKE_DEV		(RIOC | 201)
+#define	RIO_MINOR		(RIOC | 202)
+
+#define	RIO_IDENTIFY_DRIVER	(RIOC | 203)
+#define	RIO_DISPLAY_HOST_CFG	(RIOC | 204)
+
+
+/*
+** MAKE_DEV / MINOR stuff
+*/
+#define	RIO_DEV_DIRECT		0x0000
+#define	RIO_DEV_MODEM		0x0200
+#define	RIO_DEV_XPRINT		0x0400
+#define	RIO_DEV_MASK		0x0600
+
+/*
+** port management, xprint stuff
+*/
+#define	rIOCN(N)	(RIOC|(N))
+#define	rIOCR(N,T)	(RIOC|(N))
+#define	rIOCW(N,T)	(RIOC|(N))
+
+#define	RIO_GET_XP_ON     rIOCR(150,char[16])	/* start xprint string */
+#define	RIO_SET_XP_ON     rIOCW(151,char[16])
+#define	RIO_GET_XP_OFF    rIOCR(152,char[16])	/* finish xprint string */
+#define	RIO_SET_XP_OFF    rIOCW(153,char[16])
+#define	RIO_GET_XP_CPS    rIOCR(154,int)	/* xprint CPS */
+#define	RIO_SET_XP_CPS    rIOCW(155,int)
+#define RIO_GET_IXANY     rIOCR(156,int)	/* ixany allowed? */
+#define RIO_SET_IXANY     rIOCW(157,int)
+#define RIO_SET_IXANY_ON  rIOCN(158)		/* allow ixany */
+#define RIO_SET_IXANY_OFF rIOCN(159)		/* disallow ixany */
+#define RIO_GET_MODEM     rIOCR(160,int)	/* port is modem/direct line? */
+#define RIO_SET_MODEM     rIOCW(161,int)
+#define RIO_SET_MODEM_ON  rIOCN(162)		/* port is a modem */
+#define RIO_SET_MODEM_OFF rIOCN(163)		/* port is direct */
+#define RIO_GET_IXON      rIOCR(164,int)	/* ixon allowed? */
+#define RIO_SET_IXON      rIOCW(165,int)
+#define RIO_SET_IXON_ON   rIOCN(166)		/* allow ixon */
+#define RIO_SET_IXON_OFF  rIOCN(167)		/* disallow ixon */
+
+#define RIO_GET_SIVIEW	  ((('s')<<8) | 106)	/* backwards compatible with SI */
+
+#define	RIO_IOCTL_UNKNOWN	-2
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/data.h linux/drivers/char/rio/data.h
--- linux-2.2.15-pre2/drivers/char/rio/data.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/data.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,40 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: data.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)data.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_datadex__
+#define __rio_datadex__
+
+#ifndef lint
+static char *_data_h_sccs_ = "@(#)data.h	1.2";
+#endif
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/debug.h linux/drivers/char/rio/debug.h
--- linux-2.2.15-pre2/drivers/char/rio/debug.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/debug.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,39 @@
+/*
+** File:		debug.h
+**
+** Author:		David Dix
+**
+** Created:		12th March 1993
+**
+** Last modified:	93/04/27
+**
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+*/
+
+#ifndef _debug_h_
+#define _debug_h_
+
+
+#if defined(DCIRRUS)
+#define	DBPACKET(pkt, opt, str, chn) 	debug_packet((pkt), (opt), (str), (chn))
+#else
+#define	DBPACKET(pkt, opt, str, c)
+#endif	/* DCIRRUS */
+
+
+#endif	/* _debug_h_ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/defaults.h linux/drivers/char/rio/defaults.h
--- linux-2.2.15-pre2/drivers/char/rio/defaults.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/defaults.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,59 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******                     D E F A U L T S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_defaults_h_sccs = "@(#)defaults.h	1.1" ;
+#endif
+#endif
+
+
+#define MILLISECOND           (int) (1000/64)   /* 15.625 low ticks */
+#define SECOND                (int) 15625       /* Low priority ticks */
+
+#ifdef RTA
+#define RX_LIMIT       (ushort) 3
+#endif
+#ifdef HOST
+#define RX_LIMIT       (ushort) 1
+#endif
+
+#define LINK_TIMEOUT          (int) (POLL_PERIOD / 2)
+
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/eisa.h linux/drivers/char/rio/eisa.h
--- linux-2.2.15-pre2/drivers/char/rio/eisa.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/eisa.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,104 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: eisa.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)eisa.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_eisa_h__
+#define __rio_eisa_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_eisa_h_sccs_ = "@(#)eisa.h	1.2";
+#endif
+#endif
+
+/*
+** things to do with the EISA bus
+*/
+
+#define RIO_EISA_STRING_ADDRESS 	0xfffd9	/* where EISA is stored */
+
+#define	RIO_MAX_EISA_SLOTS		16	/* how many EISA slots? */
+
+#define	RIO_EISA_IDENT			0x984D	/* Specialix */
+#define	RIO_EISA_PRODUCT_CODE		0x14	/* Code 14 */
+#define	RIO_EISA_ENABLE_BIT		0x01	/* To enable card */
+
+#define	EISA_MEMORY_BASE_LO		0xC00	/* A16-A23 */
+#define	EISA_MEMORY_BASE_HI		0xC01	/* A24-A31 */
+#define	EISA_INTERRUPT_VEC		0xC02	/* see below */
+#define	EISA_CONTROL_PORT		0xC02	/* see below */
+#define	EISA_INTERRUPT_RESET		0xC03	/* read to clear IRQ */
+
+#define	EISA_PRODUCT_IDENT_LO		0xC80	/* where RIO_EISA_IDENT is */
+#define	EISA_PRODUCT_IDENT_HI		0xC81
+#define	EISA_PRODUCT_NUMBER		0xC82   /* where PROD_CODE is */
+#define	EISA_REVISION_NUMBER		0xC83	/* revision (1dp) */
+#define	EISA_ENABLE			0xC84	/* set LSB to enable card */
+#define	EISA_UNIQUE_NUM_0		0xC88	/* vomit */
+#define	EISA_UNIQUE_NUM_1		0xC8A
+#define	EISA_UNIQUE_NUM_2		0xC90	/* bit strangely arranged */
+#define	EISA_UNIQUE_NUM_3		0xC92
+#define	EISA_MANUF_YEAR			0xC98	/* when */
+#define	EISA_MANUF_WEEK			0xC9A	/* more when */
+
+#define	EISA_TP_BOOT_FROM_RAM	0x01
+#define	EISA_TP_BOOT_FROM_LINK	0x00
+#define	EISA_TP_FAST_LINKS	0x02
+#define	EISA_TP_SLOW_LINKS	0x00
+#define	EISA_TP_BUS_ENABLE	0x04
+#define	EISA_TP_BUS_DISABLE	0x00
+#define	EISA_TP_RUN		0x08
+#define	EISA_TP_RESET		0x00
+#define	EISA_POLLED		0x00
+#define	EISA_IRQ_3		0x30
+#define	EISA_IRQ_4		0x40
+#define	EISA_IRQ_5		0x50
+#define	EISA_IRQ_6		0x60
+#define	EISA_IRQ_7		0x70
+#define	EISA_IRQ_9		0x90
+#define	EISA_IRQ_10		0xA0
+#define	EISA_IRQ_11		0xB0
+#define	EISA_IRQ_12		0xC0
+#define	EISA_IRQ_14		0xE0
+#define	EISA_IRQ_15		0xF0
+
+#define	EISA_INTERRUPT_MASK	0xF0
+#define	EISA_CONTROL_MASK	0x0F
+
+#define	RIO_EISA_DEFAULT_MODE	EISA_TP_SLOW_LINKS
+
+#define	RIOEisaToIvec(X)	(uchar )((uchar)((X) & EISA_INTERRUPT_MASK)>>4)
+
+#define	INBZ(z,x)	inb(((z)<<12) | (x))
+#define	OUTBZ(z,x,y)	outb((((z)<<12) | (x)), y)
+
+#endif /* __rio_eisa_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/enable.h linux/drivers/char/rio/enable.h
--- linux-2.2.15-pre2/drivers/char/rio/enable.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/enable.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,50 @@
+/****************************************************************************
+ *******                                                              *******
+ *******               E N A B L E   H E A D E R S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_enable_h_sccs = "@(#)enable.h	1.1" ;
+#endif
+#endif
+
+
+#define ENABLE_LTT  TRUE
+#define ENABLE_LRT  TRUE
+
+
+/*********** end of file ***********/
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/error.h linux/drivers/char/rio/error.h
--- linux-2.2.15-pre2/drivers/char/rio/error.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/error.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,85 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******     E R R O R  H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+/* static char *_rio_error_h_sccs = "@(#)error.h	1.3"; */
+#endif
+
+#define E_NO_ERROR                       ((ushort) 0)
+#define E_PROCESS_NOT_INIT               ((ushort) 1)
+#define E_LINK_TIMEOUT                   ((ushort) 2)
+#define E_NO_ROUTE                       ((ushort) 3)
+#define E_CONFUSED                       ((ushort) 4)
+#define E_HOME                           ((ushort) 5)
+#define E_CSUM_FAIL                      ((ushort) 6)
+#define E_DISCONNECTED                   ((ushort) 7)
+#define E_BAD_RUP                        ((ushort) 8)
+#define E_NO_VIRGIN                      ((ushort) 9)
+#define E_BOOT_RUP_BUSY                  ((ushort) 10)
+
+
+
+    /*************************************************
+     * Parsed to mem_halt()
+     ************************************************/
+#define E_CHANALLOC                      ((ushort) 0x80)
+#define E_POLL_ALLOC                     ((ushort) 0x81)
+#define E_LTTWAKE                        ((ushort) 0x82)
+#define E_LTT_ALLOC                      ((ushort) 0x83)
+#define E_LRT_ALLOC                      ((ushort) 0x84)
+#define E_CIRRUS                         ((ushort) 0x85)
+#define E_MONITOR                        ((ushort) 0x86)
+#define E_PHB_ALLOC                      ((ushort) 0x87)
+#define E_ARRAY_ALLOC                    ((ushort) 0x88)
+#define E_QBUF_ALLOC                     ((ushort) 0x89)
+#define E_PKT_ALLOC                      ((ushort) 0x8a)
+#define E_GET_TX_Q_BUF                   ((ushort) 0x8b)
+#define E_GET_RX_Q_BUF                   ((ushort) 0x8c)
+#define E_MEM_OUT                        ((ushort) 0x8d)
+#define E_MMU_INIT                       ((ushort) 0x8e)
+#define E_LTT_INIT                       ((ushort) 0x8f)
+#define E_LRT_INIT                       ((ushort) 0x90)
+#define E_LINK_RUN                       ((ushort) 0x91)
+#define E_MONITOR_ALLOC                  ((ushort) 0x92)
+#define E_MONITOR_INIT                   ((ushort) 0x93)
+#define E_POLL_INIT                      ((ushort) 0x94)
+
+
+/*********** end of file ***********/
+
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/errors.h linux/drivers/char/rio/errors.h
--- linux-2.2.15-pre2/drivers/char/rio/errors.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/errors.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,104 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: errors.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)errors.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_errors_h__
+#define	__rio_errors_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_errors_h_sccs_ = "@(#)errors.h	1.2";
+#endif
+#endif
+
+/*
+** error codes
+*/
+
+#define	NOTHING_WRONG_AT_ALL		0
+#define	BAD_CHARACTER_IN_NAME		1
+#define	TABLE_ENTRY_ISNT_PROPERLY_NULL	2
+#define	UNKNOWN_HOST_NUMBER		3
+#define	ZERO_RTA_ID			4
+#define	BAD_RTA_ID			5
+#define	DUPLICATED_RTA_ID		6
+#define	DUPLICATE_UNIQUE_NUMBER		7
+#define	BAD_TTY_NUMBER			8
+#define	TTY_NUMBER_IN_USE		9
+#define	NAME_USED_TWICE			10
+#define	HOST_ID_NOT_ZERO		11
+#define	BOOT_IN_PROGRESS		12
+#define	COPYIN_FAILED			13
+#define	HOST_FILE_TOO_LARGE		14
+#define	COPYOUT_FAILED			15
+#define	NOT_SUPER_USER			16
+#define	RIO_ALREADY_POLLING		17
+
+#define	ID_NUMBER_OUT_OF_RANGE		18
+#define PORT_NUMBER_OUT_OF_RANGE	19
+#define	HOST_NUMBER_OUT_OF_RANGE	20
+#define	RUP_NUMBER_OUT_OF_RANGE		21
+#define	TTY_NUMBER_OUT_OF_RANGE		22
+#define	LINK_NUMBER_OUT_OF_RANGE	23
+
+#define	HOST_NOT_RUNNING		24
+#define	IOCTL_COMMAND_UNKNOWN		25
+#define	RIO_SYSTEM_HALTED		26
+#define	WAIT_FOR_DRAIN_BROKEN		27
+#define	PORT_NOT_MAPPED_INTO_SYSTEM	28
+#define	EXCLUSIVE_USE_SET		29
+#define	WAIT_FOR_NOT_CLOSING_BROKEN	30
+#define	WAIT_FOR_PORT_TO_OPEN_BROKEN	31
+#define	WAIT_FOR_CARRIER_BROKEN		32
+#define	WAIT_FOR_NOT_IN_USE_BROKEN	33
+#define	WAIT_FOR_CAN_ADD_COMMAND_BROKEN	34
+#define	WAIT_FOR_ADD_COMMAND_BROKEN	35
+#define	WAIT_FOR_NOT_PARAM_BROKEN	36
+#define	WAIT_FOR_RETRY_BROKEN		37
+#define	HOST_HAS_ALREADY_BEEN_BOOTED	38
+#define	UNIT_IS_IN_USE			39
+#define	COULDNT_FIND_ENTRY		40
+#define	RTA_UNIQUE_NUMBER_ZERO		41
+#define	CLOSE_COMMAND_FAILED		42
+#define	WAIT_FOR_CLOSE_BROKEN		43
+#define	CPS_VALUE_OUT_OF_RANGE		44
+#define	ID_ALREADY_IN_USE		45
+#define	SIGNALS_ALREADY_SET		46
+#define	NOT_RECEIVING_PROCESS		47
+#define	RTA_NUMBER_WRONG		48
+#define NO_SUCH_PRODUCT			49
+#define	HOST_SYSPORT_BAD		50
+#define	ID_NOT_TENTATIVE		51
+#define XPRINT_CPS_OUT_OF_RANGE		52
+#define	NOT_ENOUGH_CORE_FOR_PCI_COPY	53
+
+
+#endif /* __rio_errors_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/formpkt.h linux/drivers/char/rio/formpkt.h
--- linux-2.2.15-pre2/drivers/char/rio/formpkt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/formpkt.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,154 @@
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******         F O R M   P A C K E T   H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _formpkt_h
+#define _formpkt_h 1
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_formpkt_h_sccs = "@(#)formpkt.h	1.1" ;
+#endif
+#endif
+
+typedef struct FORM_BOOT_PKT_1 FORM_BOOT_PKT_1 ;
+struct FORM_BOOT_PKT_1 {
+                           ushort pkt_number ;
+                           ushort pkt_total ;
+                           ushort boot_top ;
+                       } ;
+
+typedef struct FORM_BOOT_PKT_2 FORM_BOOT_PKT_2 ;
+struct FORM_BOOT_PKT_2 {
+                           ushort pkt_number ;
+                           char   boot_data[10] ;
+                       } ;
+
+
+typedef struct FORM_ATTACH_RTA   FORM_ATTACH_RTA ;
+struct FORM_ATTACH_RTA  {
+                       char    cmd_code ;
+                       char    booter_serial[4] ;
+                       char    booter_link ;
+                       char    bootee_serial[4] ;
+                       char    bootee_link ;
+                   } ;
+
+
+typedef struct FORM_BOOT_ID   FORM_BOOT_ID ;
+struct FORM_BOOT_ID  {
+                       char    cmd_code ;
+                       char    bootee_serial[4] ;
+                       char    bootee_prod_id ;
+                       char    bootee_link ;
+                   } ;
+
+
+
+typedef struct FORM_ROUTE_1   FORM_ROUTE_1 ;
+struct FORM_ROUTE_1 {
+                        char     cmd_code ;
+                        char     pkt_number ;
+                        char     total_in_sequence ;
+                        char     unit_id ;
+                        char     host_unit_id ;
+                    } ;
+
+typedef struct FORM_ROUTE_2   FORM_ROUTE_2 ;
+struct FORM_ROUTE_2 {
+                        char   cmd_code ;
+                        char   pkt_number ;
+                        char   total_in_sequence ;
+                        char   route_data[9] ;
+                    } ;
+
+typedef struct FORM_ROUTE_REQ   FORM_ROUTE_REQ ;
+struct FORM_ROUTE_REQ {
+                          char   cmd_code ;
+                          char   pkt_number ;
+                          char   total_in_sequence ;
+                          char   route_data[10] ;
+                      } ;
+
+
+typedef struct FORM_ERROR   FORM_ERROR ;
+struct FORM_ERROR {
+                        char   cmd_code ;
+                        char   error_code ;
+
+                    } ;
+
+typedef struct FORM_STATUS   FORM_STATUS ;
+struct FORM_STATUS {
+                        char   cmd_code ;
+                        char   status_code ;
+                        char   last_packet_valid ;
+                        char   tx_buffer ;
+                        char   rx_buffer ;
+                        char   port_status ;
+                        char   phb_status ;
+                    } ;
+
+
+typedef struct FORM_LINK_STATUS   FORM_LINK_STATUS ;
+struct FORM_LINK_STATUS {
+                        char    cmd_code ;
+                        char    status_code ;
+                        char    link_number ;
+                        ushort  rx_errors ;
+                        ushort  tx_errors ;
+                        ushort  csum_errors ;
+                        ushort  disconnects ;
+                    } ;
+
+
+
+typedef struct FORM_PARTITION FORM_PARTITION ;
+struct FORM_PARTITION {
+                        char    cmd_code ;
+                        char    status_code ;
+                        char    port_number ;
+                        char    tx_max ;
+                        char    rx_max ;
+                        char    rx_limit ;
+                      } ;
+
+
+#endif
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/func.h linux/drivers/char/rio/func.h
--- linux-2.2.15-pre2/drivers/char/rio/func.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/func.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,171 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: func.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)func.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __func_h_def
+#define __func_h_def
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_func_h_sccs_ = "@(#)func.h	1.3";
+#endif
+#endif
+
+/* rioboot.c */
+int RIOBootCodeRTA(struct rio_info *, struct DownLoad *);
+int RIOBootCodeHOST(struct rio_info *, register struct DownLoad *);
+int RIOBootCodeUNKNOWN(struct rio_info *, struct DownLoad *);
+void msec_timeout(struct Host *);
+int RIOBootRup(struct rio_info *, uint, struct Host *, struct PKT *);
+int RIOBootComplete(struct rio_info *, struct Host *, uint, struct PktCmd *);
+int RIOBootOk(struct rio_info *,struct Host *, ulong);
+int RIORtaBound(struct rio_info *, uint); 
+void FillSlot(int, int, uint, struct Host *);
+
+/* riocmd.c */
+int RIOFoadRta(struct Host *, struct Map *);
+int RIOZombieRta(struct Host *, struct Map *);
+int RIOCommandRta(struct rio_info *, uint, int (* func)( struct Host *, 
+								struct Map *));
+int RIOIdentifyRta(struct rio_info *, caddr_t); 
+int RIOKillNeighbour(struct rio_info *, caddr_t);
+int RIOSuspendBootRta(struct Host *, int, int);
+int RIOFoadWakeup(struct rio_info *);
+int RIOCommandRup(struct rio_info *, uint, struct Host *, struct PKT *);
+struct CmdBlk * RIOGetCmdBlk(void);
+void RIOFreeCmdBlk(struct CmdBlk *);
+int RIOQueueCmdBlk(struct Host *, uint, struct CmdBlk *);
+void RIOPollHostCommands(struct rio_info *, struct Host *);
+int RIOStrlen(register char *);
+int RIOStrCmp(register char *, register char *);
+int RIOStrnCmp(register char *, register char *, int);
+void  RIOStrNCpy(char *, char *, int);
+int RIOWFlushMark(int, struct CmdBlk *);
+int RIORFlushEnable(int, struct CmdBlk *);
+int RIOUnUse(int, struct CmdBlk *);
+void ShowPacket(uint, struct PKT *);
+
+/* rioctrl.c */
+int copyin(int, caddr_t, int);
+int copyout(caddr_t, int, int);
+int riocontrol(struct rio_info *, dev_t,int,caddr_t,int); 
+int RIOPreemptiveCmd(struct rio_info *,struct Port *,uchar);
+
+/* rioinit.c */
+void rioinit(struct rio_info *, struct RioHostInfo *);
+void RIOInitHosts(struct rio_info *, struct RioHostInfo *);
+void RIOISAinit(struct rio_info *,int);
+int RIODoAT(struct rio_info *, int, int);
+caddr_t RIOCheckForATCard(int);
+int RIOAssignAT(struct rio_info *, int, caddr_t, int);
+int RIOBoardTest(paddr_t, caddr_t, uchar, int);
+int RIOScrub(int, BYTE *, int);
+void RIOAllocateInterrupts(struct rio_info *);
+void RIOStopInterrupts(struct rio_info *, int, int);
+void RIOAllocDataStructs(struct rio_info *);
+void RIOSetupDataStructs(struct rio_info *);
+int RIODefaultName(struct rio_info *, struct Host *, uint);
+int RIOReport(struct rio_info *);
+struct rioVersion * RIOVersid(void);
+int RIOMapin(paddr_t, int, caddr_t *);
+void RIOMapout(paddr_t, long, caddr_t);
+void RIOHostReset(uint, volatile struct DpRam *, uint);
+
+/* riointr.c */
+void riopoll(struct rio_info *);
+void riointr(struct rio_info *);
+void RIOTxEnable(char *);
+void RIOServiceHost(struct rio_info *, struct Host *, int);
+void RIOReceive(struct rio_info *, struct Port *);
+int riotproc(struct rio_info *, register struct ttystatics *, int, int);
+
+/* rioparam.c */
+int RIOParam(struct Port *, int, int, int);
+int RIODelay(struct Port *PortP, int);
+int RIODelay_ni(struct Port *PortP, int);
+void ms_timeout(struct Port *);
+int can_add_transmit(struct PKT **, struct Port *);
+void add_transmit(struct Port *);
+void put_free_end(struct Host *, struct PKT *);
+int can_remove_receive(struct PKT **, struct Port *);
+void remove_receive(struct Port *);
+
+/* rioroute.c */
+int RIORouteRup(struct rio_info *, uint, struct Host *, struct PKT *);
+void RIOFixPhbs(struct rio_info *, struct Host *, uint); 
+int RIOCheckIsolated(struct rio_info *, struct Host *, uint);
+int RIOIsolate(struct rio_info *, struct Host *, uint);
+int RIOCheck(struct Host *, uint);
+uint GetUnitType(uint);
+int RIOSetChange(struct rio_info *);
+void RIOConCon(struct rio_info *, struct Host *, uint, uint, uint, uint, int);
+int RIOFindFreeID(struct rio_info *, struct Host *, uint *, uint *);
+int RIOFreeDisconnected(struct rio_info *, struct Host *, int );
+int RIORemoveFromSavedTable(struct rio_info *, struct Map *);
+
+
+/* riotty.c */
+
+int riotopen(struct tty_struct * tty, struct file * filp);
+int riotclose(void  *ptr);
+int RIOCookMode(struct ttystatics *);
+int riotioctl(struct rio_info *, dev_t, register int, register caddr_t); 
+void ttyseth(struct Port *, struct ttystatics *, struct old_sgttyb *sg);
+
+/* riotable.c */
+int RIONewTable(struct rio_info *);
+int RIOApel(struct rio_info *);
+int RIODeleteRta(struct rio_info *, struct Map *);
+int RIOAssignRta(struct rio_info *, struct Map *);
+int RIOReMapPorts(struct rio_info *, struct Host *, struct Map *);
+int RIOChangeName(struct rio_info *, struct Map*);
+
+#if 0
+/* riodrvr.c */
+struct rio_info * rio_install(struct RioHostInfo *);
+int rio_uninstall(register struct rio_info *);
+int rio_open(struct rio_info *, int, struct file *);
+int rio_close(struct rio_info *, struct file *);
+int rio_read(struct rio_info *, struct file *, char *, int);
+int rio_write(struct rio_info *, struct file *	f, char *, int);
+int rio_ioctl(struct rio_info *, struct file *, int, char *);
+int rio_select(struct rio_info *, struct file *	f, int, struct sel *);
+int	rio_intr(char *);
+int rio_isr_thread(char  *);
+struct rio_info * rio_info_store( int cmd, struct rio_info * p);
+#endif
+
+extern int    rio_pcicopy(char *src, char *dst, int n);
+extern int rio_minor (kdev_t device);
+extern int rio_ismodem (kdev_t device);
+extern void rio_udelay (int usecs);
+
+#endif	/* __func_h_def */
diff -urN linux-2.2.15-pre2/drivers/char/rio/host.h linux/drivers/char/rio/host.h
--- linux-2.2.15-pre2/drivers/char/rio/host.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/host.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,134 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: host.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)host.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_host_h__
+#define __rio_host_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_host_h_sccs_ = "@(#)host.h	1.2";
+#endif
+#endif
+
+/*
+** the host structure - one per host card in the system.
+*/
+
+#define	MAX_EXTRA_UNITS	64
+
+/*
+**    Host data structure. This is used for the software equiv. of
+**    the host.
+*/
+struct    Host
+{
+    uchar             	    Type;      /* RIO_EISA, RIO_MCA, ... */
+    uchar             	    Ivec;      /* POLLED or ivec number */
+    uchar             	    Mode;      /* Control stuff */
+    uchar                   Slot;      /* Slot */
+    volatile caddr_t        Caddr;     /* KV address of DPRAM */
+    volatile struct DpRam   *CardP;    /* KV address of DPRAM, with overlay */
+    paddr_t          	    PaddrP;    /* Phys. address of DPRAM */
+    char                    Name[MAX_NAME_LEN];  /* The name of the host */
+    uint            	    UniqueNum; /* host unique number */
+    semtype	    HostLock;  /* Lock structure for MPX */
+    /*struct pci_devinfo	    PciDevInfo; *//* PCI Bus/Device/Function stuff */
+    /*struct lockb	    HostLock;  *//* Lock structure for MPX */
+    uint                    WorkToBeDone; /* set to true each interrupt */
+    uint                    InIntr;    /* Being serviced? */
+    uint                    IntSrvDone;	/* host's interrupt has been serviced */
+    int			    (*Copy)( caddr_t, caddr_t, int ); /* copy func */
+    struct timer_list timer;
+    /*
+    **               I M P O R T A N T !
+    **
+    ** The rest of this data structure is cleared to zero after
+    ** a RIO_HOST_FOAD command.
+    */
+    
+    ulong                   Flags;     /* Whats going down */
+#define RC_WAITING            0
+#define RC_STARTUP            1
+#define RC_RUNNING            2
+#define RC_STUFFED            3
+#define RC_SOMETHING          4
+#define RC_SOMETHING_NEW      5
+#define RC_SOMETHING_ELSE     6
+#define RC_READY              7
+#define RUN_STATE             7
+/*
+** Boot mode applies to the way in which hosts in this system will
+** boot RTAs
+*/
+#define RC_BOOT_ALL           0x8	/* Boot all RTAs attached */
+#define RC_BOOT_OWN           0x10	/* Only boot RTAs bound to this system */
+#define RC_BOOT_NONE          0x20	/* Don't boot any RTAs (slave mode) */
+
+    struct Top		    Topology[LINKS_PER_UNIT]; /* one per link */
+    struct Map              Mapping[MAX_RUP];     /* Mappings for host */
+    struct PHB		    *PhbP;                /* Pointer to the PHB array */
+    ushort           	    *PhbNumP;             /* Ptr to Number of PHB's */
+    struct LPB 	            *LinkStrP ;           /* Link Structure Array */
+    struct RUP       	    *RupP;                /* Sixteen real rups here */
+    struct PARM_MAP  	    *ParmMapP;            /* points to the parmmap */
+    uint                    ExtraUnits[MAX_EXTRA_UNITS]; /* unknown things */
+    uint                    NumExtraBooted;       /* how many of the above */
+    /*
+    ** Twenty logical rups.
+    ** The first sixteen are the real Rup entries (above), the last four
+    ** are the link RUPs.
+    */
+    struct UnixRup	    UnixRups[MAX_RUP+LINKS_PER_UNIT];
+	int				timeout_id;	/* For calling 100 ms delays */
+	int				timeout_sem;/* For calling 100 ms delays */
+    int locks;
+    char             	    ____end_marker____;
+};
+#define Control      CardP->DpControl
+#define SetInt       CardP->DpSetInt
+#define ResetTpu     CardP->DpResetTpu
+#define ResetInt     CardP->DpResetInt
+#define Signature    CardP->DpSignature
+#define Sram1        CardP->DpSram1
+#define Sram2        CardP->DpSram2
+#define Sram3        CardP->DpSram3
+#define Scratch      CardP->DpScratch
+#define __ParmMapR   CardP->DpParmMapR
+#define SLX          CardP->DpSlx
+#define Revision     CardP->DpRevision
+#define Unique       CardP->DpUnique
+#define Year         CardP->DpYear
+#define Week         CardP->DpWeek
+
+#define RIO_DUMBPARM 0x0860    /* what not to expect */
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/hosthw.h linux/drivers/char/rio/hosthw.h
--- linux-2.2.15-pre2/drivers/char/rio/hosthw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/hosthw.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,57 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                H O S T      H A R D W A R E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_hosthw_h_sccs = "@(#)hosthw.h	1.2" ;
+#endif
+#endif
+
+#define SET_OTHER_INTERRUPT  ( (volatile u_short *) 0x7c80 )
+#define SET_EISA_INTERRUPT  ( (volatile u_short *) 0x7ef0 )
+
+#define EISA_HOST    0x30
+#define AT_HOST      0xa0
+#define MCA_HOST     0xb0
+#define PCI_HOST     0xd0
+
+#define PRODUCT_MASK 0xf0
+
+
+/*********** end of file ***********/
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/link.h linux/drivers/char/rio/link.h
--- linux-2.2.15-pre2/drivers/char/rio/link.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/link.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,188 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L I N K
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _link_h
+#define _link_h 1
+
+#ifndef lint
+#ifdef SCCS_LABELS
+/* static char *_rio_link_h_sccs = "@(#)link.h	1.15"; */
+#endif
+#endif
+
+
+
+/*************************************************
+ * Define the Link Status stuff
+ ************************************************/
+#define LRT_ACTIVE         ((ushort) 0x01)
+#define LRT_SPARE1         ((ushort) 0x02)
+#define INTRO_RCVD         ((ushort) 0x04)
+#define FORCED_DISCONNECT  ((ushort) 0x08)
+#define LRT_SPARE2	   ((ushort) 0x80)
+
+#define TOP_OF_RTA_RAM     ((ushort) 0x7000)
+#define HOST_SERIAL_POINTER (unsigned char **) (TOP_OF_RTA_RAM - 2 * sizeof (ushort))
+
+/* Flags for ltt_status */
+#define  WAITING_ACK		(ushort) 0x0001
+#define  DATA_SENT		(ushort) 0x0002
+#define  WAITING_RUP		(ushort) 0x0004
+#define  WAITING_RETRY		(ushort) 0x0008
+#define  WAITING_TOPOLOGY	(ushort) 0x0010
+#define  SEND_SYNC		(ushort) 0x0020
+#define  FOAD_THIS_LINK		(ushort) 0x0040
+#define  REQUEST_SYNC		(ushort) 0x0080
+#define  REMOTE_DYING		(ushort) 0x0100
+#define  DIE_NOW		(ushort) 0x0200
+
+/* Boot request stuff */
+#define BOOT_REQUEST       ((ushort) 0)    /* Request for a boot */
+#define BOOT_ABORT         ((ushort) 1)    /* Abort a boot */
+#define BOOT_SEQUENCE      ((ushort) 2)    /* Packet with the number of packets
+                                              and load address */
+#define BOOT_COMPLETED     ((ushort) 3)    /* Boot completed */
+
+/* States that a link can be in */
+#define	LINK_DISCONNECTED  ((ushort) 0)    /* Disconnected */
+#define LINK_BOOT1         ((ushort) 1)    /* Trying to send 1st stage boot */
+#define LINK_BOOT2         ((ushort) 2)    /* Trying to send 2nd stage boot */
+#define LINK_BOOT2WAIT     ((ushort) 3)    /* Waiting for selftest results */
+#define LINK_BOOT3         ((ushort) 4)    /* Trying to send 3rd stage boots */
+#define LINK_SYNC          ((ushort) 5)    /* Syncing */
+
+#define LINK_INTRO         ((ushort) 10)    /* Introductory packet */
+#define LINK_SUPPLYID      ((ushort) 11)    /* Trying to supply an ID */
+#define LINK_TOPOLOGY      ((ushort) 12)    /* Send a topology update */
+#define LINK_REQUESTID     ((ushort) 13)    /* Waiting for an ID */
+#define LINK_CONNECTED     ((ushort) 14)    /* Connected */
+
+#define LINK_INTERCONNECT  ((ushort) 20)   /* Subnets interconnected */
+
+#define LINK_SPARE	   ((ushort) 40)
+
+/*
+** Set the default timeout for link communications.
+*/
+#define	LINKTIMEOUT		(400 * MILLISECOND)
+
+/*
+** LED stuff
+*/
+#if defined(RTA)
+#define LED_OFF            ((ushort) 0)    /* LED off */
+#define LED_RED            ((ushort) 1)    /* LED Red */
+#define LED_GREEN          ((ushort) 2)    /* LED Green */
+#define LED_ORANGE         ((ushort) 4)    /* LED Orange */
+#define LED_1TO8_OPEN      ((ushort) 1)    /* Port 1->8 LED on */
+#define LED_9TO16_OPEN     ((ushort) 2)    /* Port 9->16 LED on */
+#define LED_SET_COLOUR(colour)	(link->led = (colour))
+#define LED_OR_COLOUR(colour)	(link->led |= (colour))
+#define LED_TIMEOUT(time)    (link->led_timeout = RioTimePlus(RioTime(),(time)))
+#else
+#define LED_SET_COLOUR(colour)
+#define LED_OR_COLOUR(colour)
+#define LED_TIMEOUT(time)
+#endif /* RTA */
+
+struct LPB {
+               WORD          link_number ;       /* Link Number */
+               Channel_ptr   in_ch ;             /* Link In Channel */
+               Channel_ptr   out_ch ;            /* Link Out Channel */
+#ifdef RTA
+               uchar        stat_led ;          /* Port open leds */
+               uchar        led ;               /* True, light led! */
+#endif
+               BYTE attached_serial[4]; /* Attached serial number */
+               BYTE attached_host_serial[4];
+                                                 /* Serial number of Host who
+                                                    booted the other end */
+               WORD          descheduled ;       /* Currently Descheduled */
+               WORD          state;              /* Current state */
+               WORD          send_poll ;         /* Send a Poll Packet */
+               Process_ptr   ltt_p ;             /* Process Descriptor */
+               Process_ptr   lrt_p ;             /* Process Descriptor */
+               WORD          lrt_status ;        /* Current lrt status */
+               WORD          ltt_status ;        /* Current ltt status */
+               WORD          timeout ;           /* Timeout value */
+               WORD          topology;           /* Topology bits */
+               WORD          mon_ltt ;
+               WORD          mon_lrt ;
+               WORD          WaitNoBoot ;	 /* Secs to hold off booting */
+               PKT_ptr       add_packet_list;    /* Add packets to here */
+               PKT_ptr       remove_packet_list; /* Send packets from here */
+#ifdef RTA
+#ifdef DCIRRUS
+#define    QBUFS_PER_REDIRECT (4 / PKTS_PER_BUFFER + 1) 
+#else
+#define    QBUFS_PER_REDIRECT (8 / PKTS_PER_BUFFER + 1) 
+#endif
+               PKT_ptr_ptr   rd_add ;            /* Add a new Packet here */
+               Q_BUF_ptr     rd_add_qb;          /* Pointer to the add Q buf */
+               PKT_ptr_ptr   rd_add_st_qbb ;     /* Pointer to start of the Q's buf */
+               PKT_ptr_ptr   rd_add_end_qbb ;    /* Pointer to the end of the Q's buf */
+               PKT_ptr_ptr   rd_remove ;         /* Remove a Packet here */
+               Q_BUF_ptr     rd_remove_qb ;      /* Pointer to the remove Q buf */
+               PKT_ptr_ptr   rd_remove_st_qbb ;  /* Pointer to the start of the Q buf */
+               PKT_ptr_ptr   rd_remove_end_qbb ; /* Pointer to the end of the Q buf */
+               ushort        pkts_in_q ;         /* Packets in queue */
+#endif
+
+               Channel_ptr   lrt_fail_chan ;     /* Lrt's failure channel */
+               Channel_ptr   ltt_fail_chan ;     /* Ltt's failure channel */
+
+#if defined (HOST) || defined (INKERNEL)
+ /* RUP structure for HOST to driver communications */
+               struct RUP           rup ;              
+#endif
+               struct RUP           link_rup;           /* RUP for the link (POLL,
+                                                    topology etc.) */
+               WORD          attached_link ;     /* Number of attached link */
+               WORD          csum_errors ;       /* csum errors */
+               WORD          num_disconnects ;   /* number of disconnects */
+               WORD          num_sync_rcvd ;     /* # sync's received */
+               WORD          num_sync_rqst ;     /* # sync requests */
+               WORD          num_tx ;            /* Num pkts sent */
+               WORD          num_rx ;            /* Num pkts received */
+               WORD          module_attached;    /* Module tpyes of attached */
+               WORD          led_timeout;        /* LED timeout */
+               WORD          first_port;         /* First port to service */
+               WORD          last_port;          /* Last port to service */
+           } ;
+
+#endif
+
+/*********** end of file ***********/
diff -urN linux-2.2.15-pre2/drivers/char/rio/linux_compat.h linux/drivers/char/rio/linux_compat.h
--- linux-2.2.15-pre2/drivers/char/rio/linux_compat.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/linux_compat.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,128 @@
+/*
+ * (C) 2000 R.E.Wolff@BitWizard.nl
+ *
+ *      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.
+ */
+
+
+#define disable(oldspl) save_flags (oldspl)
+#define restore(oldspl) restore_flags (oldspl)
+
+#define sysbrk(x) kmalloc ((x), GFP_KERNEL)
+#define sysfree(p,size) kfree ((p))
+
+#define WBYTE(p,v) writeb(v, &p)
+#define RBYTE(p)   readb (&p)
+#define WWORD(p,v) writew(v, &p)
+#define RWORD(p)   readw(&p)
+#define WINDW(p,v) writew(v, p)
+#define RINDW(p)   readw(p)
+
+#define DEBUG_ALL
+
+#define cprintf printk
+
+#ifdef __KERNEL__
+#define INKERNEL
+#endif
+
+struct ttystatics {
+  struct termios tm;
+};
+
+#define bzero(d, n)         memset((d), 0, (n))
+#define bcopy(src, dest, n) memcpy ((dest), (src), (n))
+
+#define SEM_SIGIGNORE 0x1234
+
+typedef struct semaphore semtype;
+
+
+#ifdef DEBUG_SEM
+#define swait(a,b)      printk ("waiting:    " __FILE__ " line %d\n", __LINE__)
+#define ssignal(sem)    printk ("signalling: " __FILE__ " line %d\n", __LINE__)
+
+#define sreset(sem)     printk ("sreset:     " __FILE__ "\n")
+#define sem_init(sem,v) printk ("sreset:     " __FILE__ "\n")
+#endif
+
+
+#define getpid()    (current->pid)
+
+#define major(dev) MAJOR(dev)
+#define minor(dev) MINOR(dev)
+
+#define QSIZE SERIAL_XMIT_SIZE
+
+#define pseterr(errno) return (- errno)
+
+#define V_CBAUD CBAUD
+
+/* For one reason or another rioboot.c uses delay instead of RIODelay. */
+#define delay(x,y) RIODelay(NULL, y)
+
+extern int rio_debug;
+
+#define rio_dprint(f, p) do {if (rio_debug & f) printk p;} while (0)
+
+#define RIO_DEBUG_INIT         0x000001
+#define RIO_DEBUG_BOOT         0x000002
+#define RIO_DEBUG_CMD          0x000004
+#define RIO_DEBUG_CTRL         0x000008
+#define RIO_DEBUG_INTR         0x000010
+#define RIO_DEBUG_PARAM        0x000020
+#define RIO_DEBUG_ROUTE        0x000040
+#define RIO_DEBUG_TABLE        0x000080
+#define RIO_DEBUG_TTY          0x000100
+#define RIO_DEBUG_FLOW         0x000200
+#define RIO_DEBUG_MODEMSIGNALS 0x000400
+#define RIO_DEBUG_PROBE        0x000800
+#define RIO_DEBUG_CLEANUP      0x001000
+#define RIO_DEBUG_IFLOW        0x002000
+#define RIO_DEBUG_PFE          0x004000
+#define RIO_DEBUG_REC          0x008000
+#define RIO_DEBUG_SPINLOCK     0x010000
+#define RIO_DEBUG_DELAY        0x020000
+
+
+/* Copied over from riowinif.h . This is ugly. The winif file declares
+also much other stuff which is incompatible with the headers from
+the older driver. The older driver includes "brates.h" which shadows
+the definitions from Linux, and is incompatible... */
+
+/* RxBaud and TxBaud definitions... */
+#define	RIO_B0			0x00			/* RTS / DTR signals dropped */
+#define	RIO_B50			0x01			/* 50 baud */
+#define	RIO_B75			0x02			/* 75 baud */
+#define	RIO_B110		0x03			/* 110 baud */
+#define	RIO_B134		0x04			/* 134.5 baud */
+#define	RIO_B150		0x05			/* 150 baud */
+#define	RIO_B200		0x06			/* 200 baud */
+#define	RIO_B300		0x07			/* 300 baud */
+#define	RIO_B600		0x08			/* 600 baud */
+#define	RIO_B1200		0x09			/* 1200 baud */
+#define	RIO_B1800		0x0A			/* 1800 baud */
+#define	RIO_B2400		0x0B			/* 2400 baud */
+#define	RIO_B4800		0x0C			/* 4800 baud */
+#define	RIO_B9600		0x0D			/* 9600 baud */
+#define	RIO_B19200		0x0E			/* 19200 baud */
+#define	RIO_B38400		0x0F			/* 38400 baud */
+#define	RIO_B56000		0x10			/* 56000 baud */
+#define	RIO_B57600		0x11			/* 57600 baud */
+#define	RIO_B64000		0x12			/* 64000 baud */
+#define	RIO_B115200		0x13			/* 115200 baud */
+#define	RIO_B2000		0x14			/* 2000 baud */
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/list.h linux/drivers/char/rio/list.h
--- linux-2.2.15-pre2/drivers/char/rio/list.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/list.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,196 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L I S T                                 *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls.
+ Date    : 04-Nov-1990
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+ ***************************************************************************/
+
+#ifndef _list_h
+#define _list_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_rio_list_h_sccs = "@(#)list.h	1.9" ;
+#endif
+#endif
+
+#define PKT_IN_USE    0x1
+
+#ifdef INKERNEL
+
+#define ZERO_PTR (ushort) 0x8000
+#define	CaD	PortP->Caddr
+
+/*
+** We can add another packet to a transmit queue if the packet pointer pointed
+** to by the TxAdd pointer has PKT_IN_USE clear in its address.
+*/
+
+#ifndef linux
+#if defined( MIPS ) && !defined( MIPSEISA )
+/* May the shoes of the Devil dance on your grave for creating this */
+#define   can_add_transmit(PacketP,PortP) \
+          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
+          & (PKT_IN_USE<<2)))
+
+#elif  defined(MIPSEISA) || defined(nx6000) || \
+       defined(drs6000)  || defined(UWsparc)
+
+#define   can_add_transmit(PacketP,PortP) \
+          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
+	  & PKT_IN_USE))
+
+#else
+#define   can_add_transmit(PacketP,PortP) \
+          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,*PortP->TxAdd)) \
+	  & PKT_IN_USE))
+#endif
+
+/*
+** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
+** and then move the TxAdd pointer along one position to point to the next
+** packet pointer. You must wrap the pointer from the end back to the start.
+*/
+#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
+#   define add_transmit(PortP)  \
+	WINDW(PortP->TxAdd,RINDW(PortP->TxAdd) | PKT_IN_USE);\
+	if (PortP->TxAdd == PortP->TxEnd)\
+	    PortP->TxAdd = PortP->TxStart;\
+	else\
+	    PortP->TxAdd++;\
+	WWORD(PortP->PhbP->tx_add , RIO_OFF(CaD,PortP->TxAdd));
+#elif defined(AIX)
+#   define add_transmit(PortP)  \
+	{\
+	    register ushort *TxAddP = (ushort *)RIO_PTR(Cad,PortP->TxAddO);\
+	    WINDW( TxAddP, RINDW( TxAddP ) | PKT_IN_USE );\
+	    if (PortP->TxAddO == PortP->TxEndO )\
+		PortP->TxAddO = PortP->TxStartO;\
+	    else\
+		PortP->TxAddO += sizeof(ushort);\
+	    WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->tx_add , PortP->TxAddO );\
+	}
+#else
+#   define add_transmit(PortP)  \
+	*PortP->TxAdd |= PKT_IN_USE;\
+	if (PortP->TxAdd == PortP->TxEnd)\
+	    PortP->TxAdd = PortP->TxStart;\
+	else\
+	    PortP->TxAdd++;\
+	PortP->PhbP->tx_add = RIO_OFF(CaD,PortP->TxAdd);
+#endif
+
+/*
+** can_remove_receive( PacketP, PortP ) returns non-zero if PKT_IN_USE is set
+** for the next packet on the queue. It will also set PacketP to point to the
+** relevent packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
+** then can_remove_receive() returns 0.
+*/
+#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
+#   define can_remove_receive(PacketP,PortP) \
+	((RINDW(PortP->RxRemove) & PKT_IN_USE) ? \
+	(PacketP=(struct PKT *)RIO_PTR(CaD,(RINDW(PortP->RxRemove) & ~PKT_IN_USE))):0)
+#elif defined(AIX)
+#   define can_remove_receive(PacketP,PortP) \
+	((RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & PKT_IN_USE) ? \
+	(PacketP=(struct PKT *)RIO_PTR(Cad,RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & ~PKT_IN_USE)):0)
+#else
+#   define can_remove_receive(PacketP,PortP) \
+	((*PortP->RxRemove & PKT_IN_USE) ? \
+	(PacketP=(struct PKT *)RIO_PTR(CaD,(*PortP->RxRemove & ~PKT_IN_USE))):0)
+#endif
+
+
+/*
+** Will God see it within his heart to forgive us for this thing that
+** we have created? To remove a packet from the receive queue you clear
+** its PKT_IN_USE bit, and then bump the pointers. Once the pointers
+** get to the end, they must be wrapped back to the start.
+*/
+#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
+#   define remove_receive(PortP) \
+	WINDW(PortP->RxRemove, (RINDW(PortP->RxRemove) & ~PKT_IN_USE));\
+	if (PortP->RxRemove == PortP->RxEnd)\
+	    PortP->RxRemove = PortP->RxStart;\
+	else\
+	    PortP->RxRemove++;\
+	WWORD(PortP->PhbP->rx_remove , RIO_OFF(CaD,PortP->RxRemove));
+#elif defined(AIX)
+#   define remove_receive(PortP) \
+    {\
+        register ushort *RxRemoveP = (ushort *)RIO_PTR(Cad,PortP->RxRemoveO);\
+        WINDW( RxRemoveP, RINDW( RxRemoveP ) & ~PKT_IN_USE );\
+        if (PortP->RxRemoveO == PortP->RxEndO)\
+            PortP->RxRemoveO = PortP->RxStartO;\
+        else\
+            PortP->RxRemoveO += sizeof(ushort);\
+        WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->rx_remove, PortP->RxRemoveO );\
+    }
+#else
+#   define remove_receive(PortP) \
+	*PortP->RxRemove &= ~PKT_IN_USE;\
+	if (PortP->RxRemove == PortP->RxEnd)\
+	    PortP->RxRemove = PortP->RxStart;\
+	else\
+	    PortP->RxRemove++;\
+	PortP->PhbP->rx_remove = RIO_OFF(CaD,PortP->RxRemove);
+#endif
+#endif
+
+
+#else /* !IN_KERNEL */
+
+#define ZERO_PTR NULL
+
+
+#ifdef HOST
+/* #define can_remove_transmit(pkt,phb) ((((char*)pkt = (*(char**)(phb->tx_remove))-1) || 1)) && (*phb->u3.s2.tx_remove_ptr & PKT_IN_USE))   */
+#define remove_transmit(phb) *phb->u3.s2.tx_remove_ptr &= ~(ushort)PKT_IN_USE;\
+                             if (phb->tx_remove == phb->tx_end)\
+                                phb->tx_remove = phb->tx_start;\
+                             else\
+                                phb->tx_remove++;
+#define can_add_receive(phb) !(*phb->u4.s2.rx_add_ptr & PKT_IN_USE)
+#define add_receive(pkt,phb) *phb->rx_add = pkt;\
+                             *phb->u4.s2.rx_add_ptr |= PKT_IN_USE;\
+                             if (phb->rx_add == phb->rx_end)\
+                                phb->rx_add = phb->rx_start;\
+                             else\
+                                phb->rx_add++;
+#endif
+#endif
+
+#ifdef RTA
+#define splx(oldspl)    if ((oldspl) == 0) spl0()
+#endif
+
+#endif /* ifndef _list.h */
+/*********** end of file ***********/
diff -urN linux-2.2.15-pre2/drivers/char/rio/lrt.h linux/drivers/char/rio/lrt.h
--- linux-2.2.15-pre2/drivers/char/rio/lrt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/lrt.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,55 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L R T
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_lrt_h_sccs = "@(#)lrt.h	1.1" ;
+#endif
+#endif
+
+
+#ifdef DCIRRUS
+#define LRT_STACK       (unsigned short) 600
+#else
+#define LRT_STACK        (ushort) 200
+#endif
+
+
+
+/*********** end of file ***********/
+
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/ltt.h linux/drivers/char/rio/ltt.h
--- linux-2.2.15-pre2/drivers/char/rio/ltt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/ltt.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,55 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L T T
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_ltt_h_sccs = "@(#)ltt.h	1.1" ;
+#endif
+#endif
+
+#ifdef DCIRRUS
+#define LTT_STACK       (unsigned short)  600
+#else
+#define LTT_STACK       (ushort) 200
+#endif
+ 
+
+
+
+/*********** end of file ***********/
+
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/lttwake.h linux/drivers/char/rio/lttwake.h
--- linux-2.2.15-pre2/drivers/char/rio/lttwake.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/lttwake.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,53 @@
+
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******            L T T    W A K E U P    H E A D E R
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_lttwake_h_sccs = "@(#)lttwake.h	1.1" ;
+#endif
+#endif
+
+#define LTT_WAKEUP_STACK          500
+#define LTT_WAKEUP_INTERVAL       (int) (500 * MILLISECOND)
+
+
+/*********** end of file ***********/
+
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/map.h linux/drivers/char/rio/map.h
--- linux-2.2.15-pre2/drivers/char/rio/map.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/map.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,103 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: map.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:11
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)map.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_map_h__
+#define __rio_map_h__
+
+#ifdef SCCS_LABELS
+static char *_map_h_sccs_ = "@(#)map.h	1.2";
+#endif
+
+/*
+** mapping structure passed to and from the config.rio program to
+** determine the current topology of the world
+*/
+
+#define MAX_MAP_ENTRY 17
+#define	TOTAL_MAP_ENTRIES (MAX_MAP_ENTRY*RIO_SLOTS)
+#define	MAX_NAME_LEN 32
+
+struct Map
+{
+	uint	HostUniqueNum;	        /* Supporting hosts unique number */
+	uint	RtaUniqueNum;	        /* Unique number */
+	/*
+	** The next two IDs must be swapped on big-endian architectures
+	** when using a v2.04 /etc/rio/config with a v3.00 driver (when
+	** upgrading for example).
+	*/
+	ushort	ID;			/* ID used in the subnet */
+	ushort	ID2;			/* ID of 2nd block of 8 for 16 port */
+	ulong	Flags;			/* Booted, ID Given, Disconnected */
+	ulong	SysPort;		/* First tty mapped to this port */
+	struct Top   Topology[LINKS_PER_UNIT];	/* ID connected to each link */
+	char	Name[MAX_NAME_LEN];        /* Cute name by which RTA is known */
+};
+
+/*
+** Flag values:
+*/
+#define	RTA_BOOTED		0x00000001
+#define RTA_NEWBOOT		0x00000010
+#define	MSG_DONE		0x00000020
+#define	RTA_INTERCONNECT	0x00000040
+#define	RTA16_SECOND_SLOT	0x00000080
+#define	BEEN_HERE		0x00000100
+#define SLOT_TENTATIVE		0x40000000
+#define SLOT_IN_USE		0x80000000
+
+/*
+** HostUniqueNum is the unique number from the host card that this RTA
+** is to be connected to.
+** RtaUniqueNum is the unique number of the RTA concerned. It will be ZERO
+** if the slot in the table is unused. If it is the same as the HostUniqueNum
+** then this slot represents a host card.
+** Flags contains current boot/route state info
+** SysPort is a value in the range 0-504, being the number of the first tty
+** on this RTA. Each RTA supports 8 ports. The SysPort value must be modulo 8.
+** SysPort 0-127 correspond to /dev/ttyr001 to /dev/ttyr128, with minor
+** numbers 0-127. SysPort 128-255 correspond to /dev/ttyr129 to /dev/ttyr256,
+** again with minor numbers 0-127, and so on for SysPorts 256-383 and 384-511
+** ID will be in the range 0-16 for a `known' RTA. ID will be 0xFFFF for an
+** unused slot/unknown ID etc.
+** The Topology array contains the ID of the unit connected to each of the
+** four links on this unit. The entry will be 0xFFFF if NOTHING is connected
+** to the link, or will be 0xFF00 if an UNKNOWN unit is connected to the link.
+** The Name field is a null-terminated string, upto 31 characters, containing
+** the 'cute' name that the sysadmin/users know the RTA by. It is permissible
+** for this string to contain any character in the range \040 to \176 inclusive.
+** In particular, ctrl sequences and DEL (0x7F, \177) are not allowed. The
+** special character '%' IS allowable, and needs no special action.
+**
+*/
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/mca.h linux/drivers/char/rio/mca.h
--- linux-2.2.15-pre2/drivers/char/rio/mca.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/mca.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,73 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: mca.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:11
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)mca.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_mca_h__
+#define	__rio_mca_h__
+
+#ifdef SCCS_LABELS
+static char *_mca_h_sccs_ = "@(#)mca.h	1.2";
+#endif
+
+/*
+** Micro Channel stuff
+*/
+
+#define	McaMaxSlots	8
+#define McaSlotSelect	0x96
+#define	McaSlotEnable	0x08
+#define	McaIdLow	0x100
+#define	McaIdHigh	0x101
+#define	McaIrqEnable	0x102
+#define	McaMemory	0x103
+#define McaRIOId	0x6a5c
+#define	McaIrq9		0x00
+#define	McaIrq3		0x02
+#define	McaIrq4		0x04
+#define	McaIrq7		0x06
+#define	McaIrq10	0x08
+#define	McaIrq11	0x0A
+#define	McaIrq12	0x0C
+#define	McaIrq15	0x0E
+#define McaIrqMask	0x0E
+#define	McaCardEnable	0x01
+#define	McaAddress(X)	(((X)&0xFF)<<16)
+
+#define	McaTpFastLinks	        0x40
+#define	McaTpSlowLinks	        0x00
+#define	McaTpBootFromRam	0x01
+#define	McaTpBootFromLink	0x00
+#define	McaTpBusEnable		0x02
+#define	McaTpBusDisable		0x00
+
+#define	RIO_MCA_DEFAULT_MODE	SLOW_LINKS
+
+#endif	/* __rio_mca_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/mesg.h linux/drivers/char/rio/mesg.h
--- linux-2.2.15-pre2/drivers/char/rio/mesg.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/mesg.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,41 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: mesg.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)mesg.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_mesg_h__
+#define	__rio_mesg_h__
+
+#ifdef SCCS_LABELS
+static char *_mesg_h_sccs_ = "@(#)mesg.h	1.2";
+#endif
+
+
+#endif /* __rio_mesg_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/param.h linux/drivers/char/rio/param.h
--- linux-2.2.15-pre2/drivers/char/rio/param.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/param.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,61 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: param.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)param.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_param_h__
+#define __rio_param_h__
+
+#ifdef SCCS_LABELS
+static char *_param_h_sccs_ = "@(#)param.h	1.2";
+#endif
+
+
+/*
+** the param command block, as used in OPEN and PARAM calls.
+*/
+
+struct phb_param
+{
+    BYTE    Cmd;        /* It is very important that these line up */
+    BYTE    Cor1;       /* with what is expected at the other end. */
+    BYTE    Cor2;       /* to confirm that you've got it right,    */
+    BYTE    Cor4;       /* check with cirrus/cirrus.h              */
+    BYTE    Cor5;
+    BYTE    TxXon;	/* Transmit X-On character */
+    BYTE    TxXoff;	/* Transmit X-Off character */
+    BYTE    RxXon;	/* Receive X-On character */
+    BYTE    RxXoff;	/* Receive X-Off character */
+    BYTE    LNext;	/* Literal-next character */
+    BYTE    TxBaud;	/* Transmit baudrate */
+    BYTE    RxBaud;	/* Receive baudrate */
+};
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/parmmap.h linux/drivers/char/rio/parmmap.h
--- linux-2.2.15-pre2/drivers/char/rio/parmmap.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/parmmap.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,96 @@
+/****************************************************************************
+ *******                                                              *******
+ *******               H O S T   M E M O R Y  M A P
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+6/4/1991   jonb		     Made changes to accomodate Mips R3230 bus
+ ***************************************************************************/
+
+#ifndef _parmap_h
+#define _parmap_h
+
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_parmmap_h_sccs = "@(#)parmmap.h	1.4"; */
+#endif
+#endif
+
+typedef struct PARM_MAP PARM_MAP ;
+
+struct PARM_MAP
+{
+PHB_ptr           phb_ptr ;              /* Pointer to the PHB array */
+WORD_ptr          phb_num_ptr ;          /* Ptr to Number of PHB's */
+FREE_LIST_ptr     free_list;             /* Free List pointer */
+FREE_LIST_ptr     free_list_end;         /* Free List End pointer */
+Q_BUF_ptr_ptr     q_free_list_ptr ;      /* Ptr to Q_BUF variable */
+BYTE_ptr          unit_id_ptr ;          /* Unit Id */
+LPB_ptr           link_str_ptr ;         /* Link Structure Array */
+BYTE_ptr          bootloader_1 ;         /* 1st Stage Boot Loader */
+BYTE_ptr          bootloader_2 ;         /* 2nd Stage Boot Loader */
+WORD_ptr          port_route_map_ptr ;   /* Port Route Map */
+ROUTE_STR_ptr     route_ptr ;            /* Unit Route Map */
+NUMBER_ptr        map_present ;          /* Route Map present */
+NUMBER            pkt_num ;               /* Total number of packets */
+NUMBER            q_num ;                 /* Total number of Q packets */
+WORD              buffers_per_port ;      /* Number of buffers per port */
+WORD              heap_size ;             /* Initial size of heap */
+WORD              heap_left ;             /* Current Heap left */
+WORD              error ;                 /* Error code */
+WORD              tx_max;                 /* Max number of tx pkts per phb */
+WORD              rx_max;                 /* Max number of rx pkts per phb */
+WORD              rx_limit;               /* For high / low watermarks */
+NUMBER            links ;                 /* Links to use */
+NUMBER            timer ;                 /* Interrupts per second */
+RUP_ptr           rups ;                 /* Pointer to the RUPs */
+WORD              max_phb ;              /* Mostly for debugging */
+WORD              living ;               /* Just increments!! */
+WORD              init_done ;            /* Initialisation over */
+WORD              booting_link ;
+WORD              idle_count ;           /* Idle time counter */
+WORD              busy_count ;           /* Busy counter */
+WORD              idle_control ;         /* Control Idle Process */
+#if defined(HOST) || defined(INKERNEL)
+WORD              tx_intr;               /* TX interrupt pending */
+WORD              rx_intr;               /* RX interrupt pending */
+WORD              rup_intr;              /* RUP interrupt pending */
+#endif
+#if defined(RTA)
+WORD		  dying_count;		/* Count of processes dead */
+#endif
+} ;
+
+#endif
+
+/*********** end of file ***********/
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/pci.h linux/drivers/char/rio/pci.h
--- linux-2.2.15-pre2/drivers/char/rio/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/pci.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,76 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: pci.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)pci.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_pci_h__
+#define	__rio_pci_h__
+
+#ifdef SCCS_LABELS
+static char *_pci_h_sccs_ = "@(#)pci.h	1.2";
+#endif
+
+/*
+** PCI stuff
+*/
+
+#define	PCITpFastClock		0x80
+#define	PCITpSlowClock		0x00
+#define	PCITpFastLinks	        0x40
+#define	PCITpSlowLinks	        0x00
+#define	PCITpIntEnable		0x04
+#define	PCITpIntDisable		0x00
+#define	PCITpBusEnable		0x02
+#define	PCITpBusDisable		0x00
+#define	PCITpBootFromRam	0x01
+#define	PCITpBootFromLink	0x00
+
+#define	RIO_PCI_VENDOR		0x11CB
+#define	RIO_PCI_DEVICE		0x8000
+#define	RIO_PCI_BASE_CLASS	0x02
+#define	RIO_PCI_SUB_CLASS	0x80
+#define	RIO_PCI_PROG_IFACE	0x00
+
+#define RIO_PCI_RID		0x0008
+#define RIO_PCI_BADR0		0x0010
+#define RIO_PCI_INTLN		0x003C
+#define RIO_PCI_INTPIN		0x003D
+
+#define	RIO_PCI_MEM_SIZE	65536
+
+#define	RIO_PCI_TURBO_TP	0x80
+#define	RIO_PCI_FAST_LINKS	0x40
+#define	RIO_PCI_INT_ENABLE	0x04
+#define	RIO_PCI_TP_BUS_ENABLE	0x02
+#define	RIO_PCI_BOOT_FROM_RAM	0x01
+
+#define	RIO_PCI_DEFAULT_MODE	0x05
+
+#endif	/* __rio_pci_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/phb.h linux/drivers/char/rio/phb.h
--- linux-2.2.15-pre2/drivers/char/rio/phb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/phb.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,293 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                 P H B     H E A D E R                        *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra, Jeremy Rolls
+ Date    : 
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _phb_h
+#define _phb_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_phb_h_sccs = "@(#)phb.h	1.12"; */
+#endif
+#endif
+
+
+ /*************************************************
+  * Set the LIMIT values.
+  ************************************************/
+#ifdef RTA
+#define RX_LIMIT       (ushort) 3
+#endif
+#ifdef HOST
+#define RX_LIMIT       (ushort) 1
+#endif
+
+
+/*************************************************
+ * Handshake asserted. Deasserted by the LTT(s)
+ ************************************************/
+#define PHB_HANDSHAKE_SET      ((ushort) 0x001) /* Set by LRT */
+
+#define PHB_HANDSHAKE_RESET     ((ushort) 0x002) /* Set by ISR / driver */
+
+#define PHB_HANDSHAKE_FLAGS     (PHB_HANDSHAKE_RESET | PHB_HANDSHAKE_SET)
+                                                /* Reset by ltt */
+
+
+/*************************************************
+ * Maximum number of PHB's
+ ************************************************/
+#if defined (HOST) || defined (INKERNEL)
+#define MAX_PHB               ((ushort) 128)  /* range 0-127 */
+#else
+#define MAX_PHB               ((ushort) 8)    /* range 0-7 */
+#endif
+
+/*************************************************
+ * Defines for the mode fields
+ ************************************************/
+#define TXPKT_INCOMPLETE        0x0001  /* Previous tx packet not completed */
+#define TXINTR_ENABLED          0x0002  /* Tx interrupt is enabled */
+#define TX_TAB3                 0x0004  /* TAB3 mode */
+#define TX_OCRNL                0x0008  /* OCRNL mode */
+#define TX_ONLCR                0x0010  /* ONLCR mode */
+#define TX_SENDSPACES           0x0020  /* Send n spaces command needs 
+                                           completing */
+#define TX_SENDNULL             0x0040  /* Escaping NULL needs completing */
+#define TX_SENDLF               0x0080  /* LF -> CR LF needs completing */
+#define TX_PARALLELBUG          0x0100  /* CD1400 LF -> CR LF bug on parallel
+                                           port */
+#define TX_HANGOVER             (TX_SENDSPACES | TX_SENDLF | TX_SENDNULL)
+#define TX_DTRFLOW		0x0200	/* DTR tx flow control */
+#define	TX_DTRFLOWED		0x0400	/* DTR is low - don't allow more data
+					   into the FIFO */
+#define	TX_DATAINFIFO		0x0800	/* There is data in the FIFO */
+#define	TX_BUSY			0x1000	/* Data in FIFO, shift or holding regs */
+
+#define RX_SPARE	        0x0001   /* SPARE */
+#define RXINTR_ENABLED          0x0002   /* Rx interrupt enabled */
+#define RX_ICRNL                0x0008   /* ICRNL mode */
+#define RX_INLCR                0x0010   /* INLCR mode */
+#define RX_IGNCR                0x0020   /* IGNCR mode */
+#define RX_CTSFLOW              0x0040   /* CTSFLOW enabled */
+#define RX_IXOFF                0x0080   /* IXOFF enabled */
+#define RX_CTSFLOWED            0x0100   /* CTSFLOW and CTS dropped */
+#define RX_IXOFFED              0x0200   /* IXOFF and xoff sent */
+#define RX_BUFFERED		0x0400	 /* Try and pass on complete packets */
+
+#define PORT_ISOPEN             0x0001  /* Port open? */
+#define PORT_HUPCL              0x0002  /* Hangup on close? */
+#define PORT_MOPENPEND          0x0004  /* Modem open pending */
+#define PORT_ISPARALLEL         0x0008  /* Parallel port */
+#define PORT_BREAK              0x0010  /* Port on break */
+#define PORT_STATUSPEND		0x0020  /* Status packet pending */
+#define PORT_BREAKPEND          0x0040  /* Break packet pending */
+#define PORT_MODEMPEND          0x0080  /* Modem status packet pending */
+#define PORT_PARALLELBUG        0x0100  /* CD1400 LF -> CR LF bug on parallel
+                                           port */
+#define PORT_FULLMODEM          0x0200  /* Full modem signals */
+#define PORT_RJ45               0x0400  /* RJ45 connector - no RI signal */
+#define PORT_RESTRICTED         0x0600  /* Restricted connector - no RI / DTR */
+
+#define PORT_MODEMBITS          0x0600  /* Mask for modem fields */
+
+#define PORT_WCLOSE             0x0800  /* Waiting for close */
+#define	PORT_HANDSHAKEFIX	0x1000	/* Port has H/W flow control fix */
+#define	PORT_WASPCLOSED		0x2000	/* Port closed with PCLOSE */
+#define	DUMPMODE		0x4000	/* Dump RTA mem */
+#define	READ_REG		0x8000	/* Read CD1400 register */
+
+
+
+/**************************************************************************
+ * PHB Structure
+ * A  few words.
+ *
+ * Normally Packets are added to the end of the list and removed from
+ * the start. The pointer tx_add points to a SPACE to put a Packet.
+ * The pointer tx_remove points to the next Packet to remove
+ *************************************************************************/
+#ifndef INKERNEL
+#define src_unit     u2.s2.unit
+#define src_port     u2.s2.port
+#define dest_unit    u1.s1.unit
+#define dest_port    u1.s1.port
+#endif
+#ifdef HOST
+#define tx_start     u3.s1.tx_start_ptr_ptr
+#define tx_add       u3.s1.tx_add_ptr_ptr
+#define tx_end       u3.s1.tx_end_ptr_ptr
+#define tx_remove    u3.s1.tx_remove_ptr_ptr
+#define rx_start     u4.s1.rx_start_ptr_ptr
+#define rx_add       u4.s1.rx_add_ptr_ptr
+#define rx_end       u4.s1.rx_end_ptr_ptr
+#define rx_remove    u4.s1.rx_remove_ptr_ptr
+#endif
+typedef struct PHB PHB ;
+struct PHB {
+#ifdef RTA
+        ushort      port;
+#endif
+#ifdef INKERNEL
+        WORD      source;
+#else
+        union       
+        {
+            ushort source;              /* Complete source */
+            struct
+            {
+                unsigned char unit;     /* Source unit */
+                unsigned char port;     /* Source port */
+            } s2;
+        } u2;
+#endif
+        WORD      handshake ;
+        WORD      status ;
+        NUMBER       timeout ;           /* Maximum of 1.9 seconds */
+        WORD      link ;              /* Send down this link */
+#ifdef INKERNEL
+        WORD      destination;
+#else
+        union       
+        {
+            ushort destination;         /* Complete destination */
+            struct
+            {
+                unsigned char unit;     /* Destination unit */
+                unsigned char port;     /* Destination port */
+            } s1;
+        } u1;
+#endif
+#ifdef RTA
+        ushort      tx_pkts_added;
+        ushort      tx_pkts_removed;
+        Q_BUF_ptr   tx_q_start ;        /* Start of the Q list chain */
+        short       num_tx_q_bufs ;     /* Number of Q buffers in the chain */
+        PKT_ptr_ptr tx_add ;            /* Add a new Packet here */
+        Q_BUF_ptr   tx_add_qb;          /* Pointer to the add Q buf */
+        PKT_ptr_ptr tx_add_st_qbb ;     /* Pointer to start of the Q's buf */
+        PKT_ptr_ptr tx_add_end_qbb ;    /* Pointer to the end of the Q's buf */
+        PKT_ptr_ptr tx_remove ;         /* Remove a Packet here */
+        Q_BUF_ptr   tx_remove_qb ;      /* Pointer to the remove Q buf */
+        PKT_ptr_ptr tx_remove_st_qbb ;  /* Pointer to the start of the Q buf */
+        PKT_ptr_ptr tx_remove_end_qbb ; /* Pointer to the end of the Q buf */
+#endif
+#ifdef INKERNEL
+        PKT_ptr_ptr tx_start ;
+        PKT_ptr_ptr tx_end ;
+        PKT_ptr_ptr tx_add ;
+        PKT_ptr_ptr tx_remove ;
+#endif
+#ifdef HOST
+        union
+        {
+            struct
+            {
+                PKT_ptr_ptr tx_start_ptr_ptr;
+                PKT_ptr_ptr tx_end_ptr_ptr;
+                PKT_ptr_ptr tx_add_ptr_ptr;
+                PKT_ptr_ptr tx_remove_ptr_ptr;
+            } s1;
+            struct
+            {
+                ushort * tx_start_ptr;
+                ushort * tx_end_ptr;
+                ushort * tx_add_ptr;
+                ushort * tx_remove_ptr;
+            } s2;
+        } u3;
+#endif
+
+#ifdef  RTA
+        ushort      rx_pkts_added;
+        ushort      rx_pkts_removed;
+        Q_BUF_ptr   rx_q_start ;        /* Start of the Q list chain */
+        short       num_rx_q_bufs ;     /* Number of Q buffers in the chain */
+        PKT_ptr_ptr rx_add ;            /* Add a new Packet here */
+        Q_BUF_ptr   rx_add_qb ;         /* Pointer to the add Q buf */
+        PKT_ptr_ptr rx_add_st_qbb ;     /* Pointer to start of the Q's buf */
+        PKT_ptr_ptr rx_add_end_qbb ;    /* Pointer to the end of the Q's buf */
+        PKT_ptr_ptr rx_remove ;         /* Remove a Packet here */
+        Q_BUF_ptr   rx_remove_qb ;      /* Pointer to the remove Q buf */
+        PKT_ptr_ptr rx_remove_st_qbb ;  /* Pointer to the start of the Q buf */
+        PKT_ptr_ptr rx_remove_end_qbb ; /* Pointer to the end of the Q buf */
+#endif
+#ifdef INKERNEL
+        PKT_ptr_ptr rx_start ;
+        PKT_ptr_ptr rx_end ;
+        PKT_ptr_ptr rx_add ;
+        PKT_ptr_ptr rx_remove ;
+#endif
+#ifdef HOST
+        union
+        {
+            struct
+            {
+                PKT_ptr_ptr rx_start_ptr_ptr;
+                PKT_ptr_ptr rx_end_ptr_ptr;
+                PKT_ptr_ptr rx_add_ptr_ptr;
+                PKT_ptr_ptr rx_remove_ptr_ptr;
+            } s1;
+            struct
+            {
+                ushort * rx_start_ptr;
+                ushort * rx_end_ptr;
+                ushort * rx_add_ptr;
+                ushort * rx_remove_ptr;
+            } s2;
+        } u4;
+#endif
+
+#ifdef RTA                              /* some fields for the remotes */
+        ushort     flush_count;		/* Count of write flushes */
+        ushort     txmode;		/* Modes for tx */
+        ushort     rxmode;		/* Modes for rx */
+        ushort     portmode;		/* Generic modes */
+        ushort     column;		/* TAB3 column count */
+        ushort     tx_subscript;	/* (TX) Subscript into data field */
+        ushort     rx_subscript;	/* (RX) Subscript into data field */
+        PKT_ptr    rx_incomplete;	/* Hold an incomplete packet here */
+        ushort     modem_bits;		/* Modem bits to mask */
+	ushort	   lastModem;		/* Modem control lines. */
+        ushort     addr;		/* Address for sub commands */
+        ushort     MonitorTstate;	/* TRUE if monitoring tstop */
+#endif
+
+        } ;
+
+#endif
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/pkt.h linux/drivers/char/rio/pkt.h
--- linux-2.2.15-pre2/drivers/char/rio/pkt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/pkt.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,120 @@
+/****************************************************************************
+ *******                                                              *******
+ *******            P A C K E T   H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _pkt_h
+#define _pkt_h 1
+
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_pkt_h_sccs = "@(#)pkt.h	1.8"; */
+#endif
+#endif
+
+#define MAX_TTL         0xf
+#define PKT_CMD_BIT     ((ushort) 0x080)
+#define PKT_CMD_DATA    ((ushort) 0x080)
+
+#define PKT_ACK         ((ushort) 0x040)
+
+#define PKT_TGL         ((ushort) 0x020)
+
+#define PKT_LEN_MASK    ((ushort) 0x07f)
+
+#define DATA_WNDW       ((ushort) 0x10)
+#define PKT_TTL_MASK    ((ushort) 0x0f)
+
+#define PKT_MAX_DATA_LEN   72
+
+#define PKT_LENGTH         sizeof(struct PKT)
+#define SYNC_PKT_LENGTH    (PKT_LENGTH + 4)
+
+#define CONTROL_PKT_LEN_MASK PKT_LEN_MASK
+#define CONTROL_PKT_CMD_BIT  PKT_CMD_BIT
+#define CONTROL_PKT_ACK (PKT_ACK << 8)
+#define CONTROL_PKT_TGL (PKT_TGL << 8)
+#define CONTROL_PKT_TTL_MASK (PKT_TTL_MASK << 8)
+#define CONTROL_DATA_WNDW  (DATA_WNDW << 8)
+
+struct PKT    {
+#ifdef INKERNEL
+                   BYTE    dest_unit ;    /* Destination Unit Id */
+                   BYTE    dest_port ;    /* Destination POrt */
+                   BYTE    src_unit ;     /* Source Unit Id */
+                   BYTE    src_port ;     /* Source POrt */
+#else
+                   union       
+                   {
+                       ushort destination;         /* Complete destination */
+                       struct
+                       {
+                           unsigned char unit;     /* Destination unit */
+                           unsigned char port;     /* Destination port */
+                       } s1;
+                   } u1;
+                   union       
+                   {
+                       ushort source;              /* Complete source */
+                       struct
+                       {
+                           unsigned char unit;     /* Source unit */
+                           unsigned char port;     /* Source port */
+                       } s2;
+                   } u2;
+#endif
+#ifdef INKERNEL
+                   BYTE len ;
+                   BYTE control;
+#else
+                   union
+                   {
+                        ushort      control;
+                        struct
+                        {
+                            unsigned char len;
+                            unsigned char control;
+                        } s3;
+                    } u3;
+#endif
+                   BYTE    data[PKT_MAX_DATA_LEN] ;     
+                                                   /* Actual data :-) */
+                   WORD  csum ;                  /* C-SUM */
+               } ;
+#endif
+
+/*********** end of file ***********/
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/poll.h linux/drivers/char/rio/poll.h
--- linux-2.2.15-pre2/drivers/char/rio/poll.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/poll.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,76 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      P O L L
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _poll_h
+#define _poll_h
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_poll_h_sccs = "@(#)poll.h	1.2" ;
+#endif
+#endif
+
+
+#ifdef HOST
+#define POLL_STACK            100
+#endif
+#ifdef RTA
+#define POLL_STACK            200
+#endif
+
+#define POLL_PERIOD           (int) SECOND
+
+/* The various poll commands */
+#define POLL_POLL             0            /* We are connected and happy.. */
+#define POLL_INTRO            1            /* Introduction packet */
+#define POLL_TOPOLOGY         2            /* Topology update */
+#define POLL_ASSIGN           3            /* ID assign */
+#define POLL_FOAD             4            /* F*** Off And Die */
+#define POLL_LMD	      5		   /* Let Me Die */
+#define POLL_DYB	      6		   /* Die You Ba***** */
+
+/* The way data fields are split up for POLL packets */
+#define POLL_HOST_SERIAL      2            /* Host who booted me */
+#define POLL_MY_SERIAL        6            /* My serial number */
+#define POLL_YOUR_ID          1            /* Your ID number */
+#define POLL_TOPOLOGY_FIELDS  2            /* Topology maps */
+
+#endif
+
+/*********** end of file ***********/
+
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/port.h linux/drivers/char/rio/port.h
--- linux-2.2.15-pre2/drivers/char/rio/port.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/port.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,245 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: port.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)port.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_port_h__
+#define	__rio_port_h__
+
+#ifdef SCCS_LABELS
+static char *_port_h_sccs_ = "@(#)port.h	1.3";
+#endif
+
+
+#undef VPIX
+
+
+/*
+** the port data structure - one per port in the system
+*/
+
+#ifdef STATS
+struct RIOStats
+{
+	/*
+	** interrupt statistics
+	*/
+	uint	BreakIntCnt;
+	uint	ModemOffCnt;
+	uint	ModemOnCnt;
+	uint	RxIntCnt;
+	uint	TxIntCnt;
+	/*
+	** throughput statistics
+	*/
+	uint	RxCharCnt;
+	uint	RxPktCnt;
+	uint	RxSaveCnt;
+	uint	TxCharCnt;
+	uint	TxPktCnt;
+	/*
+	** driver entry statistics
+	*/
+	uint	CloseCnt;
+	uint	IoctlCnt;
+	uint	OpenCnt;
+	uint	ReadCnt;
+	uint	WriteCnt;
+	/*
+	** proc statistics
+	*/
+	uint	BlockCnt;
+	uint	OutputCnt;
+	uint	ResumeCnt;
+	uint	RflushCnt;
+	uint	SuspendCnt;
+	uint	TbreakCnt;
+	uint	TimeoutCnt;
+	uint	UnblockCnt;
+	uint	WflushCnt;
+	uint	WFBodgeCnt;
+};
+#endif
+
+/*
+**	Port data structure
+*/
+struct	Port
+{
+  struct gs_port gs; 
+  int				PortNum;	/* RIO port no., 0-511 */
+  struct Host	*HostP;
+  volatile caddr_t		Caddr;
+  ushort			HostPort;  /* Port number on host card */
+  uchar			RupNum;	/* Number of RUP for port */
+  uchar			ID2;	/* Second ID of RTA for port */
+  ulong			State;	/* FLAGS for open & xopen */
+#define	RIO_LOPEN	0x00001		/* Local open */
+#define	RIO_MOPEN	0x00002		/* Modem open */
+#define	RIO_WOPEN	0x00004		/* Waiting for open */
+#define	RIO_CLOSING	0x00008		/* The port is being close */
+#define	RIO_XPBUSY	0x00010		/* Transparent printer busy */
+#define	RIO_BREAKING	0x00020		/* Break in progress */
+#define	RIO_DIRECT	0x00040		/* Doing Direct output */
+#define	RIO_EXCLUSIVE	0x00080		/* Stream open for exclusive use */
+#define	RIO_NDELAY	0x00100		/* Stream is open FNDELAY */
+#define	RIO_CARR_ON	0x00200		/* Stream has carrier present */
+#define	RIO_XPWANTR	0x00400		/* Stream wanted by Xprint */
+#define	RIO_RBLK	0x00800		/* Stream is read-blocked */
+#define	RIO_BUSY	0x01000		/* Stream is BUSY for write */
+#define	RIO_TIMEOUT	0x02000		/* Stream timeout in progress */
+#define	RIO_TXSTOP	0x04000		/* Stream output is stopped */
+#define	RIO_WAITFLUSH	0x08000		/* Stream waiting for flush */
+#define	RIO_DYNOROD	0x10000		/* Drain failed */
+#define	RIO_DELETED	0x20000		/* RTA has been deleted */
+#define RIO_ISSCANCODE	0x40000		/* This line is in scancode mode */
+#define	RIO_USING_EUC	0x100000	/* Using extended Unix chars */
+#define	RIO_CAN_COOK	0x200000	/* This line can do cooking */
+#define RIO_TRIAD_MODE  0x400000        /* Enable TRIAD special ops. */
+#define RIO_TRIAD_BLOCK 0x800000        /* Next read will block */
+#define RIO_TRIAD_FUNC  0x1000000       /* Seen a function key coming in */
+#define RIO_THROTTLE_RX 0x2000000       /* RX needs to be throttled. */
+
+    ulong			Config;	/* FLAGS for NOREAD.... */
+#define	RIO_NOREAD	0x0001		/* Are not allowed to read port */
+#define	RIO_NOWRITE	0x0002		/* Are not allowed to write port */
+#define	RIO_NOXPRINT	0x0004		/* Are not allowed to xprint port */
+#define	RIO_NOMASK	0x0007		/* All not allowed things */
+#define RIO_IXANY	0x0008          /* Port is allowed ixany */
+#define	RIO_MODEM	0x0010		/* Stream is a modem device */
+#define	RIO_IXON	0x0020		/* Port is allowed ixon */
+#define RIO_WAITDRAIN	0x0040		/* Wait for port to completely drain */
+#define RIO_MAP_50_TO_50	0x0080	/* Map 50 baud to 50 baud */
+#define RIO_MAP_110_TO_110	0x0100	/* Map 110 baud to 110 baud */
+
+/*
+** 15.10.1998 ARG - ESIL 0761 prt fix
+** As LynxOS does not appear to support Hardware Flow Control .....
+** Define our own flow control flags in 'Config'.
+*/
+#define RIO_CTSFLOW	0x0200		/* RIO's own CTSFLOW flag */
+#define RIO_RTSFLOW	0x0400		/* RIO's own RTSFLOW flag */
+
+
+    struct PHB			*PhbP;	  /* pointer to PHB for port */
+    WORD                        *TxAdd;   /* Add packets here */
+    WORD                        *TxStart; /* Start of add array */
+    WORD                        *TxEnd;         /* End of add array */
+    WORD                        *RxRemove;      /* Remove packets here */
+    WORD                        *RxStart;       /* Start of remove array */
+    WORD                        *RxEnd;         /* End of remove array */
+    uint			RtaUniqueNum;	/* Unique number of RTA */
+    ushort			PortState;	/* status of port */
+    ushort			ModemState;	/* status of modem lines */
+    ulong			ModemLines;	/* Modem bits sent to RTA */
+    uchar			CookMode;	/* who expands CR/LF? */
+    uchar			ParamSem;	/* Prevent write during param */
+    uchar			Mapped;		/* if port mapped onto host */
+    uchar			SecondBlock;	/* if port belongs to 2nd block
+						   of 16 port RTA */
+    uchar			InUse;		/* how many pre-emptive cmds */
+    uchar			Lock;		/* if params locked */
+    uchar			Store;	/* if params stored across closes */
+    uchar			FirstOpen; /* TRUE if first time port opened */
+    uchar			FlushCmdBodge;	/* if doing a (non)flush */
+    uchar			MagicFlags;	/* require intr processing */
+#define	MAGIC_FLUSH	0x01	/* mirror of WflushFlag */
+#define	MAGIC_REBOOT	0x02	/* RTA re-booted, re-open ports */
+#define	MORE_OUTPUT_EYGOR 0x04	/* riotproc failed to empty clists */
+    uchar			WflushFlag;	/* 1 How many WFLUSHs active */
+/*
+** Transparent print stuff
+*/
+    struct Xprint
+    {
+#ifndef MAX_XP_CTRL_LEN
+#define MAX_XP_CTRL_LEN		16		/* ALSO IN DAEMON.H */
+#endif
+	uint			XpCps;
+	char			XpOn[MAX_XP_CTRL_LEN];
+	char			XpOff[MAX_XP_CTRL_LEN];
+	ushort			XpLen;		/* strlen(XpOn)+strlen(XpOff) */
+	uchar			XpActive;
+	uchar			XpLastTickOk;	/* TRUE if we can process */
+#define	XP_OPEN		00001
+#define	XP_RUNABLE	00002
+	struct ttystatics 		*XttyP;
+    } Xprint;
+#ifdef VPIX
+    v86_t			*StashP;
+    uint			IntMask;
+    struct termss 		VpixSs;
+    uchar			ModemStatusReg;	/* Modem status register */
+#endif
+    uchar			RxDataStart;
+    uchar			Cor2Copy;	/* copy of COR2 */
+    char			*Name;		/* points to the Rta's name */
+#ifdef STATS
+    struct RIOStats 		Stat;		/* ports statistics */
+#endif
+    char			*TxRingBuffer;
+    ushort			TxBufferIn;	/* New data arrives here */
+    ushort			TxBufferOut;	/* Intr removes data here */
+    ushort			OldTxBufferOut;	/* Indicates if draining */
+    int				TimeoutId;	/* Timeout ID */
+    uint			Debug;
+    uchar			WaitUntilBooted; /* True if open should block */
+    uint			statsGather;	/* True if gathering stats */
+    ulong			txchars;	/* Chars transmitted */
+    ulong			rxchars;	/* Chars received */
+    ulong			opens;		/* port open count */
+    ulong			closes;		/* port close count */
+    ulong			ioctls;		/* ioctl count */
+    uchar			LastRxTgl;	/* Last state of rx toggle bit */
+  spinlock_t				portSem;	/* Lock using this sem */
+	int				MonitorTstate;	/* Monitoring ? */
+	int				timeout_id;	/* For calling 100 ms delays */
+	int				timeout_sem;/* For calling 100 ms delays */
+	int				firstOpen;	/* First time open ? */
+	char *			p;			/* save the global struc here .. */
+};
+
+struct ModuleInfo
+{
+	char	*Name;
+	uint	Flags[4];	/* one per port on a module */
+};
+#endif
+
+/*
+** This struct is required because trying to grab an entire Port structure
+** runs into problems with differing struct sizes between driver and config.
+*/
+struct PortParams {
+	uint	Port;
+	ulong	Config;
+	ulong	State;
+	struct ttystatics	*TtyP;
+};
diff -urN linux-2.2.15-pre2/drivers/char/rio/proto.h linux/drivers/char/rio/proto.h
--- linux-2.2.15-pre2/drivers/char/rio/proto.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/proto.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,244 @@
+/*
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+ */
+#ifndef	_prototypes_h
+#define _prototypes_h
+
+
+/*
+** boot.c
+*/
+void init_boot( char *p, short stage);
+
+/*
+** disconct.c
+*/
+void kill_boot ( LPB *link );
+void disconnected( LPB *link );
+short boot_3( LPB *link, PKT *pkt );
+short send_3_pkt( LPB *link, PKT *pkt);
+
+/*
+** error.c
+*/
+void du_error(void);
+
+/*
+** formpkt.c
+*/
+ushort sum_it( PKT *pkt ) ;
+void form_rup_pkt( RUP *form_rup, PKT *pkt );
+void form_poll_pkt ( int type, LPB *link, int node );
+void form_route_pkt ( int type, PKT *pkt, LPB *link );
+
+/*
+** idle.c
+*/
+void idle( Process *idle_p );
+
+/*
+** init.c
+*/
+void general_init(void);
+void mem_halt( int error);
+
+/*
+** linkinit.c
+*/
+void initlink( u_short number, LPB *link);
+void runlink( LPB *link);
+
+/*
+** list.c
+*/
+PKT *get_free_start(void);
+void put_free_start( PKT *pkt);
+
+#ifdef HOST
+int can_remove_transmit ( PKT **pkt, PKT *pointer );
+#endif
+
+#ifdef RTA
+int spl7 ( void );
+int spl0 ( void );
+Q_BUF *get_free_q( void );
+PKT *get_free_end(void);
+int add_end( PKT *pkt, PHB *phb, int type);
+unsigned short free_packets( PHB *phb, int type);
+int can_remove_start( PKT **pkt, PHB *phb, int type);
+int can_add_start( PHB *phb, int type);
+int can_add_end( PHB *phb, int type);
+void put_free_end( PKT *pkt);
+int remove_start( PKT **pkt, PHB *phb, int type);
+#endif
+
+/*
+** Lrt.c
+*/
+void lrt( Process *lrt_p, LPB *link );
+
+#ifdef RTA
+void set_led_red ( LPB *link );
+#endif
+
+/*
+** ltt.c
+*/
+void ltt( Process *ltt_p, LPB *link, PHB *phb_ptr[] );
+void send_poll ( LPB *link );
+void request_id ( LPB *link );
+void send_topology_update ( LPB *link );
+void send_topology ( LPB *link );
+void supply_id ( LPB *link );
+
+#ifdef RTA
+void redirect_queue ( LPB *link, ushort flush );
+int obtain_rup ( int rup_number, PKT **pkt_address, LPB *link );
+#endif
+
+#ifdef TESTING_PERF
+int consume_cpu( void );
+#endif
+
+/*
+** lttwake.c
+*/
+#ifdef HOST
+void ltt_wakeup( Process *ltt_wakeup_p );
+#endif
+
+/*
+** mapgen.c
+*/
+void generate_id_map( short mapping, ROUTE_STR route[] );
+void gen_map( int mapping, int looking_at, int come_from, ROUTE_STR route[], int link, int *ttl );
+void adjust_ttl( int mapping, int looking_at, int come_from, ROUTE_STR route[], int link, int *ttl);
+void init_sys_map(void);
+
+/*
+** mmu.c
+*/
+char *rio_malloc( unsigned int amount);
+char *rio_calloc( unsigned int num, unsigned int size);
+ERROR rio_mmu_init( uint total_mem );
+
+/*
+** partn.c
+*/
+void partition_tx( struct PHB *phb, u_short tx_size, u_short rx_size, u_short rx_limit);
+
+/*
+** poll.c
+*/
+void tx_poll( Process *tx_poll_p);
+
+/*
+** process.c
+*/
+int  get_proc_space( Process **pd, int **pws, int wssize);
+
+/*
+** readrom.c
+*/
+void read_serial_number(char *buf);
+
+/*
+** rio.c
+*/
+int main( void );
+
+/*
+** route.c
+*/
+void route_update ( PKT *pkt, LPB *link);
+
+/*
+** rtainit.c
+*/
+#if defined(RTA)
+void rta_init(ushort RtaType);
+#endif /* defined(RTA) */
+
+/*
+** rupboot.c
+*/
+void rup_boot( PKT *pkt, RUP *this_rup, LPB *link);
+
+#ifdef RTA
+void kill_your_neighbour( int link_to_kill );
+#endif
+
+/*
+** rupcmd.c
+*/
+void rup_command( PKT *pkt, struct RUP *this_rup, LPB *link);
+
+/*
+** ruperr.c
+*/
+void rup_error( PKT *pkt, RUP *this_rup, LPB *link );
+void illegal_cmd( PKT *src_pkt );
+
+/*
+** ruppoll.c
+*/
+void rup_poll( PKT *pkt, RUP *this_rup, LPB *link );
+
+/*
+** ruppower.c
+*/
+void rup_power( PKT *pkt, RUP *this_rup, LPB *link );
+
+/*
+** ruprm.c
+*/
+void rup_route_map( PKT *pkt, RUP *this_rup, LPB *link);
+
+/*
+** rupstat.c
+*/
+void rup_status( PKT *pkt, RUP *this_rup, LPB *link);
+
+/*
+** rupsync.c
+*/
+void rup_sync( PKT *pkt);
+
+/*
+** rxpkt.c
+*/
+ERROR  rx_pkt( PKT_ptr_ptr pkt_address, LPB *link);
+
+/*
+** sendsts.c
+*/
+void send_status( PKT *requesting_pkt, RUP *this_rup);
+
+/*
+** serial.c
+*/
+void assign_serial ( char *ser_in, char *ser_out);
+int cmp_serial ( char *ser_1, char *ser_2);
+
+/*
+** txpkt.c
+*/
+ERROR  tx_pkt( PKT *pkt, LPB *link);
+short send_sync( LPB *link);
+
+#endif	/* _prototypes_h */
diff -urN linux-2.2.15-pre2/drivers/char/rio/protsts.h linux/drivers/char/rio/protsts.h
--- linux-2.2.15-pre2/drivers/char/rio/protsts.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/protsts.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,119 @@
+/****************************************************************************
+ *******                                                              *******
+ *******      P R O T O C O L    S T A T U S   S T R U C T U R E      *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _protsts_h
+#define _protsts_h 1
+
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_protsts_h_sccs = "@(#)protsts.h	1.4"; */
+#endif
+#endif
+
+/*************************************************
+ * ACK bit. Last Packet received OK. Set by
+ * rxpkt to indicate that the Packet has been
+ * received OK and that the LTT must set the ACK
+ * bit in the next outward bound Packet
+ * and re-set by LTT's after xmit.
+ *
+ * Gets shoved into rx_status
+ ************************************************/
+#define PHB_RX_LAST_PKT_ACKED    ((ushort) 0x080)
+
+/*******************************************************
+ * The Rx TOGGLE bit.
+ * Stuffed into rx_status by RXPKT
+ ******************************************************/
+#define PHB_RX_DATA_WNDW         ((ushort) 0x040)
+
+/*******************************************************
+ * The Rx TOGGLE bit. Matches the setting in PKT.H
+ * Stuffed into rx_status
+ ******************************************************/
+#define PHB_RX_TGL               ((ushort) 0x2000)
+
+
+/*************************************************
+ * This bit is set by the LRT to indicate that
+ * an ACK (packet) must be returned.
+ *
+ * Gets shoved into tx_status
+ ************************************************/
+#define PHB_TX_SEND_PKT_ACK      ((ushort) 0x08)
+
+/*************************************************
+ * Set by LTT to indicate that an ACK is required
+ *************************************************/
+#define PHB_TX_ACK_RQRD         ((ushort) 0x01)
+
+
+/*******************************************************
+ * The Tx TOGGLE bit.
+ * Stuffed into tx_status by RXPKT from the PKT WndW
+ * field. Looked by the LTT when the NEXT Packet
+ * is going to be sent.
+ ******************************************************/
+#define PHB_TX_DATA_WNDW         ((ushort) 0x04)
+
+
+/*******************************************************
+ * The Tx TOGGLE bit. Matches the setting in PKT.H
+ * Stuffed into tx_status
+ ******************************************************/
+#define PHB_TX_TGL               ((ushort) 0x02)
+
+/*******************************************************
+ * Request intr bit. Set when the queue has gone quiet
+ * and the PHB has requested an interrupt.
+ ******************************************************/
+#define PHB_TX_INTR             ((ushort) 0x100)
+
+/*******************************************************
+ * SET if the PHB cannot send any more data down the
+ * Link
+ ******************************************************/
+#define PHB_TX_HANDSHAKE         ((ushort) 0x010)
+
+
+#define RUP_SEND_WNDW		 ((ushort) 0x08) ;
+
+#endif
+
+/*********** end of file ***********/
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/qbuf.h linux/drivers/char/rio/qbuf.h
--- linux-2.2.15-pre2/drivers/char/rio/qbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/qbuf.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,67 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******       Q U E U E    B U F F E R   S T R U C T U R E S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _qbuf_h
+#define _qbuf_h 1
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_qbuf_h_sccs = "@(#)qbuf.h	1.1" ;
+#endif
+#endif
+
+
+
+#ifdef HOST
+#define PKTS_PER_BUFFER    1
+#else
+#define PKTS_PER_BUFFER    (220 / PKT_LENGTH)
+#endif
+
+typedef struct Q_BUF Q_BUF ;
+struct Q_BUF  {
+                  Q_BUF_ptr next ;
+                  Q_BUF_ptr prev ;
+                  PKT_ptr buf[PKTS_PER_BUFFER] ;
+              } ;
+
+
+#endif
+
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/rio.h linux/drivers/char/rio/rio.h
--- linux-2.2.15-pre2/drivers/char/rio/rio.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rio.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,304 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 1998 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rio.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)rio.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_rio_h__
+#define	__rio_rio_h__
+
+#ifdef SCCS_LABELS
+static char *_rio_h_sccs_ = "@(#)rio.h	1.3";
+#endif
+
+/*
+** 30.09.1998 ARG -
+** Introduced driver version and host card type strings
+*/
+#define RIO_DRV_STR "Specialix RIO Driver"
+#define RIO_AT_HOST_STR "ISA"
+#define RIO_PCI_HOST_STR "PCI"
+
+
+/*
+** rio_info_store() commands (arbitary values) :
+*/
+#define RIO_INFO_PUT	0xA4B3C2D1
+#define RIO_INFO_GET	0xF1E2D3C4
+
+
+/*
+** anything that I couldn't cram in somewhere else
+*/
+/*
+#ifndef RIODEBUG
+#define debug
+#else
+#define debug rioprint
+#endif
+*/
+
+
+/*
+**	Maximum numbers of things
+*/
+#define	RIO_SLOTS	4	/* number of configuration slots */
+#define	RIO_HOSTS	4	/* number of hosts that can be found */
+#define	PORTS_PER_HOST	128	/* number of ports per host */
+#define	LINKS_PER_UNIT	4	/* number of links from a host */
+#define	RIO_PORTS	(PORTS_PER_HOST * RIO_HOSTS) /* max. no. of ports */
+#define	RTAS_PER_HOST	(MAX_RUP) /* number of RTAs per host */
+#define	PORTS_PER_RTA	(PORTS_PER_HOST/RTAS_PER_HOST)	/* ports on a rta */
+#define	PORTS_PER_MODULE 4	/* number of ports on a plug-in module */
+				/* number of modules on an RTA */
+#define	MODULES_PER_RTA	 (PORTS_PER_RTA/PORTS_PER_MODULE)
+#define MAX_PRODUCT	16	/* numbr of different product codes */
+#define MAX_MODULE_TYPES 16	/* number of different types of module */
+
+#define RIO_CONTROL_DEV	128	/* minor number of host/control device */
+#define RIO_INVALID_MAJOR 0	/* test first host card's major no for validity */
+
+/*
+** number of RTAs that can be bound to a master
+*/
+#define MAX_RTA_BINDINGS (MAX_RUP * RIO_HOSTS)
+
+/*
+**	Unit types
+*/
+#define PC_RTA16	0x90000000
+#define PC_RTA8		0xe0000000
+#define TYPE_HOST	0
+#define TYPE_RTA8	1
+#define TYPE_RTA16	2
+
+/*
+**	Flag values returned by functions
+*/
+#define	RIO_FAIL	-1
+#define	RIO_SUCCESS	0
+#define	COPYFAIL	-1	/* copy[in|out] failed */
+
+/*
+** SysPort value for something that hasn't any ports
+*/
+#define	NO_PORT	0xFFFFFFFF
+
+/*
+** Unit ID Of all hosts
+*/
+#define	HOST_ID	0
+
+/*
+** Break bytes into nybles
+*/
+#define	LONYBLE(X)	((X) & 0xF)
+#define	HINYBLE(X)	(((X)>>4) & 0xF)
+
+/*
+** Flag values passed into some functions
+*/
+#define	DONT_SLEEP	0
+#define	OK_TO_SLEEP	1
+
+#define	DONT_PRINT	1
+#define	DO_PRINT	0
+
+#define PRINT_TO_LOG_CONS	0
+#define PRINT_TO_CONS	1
+#define PRINT_TO_LOG	2
+
+/*
+** Timeout has trouble with times of less than 3 ticks...
+*/
+#define	MIN_TIMEOUT	3
+
+/*
+**	Generally useful constants
+*/
+#define	HALF_A_SECOND		((HZ)>>1)
+#define	A_SECOND		(HZ)
+#define	HUNDRED_HZ		((HZ/100)?(HZ/100):1)
+#define	FIFTY_HZ		((HZ/50)?(HZ/50):1)
+#define	TWENTY_HZ		((HZ/20)?(HZ/20):1)
+#define	TEN_HZ			((HZ/10)?(HZ/10):1)
+#define	FIVE_HZ			((HZ/5)?(HZ/5):1)
+#define	HUNDRED_MS		TEN_HZ
+#define	FIFTY_MS		TWENTY_HZ
+#define	TWENTY_MS		FIFTY_HZ
+#define	TEN_MS			HUNDRED_HZ
+#define	TWO_SECONDS		((A_SECOND)*2)
+#define	FIVE_SECONDS		((A_SECOND)*5)
+#define	TEN_SECONDS		((A_SECOND)*10)
+#define	FIFTEEN_SECONDS		((A_SECOND)*15)
+#define	TWENTY_SECONDS		((A_SECOND)*20)
+#define	HALF_A_MINUTE		(A_MINUTE>>1)
+#define	A_MINUTE		(A_SECOND*60)
+#define	FIVE_MINUTES		(A_MINUTE*5)
+#define	QUARTER_HOUR		(A_MINUTE*15)
+#define	HALF_HOUR		(A_MINUTE*30)
+#define	HOUR			(A_MINUTE*60)
+
+#define	SIXTEEN_MEG		0x1000000
+#define	ONE_MEG			0x100000
+#define	SIXTY_FOUR_K		0x10000
+
+#define	RIO_AT_MEM_SIZE		SIXTY_FOUR_K
+#define	RIO_EISA_MEM_SIZE	SIXTY_FOUR_K
+#define	RIO_MCA_MEM_SIZE	SIXTY_FOUR_K
+
+#define	POLL_VECTOR		0x100
+
+#define	COOK_WELL		0
+#define	COOK_MEDIUM		1
+#define	COOK_RAW		2
+
+/*
+**	Pointer manipulation stuff
+**	RIO_PTR takes hostp->Caddr and the offset into the DP RAM area
+**	and produces a UNIX caddr_t (pointer) to the object
+**	RIO_OBJ takes hostp->Caddr and a UNIX pointer to an object and
+**	returns the offset into the DP RAM area.
+*/
+#define	RIO_PTR(C,O) (((caddr_t)(C))+(0xFFFF&(O)))
+#define	RIO_OFF(C,O) ((int)(O)-(int)(C))
+
+/*
+**	How to convert from various different device number formats:
+**	DEV is a dev number, as passed to open, close etc - NOT a minor
+**	number!
+**
+**	Note:	LynxOS only gives us 8 bits for the device minor number,
+**		so all this crap here to deal with 'modem' bits etc. is
+**		just a load of irrelevant old bunkum!
+**		This however does not stop us needing to define a value
+**		for RIO_MODEMOFFSET which is required by the 'riomkdev'
+**		utility in the New Config Utilities suite.
+*/
+/* 0-511: direct 512-1023: modem */
+#define	RIO_MODEMOFFSET		0x200	/* doesn't mean anything */
+#define	RIO_MODEM_MASK		0x1FF
+#define	RIO_MODEM_BIT		0x200
+#define	RIO_UNMODEM(DEV)	(minor(DEV) & RIO_MODEM_MASK)
+#define	RIO_ISMODEM(DEV)	(minor(DEV) & RIO_MODEM_BIT)
+#define RIO_PORT(DEV,FIRST_MAJ)	( (major(DEV) - FIRST_MAJ) * PORTS_PER_HOST) \
+					+ minor(DEV)
+
+/*
+**	Min and Max
+*/
+#ifndef min
+#define	min(A,B)	((A)<(B)?(A):(B))
+#endif
+#ifndef max
+#define	max(A,B)	((A)>(B)?(A):(B))
+#endif
+
+#define	splrio	spltty
+
+#define	RIO_IPL	5
+#define	RIO_PRI	(PZERO+10)
+#define RIO_CLOSE_PRI	PZERO-1	/* uninteruptible sleeps for close */
+
+typedef struct DbInf
+{
+	uint	Flag;
+	char	Name[8];
+} DbInf;
+
+#ifndef TRUE
+#define	TRUE (1==1)
+#endif
+#ifndef FALSE
+#define	FALSE	(!TRUE)
+#endif
+
+#define CSUM(pkt_ptr)  (((ushort *)(pkt_ptr))[0] + ((ushort *)(pkt_ptr))[1] + \
+			((ushort *)(pkt_ptr))[2] + ((ushort *)(pkt_ptr))[3] + \
+			((ushort *)(pkt_ptr))[4] + ((ushort *)(pkt_ptr))[5] + \
+			((ushort *)(pkt_ptr))[6] + ((ushort *)(pkt_ptr))[7] + \
+			((ushort *)(pkt_ptr))[8] + ((ushort *)(pkt_ptr))[9] )
+
+/*
+** This happy little macro copies SIZE bytes of data from FROM to TO
+** quite well. SIZE must be a constant.
+*/
+#define CCOPY( FROM, TO, SIZE ) { *(struct s { char data[SIZE]; } *)(TO) = *(struct s *)(FROM); }
+
+/*
+** increment a buffer pointer modulo the size of the buffer...
+*/
+#define	BUMP( P, I )	((P) = (((P)+(I)) & RIOBufferMask))
+
+#define INIT_PACKET( PK, PP ) \
+{ \
+	*((uint *)PK)    = PP->PacketInfo; \
+}
+
+#define	RIO_LINK_ENABLE	0x80FF /* FF is a hack, mainly for Mips, to        */
+			       /* prevent a really stupid race condition.  */
+
+#define	NOT_INITIALISED	0
+#define	INITIALISED	1
+
+#define	NOT_POLLING	0
+#define	POLLING		1
+
+#define	NOT_CHANGED	0
+#define	CHANGED		1
+
+#define	NOT_INUSE	0
+
+#define	DISCONNECT	0
+#define	CONNECT		1
+
+
+/*
+** Machine types - these must NOT overlap with product codes 0-15
+*/
+#define	RIO_MIPS_R3230	31
+#define	RIO_MIPS_R4030	32
+
+#define	RIO_IO_UNKNOWN	-2
+
+#undef	MODERN
+#define	ERROR( E )	do { u.u_error = E; return OPENFAIL } while ( 0 )
+
+/* Defines for MPX line discipline routines */
+
+#define DIST_LINESW_OPEN	0x01
+#define DIST_LINESW_CLOSE	0x02
+#define DIST_LINESW_READ	0x04
+#define DIST_LINESW_WRITE	0x08
+#define DIST_LINESW_IOCTL	0x10
+#define DIST_LINESW_INPUT	0x20
+#define DIST_LINESW_OUTPUT	0x40
+#define DIST_LINESW_MDMINT	0x80
+
+#endif /* __rio_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c
--- linux-2.2.15-pre2/drivers/char/rio/rio_linux.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rio_linux.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1548 @@
+
+/* rio_linux.c -- Linux driver for the Specialix RIO series cards. 
+ *
+ *
+ *   (C) 1999 R.E.Wolff@BitWizard.nl
+ *
+ * Specialix pays for the development and support of this driver.
+ * Please DO contact support@specialix.co.uk if you require
+ * support. But please read the documentation (rio.txt) first.
+ *
+ *
+ *
+ *      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 history:
+ * $Log: rio.c,v $
+ * Revision 1.1  1999/07/11 10:13:54  wolff
+ * Initial revision
+ *
+ * */
+
+
+#define RCS_ID "$Id: rio.c,v 1.1 1999/07/11 10:13:54 wolff Exp wolff $"
+#define RCS_REV "$Revision: 1.1 $"
+
+
+#include <linux/module.h>
+#include <linux/config.h> 
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/miscdevice.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+#include "protsts.h"
+#include "rioboard.h"
+
+
+#include "rio_linux.h"
+
+/* I don't think that this driver can handle more than 512 ports on
+one machine.  Specialix specifies max 4 boards in one machine. I don't
+know why. If you want to try anyway you'll have to increase the number
+of boards in rio.h.  You'll have to allocate more majors if you need
+more than 512 ports.... */
+
+
+/* ************************************************************** */
+/* * This section can be removed when 2.0 becomes outdated....  * */
+/* ************************************************************** */
+
+#if LINUX_VERSION_CODE < 0x020100    /* Less than 2.1.0 */
+#define TWO_ZERO
+#else
+#if LINUX_VERSION_CODE < 0x020209   /* less than 2.2.x */
+#warning "Please use a recent 2.2.x kernel. "
+#endif
+#endif
+
+
+#ifdef TWO_ZERO
+
+/* Here is the section that makes the 2.2 compatible driver source 
+   work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, 
+   and provide for compatibility stuff here if possible. */
+
+#include <linux/bios32.h>
+
+#define Get_user(a,b)                a = get_user(b)
+#define Put_user(a,b)                0,put_user(a,b)
+#define copy_to_user(a,b,c)          memcpy_tofs(a,b,c)
+
+static inline int copy_from_user(void *to,const void *from, int c) 
+{
+  memcpy_fromfs(to, from, c);
+  return 0;
+}
+
+#define pci_present                  pcibios_present
+#define pci_read_config_word         pcibios_read_config_word
+#define pci_read_config_dword        pcibios_read_config_dword
+
+static inline unsigned char get_irq (unsigned char bus, unsigned char fn)
+{
+  unsigned char t; 
+  pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t);
+  return t;
+}
+
+static inline void *ioremap(unsigned long base, long length)
+{
+  if (base < 0x100000) return (void *)base;
+  return vremap (base, length);
+}
+
+#define my_iounmap(x, b)             (((long)x<0x100000)?0:vfree ((void*)x))
+
+#define capable(x)                   suser()
+
+#define queue_task                   queue_task_irq_off
+#define tty_flip_buffer_push(tty)    queue_task(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current)      (current->signal & ~current->blocked)
+#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2)            (((long)t1-t2) > 0)
+
+
+#define test_and_set_bit(nr, addr)   set_bit(nr, addr)
+#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
+
+/* Not yet implemented on 2.0 */
+#define ASYNC_SPD_SHI  -1
+#define ASYNC_SPD_WARP -1
+
+
+/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
+   to the "name" field that does exist. As long as the assignments are
+   done in the right order, there is nothing to worry about. */
+#define driver_name           name 
+
+/* Should be in a header somewhere. They are in tty.h on 2.2 */
+#define TTY_HW_COOK_OUT       14 /* Flag to tell ntty what we can handle */
+#define TTY_HW_COOK_IN        15 /* in hardware - output and input       */
+
+/* The return type of a "close" routine. */
+#define INT                   void
+#define NO_ERROR              /* Nothing */
+
+#else
+
+/* The 2.2.x compatibility section. */
+#include <asm/uaccess.h>
+
+#define Get_user(a,b)         get_user(a,b)
+#define Put_user(a,b)         put_user(a,b)
+#define get_irq(pdev)         pdev->irq
+
+#define INT                   int
+#define NO_ERROR              0              
+
+#define my_iounmap(x,b)       (iounmap((char *)(b)))
+
+#endif
+
+/* ************************************************************** */
+/* *                End of compatibility section..              * */
+/* ************************************************************** */
+
+
+
+/* Why the hell am I defining these here? */
+#define RIO_TYPE_NORMAL 1
+#define RIO_TYPE_CALLOUT 2
+
+#ifndef RIO_NORMAL_MAJOR0
+/* This allows overriding on the compiler commandline, or in a "major.h" 
+   include or something like that */
+#define RIO_NORMAL_MAJOR0  154
+#define RIO_CALLOUT_MAJOR0 155
+#define RIO_NORMAL_MAJOR1  156
+#define RIO_CALLOUT_MAJOR1 157
+#endif
+
+#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
+#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
+#endif
+
+#ifndef RIO_WINDOW_LEN 
+#define RIO_WINDOW_LEN 0x10000
+#endif
+
+
+/* Configurable options: 
+   (Don't be too sure that it'll work if you toggle them) */
+
+/* Am I paranoid or not ? ;-) */
+#undef RIO_PARANOIA_CHECK
+
+
+/* 20 -> 2000 per second. The card should rate-limit interrupts at 1000
+   Hz, but it is user configurable. I don't recommend going above 1000
+   Hz. The interrupt ratelimit might trigger if the interrupt is
+   shared with a very active other device. 
+   undef this if you want to disable the check....
+*/
+#define IRQ_RATE_LIMIT 200
+
+#if 0
+/* Not implemented */
+/* 
+ * The following defines are mostly for testing purposes. But if you need
+ * some nice reporting in your syslog, you can define them also.
+ */
+#define RIO_REPORT_FIFO
+#define RIO_REPORT_OVERRUN
+#endif 
+
+
+/* These constants are derived from SCO Source */
+static struct Conf
+RIOConf =
+{
+  /* locator */         "RIO Config here",
+  /* startuptime */     HZ*2,           /* how long to wait for card to run */
+  /* slowcook */        0,              /* TRUE -> always use line disc. */
+  /* intrpolltime */    1,              /* The frequency of OUR polls */
+  /* breakinterval */   25,             /* x10 mS */
+  /* timer */           10,             /* mS */
+  /* RtaLoadBase */     0x7000,
+  /* HostLoadBase */    0x7C00,
+  /* XpHz */            5,              /* number of Xprint hits per second */
+  /* XpCps */           120,            /* Xprint characters per second */
+  /* XpOn */            "\033d#",       /* start Xprint for a wyse 60 */
+  /* XpOff */           "\024",         /* end Xprint for a wyse 60 */
+  /* MaxXpCps */        2000,           /* highest Xprint speed */
+  /* MinXpCps */        10,             /* slowest Xprint speed */
+  /* SpinCmds */        1,              /* non-zero for mega fast boots */
+  /* First Addr */      0x0A0000,       /* First address to look at */
+  /* Last Addr */       0xFF0000,       /* Last address looked at */
+  /* BufferSize */      1024,           /* Bytes per port of buffering */
+  /* LowWater */        256,            /* how much data left before wakeup */
+  /* LineLength */      80,             /* how wide is the console? */
+  /* CmdTimeout */      HZ,             /* how long a close command may take */
+};
+
+
+
+
+/* Function prototypes */
+
+static void rio_disable_tx_interrupts (void * ptr); 
+static void rio_enable_tx_interrupts (void * ptr); 
+static void rio_disable_rx_interrupts (void * ptr); 
+static void rio_enable_rx_interrupts (void * ptr); 
+static int  rio_get_CD (void * ptr); 
+static void rio_shutdown_port (void * ptr);
+static int  rio_set_real_termios (void  *ptr);
+static void rio_hungup (void  *ptr);
+static void rio_close (void  *ptr);
+static int rio_chars_in_buffer (void * ptr);
+static int rio_fw_ioctl (struct inode *inode, struct file *filp,
+		         unsigned int cmd, unsigned long arg);
+static int rio_fw_open(struct inode *inode, struct file *filp);
+static INT rio_fw_release(struct inode *inode, struct file *filp);
+static int rio_init_drivers(void);
+
+
+void my_hd (void *addr, int len);
+
+
+
+static struct tty_driver rio_driver, rio_callout_driver;
+static struct tty_driver rio_driver2, rio_callout_driver2;
+
+static struct tty_struct * rio_table[RIO_NPORTS] = { NULL, };
+static struct termios ** rio_termios;
+static struct termios ** rio_termios_locked;
+
+/* The name "p" is a bit non-descript. But that's what the rio-lynxos
+sources use all over the place. */
+struct rio_info *p;
+
+/* struct rio_board boards[RIO_HOSTS]; */
+struct rio_port *rio_ports;
+
+int rio_refcount;
+int rio_initialized = 0;
+int rio_nports = 0;
+int rio_debug = 0;
+
+
+/* You can have the driver poll your card. 
+    - Set rio_poll to 1 to poll every timer tick (10ms on Intel). 
+      This is used when the card cannot use an interrupt for some reason.
+*/
+int rio_poll = 1;
+
+
+/* These are the only open spaces in my computer. Yours may have more
+   or less.... */
+int rio_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000};
+
+#define NR_RIO_ADDRS (sizeof(rio_probe_addrs)/sizeof (int))
+
+
+/* Set the mask to all-ones. This alas, only supports 32 interrupts. 
+   Some architectures may need more. -- Changed to LONG to
+   support up to 64 bits on 64bit architectures. -- REW 20/06/99 */
+long rio_irqmask = -1;
+
+#ifndef TWO_ZERO
+#ifdef MODULE
+MODULE_PARM(rio_poll, "i");
+MODULE_PARM(rio_debug, "i");
+MODULE_PARM(rio_irqmask, "i");
+#endif
+#endif
+
+static struct real_driver rio_real_driver = {
+  rio_disable_tx_interrupts,
+  rio_enable_tx_interrupts,
+  rio_disable_rx_interrupts,
+  rio_enable_rx_interrupts,
+  rio_get_CD,
+  rio_shutdown_port, 
+  rio_set_real_termios, 
+  rio_chars_in_buffer,
+  rio_close,
+  rio_hungup,
+  NULL
+};
+
+
+/* 
+   This driver can spew a whole lot of debugging output at you. If you
+   need maximum performance, you should disable the DEBUG define. To
+   aid in debugging in the field, I'm leaving the compile-time debug
+   features enabled, and disable them "runtime". That allows me to
+   instruct people with problems to enable debugging without requiring
+   them to recompile... 
+*/
+#define DEBUG
+
+#ifdef DEBUG
+#define rio_dprintk(f, str...) if (rio_debug & f) printk (str)
+#else
+#define rio_dprintk(f, str...) /* nothing */
+#endif
+
+
+#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ "\n")
+#define func_exit()  rio_dprintk (RIO_DEBUG_FLOW, "rio: exit  " __FUNCTION__ "\n")
+
+#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ \
+                                  "(port %d)\n", port->line)
+
+
+
+
+/* 
+ *  Firmware loader driver specific routines
+ *
+ */
+
+static struct file_operations rio_fw_fops = {
+	NULL,	/*	lseek	*/
+	NULL,	/*	read	*/
+	NULL,	/*	write	*/
+	NULL,	/*	readdir	*/
+	NULL,	/*	select	*/
+	rio_fw_ioctl,
+	NULL,	/*	mmap	*/
+	rio_fw_open,
+#ifndef TWO_ZERO
+	NULL,	/*	flush	*/
+#endif
+	rio_fw_release,
+	NULL,	/*	fsync	*/
+	NULL,	/*	fasync	*/
+	NULL,	/*	check_media_change	*/
+	NULL,	/*	revalidate	*/
+};
+
+struct miscdevice rio_fw_device = {
+	RIOCTL_MISC_MINOR, "rioctl", &rio_fw_fops
+};
+
+
+
+
+
+#ifdef RIO_PARANOIA_CHECK
+
+/* This doesn't work. Who's paranoid around here? Not me! */
+
+static inline int rio_paranoia_check(struct rio_port const * port,
+				    kdev_t device, const char *routine)
+{
+
+  static const char *badmagic =
+    KERN_ERR "rio: Warning: bad rio port magic number for device %s in %s\n";
+  static const char *badinfo =
+    KERN_ERR "rio: Warning: null rio port for device %s in %s\n";
+ 
+  if (!port) {
+    printk(badinfo, kdevname(device), routine);
+    return 1;
+  }
+  if (port->magic != RIO_MAGIC) {
+    printk(badmagic, kdevname(device), routine);
+    return 1;
+  }
+
+  return 0;
+}
+#else
+#define rio_paranoia_check(a,b,c) 0
+#endif
+
+
+#ifdef DEBUG
+void my_hd (void *ad, int len)
+{
+  int i, j, ch;
+  unsigned char *addr = ad;
+  
+  for (i=0;i<len;i+=16) {
+    printk ("%08x ", (int) addr+i);
+    for (j=0;j<16;j++) {
+      printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+    }
+    for (j=0;j<16;j++) {
+      ch = addr[j+i];
+      printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+    }
+    printk ("\n");
+  }
+}
+#else
+#define my_hd(ad,len) do{/* nothing*/ } while (0)
+#endif
+
+
+/* Delay a number of jiffies, allowing a signal to interrupt */ 
+int RIODelay (struct Port *PortP, int njiffies)
+{
+  func_enter ();
+
+  rio_dprintk (RIO_DEBUG_DELAY, "delaying %d jiffies\n", njiffies);  
+  current->state = TASK_INTERRUPTIBLE;
+  schedule_timeout(njiffies);
+  current->state = TASK_RUNNING;
+  func_exit();
+
+  if (signal_pending(current))
+    return RIO_FAIL;
+  else
+    return !RIO_FAIL;
+}
+
+
+/* Delay a number of jiffies, disallowing a signal to interrupt */ 
+int RIODelay_ni (struct Port *PortP, int njiffies)
+{
+  func_enter ();
+
+  rio_dprintk (RIO_DEBUG_DELAY, "delaying %d jiffies (ni)\n", njiffies);  
+  current->state = TASK_UNINTERRUPTIBLE;
+  schedule_timeout(njiffies);
+  current->state = TASK_RUNNING;
+  func_exit();
+  return !RIO_FAIL;
+}
+
+
+int rio_minor (kdev_t device)
+{
+  return MINOR (device) + 
+    256 * ((MAJOR (device) == RIO_NORMAL_MAJOR1) ||
+	   (MAJOR (device) == RIO_CALLOUT_MAJOR1));
+}
+
+
+int rio_ismodem (kdev_t device)
+{
+  return (MAJOR (device) != RIO_NORMAL_MAJOR0) &&
+         (MAJOR (device) != RIO_NORMAL_MAJOR1);
+}
+
+
+void rio_udelay (int usecs)
+{
+  udelay (usecs);
+}
+
+
+void rio_inc_mod_count (void)
+{
+  func_enter ();
+  MOD_INC_USE_COUNT; 
+  func_exit ();
+}
+
+
+void rio_dec_mod_count (void)
+{
+  func_enter ();
+  MOD_DEC_USE_COUNT; 
+  func_exit ();
+}
+
+
+static int rio_set_real_termios (void *ptr)
+{
+  int rv;
+  func_enter();
+
+  rv = RIOParam( (struct Port *) ptr, CONFIG, 0, 1);
+
+  func_exit ();
+
+  return rv;
+}
+
+
+void rio_reset_interrupt (struct Host *HostP)
+{
+  switch( HostP->Type ) {
+  case RIO_AT:
+  case RIO_MCA:
+  case RIO_PCI:
+    WBYTE(HostP->ResetInt , 0xff);
+  }
+}
+
+
+static void rio_interrupt (int irq, void *ptr, struct pt_regs *regs)
+{
+  struct Host *HostP;
+
+  HostP = &p->RIOHosts[(long)ptr];
+  /*   func_enter ();  */
+  rio_dprintk (RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", 
+               irq, HostP->Ivec); 
+
+  /* AAargh! The order in which to do these things is essential and
+     not trivial. 
+     
+     - Rate limit goes before "recursive". Otherwise a series of
+       recursive calls will hang the machine in the interrupt routine. 
+
+     - hardware twiddling goes before "recursive". Otherwise when we
+       poll the card, and a recursive interrupt happens, we wont
+       ack the card, so it might keep on interrupting us. (especially
+       level sensitive interrupt systems like PCI).
+
+     - Rate limit goes before hardware twiddling. Otherwise we won't
+       catch a card that has gone bonkers.
+
+     - The "initialized" test goes after the hardware twiddling. Otherwise
+       the card will stick us in the interrupt routine again.
+
+     - The initialized test goes before recursive. 
+  */
+
+
+
+#ifdef IRQ_RATE_LIMIT
+  /* Aaargh! I'm ashamed. This costs more lines-of-code than the
+     actual interrupt routine!. (Well, used to when I wrote that comment) */
+  {
+    static int lastjif;
+    static int nintr=0;
+
+    if (lastjif == jiffies) {
+      if (++nintr > IRQ_RATE_LIMIT) {
+        free_irq (HostP->Ivec, ptr);
+        printk (KERN_ERR "rio: Too many interrupts. Turning off interrupt %d.\n", 
+                HostP->Ivec);
+      }
+    } else {
+      lastjif = jiffies;
+      nintr = 0;
+    }
+  }
+#endif
+
+  if (HostP->Ivec == irq) {
+    /* Tell the card we've noticed the interrupt. */
+    rio_reset_interrupt (HostP);
+  }
+
+  if ((HostP->Flags & RUN_STATE) != RC_RUNNING) return;
+
+  if (test_and_set_bit (RIO_BOARD_INTR_LOCK, &HostP->locks)) {
+    printk (KERN_ERR "Recursive interrupt! (host %d/irq%d)\n", 
+            (int) ptr, HostP->Ivec);
+    return;
+  }
+
+  RIOServiceHost(p, HostP, irq);
+
+  rio_dprintk ( RIO_DEBUG_IFLOW, "riointr() doing host %d type %d\n", 
+                (int) ptr, HostP->Type);
+
+  clear_bit (RIO_BOARD_INTR_LOCK, &HostP->locks);
+  rio_dprintk (RIO_DEBUG_IFLOW, "rio: exit rio_interrupt (%d/%d)\n", 
+               irq, HostP->Ivec); 
+  /*  func_exit ();  */
+}
+
+
+static void rio_pollfunc (unsigned long data)
+{
+  func_enter ();
+
+  rio_interrupt (0, (void *)data, NULL);
+  p->RIOHosts[data].timer.expires = jiffies + rio_poll;
+  add_timer (&p->RIOHosts[data].timer);
+
+  func_exit ();
+}
+
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *              interface with the generic_serial driver                  *
+ * ********************************************************************** */
+
+/* Ehhm. I don't know how to fiddle with interrupts on the Specialix 
+   cards. ....   Hmm. Ok I figured it out. You don't.  -- REW */
+
+static void rio_disable_tx_interrupts (void * ptr) 
+{
+  func_enter();
+
+  /*  port->gs.flags &= ~GS_TX_INTEN; */
+
+  func_exit();
+}
+
+
+static void rio_enable_tx_interrupts (void * ptr) 
+{
+  struct Port *PortP = ptr;
+  /* int hn; */
+
+  func_enter();
+
+  /* hn = PortP->HostP - p->RIOHosts;
+
+     rio_dprintk (RIO_DEBUG_TTY, "Pushing host %d\n", hn);
+     rio_interrupt (-1,(void *) hn, NULL); */
+
+  RIOTxEnable((char *) PortP);
+
+  /* 
+   * In general we cannot count on "tx empty" interrupts, although
+   * the interrupt routine seems to be able to tell the difference. 
+   */
+  PortP->gs.flags &= ~GS_TX_INTEN;
+
+  func_exit();
+}
+
+
+static void rio_disable_rx_interrupts (void * ptr) 
+{
+  func_enter();
+  func_exit();
+}
+
+static void rio_enable_rx_interrupts (void * ptr) 
+{
+  /*  struct rio_port *port = ptr; */
+  func_enter();
+  func_exit();
+}
+
+
+/* Jeez. Isn't this simple?  */
+static int rio_get_CD (void * ptr) 
+{
+  struct Port *PortP = ptr;
+  int rv;
+
+  func_enter();
+  rv = (PortP->ModemState & MSVR1_CD) != 0;
+
+  rio_dprintk (RIO_DEBUG_INIT, "Getting CD status: %d\n", rv);
+  
+  func_exit();  
+  return rv;
+}
+
+
+/* Jeez. Isn't this simple? Actually, we can sync with the actual port
+   by just pushing stuff into the queue going to the port... */
+static int rio_chars_in_buffer (void * ptr) 
+{
+  func_enter();
+
+  func_exit();  
+  return 0;
+}
+
+
+/* Nothing special here... */
+static void rio_shutdown_port (void * ptr) 
+{
+  func_enter();
+
+#if 0
+  port->gs.flags &= ~ GS_ACTIVE;
+  if (!port->gs.tty) {
+    printk ("No tty.\n");
+    return;
+  }
+  if (!port->gs.tty->termios) {
+    printk ("No termios.\n");
+    return;
+  }
+  if (port->gs.tty->termios->c_cflag & HUPCL) {
+    rio_setsignals (port, 0, 0);
+  }
+#endif
+
+  func_exit();
+}
+
+
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *               interface with the rest of the system                    *
+ * ********************************************************************** */
+
+
+static int rio_fw_open(struct inode *inode, struct file *filp)
+{
+  func_enter ();
+  rio_inc_mod_count ();
+  func_exit ();
+  return 0;
+}
+
+
+static INT rio_fw_release(struct inode *inode, struct file *filp)
+{
+  func_enter ();
+  rio_dec_mod_count ();
+  func_exit ();
+  return NO_ERROR;
+}
+
+
+/* I haven't the foggiest why the decrement use count has to happen
+   here. The whole linux serial drivers stuff needs to be redesigned.
+   My guess is that this is a hack to minimize the impact of a bug
+   elsewhere. Thinking about it some more. (try it sometime) Try
+   running minicom on a serial port that is driven by a modularized
+   driver. Have the modem hangup. Then remove the driver module. Then
+   exit minicom.  I expect an "oops".  -- REW */
+static void rio_hungup (void *ptr)
+{
+  func_enter ();
+  /* rio_dec_mod_count (); */
+  func_exit ();
+}
+
+
+/* The standard serial_close would become shorter if you'd wrap it like
+   this. 
+   rs_close (...){save_flags;cli;real_close();dec_use_count;restore_flags;}
+ */
+static void rio_close (void *ptr)
+{
+  func_enter ();
+  riotclose (ptr);
+  rio_dec_mod_count ();
+  func_exit ();
+}
+
+
+
+static int rio_fw_ioctl (struct inode *inode, struct file *filp,
+		         unsigned int cmd, unsigned long arg)
+{
+  int rc = 0;
+  func_enter();
+
+  /* The "dev" argument isn't used. */
+  rc = -riocontrol (p, 0, cmd, (void *)arg, suser ());
+
+  func_exit ();
+  return rc;
+}
+
+
+static int rio_ioctl (struct tty_struct * tty, struct file * filp, 
+                     unsigned int cmd, unsigned long arg)
+{
+#if 0
+  int rc;
+  struct rio_port *port = tty->driver_data;
+  int ival;
+
+  /* func_enter2(); */
+
+
+  rc  = 0;
+  switch (cmd) {
+  case TIOCGSOFTCAR:
+    rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+                  (unsigned int *) arg);
+    break;
+  case TIOCSSOFTCAR:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(int))) == 0) {
+      Get_user(ival, (unsigned int *) arg);
+      tty->termios->c_cflag =
+        (tty->termios->c_cflag & ~CLOCAL) |
+        (ival ? CLOCAL : 0);
+    }
+    break;
+  case TIOCGSERIAL:
+    if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                          sizeof(struct serial_struct))) == 0)
+      gs_getserial(&port->gs, (struct serial_struct *) arg);
+    break;
+  case TIOCSSERIAL:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(struct serial_struct))) == 0)
+      rc = gs_setserial(&port->gs, (struct serial_struct *) arg);
+    break;
+  case TIOCMGET:
+    if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                          sizeof(unsigned int))) == 0) {
+      ival = rio_getsignals(port);
+      put_user(ival, (unsigned int *) arg);
+    }
+    break;
+  case TIOCMBIS:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(unsigned int))) == 0) {
+      Get_user(ival, (unsigned int *) arg);
+      rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1),
+                           ((ival & TIOCM_RTS) ? 1 : -1));
+    }
+    break;
+  case TIOCMBIC:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(unsigned int))) == 0) {
+      Get_user(ival, (unsigned int *) arg);
+      rio_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1),
+                           ((ival & TIOCM_RTS) ? 0 : -1));
+    }
+    break;
+  case TIOCMSET:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(unsigned int))) == 0) {
+      Get_user(ival, (unsigned int *) arg);
+      rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0),
+                           ((ival & TIOCM_RTS) ? 1 : 0));
+    }
+    break;
+
+  default:
+    rc = -ENOIOCTLCMD;
+    break;
+  }
+  /* func_exit(); */
+  return rc;
+#else
+  return -ENOIOCTLCMD;
+#endif
+
+}
+
+
+/* The throttle/unthrottle scheme for the Specialix card is different
+ * from other drivers and deserves some explanation. 
+ * The Specialix hardware takes care of XON/XOFF
+ * and CTS/RTS flow control itself.  This means that all we have to
+ * do when signalled by the upper tty layer to throttle/unthrottle is
+ * to make a note of it here.  When we come to read characters from the
+ * rx buffers on the card (rio_receive_chars()) we look to see if the
+ * upper layer can accept more (as noted here in rio_rx_throt[]). 
+ * If it can't we simply don't remove chars from the cards buffer. 
+ * When the tty layer can accept chars, we again note that here and when
+ * rio_receive_chars() is called it will remove them from the cards buffer.
+ * The card will notice that a ports buffer has drained below some low
+ * water mark and will unflow control the line itself, using whatever
+ * flow control scheme is in use for that port. -- Simon Allen
+ */
+
+static void rio_throttle (struct tty_struct * tty)
+{
+  struct Port *port = (struct Port *)tty->driver_data;
+  
+  func_enter();
+  /* If the port is using any type of input flow
+   * control then throttle the port.
+   */
+
+  if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) {
+    port->State |= RIO_THROTTLE_RX;
+  }
+
+  func_exit();
+}
+
+
+static void rio_unthrottle (struct tty_struct * tty)
+{
+  struct Port *port = (struct Port *)tty->driver_data;
+
+  func_enter();
+  /* Always unthrottle even if flow control is not enabled on
+   * this port in case we disabled flow control while the port
+   * was throttled
+   */
+
+  port->State &= ~RIO_THROTTLE_RX;
+
+  func_exit();
+  return;
+}
+
+
+
+
+
+/* ********************************************************************** *
+ *                    Here are the initialization routines.               *
+ * ********************************************************************** */
+
+
+struct vpd_prom *get_VPD_PROM (struct Host *hp)
+{
+  static struct vpd_prom vpdp;
+  char *p;
+  int i;
+
+  func_enter();
+  rio_dprintk (RIO_DEBUG_PROBE, "Going to verify vpd prom at %p.\n", 
+              hp->Caddr + RIO_VPD_ROM);
+
+  p = (char *) &vpdp;
+  for (i=0;i< sizeof (struct vpd_prom);i++)
+    *p++ = readb (hp->Caddr+RIO_VPD_ROM + i*2);
+      /* read_rio_byte (hp, RIO_VPD_ROM + i*2); */
+
+  /* Terminate the identifier string. 
+     *** requires one extra byte in struct vpd_prom *** */
+  *p++=0; 
+
+  if (rio_debug & RIO_DEBUG_PROBE)
+    my_hd ((char *)&vpdp, 0x20);
+
+  return &vpdp;
+}
+
+
+
+static int rio_init_drivers(void)
+{
+  int error;
+  
+  func_enter();
+
+  memset(&rio_driver, 0, sizeof(rio_driver));
+  rio_driver.magic = TTY_DRIVER_MAGIC;
+  rio_driver.driver_name = "specialix_rio";
+  rio_driver.name = "ttySR";
+  rio_driver.major = RIO_NORMAL_MAJOR0;
+  rio_driver.num = 256;
+  rio_driver.type = TTY_DRIVER_TYPE_SERIAL;
+  rio_driver.subtype = RIO_TYPE_NORMAL;
+  rio_driver.init_termios = tty_std_termios;
+  rio_driver.init_termios.c_cflag =
+    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+  rio_driver.flags = TTY_DRIVER_REAL_RAW;
+  rio_driver.refcount = &rio_refcount;
+  rio_driver.table = rio_table;
+  rio_driver.termios = rio_termios;
+  rio_driver.termios_locked = rio_termios_locked;
+
+  rio_driver.open  = riotopen;
+  rio_driver.close = gs_close;
+  rio_driver.write = gs_write;
+  rio_driver.put_char = gs_put_char;
+  rio_driver.flush_chars = gs_flush_chars;
+  rio_driver.write_room = gs_write_room;
+  rio_driver.chars_in_buffer = gs_chars_in_buffer;
+  rio_driver.flush_buffer = gs_flush_buffer;
+  rio_driver.ioctl = rio_ioctl;
+  rio_driver.throttle = rio_throttle;
+  rio_driver.unthrottle = rio_unthrottle;
+  rio_driver.set_termios = gs_set_termios;
+  rio_driver.stop = gs_stop;
+  rio_driver.start = gs_start;
+  rio_driver.hangup = gs_hangup;
+
+  rio_driver2 = rio_driver;
+  rio_driver.major = RIO_NORMAL_MAJOR1;
+
+  rio_callout_driver = rio_driver;
+  rio_callout_driver.name = "cusr";
+  rio_callout_driver.major = RIO_CALLOUT_MAJOR0;
+  rio_callout_driver.subtype = RIO_TYPE_CALLOUT;
+
+  rio_callout_driver2 = rio_callout_driver;
+  rio_callout_driver2.major = RIO_CALLOUT_MAJOR1;
+
+  rio_dprintk (RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios);
+
+  if ((error = tty_register_driver(&rio_driver))) goto bad1;
+  if ((error = tty_register_driver(&rio_driver2))) goto bad2;
+  if ((error = tty_register_driver(&rio_callout_driver))) goto bad3;
+  if ((error = tty_register_driver(&rio_callout_driver2))) goto bad4;
+
+  func_exit();
+  return 0;
+  /* 
+ bad5:tty_unregister_driver (&rio_callout_driver2); */
+ bad4:tty_unregister_driver (&rio_callout_driver);
+ bad3:tty_unregister_driver (&rio_driver2);
+ bad2:tty_unregister_driver (&rio_driver);
+ bad1:printk(KERN_ERR "rio: Couldn't register a rio driver, error = %d\n",
+             error);
+  return 1;
+}
+
+
+static void * ckmalloc (int size)
+{
+  void *p;
+
+  p = kmalloc(size, GFP_KERNEL);
+  if (p) 
+    memset(p, 0, size);
+  return p;
+}
+
+
+
+static int rio_init_datastructures (void)
+{
+  int i;
+  struct Port *port;
+  func_enter();
+
+  /* Many drivers statically allocate the maximum number of ports
+     There is no reason not to allocate them dynamically. Is there? -- REW */
+  /* However, the RIO driver allows users to configure their first
+     RTA as the ports numbered 504-511. We therefore need to allocate 
+     the whole range. :-(   -- REW */
+
+#define RI_SZ   sizeof(struct rio_info)
+#define HOST_SZ sizeof(struct Host)
+#define PORT_SZ sizeof(struct Port *)
+#define TMIO_SZ sizeof(struct termios *)
+  rio_dprintk (RIO_DEBUG_INIT, "getting : %d %d %d %d %d bytes\n", 
+               RI_SZ, 
+               RIO_HOSTS * HOST_SZ,
+               RIO_PORTS * PORT_SZ,
+               RIO_PORTS * TMIO_SZ,
+               RIO_PORTS * TMIO_SZ);
+  
+  if (!(p                  = ckmalloc (              RI_SZ))) goto free0;
+  if (!(p->RIOHosts        = ckmalloc (RIO_HOSTS * HOST_SZ))) goto free1;
+  if (!(p->RIOPortp        = ckmalloc (RIO_PORTS * PORT_SZ))) goto free2;
+  if (!(rio_termios        = ckmalloc (RIO_PORTS * TMIO_SZ))) goto free3;
+  if (!(rio_termios_locked = ckmalloc (RIO_PORTS * TMIO_SZ))) goto free4;
+  p->RIOConf = RIOConf;
+  rio_dprintk (RIO_DEBUG_INIT, "Got : %p %p %p %p %p\n", 
+               p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
+
+  /* Adjust the values in the "driver" */
+  rio_driver.termios = rio_termios;
+  rio_driver.termios_locked = rio_termios_locked;
+  
+#if 1
+  for (i = 0; i < RIO_PORTS; i++) {
+    port = p->RIOPortp[i] = ckmalloc (sizeof (struct Port));
+    if (!port) {
+      goto free6;
+    }
+    rio_dprintk (RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped);
+    port->PortNum = i;
+    port->gs.callout_termios = tty_std_termios;
+    port->gs.normal_termios  = tty_std_termios;
+    port->gs.magic = RIO_MAGIC;
+    port->gs.close_delay = HZ/2;
+    port->gs.closing_wait = 30 * HZ;
+    port->gs.rd = &rio_real_driver;
+  }
+#else
+  /* We could postpone initializing them to when they are configured. */
+#endif
+
+  if (rio_debug & RIO_DEBUG_INIT) {
+    my_hd (&rio_real_driver, sizeof (rio_real_driver));
+  }
+
+  
+  func_exit();
+  return 0;
+
+ free6:for (i--;i>=0;i--)
+        kfree (p->RIOPortp[i]);
+/*free5: */
+       kfree (rio_termios_locked); 
+ free4:kfree (rio_termios);
+ free3:kfree (p->RIOPortp);
+ free2:kfree (p->RIOHosts);
+ free1:kfree (p);
+ free0:
+  rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", 
+               p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
+  return -ENOMEM;
+}
+
+
+static void rio_release_drivers(void)
+{
+  func_enter();
+  tty_unregister_driver (&rio_callout_driver2);
+  tty_unregister_driver (&rio_callout_driver);
+  tty_unregister_driver (&rio_driver2);
+  tty_unregister_driver (&rio_driver);
+  func_exit();
+}
+
+#ifdef TWO_ZERO
+#define PDEV unsigned char pci_bus, unsigned pci_fun
+#define pdev pci_bus, pci_fun
+#else
+#define PDEV   struct pci_dev *pdev
+#endif
+
+
+#ifdef CONFIG_PCI
+ /* This was written for SX, but applies to RIO too...
+    (including bugs....)
+
+    There is another bit besides Bit 17. Turning that bit off
+    (on boards shipped with the fix in the eeprom) results in a 
+    hang on the next access to the card. 
+ */
+
+ /******************************************************** 
+ * Setting bit 17 in the CNTRL register of the PLX 9050  * 
+ * chip forces a retry on writes while a read is pending.*
+ * This is to prevent the card locking up on Intel Xeon  *
+ * multiprocessor systems with the NX chipset.    -- NV  *
+ ********************************************************/
+
+/* Newer cards are produced with this bit set from the configuration
+   EEprom.  As the bit is read/write for the CPU, we can fix it here,
+   if we detect that it isn't set correctly. -- REW */
+
+void fix_rio_pci (PDEV)
+{
+  unsigned int hwbase;
+  unsigned long rebase;
+  unsigned int t;
+
+#define CNTRL_REG_OFFSET        0x50
+#define CNTRL_REG_GOODVALUE     0x00260000
+
+  pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
+  hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
+  rebase =  (ulong) ioremap(hwbase, 0x80);
+  t = readl (rebase + CNTRL_REG_OFFSET);
+  if (t != CNTRL_REG_GOODVALUE) {
+    printk (KERN_DEBUG "rio: performing cntrl reg fix: %08x -> %08x\n", 
+            t, CNTRL_REG_GOODVALUE); 
+    writel (CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);  
+  }
+  my_iounmap (hwbase, rebase);
+}
+#endif
+
+
+#ifdef MODULE
+#define rio_init init_module
+#endif
+
+extern int gs_debug;
+
+int rio_init(void) 
+{
+  int found = 0;
+  int i;
+  struct Host *hp;
+  int retval;
+  struct vpd_prom *vpdp;
+  int okboard;
+
+
+#ifdef CONFIG_PCI
+#ifndef TWO_ZERO
+  struct pci_dev *pdev = NULL;
+#else
+  unsigned char pci_bus, pci_fun;
+  /* in 2.2.x pdev is a pointer defining a PCI device. In 2.0 its the bus/fn */
+#endif
+  unsigned int tint;
+  unsigned short tshort;
+#endif
+
+  func_enter();
+  rio_dprintk (RIO_DEBUG_INIT, "Initing rio module... (rio_debug=%d)\n", 
+	       rio_debug);
+  gs_debug = rio_debug >> 24;
+
+  if (abs ((long) (&rio_debug) - rio_debug) < 0x10000) {
+    printk (KERN_WARNING "rio: rio_debug is an address, instead of a value. "
+            "Assuming -1. Was %x/%p.\n", rio_debug, &rio_debug);
+    rio_debug=-1;
+  }
+
+  retval = rio_init_datastructures ();
+  if (retval < 0) return retval;
+
+#ifdef CONFIG_PCI
+  if (pci_present ()) {
+    /* First look for the JET devices: */
+#ifndef TWO_ZERO
+    while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
+                                    PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, 
+                                    pdev))) {
+#else
+    for (i=0;i< RIO_NBOARDS;i++) {
+      if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, 
+			       PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, i,
+			       &pci_bus, &pci_fun)) break;
+#endif
+      /* Specialix has a whole bunch of cards with
+         0x2000 as the device ID. They say its because
+         the standard requires it. Stupid standard. */
+      /* It seems that reading a word doesn't work reliably on 2.0.
+         Also, reading a non-aligned dword doesn't work. So we read the
+         whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
+         ourselves */
+      /* I don't know why the define doesn't work, constant 0x2c does --REW */ 
+      pci_read_config_dword (pdev, 0x2c, &tint);
+      tshort = (tint >> 16) & 0xffff;
+      rio_dprintk (RIO_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
+      /* rio_dprintk (RIO_DEBUG_PROBE, "pdev = %d/%d  (%x)\n", pdev, tint); */ 
+      if (tshort != 0x0100) {
+        rio_dprintk (RIO_DEBUG_PROBE, "But it's not a RIO card (%d)...\n", 
+                    tshort);
+        continue;
+      }
+      rio_dprintk (RIO_DEBUG_PROBE, "cp1\n");
+
+      pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
+
+      hp = &p->RIOHosts[p->RIONumHosts];
+      hp->PaddrP =  tint & PCI_BASE_ADDRESS_MEM_MASK;
+      hp->Ivec = get_irq (pdev);
+      if (((1 << hp->Ivec) & rio_irqmask) == 0) hp->Ivec = 0;
+      hp->CardP	= (struct DpRam *)
+      hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+      hp->Type  = RIO_PCI;
+      hp->Copy  = rio_pcicopy; 
+      hp->Mode  = RIO_PCI_DEFAULT_MODE;
+ 
+      rio_dprintk (RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n",
+                   (void *)p->RIOHosts[p->RIONumHosts].PaddrP,
+                   p->RIOHosts[p->RIONumHosts].Caddr);
+      if (RIOBoardTest( p->RIOHosts[p->RIONumHosts].PaddrP,
+                        p->RIOHosts[p->RIONumHosts].Caddr, 
+                        RIO_PCI, 0 ) == RIO_SUCCESS) {
+        WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt, 0xff);
+        p->RIOHosts[p->RIONumHosts].UniqueNum  =
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0]) &0xFF)<< 0)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1]) &0xFF)<< 8)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2]) &0xFF)<<16)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3]) &0xFF)<<24);
+        rio_dprintk (RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n",
+                   p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+#if 1
+        fix_rio_pci (pdev);
+#endif
+        p->RIOLastPCISearch = RIO_SUCCESS;
+        p->RIONumHosts++;
+        found++;
+      } else {
+        my_iounmap (p->RIOHosts[p->RIONumHosts].PaddrP, 
+                    p->RIOHosts[p->RIONumHosts].Caddr);
+      }
+
+#ifdef TWO_ZERO
+    }  /* We have two variants with the opening brace, so to prevent */
+#else
+    }  /* Emacs from getting confused we have two closing braces too. */
+#endif
+
+  for (i=0;i<NR_RIO_ADDRS;i++) {
+    hp = &p->RIOHosts[p->RIONumHosts];
+    hp->PaddrP = rio_probe_addrs[i];
+    hp->Ivec = 0;
+    hp->CardP = (struct DpRam *)
+    hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+    hp->Type = RIO_AT;
+    hp->Copy = rio_pcicopy;
+    hp->Mode = 0;
+
+    vpdp = get_VPD_PROM (hp);
+
+    okboard = 0;
+    if ((strncmp (vpdp->identifier, RIO_ISA_IDENT, 16) == 0) ||
+        (strncmp (vpdp->identifier, RIO_ISA2_IDENT, 16) == 0) ||
+        (strncmp (vpdp->identifier, RIO_ISA3_IDENT, 16) == 0)) {
+      /* Board is present... */
+      if (RIOBoardTest (hp->PaddrP, 
+                        hp->Caddr, RIO_AT, 0) == RIO_SUCCESS) {
+        /* ... and feeling fine!!!! */
+        rio_dprintk (RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n",
+                   p->RIOHosts[p->RIONumHosts].UniqueNum);
+        if (RIOAssignAT(p, hp->PaddrP, hp->Caddr, 0)) {        
+          rio_dprintk (RIO_DEBUG_PROBE, "Hmm Tested ok, host%d uniqid = %x.\n",
+                       p->RIONumHosts, 
+                       p->RIOHosts[p->RIONumHosts-1].UniqueNum);
+          okboard++;
+          found++;
+        }
+      }
+
+    if (!okboard)
+      my_iounmap (hp->PaddrP, hp->Caddr);
+    }
+  }
+
+
+
+#if 0 
+#ifndef TWO_ZERO
+
+  /* These older PCI cards have problems (only byte-mode access is
+     supported), which makes them a bit hard to support. Please
+     contact Specialix or BitWizard if you have one of these. We'll
+     see what we can work out.... */
+
+  /* This section hasn't been tested/fixed. It won't work 
+     out-of-the-box. */
+
+    /* Then look for the older RIO/PCI devices: */
+    while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
+                                    PCI_DEVICE_ID_SPECIALIX_RIO, 
+                                    pdev))) {
+#else
+    for (i=0;i< RIO_NBOARDS;i++) {
+      if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, 
+			       PCI_DEVICE_ID_SPECIALIX_RIO, i,
+			       &pci_bus, &pci_fun)) break;
+#endif
+      /* Specialix has a whole bunch of cards with
+         0x2000 as the device ID. They say its because
+         the standard requires it. Stupid standard. */
+      /* It seems that reading a word doesn't work reliably on 2.0.
+         Also, reading a non-aligned dword doesn't work. So we read the
+         whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
+         ourselves */
+      /* I don't know why the define doesn't work, constant 0x2c does --REW */ 
+      pci_read_config_dword (pdev, 0x2c, &tint);
+      tshort = (tint >> 16) & 0xffff;
+      rio_dprintk (RIO_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
+      /* rio_dprintk (RIO_DEBUG_PROBE, "pdev = %d/%d  (%x)\n", pdev, tint); */ 
+      if (tshort != 0x0800) {
+        rio_dprintk (RIO_DEBUG_PROBE, "But it's not a RIO card (%d)...\n", 
+                    tshort);
+        continue;
+      }
+      board = &boards[found];
+      
+      pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
+      board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK;
+      board->base =  (ulong) ioremap(board->hw_base, RIO_WINDOW_LEN);
+      board->irq  = get_irq (pdev);
+      board->flags &= ~RIO_BOARD_TYPE;
+      board->flags |=  RIO_PCI_BOARD;
+
+      rio_dprintk (RIO_DEBUG_PROBE, "Got a specialix card: %x/%x(%d).\n", 
+                  tint, boards[found].base, board->irq);
+
+      if (found_rio (board)) {
+        found++;
+      } else 
+        my_iounmap (board->hw_base, board->base);
+#ifdef TWO_ZERO      
+    }
+#else
+    }
+#endif
+#endif 
+
+  }
+#endif
+
+
+
+  for (i=0;i<p->RIONumHosts;i++) {
+    hp = &p->RIOHosts[i];
+    if (hp->Ivec) {
+      if (request_irq (hp->Ivec, rio_interrupt, SA_SHIRQ, "rio", (void *)i)) {
+        printk(KERN_ERR "rio: Cannot allocate irq %d.\n", hp->Ivec);
+        hp->Ivec = 0;
+      }
+      rio_dprintk (RIO_DEBUG_INIT, "Got irq %d.\n", hp->Ivec);
+    }
+    /* Init the timer "always" to make sure that it can safely be 
+       deleted when we unload... */
+
+    init_timer (&hp->timer);
+    if (!hp->Ivec) {
+      rio_dprintk (RIO_DEBUG_INIT, "Starting polling at %dj intervals.\n", 
+                   rio_poll);
+      hp->timer.data = i;
+      hp->timer.function = rio_pollfunc;
+      hp->timer.expires = jiffies + rio_poll;
+      add_timer (&hp->timer);
+    }
+  }
+
+  if (found) {
+    printk (KERN_INFO "rio: total of %d boards detected.\n", found);
+
+    if (misc_register(&rio_fw_device) < 0) {
+      printk(KERN_ERR "RIO: Unable to register firmware loader driver.\n");
+      return -EIO;
+    }
+    rio_init_drivers ();
+  }
+
+  func_exit();
+  return found?0:-EIO;
+}
+
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+  int i; 
+  struct Host *hp;
+  
+  func_enter();
+
+  for (i=0,hp=p->RIOHosts;i<p->RIONumHosts;i++, hp++) {
+    RIOHostReset (hp->Type, hp->CardP, hp->Slot);
+    if (hp->Ivec) {
+      free_irq (hp->Ivec, (void *)i);
+      rio_dprintk (RIO_DEBUG_INIT, "freed irq %d.\n", hp->Ivec);
+    }
+    /* It is safe/allowed to del_timer a non-active timer */
+    del_timer (&hp->timer);
+  }
+
+  if (misc_deregister(&rio_fw_device) < 0) {
+    printk (KERN_INFO "rio: couldn't deregister control-device\n");
+  }
+
+
+  rio_dprintk (RIO_DEBUG_CLEANUP, "Cleaning up drivers\n");
+
+  rio_release_drivers ();
+
+  /* Release dynamically allocated memory */
+  kfree (rio_termios_locked); 
+  kfree (rio_termios);
+  kfree (p->RIOPortp);
+  kfree (p->RIOHosts);
+  kfree (p);
+
+  func_exit();
+}
+#endif
+
+
+
+/*
+ * Anybody who knows why this doesn't work for me, please tell me -- REW.
+ * Snatched from scsi.c (fixed one spelling error):
+ * Overrides for Emacs so that we follow Linus' tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local Variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/rio_linux.h linux/drivers/char/rio/rio_linux.h
--- linux-2.2.15-pre2/drivers/char/rio/rio_linux.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rio_linux.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,129 @@
+
+/*
+ *  rio_linux.h
+ *
+ *  Copyright (C) 1998,1999,2000 R.E.Wolff@BitWizard.nl
+ *
+ *      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.
+ *
+ *  RIO serial driver.
+ *
+ *  Version 1.0 -- July, 1999. 
+ * 
+ */
+
+#define RIO_NBOARDS        4
+#define RIO_PORTSPERBOARD 128
+#define RIO_NPORTS        (RIO_NBOARDS * RIO_PORTSPERBOARD)
+
+#ifdef __KERNEL__
+
+#define RIO_MAGIC 0x12345678
+
+
+struct vpd_prom {
+  unsigned short id;
+  char hwrev;
+  char hwass;
+  int uniqid;
+  char myear;
+  char mweek;
+  char hw_feature[5];
+  char oem_id;
+  char identifier[16];
+};
+
+
+#define RIO_DEBUG_ALL           0xffffffff
+
+#define O_OTHER(tty)    \
+      ((O_OLCUC(tty))  ||\
+      (O_ONLCR(tty))   ||\
+      (O_OCRNL(tty))   ||\
+      (O_ONOCR(tty))   ||\
+      (O_ONLRET(tty))  ||\
+      (O_OFILL(tty))   ||\
+      (O_OFDEL(tty))   ||\
+      (O_NLDLY(tty))   ||\
+      (O_CRDLY(tty))   ||\
+      (O_TABDLY(tty))  ||\
+      (O_BSDLY(tty))   ||\
+      (O_VTDLY(tty))   ||\
+      (O_FFDLY(tty)))
+
+/* Same for input. */
+#define I_OTHER(tty)    \
+      ((I_INLCR(tty))  ||\
+      (I_IGNCR(tty))   ||\
+      (I_ICRNL(tty))   ||\
+      (I_IUCLC(tty))   ||\
+      (L_ISIG(tty)))
+
+
+#endif /* __KERNEL__ */
+
+
+#define RIO_BOARD_INTR_LOCK  1
+
+
+#ifndef RIOCTL_MISC_MINOR 
+/* Allow others to gather this into "major.h" or something like that */
+#define RIOCTL_MISC_MINOR    169
+#endif
+
+
+/* Allow us to debug "in the field" without requiring clients to
+   recompile.... */
+#if 1
+#define rio_spin_lock_irqsave(sem, flags) do { \
+	rio_dprint(RIO_DEBUG_SPINLOCK, ("spinlockirqsave: %p %s:%d\n", \
+					sem, __FILE__, __LINE__));\
+        spin_lock_irqsave(sem, flags);\
+        } while (0)
+
+#define rio_spin_unlock_irqrestore(sem, flags) do { \
+	rio_dprint(RIO_DEBUG_SPINLOCK, ("spinunlockirqrestore: %p %s:%d\n",\
+					sem, __FILE__, __LINE__));\
+        spin_unlock_irqrestore(sem, flags);\
+        } while (0)
+
+
+#define rio_spin_lock(sem) do { \
+	rio_dprint(RIO_DEBUG_SPINLOCK, ("spinlock: %p %s:%d\n",\
+					sem, __FILE__, __LINE__));\
+        spin_lock(sem);\
+        } while (0)
+
+#define rio_spin_unlock(sem) do { \
+	rio_dprint(RIO_DEBUG_SPINLOCK, ("spinunlock: %p %s:%d\n",\
+					sem, __FILE__, __LINE__));\
+        spin_unlock(sem);\
+        } while (0)
+#else
+#define rio_spin_lock_irqsave(sem, flags) \
+            spin_lock_irqsave(sem, flags)
+
+#define rio_spin_unlock_irqrestore(sem, flags) \
+            spin_unlock_irqrestore(sem, flags)
+
+#define rio_spin_lock(sem) \
+            spin_lock(sem) 
+
+#define rio_spin_unlock(sem) \
+            spin_unlock(sem) 
+
+#endif
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/rioboard.h linux/drivers/char/rio/rioboard.h
--- linux-2.2.15-pre2/drivers/char/rio/rioboard.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioboard.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,281 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	RIO Host Card Hardware Definitions	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	26th April 1999				*/
+/*									*/
+/*	Version		:	1.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1999	*
+ *
+ *      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.
+ *									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing the RIO board hardware	*/
+/*									*/
+/************************************************************************/
+
+/* History...
+
+1.0.0	26/04/99 NPV	Creation.
+
+*/
+
+#ifndef	_rioboard_h				/* If RIOBOARD.H not already defined */
+#define	_rioboard_h    1
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   Hardware Control Registers   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* Hardware Registers... */
+
+#define	RIO_REG_BASE	0x7C00			/* Base of control registers */
+
+#define	RIO_CONFIG	RIO_REG_BASE + 0x0000	/* WRITE: Configuration Register */
+#define	RIO_INTSET	RIO_REG_BASE + 0x0080	/* WRITE: Interrupt Set */
+#define	RIO_RESET	RIO_REG_BASE + 0x0100	/* WRITE: Host Reset */
+#define	RIO_INTRESET	RIO_REG_BASE + 0x0180	/* WRITE: Interrupt Reset */
+
+#define	RIO_VPD_ROM	RIO_REG_BASE + 0x0000	/* READ: Vital Product Data ROM */
+#define	RIO_INTSTAT	RIO_REG_BASE + 0x0080	/* READ: Interrupt Status (Jet boards only) */
+#define	RIO_RESETSTAT	RIO_REG_BASE + 0x0100	/* READ: Reset Status (Jet boards only) */
+
+/* RIO_VPD_ROM definitions... */
+#define	VPD_SLX_ID1	0x00			/* READ: Specialix Identifier #1 */
+#define	VPD_SLX_ID2	0x01			/* READ: Specialix Identifier #2 */
+#define	VPD_HW_REV	0x02			/* READ: Hardware Revision */
+#define	VPD_HW_ASSEM	0x03			/* READ: Hardware Assembly Level */
+#define	VPD_UNIQUEID4	0x04			/* READ: Unique Identifier #4 */
+#define	VPD_UNIQUEID3	0x05			/* READ: Unique Identifier #3 */
+#define	VPD_UNIQUEID2	0x06			/* READ: Unique Identifier #2 */
+#define	VPD_UNIQUEID1	0x07			/* READ: Unique Identifier #1 */
+#define	VPD_MANU_YEAR	0x08			/* READ: Year Of Manufacture (0 = 1970) */
+#define	VPD_MANU_WEEK	0x09			/* READ: Week Of Manufacture (0 = week 1 Jan) */
+#define	VPD_HWFEATURE1	0x0A			/* READ: Hardware Feature Byte 1 */
+#define	VPD_HWFEATURE2	0x0B			/* READ: Hardware Feature Byte 2 */
+#define	VPD_HWFEATURE3	0x0C			/* READ: Hardware Feature Byte 3 */
+#define	VPD_HWFEATURE4	0x0D			/* READ: Hardware Feature Byte 4 */
+#define	VPD_HWFEATURE5	0x0E			/* READ: Hardware Feature Byte 5 */
+#define	VPD_OEMID	0x0F			/* READ: OEM Identifier */
+#define	VPD_IDENT	0x10			/* READ: Identifier string (16 bytes) */
+#define	VPD_IDENT_LEN	0x10
+
+/* VPD ROM Definitions... */
+#define	SLX_ID1		0x4D
+#define	SLX_ID2		0x98
+
+#define	PRODUCT_ID(a)	((a>>4)&0xF)		/* Use to obtain Product ID from VPD_UNIQUEID1 */
+
+#define	ID_SX_ISA	0x2
+#define	ID_RIO_EISA	0x3
+#define	ID_SX_PCI	0x5
+#define	ID_SX_EISA	0x7
+#define	ID_RIO_RTA16	0x9
+#define	ID_RIO_ISA	0xA
+#define	ID_RIO_MCA	0xB
+#define	ID_RIO_SBUS	0xC
+#define	ID_RIO_PCI	0xD
+#define	ID_RIO_RTA8	0xE
+
+/* Transputer bootstrap definitions... */
+
+#define	BOOTLOADADDR		(0x8000 - 6)
+#define	BOOTINDICATE		(0x8000 - 2)
+
+/* Firmware load position... */
+
+#define	FIRMWARELOADADDR	0x7C00		/* Firmware is loaded _before_ this address */
+
+/*****************************************************************************
+*****************************                    *****************************
+*****************************   RIO (Rev1) ISA   *****************************
+*****************************                    *****************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_ISA_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_ISA_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_ISA_CFG_IRQMASK	0x30		/* Interrupt mask */
+#define	  RIO_ISA_CFG_IRQ12	0x10		/* Interrupt Level 12 */
+#define	  RIO_ISA_CFG_IRQ11	0x20		/* Interrupt Level 11 */
+#define	  RIO_ISA_CFG_IRQ9	0x30		/* Interrupt Level 9 */
+#define	RIO_ISA_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+#define	RIO_ISA_CFG_WAITSTATE0	0x80		/* 0 waitstates, else 1 */
+
+/*****************************************************************************
+*****************************                    *****************************
+*****************************   RIO (Rev2) ISA   *****************************
+*****************************                    *****************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA2_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_ISA2_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_ISA2_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_ISA2_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+#define	RIO_ISA2_CFG_16BIT	0x08		/* 16bit mode, else 8bit */
+#define	RIO_ISA2_CFG_IRQMASK	0x30		/* Interrupt mask */
+#define	  RIO_ISA2_CFG_IRQ15	0x00		/* Interrupt Level 15 */
+#define	  RIO_ISA2_CFG_IRQ12	0x10		/* Interrupt Level 12 */
+#define	  RIO_ISA2_CFG_IRQ11	0x20		/* Interrupt Level 11 */
+#define	  RIO_ISA2_CFG_IRQ9	0x30		/* Interrupt Level 9 */
+#define	RIO_ISA2_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+#define	RIO_ISA2_CFG_WAITSTATE0	0x80		/* 0 waitstates, else 1 */
+
+/*****************************************************************************
+*****************************                   ******************************
+*****************************   RIO (Jet) ISA   ******************************
+*****************************                   ******************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA3_IDENT	"JET HOST BY KEV#"
+
+#define	RIO_ISA3_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_ISA3_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+#define	RIO_ISA32_CFG_IRQMASK	0xF30		/* Interrupt mask */
+#define	  RIO_ISA3_CFG_IRQ15	0xF0		/* Interrupt Level 15 */
+#define	  RIO_ISA3_CFG_IRQ12	0xC0		/* Interrupt Level 12 */
+#define	  RIO_ISA3_CFG_IRQ11	0xB0		/* Interrupt Level 11 */
+#define	  RIO_ISA3_CFG_IRQ10	0xA0		/* Interrupt Level 10 */
+#define	  RIO_ISA3_CFG_IRQ9	0x90		/* Interrupt Level 9 */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   RIO MCA   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_MCA_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_MCA_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_MCA_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_MCA_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+
+/*****************************************************************************
+********************************              ********************************
+********************************   RIO EISA   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+/* EISA Configuration Space Definitions... */
+#define	EISA_PRODUCT_ID1	0xC80
+#define	EISA_PRODUCT_ID2	0xC81
+#define	EISA_PRODUCT_NUMBER	0xC82
+#define	EISA_REVISION_NUMBER	0xC83
+#define	EISA_CARD_ENABLE	0xC84
+#define	EISA_VPD_UNIQUEID4	0xC88		/* READ: Unique Identifier #4 */
+#define	EISA_VPD_UNIQUEID3	0xC8A		/* READ: Unique Identifier #3 */
+#define	EISA_VPD_UNIQUEID2	0xC90		/* READ: Unique Identifier #2 */
+#define	EISA_VPD_UNIQUEID1	0xC92		/* READ: Unique Identifier #1 */
+#define	EISA_VPD_MANU_YEAR	0xC98		/* READ: Year Of Manufacture (0 = 1970) */
+#define	EISA_VPD_MANU_WEEK	0xC9A		/* READ: Week Of Manufacture (0 = week 1 Jan) */
+#define	EISA_MEM_ADDR_23_16	0xC00
+#define	EISA_MEM_ADDR_31_24	0xC01
+#define	EISA_RIO_CONFIG		0xC02		/* WRITE: Configuration Register */
+#define	EISA_RIO_INTSET		0xC03		/* WRITE: Interrupt Set */
+#define	EISA_RIO_INTRESET	0xC03		/* READ:  Interrupt Reset */
+
+/* Control Register Definitions... */
+#define	RIO_EISA_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_EISA_CFG_LINK20	0x02		/* 20Mbps link, else 10Mbps */
+#define	RIO_EISA_CFG_BUSENABLE	0x04		/* Enable processor bus */
+#define	RIO_EISA_CFG_PROCRUN	0x08		/* Processor running, else reset */
+#define	RIO_EISA_CFG_IRQMASK	0xF0		/* Interrupt mask */
+#define	  RIO_EISA_CFG_IRQ15	0xF0		/* Interrupt Level 15 */
+#define	  RIO_EISA_CFG_IRQ14	0xE0		/* Interrupt Level 14 */
+#define	  RIO_EISA_CFG_IRQ12	0xC0		/* Interrupt Level 12 */
+#define	  RIO_EISA_CFG_IRQ11	0xB0		/* Interrupt Level 11 */
+#define	  RIO_EISA_CFG_IRQ10	0xA0		/* Interrupt Level 10 */
+#define	  RIO_EISA_CFG_IRQ9	0x90		/* Interrupt Level 9 */
+#define	  RIO_EISA_CFG_IRQ7	0x70		/* Interrupt Level 7 */
+#define	  RIO_EISA_CFG_IRQ6	0x60		/* Interrupt Level 6 */
+#define	  RIO_EISA_CFG_IRQ5	0x50		/* Interrupt Level 5 */
+#define	  RIO_EISA_CFG_IRQ4	0x40		/* Interrupt Level 4 */
+#define	  RIO_EISA_CFG_IRQ3	0x30		/* Interrupt Level 3 */
+
+/*****************************************************************************
+********************************              ********************************
+********************************   RIO SBus   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_SBUS_IDENT	"JBPGK#\0\0\0\0\0\0\0\0\0\0"
+
+#define	RIO_SBUS_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_SBUS_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_SBUS_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+#define	RIO_SBUS_CFG_IRQMASK	0x38		/* Interrupt mask */
+#define	  RIO_SBUS_CFG_IRQNONE	0x00		/* No Interrupt */
+#define	  RIO_SBUS_CFG_IRQ7	0x38		/* Interrupt Level 7 */
+#define	  RIO_SBUS_CFG_IRQ6	0x30		/* Interrupt Level 6 */
+#define	  RIO_SBUS_CFG_IRQ5	0x28		/* Interrupt Level 5 */
+#define	  RIO_SBUS_CFG_IRQ4	0x20		/* Interrupt Level 4 */
+#define	  RIO_SBUS_CFG_IRQ3	0x18		/* Interrupt Level 3 */
+#define	  RIO_SBUS_CFG_IRQ2	0x10		/* Interrupt Level 2 */
+#define	  RIO_SBUS_CFG_IRQ1	0x08		/* Interrupt Level 1 */
+#define	RIO_SBUS_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+#define	RIO_SBUS_CFG_PROC25	0x80		/* 25Mhz processor clock, else 20Mhz */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   RIO PCI   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_PCI_IDENT	"ECDDPGJGJHJRGSK#"
+
+#define	RIO_PCI_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_PCI_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_PCI_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+#define	RIO_PCI_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+#define	RIO_PCI_CFG_PROC25	0x80		/* 25Mhz processor clock, else 20Mhz */
+
+/* PCI Definitions... */
+#define	SPX_VENDOR_ID		0x11CB		/* Assigned by the PCI SIG */
+#define	SPX_DEVICE_ID		0x8000		/* RIO bridge boards */
+#define	SPX_PLXDEVICE_ID	0x2000		/* PLX bridge boards */
+#define	SPX_SUB_VENDOR_ID	SPX_VENDOR_ID	/* Same as vendor id */
+#define	RIO_SUB_SYS_ID		0x0800		/* RIO PCI board */
+
+/*****************************************************************************
+*****************************                   ******************************
+*****************************   RIO (Jet) PCI   ******************************
+*****************************                   ******************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_PCI2_IDENT	"JET HOST BY KEV#"
+
+#define	RIO_PCI2_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_PCI2_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+
+/* PCI Definitions... */
+#define	RIO2_SUB_SYS_ID		0x0100		/* RIO (Jet) PCI board */
+
+#endif						/*_rioboard_h */
+
+/* End of RIOBOARD.H */
diff -urN linux-2.2.15-pre2/drivers/char/rio/rioboot.c linux/drivers/char/rio/rioboot.c
--- linux-2.2.15-pre2/drivers/char/rio/rioboot.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioboot.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1330 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioboot.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:36
+**	Retrieved	: 11/6/98 10:33:48
+**
+**  ident @(#)rioboot.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifdef SCCS_LABELS
+static char *_rioboot_c_sccs_ = "@(#)rioboot.c	1.3";
+#endif
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+
+
+static uchar
+RIOAtVec2Ctrl[] =
+{
+	/* 0 */  INTERRUPT_DISABLE,
+	/* 1 */  INTERRUPT_DISABLE,
+	/* 2 */  INTERRUPT_DISABLE,
+	/* 3 */  INTERRUPT_DISABLE,
+	/* 4 */  INTERRUPT_DISABLE,
+	/* 5 */  INTERRUPT_DISABLE,
+	/* 6 */  INTERRUPT_DISABLE,
+	/* 7 */  INTERRUPT_DISABLE,
+	/* 8 */  INTERRUPT_DISABLE,
+	/* 9 */  IRQ_9|INTERRUPT_ENABLE,
+	/* 10 */ INTERRUPT_DISABLE,
+	/* 11 */ IRQ_11|INTERRUPT_ENABLE,
+	/* 12 */ IRQ_12|INTERRUPT_ENABLE,
+	/* 13 */ INTERRUPT_DISABLE,
+	/* 14 */ INTERRUPT_DISABLE,
+	/* 15 */ IRQ_15|INTERRUPT_ENABLE
+};
+
+/*
+** Load in the RTA boot code.
+*/
+int
+RIOBootCodeRTA(p, rbp)
+struct rio_info *	p;
+struct DownLoad *	rbp; 
+{
+	int offset;
+
+	/* Linux doesn't allow you to disable interrupts during a
+	   "copyin". (Crash when a pagefault occurs). */
+	/* disable(oldspl); */
+	
+	rio_dprint(RIO_DEBUG_BOOT, ("Data at user address 0x%x\n",(int)rbp->DataP));
+
+	/*
+	** Check that we have set asside enough memory for this
+	*/
+	if ( rbp->Count > SIXTY_FOUR_K ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot Code Too Large!\n"));
+		p->RIOError.Error = HOST_FILE_TOO_LARGE;
+		/* restore(oldspl); */
+		return ENOMEM;
+	}
+
+	if ( p->RIOBooting ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot Code : BUSY BUSY BUSY!\n"));
+		p->RIOError.Error = BOOT_IN_PROGRESS;
+		/* restore(oldspl); */
+		return EBUSY;
+	}
+
+	/*
+	** The data we load in must end on a (RTA_BOOT_DATA_SIZE) byte boundary,
+	** so calculate how far we have to move the data up the buffer
+	** to achieve this.
+	*/
+	offset = (RTA_BOOT_DATA_SIZE - (rbp->Count % RTA_BOOT_DATA_SIZE)) % 
+							RTA_BOOT_DATA_SIZE;
+
+	/*
+	** Be clean, and clear the 'unused' portion of the boot buffer,
+	** because it will (eventually) be part of the Rta run time environment
+	** and so should be zeroed.
+	*/
+	bzero( (caddr_t)p->RIOBootPackets, offset );
+
+	/*
+	** Copy the data from user space.
+	*/
+
+	if ( copyin((int)rbp->DataP,((caddr_t)(p->RIOBootPackets))+offset,
+				rbp->Count) ==COPYFAIL ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("Bad data copy from user space\n"));
+		p->RIOError.Error = COPYIN_FAILED;
+		/* restore(oldspl); */
+		return EFAULT;
+	}
+
+	/*
+	** Make sure that our copy of the size includes that offset we discussed
+	** earlier.
+	*/
+	p->RIONumBootPkts = (rbp->Count+offset)/RTA_BOOT_DATA_SIZE;
+	p->RIOBootCount   = rbp->Count;
+
+	/* restore(oldspl); */
+	return 0;
+}
+
+
+/*
+** Load in the host boot code - load it directly onto all halted hosts
+** of the correct type.
+**
+** Put your rubber pants on before messing with this code - even the magic
+** numbers have trouble understanding what they are doing here.
+*/
+int
+RIOBootCodeHOST(p, rbp)
+struct rio_info *	p;
+register struct DownLoad *rbp;
+{
+	register struct Host *HostP;
+	register caddr_t Cad;
+	register PARM_MAP *ParmMapP;
+	register int RupN;
+	int PortN;
+	uint host;
+	caddr_t StartP;
+	BYTE *DestP;
+	int wait_count;
+	ushort OldParmMap;
+	ushort offset;	/* It is very important that this is a ushort */
+	/* uint byte; */
+	caddr_t DownCode = NULL;
+	unsigned long flags;
+
+	HostP = NULL; /* Assure the compiler we've initialized it */
+	for ( host=0; host<p->RIONumHosts; host++ ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("Attempt to boot host %d\n",host));
+		HostP = &p->RIOHosts[host];
+
+		if ( (HostP->Flags & RUN_STATE) != RC_WAITING ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("%s %d already running\n","Host",host));
+			continue;
+		}
+
+		/*
+		** Grab a 32 bit pointer to the card.
+		*/
+		Cad = HostP->Caddr;
+
+		/*
+		** We are going to (try) and load in rbp->Count bytes.
+		** The last byte will reside at p->RIOConf.HostLoadBase-1;
+		** Therefore, we need to start copying at address
+		** (caddr+p->RIOConf.HostLoadBase-rbp->Count)
+		*/
+		StartP = (caddr_t)&Cad[p->RIOConf.HostLoadBase-rbp->Count];
+
+		rio_dprint(RIO_DEBUG_BOOT,  ("kernel virtual address for host is 0x%x\n", (int)Cad ) );
+		rio_dprint(RIO_DEBUG_BOOT,  ("kernel virtual address for download is 0x%x\n", (int)StartP ) );
+		rio_dprint(RIO_DEBUG_BOOT, ("host loadbase is 0x%x\n",p->RIOConf.HostLoadBase));
+		rio_dprint(RIO_DEBUG_BOOT,  ("size of download is 0x%x\n", rbp->Count ) );
+
+		if ( p->RIOConf.HostLoadBase < rbp->Count ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Bin too large\n"));
+			p->RIOError.Error = HOST_FILE_TOO_LARGE;
+			return EFBIG;
+		}
+		/*
+		** Ensure that the host really is stopped.
+		** Disable it's external bus & twang its reset line.
+		*/
+		RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );
+
+		/*
+		** Copy the data directly from user space to the SRAM.
+		** This ain't going to be none too clever if the download
+		** code is bigger than this segment.
+		*/
+		rio_dprint(RIO_DEBUG_BOOT, ("Copy in code\n"));
+
+		/*
+		** PCI hostcard can't cope with 32 bit accesses and so need to copy 
+		** data to a local buffer, and then dripfeed the card.
+		*/
+		if ( HostP->Type == RIO_PCI ) {
+		  /* int offset; */
+
+			DownCode = sysbrk(rbp->Count);
+			if ( !DownCode ) {
+				rio_dprint(RIO_DEBUG_BOOT, ("No system memory available\n"));
+				p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY;
+				return ENOMEM;
+			}
+			bzero(DownCode, rbp->Count);
+
+			if ( copyin((int)rbp->DataP,DownCode,rbp->Count)==COPYFAIL ) {
+				rio_dprint(RIO_DEBUG_BOOT, ("Bad copyin of host data\n"));
+				p->RIOError.Error = COPYIN_FAILED;
+				return EFAULT;
+			}
+
+			HostP->Copy( DownCode, StartP, rbp->Count );
+
+			sysfree( DownCode, rbp->Count );
+		}
+		else if ( copyin((int)rbp->DataP,StartP,rbp->Count)==COPYFAIL ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Bad copyin of host data\n"));
+			p->RIOError.Error = COPYIN_FAILED;
+			return EFAULT;
+		}
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Copy completed\n"));
+
+		/*
+		**			S T O P !
+		**
+		** Upto this point the code has been fairly rational, and possibly
+		** even straight forward. What follows is a pile of crud that will
+		** magically turn into six bytes of transputer assembler. Normally
+		** you would expect an array or something, but, being me, I have
+		** chosen [been told] to use a technique whereby the startup code
+		** will be correct if we change the loadbase for the code. Which
+		** brings us onto another issue - the loadbase is the *end* of the
+		** code, not the start.
+		**
+		** If I were you I wouldn't start from here.
+		*/
+
+		/*
+		** We now need to insert a short boot section into
+		** the memory at the end of Sram2. This is normally (de)composed
+		** of the last eight bytes of the download code. The
+		** download has been assembled/compiled to expect to be
+		** loaded from 0x7FFF downwards. We have loaded it
+		** at some other address. The startup code goes into the small
+		** ram window at Sram2, in the last 8 bytes, which are really
+		** at addresses 0x7FF8-0x7FFF.
+		**
+		** If the loadbase is, say, 0x7C00, then we need to branch to
+		** address 0x7BFE to run the host.bin startup code. We assemble
+		** this jump manually.
+		**
+		** The two byte sequence 60 08 is loaded into memory at address
+		** 0x7FFE,F. This is a local branch to location 0x7FF8 (60 is nfix 0,
+		** which adds '0' to the .O register, complements .O, and then shifts
+		** it left by 4 bit positions, 08 is a jump .O+8 instruction. This will
+		** add 8 to .O (which was 0xFFF0), and will branch RELATIVE to the new
+		** location. Now, the branch starts from the value of .PC (or .IP or
+		** whatever the bloody register is called on this chip), and the .PC
+		** will be pointing to the location AFTER the branch, in this case
+		** .PC == 0x8000, so the branch will be to 0x8000+0xFFF8 = 0x7FF8.
+		**
+		** A long branch is coded at 0x7FF8. This consists of loading a four
+		** byte offset into .O using nfix (as above) and pfix operators. The
+		** pfix operates in exactly the same way as the nfix operator, but
+		** without the complement operation. The offset, of course, must be
+		** relative to the address of the byte AFTER the branch instruction,
+		** which will be (urm) 0x7FFC, so, our final destination of the branch
+		** (loadbase-2), has to be reached from here. Imagine that the loadbase
+		** is 0x7C00 (which it is), then we will need to branch to 0x7BFE (which
+		** is the first byte of the initial two byte short local branch of the
+		** download code).
+		**
+		** To code a jump from 0x7FFC (which is where the branch will start
+		** from) to 0x7BFE, we will need to branch 0xFC02 bytes (0x7FFC+0xFC02)=
+		** 0x7BFE.
+		** This will be coded as four bytes:
+		** 60 2C 20 02
+		** being nfix .O+0
+		**	   pfix .O+C
+		**	   pfix .O+0
+		**	   jump .O+2
+		**
+		** The nfix operator is used, so that the startup code will be
+		** compatible with the whole Tp family. (lies, damn lies, it'll never
+		** work in a month of Sundays).
+		**
+		** The nfix nyble is the 1s compliment of the nyble value you
+		** want to load - in this case we wanted 'F' so we nfix loaded '0'.
+		*/
+
+
+		/*
+		** Dest points to the top 8 bytes of Sram2. The Tp jumps
+		** to 0x7FFE at reset time, and starts executing. This is
+		** a short branch to 0x7FF8, where a long branch is coded.
+		*/
+
+		DestP = (BYTE *)&Cad[0x7FF8];	/* <<<---- READ THE ABOVE COMMENTS */
+
+#define	NFIX(N)	(0x60 | (N))	/* .O  = (~(.O + N))<<4 */
+#define	PFIX(N)	(0x20 | (N))	/* .O  =   (.O + N)<<4  */
+#define	JUMP(N)	(0x00 | (N))	/* .PC =   .PC + .O	 */
+
+		/*
+		** 0x7FFC is the address of the location following the last byte of
+		** the four byte jump instruction.
+		** READ THE ABOVE COMMENTS
+		**
+		** offset is (TO-FROM) % MEMSIZE, but with compound buggering about.
+		** Memsize is 64K for this range of Tp, so offset is a short (unsigned,
+		** cos I don't understand 2's complement).
+		*/
+		offset = (p->RIOConf.HostLoadBase-2)-0x7FFC;
+		WBYTE( DestP[0] , NFIX(((ushort)(~offset) >> (ushort)12) & 0xF) );
+		WBYTE( DestP[1] , PFIX(( offset >> 8) & 0xF) );
+		WBYTE( DestP[2] , PFIX(( offset >> 4) & 0xF) );
+		WBYTE( DestP[3] , JUMP( offset & 0xF) );
+
+		WBYTE( DestP[6] , NFIX(0) );
+		WBYTE( DestP[7] , JUMP(8) );
+
+		rio_dprint(RIO_DEBUG_BOOT, ("host loadbase is 0x%x\n",p->RIOConf.HostLoadBase));
+		rio_dprint(RIO_DEBUG_BOOT, ("startup offset is 0x%x\n",offset));
+
+		/*
+		** Flag what is going on
+		*/
+		HostP->Flags &= ~RUN_STATE;
+		HostP->Flags |= RC_STARTUP;
+
+		/*
+		** Grab a copy of the current ParmMap pointer, so we
+		** can tell when it has changed.
+		*/
+		OldParmMap = RWORD(HostP->__ParmMapR);
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Original parmmap is 0x%x\n",OldParmMap));
+
+		/*
+		** And start it running (I hope).
+		** As there is nothing dodgy or obscure about the
+		** above code, this is guaranteed to work every time.
+		*/
+		rio_dprint(RIO_DEBUG_BOOT,  ("Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n",
+		    HostP->Type, HostP->Mode, HostP->Ivec ) );
+
+		switch ( HostP->Type ) {
+			case RIO_AT:
+				rio_dprint(RIO_DEBUG_BOOT, ("Start ISA card running\n"));
+				WBYTE(HostP->Control, 
+					BOOT_FROM_RAM | EXTERNAL_BUS_ON
+					| HostP->Mode
+					| RIOAtVec2Ctrl[HostP->Ivec & 0xF] );
+				break;
+
+#ifdef FUTURE_RELEASE
+			case RIO_MCA:
+				/*
+				** MCA handles IRQ vectors differently, so we don't write 
+				** them to this register.
+				*/
+				rio_dprint(RIO_DEBUG_BOOT, ("Start MCA card running\n"));
+				WBYTE(HostP->Control, McaTpBootFromRam | McaTpBusEnable | HostP->Mode);
+				break;
+
+			case RIO_EISA:
+				/*
+				** EISA is totally different and expects OUTBZs to turn it on.
+				*/
+				rio_dprint(RIO_DEBUG_BOOT, NULL,DBG_DAEMON,"Start EISA card running\n");
+				OUTBZ( HostP->Slot, EISA_CONTROL_PORT, HostP->Mode | RIOEisaVec2Ctrl[HostP->Ivec] | EISA_TP_RUN | EISA_TP_BUS_ENABLE | EISA_TP_BOOT_FROM_RAM );
+				break;
+#endif
+
+			case RIO_PCI:
+				/*
+				** PCI is much the same as MCA. Everything is once again memory
+				** mapped, so we are writing to memory registers instead of io
+				** ports.
+				*/
+				rio_dprint(RIO_DEBUG_BOOT, ("Start PCI card running\n"));
+				WBYTE(HostP->Control, PCITpBootFromRam | PCITpBusEnable | HostP->Mode);
+				break;
+			default:
+				rio_dprint(RIO_DEBUG_BOOT, ("Unknown host type %d\n",HostP->Type));
+				break;
+		}
+		rio_dprint(RIO_DEBUG_BOOT, ("Set control port\n"));
+
+		/*
+		** Now, wait for upto five seconds for the Tp to setup the parmmap
+		** pointer:
+		*/
+		for ( wait_count=0; (wait_count<p->RIOConf.StartupTime)&&
+				(RWORD(HostP->__ParmMapR)==OldParmMap); wait_count++ ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Checkout %d, 0x%x\n",wait_count,RWORD(HostP->__ParmMapR)));
+			delay(HostP, HUNDRED_MS);
+		}
+
+		/*
+		** If the parmmap pointer is unchanged, then the host code
+		** has crashed & burned in a really spectacular way
+		*/
+		if ( RWORD(HostP->__ParmMapR) == OldParmMap ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("parmmap 0x%x\n", RWORD(HostP->__ParmMapR)));
+			rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail\n"));
+
+#define	HOST_DISABLE \
+		HostP->Flags &= ~RUN_STATE; \
+		HostP->Flags |= RC_STUFFED; \
+		RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );\
+		continue
+
+			HOST_DISABLE;
+		}
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Running 0x%x\n",RWORD(HostP->__ParmMapR)));
+
+		/*
+		** Well, the board thought it was OK, and setup its parmmap
+		** pointer. For the time being, we will pretend that this
+		** board is running, and check out what the error flag says.
+		*/
+
+		/*
+		** Grab a 32 bit pointer to the parmmap structure
+		*/
+		ParmMapP = (PARM_MAP *)RIO_PTR(Cad,RWORD(HostP->__ParmMapR));
+		rio_dprint(RIO_DEBUG_BOOT, ("ParmMapP : %x\n", (int)ParmMapP));
+		ParmMapP = (PARM_MAP *)((unsigned long)Cad + 
+						(unsigned long)((RWORD((HostP->__ParmMapR))) & 0xFFFF)); 
+		rio_dprint(RIO_DEBUG_BOOT, ("ParmMapP : %x\n", (int)ParmMapP));
+
+		/*
+		** The links entry should be 0xFFFF; we set it up
+		** with a mask to say how many PHBs to use, and 
+		** which links to use.
+		*/
+		if ( (RWORD(ParmMapP->links) & 0xFFFF) != 0xFFFF ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail %s\n", HostP->Name));
+			rio_dprint(RIO_DEBUG_BOOT, ("Links = 0x%x\n",RWORD(ParmMapP->links)));
+			HOST_DISABLE;
+		}
+
+		WWORD(ParmMapP->links , RIO_LINK_ENABLE);
+
+		/*
+		** now wait for the card to set all the parmmap->XXX stuff
+		** this is a wait of upto two seconds....
+		*/
+		rio_dprint(RIO_DEBUG_BOOT, ("Looking for init_done - %d ticks\n",p->RIOConf.StartupTime));
+		HostP->timeout_id = 0;
+		for ( wait_count=0; (wait_count<p->RIOConf.StartupTime) && 
+						!RWORD(ParmMapP->init_done); wait_count++ ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Waiting for init_done\n"));
+			delay(HostP, HUNDRED_MS);
+		}
+		rio_dprint(RIO_DEBUG_BOOT, ("OK! init_done!\n"));
+
+		if (RWORD(ParmMapP->error) != E_NO_ERROR || 
+							!RWORD(ParmMapP->init_done) ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail %s\n", HostP->Name));
+			rio_dprint(RIO_DEBUG_BOOT, ("Timedout waiting for init_done\n"));
+			HOST_DISABLE;
+		}
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Got init_done\n"));
+
+		/*
+		** It runs! It runs!
+		*/
+		rio_dprint(RIO_DEBUG_BOOT, ("Host ID %x Running\n",HostP->UniqueNum));
+
+		/*
+		** set the time period between interrupts.
+		*/
+		WWORD(ParmMapP->timer, (short)p->RIOConf.Timer );
+
+		/*
+		** Translate all the 16 bit pointers in the __ParmMapR into
+		** 32 bit pointers for the driver.
+		*/
+		HostP->ParmMapP	 =	ParmMapP;
+		HostP->PhbP		 =	(PHB*)RIO_PTR(Cad,RWORD(ParmMapP->phb_ptr));
+		HostP->RupP		 =	(RUP*)RIO_PTR(Cad,RWORD(ParmMapP->rups));
+		HostP->PhbNumP	  = (ushort*)RIO_PTR(Cad,RWORD(ParmMapP->phb_num_ptr));
+		HostP->LinkStrP	 =	(LPB*)RIO_PTR(Cad,RWORD(ParmMapP->link_str_ptr));
+
+		/*
+		** point the UnixRups at the real Rups
+		*/
+		for ( RupN = 0; RupN<MAX_RUP; RupN++ ) {
+			HostP->UnixRups[RupN].RupP		= &HostP->RupP[RupN];
+			HostP->UnixRups[RupN].Id		  = RupN+1;
+			HostP->UnixRups[RupN].BaseSysPort = NO_PORT;
+		}
+
+		for ( RupN = 0; RupN<LINKS_PER_UNIT; RupN++ ) {
+			HostP->UnixRups[RupN+MAX_RUP].RupP	= &HostP->LinkStrP[RupN].rup;
+			HostP->UnixRups[RupN+MAX_RUP].Id  = 0;
+			HostP->UnixRups[RupN+MAX_RUP].BaseSysPort = NO_PORT;
+		}
+
+		/*
+		** point the PortP->Phbs at the real Phbs
+		*/
+		for ( PortN=p->RIOFirstPortsMapped; 
+				PortN<p->RIOLastPortsMapped+PORTS_PER_RTA; PortN++ ) {
+			if ( p->RIOPortp[PortN]->HostP == HostP ) {
+				struct Port *PortP = p->RIOPortp[PortN];
+				struct PHB *PhbP;
+				/* int oldspl; */
+
+				if ( !PortP->Mapped )
+					continue;
+
+				PhbP = &HostP->PhbP[PortP->HostPort];
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				PortP->PhbP = PhbP;
+
+				PortP->TxAdd	= (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_add));
+				PortP->TxStart  = (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_start));
+				PortP->TxEnd	= (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_end));
+				PortP->RxRemove = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_remove));
+				PortP->RxStart  = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_start));
+				PortP->RxEnd	= (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_end));
+
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				/*
+				** point the UnixRup at the base SysPort
+				*/
+				if ( !(PortN % PORTS_PER_RTA) )
+					HostP->UnixRups[PortP->RupNum].BaseSysPort = PortN;
+			}
+		}
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Set the card running... \n"));
+		/*
+		** last thing - show the world that everything is in place
+		*/
+		HostP->Flags &= ~RUN_STATE;
+		HostP->Flags |= RC_RUNNING;
+	}
+	/*
+	** MPX always uses a poller. This is actually patched into the system
+	** configuration and called directly from each clock tick.
+	**
+	*/
+	p->RIOPolling = 1;
+
+	p->RIOSystemUp++;
+	
+	rio_dprint(RIO_DEBUG_BOOT, ("Done everything %x\n", HostP->Ivec));
+	return 0;
+}
+
+
+
+/*
+** Boot an RTA. If we have successfully processed this boot, then
+** return 1. If we havent, then return 0.
+*/
+int
+RIOBootRup( p, Rup, HostP, PacketP)
+struct rio_info *	p;
+uint Rup;
+struct Host *HostP;
+struct PKT *PacketP; 
+{
+	struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data;
+	struct PktCmd_M *PktReplyP;
+	struct CmdBlk *CmdBlkP;
+	uint sequence;
+
+#ifdef CHECK
+	CheckHost(Host);
+	CheckRup(Rup);
+	CheckHostP(HostP);
+	CheckPacketP(PacketP);
+#endif
+
+	/*
+	** If we haven't been told what to boot, we can't boot it.
+	*/
+	if ( p->RIONumBootPkts == 0 ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("No RTA code to download yet\n"));
+		return 0;
+	}
+
+	/* rio_dprint(RIO_DEBUG_BOOT, NULL,DBG_BOOT,"Incoming command packet\n"); */
+	/* ShowPacket( DBG_BOOT, PacketP ); */
+
+	/*
+	** Special case of boot completed - if we get one of these then we
+	** don't need a command block. For all other cases we do, so handle
+	** this first and then get a command block, then handle every other
+	** case, relinquishing the command block if disaster strikes!
+	*/
+	if ( (RBYTE(PacketP->len) & PKT_CMD_BIT) && 
+			(RBYTE(PktCmdP->Command)==BOOT_COMPLETED) )
+		return RIOBootComplete(p, HostP, Rup, PktCmdP );
+
+	/*
+	** try to unhook a command block from the command free list.
+	*/
+	if ( !(CmdBlkP = RIOGetCmdBlk()) ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("No command blocks to boot RTA! come back later.\n"));
+		return 0;
+	}
+
+	/*
+	** Fill in the default info on the command block
+	*/
+	CmdBlkP->Packet.dest_unit = Rup < (ushort)MAX_RUP ? Rup : 0;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+
+	CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
+	PktReplyP = (struct PktCmd_M *)CmdBlkP->Packet.data;
+
+	/*
+	** process COMMANDS on the boot rup!
+	*/
+	if ( RBYTE(PacketP->len) & PKT_CMD_BIT ) {
+		/*
+		** We only expect one type of command - a BOOT_REQUEST!
+		*/
+		if ( RBYTE(PktCmdP->Command) != BOOT_REQUEST ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Unexpected command %d on BOOT RUP %d of host %d\n", 
+						PktCmdP->Command,Rup,HostP-p->RIOHosts));
+			ShowPacket( DBG_BOOT, PacketP );
+			RIOFreeCmdBlk( CmdBlkP );
+			return 1;
+		}
+
+		/*
+		** Build a Boot Sequence command block
+		**
+		** 02.03.1999 ARG - ESIL 0820 fix
+		** We no longer need to use "Boot Mode", we'll always allow
+		** boot requests - the boot will not complete if the device
+		** appears in the bindings table.
+		** So, this conditional is not required ...
+		**
+		if (p->RIOBootMode == RC_BOOT_NONE)
+			**
+			** If the system is in slave mode, and a boot request is
+			** received, set command to BOOT_ABORT so that the boot
+			** will not complete.
+			**
+			PktReplyP->Command			 = BOOT_ABORT;
+		else
+		**
+		** We'll just (always) set the command field in packet reply
+		** to allow an attempted boot sequence :
+		*/
+		PktReplyP->Command = BOOT_SEQUENCE;
+
+		PktReplyP->BootSequence.NumPackets = p->RIONumBootPkts;
+		PktReplyP->BootSequence.LoadBase   = p->RIOConf.RtaLoadBase;
+		PktReplyP->BootSequence.CodeSize   = p->RIOBootCount;
+
+		CmdBlkP->Packet.len				= BOOT_SEQUENCE_LEN | PKT_CMD_BIT;
+
+		bcopy("BOOT",(void *)&CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN],4);
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Boot RTA on Host %d Rup %d - %d (0x%x) packets to 0x%x\n",
+			HostP-p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, 
+								p->RIOConf.RtaLoadBase));
+
+		/*
+		** If this host is in slave mode, send the RTA an invalid boot
+		** sequence command block to force it to kill the boot. We wait
+		** for half a second before sending this packet to prevent the RTA
+		** attempting to boot too often. The master host should then grab
+		** the RTA and make it its own.
+		*/
+		p->RIOBooting++;
+		RIOQueueCmdBlk( HostP, Rup, CmdBlkP );
+		return 1;
+	}
+
+	/*
+	** It is a request for boot data.
+	*/
+	sequence = RWORD(PktCmdP->Sequence);
+
+	rio_dprint(RIO_DEBUG_BOOT, ("Boot block %d on Host %d Rup%d\n",sequence,HostP-p->RIOHosts,Rup));
+
+	if ( sequence >= p->RIONumBootPkts ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("Got a request for packet %d, max is %d\n", sequence, 
+					p->RIONumBootPkts));
+		ShowPacket( DBG_BOOT, PacketP );
+	}
+
+	PktReplyP->Sequence = sequence;
+
+	bcopy( p->RIOBootPackets[ p->RIONumBootPkts - sequence - 1 ], 
+				PktReplyP->BootData, RTA_BOOT_DATA_SIZE );
+
+	CmdBlkP->Packet.len = PKT_MAX_DATA_LEN;
+	ShowPacket( DBG_BOOT, &CmdBlkP->Packet );
+	RIOQueueCmdBlk( HostP, Rup, CmdBlkP );
+	return 1;
+}
+
+/*
+** This function is called when an RTA been booted.
+** If booted by a host, HostP->HostUniqueNum is the booting host.
+** If booted by an RTA, HostP->Mapping[Rup].RtaUniqueNum is the booting RTA.
+** RtaUniq is the booted RTA.
+*/
+int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct PktCmd *PktCmdP )
+{
+	struct Map	*MapP = NULL;
+	struct Map	*MapP2 = NULL;
+	int	Flag;
+	int	found;
+	int	host, rta;
+	int	EmptySlot = -1;
+	int	entry, entry2;
+	char	*MyType, *MyName;
+	uint	MyLink;
+	ushort	RtaType;
+	uint	RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) +
+			  (RBYTE(PktCmdP->UniqNum[1]) << 8) +
+			  (RBYTE(PktCmdP->UniqNum[2]) << 16) +
+			  (RBYTE(PktCmdP->UniqNum[3]) << 24);
+
+	/* Was RIOBooting-- . That's bad. If an RTA sends two of them, the
+	   driver will never think that the RTA has booted... -- REW */
+	p->RIOBooting = 0;
+
+	rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot completed - BootInProgress now %d\n", p->RIOBooting));
+
+	/*
+	** Determine type of unit (16/8 port RTA).
+	*/
+	RtaType = GetUnitType(RtaUniq);
+        if ( Rup >= (ushort)MAX_RUP ) {
+	    rio_dprint(RIO_DEBUG_BOOT, ("RIO: Host %s has booted an RTA(%d) on link %c\n",
+	     HostP->Name, 8 * RtaType, RBYTE(PktCmdP->LinkNum)+'A' ));
+	} else {
+	    rio_dprint(RIO_DEBUG_BOOT, ("RIO: RTA %s has booted an RTA(%d) on link %c\n",
+	     HostP->Mapping[Rup].Name, 8 * RtaType,
+	     RBYTE(PktCmdP->LinkNum)+'A'));
+	}
+
+	rio_dprint(RIO_DEBUG_BOOT, ("UniqNum is 0x%x\n",RtaUniq));
+
+        if ( ( RtaUniq == 0x00000000 ) || ( RtaUniq == 0xffffffff ) )
+	{
+	    rio_dprint(RIO_DEBUG_BOOT, ( "Illegal RTA Uniq Number\n"));
+	    return TRUE;
+	}
+
+	/*
+	** If this RTA has just booted an RTA which doesn't belong to this
+	** system, or the system is in slave mode, do not attempt to create
+	** a new table entry for it.
+	*/
+	if (!RIOBootOk(p, HostP, RtaUniq))
+	{
+	    MyLink = RBYTE(PktCmdP->LinkNum);
+	    if (Rup < (ushort) MAX_RUP)
+	    {
+		/*
+		** RtaUniq was clone booted (by this RTA). Instruct this RTA
+		** to hold off further attempts to boot on this link for 30
+		** seconds.
+		*/
+		if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink))
+		{
+		    rio_dprint(RIO_DEBUG_BOOT, ("RTA failed to suspend booting on link %c\n",
+		     'A' + MyLink));
+		}
+	    }
+	    else
+	    {
+		/*
+		** RtaUniq was booted by this host. Set the booting link
+		** to hold off for 30 seconds to give another unit a
+		** chance to boot it.
+		*/
+		WWORD(HostP->LinkStrP[MyLink].WaitNoBoot, 30);
+	    }
+	    rio_dprint(RIO_DEBUG_BOOT, ("RTA %x not owned - suspend booting down link %c on unit %x\n",
+	      RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum));
+	    return TRUE;
+	}
+
+	/*
+	** Check for a SLOT_IN_USE entry for this RTA attached to the
+	** current host card in the driver table.
+	**
+	** If it exists, make a note that we have booted it. Other parts of
+	** the driver are interested in this information at a later date,
+	** in particular when the booting RTA asks for an ID for this unit,
+	** we must have set the BOOTED flag, and the NEWBOOT flag is used
+	** to force an open on any ports that where previously open on this
+	** unit.
+	*/
+        for ( entry=0; entry<MAX_RUP; entry++ )
+	{
+	    uint sysport;
+
+	    if ((HostP->Mapping[entry].Flags & SLOT_IN_USE) && 
+	       (HostP->Mapping[entry].RtaUniqueNum==RtaUniq))
+	    {
+	        HostP->Mapping[entry].Flags |= RTA_BOOTED|RTA_NEWBOOT;
+#if NEED_TO_FIX
+		RIO_SV_BROADCAST(HostP->svFlags[entry]);
+#endif
+		if ( (sysport=HostP->Mapping[entry].SysPort) != NO_PORT )
+		{
+		   if ( sysport < p->RIOFirstPortsBooted )
+			p->RIOFirstPortsBooted = sysport;
+		   if ( sysport > p->RIOLastPortsBooted )
+			p->RIOLastPortsBooted = sysport;
+		   /*
+		   ** For a 16 port RTA, check the second bank of 8 ports
+		   */
+		   if (RtaType == TYPE_RTA16)
+		   {
+			entry2 = HostP->Mapping[entry].ID2 - 1;
+			HostP->Mapping[entry2].Flags |= RTA_BOOTED|RTA_NEWBOOT;
+#if NEED_TO_FIX
+			RIO_SV_BROADCAST(HostP->svFlags[entry2]);
+#endif
+			sysport = HostP->Mapping[entry2].SysPort;
+			if ( sysport < p->RIOFirstPortsBooted )
+			    p->RIOFirstPortsBooted = sysport;
+			if ( sysport > p->RIOLastPortsBooted )
+			    p->RIOLastPortsBooted = sysport;
+		   }
+		}
+		if (RtaType == TYPE_RTA16) {
+		   rio_dprint(RIO_DEBUG_BOOT, ("RTA will be given IDs %d+%d\n",
+		    entry+1, entry2+1));
+		} else {
+		   rio_dprint(RIO_DEBUG_BOOT, ("RTA will be given ID %d\n",entry+1));
+		}
+		return TRUE;
+	    }
+	}
+
+	rio_dprint(RIO_DEBUG_BOOT, ("RTA not configured for this host\n"));
+
+	if ( Rup >= (ushort)MAX_RUP )
+	{
+	    /*
+	    ** It was a host that did the booting
+	    */
+	    MyType = "Host";
+	    MyName = HostP->Name;
+	}
+	else
+	{
+	    /*
+	    ** It was an RTA that did the booting
+	    */
+	    MyType = "RTA";
+	    MyName = HostP->Mapping[Rup].Name;
+	}
+#ifdef CHECK
+	CheckString(MyType);
+	CheckString(MyName);
+#endif
+
+	MyLink = RBYTE(PktCmdP->LinkNum);
+
+	/*
+	** There is no SLOT_IN_USE entry for this RTA attached to the current
+	** host card in the driver table.
+	**
+	** Check for a SLOT_TENTATIVE entry for this RTA attached to the
+	** current host card in the driver table.
+	**
+	** If we find one, then we re-use that slot.
+	*/
+	for ( entry=0; entry<MAX_RUP; entry++ )
+	{
+	    if ( (HostP->Mapping[entry].Flags & SLOT_TENTATIVE) &&
+		 (HostP->Mapping[entry].RtaUniqueNum == RtaUniq) )
+	    {
+		if (RtaType == TYPE_RTA16)
+		{
+		    entry2 = HostP->Mapping[entry].ID2 - 1;
+		    if ( (HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) &&
+			 (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq) )
+			rio_dprint(RIO_DEBUG_BOOT, ("Found previous tentative slots (%d+%d)\n",
+			 entry, entry2));
+		    else
+			continue;
+		}
+		else
+			rio_dprint(RIO_DEBUG_BOOT, ("Found previous tentative slot (%d)\n",entry));
+		if (! p->RIONoMessage)
+		    cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A');
+		return TRUE;
+	    }
+	}
+
+	/*
+	** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	** attached to the current host card in the driver table.
+	**
+	** Check if there is a SLOT_IN_USE or SLOT_TENTATIVE entry on another
+	** host for this RTA in the driver table.
+	**
+	** For a SLOT_IN_USE entry on another host, we need to delete the RTA
+	** entry from the other host and add it to this host (using some of
+	** the functions from table.c which do this).
+	** For a SLOT_TENTATIVE entry on another host, we must cope with the
+	** following scenario:
+	**
+	** + Plug 8 port RTA into host A. (This creates SLOT_TENTATIVE entry
+	**   in table)
+	** + Unplug RTA and plug into host B. (We now have 2 SLOT_TENTATIVE
+	**   entries)
+	** + Configure RTA on host B. (This slot now becomes SLOT_IN_USE)
+	** + Unplug RTA and plug back into host A.
+	** + Configure RTA on host A. We now have the same RTA configured
+	**   with different ports on two different hosts.
+	*/
+	rio_dprint(RIO_DEBUG_BOOT, ("Have we seen RTA %x before?\n", RtaUniq ));
+	found = 0;
+	Flag = 0; /* Convince the compiler this variable is initialized */
+	for ( host = 0; !found && (host < p->RIONumHosts); host++ )
+	{
+	    for ( rta=0; rta<MAX_RUP; rta++ )
+	    {
+		if ((p->RIOHosts[host].Mapping[rta].Flags &
+		 (SLOT_IN_USE | SLOT_TENTATIVE)) &&
+		 (p->RIOHosts[host].Mapping[rta].RtaUniqueNum==RtaUniq))
+		{
+		    Flag = p->RIOHosts[host].Mapping[rta].Flags;
+		    MapP = &p->RIOHosts[host].Mapping[rta];
+		    if (RtaType == TYPE_RTA16)
+		    {
+			MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1];
+			rio_dprint(RIO_DEBUG_BOOT, ("This RTA is units %d+%d from host %s\n",
+			 rta+1, MapP->ID2, p->RIOHosts[host].Name ));
+		    }
+		    else
+			rio_dprint(RIO_DEBUG_BOOT, ("This RTA is unit %d from host %s\n",
+			 rta+1, p->RIOHosts[host].Name ));
+		    found = 1;
+		    break;
+		}
+	    }
+	}
+
+	/*
+	** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	** attached to the current host card in the driver table.
+	**
+	** If we have not found a SLOT_IN_USE or SLOT_TENTATIVE entry on
+	** another host for this RTA in the driver table...
+	**
+	** Check for a SLOT_IN_USE entry for this RTA in the config table.
+	*/
+	if ( !MapP )
+	{
+	    rio_dprint(RIO_DEBUG_BOOT, ("Look for RTA %x in RIOSavedTable\n",RtaUniq));
+	    for ( rta=0; rta < TOTAL_MAP_ENTRIES; rta++ )
+	    {
+		rio_dprint(RIO_DEBUG_BOOT, ("Check table entry %d (%x)",
+		      rta,
+		      p->RIOSavedTable[rta].RtaUniqueNum ));
+
+		if ( (p->RIOSavedTable[rta].Flags & SLOT_IN_USE) &&
+		 (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq) )
+		{
+		    MapP = &p->RIOSavedTable[rta];
+		    Flag = p->RIOSavedTable[rta].Flags;
+		    if (RtaType == TYPE_RTA16)
+		    {
+                        for (entry2 = rta + 1; entry2 < TOTAL_MAP_ENTRIES;
+                         entry2++)
+                        {
+                            if (p->RIOSavedTable[entry2].RtaUniqueNum == RtaUniq)
+                                break;
+                        }
+                        MapP2 = &p->RIOSavedTable[entry2];
+                        rio_dprint(RIO_DEBUG_BOOT, ("This RTA is from table entries %d+%d\n",
+                              rta, entry2));
+		    }
+		    else
+			rio_dprint(RIO_DEBUG_BOOT, ("This RTA is from table entry %d\n", rta));
+		    break;
+		}
+	    }
+	}
+
+	/*
+	** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	** attached to the current host card in the driver table.
+	**
+	** We may have found a SLOT_IN_USE entry on another host for this
+	** RTA in the config table, or a SLOT_IN_USE or SLOT_TENTATIVE entry
+	** on another host for this RTA in the driver table.
+	**
+	** Check the driver table for room to fit this newly discovered RTA.
+	** RIOFindFreeID() first looks for free slots and if it does not
+	** find any free slots it will then attempt to oust any
+	** tentative entry in the table.
+	*/
+	EmptySlot = 1;
+	if (RtaType == TYPE_RTA16)
+	{
+	    if (RIOFindFreeID(p, HostP, &entry, &entry2) == 0)
+	    {
+		RIODefaultName(p, HostP, entry);
+		FillSlot(entry, entry2, RtaUniq, HostP);
+		EmptySlot = 0;
+	    }
+	}
+	else
+	{
+	    if (RIOFindFreeID(p, HostP, &entry, NULL) == 0)
+	    {
+		RIODefaultName(p, HostP, entry);
+		FillSlot(entry, 0, RtaUniq, HostP);
+		EmptySlot = 0;
+	    }
+	}
+
+	/*
+	** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	** attached to the current host card in the driver table.
+	**
+	** If we found a SLOT_IN_USE entry on another host for this
+	** RTA in the config or driver table, and there are enough free
+	** slots in the driver table, then we need to move it over and
+	** delete it from the other host.
+	** If we found a SLOT_TENTATIVE entry on another host for this
+	** RTA in the driver table, just delete the other host entry.
+	*/
+	if (EmptySlot == 0)
+	{
+	    if ( MapP )
+	    {
+		if (Flag & SLOT_IN_USE)
+		{
+		    rio_dprint(RIO_DEBUG_BOOT, (
+    "This RTA configured on another host - move entry to current host (1)\n"));
+		    HostP->Mapping[entry].SysPort = MapP->SysPort;
+		    CCOPY( MapP->Name, HostP->Mapping[entry].Name, MAX_NAME_LEN );
+		    HostP->Mapping[entry].Flags =
+		     SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT;
+#if NEED_TO_FIX
+		    RIO_SV_BROADCAST(HostP->svFlags[entry]);
+#endif
+		    RIOReMapPorts( p, HostP, &HostP->Mapping[entry] );
+		    if ( HostP->Mapping[entry].SysPort < p->RIOFirstPortsBooted )
+			p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort;
+		    if ( HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted )
+			p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort;
+		    rio_dprint(RIO_DEBUG_BOOT, ("SysPort %d, Name %s\n",(int)MapP->SysPort,MapP->Name));
+		}
+		else
+		{
+		    rio_dprint(RIO_DEBUG_BOOT, (
+   "This RTA has a tentative entry on another host - delete that entry (1)\n"));
+		    HostP->Mapping[entry].Flags =
+		     SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT;
+#if NEED_TO_FIX
+		    RIO_SV_BROADCAST(HostP->svFlags[entry]);
+#endif
+		}
+		if (RtaType == TYPE_RTA16)
+		{
+		    if (Flag & SLOT_IN_USE)
+		    {
+			HostP->Mapping[entry2].Flags = SLOT_IN_USE |
+			 RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
+#if NEED_TO_FIX
+			RIO_SV_BROADCAST(HostP->svFlags[entry2]);
+#endif
+			HostP->Mapping[entry2].SysPort = MapP2->SysPort;
+			/*
+			** Map second block of ttys for 16 port RTA
+			*/
+			RIOReMapPorts( p, HostP, &HostP->Mapping[entry2] );
+		       if (HostP->Mapping[entry2].SysPort < p->RIOFirstPortsBooted)
+			 p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort;
+		       if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted)
+			 p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort;
+			rio_dprint(RIO_DEBUG_BOOT, ("SysPort %d, Name %s\n",
+			       (int)HostP->Mapping[entry2].SysPort,
+			       HostP->Mapping[entry].Name));
+		    }
+		    else
+			HostP->Mapping[entry2].Flags = SLOT_TENTATIVE |
+			 RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
+#if NEED_TO_FIX
+			RIO_SV_BROADCAST(HostP->svFlags[entry2]);
+#endif
+		    bzero( (caddr_t)MapP2, sizeof(struct Map) );
+		}
+		bzero( (caddr_t)MapP, sizeof(struct Map) );
+		if (! p->RIONoMessage)
+		    cprintf("An orphaned RTA has been adopted by %s '%s' (%c).\n",MyType,MyName,MyLink+'A');
+	    }
+	    else if (! p->RIONoMessage)
+		cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A');
+	    RIOSetChange(p);
+	    return TRUE;
+	}
+
+	/*
+	** There is no room in the driver table to make an entry for the
+	** booted RTA. Keep a note of its Uniq Num in the overflow table,
+	** so we can ignore it's ID requests.
+	*/
+	if (! p->RIONoMessage)
+	    cprintf("The RTA connected to %s '%s' (%c) cannot be configured.  You cannot configure more than 128 ports to one host card.\n",MyType,MyName,MyLink+'A');
+	for ( entry=0; entry<HostP->NumExtraBooted; entry++ )
+	{
+	    if ( HostP->ExtraUnits[entry] == RtaUniq )
+	    {
+		/*
+		** already got it!
+		*/
+		return TRUE;
+	    }
+	}
+	/*
+	** If there is room, add the unit to the list of extras
+	*/
+	if ( HostP->NumExtraBooted < MAX_EXTRA_UNITS )
+	    HostP->ExtraUnits[HostP->NumExtraBooted++] = RtaUniq;
+	return TRUE;
+}
+
+
+/*
+** If the RTA or its host appears in the RIOBindTab[] structure then
+** we mustn't boot the RTA and should return FALSE.
+** This operation is slightly different from the other drivers for RIO
+** in that this is designed to work with the new utilities
+** not config.rio and is FAR SIMPLER.
+** We no longer support the RIOBootMode variable. It is all done from the
+** "boot/noboot" field in the rio.cf file.
+*/
+int
+RIOBootOk(p, HostP, RtaUniq)
+struct rio_info *	p;
+struct Host *		HostP;
+ulong RtaUniq;
+{
+    int		Entry;
+    uint HostUniq = HostP->UniqueNum;
+
+	/*
+	** Search bindings table for RTA or its parent.
+	** If it exists, return 0, else 1.
+	*/
+	for (Entry = 0;
+	    ( Entry < MAX_RTA_BINDINGS ) && ( p->RIOBindTab[Entry] != 0 );
+	    Entry++)
+	{
+		if ( (p->RIOBindTab[Entry] == HostUniq) ||
+		     (p->RIOBindTab[Entry] == RtaUniq) )
+			return 0;
+	}
+	return 1;
+}
+
+/*
+** Make an empty slot tentative. If this is a 16 port RTA, make both
+** slots tentative, and the second one RTA_SECOND_SLOT as well.
+*/
+
+void
+FillSlot(entry, entry2, RtaUniq, HostP)
+int entry;
+int entry2;
+uint RtaUniq;
+struct Host *HostP;
+{
+	int		link;
+
+	rio_dprint(RIO_DEBUG_BOOT, ("FillSlot(%d, %d, 0x%x...)\n", entry, entry2, RtaUniq));
+
+	HostP->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE);
+	HostP->Mapping[entry].SysPort = NO_PORT;
+	HostP->Mapping[entry].RtaUniqueNum = RtaUniq;
+	HostP->Mapping[entry].HostUniqueNum = HostP->UniqueNum;
+	HostP->Mapping[entry].ID = entry + 1;
+	HostP->Mapping[entry].ID2 = 0;
+	if (entry2) {
+		HostP->Mapping[entry2].Flags = (RTA_BOOTED | RTA_NEWBOOT | 
+								SLOT_TENTATIVE | RTA16_SECOND_SLOT);
+		HostP->Mapping[entry2].SysPort = NO_PORT;
+		HostP->Mapping[entry2].RtaUniqueNum = RtaUniq;
+		HostP->Mapping[entry2].HostUniqueNum = HostP->UniqueNum;
+		HostP->Mapping[entry2].Name[0] = '\0';
+		HostP->Mapping[entry2].ID = entry2 + 1;
+		HostP->Mapping[entry2].ID2 = entry + 1;
+		HostP->Mapping[entry].ID2 = entry2 + 1;
+	}
+	/*
+	** Must set these up, so that utilities show
+	** topology of 16 port RTAs correctly
+	*/
+	for ( link=0; link<LINKS_PER_UNIT; link++ ) {
+		HostP->Mapping[entry].Topology[link].Unit = ROUTE_DISCONNECT;
+		HostP->Mapping[entry].Topology[link].Link = NO_LINK;
+		if (entry2) {
+			HostP->Mapping[entry2].Topology[link].Unit = ROUTE_DISCONNECT;
+			HostP->Mapping[entry2].Topology[link].Link = NO_LINK;
+		}
+	}
+}
+
+#if 0
+/*
+	Function:	This function is to disable the disk interrupt 
+    Returns :   Nothing
+*/
+void
+disable_interrupt(vector)
+int	vector;
+{
+	int	ps;
+	int	val;
+
+	disable(ps);
+	if (vector > 40)  {
+		val = 1 << (vector - 40);
+		__outb(S8259+1, __inb(S8259+1) | val);
+	}
+	else {
+		val = 1 << (vector - 32);
+		__outb(M8259+1, __inb(M8259+1) | val);
+	}
+	restore(ps);
+}
+
+/*
+	Function:	This function is to enable the disk interrupt 
+    Returns :   Nothing
+*/
+void
+enable_interrupt(vector)
+int	vector;
+{
+	int	ps;
+	int	val;
+
+	disable(ps);
+	if (vector > 40)  {
+		val = 1 << (vector - 40);
+		val = ~val;
+		__outb(S8259+1, __inb(S8259+1) & val);
+	}
+	else {
+		val = 1 << (vector - 32);
+		val = ~val;
+		__outb(M8259+1, __inb(M8259+1) & val);
+	}
+	restore(ps);
+}
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/riocmd.c linux/drivers/char/rio/riocmd.c
--- linux-2.2.15-pre2/drivers/char/rio/riocmd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riocmd.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1146 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  ported from the existing SCO driver source
+**
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riocmd.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:41
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)riocmd.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riocmd_c_sccs_ = "@(#)riocmd.c	1.2";
+#endif
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/spinlock.h>
+
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+
+
+static struct IdentifyRta IdRta;
+static struct KillNeighbour KillUnit;
+
+int
+RIOFoadRta(HostP, MapP)
+struct Host *	HostP;
+struct Map *	MapP;
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA\n"));
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if ( !CmdBlkP ) {
+		rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA: GetCmdBlk failed\n"));
+		return ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = MapP->ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+	CmdBlkP->Packet.len	   = 0x84;
+	CmdBlkP->Packet.data[0]   = IFOAD;
+	CmdBlkP->Packet.data[1]   = 0;
+	CmdBlkP->Packet.data[2]   = IFOAD_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3]   = (IFOAD_MAGIC >> 8) & 0xFF;
+
+	if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA: Failed to queue foad command\n"));
+		return EIO;
+	}
+	return 0;
+}
+
+int
+RIOZombieRta(HostP, MapP)
+struct Host *	HostP;
+struct Map *	MapP;
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA\n"));
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if ( !CmdBlkP ) {
+		rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA: GetCmdBlk failed\n"));
+		return ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = MapP->ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+	CmdBlkP->Packet.len	   = 0x84;
+	CmdBlkP->Packet.data[0]   = ZOMBIE;
+	CmdBlkP->Packet.data[1]   = 0;
+	CmdBlkP->Packet.data[2]   = ZOMBIE_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3]   = (ZOMBIE_MAGIC >> 8) & 0xFF;
+
+	if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA: Failed to queue zombie command\n"));
+		return EIO;
+	}
+	return 0;
+}
+
+int
+RIOCommandRta(p, RtaUnique, func)
+struct rio_info *	p;
+uint RtaUnique;
+int (* func)( struct Host *HostP, struct Map *MapP );
+{
+	uint Host;
+
+	rio_dprint(RIO_DEBUG_CMD, ("Command RTA 0x%x func 0x%x\n", RtaUnique, (int)func ));
+
+	if ( !RtaUnique )
+		return(0);
+
+	for ( Host = 0; Host < p->RIONumHosts; Host++ ) {
+		uint Rta;
+		struct Host *HostP = &p->RIOHosts[Host];
+
+		for ( Rta = 0; Rta < RTAS_PER_HOST; Rta++ ) {
+			struct Map *MapP = &HostP->Mapping[Rta];
+
+			if ( MapP->RtaUniqueNum == RtaUnique ) {
+				uint Link;
+
+				/*
+				** now, lets just check we have a route to it...
+				** IF the routing stuff is working, then one of the
+				** topology entries for this unit will have a legit
+				** route *somewhere*. We care not where - if its got
+				** any connections, we can get to it.
+				*/
+				for ( Link = 0; Link < LINKS_PER_UNIT; Link++ ) {
+					if ( MapP->Topology[Link].Unit <= (uchar)MAX_RUP ) {
+						/*
+						** Its worth trying the operation...
+						*/
+						return (*func)( HostP, MapP );
+					}
+				}
+			}
+		}
+	}
+	return ENXIO;
+}
+
+
+int
+RIOIdentifyRta(p, arg)
+struct rio_info *	p;
+caddr_t arg;
+{
+	uint Host;
+
+	if ( copyin( (int)arg, (caddr_t)&IdRta, sizeof(IdRta) ) == COPYFAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("RIO_IDENTIFY_RTA copy failed\n"));
+		p->RIOError.Error = COPYIN_FAILED;
+		return EFAULT;
+	}
+
+	for ( Host = 0 ; Host < p->RIONumHosts; Host++ ) {
+		uint Rta;
+		struct Host *HostP = &p->RIOHosts[Host];
+
+		for ( Rta = 0; Rta < RTAS_PER_HOST; Rta++ ) {
+			struct Map *MapP = &HostP->Mapping[Rta];
+
+			if ( MapP->RtaUniqueNum == IdRta.RtaUnique ) {
+				uint Link;
+				/*
+				** now, lets just check we have a route to it...
+				** IF the routing stuff is working, then one of the
+				** topology entries for this unit will have a legit
+				** route *somewhere*. We care not where - if its got
+				** any connections, we can get to it.
+				*/
+				for ( Link = 0; Link < LINKS_PER_UNIT; Link++ ) {
+					if ( MapP->Topology[Link].Unit <= (uchar)MAX_RUP ) {
+						/*
+						** Its worth trying the operation...
+						*/
+						struct CmdBlk *CmdBlkP;
+
+						rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA\n"));
+
+						CmdBlkP = RIOGetCmdBlk();
+
+						if ( !CmdBlkP ) {
+							rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA: GetCmdBlk failed\n"));
+							return ENXIO;
+						}
+		
+						CmdBlkP->Packet.dest_unit = MapP->ID;
+						CmdBlkP->Packet.dest_port = BOOT_RUP;
+						CmdBlkP->Packet.src_unit  = 0;
+						CmdBlkP->Packet.src_port  = BOOT_RUP;
+						CmdBlkP->Packet.len	   = 0x84;
+						CmdBlkP->Packet.data[0]   = IDENTIFY;
+						CmdBlkP->Packet.data[1]   = 0;
+						CmdBlkP->Packet.data[2]   = IdRta.ID;
+		
+						if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) 
+										== RIO_FAIL ) {
+							rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA: Failed to queue command\n"));
+							return EIO;
+						}
+						return 0;
+					}
+				}
+			}
+		}
+	} 
+	return ENOENT;
+}
+
+
+int
+RIOKillNeighbour(p, arg)
+struct rio_info *	p;
+caddr_t arg;
+{
+	uint Host;
+	uint ID;
+	struct Host *HostP;
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("KILL HOST NEIGHBOUR\n"));
+
+	if ( copyin( (int)arg, (caddr_t)&KillUnit, 
+					sizeof(KillUnit) ) == COPYFAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("RIO_KILL_NEIGHBOUR copy failed\n"));
+		p->RIOError.Error = COPYIN_FAILED;
+		return EFAULT;
+	}
+
+	if ( KillUnit.Link > 3 )
+		return ENXIO;
+ 
+	CmdBlkP = RIOGetCmdBlk();
+
+	if ( !CmdBlkP ) {
+		rio_dprint(RIO_DEBUG_CMD, ("UFOAD: GetCmdBlk failed\n"));
+		return ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = 0;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+	CmdBlkP->Packet.len	   = 0x84;
+	CmdBlkP->Packet.data[0]   = UFOAD;
+	CmdBlkP->Packet.data[1]   = KillUnit.Link;
+	CmdBlkP->Packet.data[2]   = UFOAD_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3]   = (UFOAD_MAGIC >> 8) & 0xFF;
+
+	for ( Host = 0; Host < p->RIONumHosts; Host++ ) {
+		ID = 0;
+		HostP = &p->RIOHosts[Host];
+
+		if ( HostP->UniqueNum == KillUnit.UniqueNum ) {
+			if ( RIOQueueCmdBlk( HostP, RTAS_PER_HOST+KillUnit.Link,
+							CmdBlkP) == RIO_FAIL ) {
+				rio_dprint(RIO_DEBUG_CMD, ("UFOAD: Failed queue command\n"));
+				return EIO;
+			}
+			return 0;
+		}
+
+		for ( ID=0; ID < RTAS_PER_HOST; ID++ ) {
+			if ( HostP->Mapping[ID].RtaUniqueNum == KillUnit.UniqueNum ) {
+				CmdBlkP->Packet.dest_unit = ID+1;
+				if ( RIOQueueCmdBlk( HostP, ID, CmdBlkP) == RIO_FAIL ) {
+					rio_dprint(RIO_DEBUG_CMD, ("UFOAD: Failed queue command\n"));
+					return EIO;
+				}
+				return 0;
+			}
+		}
+	}
+	RIOFreeCmdBlk( CmdBlkP );
+	return ENXIO;
+}
+
+int
+RIOSuspendBootRta(HostP, ID, Link)
+struct Host *HostP;
+int ID;
+int Link; 
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link));
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if ( !CmdBlkP ) {
+		rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA: GetCmdBlk failed\n"));
+		return ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+	CmdBlkP->Packet.len	   = 0x84;
+	CmdBlkP->Packet.data[0]   = IWAIT;
+	CmdBlkP->Packet.data[1]   = Link;
+	CmdBlkP->Packet.data[2]   = IWAIT_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3]   = (IWAIT_MAGIC >> 8) & 0xFF;
+
+	if ( RIOQueueCmdBlk( HostP, ID - 1, CmdBlkP) == RIO_FAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA: Failed to queue iwait command\n"));
+		return EIO;
+	}
+	return 0;
+}
+
+int
+RIOFoadWakeup(p)
+struct rio_info *	p;
+{
+	int port;
+	register struct Port *PortP;
+	unsigned long flags;
+
+	for ( port=0; port<RIO_PORTS; port++) {
+		PortP = p->RIOPortp[port];
+
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->Config = 0;
+		PortP->State = 0;
+		PortP->InUse = NOT_INUSE;
+		PortP->PortState = 0;
+		PortP->FlushCmdBodge = 0;
+		PortP->ModemLines = 0;
+		PortP->ModemState = 0;
+		PortP->CookMode = 0;
+		PortP->ParamSem = 0;
+		PortP->Mapped = 0;
+		PortP->WflushFlag = 0;
+		PortP->MagicFlags = 0;
+		PortP->RxDataStart = 0;
+		PortP->TxBufferIn = 0;
+		PortP->TxBufferOut = 0;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	}
+	return(0);
+}
+
+/*
+** Incoming command on the COMMAND_RUP to be processed.
+*/
+int
+RIOCommandRup(p, Rup, HostP, PacketP)
+struct rio_info *	p;
+uint Rup;
+struct Host *HostP;
+PKT *PacketP; 
+{
+	struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data;
+	struct Port *PortP;
+	struct UnixRup *UnixRupP;
+	ushort SysPort;
+	ushort ReportedModemStatus;
+	ushort rup;
+	ushort subCommand;
+	unsigned long flags;
+
+
+#ifdef CHECK
+	CheckHost( Host );
+	CheckHostP( HostP );
+	CheckPacketP( PacketP );
+#endif
+
+	/*
+	** 16 port RTA note:
+	** Command rup packets coming from the RTA will have pkt->data[1] (which
+	** translates to PktCmdP->PhbNum) set to the host port number for the
+	** particular unit. To access the correct BaseSysPort for a 16 port RTA,
+	** we can use PhbNum to get the rup number for the appropriate 8 port
+	** block (for the first block, this should be equal to 'Rup').
+	*/
+	rup = RBYTE(PktCmdP->PhbNum) / (ushort)PORTS_PER_RTA;
+	UnixRupP = &HostP->UnixRups[rup];
+	SysPort = UnixRupP->BaseSysPort + 
+			(RBYTE(PktCmdP->PhbNum) % (ushort)PORTS_PER_RTA);
+	rio_dprint(RIO_DEBUG_CMD, ("Command on rup %d, port %d\n", rup, SysPort));
+
+#ifdef CHECK
+	CheckRup( rup );
+	CheckUnixRupP( UnixRupP );
+#endif
+	if ( UnixRupP->BaseSysPort == NO_PORT ) {
+		rio_dprint(RIO_DEBUG_CMD, ("OBSCURE ERROR!\n"));
+		rio_dprint(RIO_DEBUG_CMD, ("Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n"));
+		rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: Host number %d, name ``%s''\n", 
+					HostP-p->RIOHosts, HostP->Name ));
+		rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: Rup number  0x%x\n", rup));
+
+		if ( Rup >= (ushort)MAX_RUP )
+			rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: This is the RUP for RTA ``%s''\n",
+						HostP->Mapping[Rup].Name ));
+		else
+			rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", 'A' + Rup - MAX_RUP, HostP->Name ));
+
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Destination 0x%x:0x%x\n",
+					PacketP->dest_unit, PacketP->dest_port ));
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Source	  0x%x:0x%x\n",
+					PacketP->src_unit, PacketP->src_port ));
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Length	  0x%x (%d)\n", PacketP->len,PacketP->len ));
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Control	 0x%x (%d)\n", PacketP->control, PacketP->control));
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Check	   0x%x (%d)\n", PacketP->csum, PacketP->csum ));
+		rio_dprint(RIO_DEBUG_CMD, ("COMMAND information: Host Port Number 0x%x, 
+					Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command ));
+		return TRUE;
+	}
+
+#ifdef CHECK
+	CheckSysPort( SysPort );
+#endif
+	PortP = p->RIOPortp[ SysPort ];
+#if 0
+	ttyP = PortP->TtyP;
+#endif
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	switch( RBYTE(PktCmdP->Command) ) {
+		case BREAK_RECEIVED:
+			rio_dprint(RIO_DEBUG_CMD, ("Received a break!\n"));
+			/* If the current line disc. is not multi-threading and
+	   			the current processor is not the default, reset rup_intr
+	   			and return FALSE to ensure that the command packet is
+	   			not freed. */
+			/* Call tmgr HANGUP HERE */
+			/* Fix this later when every thing works !!!! RAMRAJ */
+			break;
+
+		case COMPLETE:
+			rio_dprint(RIO_DEBUG_CMD, ("Command complete on phb %d host %d\n",
+							RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts));
+			subCommand = 1;
+			switch (RBYTE(PktCmdP->SubCommand)) {
+				case MEMDUMP :
+					rio_dprint(RIO_DEBUG_CMD, ("Memory dump cmd (0x%x) from addr 0x%x\n",
+		 				RBYTE(PktCmdP->SubCommand), RWORD(PktCmdP->SubAddr)));
+					break;
+				case READ_REGISTER :
+					rio_dprint(RIO_DEBUG_CMD, ("Read register (0x%x)\n", RWORD(PktCmdP->SubAddr)));
+					p->CdRegister = (RBYTE(PktCmdP->ModemStatus) & MSVR1_HOST);
+					break;
+				default :
+					subCommand = 0;
+				break;
+			}
+			if (subCommand)
+				break;
+			rio_dprint(RIO_DEBUG_CMD, ("New status is 0x%x was 0x%x\n",
+					 RBYTE(PktCmdP->PortStatus),PortP->PortState));
+			if (PortP->PortState != RBYTE(PktCmdP->PortStatus)) {
+				rio_dprint(RIO_DEBUG_CMD, ("Mark status & wakeup\n"));
+				PortP->PortState = RBYTE(PktCmdP->PortStatus);
+				/* What should we do here ...
+				wakeup( &PortP->PortState );
+				*/
+			}
+			else {
+				rio_dprint(RIO_DEBUG_CMD, ("No change\n"));
+			}
+
+			/* FALLTHROUGH */
+		case MODEM_STATUS:
+			/*
+			** Knock out the tbusy and tstop bits, as these are not relevant
+			** to the check for modem status change (they're just there because
+			** it's a convenient place to put them!).
+			*/
+			ReportedModemStatus = RBYTE(PktCmdP->ModemStatus);
+			if ((PortP->ModemState & MSVR1_HOST) ==
+					(ReportedModemStatus & MSVR1_HOST)) {
+				rio_dprint(RIO_DEBUG_CMD, ("Modem status unchanged 0x%x\n", PortP->ModemState));
+				/*
+				** Update ModemState just in case tbusy or tstop states have
+				** changed.
+				*/
+				PortP->ModemState = ReportedModemStatus;
+			}
+			else {
+				rio_dprint(RIO_DEBUG_CMD, ("Modem status change from 0x%x to 0x%x\n",
+							 PortP->ModemState, ReportedModemStatus));
+				PortP->ModemState = ReportedModemStatus;
+#ifdef MODEM_SUPPORT
+				if ( PortP->Mapped ) {
+				/***********************************************************\
+				*************************************************************
+				***													   ***
+				***		  M O D E M   S T A T E   C H A N G E		  ***
+				***													   ***
+				*************************************************************
+				\***********************************************************/
+				/*
+				** If the device is a modem, then check the modem
+				** carrier.
+				*/
+				if(!(ttyP->t_cflag & CLOCAL) && 
+					((PortP->State & (RIO_MOPEN|RIO_WOPEN))))
+				{
+			/*
+			** Is there a carrier?
+			*/
+			if ( PortP->ModemState & MSVR1_CD )
+			{
+			/*
+			** Has carrier just appeared?
+			*/
+			if (!(ttyP->t_state & CARR_ON))
+			{
+				rio_dprint(RIO_DEBUG_CMD, PortP,DBG_MODEM,"Carrier just came up.\n");
+				ttyP->t_state |=CARR_ON;
+				/*
+				** wakeup anyone in WOPEN
+				*/
+				if ( ttyP->t_state & (ISOPEN|WOPEN) )
+				wakeup((caddr_t)&ttyP->t_canq);
+#ifdef STATS
+				PortP->Stat.ModemOnCnt++;
+#endif
+			}
+			}
+			else
+			{
+			/*
+			** Has carrier just dropped?
+			*/
+			if (ttyP->t_state & CARR_ON)
+			{
+				/*
+				** send SIGHUP to the process group
+				*/
+				if ( ttyP->t_state & (ISOPEN|WOPEN) )
+				{
+				signal(ttyP->t_pgrp,SIGHUP);
+				ttyflush(ttyP,(FREAD|FWRITE));
+				}
+				ttyP->t_state &= ~CARR_ON;
+				wakeup( (caddr_t)&PortP->TxBufferOut );
+				wakeup( (caddr_t)&PortP->TxBufferIn );
+				rio_dprint(RIO_DEBUG_CMD, PortP,DBG_MODEM,"Carrier just went down.\n");
+#ifdef STATS
+				PortP->Stat.ModemOffCnt++;
+#endif
+			}
+			}
+		}
+		}
+#endif
+			}
+			break;
+
+		default:
+			rio_dprint(RIO_DEBUG_CMD, ("Unknown command %d on CMD_RUP of host %d\n",
+				RBYTE(PktCmdP->Command),HostP-p->RIOHosts));
+			break;
+	}
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return TRUE;
+}
+/*
+** The command mechanism:
+**	Each rup has a chain of commands associated with it.
+**	This chain is maintained by routines in this file.
+**	Periodically we are called and we run a quick check of all the
+**	active chains to determine if there is a command to be executed,
+**	and if the rup is ready to accept it.
+**
+*/
+
+/*
+** Allocate an empty command block.
+*/
+struct CmdBlk *
+RIOGetCmdBlk()
+{
+	struct CmdBlk *CmdBlkP;
+
+	CmdBlkP = (struct CmdBlk *)sysbrk(sizeof(struct CmdBlk));
+	bzero(CmdBlkP, sizeof(struct CmdBlk));
+
+	return CmdBlkP;
+}
+
+/*
+** Return a block to the head of the free list.
+*/
+void
+RIOFreeCmdBlk(CmdBlkP)
+struct CmdBlk *CmdBlkP;
+{
+	sysfree((void *)CmdBlkP, sizeof(struct CmdBlk));
+}
+
+/*
+** attach a command block to the list of commands to be performed for
+** a given rup.
+*/
+int
+RIOQueueCmdBlk(HostP, Rup, CmdBlkP)
+struct Host *HostP;
+uint Rup;
+struct CmdBlk *CmdBlkP;
+{
+	struct CmdBlk **Base;
+	struct UnixRup *UnixRupP;
+	unsigned long flags;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckRup( Rup );
+	CheckCmdBlkP( CmdBlkP );
+#endif
+
+	rio_dprint(RIO_DEBUG_CMD, ("RIOQueueCmdBlk(Host, Rup %d, 0x%x)\n", Rup, (int)CmdBlkP ));
+
+	if ( Rup >= (ushort)(MAX_RUP+LINKS_PER_UNIT) ) {
+		rio_dprint(RIO_DEBUG_CMD, ("Illegal rup number %d in RIOQueueCmdBlk\n",Rup));
+		RIOFreeCmdBlk( CmdBlkP );
+		return RIO_FAIL;
+	}
+
+	UnixRupP = &HostP->UnixRups[Rup];
+
+	rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+
+	/*
+	** If the RUP is currently inactive, then put the request
+	** straight on the RUP....
+	*/
+	if ( (UnixRupP->CmdsWaitingP == NULL) && (UnixRupP->CmdPendingP == NULL) && 
+		(RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) &&
+		(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg,CmdBlkP)
+							:TRUE)) {
+		rio_dprint(RIO_DEBUG_CMD, ("RUP inactive-placing command straight on. Cmd byte is 0x%x\n",
+					CmdBlkP->Packet.data[0]));
+
+		/*
+		** Whammy! blat that pack!
+		*/
+		HostP->Copy( (caddr_t)&CmdBlkP->Packet, 
+			RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt ), sizeof(PKT) );
+
+		/*
+		** place command packet on the pending position.
+		*/
+		UnixRupP->CmdPendingP = CmdBlkP;
+
+		/*
+		** set the command register
+		*/
+		WWORD(UnixRupP->RupP->txcontrol , TX_PACKET_READY);
+
+		rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+
+		return RIO_SUCCESS;
+	}
+
+	rio_dprint(RIO_DEBUG_CMD, ("RUP active - en-queing\n"));
+
+	if ( UnixRupP->CmdsWaitingP != NULL)
+		rio_dprint(RIO_DEBUG_CMD, ("Rup active - command waiting\n"));
+	if ( UnixRupP->CmdPendingP != NULL )
+		rio_dprint(RIO_DEBUG_CMD, ("Rup active - command pending\n"));
+	if ( RWORD(UnixRupP->RupP->txcontrol) != TX_RUP_INACTIVE )
+		rio_dprint(RIO_DEBUG_CMD, ("Rup active - command rup not ready\n"));
+
+	Base = &UnixRupP->CmdsWaitingP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("First try to queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base));
+
+	while ( *Base ) {
+		rio_dprint(RIO_DEBUG_CMD, ("Command cmdblk 0x%x here\n",(int)(*Base)));
+		Base = &((*Base)->NextP);
+		rio_dprint(RIO_DEBUG_CMD, ("Now try to queue cmd cmdblk 0x%x at 0x%x\n",
+		       (int)CmdBlkP,(int)Base));
+	}
+
+	rio_dprint(RIO_DEBUG_CMD, ("Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base));
+
+	*Base = CmdBlkP;
+
+	CmdBlkP->NextP = NULL;
+
+	rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+
+	return RIO_SUCCESS;
+}
+
+/*
+** Here we go - if there is an empty rup, fill it!
+** must be called at splrio() or higher.
+*/
+void
+RIOPollHostCommands(p, HostP)
+struct rio_info *	p;
+struct Host *		HostP;
+{
+	register struct CmdBlk *CmdBlkP;
+	register struct UnixRup *UnixRupP;
+	struct PKT *PacketP;
+	ushort Rup;
+	unsigned long flags;
+
+
+	Rup = MAX_RUP+LINKS_PER_UNIT;
+
+	do {	/* do this loop for each RUP */
+		/*
+		** locate the rup we are processing & lock it
+		*/
+		UnixRupP = &HostP->UnixRups[--Rup];
+
+		spin_lock_irqsave(&UnixRupP->RupLock, flags);
+
+		/*
+		** First check for incoming commands:
+		*/
+		if ( RWORD(UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE ) {
+			int FreeMe;
+
+			/* rio_dprint(RIO_DEBUG_CMD, ("RIORupCmd( %d, %d )\n", HostP-p->RIOHosts, Rup )); */
+
+			PacketP =(PKT *)RIO_PTR(HostP->Caddr,RWORD(UnixRupP->RupP->rxpkt));
+
+			ShowPacket( DBG_CMD, PacketP );
+
+			switch ( RBYTE(PacketP->dest_port) ) {
+				case BOOT_RUP:
+					rio_dprint(RIO_DEBUG_CMD, ("Incoming Boot %s packet '%x'\n", 
+						RBYTE(PacketP->len) & 0x80 ? "Command":"Data", 
+						RBYTE(PacketP->data[0]) )); 
+					rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+					FreeMe= RIOBootRup(p, Rup,HostP,PacketP);
+					rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+					break;
+
+				case COMMAND_RUP:
+					/*
+					** Free the RUP lock as loss of carrier causes a
+					** ttyflush which will (eventually) call another
+					** routine that uses the RUP lock.
+					*/
+					rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+					FreeMe= RIOCommandRup(p, Rup,HostP,PacketP);
+					if (PacketP->data[5] == MEMDUMP) {
+						rio_dprint(RIO_DEBUG_CMD, ("Memdump from 0x%x complete\n",
+			 				*(ushort *) &(PacketP->data[6])));
+						HostP->Copy( (caddr_t)&(PacketP->data[8]), 
+								(caddr_t)p->RIOMemDump, 32 );
+					}
+					rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+					break;
+
+				case ROUTE_RUP:
+					rio_spin_unlock_irqrestore( &UnixRupP->RupLock, flags);
+					FreeMe = RIORouteRup(p, Rup, HostP, PacketP );
+					rio_spin_lock_irqsave( &UnixRupP->RupLock, flags );
+					break;
+
+				default:
+					rio_dprint(RIO_DEBUG_CMD, ("Unknown RUP %d\n", RBYTE(PacketP->dest_port)));
+					FreeMe = 1;
+					break;
+			}
+
+			if ( FreeMe ) {
+				rio_dprint(RIO_DEBUG_CMD, ("Free processed incoming command packet\n"));
+				put_free_end(HostP,PacketP);
+
+				WWORD(UnixRupP->RupP->rxcontrol , RX_RUP_INACTIVE);
+
+				if ( RWORD(UnixRupP->RupP->handshake)==PHB_HANDSHAKE_SET ) {
+					rio_dprint(RIO_DEBUG_CMD, ("Handshake rup %d\n",Rup));
+					WWORD(UnixRupP->RupP->handshake,
+						PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET);
+				}
+			}
+		}
+
+		/*
+		** IF a command was running on the port, 
+		** and it has completed, then tidy it up.
+		*/
+		if ( (CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */
+			(RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) ) {
+			/*
+			** we are idle.
+			** there is a command in pending.
+			** Therefore, this command has finished.
+			** So, wakeup whoever is waiting for it (and tell them
+			** what happened).
+			*/
+			if ( CmdBlkP->Packet.dest_port == BOOT_RUP )
+				rio_dprint(RIO_DEBUG_CMD, ("Free Boot %s Command Block '%x'\n", 
+						CmdBlkP->Packet.len & 0x80 ? "Command":"Data", 
+							CmdBlkP->Packet.data[0] ));
+
+			rio_dprint(RIO_DEBUG_CMD, ("Command 0x%x completed\n",(int)CmdBlkP));
+
+			/*
+			** Clear the Rup lock to prevent mutual exclusion.
+			*/
+			if ( CmdBlkP->PostFuncP ) {
+				rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+				(*CmdBlkP->PostFuncP) (CmdBlkP->PostArg,CmdBlkP);
+				rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+			}
+
+			/*
+			** ....clear the pending flag....
+			*/
+			UnixRupP->CmdPendingP = NULL;
+
+			/*
+			** ....and return the command block to the freelist.
+			*/
+			RIOFreeCmdBlk( CmdBlkP );
+		}
+
+		/*
+		** If there is a command for this rup, and the rup
+		** is idle, then process the command
+		*/
+		if ( (CmdBlkP = UnixRupP->CmdsWaitingP) && /* ASSIGN! */
+			(UnixRupP->CmdPendingP == NULL) &&
+				(RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) ) {
+			/*
+			** if the pre-function is non-zero, call it.
+			** If it returns RIO_FAIL then don't
+			** send this command yet!
+			*/
+#ifdef CHECK
+CheckCmdBlkP( CmdBlkP );
+#endif
+			if ( !(CmdBlkP->PreFuncP ?
+				(*CmdBlkP->PreFuncP)(CmdBlkP->PreArg, CmdBlkP) : TRUE)) {
+				rio_dprint(RIO_DEBUG_CMD, ("Not ready to start command 0x%x\n",(int)CmdBlkP));
+			}
+			else {
+				rio_dprint(RIO_DEBUG_CMD, ("Start new command 0x%x Cmd byte is 0x%x\n",
+						(int)CmdBlkP, CmdBlkP->Packet.data[0]));
+				/*
+				** Whammy! blat that pack!
+				*/
+#ifdef CHECK
+CheckPacketP( (PKT *)RIO_PTR(HostP->Caddr,UnixRupP->RupP->txpkt) );
+#endif
+				HostP->Copy( (caddr_t)&CmdBlkP->Packet, 
+					RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt), sizeof(PKT));
+
+				/*
+				** remove the command from the rup command queue...
+				*/
+				UnixRupP->CmdsWaitingP = CmdBlkP->NextP;
+
+				/*
+				** ...and place it on the pending position.
+				*/
+				UnixRupP->CmdPendingP = CmdBlkP;
+
+				/*
+				** set the command register
+				*/
+				WWORD(UnixRupP->RupP->txcontrol,TX_PACKET_READY);
+
+				/*
+				** the command block will be freed
+				** when the command has been processed.
+				*/
+			}
+		}
+		spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+	} while ( Rup );
+}
+
+
+/*
+** Return the length of the named string
+*/
+int
+RIOStrlen(Str)
+register char *Str;
+{
+	register int len = 0;
+
+	while ( *Str++ )
+		len++;
+	return len;
+}
+
+/*
+** compares s1 to s2 and return 0 if they match.
+*/
+int
+RIOStrCmp(s1, s2)
+register char *s1;
+register char *s2;
+{
+	while ( *s1 && *s2 && *s1==*s2 )
+		s1++, s2++;
+	return *s1-*s2;
+}
+
+/*
+** compares s1 to s2 for upto n bytes and return 0 if they match.
+*/
+int
+RIOStrnCmp(s1, s2, n)
+register char *s1;
+register char *s2;
+int n;
+{
+	while ( n && *s1 && *s2 && *s1==*s2 )
+		n--, s1++, s2++;
+	return n ? *s1!=*s2 : 0;
+}
+
+/*
+** copy up to 'len' bytes from 'from' to 'to'.
+*/
+void
+RIOStrNCpy(to, from, len)
+char *to;
+char *from;
+int len; 
+{
+	while ( len-- && (*to++ = *from++) )
+		;
+	to[-1]='\0';
+}
+
+int
+RIOWFlushMark(iPortP, CmdBlkP)
+int iPortP;
+struct CmdBlk *CmdBlkP;
+{
+	struct Port *	PortP = (struct Port *)iPortP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+#ifdef CHECK
+	CheckPortP( PortP );
+#endif
+	PortP->WflushFlag++;
+	PortP->MagicFlags |= MAGIC_FLUSH;
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return RIOUnUse( iPortP, CmdBlkP );
+}
+
+int
+RIORFlushEnable(iPortP, CmdBlkP)
+int iPortP;
+struct CmdBlk *CmdBlkP; 
+{
+	struct Port *	PortP = (struct Port *)iPortP;
+	PKT *PacketP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	while ( can_remove_receive(&PacketP, PortP) ) {
+		remove_receive(PortP);
+		ShowPacket(DBG_PROC, PacketP );
+		put_free_end( PortP->HostP, PacketP );
+	}
+
+	if ( RWORD(PortP->PhbP->handshake)==PHB_HANDSHAKE_SET ) {
+		/*
+		** MAGIC! (Basically, handshake the RX buffer, so that
+		** the RTAs upstream can be re-enabled.)
+		*/
+		rio_dprint(RIO_DEBUG_CMD, ("Util: Set RX handshake bit\n"));
+		WWORD(PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET);
+	}
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return RIOUnUse( iPortP, CmdBlkP );
+}
+
+int
+RIOUnUse(iPortP, CmdBlkP)
+int iPortP;
+struct CmdBlk *CmdBlkP; 
+{
+	struct Port *	PortP = (struct Port *)iPortP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+#ifdef CHECK
+	CheckPortP( PortP );
+#endif
+	rio_dprint(RIO_DEBUG_CMD, ("Decrement in use count for port\n"));
+
+	if (PortP->InUse) {
+		if ( --PortP->InUse != NOT_INUSE ) {
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+		}
+	}
+	/*
+	** While PortP->InUse is set (i.e. a preemptive command has been sent to
+	** the RTA and is awaiting completion), any transmit data is prevented from
+	** being transferred from the write queue into the transmit packets
+	** (add_transmit) and no furthur transmit interrupt will be sent for that
+	** data. The next interrupt will occur up to 500ms later (RIOIntr is called
+	** twice a second as a saftey measure). This was the case when kermit was
+	** used to send data into a RIO port. After each packet was sent, TCFLSH
+	** was called to flush the read queue preemptively. PortP->InUse was
+	** incremented, thereby blocking the 6 byte acknowledgement packet
+	** transmitted back. This acknowledgment hung around for 500ms before
+	** being sent, thus reducing input performance substantially!.
+	** When PortP->InUse becomes NOT_INUSE, we must ensure that any data
+	** hanging around in the transmit buffer is sent immediately.
+	*/
+	WWORD(PortP->HostP->ParmMapP->tx_intr, 1);
+	/* What to do here ..
+	wakeup( (caddr_t)&(PortP->InUse) );
+	*/
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return 0;
+}
+
+void
+ShowPacket(Flags, PacketP)
+uint Flags;
+struct PKT *PacketP; 
+{
+}
+
+/*
+** 
+** How to use this file:
+** 
+** To send a command down a rup, you need to allocate a command block, fill
+** in the packet information, fill in the command number, fill in the pre-
+** and post- functions and arguments, and then add the command block to the
+** queue of command blocks for the port in question. When the port is idle,
+** then the pre-function will be called. If this returns RIO_FAIL then the
+** command will be re-queued and tried again at a later date (probably in one
+** clock tick). If the pre-function returns NOT RIO_FAIL, then the command
+** packet will be queued on the RUP, and the txcontrol field set to the
+** command number. When the txcontrol field has changed from being the
+** command number, then the post-function will be called, with the argument
+** specified earlier, a pointer to the command block, and the value of
+** txcontrol.
+** 
+** To allocate a command block, call RIOGetCmdBlk(). This returns a pointer
+** to the command block structure allocated, or NULL if there aren't any.
+** The block will have been zeroed for you.
+** 
+** The structure has the following fields:
+** 
+** struct CmdBlk
+** {
+**	 struct CmdBlk *NextP;		  ** Pointer to next command block   **
+**	 struct PKT	 Packet;		** A packet, to copy to the rup	**
+**			int	 (*PreFuncP)();  ** The func to call to check if OK **
+**			int	 PreArg;		** The arg for the func			**
+**			int	 (*PostFuncP)(); ** The func to call when completed **
+**			int	 PostArg;	   ** The arg for the func			**
+** };
+** 
+** You need to fill in ALL fields EXCEPT NextP, which is used to link the
+** blocks together either on the free list or on the Rup list.
+** 
+** Packet is an actual packet structure to be filled in with the packet
+** information associated with the command. You need to fill in everything,
+** as the command processore doesn't process the command packet in any way.
+** 
+** The PreFuncP is called before the packet is enqueued on the host rup.
+** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must
+** return !RIO_FAIL to have the packet queued on the rup, and RIO_FAIL
+** if the packet is NOT to be queued.
+** 
+** The PostFuncP is called when the command has completed. It is called
+** as (*PostFuncP)(PostArg, CmdBlkP, txcontrol);. PostFuncP is not expected
+** to return a value. PostFuncP does NOT need to free the command block,
+** as this happens automatically after PostFuncP returns.
+** 
+** Once the command block has been filled in, it is attached to the correct
+** queue by calling RIOQueueCmdBlk( HostP, Rup, CmdBlkP ) where HostP is
+** a pointer to the struct Host, Rup is the NUMBER of the rup (NOT a pointer
+** to it!), and CmdBlkP is the pointer to the command block allocated using
+** RIOGetCmdBlk().
+** 
+*/
diff -urN linux-2.2.15-pre2/drivers/char/rio/rioctrl.c linux/drivers/char/rio/rioctrl.c
--- linux-2.2.15-pre2/drivers/char/rio/rioctrl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioctrl.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1899 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioctrl.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:42
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)rioctrl.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_rioctrl_c_sccs_ = "@(#)rioctrl.c	1.3";
+#endif
+
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+static struct LpbReq	 LpbReq;
+static struct RupReq	 RupReq;
+static struct PortReq	PortReq;
+static struct HostReq	HostReq;
+static struct HostDpRam HostDpRam;
+static struct DebugCtrl DebugCtrl;
+static struct Map		 MapEnt;
+static struct PortSetup PortSetup;
+static struct DownLoad	DownLoad;
+static struct SendPack  SendPack;
+/* static struct StreamInfo	StreamInfo; */
+/* static char modemtable[RIO_PORTS]; */
+static struct SpecialRupCmd SpecialRupCmd;
+static struct PortParams PortParams;
+static struct portStats portStats;
+
+static struct SubCmdStruct {
+	ushort	Host;
+	ushort	Rup;
+	ushort	Port;
+	ushort	Addr;
+} SubCmd;
+
+struct PortTty {
+	uint		port;
+	struct ttystatics	Tty;
+};
+
+static struct PortTty	PortTty;
+typedef struct ttystatics TERMIO;
+
+/*
+** This table is used when the config.rio downloads bin code to the
+** driver. We index the table using the product code, 0-F, and call
+** the function pointed to by the entry, passing the information
+** about the boot.
+** The RIOBootCodeUNKNOWN entry is there to politely tell the calling
+** process to bog off.
+*/
+static int 
+(*RIOBootTable[MAX_PRODUCT])(struct rio_info *, struct DownLoad *) =
+{
+/* 0 */	RIOBootCodeHOST,	/* Host Card */
+/* 1 */	RIOBootCodeRTA,		/* RTA */
+};
+
+#define drv_makedev(maj, min) ((((uint) maj & 0xff) << 8) | ((uint) min & 0xff))
+
+#ifdef linux
+int copyin (int arg, caddr_t dp, int siz)
+{
+  int rv;
+
+  rio_dprint (RIO_DEBUG_CTRL, ("Copying %d bytes from user %p to %p.\n", siz, (void *) arg, dp));
+  rv = copy_from_user (dp, (void *)arg, siz);
+  if (rv < 0) return COPYFAIL;
+  else return rv;
+}
+
+
+int copyout (caddr_t dp, int arg, int siz)
+{
+  int rv;
+
+  rio_dprint (RIO_DEBUG_CTRL, ("Copying %d bytes to user %p from %p.\n", siz, (void *) arg, dp));
+  rv = copy_to_user ((void *)arg, dp, siz);
+  if (rv < 0) return COPYFAIL;
+  else return rv;
+}
+
+#else
+
+int
+copyin(arg, dp, siz)
+int arg;
+caddr_t dp;
+int siz; 
+{
+	if (rbounds ((unsigned long) arg) >= siz) {
+		bcopy ( arg, dp, siz );
+		return OK;
+	} else
+		return ( COPYFAIL );
+}
+
+int
+copyout (dp, arg, siz)
+caddr_t dp;
+int arg;
+int siz;
+{
+	if (wbounds ((unsigned long) arg) >=  siz ) {
+		bcopy ( dp, arg, siz );
+		return OK;
+	} else
+		return ( COPYFAIL );
+}
+#endif
+
+int
+riocontrol(p, dev, cmd, arg, su)
+struct rio_info	* p;
+dev_t		dev;
+int		cmd;
+caddr_t		arg;
+int		su;
+{
+	uint	Host;	/* leave me unsigned! */
+	uint	port;	/* and me! */
+	struct Host	*HostP;
+	ushort	loop;
+	int		Entry;
+	struct Port	*PortP;
+	PKT	*PacketP;
+	int		retval = 0;
+	unsigned long flags;
+	
+	/* Confuse teh compiler to think that we've initialized these */
+	Host=0;
+	PortP = NULL;
+
+	rio_dprint(RIO_DEBUG_CTRL, ("control ioctl cmd: 0x%x arg: 0x%x\n", cmd, (int)arg));
+
+	switch (cmd) {
+		/*
+		** RIO_SET_TIMER
+		**
+		** Change the value of the host card interrupt timer.
+		** If the host card number is -1 then all host cards are changed
+		** otherwise just the specified host card will be changed.
+		*/
+		case RIO_SET_TIMER:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_TIMER to %dms\n", (uint)arg));
+			{
+				int host, value;
+				host = (uint)arg >> 16;
+				value = (uint)arg & 0x0000ffff;
+				if (host == -1) {
+					for (host = 0; host < p->RIONumHosts; host++) {
+						if (p->RIOHosts[host].Flags == RC_RUNNING) {
+							WWORD(p->RIOHosts[host].ParmMapP->timer , value);
+						}
+					}
+				} else if (host >= p->RIONumHosts) {
+					return EINVAL;
+				} else {
+					if ( p->RIOHosts[host].Flags == RC_RUNNING ) {
+						WWORD(p->RIOHosts[host].ParmMapP->timer , value);
+					}
+				}
+			}
+			return 0;
+
+		case RIO_IDENTIFY_DRIVER:
+			/*
+			** 15.10.1998 ARG - ESIL 0760 part fix
+			** Added driver ident string output.
+			**
+#ifndef __THIS_RELEASE__
+#warning Driver Version string not defined !
+#endif
+			cprintf("%s %s %s %s\n",
+				RIO_DRV_STR,
+				__THIS_RELEASE__,
+				__DATE__, __TIME__ );
+
+			return 0;
+
+		case RIO_DISPLAY_HOST_CFG:
+			**
+			** 15.10.1998 ARG - ESIL 0760 part fix
+			** Added driver host card ident string output.
+			**
+			** Note that the only types currently supported
+			** are ISA and PCI. Also this driver does not
+			** (yet) distinguish between the Old PCI card
+			** and the Jet PCI card. In fact I think this
+			** driver only supports JET PCI !
+			**
+
+			for (Host = 0; Host < p->RIONumHosts; Host++)
+			{
+				HostP = &(p->RIOHosts[Host]);
+
+				switch ( HostP->Type )
+				{
+				    case RIO_AT :
+					strcpy( host_type, RIO_AT_HOST_STR );
+					break;
+
+				    case RIO_PCI :
+					strcpy( host_type, RIO_PCI_HOST_STR );
+					break;
+
+				    default :
+					strcpy( host_type, "Unknown" );
+					break;
+				}
+
+				cprintf(
+				  "RIO Host %d - Type:%s Addr:%X IRQ:%d\n",
+					Host, host_type,
+					(uint)HostP->PaddrP,
+					(int)HostP->Ivec - 32  );
+			}
+			return 0;
+			**
+			*/
+
+		case RIO_FOAD_RTA:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_FOAD_RTA\n"));
+			return RIOCommandRta(p, (uint)arg, RIOFoadRta);
+
+		case RIO_ZOMBIE_RTA:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_ZOMBIE_RTA\n"));
+			return RIOCommandRta(p, (uint)arg, RIOZombieRta);
+
+		case RIO_IDENTIFY_RTA:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_IDENTIFY_RTA\n"));
+			return RIOIdentifyRta(p, arg);
+
+		case RIO_KILL_NEIGHBOUR:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_KILL_NEIGHBOUR\n"));
+			return RIOKillNeighbour(p, arg);
+
+		case SPECIAL_RUP_CMD:
+			{
+				struct CmdBlk *CmdBlkP;
+
+				rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD\n"));
+				if (copyin((int)arg, (caddr_t)&SpecialRupCmd, 
+							sizeof(SpecialRupCmd)) == COPYFAIL ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD copy failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+				CmdBlkP = RIOGetCmdBlk();
+				if ( !CmdBlkP ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD GetCmdBlk failed\n"));
+					return ENXIO;
+				}
+				CmdBlkP->Packet = SpecialRupCmd.Packet;
+				if ( SpecialRupCmd.Host >= p->RIONumHosts )
+					SpecialRupCmd.Host = 0;
+					rio_dprint(RIO_DEBUG_CTRL, ("Queue special rup command for host %d rup %d\n",
+						SpecialRupCmd.Host, SpecialRupCmd.RupNum));
+					if (RIOQueueCmdBlk(&p->RIOHosts[SpecialRupCmd.Host], 
+							SpecialRupCmd.RupNum, CmdBlkP) == RIO_FAIL) {
+						cprintf("FAILED TO QUEUE SPECIAL RUP COMMAND\n");
+					}
+					return 0;
+				}
+
+			case RIO_DEBUG_MEM:
+#ifdef DEBUG_MEM_SUPPORT
+RIO_DEBUG_CTRL, 				if (su)
+					return rio_RIODebugMemory(RIO_DEBUG_CTRL, arg);
+				else
+#endif
+					return EPERM;
+
+			case RIO_ALL_MODEM:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_ALL_MODEM\n"));
+				p->RIOError.Error = IOCTL_COMMAND_UNKNOWN;
+				return EINVAL;
+
+			case RIO_GET_TABLE:
+				/*
+				** Read the routing table from the device driver to user space
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_TABLE\n"));
+
+				if ((retval = RIOApel(p)) != 0)
+		 			return retval;
+
+				if (copyout((caddr_t)p->RIOConnectTable, (int)arg,
+						TOTAL_MAP_ENTRIES*sizeof(struct Map)) == COPYFAIL) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_TABLE copy failed\n"));
+		 			p->RIOError.Error = COPYOUT_FAILED;
+		 			return EFAULT;
+				}
+
+				{
+					int entry;
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nMAP ENTRIES\n") );
+					for ( entry=0; entry<TOTAL_MAP_ENTRIES; entry++ )
+					{
+					  if ((p->RIOConnectTable[entry].ID == 0) &&
+					      (p->RIOConnectTable[entry].HostUniqueNum == 0) &&
+					      (p->RIOConnectTable[entry].RtaUniqueNum == 0)) continue;
+					      
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Flags = 0x%x\n", entry, (int)p->RIOConnectTable[entry].Flags ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.SysPort = 0x%x\n", entry, (int)p->RIOConnectTable[entry].SysPort ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[3].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[4].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ) );
+					}
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nEND MAP ENTRIES\n") );
+				}
+				p->RIOQuickCheck = NOT_CHANGED;	/* a table has been gotten */
+				return 0;
+
+			case RIO_PUT_TABLE:
+				/*
+				** Write the routing table to the device driver from user space
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE\n"));
+
+				if ( !su ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE !Root\n"));
+		 			p->RIOError.Error = NOT_SUPER_USER;
+		 			return EPERM;
+				}
+				if ( copyin((int)arg, (caddr_t)&p->RIOConnectTable[0], 
+					TOTAL_MAP_ENTRIES*sizeof(struct Map) ) == COPYFAIL ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE copy failed\n"));
+		 			p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+/*
+***********************************
+				{
+					int entry;
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nMAP ENTRIES\n") );
+					for ( entry=0; entry<TOTAL_MAP_ENTRIES; entry++ )
+					{
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Flags = 0x%x\n", entry, p->RIOConnectTable[entry].Flags ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.SysPort = 0x%x\n", entry, p->RIOConnectTable[entry].SysPort ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[0].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[1].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[2].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[3].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[4].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[3].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ) );
+					}
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nEND MAP ENTRIES\n") );
+				}
+***********************************
+*/
+				return RIONewTable(p);
+
+	 		case RIO_GET_BINDINGS :
+				/*
+				** Send bindings table, containing unique numbers of RTAs owned
+				** by this system to user space
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS\n"));
+
+				if ( !su )
+				{
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS !Root\n"));
+		 			p->RIOError.Error = NOT_SUPER_USER;
+		 			return EPERM;
+				}
+				if (copyout((caddr_t) p->RIOBindTab, (int)arg, 
+						(sizeof(ulong) * MAX_RTA_BINDINGS)) == COPYFAIL ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS copy failed\n"));
+		 			p->RIOError.Error = COPYOUT_FAILED;
+		 			return EFAULT;
+				}
+				return 0;
+
+	 		case RIO_PUT_BINDINGS :
+			/*
+			** Receive a bindings table, containing unique numbers of RTAs owned
+			** by this system
+			*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS\n"));
+
+				if ( !su )
+				{
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS !Root\n"));
+		 			p->RIOError.Error = NOT_SUPER_USER;
+		 			return EPERM;
+				}
+				if (copyin((int)arg, (caddr_t)&p->RIOBindTab[0], 
+						(sizeof(ulong) * MAX_RTA_BINDINGS))==COPYFAIL ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS copy failed\n"));
+		 			p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+				return 0;
+
+			case RIO_BIND_RTA :
+				{
+					int	EmptySlot = -1;
+					/*
+					** Bind this RTA to host, so that it will be booted by 
+					** host in 'boot owned RTAs' mode.
+					*/
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_BIND_RTA\n"));
+
+					if ( !su ) {
+		 				rio_dprint(RIO_DEBUG_CTRL, ("RIO_BIND_RTA !Root\n"));
+		 				p->RIOError.Error = NOT_SUPER_USER;
+		 				return EPERM;
+					}
+					for (Entry = 0; Entry < MAX_RTA_BINDINGS; Entry++) {
+		 				if ((EmptySlot == -1) && (p->RIOBindTab[Entry] == 0L))
+							EmptySlot = Entry;
+		 				else if (p->RIOBindTab[Entry] == (int) arg) {
+							/*
+							** Already exists - delete
+							*/
+							p->RIOBindTab[Entry] = 0L;
+							rio_dprint(RIO_DEBUG_CTRL, ("Removing Rta %x from p->RIOBindTab\n",
+		 												(int) arg));
+							return 0;
+		 				}
+					}
+					/*
+					** Dosen't exist - add
+					*/
+					if (EmptySlot != -1) {
+		 				p->RIOBindTab[EmptySlot] = (int) arg;
+		 				rio_dprint(RIO_DEBUG_CTRL, ("Adding Rta %x to p->RIOBindTab\n",
+		  					(int) arg));
+					}
+					else {
+		 				rio_dprint(RIO_DEBUG_CTRL, ("p->RIOBindTab full! - Rta %x not added\n",
+		  					(int) arg));
+		 				return 1;
+					}
+					return 0;
+				}
+
+			case RIO_RESUME :
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME\n"));
+				port = (uint) arg;
+				if ((port < 0) || (port > 511)) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Bad port number %d\n", port));
+		 			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+		 			return EINVAL;
+				}
+				PortP = p->RIOPortp[port];
+				if (!PortP->Mapped) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d not mapped\n", port));
+		 			p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM;
+		 			return EINVAL;
+				}
+				if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d not open\n", port));
+		 			return EINVAL;
+				}
+
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RESUME) == 
+										RIO_FAIL) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME failed\n"));
+					rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+					return EBUSY;
+				}
+				else {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d resumed\n", port));
+					PortP->State |= RIO_BUSY;
+				}
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				return retval;
+
+			case RIO_ASSIGN_RTA:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_ASSIGN_RTA\n"));
+				if ( !su ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_ASSIGN_RTA !Root\n"));
+					p->RIOError.Error = NOT_SUPER_USER;
+					return EPERM;
+				}
+				if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt))
+									== COPYFAIL) {
+					rio_dprint(RIO_DEBUG_CTRL, ("Copy from user space failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+				return RIOAssignRta(p, &MapEnt);
+
+			case RIO_CHANGE_NAME:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_CHANGE_NAME\n"));
+				if ( !su ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_CHANGE_NAME !Root\n"));
+					p->RIOError.Error = NOT_SUPER_USER;
+					return EPERM;
+				}
+				if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt))
+						== COPYFAIL) {
+					rio_dprint(RIO_DEBUG_CTRL, ("Copy from user space failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+				return RIOChangeName(p, &MapEnt);
+
+			case RIO_DELETE_RTA:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_DELETE_RTA\n"));
+				if ( !su ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_DELETE_RTA !Root\n"));
+		 			p->RIOError.Error = NOT_SUPER_USER;
+		 			return EPERM;
+				}
+				if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt))
+							== COPYFAIL ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("Copy from data space failed\n"));
+		 			p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+				return RIODeleteRta(p, &MapEnt);
+
+			case RIO_QUICK_CHECK:
+				/*
+				** 09.12.1998 ARG - ESIL 0776 part fix
+				** A customer was using this to get the RTAs
+				** connect/disconnect status.
+				** RIOConCon() had been botched use RIOHalted
+				** to keep track of RTA connections and
+				** disconnections. That has been changed and
+				** RIORtaDisCons in the rio_info struct now
+				** does the job. So we need to return the value
+				** of RIORtaCons instead of RIOHalted.
+				**
+				if (copyout((caddr_t)&p->RIOHalted,(int)arg,
+							sizeof(uint))==COPYFAIL) {
+				**
+				*/
+
+				if (copyout((caddr_t)&p->RIORtaDisCons,(int)arg,
+							sizeof(uint))==COPYFAIL) {
+					p->RIOError.Error = COPYOUT_FAILED;
+					return EFAULT;
+				}
+				return 0;
+
+			case RIO_LAST_ERROR:
+				if (copyout((caddr_t)&p->RIOError, (int)arg, 
+						sizeof(struct Error)) ==COPYFAIL )
+					return EFAULT;
+				return 0;
+
+			case RIO_GET_LOG:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_LOG\n"));
+#ifdef LOGGING
+				RIOGetLog(arg);
+				return 0;
+#else
+				return EINVAL;
+#endif
+
+			case RIO_GET_MODTYPE:
+				if ( copyin( (int)arg, (caddr_t)&port, 
+									sizeof(uint)) == COPYFAIL )
+				{
+		 			p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Get module type for port %d\n", port));
+				if ( port < 0 || port > 511 )
+				{
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_MODTYPE: Bad port number %d\n", port));
+		 			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+		 			return EINVAL;
+				}
+				PortP = (p->RIOPortp[port]);
+				if (!PortP->Mapped)
+				{
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_MODTYPE: Port %d not mapped\n", port));
+		 			p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM;
+		 			return EINVAL;
+				}
+				/*
+				** Return module type of port
+				*/
+				port = PortP->HostP->UnixRups[PortP->RupNum].ModTypes;
+				if (copyout((caddr_t)&port, (int)arg, 
+							sizeof(uint)) == COPYFAIL) {
+		 			p->RIOError.Error = COPYOUT_FAILED;
+		 			return EFAULT;
+				}
+				return(0);
+			/*
+			** 02.03.1999 ARG - ESIL 0820 fix
+			** We are no longer using "Boot Mode", so these ioctls
+			** are not required :
+			**
+	 		case RIO_GET_BOOT_MODE :
+				rio_dprint(RIO_DEBUG_CTRL, ("Get boot mode - %x\n", p->RIOBootMode));
+				**
+				** Return boot state of system - BOOT_ALL, BOOT_OWN or BOOT_NONE
+				**
+				if (copyout((caddr_t)&p->RIOBootMode, (int)arg, 
+						sizeof(p->RIOBootMode)) == COPYFAIL) {
+		 			p->RIOError.Error = COPYOUT_FAILED;
+		 			return EFAULT;
+				}
+				return(0);
+			
+ 			case RIO_SET_BOOT_MODE :
+				p->RIOBootMode = (uint) arg;
+				rio_dprint(RIO_DEBUG_CTRL, ("Set boot mode to 0x%x\n", p->RIOBootMode));
+				return(0);
+			**
+			** End ESIL 0820 fix
+			*/
+
+	 		case RIO_BLOCK_OPENS:
+				rio_dprint(RIO_DEBUG_CTRL, ("Opens block until booted\n"));
+				for ( Entry=0; Entry < RIO_PORTS; Entry++ ) {
+		 			rio_spin_lock_irqsave(&PortP->portSem, flags);
+		 			p->RIOPortp[Entry]->WaitUntilBooted = 1;
+		 			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				}
+				return 0;
+			
+	 		case RIO_SETUP_PORTS:
+				rio_dprint(RIO_DEBUG_CTRL, ("Setup ports\n"));
+				if (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) 
+						== COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 rio_dprint(RIO_DEBUG_CTRL, ("EFAULT"));
+					 return EFAULT;
+				}
+				if ( PortSetup.From > PortSetup.To || 
+								PortSetup.To >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 rio_dprint(RIO_DEBUG_CTRL, ("ENXIO"));
+					 return ENXIO;
+				}
+				if ( PortSetup.XpCps > p->RIOConf.MaxXpCps ||
+					 PortSetup.XpCps < p->RIOConf.MinXpCps ) {
+					 p->RIOError.Error = XPRINT_CPS_OUT_OF_RANGE;
+					 rio_dprint(RIO_DEBUG_CTRL, ("EINVAL"));
+					 return EINVAL;
+				}
+				if ( !p->RIOPortp ) {
+					 cprintf("No p->RIOPortp array!\n");
+					 rio_dprint(RIO_DEBUG_CTRL, ("No p->RIOPortp array!\n"));
+					 return EIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("entering loop (%d %d)!\n", PortSetup.From, PortSetup.To));
+				for (loop=PortSetup.From; loop<=PortSetup.To; loop++) {
+				rio_dprint(RIO_DEBUG_CTRL, ("in loop (%d)!\n", loop));
+#if 0
+					PortP = p->RIOPortp[loop];
+					if ( !PortP->TtyP )
+						PortP->TtyP = &p->channel[loop];
+
+		 				rio_spin_lock_irqsave(&PortP->portSem, flags);
+						if ( PortSetup.IxAny )
+							PortP->Config |= RIO_IXANY;
+						else
+							PortP->Config &= ~RIO_IXANY;
+						if ( PortSetup.IxOn )
+							PortP->Config |= RIO_IXON;
+						else
+							PortP->Config &= ~RIO_IXON;
+					 
+					 /*
+					 ** If the port needs to wait for all a processes output
+					 ** to drain before closing then this flag will be set.
+					 */
+					 	if (PortSetup.Drain) {
+							PortP->Config |= RIO_WAITDRAIN;
+					 	} else {
+							PortP->Config &= ~RIO_WAITDRAIN;
+					 	}
+					 /*
+					 ** Store setings if locking or unlocking port or if the
+					 ** port is not locked, when setting the store option.
+					 */
+					 if (PortP->Mapped &&
+						 ((PortSetup.Lock && !PortP->Lock) ||
+							(!PortP->Lock &&
+							(PortSetup.Store && !PortP->Store)))) {
+						PortP->StoredTty.iflag = PortP->TtyP->tm.c_iflag;
+						PortP->StoredTty.oflag = PortP->TtyP->tm.c_oflag;
+						PortP->StoredTty.cflag = PortP->TtyP->tm.c_cflag;
+						PortP->StoredTty.lflag = PortP->TtyP->tm.c_lflag;
+						PortP->StoredTty.line = PortP->TtyP->tm.c_line;
+						bcopy(PortP->TtyP->tm.c_cc, PortP->StoredTty.cc,
+					 		NCC + 5);
+					 }
+					 PortP->Lock = PortSetup.Lock;
+					 PortP->Store = PortSetup.Store;
+					 PortP->Xprint.XpCps = PortSetup.XpCps;
+					 bcopy(PortSetup.XpOn,PortP->Xprint.XpOn,MAX_XP_CTRL_LEN);
+					 bcopy(PortSetup.XpOff,PortP->Xprint.XpOff,MAX_XP_CTRL_LEN);
+					 PortP->Xprint.XpOn[MAX_XP_CTRL_LEN-1] = '\0';
+					 PortP->Xprint.XpOff[MAX_XP_CTRL_LEN-1] = '\0';
+					 PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+								RIOStrlen(PortP->Xprint.XpOff);
+					 rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+#endif
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("after loop (%d)!\n", loop));
+				rio_dprint(RIO_DEBUG_CTRL,  ("Retval:%x\n", retval ) );
+				return retval;
+
+			case RIO_GET_PORT_SETUP :
+				rio_dprint(RIO_DEBUG_CTRL, ("Get port setup\n"));
+				if (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) 
+							== COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( PortSetup.From >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+
+				port = PortSetup.To = PortSetup.From;
+				PortSetup.IxAny = (p->RIOPortp[port]->Config & RIO_IXANY) ? 
+													1 : 0;
+				PortSetup.IxOn = (p->RIOPortp[port]->Config & RIO_IXON) ? 
+													1 : 0;
+				PortSetup.Drain = (p->RIOPortp[port]->Config & RIO_WAITDRAIN) ?
+												 	1 : 0;
+				PortSetup.Store = p->RIOPortp[port]->Store;
+				PortSetup.Lock = p->RIOPortp[port]->Lock;
+				PortSetup.XpCps = p->RIOPortp[port]->Xprint.XpCps;
+				bcopy(p->RIOPortp[port]->Xprint.XpOn, PortSetup.XpOn,
+													MAX_XP_CTRL_LEN);
+				bcopy(p->RIOPortp[port]->Xprint.XpOff, PortSetup.XpOff,
+													MAX_XP_CTRL_LEN);
+				PortSetup.XpOn[MAX_XP_CTRL_LEN-1] = '\0';
+				PortSetup.XpOff[MAX_XP_CTRL_LEN-1] = '\0';
+
+				if ( copyout((caddr_t)&PortSetup,(int)arg,sizeof(PortSetup))
+														==COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_GET_PORT_PARAMS :
+				rio_dprint(RIO_DEBUG_CTRL, ("Get port params\n"));
+				if (copyin( (int)arg, (caddr_t)&PortParams,
+					sizeof(struct PortParams)) == COPYFAIL) {
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+				if (PortParams.Port >= RIO_PORTS) {
+					p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					return ENXIO;
+				}
+				PortP = (p->RIOPortp[PortParams.Port]);
+				PortParams.Config = PortP->Config;
+				PortParams.State = PortP->State;
+				rio_dprint(RIO_DEBUG_CTRL, ("Port %d\n", PortParams.Port));
+
+				if (copyout((caddr_t)&PortParams, (int)arg, 
+						sizeof(struct PortParams)) == COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_GET_PORT_TTY :
+				rio_dprint(RIO_DEBUG_CTRL, ("Get port tty\n"));
+				if (copyin((int)arg, (caddr_t)&PortTty, sizeof(struct PortTty)) 
+						== COPYFAIL) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( PortTty.port >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+
+				rio_dprint(RIO_DEBUG_CTRL, ("Port %d\n", PortTty.port));
+				PortP = (p->RIOPortp[PortTty.port]);
+#if 0
+				PortTty.Tty.tm.c_iflag = PortP->TtyP->tm.c_iflag;
+				PortTty.Tty.tm.c_oflag = PortP->TtyP->tm.c_oflag;
+				PortTty.Tty.tm.c_cflag = PortP->TtyP->tm.c_cflag;
+				PortTty.Tty.tm.c_lflag = PortP->TtyP->tm.c_lflag;
+#endif
+				if (copyout((caddr_t)&PortTty, (int)arg, 
+							sizeof(struct PortTty)) == COPYFAIL) {
+					p->RIOError.Error = COPYOUT_FAILED;
+					return EFAULT;
+				}
+				return retval;
+
+			case RIO_SET_PORT_TTY :
+				if (copyin((int)arg, (caddr_t)&PortTty, 
+						sizeof(struct PortTty)) == COPYFAIL) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Set port %d tty\n", PortTty.port));
+				if (PortTty.port >= (ushort) RIO_PORTS) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[PortTty.port]);
+#if 0
+		 		rio_spin_lock_irqsave(&PortP->portSem, flags);
+				PortP->TtyP->tm.c_iflag = PortTty.Tty.tm.c_iflag;
+				PortP->TtyP->tm.c_oflag = PortTty.Tty.tm.c_oflag;
+				PortP->TtyP->tm.c_cflag = PortTty.Tty.tm.c_cflag;
+				PortP->TtyP->tm.c_lflag = PortTty.Tty.tm.c_lflag;
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+#endif
+
+				RIOParam(PortP, CONFIG, PortP->State & RIO_MODEM, OK_TO_SLEEP);
+				return retval;
+
+			case RIO_SET_PORT_PARAMS :
+				rio_dprint(RIO_DEBUG_CTRL, ("Set port params\n"));
+				if ( copyin((int)arg, (caddr_t)&PortParams, sizeof(PortParams))
+					== COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if (PortParams.Port >= (ushort) RIO_PORTS) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[PortParams.Port]);
+		 		rio_spin_lock_irqsave(&PortP->portSem, flags);
+				PortP->Config = PortParams.Config;
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+			case RIO_GET_PORT_STATS :
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_PORT_STATS\n"));
+				if ( copyin((int)arg, (caddr_t)&portStats, 
+						sizeof(struct portStats)) == COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( portStats.port >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[portStats.port]);
+				portStats.gather = PortP->statsGather;
+				portStats.txchars = PortP->txchars;
+				portStats.rxchars = PortP->rxchars;
+				portStats.opens = PortP->opens;
+				portStats.closes = PortP->closes;
+				portStats.ioctls = PortP->ioctls;
+				if ( copyout((caddr_t)&portStats, (int)arg, 
+							sizeof(struct portStats)) == COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_RESET_PORT_STATS :
+				port = (uint) arg;
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESET_PORT_STATS\n"));
+				if ( port >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[port]);
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				PortP->txchars	= 0;
+				PortP->rxchars	= 0;
+				PortP->opens	= 0;
+				PortP->closes	= 0;
+				PortP->ioctls	= 0;
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				return retval;
+
+			case RIO_GATHER_PORT_STATS :
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GATHER_PORT_STATS\n"));
+				if ( copyin( (int)arg, (caddr_t)&portStats, 
+						sizeof(struct portStats)) == COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( portStats.port >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[portStats.port]);
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				PortP->statsGather = portStats.gather;
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+#ifdef DEBUG_SUPPORTED
+			case RIO_READ_LEVELS:
+				{
+					 int num;
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_LEVELS\n"));
+					 for ( num=0; RIODbInf[num].Flag; num++ ) ;
+					 rio_dprint(RIO_DEBUG_CTRL, ("%d levels to copy\n",num));
+					 if (copyout((caddr_t)RIODbInf,(int)arg,
+						sizeof(struct DbInf)*(num+1))==COPYFAIL) {
+						rio_dprint(RIO_DEBUG_CTRL, ("ReadLevels Copy failed\n"));
+						p->RIOError.Error = COPYOUT_FAILED;
+						return EFAULT;
+					 }
+					 rio_dprint(RIO_DEBUG_CTRL, ("%d levels to copied\n",num));
+					 return retval;
+				}
+#endif
+
+			 case RIO_READ_CONFIG:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_CONFIG\n"));
+				if (copyout((caddr_t)&p->RIOConf, (int)arg, 
+							sizeof(struct Conf)) ==COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_SET_CONFIG:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_CONFIG\n"));
+				if ( !su ) {
+					 p->RIOError.Error = NOT_SUPER_USER;
+					 return EPERM;
+				}
+				if ( copyin((int)arg, (caddr_t)&p->RIOConf, sizeof(struct Conf) )
+						==COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				/*
+				** move a few value around
+				*/
+				for (Host=0; Host < p->RIONumHosts; Host++)
+					 if ( (p->RIOHosts[Host].Flags & RUN_STATE) == RC_RUNNING )
+					 	WWORD(p->RIOHosts[Host].ParmMapP->timer , 
+								p->RIOConf.Timer);
+				return retval;
+
+			case RIO_START_POLLER:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_START_POLLER\n"));
+				return EINVAL;
+
+			case RIO_STOP_POLLER:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_STOP_POLLER\n"));
+				if ( !su ) {
+					 p->RIOError.Error = NOT_SUPER_USER;
+					 return EPERM;
+				}
+				p->RIOPolling = NOT_POLLING;
+				return retval;
+
+			case RIO_SETDEBUG:
+			case RIO_GETDEBUG:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_SETDEBUG/RIO_GETDEBUG\n"));
+				if ( copyin( (int)arg, (caddr_t)&DebugCtrl, sizeof(DebugCtrl) )
+							==COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( DebugCtrl.SysPort == NO_PORT ) {
+					if ( cmd == RIO_SETDEBUG ) {
+						if ( !su ) {
+							p->RIOError.Error = NOT_SUPER_USER;
+							return EPERM;
+						}
+						p->rio_debug = DebugCtrl.Debug;
+						p->RIODebugWait = DebugCtrl.Wait;
+						rio_dprint(RIO_DEBUG_CTRL, ("Set global debug to 0x%x set wait to 0x%x\n",
+							p->rio_debug,p->RIODebugWait));
+					}
+				 	else {
+						rio_dprint(RIO_DEBUG_CTRL, ("Get global debug 0x%x wait 0x%x\n",
+										p->rio_debug,p->RIODebugWait));
+						DebugCtrl.Debug = p->rio_debug;
+						DebugCtrl.Wait  = p->RIODebugWait;
+						if ( copyout((caddr_t)&DebugCtrl,(int)arg,
+								sizeof(DebugCtrl)) == COPYFAIL ) {
+							rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET/GET DEBUG: bad port number %d\n",
+									DebugCtrl.SysPort));
+						 	p->RIOError.Error = COPYOUT_FAILED;
+						 	return EFAULT;
+						}
+					}
+				}
+				else if ( DebugCtrl.SysPort >= RIO_PORTS && 
+							DebugCtrl.SysPort != NO_PORT ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET/GET DEBUG: bad port number %d\n",
+									DebugCtrl.SysPort));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				else if ( cmd == RIO_SETDEBUG ) {
+					if ( !su ) {
+						p->RIOError.Error = NOT_SUPER_USER;
+						return EPERM;
+					}
+					rio_spin_lock_irqsave(&PortP->portSem, flags);
+					p->RIOPortp[DebugCtrl.SysPort]->Debug = DebugCtrl.Debug;
+					rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_SETDEBUG 0x%x\n",
+								p->RIOPortp[DebugCtrl.SysPort]->Debug));
+				}
+				else {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_GETDEBUG 0x%x\n",
+									 p->RIOPortp[DebugCtrl.SysPort]->Debug));
+					DebugCtrl.Debug = p->RIOPortp[DebugCtrl.SysPort]->Debug;
+					if ( copyout((caddr_t)&DebugCtrl,(int)arg,
+								sizeof(DebugCtrl))==COPYFAIL ) {
+						rio_dprint(RIO_DEBUG_CTRL, ("RIO_GETDEBUG: Bad copy to user space\n"));
+						p->RIOError.Error = COPYOUT_FAILED;
+						return EFAULT;
+					}
+				}
+				return retval;
+
+			case RIO_VERSID:
+				/*
+				** Enquire about the release and version.
+				** We return MAX_VERSION_LEN bytes, being a
+				** textual null terminated string.
+				*/
+				rio_dprint(RIO_DEBUG_CTRL,  ("RIO_VERSID\n") );
+				if ( copyout(	(caddr_t)RIOVersid(),
+						(int)arg,
+						sizeof(struct rioVersion) ) == COPYFAIL )
+				{
+					 rio_dprint(RIO_DEBUG_CTRL,  ("RIO_VERSID: Bad copy to user space (host=%d)\n",Host) );
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			/*
+			** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+			** !! commented out previous 'RIO_VERSID' functionality !!
+			** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+			**
+			case RIO_VERSID:
+				**
+				** Enquire about the release and version.
+				** We return MAX_VERSION_LEN bytes, being a textual null
+				** terminated string.
+				**
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID\n"));
+				if (copyout((caddr_t)RIOVersid(), 
+						(int)arg, MAX_VERSION_LEN ) == COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID: Bad copy to user space\n",Host));
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+			**
+			** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+			*/
+
+			case RIO_NUM_HOSTS:
+				/*
+				** Enquire as to the number of hosts located
+				** at init time.
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_NUM_HOSTS\n"));
+				if (copyout((caddr_t)&p->RIONumHosts, (int)arg, 
+							sizeof(p->RIONumHosts) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_NUM_HOSTS: Bad copy to user space\n"));
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_HOST_FOAD:
+				/*
+				** Kill host. This may not be in the final version...
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_FOAD %d\n", (int)arg));
+				if ( !su ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_FOAD: Not super user\n"));
+					 p->RIOError.Error = NOT_SUPER_USER;
+					 return EPERM;
+				}
+				p->RIOHalted = 1;
+				p->RIOSystemUp = 0;
+
+				for ( Host=0; Host<p->RIONumHosts; Host++ ) {
+					 (void)RIOBoardTest( p->RIOHosts[Host].PaddrP, 
+						p->RIOHosts[Host].Caddr, p->RIOHosts[Host].Type, 
+								p->RIOHosts[Host].Slot );
+					 bzero( (caddr_t)&p->RIOHosts[Host].Flags, 
+							((int)&p->RIOHosts[Host].____end_marker____) -
+								 ((int)&p->RIOHosts[Host].Flags) );
+					 p->RIOHosts[Host].Flags  = RC_WAITING;
+#if 0
+					 RIOSetupDataStructs(p);
+#endif
+				}
+				RIOFoadWakeup(p);
+				p->RIONumBootPkts = 0;
+				p->RIOBooting = 0;
+
+#ifdef RINGBUFFER_SUPPORT
+				for( loop=0; loop<RIO_PORTS; loop++ )
+					if ( p->RIOPortp[loop]->TxRingBuffer )
+						sysfree((void *)p->RIOPortp[loop]->TxRingBuffer, 
+							RIOBufferSize );
+#endif
+#if 0
+				bzero((caddr_t)&p->RIOPortp[0],RIO_PORTS*sizeof(struct Port));
+#else
+				printk ("HEEEEELP!\n");
+#endif
+
+				for( loop=0; loop<RIO_PORTS; loop++ ) {
+#if 0
+					p->RIOPortp[loop]->TtyP = &p->channel[loop];
+#endif
+					
+					p->RIOPortp[loop]->portSem = SPIN_LOCK_UNLOCKED;
+					p->RIOPortp[loop]->InUse = NOT_INUSE;
+				}
+
+				p->RIOSystemUp = 0;
+				return retval;
+
+			case RIO_DOWNLOAD:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD\n"));
+				if ( !su ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Not super user\n"));
+					 p->RIOError.Error = NOT_SUPER_USER;
+					 return EPERM;
+				}
+				if ( copyin((int)arg, (caddr_t)&DownLoad, 
+							sizeof(DownLoad) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Copy in from user space failed\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL,  ("Copied in download code for product code 0x%x\n",
+				    DownLoad.ProductCode ) );
+
+				/*
+				** It is important that the product code is an unsigned object!
+				*/
+				if ( DownLoad.ProductCode > MAX_PRODUCT ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Bad product code %d passed\n",
+							DownLoad.ProductCode));
+					 p->RIOError.Error = NO_SUCH_PRODUCT;
+					 return ENXIO;
+				}
+				/*
+				** do something!
+				*/
+				retval = (*(RIOBootTable[DownLoad.ProductCode]))(p, &DownLoad);
+										/* <-- Panic */
+				p->RIOHalted = 0;
+				/*
+				** and go back, content with a job well completed.
+				*/
+				return retval;
+
+			case RIO_PARMS:
+				{
+					uint host;
+
+					if (copyin((int)arg, (caddr_t)&host, 
+							sizeof(host) ) == COPYFAIL ) {
+						rio_dprint(RIO_DEBUG_CTRL, (
+							"RIO_HOST_REQ: Copy in from user space failed\n"));
+						p->RIOError.Error = COPYIN_FAILED;
+						return EFAULT;
+					}
+					/*
+					** Fetch the parmmap
+					*/
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_PARMS\n"));
+					if ( copyout( (caddr_t)p->RIOHosts[host].ParmMapP, 
+								(int)arg, sizeof(PARM_MAP) )==COPYFAIL ) {
+						p->RIOError.Error = COPYOUT_FAILED;
+						rio_dprint(RIO_DEBUG_CTRL, ("RIO_PARMS: Copy out to user space failed\n"));
+						return EFAULT;
+					}
+				}
+				return retval;
+
+			case RIO_HOST_REQ:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ\n"));
+				if (copyin((int)arg, (caddr_t)&HostReq, 
+							sizeof(HostReq) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Copy in from user space failed\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( HostReq.HostNum >= p->RIONumHosts ) {
+					 p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Illegal host number %d\n",
+							HostReq.HostNum));
+					 return ENXIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for host %d\n", HostReq.HostNum));
+
+				if (copyout((caddr_t)&p->RIOHosts[HostReq.HostNum], 
+					(int)HostReq.HostP,sizeof(struct Host) ) == COPYFAIL) {
+					p->RIOError.Error = COPYOUT_FAILED;
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Bad copy to user space\n"));
+					return EFAULT;
+				}
+				return retval;
+
+			 case RIO_HOST_DPRAM:
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for DPRAM\n"));
+				if ( copyin( (int)arg, (caddr_t)&HostDpRam, 
+								sizeof(HostDpRam) )==COPYFAIL ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Copy in from user space failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+				if ( HostDpRam.HostNum >= p->RIONumHosts ) {
+					p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Illegal host number %d\n",
+										HostDpRam.HostNum));
+					return ENXIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for host %d\n", HostDpRam.HostNum));
+
+				if (p->RIOHosts[HostDpRam.HostNum].Type == RIO_PCI) {
+					 int off;
+					 /* It's hardware like this that really gets on my tits. */
+					 static unsigned char copy[sizeof(struct DpRam)];
+					for ( off=0; off<sizeof(struct DpRam); off++ )
+						copy[off] = p->RIOHosts[HostDpRam.HostNum].Caddr[off];
+					if ( copyout( (caddr_t)copy, (int)HostDpRam.DpRamP, 
+							sizeof(struct DpRam) ) == COPYFAIL ) {
+						p->RIOError.Error = COPYOUT_FAILED;
+						rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Bad copy to user space\n"));
+						return EFAULT;
+					}
+				}
+				else if (copyout((caddr_t)p->RIOHosts[HostDpRam.HostNum].Caddr,
+					(int)HostDpRam.DpRamP, 
+						sizeof(struct DpRam) ) == COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Bad copy to user space\n"));
+					 return EFAULT;
+				}
+				return retval;
+
+			 case RIO_SET_BUSY:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_BUSY\n"));
+				if ( (int)arg < 0 || (int)arg > 511 ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_BUSY: Bad port number %d\n",(int)arg));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				p->RIOPortp[(int)arg]->State |= RIO_BUSY;
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+			 case RIO_HOST_PORT:
+				/*
+				** The daemon want port information
+				** (probably for debug reasons)
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT\n"));
+				if ( copyin((int)arg, (caddr_t)&PortReq, 
+					sizeof(PortReq) )==COPYFAIL ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Copy in from user space failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+
+				if (PortReq.SysPort >= RIO_PORTS) { /* SysPort is unsigned */
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Illegal port number %d\n",
+											PortReq.SysPort));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for port %d\n", PortReq.SysPort));
+				if (copyout((caddr_t)p->RIOPortp[PortReq.SysPort], 
+							 (int)PortReq.PortP,
+								sizeof(struct Port) ) == COPYFAIL) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Bad copy to user space\n"));
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_HOST_RUP:
+				/*
+				** The daemon want rup information
+				** (probably for debug reasons)
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP\n"));
+				if (copyin((int)arg, (caddr_t)&RupReq, 
+						sizeof(RupReq) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Copy in from user space failed\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if (RupReq.HostNum >= p->RIONumHosts) { /* host is unsigned */
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Illegal host number %d\n",
+								RupReq.HostNum));
+					 p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				if ( RupReq.RupNum >= MAX_RUP+LINKS_PER_UNIT ) { /* eek! */
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Illegal rup number %d\n",
+							RupReq.RupNum));
+					 p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+				HostP = &p->RIOHosts[RupReq.HostNum];
+
+				if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Host %d not running\n",
+							RupReq.HostNum));
+					 p->RIOError.Error = HOST_NOT_RUNNING;
+					 return EIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for rup %d from host %d\n",
+						RupReq.RupNum,RupReq.HostNum));
+
+				if (copyout((caddr_t)HostP->UnixRups[RupReq.RupNum].RupP,
+					(int)RupReq.RupP,sizeof(struct RUP) ) == COPYFAIL) {
+					p->RIOError.Error = COPYOUT_FAILED;
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Bad copy to user space\n"));
+					return EFAULT;
+				}
+				return retval;
+
+			case RIO_HOST_LPB:
+				/*
+				** The daemon want lpb information
+				** (probably for debug reasons)
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB\n"));
+				if (copyin((int)arg, (caddr_t)&LpbReq, 
+					sizeof(LpbReq) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Bad copy from user space\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if (LpbReq.Host >= p->RIONumHosts) { /* host is unsigned */
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Illegal host number %d\n",
+							LpbReq.Host));
+					p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					return ENXIO;
+				}
+				if ( LpbReq.Link >= LINKS_PER_UNIT ) { /* eek! */
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Illegal link number %d\n",
+							LpbReq.Link));
+					 p->RIOError.Error = LINK_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+				HostP = &p->RIOHosts[LpbReq.Host];
+
+				if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Host %d not running\n",
+						LpbReq.Host));
+					 p->RIOError.Error = HOST_NOT_RUNNING;
+					 return EIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for lpb %d from host %d\n",
+					LpbReq.Link, LpbReq.Host));
+
+				if (copyout((caddr_t)&HostP->LinkStrP[LpbReq.Link],
+					(int)LpbReq.LpbP,sizeof(struct LPB) ) == COPYFAIL) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Bad copy to user space\n"));
+					p->RIOError.Error = COPYOUT_FAILED;
+					return EFAULT;
+				}
+				return retval;
+
+				/*
+				** Here 3 IOCTL's that allow us to change the way in which
+				** rio logs errors. send them just to syslog or send them
+				** to both syslog and console or send them to just the console.
+				**
+				** See RioStrBuf() in util.c for the other half.
+				*/
+			case RIO_SYSLOG_ONLY:
+				p->RIOPrintLogState = PRINT_TO_LOG;	/* Just syslog */
+				return 0;
+
+			case RIO_SYSLOG_CONS:
+				p->RIOPrintLogState = PRINT_TO_LOG_CONS;/* syslog and console */
+				return 0;
+
+			case RIO_CONS_ONLY:
+				p->RIOPrintLogState = PRINT_TO_CONS;	/* Just console */
+				return 0;
+
+			case RIO_SIGNALS_ON:
+				if ( p->RIOSignalProcess ) {
+					 p->RIOError.Error = SIGNALS_ALREADY_SET;
+					 return EBUSY;
+				}
+				p->RIOSignalProcess = getpid();
+				p->RIOPrintDisabled = DONT_PRINT;
+				return retval;
+
+			case RIO_SIGNALS_OFF:
+				if ( p->RIOSignalProcess != getpid() ) {
+					 p->RIOError.Error = NOT_RECEIVING_PROCESS;
+					 return EPERM;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Clear signal process to zero\n"));
+				p->RIOSignalProcess = 0;
+				return retval;
+
+			case RIO_SET_BYTE_MODE:
+				for ( Host=0; Host<p->RIONumHosts; Host++ )
+					 if ( p->RIOHosts[Host].Type == RIO_AT )
+						 p->RIOHosts[Host].Mode &= ~WORD_OPERATION;
+				return retval;
+
+			case RIO_SET_WORD_MODE:
+				for ( Host=0; Host<p->RIONumHosts; Host++ )
+					 if ( p->RIOHosts[Host].Type == RIO_AT )
+						 p->RIOHosts[Host].Mode |= WORD_OPERATION;
+				return retval;
+
+			case RIO_SET_FAST_BUS:
+				for ( Host=0; Host<p->RIONumHosts; Host++ )
+					 if ( p->RIOHosts[Host].Type == RIO_AT )
+						 p->RIOHosts[Host].Mode |= FAST_AT_BUS;
+				return retval;
+
+			case RIO_SET_SLOW_BUS:
+				for ( Host=0; Host<p->RIONumHosts; Host++ )
+					 if ( p->RIOHosts[Host].Type == RIO_AT )
+						 p->RIOHosts[Host].Mode &= ~FAST_AT_BUS;
+				return retval;
+
+			case RIO_MAP_B50_TO_50:
+			case RIO_MAP_B50_TO_57600:
+			case RIO_MAP_B110_TO_110:
+			case RIO_MAP_B110_TO_115200:
+				rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping\n"));
+				port = (uint) arg;
+				if ( port < 0 || port > 511 ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping: Bad port number %d\n", port));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				switch( cmd )
+				{
+					case RIO_MAP_B50_TO_50 :
+						p->RIOPortp[port]->Config |= RIO_MAP_50_TO_50;
+						break;
+					case RIO_MAP_B50_TO_57600 :
+						p->RIOPortp[port]->Config &= ~RIO_MAP_50_TO_50;
+						break;
+					case RIO_MAP_B110_TO_110 :
+						p->RIOPortp[port]->Config |= RIO_MAP_110_TO_110;
+						break;
+					case RIO_MAP_B110_TO_115200 :
+						p->RIOPortp[port]->Config &= ~RIO_MAP_110_TO_110;
+						break;
+				}
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+			case RIO_STREAM_INFO:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_STREAM_INFO\n"));
+				return EINVAL;
+
+			case RIO_SEND_PACKET:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_SEND_PACKET\n"));
+				if ( copyin( (int)arg, (caddr_t)&SendPack,
+									sizeof(SendPack) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_SEND_PACKET: Bad copy from user space\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( SendPack.PortNum >= 128 ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+
+				PortP = p->RIOPortp[SendPack.PortNum];
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				if ( !can_add_transmit(&PacketP,PortP) ) {
+					 p->RIOError.Error = UNIT_IS_IN_USE;
+					 rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+					 return ENOSPC;
+				}
+
+				for ( loop=0; loop<(ushort)(SendPack.Len & 127); loop++ )
+					 WBYTE(PacketP->data[loop], SendPack.Data[loop] );
+
+				WBYTE(PacketP->len, SendPack.Len);
+
+				add_transmit( PortP );
+				/*
+				** Count characters transmitted for port statistics reporting
+				*/
+				if (PortP->statsGather)
+					 PortP->txchars += (SendPack.Len & 127);
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+			case RIO_NO_MESG:
+				if ( su )
+					 p->RIONoMessage = 1;
+				return su ? 0 : EPERM;
+
+			case RIO_MESG:
+				if ( su )
+					p->RIONoMessage = 0;
+				return su ? 0 : EPERM;
+
+			case RIO_WHAT_MESG:
+				if ( copyout( (caddr_t)&p->RIONoMessage, (int)arg, 
+					sizeof(p->RIONoMessage) )==COPYFAIL ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_WHAT_MESG: Bad copy to user space\n"));
+					p->RIOError.Error = COPYOUT_FAILED;
+					return EFAULT;
+				}
+				return 0;
+
+			case RIO_MEM_DUMP :
+				if (copyin((int)arg, (caddr_t)&SubCmd, 
+						sizeof(struct SubCmdStruct)) == COPYFAIL) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP host %d rup %d addr %x\n", 
+						SubCmd.Host, SubCmd.Rup, SubCmd.Addr));
+
+				if (SubCmd.Rup >= MAX_RUP+LINKS_PER_UNIT ) {
+					 p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				if (SubCmd.Host >= p->RIONumHosts ) {
+					 p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				port = p->RIOHosts[SubCmd.Host].
+								UnixRups[SubCmd.Rup].BaseSysPort;
+
+				PortP = p->RIOPortp[port];
+
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				if ( RIOPreemptiveCmd(p,  PortP, MEMDUMP ) == RIO_FAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP failed\n"));
+					 rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+					 return EBUSY;
+				}
+				else
+					 PortP->State |= RIO_BUSY;
+
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				if ( copyout( (caddr_t)p->RIOMemDump, (int)arg, 
+							MEMDUMP_SIZE) == COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP copy failed\n"));
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return 0;
+
+			case RIO_TICK:
+				if ((int)arg < 0 || (int)arg >= p->RIONumHosts)
+					 return EINVAL;
+				rio_dprint(RIO_DEBUG_CTRL, ("Set interrupt for host %d\n", (int)arg ));
+				WBYTE(p->RIOHosts[(int)arg].SetInt , 0xff);
+				return 0;
+
+			case RIO_TOCK:
+				if ((int)arg < 0 || (int)arg >= p->RIONumHosts)
+					 return EINVAL;
+				rio_dprint(RIO_DEBUG_CTRL, ("Clear interrupt for host %d\n", (int)arg ));
+				WBYTE((p->RIOHosts[(int)arg].ResetInt) , 0xff);
+				return 0;
+
+			case RIO_READ_CHECK:
+				/* Check reads for pkts with data[0] the same */
+				p->RIOReadCheck = !p->RIOReadCheck;
+				if (copyout((caddr_t)&p->RIOReadCheck,(int)arg,
+							sizeof(uint))== COPYFAIL) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return 0;
+
+			case RIO_READ_REGISTER :
+				if (copyin((int)arg, (caddr_t)&SubCmd, 
+							sizeof(struct SubCmdStruct)) == COPYFAIL) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER host %d rup %d port %d reg %x\n", 
+						SubCmd.Host, SubCmd.Rup, SubCmd.Port, SubCmd.Addr));
+
+				if (SubCmd.Port > 511) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping: Bad port number %d\n", 
+								SubCmd.Port));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				if (SubCmd.Rup >= MAX_RUP+LINKS_PER_UNIT ) {
+					 p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				if (SubCmd.Host >= p->RIONumHosts ) {
+					 p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				port = p->RIOHosts[SubCmd.Host].
+						UnixRups[SubCmd.Rup].BaseSysPort + SubCmd.Port;
+				PortP = p->RIOPortp[port];
+
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				if (RIOPreemptiveCmd(p, PortP, READ_REGISTER) == RIO_FAIL) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER failed\n"));
+					 rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+					 return EBUSY;
+				}
+				else
+					 PortP->State |= RIO_BUSY;
+
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				if (copyout((caddr_t)&p->CdRegister, (int)arg, 
+							sizeof(uint)) == COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER copy failed\n"));
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return 0;
+				/*
+				** rio_make_dev: given port number (0-511) ORed with port type
+				** (RIO_DEV_DIRECT, RIO_DEV_MODEM, RIO_DEV_XPRINT) return dev_t
+				** value to pass to mknod to create the correct device node.
+				*/
+			case RIO_MAKE_DEV:
+				{
+					uint port = (uint)arg & RIO_MODEM_MASK;
+
+					switch ( (uint)arg & RIO_DEV_MASK ) {
+						case RIO_DEV_DIRECT:
+							arg = (caddr_t)drv_makedev(major(dev), port);
+							rio_dprint(RIO_DEBUG_CTRL, ("Makedev direct 0x%x is 0x%x\n",port, (int)arg ));
+							return (int)arg;
+					 	case RIO_DEV_MODEM:
+							arg =  (caddr_t)drv_makedev(major(dev), (port|RIO_MODEM_BIT) );
+							rio_dprint(RIO_DEBUG_CTRL, ("Makedev modem 0x%x is 0x%x\n",port, (int)arg ));
+							return (int)arg;
+						case RIO_DEV_XPRINT:
+							arg = (caddr_t)drv_makedev(major(dev), port);
+							rio_dprint(RIO_DEBUG_CTRL, ("Makedev printer 0x%x is 0x%x\n",port, (int)arg ));
+							return (int)arg;
+					}
+					rio_dprint(RIO_DEBUG_CTRL, ("MAKE Device is called\n"));
+					return EINVAL;
+				}
+				/*
+				** rio_minor: given a dev_t from a stat() call, return
+				** the port number (0-511) ORed with the port type
+				** ( RIO_DEV_DIRECT, RIO_DEV_MODEM, RIO_DEV_XPRINT )
+				*/
+			case RIO_MINOR:
+				{
+					dev_t dv;
+					int mino;
+
+					dv = (dev_t)((int)arg);
+					mino = RIO_UNMODEM(dv);
+
+					if ( RIO_ISMODEM(dv) ) {
+						rio_dprint(RIO_DEBUG_CTRL, ("Minor for device 0x%x: modem %d\n", dv, mino));
+						arg = (caddr_t)(mino | RIO_DEV_MODEM);
+					}
+					else {
+						rio_dprint(RIO_DEBUG_CTRL, ("Minor for device 0x%x: direct %d\n", dv, mino));
+						arg = (caddr_t)(mino | RIO_DEV_DIRECT);
+					}
+					return (int)arg;
+				}
+	}
+	rio_dprint(RIO_DEBUG_CTRL, ("INVALID DAEMON IOCTL 0x%x\n",cmd));
+	p->RIOError.Error = IOCTL_COMMAND_UNKNOWN;
+	return EINVAL;
+}
+
+/*
+** Pre-emptive commands go on RUPs and are only one byte long.
+*/
+int
+RIOPreemptiveCmd(p, PortP, Cmd)
+struct rio_info *	p;
+struct Port *PortP;
+uchar Cmd;
+{
+	struct CmdBlk *CmdBlkP;
+	struct PktCmd_M *PktCmdP;
+	int Ret;
+	ushort rup;
+	int port;
+
+#ifdef CHECK
+	CheckPortP( PortP );
+#endif
+
+	if ( PortP->State & RIO_DELETED ) {
+		rio_dprint(RIO_DEBUG_CTRL, ("Preemptive command to deleted RTA ignored\n"));
+		return RIO_FAIL;
+	}
+
+	if (((int)((char)PortP->InUse) == -1) || ! (CmdBlkP = RIOGetCmdBlk()) ) {
+		rio_dprint(RIO_DEBUG_CTRL, ("Cannot allocate command block for command %d on port %d\n",
+		       Cmd, PortP->PortNum));
+		return RIO_FAIL;
+	}
+
+	rio_dprint(RIO_DEBUG_CTRL, ("Command blk 0x%x - InUse now %d\n", 
+	       (int)CmdBlkP,PortP->InUse));
+
+	PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0];
+
+	CmdBlkP->Packet.src_unit  = 0;
+	if (PortP->SecondBlock)
+		rup = PortP->ID2;
+	else
+		rup = PortP->RupNum;
+	CmdBlkP->Packet.dest_unit = rup;
+	CmdBlkP->Packet.src_port  = COMMAND_RUP;
+	CmdBlkP->Packet.dest_port = COMMAND_RUP;
+	CmdBlkP->Packet.len	  = PKT_CMD_BIT | 2;
+	CmdBlkP->PostFuncP	= RIOUnUse;
+	CmdBlkP->PostArg	= (int)PortP;
+	PktCmdP->Command	= Cmd;
+	port				= PortP->HostPort % (ushort)PORTS_PER_RTA;
+	/*
+	** Index ports 8-15 for 2nd block of 16 port RTA.
+	*/
+	if (PortP->SecondBlock)
+		port += (ushort) PORTS_PER_RTA;
+	PktCmdP->PhbNum	   = port;
+
+	switch ( Cmd ) {
+		case MEMDUMP:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue MEMDUMP command blk 0x%x (addr 0x%x)\n",
+			       (int)CmdBlkP, (int)SubCmd.Addr));
+			PktCmdP->SubCommand		= MEMDUMP;
+			PktCmdP->SubAddr		= SubCmd.Addr;
+			break;
+		case FCLOSE:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue FCLOSE command blk 0x%x\n",(int)CmdBlkP));
+			break;
+		case READ_REGISTER:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue READ_REGISTER (0x%x) command blk 0x%x\n",
+		 		(int)SubCmd.Addr, (int)CmdBlkP));
+			PktCmdP->SubCommand		= READ_REGISTER;
+			PktCmdP->SubAddr		= SubCmd.Addr;
+			break;
+		case RESUME:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue RESUME command blk 0x%x\n",(int)CmdBlkP));
+			break;
+		case RFLUSH:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue RFLUSH command blk 0x%x\n",(int)CmdBlkP));
+			CmdBlkP->PostFuncP = RIORFlushEnable;
+			break;
+		case SUSPEND:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue SUSPEND command blk 0x%x\n",(int)CmdBlkP));
+			break;
+
+		case MGET :
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue MGET command blk 0x%x\n", (int)CmdBlkP));
+			break;
+
+		case MSET :
+		case MBIC :
+		case MBIS :
+			CmdBlkP->Packet.data[4] = (char) PortP->ModemLines;
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue MSET/MBIC/MBIS command blk 0x%x\n", (int)CmdBlkP));
+			break;
+
+		case WFLUSH:
+			/*
+			** If we have queued up the maximum number of Write flushes
+			** allowed then we should not bother sending any more to the
+			** RTA.
+			*/
+			if ((int)((char)PortP->WflushFlag) == (int)-1) {
+				rio_dprint(RIO_DEBUG_CTRL, ("Trashed WFLUSH, WflushFlag about to wrap!"));
+				RIOFreeCmdBlk(CmdBlkP);
+				return(RIO_FAIL);
+			} else {
+				rio_dprint(RIO_DEBUG_CTRL, ("Queue WFLUSH command blk 0x%x\n",
+				       (int)CmdBlkP));
+				CmdBlkP->PostFuncP = RIOWFlushMark;
+			}
+			break;
+	}
+
+	PortP->InUse++;
+
+	Ret = RIOQueueCmdBlk( PortP->HostP, rup, CmdBlkP );
+
+	return Ret;
+}
diff -urN linux-2.2.15-pre2/drivers/char/rio/riodrvr.h linux/drivers/char/rio/riodrvr.h
--- linux-2.2.15-pre2/drivers/char/rio/riodrvr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riodrvr.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,143 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riodrvr.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 09:22:46
+**	Retrieved	: 11/6/98 09:22:46
+**
+**  ident @(#)riodrvr.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __riodrvr_h
+#define __riodrvr_h
+
+#ifdef SCCS_LABELS
+static char *_riodrvr_h_sccs_ = "@(#)riodrvr.h	1.3";
+#endif
+
+#define MEMDUMP_SIZE	32
+#define HZ				100
+#define	MOD_DISABLE	(RIO_NOREAD|RIO_NOWRITE|RIO_NOXPRINT)
+
+
+struct rio_info {
+	int			mode;			/* Intr or polled, word/byte */
+	semtype			RIOIntrSem;		/* Interrupt thread sem */
+	int			current_chan;		/* current channel */
+	int			RIOFailed;		/* Not initialised ? */
+	int			RIOInstallAttempts;	/* no. of rio-install() calls */
+	int			RIOLastPCISearch;	/* status of last search */
+	int			RIONumHosts;		/* Number of RIO Hosts */
+	struct Host		* RIOHosts;		/* RIO Host values */
+	struct Port		**RIOPortp;		/* RIO port values */
+/*
+** 02.03.1999 ARG - ESIL 0820 fix
+** We no longer use RIOBootMode
+**
+	int			RIOBootMode;		* RIO boot mode *
+**
+*/
+	int			RIOPrintDisabled;	/* RIO printing disabled ? */
+	int			RIOPrintLogState;	/* RIO printing state ? */
+	int			RIOPolling;		/* Polling ? */
+/*
+** 09.12.1998 ARG - ESIL 0776 part fix
+** The 'RIO_QUICK_CHECK' ioctl was using RIOHalted.
+** The fix for this ESIL introduces another member (RIORtaDisCons) here to be
+** updated in RIOConCon() - to keep track of RTA connections/disconnections.
+** 'RIO_QUICK_CHECK' now returns the value of RIORtaDisCons.
+*/
+	int			RIOHalted;		/* halted ? */
+	int			RIORtaDisCons;		/* RTA connections/disconnections */
+	uint			RIOReadCheck;		/* Rio read check */
+	uint			RIONoMessage;		/* To display message or not */
+	uint			RIONumBootPkts;		/* how many packets for an RTA */
+	uint			RIOBootCount; 		/* size of RTA code */
+	uint			RIOBooting;		/* count of outstanding boots */
+	uint			RIOSystemUp;		/* Booted ?? */
+	uint			RIOCounting;		/* for counting interrupts */
+	uint			RIOIntCount;		/* # of intr since last check */
+	uint			RIOTxCount;		/* number of xmit intrs  */
+	uint			RIORxCount;		/* number of rx intrs */
+	uint			RIORupCount;		/* number of rup intrs */
+	int			RIXTimer; 
+	int			RIOBufferSize;		/* Buffersize */
+	int			RIOBufferMask;		/* Buffersize */
+
+	int			RIOFirstMajor;		/* First host card's major no */
+
+	uint			RIOLastPortsMapped;	/* highest port number known */
+	uint			RIOFirstPortsMapped;	/* lowest port number known */
+
+	uint			RIOLastPortsBooted;	/* highest port number running */
+	uint			RIOFirstPortsBooted;	/* lowest port number running */
+
+	uint			RIOLastPortsOpened;	/* highest port number running */
+	uint			RIOFirstPortsOpened;	/* lowest port number running */
+
+	/* Flag to say that the topology information has been changed. */
+	uint			RIOQuickCheck; 
+	uint			CdRegister;		/* ??? */
+	int			RIOSignalProcess;	/* Signalling process */
+	int			rio_debug;		/* To debug ... */
+	int			RIODebugWait;		/* For what ??? */
+	int			tpri;			/* Thread prio */
+	int			tid;			/* Thread id */
+	uint			_RIO_Polled;		/* Counter for polling */
+	uint			_RIO_Interrupted;	/* Counter for interrupt */
+	int			intr_tid;		/* iointset return value */
+	int			TxEnSem;		/* TxEnable Semaphore */
+
+
+	struct Error		RIOError;		/* to Identify what went wrong */ 
+	struct Conf		RIOConf;		/* Configuration ??? */
+	struct ttystatics	channel[RIO_PORTS];	/* channel information */
+	char			RIOBootPackets[1+(SIXTY_FOUR_K/RTA_BOOT_DATA_SIZE)]
+								[RTA_BOOT_DATA_SIZE];
+	struct Map		RIOConnectTable[TOTAL_MAP_ENTRIES];
+	struct Map		RIOSavedTable[TOTAL_MAP_ENTRIES];
+
+	/* RTA to host binding table for master/slave operation */
+	ulong			RIOBindTab[MAX_RTA_BINDINGS];
+	/* RTA memory dump variable */
+	uchar			RIOMemDump[MEMDUMP_SIZE]; 
+	struct ModuleInfo 	RIOModuleTypes[MAX_MODULE_TYPES];
+
+};
+
+
+#ifdef linux
+#define debug(x)        printk x
+#else
+#define debug(x)	kkprintf x
+#endif
+
+
+
+#define RIO_RESET_INT	0x7d80
+#define WRBYTE(x,y)		*(volatile unsigned char *)((x)) = \
+					(unsigned char)(y)
+
+#endif	/* __riodrvr.h */
diff -urN linux-2.2.15-pre2/drivers/char/rio/rioinfo.h linux/drivers/char/rio/rioinfo.h
--- linux-2.2.15-pre2/drivers/char/rio/rioinfo.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioinfo.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,96 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioinfo.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 14:07:49
+**	Retrieved	: 11/6/98 14:07:50
+**
+**  ident @(#)rioinfo.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rioinfo_h
+#define __rioinfo_h
+
+#ifdef SCCS_LABELS
+static char *_rioinfo_h_sccs_ = "@(#)rioinfo.h	1.2";
+#endif
+
+/*
+** Host card data structure
+*/
+struct RioHostInfo {
+	long	location;	/* RIO Card Base I/O address */
+	long	vector;		/* RIO Card IRQ vector */
+	int	bus;		/* ISA/EISA/MCA/PCI */
+	int	mode;		/* pointer to host mode - INTERUPT / POLLED */
+	struct old_sgttyb
+		* Sg;		/* pointer to default term characteristics */
+};
+
+
+/* Mode in rio device info */
+#define INTERRUPTED_MODE	0x01		/* Interrupt is generated */
+#define POLLED_MODE		0x02		/* No interrupt */
+#define AUTO_MODE		0x03		/* Auto mode */
+
+#define WORD_ACCESS_MODE	0x10		/* Word Access Mode */
+#define BYTE_ACCESS_MODE	0x20		/* Byte Access Mode */
+
+
+/* Bus type that RIO supports */
+#define ISA_BUS			0x01		/* The card is ISA */
+#define EISA_BUS		0x02		/* The card is EISA */
+#define MCA_BUS			0x04		/* The card is MCA */
+#define PCI_BUS			0x08		/* The card is PCI */
+
+/*
+** 11.11.1998 ARG - ESIL ???? part fix
+** Moved definition for 'CHAN' here from rioinfo.c (it is now
+** called 'DEF_TERM_CHARACTERISTICS').
+*/
+
+#define DEF_TERM_CHARACTERISTICS \
+{ \
+	B19200, B19200,				/* input and output speed */ \
+	'H' - '@',				/* erase char */ \
+	-1,					/* 2nd erase char */ \
+	'U' - '@',				/* kill char */ \
+	ECHO | CRMOD,				/* mode */ \
+	'C' - '@',				/* interrupt character */ \
+	'\\' - '@',				/* quit char */ \
+	'Q' - '@',				/* start char */ \
+	'S' - '@',				/* stop char */ \
+	'D' - '@',				/* EOF */ \
+	-1,					/* brk */ \
+	(LCRTBS | LCRTERA | LCRTKIL | LCTLECH),	/* local mode word */ \
+	'Z' - '@',				/* process stop */ \
+	'Y' - '@',				/* delayed stop */ \
+	'R' - '@',				/* reprint line */ \
+	'O' - '@',				/* flush output */ \
+	'W' - '@',				/* word erase */ \
+	'V' - '@'				/* literal next char */ \
+}
+
+#endif /* __rioinfo_h */
diff -urN linux-2.2.15-pre2/drivers/char/rio/rioinit.c linux/drivers/char/rio/rioinit.c
--- linux-2.2.15-pre2/drivers/char/rio/rioinit.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioinit.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1652 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioinit.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:43
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)rioinit.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_rioinit_c_sccs_ = "@(#)rioinit.c	1.3";
+#endif
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+#undef bcopy
+#define bcopy rio_pcicopy
+
+int
+RIOPCIinit(struct rio_info *p, int Mode);
+
+
+#if 0
+extern int	rio_intr();
+
+/*
+**	Init time code.
+*/
+void
+rioinit( p, info )
+struct rio_info		* p;
+struct RioHostInfo	* info;
+{
+	/*
+	** Multi-Host card support - taking the easy way out - sorry !
+	** We allocate and set up the Host and Port structs when the
+	** driver is called to 'install' the first host.
+	** We check for this first 'call' by testing the RIOPortp pointer.
+	*/
+	if ( !p->RIOPortp )
+	{
+		rio_dprint(RIO_DEBUG_INIT,  ("Allocating and setting up driver data structures\n") );
+
+		RIOAllocDataStructs(p);		/* allocate host/port structs */
+		RIOSetupDataStructs(p);		/* setup topology structs */
+	}
+
+	RIOInitHosts( p, info );	/* hunt down the hardware */
+
+	RIOAllocateInterrupts(p);	/* allocate interrupts */
+	RIOReport(p);			/* show what we found */
+}
+
+/*
+** Initialise the Cards 
+*/ 
+void
+RIOInitHosts(p, info)
+struct rio_info		* p;
+struct RioHostInfo	* info;
+{
+/*
+** 15.10.1998 ARG - ESIL 0762 part fix
+** If there is no ISA card definition - we always look for PCI cards.
+** As we currently only support one host card this lets an ISA card
+** definition take precedence over PLUG and PLAY.
+** No ISA card - we are PLUG and PLAY with PCI.
+*/
+
+	/*
+	** Note - for PCI both these will be zero, that's okay because
+	** RIOPCIInit() fills them in if a card is found.
+	*/
+	p->RIOHosts[p->RIONumHosts].Ivec	= info->vector;
+	p->RIOHosts[p->RIONumHosts].PaddrP	= info->location;
+
+	/*
+	** Check that we are able to accomodate another host
+	*/
+	if ( p->RIONumHosts >= RIO_HOSTS )
+	{
+		p->RIOFailed++;
+		return;
+	}
+
+	if ( info->bus & ISA_BUS )
+	{
+		rio_dprint(RIO_DEBUG_INIT,  ("initialising card %d (ISA)\n", p->RIONumHosts) );
+		RIOISAinit(p, p->mode);
+	}
+	else
+	{
+		rio_dprint(RIO_DEBUG_INIT,  ("initialising card %d (PCI)\n", p->RIONumHosts) );
+		RIOPCIinit(p, RIO_PCI_DEFAULT_MODE);
+	}
+
+	rio_dprint(RIO_DEBUG_INIT,  ("Total hosts initialised so far : %d\n", p->RIONumHosts) );
+
+
+#ifdef FUTURE_RELEASE
+	if (p->bus & EISA_BUS)
+		/* EISA card */
+		RIOEISAinit(p, RIO_EISA_DEFAULT_MODE);
+
+	if (p->bus & MCA_BUS)
+		/* MCA card */
+		RIOMCAinit(p, RIO_MCA_DEFAULT_MODE);
+#endif
+}
+
+/*
+** go through memory for an AT host that we pass in the device info
+** structure and initialise
+*/
+void
+RIOISAinit(p, mode)
+struct rio_info *	p;
+int					mode;
+{
+
+  /* XXX Need to implement this. */
+#if 0
+	p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec,
+					(int (*)())rio_intr, (char*)p->RIONumHosts);
+
+	rio_dprint(RIO_DEBUG_INIT,  ("Set interrupt handler, intr_tid = 0x%x\n", p->intr_tid ) );
+
+	if (RIODoAT(p, p->RIOHosts[p->RIONumHosts].PaddrP, mode)) {
+		return;
+	}
+	else {
+		rio_dprint(RIO_DEBUG_INIT, ("RIODoAT failed\n"));
+		p->RIOFailed++;
+	}
+#endif
+
+}
+
+/*
+** RIODoAT :
+**
+** Map in a boards physical address, check that the board is there,
+** test the board and if everything is okay assign the board an entry
+** in the Rio Hosts structure.
+*/
+int
+RIODoAT(p, Base, mode)
+struct rio_info *	p;
+int		Base;
+int		mode;
+{
+#define	FOUND		1
+#define NOT_FOUND	0
+
+	caddr_t		cardAddr;
+
+	/*
+	** Check to see if we actually have a board at this physical address.
+	*/
+	if ((cardAddr = RIOCheckForATCard(Base)) != 0) {
+		/*
+		** Now test the board to see if it is working.
+		*/
+		if (RIOBoardTest(Base, cardAddr, RIO_AT, 0) == RIO_SUCCESS) {
+			/*
+			** Fill out a slot in the Rio host structure.
+			*/
+			if (RIOAssignAT(p, Base, cardAddr, mode)) {
+				return(FOUND);
+			}
+		}
+		RIOMapout(Base, RIO_AT_MEM_SIZE, cardAddr);
+	}
+	return(NOT_FOUND);
+}
+
+caddr_t
+RIOCheckForATCard(Base)
+int		Base;
+{
+	int				off;
+	struct DpRam	*cardp;		/* (Points at the host) */
+	caddr_t			virtAddr;
+	unsigned char			RIOSigTab[24];
+/*
+** Table of values to search for as prom signature of a host card
+*/
+	strcpy(RIOSigTab, "JBJGPGGHINSMJPJR");
+
+	/*
+	** Hey! Yes, You reading this code! Yo, grab a load a this:
+	**
+	** IF the card is using WORD MODE rather than BYTE MODE
+	** then it will occupy 128K of PHYSICAL memory area. So,
+	** you might think that the following Mapin is wrong. Well,
+	** it isn't, because the SECOND 64K of occupied space is an
+	** EXACT COPY of the FIRST 64K. (good?), so, we need only
+	** map it in in one 64K block.
+	*/
+	if (RIOMapin(Base, RIO_AT_MEM_SIZE, &virtAddr) == -1) {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Couldn't map the board in!\n"));
+		return((caddr_t)0);
+	}
+
+	/*
+	** virtAddr points to the DP ram of the system.
+	** We now cast this to a pointer to a RIO Host,
+	** and have a rummage about in the PROM.
+	*/
+	cardp = (struct DpRam *)virtAddr;
+
+	for (off=0; RIOSigTab[off]; off++) {
+		if ((RBYTE(cardp->DpSignature[off]) & 0xFF) != RIOSigTab[off]) {
+			/*
+			** Signature mismatch - card not at this address
+			*/
+			RIOMapout(Base, RIO_AT_MEM_SIZE, virtAddr);
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Couldn't match the signature 0x%x 0x%x!\n",
+						(int)cardp, off));
+			return((caddr_t)0);
+		}
+	}
+
+	/*
+	** If we get here then we must have found a valid board so return
+	** its virtual address.
+	*/
+	return(virtAddr);
+}
+#endif
+
+/**
+** RIOAssignAT :
+**
+** Fill out the fields in the p->RIOHosts structure now we know we know
+** we have a board present.
+**
+** bits < 0 indicates 8 bit operation requested,
+** bits > 0 indicates 16 bit operation.
+*/
+int
+RIOAssignAT(p, Base, virtAddr, mode)
+struct rio_info *	p;
+int		Base;
+caddr_t	virtAddr;
+int		mode;
+{
+	int		bits;
+	struct DpRam *cardp = (struct DpRam *)virtAddr;
+
+	if ((Base < ONE_MEG) || (mode & BYTE_ACCESS_MODE))
+		bits = BYTE_OPERATION;
+	else
+		bits = WORD_OPERATION;
+
+	/*
+	** Board has passed its scrub test. Fill in all the
+	** transient stuff.
+	*/
+	p->RIOHosts[p->RIONumHosts].Caddr	= virtAddr;
+	p->RIOHosts[p->RIONumHosts].CardP	= (struct DpRam *)virtAddr;
+
+	/*
+	** Revision 01 AT host cards don't support WORD operations,
+	*/
+	if ( RBYTE(cardp->DpRevision) == 01 )
+		bits = BYTE_OPERATION;
+
+	p->RIOHosts[p->RIONumHosts].Type = RIO_AT;
+	p->RIOHosts[p->RIONumHosts].Copy = bcopy;
+											/* set this later */
+	p->RIOHosts[p->RIONumHosts].Slot = -1;
+	p->RIOHosts[p->RIONumHosts].Mode = SLOW_LINKS | SLOW_AT_BUS | bits;
+	WBYTE(p->RIOHosts[p->RIONumHosts].Control, 
+			BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+			p->RIOHosts[p->RIONumHosts].Mode | 
+			INTERRUPT_DISABLE );
+	WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff);
+	WBYTE(p->RIOHosts[p->RIONumHosts].Control,
+			BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+			p->RIOHosts[p->RIONumHosts].Mode |
+			INTERRUPT_DISABLE );
+	WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff);
+	p->RIOHosts[p->RIONumHosts].UniqueNum =
+		((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0])&0xFF)<<0)|
+		((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)|
+		((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)|
+		((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24);
+	rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Uniquenum 0x%x\n",p->RIOHosts[p->RIONumHosts].UniqueNum));
+
+	p->RIONumHosts++;
+	rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Tests Passed at 0x%x\n", Base));
+	return(1);
+}
+#if 0
+#ifdef FUTURE_RELEASE
+int RIOMCAinit(int Mode)
+{
+	uchar SlotNumber;
+	caddr_t Caddr;
+	uint	Paddr;
+	uint	Ivec;
+	int	 Handle;
+	int	 ret = 0;
+
+	/*
+	** Valid mode information for MCA cards
+	** is only FAST LINKS
+	*/
+	Mode = (Mode & FAST_LINKS) ? McaTpFastLinks : McaTpSlowLinks;
+	rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOMCAinit(%d)\n",Mode);
+
+
+	/*
+	** Check out each of the slots
+	*/
+	for (SlotNumber = 0; SlotNumber < McaMaxSlots; SlotNumber++) {
+	/*
+	** Enable the slot we want to talk to
+	*/
+	outb( McaSlotSelect, SlotNumber | McaSlotEnable );
+
+	/*
+	** Read the ID word from the slot
+	*/
+	if (((inb(McaIdHigh)<< 8)|inb(McaIdLow)) == McaRIOId)
+	{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Potential MCA card in slot %d\n",SlotNumber);
+
+		/*
+		** Card appears to be a RIO MCA card!
+		*/
+		RIOMachineType |= (1<<RIO_MCA);
+
+		/*
+		** Just check we haven't found too many wonderful objects
+		*/
+		if ( RIONumHosts >= RIO_HOSTS )
+		{
+		Rprintf(RIOMesgTooManyCards);
+		return(ret);
+		}
+
+		/*
+		** McaIrqEnable contains the interrupt vector, and a card
+		** enable bit.
+		*/
+		Ivec = inb(McaIrqEnable);
+
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Ivec is %x\n",Ivec);
+
+		switch ( Ivec & McaIrqMask )
+		{
+		case McaIrq9:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ9\n");
+		break;
+		case McaIrq3:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ3\n");
+		break;
+		case McaIrq4:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ4\n");
+		break;
+		case McaIrq7:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ7\n");
+		break;
+		case McaIrq10:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ10\n");
+		break;
+		case McaIrq11:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ11\n");
+		break;
+		case McaIrq12:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ12\n");
+		break;
+		case McaIrq15:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ15\n");
+		break;
+		}
+
+		/*
+		** If the card enable bit isn't set, then set it!
+		*/
+		if ((Ivec & McaCardEnable) != McaCardEnable )
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"McaCardEnable not set - setting!\n");
+		outb(McaIrqEnable,Ivec|McaCardEnable);
+		}
+		else
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"McaCardEnable already set\n");
+		}
+
+		/*
+		** Convert the IRQ enable mask into something useful
+		*/
+		Ivec = RIOMcaToIvec[Ivec & McaIrqMask];
+
+		/*
+		** Find the physical address
+		*/
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"inb(McaMemory) is %x\n",inb(McaMemory));
+		Paddr = McaAddress(inb(McaMemory));
+
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"MCA card has Ivec %d Addr %x\n",Ivec,Paddr);
+
+		if ( Paddr != 0 )
+		{
+
+		/*
+		** Tell the memory mapper that we want to talk to it
+		*/
+		Handle = RIOMapin( Paddr, RIO_MCA_MEM_SIZE, &Caddr );
+
+		if ( Handle == -1 ) {
+			rio_dprint(RIO_DEBUG_INIT, ("Couldn't map %d bytes at %x\n", RIO_MCA_MEM_SIZE,Paddr);
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Board mapped to vaddr 0x%x\n",Caddr);
+
+		/*
+		** And check that it is actually there!
+		*/
+		if ( RIOBoardTest( Paddr,Caddr,RIO_MCA,SlotNumber ) == RIO_SUCCESS )
+		{
+			rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Board has passed test\n");
+			rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,
+	"Slot %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n",
+			SlotNumber,RIO_MCA,Paddr,Caddr,Mode);
+
+			/*
+			** Board has passed its scrub test. Fill in all the
+			** transient stuff.
+			*/
+			p->RIOHosts[RIONumHosts].Slot	 = SlotNumber;
+			p->RIOHosts[RIONumHosts].Ivec	 = Ivec;
+			p->RIOHosts[RIONumHosts].Type	 = RIO_MCA;
+			p->RIOHosts[RIONumHosts].Copy	 = bcopy;
+			p->RIOHosts[RIONumHosts].PaddrP   = Paddr;
+			p->RIOHosts[RIONumHosts].Caddr	= Caddr;
+			p->RIOHosts[RIONumHosts].CardP	= (struct DpRam *)Caddr;
+			p->RIOHosts[RIONumHosts].Mode	 = Mode;
+			WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt , 0xff);
+			p->RIOHosts[RIONumHosts].UniqueNum =
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[0])&0xFF)<<0)|
+						((RBYTE(p->RIOHosts[RIONumHosts].Unique[1])&0xFF)<<8)|
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[2])&0xFF)<<16)|
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[3])&0xFF)<<24);
+			RIONumHosts++;
+			ret++;
+		}
+		else
+		{
+			/*
+			** It failed the test, so ignore it.
+			*/
+			rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"TEST FAILED\n");
+			RIOMapout(Paddr, RIO_MCA_MEM_SIZE, Caddr );
+		}
+		}
+		else
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d - Paddr zero!\n",SlotNumber);
+		}
+	}
+	else
+	{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d NOT RIO\n",SlotNumber);
+	}
+	}
+	/*
+	** Now we have checked all the slots, turn off the MCA slot selector
+	*/
+	outb(McaSlotSelect,0);
+	rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d NOT RIO\n",SlotNumber);
+	return ret;
+}
+
+int RIOEISAinit( int Mode )
+{
+	static int EISADone = 0;
+	uint Paddr;
+	int PollIntMixMsgDone = 0;
+	caddr_t Caddr;
+	ushort Ident;
+	uchar EisaSlot;
+	uchar Ivec;
+	int ret = 0;
+
+	/*
+	** The only valid mode information for EISA hosts is fast or slow
+	** links.
+	*/
+	Mode = (Mode & FAST_LINKS) ? EISA_TP_FAST_LINKS : EISA_TP_SLOW_LINKS;
+
+	if ( EISADone )
+	{
+	rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOEISAinit() - already done, return.\n");
+		return(0);
+	}
+
+	EISADone++;
+
+	rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOEISAinit()\n");
+
+
+	/*
+	** First check all cards to see if ANY are set for polled mode operation.
+	** If so, set ALL to polled.
+	*/
+
+	for ( EisaSlot=1; EisaSlot<=RIO_MAX_EISA_SLOTS; EisaSlot++ )
+	{
+	Ident = (INBZ(EisaSlot,EISA_PRODUCT_IDENT_HI)<<8) |
+		 INBZ(EisaSlot,EISA_PRODUCT_IDENT_LO);
+
+	/* rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT, "Check EISA slot %d, ID=%x\n",EisaSlot,Ident); */
+
+	if ( Ident == RIO_EISA_IDENT )
+	{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Found Specialix product\n");
+
+		if ( INBZ(EisaSlot,EISA_PRODUCT_NUMBER) != RIO_EISA_PRODUCT_CODE )
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Not Specialix RIO - Product number %x\n",
+						INBZ(EisaSlot,EISA_PRODUCT_NUMBER));
+		continue;  /* next slot */
+		}
+		/*
+		** Its a Specialix RIO!
+		*/
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIO Revision %d\n",
+					INBZ(EisaSlot,EISA_REVISION_NUMBER));
+		
+		RIOMachineType |= (1<<RIO_EISA);
+
+		/*
+		** Just check we haven't found too many wonderful objects
+		*/
+		if ( RIONumHosts >= RIO_HOSTS )
+		{
+		Rprintf(RIOMesgTooManyCards);
+		return 0;
+		}
+
+		/*
+		** Ensure that the enable bit is set!
+		*/
+		OUTBZ( EisaSlot, EISA_ENABLE, RIO_EISA_ENABLE_BIT );
+
+		/*
+		** EISA_INTERRUPT_VEC contains the interrupt vector.
+		*/
+		Ivec = INBZ(EisaSlot,EISA_INTERRUPT_VEC);
+
+#ifdef RIODEBUG
+		switch ( Ivec & EISA_INTERRUPT_MASK )
+		{
+		case EISA_IRQ_3:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 3\n");
+		break;
+		case EISA_IRQ_4:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 4\n");
+		break;
+		case EISA_IRQ_5:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 5\n");
+		break;
+		case EISA_IRQ_6:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 6\n");
+		break;
+		case EISA_IRQ_7:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 7\n");
+		break;
+		case EISA_IRQ_9:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 9\n");
+		break;
+		case EISA_IRQ_10:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 10\n");
+		break;
+		case EISA_IRQ_11:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 11\n");
+		break;
+		case EISA_IRQ_12:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 12\n");
+		break;
+		case EISA_IRQ_14:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 14\n");
+		break;
+		case EISA_IRQ_15:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 15\n");
+		break;
+		case EISA_POLLED:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA POLLED\n");
+		break;
+		default:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT|DBG_FAIL,"Shagged interrupt number!\n");
+		Ivec &= EISA_CONTROL_MASK;
+		}
+#endif
+
+		if ( (Ivec & EISA_INTERRUPT_MASK) ==
+		 EISA_POLLED )
+		{
+		RIOWillPoll = 1;
+		break;		/* From EisaSlot loop */
+		}
+	}
+	}
+
+	/*
+	** Do it all again now we know whether to change all cards to polled
+	** mode or not
+	*/
+
+	for ( EisaSlot=1; EisaSlot<=RIO_MAX_EISA_SLOTS; EisaSlot++ )
+	{
+	Ident = (INBZ(EisaSlot,EISA_PRODUCT_IDENT_HI)<<8) |
+		 INBZ(EisaSlot,EISA_PRODUCT_IDENT_LO);
+
+	if ( Ident == RIO_EISA_IDENT )
+	{
+		if ( INBZ(EisaSlot,EISA_PRODUCT_NUMBER) != RIO_EISA_PRODUCT_CODE )
+		continue;  /* next slot */
+
+		/*
+		** Its a Specialix RIO!
+		*/
+		
+		/*
+		** Ensure that the enable bit is set!
+		*/
+		OUTBZ( EisaSlot, EISA_ENABLE, RIO_EISA_ENABLE_BIT );
+
+		/*
+		** EISA_INTERRUPT_VEC contains the interrupt vector.
+		*/
+		Ivec = INBZ(EisaSlot,EISA_INTERRUPT_VEC);
+
+		if ( RIOWillPoll )
+		{
+			/*
+			** If we are going to operate in polled mode, but this
+			** board is configured to be interrupt driven, display
+			** the message explaining the situation to the punter,
+			** assuming we haven't already done so.
+			*/
+
+			if ( !PollIntMixMsgDone &&
+			 (Ivec & EISA_INTERRUPT_MASK) != EISA_POLLED )
+			{
+			Rprintf(RIOMesgAllPolled);
+			PollIntMixMsgDone = 1;
+			}
+
+			/*
+			** Ungraciously ignore whatever the board reports as its
+			** interrupt vector...
+			*/
+
+			Ivec &= ~EISA_INTERRUPT_MASK;
+
+			/*
+			** ...and force it to dance to the poll tune.
+			*/
+
+			Ivec |= EISA_POLLED;
+		}
+
+		/*
+		** Convert the IRQ enable mask into something useful (0-15)
+		*/
+		Ivec = RIOEisaToIvec(Ivec);
+
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT, "EISA host in slot %d has Ivec 0x%x\n",
+		 EisaSlot, Ivec);
+
+		/*
+		** Find the physical address
+		*/
+		Paddr = (INBZ(EisaSlot,EISA_MEMORY_BASE_HI)<<24) |
+				(INBZ(EisaSlot,EISA_MEMORY_BASE_LO)<<16);
+
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"EISA card has Ivec %d Addr %x\n",Ivec,Paddr);
+
+		if ( Paddr == 0 )
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT | DBG_FAIL,
+		 "Board in slot %d configured for address zero!\n", EisaSlot);
+		continue;
+		}
+
+		/*
+		** Tell the memory mapper that we want to talk to it
+		*/
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"About to map EISA card \n");
+
+		if (RIOMapin( Paddr, RIO_EISA_MEM_SIZE, &Caddr) == -1) {
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"Couldn't map %d bytes at %x\n",
+							RIO_EISA_MEM_SIZE,Paddr);
+		continue;
+		}
+
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"Board mapped to vaddr 0x%x\n",Caddr);
+
+		/*
+		** And check that it is actually there!
+		*/
+		if ( RIOBoardTest( Paddr,Caddr,RIO_EISA,EisaSlot) == RIO_SUCCESS )
+			{
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"Board has passed test\n");
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,
+		"Slot %d. Ivec %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n",
+			EisaSlot,Ivec,RIO_EISA,Paddr,Caddr,Mode);
+
+		/*
+		** Board has passed its scrub test. Fill in all the
+		** transient stuff.
+		*/
+		p->RIOHosts[RIONumHosts].Slot	 = EisaSlot;
+		p->RIOHosts[RIONumHosts].Ivec	 = Ivec;
+		p->RIOHosts[RIONumHosts].Type	 = RIO_EISA;
+		p->RIOHosts[RIONumHosts].Copy	 = bcopy;
+				p->RIOHosts[RIONumHosts].PaddrP   = Paddr;
+				p->RIOHosts[RIONumHosts].Caddr	= Caddr;
+		p->RIOHosts[RIONumHosts].CardP	= (struct DpRam *)Caddr;
+				p->RIOHosts[RIONumHosts].Mode	 = Mode;
+		/*
+		** because the EISA prom is mapped into IO space, we
+		** need to copy the unqiue number into the memory area
+		** that it would have occupied, so that the download
+		** code can determine its ID and card type.
+		*/
+	 WBYTE(p->RIOHosts[RIONumHosts].Unique[0],INBZ(EisaSlot,EISA_UNIQUE_NUM_0));
+	 WBYTE(p->RIOHosts[RIONumHosts].Unique[1],INBZ(EisaSlot,EISA_UNIQUE_NUM_1));
+	 WBYTE(p->RIOHosts[RIONumHosts].Unique[2],INBZ(EisaSlot,EISA_UNIQUE_NUM_2));
+	 WBYTE(p->RIOHosts[RIONumHosts].Unique[3],INBZ(EisaSlot,EISA_UNIQUE_NUM_3));
+		p->RIOHosts[RIONumHosts].UniqueNum =
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[0])&0xFF)<<0)|
+						((RBYTE(p->RIOHosts[RIONumHosts].Unique[1])&0xFF)<<8)|
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[2])&0xFF)<<16)|
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[3])&0xFF)<<24);
+		INBZ(EisaSlot,EISA_INTERRUPT_RESET);
+				RIONumHosts++;
+		ret++;
+			}
+		else
+		{
+		/*
+		** It failed the test, so ignore it.
+		*/
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"TEST FAILED\n");
+
+		RIOMapout(Paddr, RIO_EISA_MEM_SIZE, Caddr );
+		}
+	}
+	}
+	if (RIOMachineType & RIO_EISA)
+	return ret+1;
+	return ret;
+}
+#endif
+
+
+#ifndef linux
+
+#define CONFIG_ADDRESS	0xcf8
+#define CONFIG_DATA		0xcfc
+#define FORWARD_REG		0xcfa
+
+
+static int
+read_config(int bus_number, int device_num, int r_number) 
+{
+	unsigned int cav;
+	unsigned int val;
+
+/*
+   Build config_address_value:
+
+      31        24 23        16 15      11 10  8 7        0 
+      ------------------------------------------------------
+      |1| 0000000 | bus_number | device # | 000 | register |
+      ------------------------------------------------------
+*/
+
+	cav = r_number & 0xff;
+	cav |= ((device_num & 0x1f) << 11);
+	cav |= ((bus_number & 0xff) << 16);
+	cav |= 0x80000000; /* Enable bit */
+	outpd(CONFIG_ADDRESS,cav);
+	val = inpd(CONFIG_DATA);
+	outpd(CONFIG_ADDRESS,0);
+	return val;
+}
+
+static
+write_config(bus_number,device_num,r_number,val) 
+{
+	unsigned int cav;
+
+/*
+   Build config_address_value:
+
+      31        24 23        16 15      11 10  8 7        0 
+      ------------------------------------------------------
+      |1| 0000000 | bus_number | device # | 000 | register |
+      ------------------------------------------------------
+*/
+
+	cav = r_number & 0xff;
+	cav |= ((device_num & 0x1f) << 11);
+	cav |= ((bus_number & 0xff) << 16);
+	cav |= 0x80000000; /* Enable bit */
+	outpd(CONFIG_ADDRESS, cav);
+	outpd(CONFIG_DATA, val);
+	outpd(CONFIG_ADDRESS, 0);
+	return val;
+}
+#else
+/* XXX Implement these... */
+static int
+read_config(int bus_number, int device_num, int r_number) 
+{
+  return 0;
+}
+
+static int
+write_config(int bus_number, int device_num, int r_number) 
+{
+  return 0;
+}
+
+#endif
+
+int
+RIOPCIinit(p, Mode)
+struct rio_info	*p;
+int 		Mode;
+{
+	#define MAX_PCI_SLOT		32
+	#define RIO_PCI_JET_CARD	0x200011CB
+
+	static int	slot;	/* count of machine's PCI slots searched so far */
+	caddr_t		Caddr;	/* Virtual address of the current PCI host card. */
+	unsigned char	Ivec;	/* interrupt vector for the current PCI host */
+	unsigned long	Paddr;	/* Physical address for the current PCI host */
+	int		Handle;	/* Handle to Virtual memory allocated for current PCI host */
+
+
+	rio_dprint(RIO_DEBUG_INIT,  ("Search for a RIO PCI card - start at slot %d\n", slot ) );
+
+	/*
+	** Initialise the search status
+	*/
+	p->RIOLastPCISearch	= RIO_FAIL;
+
+	while ( (slot < MAX_PCI_SLOT) & (p->RIOLastPCISearch != RIO_SUCCESS) )
+	{
+		rio_dprint(RIO_DEBUG_INIT,  ("Currently testing slot %d\n", slot ) );
+
+		if (read_config(0,slot,0) == RIO_PCI_JET_CARD) {
+			p->RIOHosts[p->RIONumHosts].Ivec = 0;
+			Paddr = read_config(0,slot,0x18);
+			Paddr = Paddr - (Paddr & 0x1); /* Mask off the io bit */
+
+			if ( (Paddr == 0) || ((Paddr & 0xffff0000) == 0xffff0000) ) {
+				rio_dprint(RIO_DEBUG_INIT,  ("Goofed up slot\n") );	/* what! */
+				slot++;
+				continue;
+			}
+
+			p->RIOHosts[p->RIONumHosts].PaddrP = Paddr;
+			Ivec = (read_config(0,slot,0x3c) & 0xff);
+
+			rio_dprint(RIO_DEBUG_INIT,  ("PCI Host at 0x%x, Intr %d\n", (int)Paddr, Ivec ) );
+
+			Handle = RIOMapin( Paddr, RIO_PCI_MEM_SIZE, &Caddr );
+			if (Handle == -1) {
+				rio_dprint(RIO_DEBUG_INIT,  ("Couldn't map %d bytes at 0x%x\n", RIO_PCI_MEM_SIZE, (int)Paddr ) );
+				slot++;
+				continue;
+			}
+			p->RIOHosts[p->RIONumHosts].Ivec = Ivec + 32;
+			p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec,
+						(int (*)())rio_intr, (char *)p->RIONumHosts);
+			if (RIOBoardTest( Paddr, Caddr, RIO_PCI, 0 ) == RIO_SUCCESS) {
+				rio_dprint(RIO_DEBUG_INIT, ("Board has passed test\n"));
+				rio_dprint(RIO_DEBUG_INIT, ("Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", Paddr, Caddr, 
+																Mode));
+
+				/*
+				** Board has passed its scrub test. Fill in all the
+				** transient stuff.
+				*/
+				p->RIOHosts[p->RIONumHosts].Slot	   = 0;
+				p->RIOHosts[p->RIONumHosts].Ivec	   = Ivec + 32;
+				p->RIOHosts[p->RIONumHosts].Type	   = RIO_PCI;
+				p->RIOHosts[p->RIONumHosts].Copy	   = rio_pcicopy; 
+				p->RIOHosts[p->RIONumHosts].PaddrP	   = Paddr;
+				p->RIOHosts[p->RIONumHosts].Caddr	   = Caddr;
+				p->RIOHosts[p->RIONumHosts].CardP	   = (struct DpRam *)Caddr;
+				p->RIOHosts[p->RIONumHosts].Mode	   = Mode;
+
+#if 0
+				WBYTE(p->RIOHosts[p->RIONumHosts].Control, 
+						BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+						p->RIOHosts[p->RIONumHosts].Mode | 
+						INTERRUPT_DISABLE );
+				WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff);
+				WBYTE(p->RIOHosts[p->RIONumHosts].Control,
+						BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+						p->RIOHosts[p->RIONumHosts].Mode |
+						INTERRUPT_DISABLE );
+				WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff);
+#else
+				WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt, 0xff);
+#endif
+				p->RIOHosts[p->RIONumHosts].UniqueNum  =
+					((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0])&0xFF)<<0)|
+					((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)|
+					((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)|
+					((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24);
+
+				rio_dprint(RIO_DEBUG_INIT,  ("Unique no 0x%x.\n", 
+				    p->RIOHosts[p->RIONumHosts].UniqueNum ) );
+
+				p->RIOLastPCISearch = RIO_SUCCESS;
+				p->RIONumHosts++;
+			}
+		}
+		slot++;
+	}
+
+	if ( slot >= MAX_PCI_SLOT ) {
+		rio_dprint(RIO_DEBUG_INIT,  ("All %d PCI slots have tested for RIO cards !!!\n",
+		    MAX_PCI_SLOT ) );
+	}
+
+
+	/*
+	** I don't think we want to do this anymore
+	**
+
+	if (!p->RIOLastPCISearch == RIO_FAIL ) {
+		p->RIOFailed++;
+	}
+
+	**
+	*/
+}
+
+#ifdef FUTURE_RELEASE
+void riohalt( void )
+{
+	int host;
+	for ( host=0; host<p->RIONumHosts; host++ )
+	{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Stop host %d\n",host);
+		(void)RIOBoardTest( p->RIOHosts[host].PaddrP, p->RIOHosts[host].Caddr, p->RIOHosts[host].Type,p->RIOHosts[host].Slot );
+	}
+}
+#endif
+#endif
+
+static	uchar	val[] = {
+#ifdef VERY_LONG_TEST
+	  0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+	  0xa5, 0xff, 0x5a, 0x00, 0xff, 0xc9, 0x36, 
+#endif
+	  0xff, 0x00, 0x00 };
+
+#define	TEST_END sizeof(val)
+
+/*
+** RAM test a board. 
+** Nothing too complicated, just enough to check it out.
+*/
+int
+RIOBoardTest(paddr, caddr, type, slot)
+paddr_t	paddr;
+caddr_t	caddr;
+uchar	type;
+int		slot;
+{
+	struct DpRam *DpRam = (struct DpRam *)caddr;
+	char *ram[4];
+	int  size[4];
+	int  op, bank;
+	int  nbanks;
+
+	rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Reset host type=%d, DpRam=0x%x, slot=%d\n",
+			type,(int)DpRam,slot));
+
+	RIOHostReset(type, DpRam, slot);
+
+	/*
+	** Scrub the memory. This comes in several banks:
+	** DPsram1	- 7000h bytes
+	** DPsram2	- 200h  bytes
+	** DPsram3	- 7000h bytes
+	** scratch	- 1000h bytes
+	*/
+
+	rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Setup ram/size arrays\n"));
+
+	size[0] = DP_SRAM1_SIZE;
+	size[1] = DP_SRAM2_SIZE;
+	size[2] = DP_SRAM3_SIZE;
+	size[3] = DP_SCRATCH_SIZE;
+
+	ram[0] = (char *)&DpRam->DpSram1[0];
+	ram[1] = (char *)&DpRam->DpSram2[0];
+	ram[2] = (char *)&DpRam->DpSram3[0];
+	nbanks = (type == RIO_PCI) ? 3 : 4;
+	if (nbanks == 4)
+		ram[3] = (char *)&DpRam->DpScratch[0];
+
+
+	if (nbanks == 3) {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Memory: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n",
+				(int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2]));
+	} else {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n",
+			(int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2], (int)ram[3], 
+					size[3]));
+	}
+
+	/*
+	** This scrub operation will test for crosstalk between
+	** banks. TEST_END is a magic number, and relates to the offset
+	** within the 'val' array used by Scrub.
+	*/
+	for (op=0; op<TEST_END; op++) {
+		for (bank=0; bank<nbanks; bank++) {
+			if (RIOScrub(op, (BYTE *)ram[bank], size[bank]) == RIO_FAIL) {
+				rio_dprint(RIO_DEBUG_INIT, ("RIO-init: RIOScrub band %d, op %d failed\n", 
+							bank, op));
+				return RIO_FAIL;
+			}
+		}
+	}
+
+	rio_dprint(RIO_DEBUG_INIT, ("Test completed\n"));
+	return RIO_SUCCESS;
+}
+
+
+/*
+** Scrub an area of RAM.
+** Define PRETEST and POSTTEST for a more thorough checking of the
+** state of the memory.
+** Call with op set to an index into the above 'val' array to determine
+** which value will be written into memory.
+** Call with op set to zero means that the RAM will not be read and checked
+** before it is written.
+** Call with op not zero, and the RAM will be read and compated with val[op-1]
+** to check that the data from the previous phase was retained.
+*/
+int
+RIOScrub(op, ram, size)
+int		op;
+BYTE *	ram;
+int		size; 
+{
+	int				off;
+	unsigned char	oldbyte;
+	unsigned char	newbyte;
+	unsigned char	invbyte;
+	unsigned short	oldword;
+	unsigned short	newword;
+	unsigned short	invword;
+	unsigned short	swapword;
+
+	if (op) {
+		oldbyte = val[op-1];
+		oldword = oldbyte | (oldbyte<<8);
+	} else
+	  oldbyte = oldword = 0; /* Tell the compiler we've initilalized them. */
+	newbyte = val[op];
+	newword = newbyte | (newbyte<<8);
+	invbyte = ~newbyte;
+	invword = invbyte | (invbyte<<8);
+
+	/*
+	** Check that the RAM contains the value that should have been left there
+	** by the previous test (not applicable for pass zero)
+	*/
+	if (op) {
+		for (off=0; off<size; off++) {
+			if (RBYTE(ram[off]) != oldbyte) {
+				rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Pre Check 1: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, RBYTE(ram[off])));
+				return RIO_FAIL;
+			}
+		}
+		for (off=0; off<size; off+=2) {
+			if (*(ushort *)&ram[off] != oldword) {
+				rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Pre Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,oldword,*(ushort *)&ram[off]));
+				rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Pre Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+				return RIO_FAIL;
+			}
+		}
+	}
+
+	/*
+	** Now write the INVERSE of the test data into every location, using
+	** BYTE write operations, first checking before each byte is written
+	** that the location contains the old value still, and checking after
+	** the write that the location contains the data specified - this is
+	** the BYTE read/write test.
+	*/
+	for (off=0; off<size; off++) {
+		if (op && (RBYTE(ram[off]) != oldbyte)) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Pre Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off,oldbyte,RBYTE(ram[off])));
+			return RIO_FAIL;
+		}
+		WBYTE(ram[off],invbyte);
+		if (RBYTE(ram[off]) != invbyte) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Inv Check: BYTE at offset 0x%x should have been=%x, was=%x\n",off,invbyte,RBYTE(ram[off])));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** now, use WORD operations to write the test value into every location,
+	** check as before that the location contains the previous test value
+	** before overwriting, and that it contains the data value written
+	** afterwards.
+	** This is the WORD operation test.
+	*/
+	for (off=0; off<size; off+=2) {
+		if (*(ushort *)&ram[off] != invword) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Inv Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,invword,*(ushort *)&ram[off]));
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Inv Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+
+		*(ushort *)&ram[off] = newword;
+		if ( *(ushort *)&ram[off] != newword ) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 1: WORD at offset 0x%x should have been=%x, was=%x\n",off,newword,*(ushort *)&ram[off]));
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** now run through the block of memory again, first in byte mode
+	** then in word mode, and check that all the locations contain the
+	** required test data.
+	*/
+	for (off=0; off<size; off++) {
+		if (RBYTE(ram[off]) != newbyte) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Byte Check: BYTE at offset 0x%x should have been=%x, was=%x\n",off,newbyte,RBYTE(ram[off])));
+			return RIO_FAIL;
+		}
+	}
+
+	for (off=0; off<size; off+=2) {
+		if ( *(ushort *)&ram[off] != newword ) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 2: WORD at offset 0x%x should have been=%x, was=%x\n",off,newword,*(ushort *)&ram[off]));
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 2: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** time to check out byte swapping errors
+	*/
+	swapword = invbyte | (newbyte << 8);
+
+	for (off=0; off<size; off+=2) {
+		WBYTE(ram[off],invbyte);
+		WBYTE(ram[off+1],newbyte);
+	}
+
+	for ( off=0; off<size; off+=2 ) {
+		if (*(ushort *)&ram[off] != swapword) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 1: WORD at offset 0x%x should have been=%x, was=%x\n",off,swapword,*((ushort *)&ram[off])));
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+		*((ushort *)&ram[off]) = ~swapword;
+	}
+
+	for (off=0; off<size; off+=2) {
+		if (RBYTE(ram[off]) != newbyte) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off,newbyte,RBYTE(ram[off])));
+			return RIO_FAIL;
+		}
+		if (RBYTE(ram[off+1]) != invbyte) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off+1,invbyte,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+		*((ushort *)&ram[off]) = newword;
+	}
+	return RIO_SUCCESS;
+}
+
+/*
+** try to ensure that every host is either in polled mode
+** or is in interrupt mode. Only allow interrupt mode if
+** all hosts can interrupt (why?)
+** and force into polled mode if told to. Patch up the
+** interrupt vector & salute The Queen when you've done.
+*/
+void
+RIOAllocateInterrupts(p)
+struct rio_info *	p;
+{
+	int Host;
+
+	/*
+	** Easy case - if we have been told to poll, then we poll.
+	*/
+	if (p->mode & POLLED_MODE) {
+		RIOStopInterrupts(p, 0, 0);
+		return;
+	}
+
+	/*
+	** check - if any host has been set to polled mode, then all must be.
+	*/
+	for (Host=0; Host<p->RIONumHosts; Host++) {
+		if ( (p->RIOHosts[Host].Type != RIO_AT) &&
+				(p->RIOHosts[Host].Ivec == POLLED) ) {
+			RIOStopInterrupts(p, 1, Host );
+			return;
+		}
+	}
+	for (Host=0; Host<p->RIONumHosts; Host++) {
+		if (p->RIOHosts[Host].Type == RIO_AT) {
+			if ( (p->RIOHosts[Host].Ivec - 32) == 0) {
+				RIOStopInterrupts(p, 2, Host );
+				return;
+			}
+		}
+	}
+}
+
+/*
+** something has decided that we can't be doing with these
+** new-fangled interrupt thingies. Set everything up to just
+** poll.
+*/
+void
+RIOStopInterrupts(p, Reason, Host)
+struct rio_info *	p;
+int	Reason;
+int	Host; 
+{
+#ifdef FUTURE_RELEASE
+	switch (Reason) {
+		case 0:	/* forced into polling by rio_polled */
+			break;
+		case 1:	/* SCU has set 'Host' into polled mode */
+			break;
+		case 2:	/* there aren't enough interrupt vectors for 'Host' */
+			break;
+	}
+#endif
+
+	for (Host=0; Host<p->RIONumHosts; Host++ ) {
+		struct Host *HostP = &p->RIOHosts[Host];
+
+		switch (HostP->Type) {
+			case RIO_AT:
+				/*
+				** The AT host has it's interrupts disabled by clearing the
+				** int_enable bit.
+				*/
+				HostP->Mode &= ~INTERRUPT_ENABLE;
+				HostP->Ivec = POLLED;
+				break;
+#ifdef FUTURE_RELEASE
+			case RIO_EISA:
+				/*
+				** The EISA host has it's interrupts disabled by setting the
+				** Ivec to zero
+				*/
+				HostP->Ivec = POLLED;
+				break;
+#endif
+			case RIO_PCI:
+				/*
+				** The PCI host has it's interrupts disabled by clearing the
+				** int_enable bit, like a regular host card.
+				*/
+				HostP->Mode &= ~RIO_PCI_INT_ENABLE;
+				HostP->Ivec = POLLED;
+				break;
+#ifdef FUTURE_RELEASE
+			case RIO_MCA:
+				/*
+				** There's always one, isn't there?
+				** The MCA host card cannot have it's interrupts disabled.
+				*/
+				RIOPatchVec(HostP);
+				break;
+#endif
+		}
+	}
+}
+
+#if 0
+/*
+** This function is called at init time to setup the data structures.
+*/
+void
+RIOAllocDataStructs(p)
+struct rio_info *	p;
+{
+	int	port,
+		host,
+		tm;
+
+	p->RIOPortp = (struct Port *)sysbrk(RIO_PORTS * sizeof(struct Port));
+	if (!p->RIOPortp) {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: No memory for port structures\n"));
+		p->RIOFailed++;
+		return;
+	} 
+	bzero( p->RIOPortp, sizeof(struct Port) * RIO_PORTS );
+	rio_dprint(RIO_DEBUG_INIT,  ("RIO-init: allocated and cleared memory for port structs\n") );
+	rio_dprint(RIO_DEBUG_INIT,  ("First RIO port struct @0x%x, size=0x%x bytes\n",
+	    (int)p->RIOPortp, sizeof(struct Port) ) );
+
+	for( port=0; port<RIO_PORTS; port++ ) {
+		p->RIOPortp[port].PortNum = port;
+		p->RIOPortp[port].TtyP = &p->channel[port];
+		sreset (p->RIOPortp[port].InUse);	/* Let the first guy uses it */
+		p->RIOPortp[port].portSem = -1;	/* Let the first guy takes it */
+		p->RIOPortp[port].ParamSem = -1;	/* Let the first guy takes it */
+		p->RIOPortp[port].timeout_id = 0;	/* Let the first guy takes it */
+	}
+
+	p->RIOHosts = (struct Host *)sysbrk(RIO_HOSTS * sizeof(struct Host));
+	if (!p->RIOHosts) {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: No memory for host structures\n"));
+		p->RIOFailed++;
+		return;
+	}
+	bzero(p->RIOHosts, sizeof(struct Host)*RIO_HOSTS);
+	rio_dprint(RIO_DEBUG_INIT,  ("RIO-init: allocated and cleared memory for host structs\n"));
+	rio_dprint(RIO_DEBUG_INIT,  ("First RIO host struct @0x%x, size=0x%x bytes\n",
+	    (int)p->RIOHosts, sizeof(struct Host) ) );
+
+	for( host=0; host<RIO_HOSTS; host++ ) {
+		p->RIOHosts[host].HostLock = -1; /* Let the first guy takes it */
+		p->RIOHosts[host].timeout_id = 0; /* Let the first guy takes it */
+	}
+	/*
+	** check that the buffer size is valid, round down to the next power of
+	** two if necessary; if the result is zero, then, hey, no double buffers.
+	*/
+	for ( tm = 1; tm && tm <= p->RIOConf.BufferSize; tm <<= 1 )
+		;
+	tm >>= 1;
+	p->RIOBufferSize = tm;
+	p->RIOBufferMask = tm ? tm - 1 : 0;
+}
+
+/*
+** this function gets called whenever the data structures need to be
+** re-setup, for example, after a riohalt (why did I ever invent it?)
+*/
+void
+RIOSetupDataStructs(p)
+struct rio_info	* p;
+{
+	int host, entry, rup;
+
+	for ( host=0; host<RIO_HOSTS; host++ ) {
+		struct Host *HostP = &p->RIOHosts[host];
+		for ( entry=0; entry<LINKS_PER_UNIT; entry++ ) {
+			HostP->Topology[entry].Unit = ROUTE_DISCONNECT;
+			HostP->Topology[entry].Link = NO_LINK;
+		}
+		bcopy("HOST X", HostP->Name, 7);
+		HostP->Name[5] = '1'+host;
+		for (rup=0; rup<(MAX_RUP + LINKS_PER_UNIT); rup++) {
+			if (rup < MAX_RUP) {
+				for (entry=0; entry<LINKS_PER_UNIT; entry++ ) {
+					HostP->Mapping[rup].Topology[entry].Unit = ROUTE_DISCONNECT;
+					HostP->Mapping[rup].Topology[entry].Link = NO_LINK;
+				}
+				RIODefaultName(p, HostP, rup);
+			}
+			HostP->UnixRups[rup].RupLock = -1;
+		}
+	}
+}
+#endif
+
+int
+RIODefaultName(p, HostP, UnitId)
+struct rio_info *	p;
+struct Host *	HostP;
+uint			UnitId;
+{
+#ifdef CHECK
+	CheckHost( Host );
+	CheckUnitId( UnitId );
+#endif
+	bcopy("UNKNOWN RTA X-XX",HostP->Mapping[UnitId].Name,17);
+	HostP->Mapping[UnitId].Name[12]='1'+(HostP-p->RIOHosts);
+	if ((UnitId+1) > 9) {
+		HostP->Mapping[UnitId].Name[14]='0'+((UnitId+1)/10);
+		HostP->Mapping[UnitId].Name[15]='0'+((UnitId+1)%10);
+	}
+	else {
+		HostP->Mapping[UnitId].Name[14]='1'+UnitId;
+		HostP->Mapping[UnitId].Name[15]=0;
+	}
+	return 0;
+}
+
+#define RIO_RELEASE	"Linux"
+#define RELEASE_ID	"1.0"
+
+int
+RIOReport(p)
+struct rio_info *	p;
+{
+	char *	RIORelease = RIO_RELEASE;
+	char *	RIORelID = RELEASE_ID;
+	int		host;
+
+	rio_dprint(RIO_DEBUG_INIT, ("RIO : Release: %s ID: %s\n", RIORelease, RIORelID));
+
+	if ( p->RIONumHosts==0 ) {
+		rio_dprint(RIO_DEBUG_INIT, ("\nNo Hosts configured\n"));
+		return(0);
+	}
+
+	for ( host=0; host < p->RIONumHosts; host++ ) {
+		struct Host *HostP = &p->RIOHosts[host];
+		switch ( HostP->Type ) {
+			case RIO_AT:
+				rio_dprint(RIO_DEBUG_INIT, ("AT BUS : found the card at 0x%x\n", HostP->PaddrP));
+		}
+	}
+	return 0;
+}
+
+/*
+** This function returns release/version information as used by ioctl() calls
+** It returns a MAX_VERSION_LEN byte string, null terminated.
+*/
+char *
+OLD_RIOVersid( void )
+{
+	static char	Info[MAX_VERSION_LEN];
+	char *	RIORelease = RIO_RELEASE;
+	char *	cp;
+	int		ct = 0;
+
+	for ( ct=0; RIORelease[ct] && ct<MAX_VERSION_LEN; ct++ )
+		Info[ct] = RIORelease[ct];
+	if ( ct>=MAX_VERSION_LEN ) {
+		Info[MAX_VERSION_LEN-1] = '\0';
+		return Info;
+	}
+	Info[ct++]=' ';
+	if ( ct>=MAX_VERSION_LEN ) {
+		Info[MAX_VERSION_LEN-1] = '\0';
+		return Info;
+	}
+
+	cp="";	/* Fill the RCS Id here */
+
+	while ( *cp && ct<MAX_VERSION_LEN )
+		Info[ct++] = *cp++;
+	if ( ct<MAX_VERSION_LEN-1 )
+		Info[ct] = '\0';
+	Info[MAX_VERSION_LEN-1] = '\0';
+	return Info;
+}
+
+
+static struct rioVersion	stVersion;
+
+struct rioVersion *
+RIOVersid(void)
+{
+    strncpy(stVersion.version, "RIO driver for linux V1.0", 255);
+    strncpy(stVersion.buildDate, __DATE__, 255);
+
+    return &stVersion;
+}
+
+#if 0
+int
+RIOMapin(paddr, size, vaddr)
+paddr_t		paddr;
+int			size;
+caddr_t *	vaddr;
+{
+	*vaddr = (caddr_t)permap( (long)paddr, size);
+	return ((int)*vaddr);
+}
+
+void
+RIOMapout(paddr, size, vaddr)
+paddr_t		paddr;
+long		size;
+caddr_t 	vaddr;
+{
+}
+#endif
+
+
+void
+RIOHostReset(Type, DpRamP, Slot)
+uint Type;
+volatile struct DpRam *DpRamP;
+uint Slot; 
+{
+	/*
+	** Reset the Tpu
+	*/
+	rio_dprint(RIO_DEBUG_INIT,  ("RIOHostReset: type 0x%x", Type ) );
+	switch ( Type ) {
+		case RIO_AT:
+			rio_dprint(RIO_DEBUG_INIT, (" (RIO_AT)\n"));
+			WBYTE(DpRamP->DpControl,  BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+					  INTERRUPT_DISABLE | BYTE_OPERATION |
+					  SLOW_LINKS | SLOW_AT_BUS);
+			WBYTE(DpRamP->DpResetTpu, 0xFF);
+			rio_udelay (3);
+
+			rio_dprint(RIO_DEBUG_INIT,  ("RIOHostReset: Don't know if it worked. Try reset again\n") );
+			WBYTE(DpRamP->DpControl,  BOOT_FROM_RAM | EXTERNAL_BUS_OFF |
+					  INTERRUPT_DISABLE | BYTE_OPERATION |
+					  SLOW_LINKS | SLOW_AT_BUS);
+			WBYTE(DpRamP->DpResetTpu, 0xFF);
+			rio_udelay (3);
+			break;
+#ifdef FUTURE_RELEASE
+	case RIO_EISA:
+	/*
+	** Bet this doesn't work!
+	*/
+	OUTBZ( Slot, EISA_CONTROL_PORT,
+		EISA_TP_RUN		| EISA_TP_BUS_DISABLE   |
+		EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM );
+	OUTBZ( Slot, EISA_CONTROL_PORT,
+		EISA_TP_RESET	  | EISA_TP_BUS_DISABLE   | 
+		EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM );
+	suspend( 3 );
+	OUTBZ( Slot, EISA_CONTROL_PORT,
+		EISA_TP_RUN		| EISA_TP_BUS_DISABLE   | 
+		EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM );
+	break;
+	case RIO_MCA:
+	WBYTE(DpRamP->DpControl  , McaTpBootFromRam | McaTpBusDisable );
+	WBYTE(DpRamP->DpResetTpu , 0xFF );
+	suspend( 3 );
+	WBYTE(DpRamP->DpControl  , McaTpBootFromRam | McaTpBusDisable );
+	WBYTE(DpRamP->DpResetTpu , 0xFF );
+	suspend( 3 );
+		break;
+#endif
+	case RIO_PCI:
+		rio_dprint(RIO_DEBUG_INIT,  (" (RIO_PCI)\n") );
+		DpRamP->DpControl  = RIO_PCI_BOOT_FROM_RAM;
+		DpRamP->DpResetInt = 0xFF;
+		DpRamP->DpResetTpu = 0xFF;
+		rio_udelay (100);
+		/* for (i=0; i<6000; i++);  */
+		/* suspend( 3 ); */
+		break;
+#ifdef FUTURE_RELEASE
+	default:
+	Rprintf(RIOMesgNoSupport,Type,DpRamP,Slot);
+	return;
+#endif
+
+	default:
+		rio_dprint(RIO_DEBUG_INIT,  (" (UNKNOWN)\n") );
+		break;
+	}
+	return;
+}
diff -urN linux-2.2.15-pre2/drivers/char/rio/riointr.c linux/drivers/char/rio/riointr.c
--- linux-2.2.15-pre2/drivers/char/rio/riointr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riointr.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1111 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riointr.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:44
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)riointr.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riointr_c_sccs_ = "@(#)riointr.c	1.2";
+#endif
+
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+#include <linux/delay.h>
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+/*
+** riopoll is called every clock tick. Once the /dev/rio device has been
+** opened, and polldistributed( ) has been called, this routine is called
+** every clock tick *by every cpu*. The 'interesting' piece of code that
+** manipulates 'RIONumCpus' and 'RIOCpuCountdown' is used to fair-share
+** the work between the CPUs. If there are 'N' cpus, then each poll time
+** we increment a counter, modulo 'N-1'. When this counter is 0, we call
+** the interrupt handler. This has the effect that polls are serviced
+** by processor 'N', 'N-1', 'N-2', ... '0', round and round. Neat.
+*/
+void
+riopoll(p)
+struct rio_info *	p;
+{
+	int   host;
+
+	/*
+	** Here's the deal. We try to fair share as much as possible amongst
+	** all the processors that are available. Since each processor 
+	** should generate HZ ticks per second and since we only need HZ ticks
+	** in total for proper operation we simply attempt to cycle round each
+	** processor in turn, using RIOCpuCountdown to decide whether to call
+	** the interrupt routine. ( In fact the count zeroes when it reaches
+	** one less than the total number of processors - so e.g. on a two
+	** processor system RIOService will get called 2*HZ times per second. )
+	** this_cpu (cur_cpu()) tells us the number of the current processor
+	** as follows:
+	**
+	**		0 - default CPU
+	**		1 - first extra CPU
+	**		2 - second extra CPU
+	**		etc.
+	*/
+
+	/*
+	** okay, we've got a cpu that hasn't had a go recently 
+	** - lets check to see what needs doing.
+	*/
+	for ( host=0; host<p->RIONumHosts; host++ ) {
+		struct Host *HostP = &p->RIOHosts[host];
+
+		rio_spin_lock( &HostP->HostLock );
+
+		if ( ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) ||
+		     HostP->InIntr ) {
+			rio_spin_unlock (&HostP->HostLock); 
+			continue;
+		}
+
+		if ( RWORD( HostP->ParmMapP->rup_intr ) ||
+			 RWORD( HostP->ParmMapP->rx_intr  ) ||
+			 RWORD( HostP->ParmMapP->tx_intr  ) ) {
+			HostP->InIntr = 1;
+
+#ifdef FUTURE_RELEASE
+			if( HostP->Type == RIO_EISA )
+				INBZ( HostP->Slot, EISA_INTERRUPT_RESET );
+			else
+#endif
+				WBYTE( HostP->ResetInt , 0xff );
+
+			rio_spin_lock(&HostP->HostLock); 
+
+			p->_RIO_Polled++;
+			RIOServiceHost(p, HostP, 'p' );
+			rio_spin_lock( &HostP->HostLock); 
+			HostP->InIntr = 0;
+			rio_spin_unlock (&HostP->HostLock);
+		}
+	}
+	rio_spin_unlock (&p->RIOIntrSem); 
+}
+
+
+char *firstchars (char *p, int nch)
+{
+  static char buf[2][128];
+  static int t=0;
+  t = ! t;
+  memcpy (buf[t], p, nch);
+  buf[t][nch] = 0;
+  return buf[t];
+}
+
+
+#define	INCR( P, I )	((P) = (((P)+(I)) & p->RIOBufferMask))
+/* Enable and start the transmission of packets */
+void
+RIOTxEnable(en)
+char *		en;
+{
+  struct Port *	PortP;
+  struct rio_info *p;
+  struct tty_struct* tty;
+  int c;
+  struct PKT *	PacketP;
+  unsigned long flags;
+
+  PortP = (struct Port *)en; 
+  p = (struct rio_info *)PortP->p;
+  tty = PortP->gs.tty;
+
+
+  rio_dprint (RIO_DEBUG_INTR, ("tx port %d: %d chars queued.\n", 
+	      PortP->PortNum, PortP->gs.xmit_cnt));
+
+  if (!PortP->gs.xmit_cnt) return;
+  
+
+  /* This routine is an order of magnitude simpler than the specialix
+     version. One of the disadvantages is that this version will send
+     an incomplete packet (usually 64 bytes instead of 72) once for
+     every 4k worth of data. Let's just say that this won't influence
+     performance significantly..... */
+
+  rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+  while (can_add_transmit( &PacketP, PortP )) {
+    c = PortP->gs.xmit_cnt;
+    if (c > PKT_MAX_DATA_LEN) c = PKT_MAX_DATA_LEN;
+
+    /* Don't copy past the end of the source buffer */
+    if (c > SERIAL_XMIT_SIZE - PortP->gs.xmit_tail) 
+      c = SERIAL_XMIT_SIZE - PortP->gs.xmit_tail;
+
+    { int t;
+    t = (c > 10)?10:c;
+    
+    rio_dprint (RIO_DEBUG_INTR, ("tx port %d: copying %d chars: %s - %s\n", 
+				 PortP->PortNum, c, 
+	 firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail      , t),
+	 firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail + c-t, t)));
+    }
+    /* If for one reason or another, we can't copy more data, 
+       we're done! */
+    if (c == 0) break;
+
+    memcpy_toio ((caddr_t)PacketP->data, 
+		 PortP->gs.xmit_buf + PortP->gs.xmit_tail, c);
+    /*    udelay (1); */
+
+    PacketP->len = c;
+    if (!( PortP->State & RIO_DELETED ) ) {
+      add_transmit ( PortP );
+      /*
+      ** Count chars tx'd for port statistics reporting
+      */
+      if ( PortP->statsGather )
+	PortP->txchars += c;
+    }
+    PortP->gs.xmit_tail = (PortP->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1);
+    PortP->gs.xmit_cnt -= c;
+  }
+
+  rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+  if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2*PKT_MAX_DATA_LEN)) {
+    rio_dprint (RIO_DEBUG_INTR, ("Waking up.... ldisc:%d (%d/%d)....",
+		 (int)(PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)),
+		 PortP->gs.wakeup_chars, PortP->gs.xmit_cnt)); 
+    if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	PortP->gs.tty->ldisc.write_wakeup)
+      (PortP->gs.tty->ldisc.write_wakeup)(PortP->gs.tty);
+    rio_dprint (RIO_DEBUG_INTR, ("(%d/%d)\n",
+		PortP->gs.wakeup_chars, PortP->gs.xmit_cnt)); 
+    wake_up_interruptible(&PortP->gs.tty->write_wait);
+  }
+
+}
+
+
+/*
+** When a real-life interrupt comes in here, we try to find out
+** which host card it belongs to, and then service only that host
+** Notice the cunning way that, once we've found a candidate, we
+** continue just in case we are sharing interrupts.
+*/
+void
+riointr(p)
+struct rio_info *	p;
+{
+	int host;
+
+	for ( host=0; host<p->RIONumHosts; host++ ) {
+		struct Host *HostP = &p->RIOHosts[host];
+
+		rio_dprint(RIO_DEBUG_INTR,  ("riointr() doing host %d type %d\n", host, HostP->Type ) );
+
+		switch( HostP->Type ) {
+			case RIO_AT:
+			case RIO_MCA:
+			case RIO_PCI:
+			  	rio_spin_lock(&HostP->HostLock);
+				WBYTE(HostP->ResetInt , 0xff);
+				if ( !HostP->InIntr ) {
+					HostP->InIntr = 1;
+					rio_spin_unlock (&HostP->HostLock);
+					p->_RIO_Interrupted++;
+					RIOServiceHost(p, HostP, 'i');
+					rio_spin_lock(&HostP->HostLock);
+					HostP->InIntr = 0;
+				}
+				rio_spin_unlock(&HostP->HostLock); 
+				break;
+#ifdef FUTURE_RELEASE
+		case RIO_EISA:
+			if ( ivec == HostP->Ivec )
+			{
+				OldSpl = LOCKB( &HostP->HostLock );
+				INBZ( HostP->Slot, EISA_INTERRUPT_RESET );
+				if ( !HostP->InIntr )
+				{
+					HostP->InIntr = 1;
+					UNLOCKB( &HostP->HostLock, OldSpl );
+					if ( this_cpu < RIO_CPU_LIMIT )
+					{
+						int intrSpl = LOCKB( &RIOIntrLock );
+						UNLOCKB( &RIOIntrLock, intrSpl );
+					}
+						p->_RIO_Interrupted++;
+					RIOServiceHost( HostP, 'i' );
+					OldSpl = LOCKB( &HostP->HostLock );
+					HostP->InIntr = 0;
+				}
+				UNLOCKB( &HostP->HostLock, OldSpl );
+				done++;
+			}
+			break;
+#endif
+		}
+
+		HostP->IntSrvDone++;
+	}
+
+#ifdef FUTURE_RELEASE
+	if ( !done )
+	{
+		cmn_err( CE_WARN, "RIO: Interrupt received with vector 0x%x\n", ivec );
+		cmn_err( CE_CONT, "	 Valid vectors are:\n");
+		for ( host=0; host<RIONumHosts; host++ )
+		{
+			switch( RIOHosts[host].Type )
+			{
+				case RIO_AT:
+				case RIO_MCA:
+				case RIO_EISA:
+						cmn_err( CE_CONT, "0x%x ", RIOHosts[host].Ivec );
+						break;
+				case RIO_PCI:
+						cmn_err( CE_CONT, "0x%x ", get_intr_arg( RIOHosts[host].PciDevInfo.busnum, IDIST_PCI_IRQ( RIOHosts[host].PciDevInfo.slotnum, RIOHosts[host].PciDevInfo.funcnum ) ));
+						break;
+			}
+		}
+		cmn_err( CE_CONT, "\n" );
+	}
+#endif
+}
+
+/*
+** RIO Host Service routine. Does all the work traditionally associated with an
+** interrupt.
+*/
+static int	RupIntr;
+static int	RxIntr;
+static int	TxIntr;
+void
+RIOServiceHost(p, HostP, From)
+struct rio_info *	p;
+struct Host *HostP;
+int From; 
+{
+  rio_spin_lock (&HostP->HostLock);
+  if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) { 
+    static int t =0;
+    rio_spin_unlock (&HostP->HostLock); 
+    if ((t++ % 200) == 0)
+      rio_dprint(RIO_DEBUG_INTR, ("Interrupt but host not running. flags=%x.\n", (int)HostP->Flags));
+    return;
+  }
+  rio_spin_unlock (&HostP->HostLock); 
+
+  if ( RWORD( HostP->ParmMapP->rup_intr ) ) {
+    WWORD( HostP->ParmMapP->rup_intr , 0 );
+    p->RIORupCount++;
+    RupIntr++;
+    rio_dprint(RIO_DEBUG_INTR, ("RUP interrupt on host %d\n", HostP-p->RIOHosts ));
+    RIOPollHostCommands(p, HostP );
+  }
+
+  if ( RWORD( HostP->ParmMapP->rx_intr ) ) {
+    int port;
+
+    WWORD( HostP->ParmMapP->rx_intr , 0 );
+    p->RIORxCount++;
+    RxIntr++;
+
+    rio_dprint(RIO_DEBUG_INTR, ("RX interrupt on host %d\n", HostP-p->RIOHosts));
+    /*
+    ** Loop through every port. If the port is mapped into
+    ** the system ( i.e. has /dev/ttyXXXX associated ) then it is
+    ** worth checking. If the port isn't open, grab any packets
+    ** hanging on its receive queue and stuff them on the free
+    ** list; check for commands on the way.
+    */
+    for ( port=p->RIOFirstPortsBooted; 
+	  port<p->RIOLastPortsBooted+PORTS_PER_RTA; port++ ) {
+      struct Port *PortP = p->RIOPortp[port];
+      struct tty_struct *ttyP;
+      struct PKT *PacketP;
+		
+      /*
+      ** not mapped in - most of the RIOPortp[] information
+      ** has not been set up!
+      ** Optimise: ports come in bundles of eight.
+      */
+      if ( !PortP->Mapped ) {
+	port += 7;
+	continue; /* with the next port */
+      }
+
+      /*
+      ** If the host board isn't THIS host board, check the next one.
+      ** optimise: ports come in bundles of eight.
+      */
+      if ( PortP->HostP != HostP ) {
+	port += 7;
+	continue;
+      }
+
+      /*
+      ** Let us see - is the port open? If not, then don't service it.
+      */
+      if ( !( PortP->PortState & PORT_ISOPEN ) ) {
+	continue;
+      }
+
+      /*
+      ** find corresponding tty structure. The process of mapping
+      ** the ports puts these here.
+      */
+      ttyP = PortP->gs.tty;
+
+      /*
+      ** Lock the port before we begin working on it.
+      */
+      rio_spin_lock(&PortP->portSem);
+
+      /*
+      ** Process received data if there is any.
+      */
+      if ( can_remove_receive( &PacketP, PortP ) )
+	RIOReceive(p, PortP);
+
+      /*
+      ** If there is no data left to be read from the port, and
+      ** it's handshake bit is set, then we must clear the handshake,
+      ** so that that downstream RTA is re-enabled.
+      */
+      if ( !can_remove_receive( &PacketP, PortP ) && 
+	   ( RWORD( PortP->PhbP->handshake )==PHB_HANDSHAKE_SET ) ) {
+				/*
+				** MAGIC! ( Basically, handshake the RX buffer, so that
+				** the RTAs upstream can be re-enabled. )
+				*/
+	rio_dprint(RIO_DEBUG_INTR, ("Set RX handshake bit\n" ));
+	WWORD( PortP->PhbP->handshake, 
+	       PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET );
+      }
+      rio_spin_unlock(&PortP->portSem);
+    }
+  }
+
+  if ( RWORD( HostP->ParmMapP->tx_intr ) ) {
+    int port;
+
+    WWORD( HostP->ParmMapP->tx_intr , 0);
+
+    p->RIOTxCount++;
+    TxIntr++;
+    rio_dprint(RIO_DEBUG_INTR, ("TX interrupt on host %d\n", HostP-p->RIOHosts));
+
+    /*
+    ** Loop through every port.
+    ** If the port is mapped into the system ( i.e. has /dev/ttyXXXX
+    ** associated ) then it is worth checking.
+    */
+    for ( port=p->RIOFirstPortsBooted; 
+	  port<p->RIOLastPortsBooted+PORTS_PER_RTA; port++ ) {
+      struct Port *PortP = p->RIOPortp[port];
+      struct tty_struct *ttyP;
+      struct PKT *PacketP;
+
+      /*
+      ** not mapped in - most of the RIOPortp[] information
+      ** has not been set up!
+      */
+      if ( !PortP->Mapped ) {
+	port += 7;
+	continue; /* with the next port */
+      }
+
+      /*
+      ** If the host board isn't running, then its data structures
+      ** are no use to us - continue quietly.
+      */
+      if ( PortP->HostP != HostP ) {
+	port += 7;
+	continue; /* with the next port */
+      }
+
+      /*
+      ** Let us see - is the port open? If not, then don't service it.
+      */
+      if ( !( PortP->PortState & PORT_ISOPEN ) ) {
+	continue;
+      }
+
+      rio_dprint (RIO_DEBUG_INTR, ("Looking into port %d.\n", port));
+      /*
+      ** Lock the port before we begin working on it.
+      */
+      rio_spin_lock(&PortP->portSem);
+
+      /*
+      ** If we can't add anything to the transmit queue, then
+      ** we need do none of this processing.
+      */
+      if ( !can_add_transmit( &PacketP, PortP ) ) {
+	rio_dprint (RIO_DEBUG_INTR, ("Can't add to port, so skipping.\n"));
+	rio_spin_unlock(&PortP->portSem);
+	continue;
+      }
+
+      /*
+      ** find corresponding tty structure. The process of mapping
+      ** the ports puts these here.
+      */
+      ttyP = PortP->gs.tty;
+      /* If ttyP is NULL, the port is getting closed. Forget about it. */
+      if (!ttyP) {
+	rio_dprint (RIO_DEBUG_INTR, ("no tty, so skipping.\n"));
+	rio_spin_unlock(&PortP->portSem);
+	continue;
+      }
+      /*
+      ** If there is more room available we start up the transmit
+      ** data process again. This can be direct I/O, if the cookmode
+      ** is set to COOK_RAW or COOK_MEDIUM, or will be a call to the
+      ** riotproc( T_OUTPUT ) if we are in COOK_WELL mode, to fetch
+      ** characters via the line discipline. We must always call
+      ** the line discipline,
+      ** so that user input characters can be echoed correctly.
+      **
+      ** ++++ Update +++++
+      ** With the advent of double buffering, we now see if
+      ** TxBufferOut-In is non-zero. If so, then we copy a packet
+      ** to the output place, and set it going. If this empties
+      ** the buffer, then we must issue a wakeup( ) on OUT.
+      ** If it frees space in the buffer then we must issue
+      ** a wakeup( ) on IN.
+      **
+      ** ++++ Extra! Extra! If PortP->WflushFlag is set, then we
+      ** have to send a WFLUSH command down the PHB, to mark the
+      ** end point of a WFLUSH. We also need to clear out any
+      ** data from the double buffer! ( note that WflushFlag is a
+      ** *count* of the number of WFLUSH commands outstanding! )
+      **
+      ** ++++ And there's more!
+      ** If an RTA is powered off, then on again, and rebooted,
+      ** whilst it has ports open, then we need to re-open the ports.
+      ** ( reasonable enough ). We can't do this when we spot the
+      ** re-boot, in interrupt time, because the queue is probably
+      ** full. So, when we come in here, we need to test if any
+      ** ports are in this condition, and re-open the port before
+      ** we try to send any more data to it. Now, the re-booted
+      ** RTA will be discarding packets from the PHB until it
+      ** receives this open packet, but don't worry tooo much
+      ** about that. The one thing that is interesting is the
+      ** combination of this effect and the WFLUSH effect!
+      */
+      /* For now don't handle RTA reboots. -- REW. 
+	 Reenabled. Otherwise RTA reboots didn't work. Duh. -- REW */
+      if ( PortP->MagicFlags ) {
+#if 1
+	if ( PortP->MagicFlags & MAGIC_REBOOT ) {
+	  /*
+	  ** well, the RTA has been rebooted, and there is room
+	  ** on its queue to add the open packet that is required.
+	  **
+	  ** The messy part of this line is trying to decide if
+	  ** we need to call the Param function as a tty or as
+	  ** a modem.
+	  ** DONT USE CLOCAL AS A TEST FOR THIS!
+	  **
+	  ** If we can't param the port, then move on to the
+	  ** next port.
+	  */
+	  PortP->InUse = NOT_INUSE;
+
+	  rio_spin_unlock(&PortP->portSem);
+	  if ( RIOParam(PortP, OPEN, ((PortP->Cor2Copy & 
+				       (COR2_RTSFLOW|COR2_CTSFLOW ) )== 
+				      (COR2_RTSFLOW|COR2_CTSFLOW ) ) ? 
+			TRUE : FALSE, DONT_SLEEP ) == RIO_FAIL ) {
+	    continue; /* with next port */
+	  }
+	  rio_spin_lock(&PortP->portSem);
+	  PortP->MagicFlags &= ~MAGIC_REBOOT;
+	}
+#endif
+
+	/*
+	** As mentioned above, this is a tacky hack to cope
+	** with WFLUSH
+	*/
+	if ( PortP->WflushFlag ) {
+	  rio_dprint(RIO_DEBUG_INTR, ("Want to WFLUSH mark this port\n"));
+
+	  if ( PortP->InUse )
+	    rio_dprint(RIO_DEBUG_INTR, ("FAILS - PORT IS IN USE\n"));
+	}
+				
+	while ( PortP->WflushFlag &&
+		can_add_transmit( &PacketP, PortP ) && 
+		( PortP->InUse == NOT_INUSE ) ) {
+	  int p;
+	  struct PktCmd *PktCmdP;
+
+	  rio_dprint(RIO_DEBUG_INTR, ("Add WFLUSH marker to data queue\n"));
+	  /*
+	  ** make it look just like a WFLUSH command
+	  */
+	  PktCmdP = ( struct PktCmd * )&PacketP->data[0];
+
+	  WBYTE( PktCmdP->Command , WFLUSH );
+
+	  p =  PortP->HostPort % ( ushort )PORTS_PER_RTA;
+
+	  /*
+	  ** If second block of ports for 16 port RTA, add 8
+	  ** to index 8-15.
+	  */
+	  if ( PortP->SecondBlock )
+	    p += PORTS_PER_RTA;
+
+	  WBYTE( PktCmdP->PhbNum, p );
+
+	  /*
+	  ** to make debuggery easier
+	  */
+	  WBYTE( PacketP->data[ 2], 'W'  );
+	  WBYTE( PacketP->data[ 3], 'F'  );
+	  WBYTE( PacketP->data[ 4], 'L'  );
+	  WBYTE( PacketP->data[ 5], 'U'  );
+	  WBYTE( PacketP->data[ 6], 'S'  );
+	  WBYTE( PacketP->data[ 7], 'H'  );
+	  WBYTE( PacketP->data[ 8], ' '  );
+	  WBYTE( PacketP->data[ 9], '0'+PortP->WflushFlag );
+	  WBYTE( PacketP->data[10], ' '  );
+	  WBYTE( PacketP->data[11], ' '  );
+	  WBYTE( PacketP->data[12], '\0' );
+
+	  /*
+	  ** its two bytes long!
+	  */
+	  WBYTE( PacketP->len , PKT_CMD_BIT | 2 );
+
+	  /*
+	  ** queue it!
+	  */
+	  if ( !( PortP->State & RIO_DELETED ) ) {
+	    add_transmit( PortP );
+	    /*
+	    ** Count chars tx'd for port statistics reporting
+	    */
+	    if ( PortP->statsGather )
+	      PortP->txchars += 2;
+	  }
+
+	  if ( --( PortP->WflushFlag ) == 0 ) {
+	    PortP->MagicFlags &= ~MAGIC_FLUSH;
+	  }
+
+	  rio_dprint(RIO_DEBUG_INTR, ("Wflush count now stands at %d\n", 
+		 PortP->WflushFlag));
+	}
+	if ( PortP->MagicFlags & MORE_OUTPUT_EYGOR ) {
+	  if ( PortP->MagicFlags & MAGIC_FLUSH ) {
+	    PortP->MagicFlags |= MORE_OUTPUT_EYGOR;
+	  }
+	  else {
+	    if ( !can_add_transmit( &PacketP, PortP ) ) {
+	      rio_spin_unlock(&PortP->portSem);
+	      continue;
+	    }
+	    rio_spin_unlock(&PortP->portSem);
+	    RIOTxEnable((char *)PortP);
+	    rio_spin_lock(&PortP->portSem);
+	    PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR;
+	  }
+	}
+      }
+
+
+      /*
+      ** If we can't add anything to the transmit queue, then
+      ** we need do none of the remaining processing.
+      */
+      if (!can_add_transmit( &PacketP, PortP ) ) {
+	rio_spin_unlock(&PortP->portSem);
+	continue;
+      }
+
+      rio_spin_unlock(&PortP->portSem);
+      RIOTxEnable((char *)PortP);
+    }
+  }
+}
+
+/*
+** Routine for handling received data for clist drivers.
+** NB: Called with the tty locked. The spl from the lockb( ) is passed.
+** we return the ttySpl level that we re-locked at.
+*/
+void
+RIOReceive(p, PortP)
+struct rio_info *	p;
+struct Port *		PortP;
+{
+  struct tty_struct *TtyP;
+  register ushort transCount;
+  struct PKT *PacketP;
+  register uint	DataCnt;
+  uchar *	ptr;
+  int copied =0;
+
+  static int intCount, RxIntCnt;
+
+  /*
+  ** The receive data process is to remove packets from the
+  ** PHB until there aren't any more or the current cblock
+  ** is full. When this occurs, there will be some left over
+  ** data in the packet, that we must do something with.
+  ** As we haven't unhooked the packet from the read list
+  ** yet, we can just leave the packet there, having first
+  ** made a note of how far we got. This means that we need
+  ** a pointer per port saying where we start taking the
+  ** data from - this will normally be zero, but when we
+  ** run out of space it will be set to the offset of the
+  ** next byte to copy from the packet data area. The packet
+  ** length field is decremented by the number of bytes that
+  ** we succesfully removed from the packet. When this reaches
+  ** zero, we reset the offset pointer to be zero, and free
+  ** the packet from the front of the queue.
+  */
+
+  intCount++;
+
+  TtyP = PortP->gs.tty;
+  if (!TtyP) {
+    rio_dprint (RIO_DEBUG_INTR, ("RIOReceive: tty is null. \n"));
+    return;
+  }
+
+  if (PortP->State & RIO_THROTTLE_RX) {
+    rio_dprint (RIO_DEBUG_INTR, ("RIOReceive: Throttled. Can't handle more input.\n"));
+    return;
+  }
+
+  if ( PortP->State & RIO_DELETED )
+    {
+      while ( can_remove_receive( &PacketP, PortP ) )
+	{
+	  remove_receive( PortP );
+	  put_free_end( PortP->HostP, PacketP );
+	}
+    }
+  else
+    {
+      /*
+      ** loop, just so long as:
+      **   i ) there's some data ( i.e. can_remove_receive )
+      **  ii ) we haven't been blocked
+      ** iii ) there's somewhere to put the data
+      **  iv ) we haven't outstayed our welcome
+      */
+      transCount = 1;
+      while ( can_remove_receive(&PacketP, PortP)
+	      && transCount)
+	{
+#ifdef STATS
+	  PortP->Stat.RxIntCnt++;
+#endif /* STATS */
+	  RxIntCnt++;
+
+	  /*
+	  ** check that it is not a command!
+	  */
+	  if ( PacketP->len & PKT_CMD_BIT ) {
+	    rio_dprint(RIO_DEBUG_INTR, ("RIO: unexpected command packet received on PHB\n"));
+	    /*	    rio_dprint(RIO_DEBUG_INTR, (" sysport   = %d\n", p->RIOPortp->PortNum)); */
+	    rio_dprint(RIO_DEBUG_INTR, (" dest_unit = %d\n", PacketP->dest_unit));
+	    rio_dprint(RIO_DEBUG_INTR, (" dest_port = %d\n", PacketP->dest_port));
+	    rio_dprint(RIO_DEBUG_INTR, (" src_unit  = %d\n", PacketP->src_unit));
+	    rio_dprint(RIO_DEBUG_INTR, (" src_port  = %d\n", PacketP->src_port));
+	    rio_dprint(RIO_DEBUG_INTR, (" len	   = %d\n", PacketP->len));
+	    rio_dprint(RIO_DEBUG_INTR, (" control   = %d\n", PacketP->control));
+	    rio_dprint(RIO_DEBUG_INTR, (" csum	   = %d\n", PacketP->csum));
+	    rio_dprint(RIO_DEBUG_INTR, ("	 data bytes: "));
+	    for ( DataCnt=0; DataCnt<PKT_MAX_DATA_LEN; DataCnt++ )
+	      rio_dprint(RIO_DEBUG_INTR, ("%d\n", PacketP->data[DataCnt]));
+	    remove_receive( PortP );
+	    put_free_end( PortP->HostP, PacketP );
+	    continue; /* with next packet */
+	  }
+
+	  /*
+	  ** How many characters can we move 'upstream' ?
+	  **
+	  ** Determine the minimum of the amount of data
+	  ** available and the amount of space in which to
+	  ** put it.
+	  **
+	  ** 1.	Get the packet length by masking 'len'
+	  **	for only the length bits.
+	  ** 2.	Available space is [buffer size] - [space used]
+	  **
+	  ** Transfer count is the minimum of packet length
+	  ** and available space.
+	  */
+			
+	  transCount = min(PacketP->len & PKT_LEN_MASK,
+			   TTY_FLIPBUF_SIZE - TtyP->flip.count);
+	  rio_dprint(RIO_DEBUG_REC,  ("port %d: Copy %d bytes\n", 
+				      PortP->PortNum, transCount ) );
+	  /*
+	  ** To use the following 'kkprintfs' for debugging - change the '#undef'
+	  ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the
+	  ** driver).
+	  */
+#undef ___DEBUG_IT___
+#ifdef ___DEBUG_IT___
+	  kkprintf("I:%d R:%d P:%d Q:%d C:%d F:%x ",
+		   intCount,
+		   RxIntCnt,
+		   PortP->PortNum,
+		   TtyP->rxqueue.count,
+		   transCount,
+		   TtyP->flags );
+#endif
+	  ptr = (uchar *) PacketP->data + PortP->RxDataStart;
+
+	  memcpy_fromio (TtyP->flip.char_buf_ptr, ptr, transCount);
+	  memset(TtyP->flip.flag_buf_ptr, TTY_NORMAL, transCount);
+
+#ifdef STATS
+	  /*
+	  ** keep a count for statistical purposes
+	  */
+	  PortP->Stat.RxCharCnt	+= transCount;
+#endif
+	  PortP->RxDataStart	+= transCount;
+	  PacketP->len		-= transCount;
+	  copied += transCount;
+	  TtyP->flip.count += transCount;
+	  TtyP->flip.char_buf_ptr += transCount;
+	  TtyP->flip.flag_buf_ptr += transCount;
+
+
+#ifdef ___DEBUG_IT___
+	  kkprintf("T:%d L:%d\n", DataCnt, PacketP->len );
+#endif
+
+	  if ( PacketP->len == 0 )
+	    {
+				/*
+				** If we have emptied the packet, then we can
+				** free it, and reset the start pointer for
+				** the next packet.
+				*/
+	      remove_receive( PortP );
+	      put_free_end( PortP->HostP, PacketP );
+	      PortP->RxDataStart = 0;
+#ifdef STATS
+				/*
+				** more lies ( oops, I mean statistics )
+				*/
+	      PortP->Stat.RxPktCnt++;
+#endif /* STATS */
+	    }
+	}
+    }
+  if (copied) {
+    rio_dprint ( RIO_DEBUG_REC, ("port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum,  copied));
+    tty_flip_buffer_push (TtyP);
+  }
+
+  return;
+}
+
+#ifdef FUTURE_RELEASE
+/*
+** The proc routine called by the line discipline to do the work for it.
+** The proc routine works hand in hand with the interrupt routine.
+*/
+int
+riotproc(p, tp, cmd, port)
+struct rio_info *	p;
+register struct ttystatics *tp;
+int cmd;
+int	port;
+{
+	register struct Port *PortP;
+	int SysPort;
+	struct PKT *PacketP;
+
+	SysPort = port;	/* Believe me, it works. */
+
+	if ( SysPort < 0 || SysPort >= RIO_PORTS ) {
+		rio_dprint(RIO_DEBUG_INTR, ("Illegal port %d derived from TTY in riotproc()\n",SysPort));
+		return 0;
+	}
+	PortP = p->RIOPortp[SysPort];
+
+	if ((uint)PortP->PhbP < (uint)PortP->Caddr || 
+			(uint)PortP->PhbP >= (uint)PortP->Caddr+SIXTY_FOUR_K ) {
+		rio_dprint(RIO_DEBUG_INTR, ("RIO: NULL or BAD PhbP on sys port %d in proc routine\n",
+							SysPort));
+		rio_dprint(RIO_DEBUG_INTR, ("	 PortP = 0x%x\n",PortP));
+		rio_dprint(RIO_DEBUG_INTR, ("	 PortP->PhbP = 0x%x\n",PortP->PhbP));
+		rio_dprint(RIO_DEBUG_INTR, ("	 PortP->Caddr = 0x%x\n",PortP->PhbP));
+		rio_dprint(RIO_DEBUG_INTR, ("	 PortP->HostPort = 0x%x\n",PortP->HostPort));
+		return 0;
+	}
+
+	switch(cmd) {
+		case T_WFLUSH:
+			rio_dprint(RIO_DEBUG_INTR, "T_WFLUSH\n");
+			/*
+			** Because of the spooky way the RIO works, we don't need
+			** to issue a flush command on any of the SET*F commands,
+			** as that causes trouble with getty and login, which issue
+			** these commands to incur a READ flush, and rely on the fact
+			** that the line discipline does a wait for drain for them.
+			** As the rio doesn't wait for drain, the write flush would
+			** destroy the Password: prompt. This isn't very friendly, so
+			** here we only issue a WFLUSH command if we are in the interrupt
+			** routine, or we aren't executing a SET*F command.
+			*/
+			if ( PortP->HostP->InIntr || !PortP->FlushCmdBodge ) {
+				/*
+				** form a wflush packet - 1 byte long, no data
+				*/
+				if ( PortP->State & RIO_DELETED ) {
+					rio_dprint(RIO_DEBUG_INTR, ("WFLUSH on deleted RTA\n"));
+				}
+				else {
+					if ( RIOPreemptiveCmd(p, PortP, WFLUSH ) == RIO_FAIL ) {
+						rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command failed\n"));
+					}
+					else
+						rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command\n"));
+				}
+				/*
+				** WFLUSH operation - flush the data!
+				*/
+				PortP->TxBufferIn = PortP->TxBufferOut = 0;
+			}
+			else {
+				rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command ignored\n"));
+			}
+			/*
+			** sort out the line discipline
+			*/
+			if (PortP->CookMode == COOK_WELL)
+				goto start;
+			break;
+	
+		case T_RESUME:
+			rio_dprint(RIO_DEBUG_INTR, ("T_RESUME\n"));
+			/*
+			** send pre-emptive resume packet
+			*/
+			if ( PortP->State & RIO_DELETED ) {
+				rio_dprint(RIO_DEBUG_INTR, ("RESUME on deleted RTA\n"));
+			}
+			else {
+				if ( RIOPreemptiveCmd(p, PortP, RESUME ) == RIO_FAIL ) {
+					rio_dprint(RIO_DEBUG_INTR, ("T_RESUME Command failed\n"));
+				}
+			}
+			/*
+			** and re-start the sender software!
+			*/
+			if (PortP->CookMode == COOK_WELL)
+				goto start;
+			break;
+	
+		case T_TIME:
+			rio_dprint(RIO_DEBUG_INTR, ("T_TIME\n"));
+			/*
+			** T_TIME is called when xDLY is set in oflags and
+			** the line discipline timeout has expired. It's
+			** function in life is to clear the TIMEOUT flag
+			** and to re-start output to the port.
+			*/
+			/*
+			** Fall through and re-start output
+			*/
+		case T_OUTPUT:
+start:
+			if ( PortP->MagicFlags & MAGIC_FLUSH ) {
+				PortP->MagicFlags |= MORE_OUTPUT_EYGOR;
+				return 0;
+			}
+			RIOTxEnable((char *)PortP);
+			PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR;
+			/*rio_dprint(RIO_DEBUG_INTR, PortP,DBG_PROC,"T_OUTPUT finished\n");*/
+			break;
+	
+		case T_SUSPEND:
+			rio_dprint(RIO_DEBUG_INTR, ("T_SUSPEND\n"));
+			/*
+			** send a suspend pre-emptive packet.
+			*/
+			if ( PortP->State & RIO_DELETED ) {
+				rio_dprint(RIO_DEBUG_INTR, ("SUSPEND deleted RTA\n"));
+			}
+			else {
+				if ( RIOPreemptiveCmd(p, PortP, SUSPEND ) == RIO_FAIL ) {
+					rio_dprint(RIO_DEBUG_INTR, ("T_SUSPEND Command failed\n"));
+				}
+			}
+			/*
+			** done!
+			*/
+			break;
+	
+		case T_BLOCK:
+			rio_dprint(RIO_DEBUG_INTR, ("T_BLOCK\n"));
+			break;
+	
+		case T_RFLUSH:
+			rio_dprint(RIO_DEBUG_INTR, ("T_RFLUSH\n"));
+			if ( PortP->State & RIO_DELETED ) {
+				rio_dprint(RIO_DEBUG_INTR, ("RFLUSH on deleted RTA\n"));
+				PortP->RxDataStart = 0;
+			}
+			else {
+				if ( RIOPreemptiveCmd( p, PortP, RFLUSH ) == RIO_FAIL ) {
+					rio_dprint(RIO_DEBUG_INTR, ("T_RFLUSH Command failed\n"));
+					return 0;
+				}
+				PortP->RxDataStart = 0;
+				while ( can_remove_receive(&PacketP, PortP) ) {
+					remove_receive(PortP);
+					ShowPacket(DBG_PROC, PacketP );
+					put_free_end(PortP->HostP, PacketP );
+				}
+				if ( PortP->PhbP->handshake == PHB_HANDSHAKE_SET ) {
+					/*
+					** MAGIC!
+					*/
+					rio_dprint(RIO_DEBUG_INTR, ("Set receive handshake bit\n"));
+					PortP->PhbP->handshake |= PHB_HANDSHAKE_RESET;
+				}
+			}
+			break;
+			/* FALLTHROUGH */
+		case T_UNBLOCK:
+			rio_dprint(RIO_DEBUG_INTR, ("T_UNBLOCK\n"));
+			/*
+			** If there is any data to receive set a timeout to service it.
+			*/
+			RIOReceive(p, PortP);
+			break;
+	
+		case T_BREAK:
+			rio_dprint(RIO_DEBUG_INTR, ("T_BREAK\n"));
+			/*
+			** Send a break command. For Sys V
+			** this is a timed break, so we
+			** send a SBREAK[time] packet
+			*/
+			/*
+			** Build a BREAK command
+			*/
+			if ( PortP->State & RIO_DELETED ) {
+				rio_dprint(RIO_DEBUG_INTR, ("BREAK on deleted RTA\n"));
+			}
+			else {
+				if (RIOShortCommand(PortP,SBREAK,2,
+								p->RIOConf.BreakInterval)==RIO_FAIL) {
+			   		rio_dprint(RIO_DEBUG_INTR, ("SBREAK RIOShortCommand failed\n"));
+				}
+			}
+	
+			/*
+			** done!
+			*/
+			break;
+	
+		case T_INPUT:
+			rio_dprint(RIO_DEBUG_INTR, ("Proc T_INPUT called - I don't know what to do!\n"));
+			break;
+		case T_PARM:
+			rio_dprint(RIO_DEBUG_INTR, ("Proc T_PARM called - I don't know what to do!\n"));
+			break;
+	
+		case T_SWTCH:
+			rio_dprint(RIO_DEBUG_INTR, ("Proc T_SWTCH called - I don't know what to do!\n"));
+			break;
+	
+		default:
+			rio_dprint(RIO_DEBUG_INTR, ("Proc UNKNOWN command %d\n",cmd));
+	}
+	/*
+	** T_OUTPUT returns without passing through this point!
+	*/
+	/*rio_dprint(RIO_DEBUG_INTR, PortP,DBG_PROC,"riotproc done\n");*/
+	return(0);
+}
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/rioioctl.h linux/drivers/char/rio/rioioctl.h
--- linux-2.2.15-pre2/drivers/char/rio/rioioctl.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioioctl.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,103 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioioctl.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)rioioctl.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rioioctl_h__
+#define	__rioioctl_h__
+
+#ifdef SCCS_LABELS
+static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h	1.2";
+#endif
+
+/*
+** RIO device driver - user ioctls and associated structures.
+*/
+
+struct portStats {
+	int	port;
+	int	gather;
+	ulong	txchars;
+	ulong	rxchars;
+	ulong	opens;
+	ulong	closes;
+	ulong	ioctls;
+}; 
+
+
+#define rIOC	('r'<<8)
+#define	TCRIOSTATE	(rIOC | 1)
+#define	TCRIOXPON	(rIOC | 2)
+#define	TCRIOXPOFF	(rIOC | 3)
+#define	TCRIOXPCPS	(rIOC | 4)
+#define	TCRIOXPRINT	(rIOC | 5)
+#define TCRIOIXANYON	(rIOC | 6)
+#define	TCRIOIXANYOFF	(rIOC | 7)
+#define TCRIOIXONON	(rIOC | 8)
+#define	TCRIOIXONOFF	(rIOC | 9)
+#define	TCRIOMBIS	(rIOC | 10)
+#define	TCRIOMBIC	(rIOC | 11)
+#define	TCRIOTRIAD	(rIOC | 12)
+#define TCRIOTSTATE	(rIOC | 13)
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** Add RIO ioctls for manipulating RTS and CTS flow control, (as LynxOS
+** appears to not support hardware flow control).
+*/
+#define TCRIOCTSFLOWEN	(rIOC | 14)	/* enable CTS flow control */
+#define TCRIOCTSFLOWDIS	(rIOC | 15)	/* disable CTS flow control */
+#define TCRIORTSFLOWEN	(rIOC | 16)	/* enable RTS flow control */
+#define TCRIORTSFLOWDIS	(rIOC | 17)	/* disable RTS flow control */
+
+/*
+** 09.12.1998 ARG - ESIL 0776 part fix
+** Definition for 'RIOC' also appears in daemon.h, so we'd better do a
+** #ifndef here first.
+** 'RIO_QUICK_CHECK' also #define'd here as this ioctl is now
+** allowed to be used by customers.
+**
+** 05.02.1999 ARG -
+** This is what I've decied to do with ioctls etc., which are intended to be
+** invoked from users applications :
+** Anything that needs to be defined here will be removed from daemon.h, that
+** way it won't end up having to be defined/maintained in two places. The only
+** consequence of this is that this file should now be #include'd by daemon.h
+**
+** 'stats' ioctls now #define'd here as they are to be used by customers.
+*/
+#define	RIOC	('R'<<8)|('i'<<16)|('o'<<24)
+
+#define	RIO_QUICK_CHECK	  	(RIOC | 105)
+#define RIO_GATHER_PORT_STATS	(RIOC | 193)
+#define RIO_RESET_PORT_STATS	(RIOC | 194)
+#define RIO_GET_PORT_STATS	(RIOC | 195)
+
+#endif	/* __rioioctl_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/riolocks.h linux/drivers/char/rio/riolocks.h
--- linux-2.2.15-pre2/drivers/char/rio/riolocks.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riolocks.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,43 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riolocks.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)riolocks.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_riolocks_h__
+#define	__rio_riolocks_h__
+
+#ifdef SCCS_LABELS
+static char *_riolocks_h_sccs_ = "@(#)riolocks.h	1.2";
+#endif
+
+#define LOCKB(lk)		lockb(lk);
+#define UNLOCKB(lk, oldspl)	unlockb(lk, oldspl);
+
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/rioparam.c linux/drivers/char/rio/rioparam.c
--- linux-2.2.15-pre2/drivers/char/rio/rioparam.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioparam.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,728 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioparam.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:45
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)rioparam.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifdef SCCS_LABELS
+static char *_rioparam_c_sccs_ = "@(#)rioparam.c	1.3";
+#endif
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+
+
+
+/*
+** The Scam, based on email from jeremyr@bugs.specialix.co.uk....
+**
+** To send a command on a particular port, you put a packet with the
+** command bit set onto the port. The command bit is in the len field,
+** and gets ORed in with the actual byte count.
+**
+** When you send a packet with the command bit set, then the first
+** data byte ( data[0] ) is interpretted as the command to execute.
+** It also governs what data structure overlay should accompany the packet.
+** Commands are defined in cirrus/cirrus.h
+**
+** If you want the command to pre-emt data already on the queue for the
+** port, set the pre-emptive bit in conjunction with the command bit.
+** It is not defined what will happen if you set the preemptive bit
+** on a packet that is NOT a command.
+**
+** Pre-emptive commands should be queued at the head of the queue using
+** add_start(), whereas normal commands and data are enqueued using
+** add_end().
+**
+** Most commands do not use the remaining bytes in the data array. The
+** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and
+** OPEN are currently analagous). With these three commands the following
+** 11 data bytes are all used to pass config information such as baud rate etc.
+** The fields are also defined in cirrus.h. Some contain straightforward
+** information such as the transmit XON character. Two contain the transmit and
+** receive baud rates respectively. For most baud rates there is a direct
+** mapping between the rates defined in <sys/termio.h> and the byte in the
+** packet. There are additional (non UNIX-standard) rates defined in
+** /u/dos/rio/cirrus/h/brates.h.
+**
+** The rest of the data fields contain approximations to the Cirrus registers
+** that are used to program number of bits etc. Each registers bit fields is
+** defined in cirrus.h.
+** 
+** NB. Only use those bits that are defined as being driver specific
+** or common to the RTA and the driver.
+** 
+** All commands going from RTA->Host will be dealt with by the Host code - you
+** will never see them. As with the SI there will be three fields to look out
+** for in each phb (not yet defined - needs defining a.s.a.p).
+** 
+** modem_status	- current state of handshake pins.
+**
+** port_status	 - current port status - equivalent to hi_stat for SI, indicates
+** if port is IDLE_OPEN, IDLE_CLOSED etc.
+**
+** break_status	- bit X set if break has been received.
+** 
+** Happy hacking.
+** 
+*/
+
+/* 
+** RIOParam is used to open or configure a port. You pass it a PortP,
+** which will have a tty struct attached to it. You also pass a command,
+** either OPEN or CONFIG. The port's setup is taken from the t_ fields
+** of the tty struct inside the PortP, and the port is either opened
+** or re-configured. You must also tell RIOParam if the device is a modem
+** device or not (i.e. top bit of minor number set or clear - take special
+** care when deciding on this!).
+** RIOParam neither flushes nor waits for drain, and is NOT preemptive.
+**
+** RIOParam assumes it will be called at splrio(), and also assumes
+** that CookMode is set correctly in the port structure.
+**
+** NB. for MPX
+**	tty lock must NOT have been previously acquired.
+*/
+int
+RIOParam(PortP, cmd, Modem, SleepFlag)
+struct Port *PortP;
+int cmd;
+int Modem;
+int SleepFlag; 
+{
+	register struct tty_struct *TtyP;
+	int	retval;
+	register struct phb_param *phb_param_ptr;
+	PKT *PacketP;
+	int res;
+	uchar Cor1=0, Cor2=0, Cor4=0, Cor5=0;
+	uchar TxXon=0, TxXoff=0, RxXon=0, RxXoff=0;
+	uchar LNext=0, TxBaud=0, RxBaud=0;
+	int		retries = 0xff;
+	unsigned long flags;
+
+	TtyP = PortP->gs.tty;
+
+	rio_dprint(RIO_DEBUG_PARAM, ("RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n",
+	    PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP) );
+
+	if (!TtyP) {
+	  rio_dprint (RIO_DEBUG_PARAM, ("Can't call rioparam with null tty.\n"));
+	  return RIO_FAIL;
+	}
+	rio_spin_lock_irqsave(&PortP->portSem, flags );
+
+	if (cmd == OPEN) {
+		/*
+		** If the port is set to store or lock the parameters, and it is
+		** paramed with OPEN, we want to restore the saved port termio, but
+		** only if StoredTermio has been saved, i.e. NOT 1st open after reboot.
+		*/
+#if 0
+		if (PortP->FirstOpen) {
+			PortP->StoredTty.iflag = TtyP->tm.c_iflag;
+			PortP->StoredTty.oflag = TtyP->tm.c_oflag;
+			PortP->StoredTty.cflag = TtyP->tm.c_cflag;
+			PortP->StoredTty.lflag = TtyP->tm.c_lflag;
+			PortP->StoredTty.line = TtyP->tm.c_line;
+			for (i = 0; i < NCC + 5; i++)
+				PortP->StoredTty.cc[i] = TtyP->tm.c_cc[i];
+			PortP->FirstOpen = 0;
+		}
+		else if (PortP->Store || PortP->Lock) {
+			rio_dprint(RIO_DEBUG_PARAM, ("OPEN: Restoring stored/locked params\n"));
+			TtyP->tm.c_iflag = PortP->StoredTty.iflag;
+			TtyP->tm.c_oflag = PortP->StoredTty.oflag;
+			TtyP->tm.c_cflag = PortP->StoredTty.cflag;
+			TtyP->tm.c_lflag = PortP->StoredTty.lflag;
+			TtyP->tm.c_line = PortP->StoredTty.line;
+			for (i = 0; i < NCC + 5; i++)
+				TtyP->tm.c_cc[i] = PortP->StoredTty.cc[i];
+		}
+#endif
+	}
+
+	/*
+	** wait for space
+	*/
+	while ( !(res=can_add_transmit(&PacketP,PortP)) || 
+			(PortP->InUse != NOT_INUSE) ) {
+		if (retries -- <= 0) {
+			break;
+		}
+		if ( PortP->InUse != NOT_INUSE ) {
+			rio_dprint(RIO_DEBUG_PARAM, ("Port IN_USE for pre-emptive command\n"));
+		}
+
+		if ( !res ) {
+			rio_dprint(RIO_DEBUG_PARAM, ("Port has no space on transmit queue\n"));
+		}
+
+		if ( SleepFlag != OK_TO_SLEEP ) {
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			return RIO_FAIL;
+		}
+
+		rio_dprint(RIO_DEBUG_PARAM, ("wait for can_add_transmit\n"));
+		rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+		retval = RIODelay(PortP, HUNDRED_MS);
+		rio_spin_lock_irqsave( &PortP->portSem, flags);
+		if (retval == RIO_FAIL) {
+			rio_dprint(RIO_DEBUG_PARAM, ("wait for can_add_transmit broken by signal\n"));
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			pseterr(EINTR);
+			return RIO_FAIL;
+		}
+		if ( PortP->State & RIO_DELETED ) {
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			return RIO_SUCCESS;
+		}
+	}
+
+	if (!res) {
+		rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	rio_dprint(RIO_DEBUG_PARAM, ("can_add_transmit() returns %x\n",res));
+	rio_dprint(RIO_DEBUG_PARAM, ("Packet is 0x%x\n",(int) PacketP));
+
+	phb_param_ptr = (struct phb_param *)PacketP->data;
+
+
+#if 0
+	/*
+	** COR 1
+	*/
+	if ( TtyP->tm.c_iflag & INPCK ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Parity checking on input enabled\n"));
+		Cor1 |= COR1_INPCK;
+	}
+#endif
+
+	switch ( TtyP->termios->c_cflag & CSIZE ) {
+		case CS5:
+		{
+			rio_dprint(RIO_DEBUG_PARAM, ("5 bit data\n"));
+			Cor1 |= COR1_5BITS;
+			break;
+		}
+		case CS6:
+		{
+			rio_dprint(RIO_DEBUG_PARAM, ("6 bit data\n"));
+			Cor1 |= COR1_6BITS;
+			break;
+		}
+		case CS7:
+		{
+			rio_dprint(RIO_DEBUG_PARAM, ("7 bit data\n"));
+			Cor1 |= COR1_7BITS;
+			break;
+		}
+		case CS8:
+		{
+			rio_dprint(RIO_DEBUG_PARAM, ("8 bit data\n"));
+			Cor1 |= COR1_8BITS;
+			break;
+		}
+	}
+
+	if ( TtyP->termios->c_cflag & CSTOPB ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("2 stop bits\n"));
+		Cor1 |= COR1_2STOP;
+	}
+	else {
+		rio_dprint(RIO_DEBUG_PARAM, ("1 stop bit\n"));
+		Cor1 |= COR1_1STOP;
+	}
+
+	if ( TtyP->termios->c_cflag & PARENB ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable parity\n"));
+		Cor1 |= COR1_NORMAL;
+	}
+	else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Disable parity\n"));
+		Cor1 |= COR1_NOP;
+	}
+	if ( TtyP->termios->c_cflag & PARODD ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Odd parity\n"));
+		Cor1 |= COR1_ODD;
+	}
+	else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Even parity\n"));
+		Cor1 |= COR1_EVEN; 
+	}
+
+	/*
+	** COR 2
+	*/
+	if ( TtyP->termios->c_iflag & IXON ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable start/stop output control\n"));
+		Cor2 |= COR2_IXON;
+	}
+	else {
+		if ( PortP->Config & RIO_IXON ) {
+			rio_dprint(RIO_DEBUG_PARAM, ("Force enable start/stop output control\n"));
+			Cor2 |= COR2_IXON;
+		}
+		else
+			rio_dprint(RIO_DEBUG_PARAM, ("IXON has been disabled.\n"));
+	}
+
+	if (TtyP->termios->c_iflag & IXANY) {
+		if ( PortP->Config & RIO_IXANY ) {
+			rio_dprint(RIO_DEBUG_PARAM, ("Enable any key to restart output\n"));
+			Cor2 |= COR2_IXANY;
+		}
+		else
+			rio_dprint(RIO_DEBUG_PARAM, ("IXANY has been disabled due to sanity reasons.\n"));
+	}
+
+	if ( TtyP->termios->c_iflag & IXOFF ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable start/stop input control 2\n"));
+		Cor2 |= COR2_IXOFF;
+	}
+
+	if ( TtyP->termios->c_cflag & HUPCL ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Hangup on last close\n"));
+		Cor2 |= COR2_HUPCL;
+	}
+
+	if ( C_CRTSCTS (TtyP)) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Rx hardware flow control enabled\n"));
+		Cor2 |= COR2_CTSFLOW;
+		Cor2 |= COR2_RTSFLOW;
+	} else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Rx hardware flow control disabled\n"));
+		Cor2 &= ~COR2_CTSFLOW;
+		Cor2 &= ~COR2_RTSFLOW;
+	}
+
+
+	if ( TtyP->termios->c_cflag & CLOCAL ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Local line\n"));
+	}
+	else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Possible Modem line\n"));
+	}
+
+	/*
+	** COR 4 (there is no COR 3)
+	*/
+	if ( TtyP->termios->c_iflag & IGNBRK ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Ignore break condition\n"));
+		Cor4 |= COR4_IGNBRK;
+	}
+	if ( !(TtyP->termios->c_iflag & BRKINT) ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Break generates NULL condition\n"));
+		Cor4 |= COR4_NBRKINT;
+	} else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Interrupt on	break condition\n"));
+	}
+
+	if ( TtyP->termios->c_iflag & INLCR ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Map newline to carriage return on input\n"));
+		Cor4 |= COR4_INLCR;
+	}
+
+	if ( TtyP->termios->c_iflag & IGNCR ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Ignore carriage return on input\n"));
+		Cor4 |= COR4_IGNCR;
+	}
+
+	if ( TtyP->termios->c_iflag & ICRNL ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Map carriage return to newline on input\n"));
+		Cor4 |= COR4_ICRNL;
+	}
+	if ( TtyP->termios->c_iflag & IGNPAR ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Ignore characters with parity errors\n"));
+		Cor4 |= COR4_IGNPAR;
+	}
+	if ( TtyP->termios->c_iflag & PARMRK ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Mark parity errors\n"));
+		Cor4 |= COR4_PARMRK;
+	}
+
+	/*
+	** Set the RAISEMOD flag to ensure that the modem lines are raised
+	** on reception of a config packet.
+	** The download code handles the zero baud condition.
+	*/
+	Cor4 |= COR4_RAISEMOD;
+
+	/*
+	** COR 5
+	*/
+
+	Cor5 = COR5_CMOE;
+
+	/*
+	** Set to monitor tbusy/tstop (or not).
+	*/
+
+	if (PortP->MonitorTstate)
+		Cor5 |= COR5_TSTATE_ON;
+	else
+		Cor5 |= COR5_TSTATE_OFF;
+
+	/*
+	** Could set LNE here if you wanted LNext processing. SVR4 will use it.
+	*/
+	if ( TtyP->termios->c_iflag & ISTRIP ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Strip input characters\n"));
+		if (! (PortP->State & RIO_TRIAD_MODE)) {
+			Cor5 |= COR5_ISTRIP;
+		}
+	}
+
+	if ( TtyP->termios->c_oflag & ONLCR ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Map newline to carriage-return, newline on output\n"));
+		if ( PortP->CookMode == COOK_MEDIUM )
+			Cor5 |= COR5_ONLCR;
+	}
+	if ( TtyP->termios->c_oflag & OCRNL ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Map carriage return to newline on output\n"));
+		if ( PortP->CookMode == COOK_MEDIUM )
+			Cor5 |= COR5_OCRNL;
+	}
+	if ( ( TtyP->termios->c_oflag & TABDLY) == TAB3 ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Tab delay 3 set\n"));
+		if ( PortP->CookMode == COOK_MEDIUM )
+			Cor5 |= COR5_TAB3;
+	}
+
+	/*
+	** Flow control bytes.
+	*/
+	TxXon = TtyP->termios->c_cc[VSTART];
+	TxXoff = TtyP->termios->c_cc[VSTOP];
+	RxXon = TtyP->termios->c_cc[VSTART];
+	RxXoff = TtyP->termios->c_cc[VSTOP];
+	/*
+	** LNEXT byte
+	*/
+	LNext = 0;
+
+	/*
+	** Baud rate bytes
+	*/
+	rio_dprint(RIO_DEBUG_PARAM, ("Mapping of rx/tx baud %x (%x)\n", 
+				     TtyP->termios->c_cflag, CBAUD));
+
+	switch (TtyP->termios->c_cflag & CBAUD) {
+#define e(b) case B ## b : RxBaud = TxBaud = RIO_B ## b ;break
+	  e(50);e(75);e(110);e(134);e(150);e(200);e(300);e(600);e(1200);
+	  e(1800);e(2400);e(4800);e(9600);e(19200);e(38400);e(57600);
+	  e(115200); /* e(230400);e(460800); e(921600);  */
+	}
+
+	/* XXX MIssing conversion table. XXX */
+	/* 	 (TtyP->termios->c_cflag & V_CBAUD); */
+
+	rio_dprint(RIO_DEBUG_PARAM, ("tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud));
+
+
+	/*
+	** Leftovers
+	*/
+	if ( TtyP->termios->c_cflag & CREAD )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable receiver\n"));
+#ifdef RCV1EN
+	if ( TtyP->termios->c_cflag & RCV1EN )
+		rio_dprint(RIO_DEBUG_PARAM, ("RCV1EN (?)\n"));
+#endif
+#ifdef XMT1EN
+	if ( TtyP->termios->c_cflag & XMT1EN )
+		rio_dprint(RIO_DEBUG_PARAM, ("XMT1EN (?)\n"));
+#endif
+#if 0
+	if ( TtyP->termios->c_cflag & LOBLK )
+		rio_dprint(RIO_DEBUG_PARAM, ("LOBLK - JCL output blocks when not current\n"));
+#endif
+	if ( TtyP->termios->c_lflag & ISIG )
+		rio_dprint(RIO_DEBUG_PARAM, ("Input character signal generating enabled\n"));
+	if ( TtyP->termios->c_lflag & ICANON )
+		rio_dprint(RIO_DEBUG_PARAM, ("Canonical input: erase and kill enabled\n"));
+	if ( TtyP->termios->c_lflag & XCASE )
+		rio_dprint(RIO_DEBUG_PARAM, ("Canonical upper/lower presentation\n"));
+	if ( TtyP->termios->c_lflag & ECHO )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable input echo\n"));
+	if ( TtyP->termios->c_lflag & ECHOE )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable echo erase\n"));
+	if ( TtyP->termios->c_lflag & ECHOK )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable echo kill\n"));
+	if ( TtyP->termios->c_lflag & ECHONL )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable echo newline\n"));
+	if ( TtyP->termios->c_lflag & NOFLSH )
+		rio_dprint(RIO_DEBUG_PARAM, ("Disable flush after interrupt or quit\n"));
+#ifdef TOSTOP
+	if ( TtyP->termios->c_lflag & TOSTOP )
+		rio_dprint(RIO_DEBUG_PARAM, ("Send SIGTTOU for background output\n"));
+#endif
+#ifdef XCLUDE
+	if ( TtyP->termios->c_lflag & XCLUDE )
+		rio_dprint(RIO_DEBUG_PARAM, ("Exclusive use of this line\n"));
+#endif
+	if ( TtyP->termios->c_iflag & IUCLC )
+		rio_dprint(RIO_DEBUG_PARAM, ("Map uppercase to lowercase on input\n"));
+	if ( TtyP->termios->c_oflag & OPOST )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable output post-processing\n"));
+	if ( TtyP->termios->c_oflag & OLCUC )
+		rio_dprint(RIO_DEBUG_PARAM, ("Map lowercase to uppercase on output\n"));
+	if ( TtyP->termios->c_oflag & ONOCR )
+		rio_dprint(RIO_DEBUG_PARAM, ("No carriage return output at column 0\n"));
+	if ( TtyP->termios->c_oflag & ONLRET )
+		rio_dprint(RIO_DEBUG_PARAM, ("Newline performs carriage return function\n"));
+	if ( TtyP->termios->c_oflag & OFILL )
+		rio_dprint(RIO_DEBUG_PARAM, ("Use fill characters for delay\n"));
+	if ( TtyP->termios->c_oflag & OFDEL )
+		rio_dprint(RIO_DEBUG_PARAM, ("Fill character is DEL\n"));
+	if ( TtyP->termios->c_oflag & NLDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Newline delay set\n"));
+	if ( TtyP->termios->c_oflag & CRDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Carriage return delay set\n"));
+	if ( TtyP->termios->c_oflag & TABDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Tab delay set\n"));
+#if 0
+	if ( TtyP->termios->c_oflag & BSDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Back-space delay set\n"));
+	if ( TtyP->termios->c_oflag & VTDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Vertical tab delay set\n"));
+	if ( TtyP->termios->c_oflag & FFDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Form-feed delay set\n"));
+#endif
+	/*
+	** These things are kind of useful in a later life!
+	*/
+	PortP->Cor2Copy = Cor2;
+
+	if ( PortP->State & RIO_DELETED ) {
+		rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	/*
+	** Actually write the info into the packet to be sent
+	*/
+	WBYTE(phb_param_ptr->Cmd,	cmd);
+	WBYTE(phb_param_ptr->Cor1,	 Cor1);
+	WBYTE(phb_param_ptr->Cor2,	 Cor2);
+	WBYTE(phb_param_ptr->Cor4,	 Cor4);
+	WBYTE(phb_param_ptr->Cor5,	 Cor5);
+	WBYTE(phb_param_ptr->TxXon,	TxXon);
+	WBYTE(phb_param_ptr->RxXon,	RxXon);
+	WBYTE(phb_param_ptr->TxXoff, TxXoff);
+	WBYTE(phb_param_ptr->RxXoff, RxXoff);
+	WBYTE(phb_param_ptr->LNext,	LNext);
+	WBYTE(phb_param_ptr->TxBaud, TxBaud);
+	WBYTE(phb_param_ptr->RxBaud, RxBaud);
+
+	/*
+	** Set the length/command field
+	*/
+	WBYTE(PacketP->len , 12 | PKT_CMD_BIT);
+
+	/*
+	** The packet is formed - now, whack it off
+	** to its final destination:
+	*/
+	add_transmit(PortP);
+	/*
+	** Count characters transmitted for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->txchars += 12;
+
+	rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+
+	rio_dprint(RIO_DEBUG_PARAM, ("add_transmit returned.\n"));
+	/*
+	** job done.
+	*/
+	return RIO_SUCCESS;
+}
+
+
+/*
+** We can add another packet to a transmit queue if the packet pointer pointed
+** to by the TxAdd pointer has PKT_IN_USE clear in its address.
+*/
+int
+can_add_transmit(PktP, PortP)
+PKT **PktP;
+struct Port *PortP; 
+{
+	register PKT *tp;
+
+	*PktP = tp = (PKT *)RIO_PTR(PortP->Caddr,RWORD(*PortP->TxAdd));
+
+	return !((uint)tp & PKT_IN_USE);
+}
+
+/*
+** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
+** and then move the TxAdd pointer along one position to point to the next
+** packet pointer. You must wrap the pointer from the end back to the start.
+*/
+void
+add_transmit(PortP)
+struct Port *PortP; 
+{
+  if (RWORD(*PortP->TxAdd) & PKT_IN_USE) {
+    rio_dprint (RIO_DEBUG_PARAM, ("add_transmit: Packet has been stolen!"));
+  }
+	WWORD( *(ushort *)PortP->TxAdd, RWORD(*PortP->TxAdd) | PKT_IN_USE);
+	PortP->TxAdd = (PortP->TxAdd == PortP->TxEnd) ? PortP->TxStart : 
+					PortP->TxAdd + 1;
+	WWORD( PortP->PhbP->tx_add , RIO_OFF(PortP->Caddr,PortP->TxAdd) );
+}
+
+/****************************************
+ * Put a packet onto the end of the
+ * free list
+ ****************************************/
+void
+put_free_end(HostP, PktP)
+struct Host *HostP;
+PKT *PktP;
+{
+	FREE_LIST *tmp_pointer;
+	ushort old_end, new_end;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+	 /*************************************************
+	* Put a packet back onto the back of the free list
+	*
+	************************************************/
+
+	rio_dprint(RIO_DEBUG_PFE, ("put_free_end(PktP=%x)\n",(int)PktP));
+
+	if ((old_end=RWORD(HostP->ParmMapP->free_list_end)) != TPNULL) {
+		new_end = RIO_OFF(HostP->Caddr,PktP);
+		tmp_pointer = (FREE_LIST *)RIO_PTR(HostP->Caddr,old_end);
+		WWORD(tmp_pointer->next , new_end );
+		WWORD(((FREE_LIST *)PktP)->prev , old_end);
+		WWORD(((FREE_LIST *)PktP)->next , TPNULL);
+		WWORD(HostP->ParmMapP->free_list_end, new_end);
+	}
+	else {	/* First packet on the free list this should never happen! */
+		rio_dprint(RIO_DEBUG_PFE, ("put_free_end(): This should never happen\n"));
+		WWORD(HostP->ParmMapP->free_list_end , RIO_OFF(HostP->Caddr,PktP));
+		tmp_pointer = (FREE_LIST *)PktP;
+		WWORD(tmp_pointer->prev , TPNULL);
+		WWORD(tmp_pointer->next , TPNULL);
+	}
+	rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+}
+
+/*
+** can_remove_receive(PktP,P) returns non-zero if PKT_IN_USE is set
+** for the next packet on the queue. It will also set PktP to point to the
+** relevent packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
+** then can_remove_receive() returns 0.
+*/
+int
+can_remove_receive(PktP, PortP)
+PKT **PktP;
+struct Port *PortP;
+{
+	if ( RWORD(*PortP->RxRemove) & PKT_IN_USE) {
+		*PktP = (PKT *)RIO_PTR(PortP->Caddr,
+					RWORD(*PortP->RxRemove) & ~PKT_IN_USE);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+** To remove a packet from the receive queue you clear its PKT_IN_USE bit,
+** and then bump the pointers. Once the pointers get to the end, they must
+** be wrapped back to the start.
+*/
+void
+remove_receive(PortP)
+struct Port *PortP; 
+{
+	WWORD( *PortP->RxRemove, RWORD(*PortP->RxRemove) & ~PKT_IN_USE );
+	PortP->RxRemove = (PortP->RxRemove == PortP->RxEnd) ? PortP->RxStart : 
+								PortP->RxRemove + 1;
+	WWORD( PortP->PhbP->rx_remove , RIO_OFF(PortP->Caddr, PortP->RxRemove) );
+}
diff -urN linux-2.2.15-pre2/drivers/char/rio/riopcicopy.c linux/drivers/char/rio/riopcicopy.c
--- linux-2.2.15-pre2/drivers/char/rio/riopcicopy.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riopcicopy.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,8 @@
+
+/* Yeah. We have copyright on this one. Sure. */
+
+void rio_pcicopy( char *from, char *to, int amount)
+{
+  while ( amount-- )
+    *to++ = *from++;
+}
diff -urN linux-2.2.15-pre2/drivers/char/rio/rioroute.c linux/drivers/char/rio/rioroute.c
--- linux-2.2.15-pre2/drivers/char/rio/rioroute.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioroute.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1234 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioroute.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:46
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)rioroute.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_rioroute_c_sccs_ = "@(#)rioroute.c	1.3";
+#endif
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+
+/*
+** Incoming on the ROUTE_RUP
+** I wrote this while I was tired. Forgive me.
+*/
+int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP )
+{
+  struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data;
+  struct PktCmd_M *PktReplyP;
+  struct CmdBlk *CmdBlkP;
+  struct Port *PortP;
+  struct Map *MapP;
+  struct Top *TopP;
+  int ThisLink, ThisLinkMin, ThisLinkMax;
+  int port;
+  int Mod, Mod1, Mod2;
+  ushort RtaType;
+  uint RtaUniq;
+  uint ThisUnit, ThisUnit2;	/* 2 ids to accommodate 16 port RTA */
+  uint OldUnit, NewUnit, OldLink, NewLink;
+  char *MyType, *MyName;
+  int Lies;
+  unsigned long flags;
+
+#ifdef STACK
+    RIOStackCheck("RIORouteRup");
+#endif
+#ifdef CHECK
+    CheckPacketP(PacketP);
+    CheckHostP(HostP);
+    CheckRup(Rup);
+    CheckHost(Host);
+#endif
+  /*
+  ** Is this unit telling us it's current link topology?
+  */
+  if ( RBYTE(PktCmdP->Command) == ROUTE_TOPOLOGY )
+  {
+    MapP = HostP->Mapping;
+
+    /*
+    ** The packet can be sent either by the host or by an RTA.
+    ** If it comes from the host, then we need to fill in the
+    ** Topology array in the host structure. If it came in
+    ** from an RTA then we need to fill in the Mapping structure's
+    ** Topology array for the unit.
+    */
+    if ( Rup >= (ushort)MAX_RUP )
+    {
+      ThisUnit = HOST_ID;
+      TopP = HostP->Topology;
+      MyType = "Host";
+      MyName = HostP->Name;
+      ThisLinkMin = ThisLinkMax = Rup - MAX_RUP;
+    }
+    else
+    {
+      ThisUnit = Rup+1;
+      TopP = HostP->Mapping[Rup].Topology;
+      MyType = "RTA";
+      MyName = HostP->Mapping[Rup].Name;
+      ThisLinkMin = 0;
+      ThisLinkMax = LINKS_PER_UNIT - 1;
+    }
+
+    /*
+    ** Lies will not be tolerated.
+    ** If any pair of links claim to be connected to the same
+    ** place, then ignore this packet completely.
+    */
+    Lies = 0;
+    for ( ThisLink=ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++)
+    {
+      /*
+      ** it won't lie about network interconnect, total disconnects
+      ** and no-IDs. (or at least, it doesn't *matter* if it does)
+      */
+      if ( RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) > (ushort)MAX_RUP )
+	  continue;
+
+      for ( NewLink=ThisLinkMin; NewLink < ThisLink; NewLink++ )
+      {
+        if ( (RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) ==
+              RBYTE(PktCmdP->RouteTopology[NewLink].Unit)) &&
+	     (RBYTE(PktCmdP->RouteTopology[ThisLink].Link) ==
+              RBYTE(PktCmdP->RouteTopology[NewLink].Link)) )
+	{
+          Lies++;
+	}
+      }
+    }
+
+    if ( Lies )
+    {
+      rio_dprint(RIO_DEBUG_ROUTE, ("LIES! DAMN LIES! %d LIES!\n",Lies));
+      rio_dprint(RIO_DEBUG_ROUTE, ("%d:%c %d:%c %d:%c %d:%c\n",
+          RBYTE(PktCmdP->RouteTopology[0].Unit), 
+	  'A'+RBYTE(PktCmdP->RouteTopology[0].Link),
+          RBYTE(PktCmdP->RouteTopology[1].Unit),
+	  'A'+RBYTE(PktCmdP->RouteTopology[1].Link),
+          RBYTE(PktCmdP->RouteTopology[2].Unit),
+	  'A'+RBYTE(PktCmdP->RouteTopology[2].Link),
+          RBYTE(PktCmdP->RouteTopology[3].Unit),
+	  'A'+RBYTE(PktCmdP->RouteTopology[3].Link)));
+      return TRUE;
+    }
+
+    /*
+    ** now, process each link.
+    */
+    for ( ThisLink=ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++)
+    {
+      /*
+      ** this is what it was connected to
+      */
+      OldUnit = TopP[ThisLink].Unit;
+      OldLink = TopP[ThisLink].Link;
+
+      /*
+      ** this is what it is now connected to
+      */
+      NewUnit = RBYTE(PktCmdP->RouteTopology[ThisLink].Unit);
+      NewLink = RBYTE(PktCmdP->RouteTopology[ThisLink].Link);
+
+      if ( OldUnit != NewUnit || OldLink != NewLink )
+      {
+	/*
+	** something has changed!
+	*/
+
+        if ( NewUnit > MAX_RUP &&
+	     NewUnit != ROUTE_DISCONNECT &&
+	     NewUnit != ROUTE_NO_ID &&
+	     NewUnit != ROUTE_INTERCONNECT )
+	{
+	    rio_dprint(RIO_DEBUG_ROUTE, ("I have a link from %s %s to unit %d:%d - I don't like it.\n",
+		  MyType,
+		  MyName,
+		  NewUnit,
+		  NewLink));
+	}
+	else
+	{
+	  /*
+	  ** put the new values in
+	  */
+	  TopP[ThisLink].Unit = NewUnit;
+	  TopP[ThisLink].Link = NewLink;
+
+	  RIOSetChange(p);
+
+	  if ( OldUnit <= MAX_RUP )
+	  {
+	    /*
+	    ** If something has become bust, then re-enable them messages
+	    */
+	    if (! p->RIONoMessage)
+		RIOConCon(p,HostP,ThisUnit,ThisLink,OldUnit,OldLink,DISCONNECT);
+	  }
+
+	  if ( ( NewUnit <= MAX_RUP ) && !p->RIONoMessage )
+	    RIOConCon(p,HostP,ThisUnit,ThisLink,NewUnit,NewLink,CONNECT);
+
+	  if ( NewUnit == ROUTE_NO_ID )
+	    rio_dprint(RIO_DEBUG_ROUTE, ("%s %s (%c) is connected to an unconfigured unit.\n",
+		    MyType,MyName,'A'+ThisLink));
+
+	  if ( NewUnit == ROUTE_INTERCONNECT )
+	  {
+	    if (! p->RIONoMessage)
+		cprintf("%s '%s' (%c) is connected to another network.\n", MyType,MyName,'A'+ThisLink);
+	  }
+
+	  /*
+	  ** perform an update for 'the other end', so that these messages
+	  ** only appears once. Only disconnect the other end if it is pointing
+	  ** at us!
+	  */
+	  if ( OldUnit == HOST_ID )
+	  {
+	    if ( HostP->Topology[OldLink].Unit == ThisUnit &&
+		 HostP->Topology[OldLink].Link == ThisLink )
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("SETTING HOST (%c) TO DISCONNECTED!\n", OldLink+'A'));
+	      HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT;
+	      HostP->Topology[OldLink].Link = NO_LINK;
+	    }
+	    else
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n",
+		    OldLink+'A',HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'));
+	    }
+	  }
+	  else if ( OldUnit <= MAX_RUP )
+	  {
+	    if ( HostP->Mapping[OldUnit-1].Topology[OldLink].Unit == ThisUnit &&
+	         HostP->Mapping[OldUnit-1].Topology[OldLink].Link == ThisLink )
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("SETTING RTA %s (%c) TO DISCONNECTED!\n",
+				   HostP->Mapping[OldUnit-1].Name,OldLink+'A'));
+	      HostP->Mapping[OldUnit-1].Topology[OldLink].Unit=ROUTE_DISCONNECT;
+	      HostP->Mapping[OldUnit-1].Topology[OldLink].Link=NO_LINK;
+	    }
+	    else
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n",
+			    HostP->Mapping[OldUnit-1].Name,OldLink+'A',
+			    HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'));
+	    }
+	  }
+	  if ( NewUnit == HOST_ID )
+	  {
+	    rio_dprint(RIO_DEBUG_ROUTE, ("MARKING HOST (%c) CONNECTED TO %s (%c)\n",
+				NewLink+'A',MyName,ThisLink+'A'));
+	    HostP->Topology[NewLink].Unit = ThisUnit;
+	    HostP->Topology[NewLink].Link = ThisLink;
+	  }
+	  else if ( NewUnit <= MAX_RUP )
+	  {
+	    rio_dprint(RIO_DEBUG_ROUTE, ("MARKING RTA %s (%c) CONNECTED TO %s (%c)\n",
+	      HostP->Mapping[NewUnit-1].Name,NewLink+'A',MyName,ThisLink+'A'));
+	    HostP->Mapping[NewUnit-1].Topology[NewLink].Unit=ThisUnit;
+	    HostP->Mapping[NewUnit-1].Topology[NewLink].Link=ThisLink;
+	  }
+	}
+	RIOSetChange(p);
+	RIOCheckIsolated(p, HostP, OldUnit );
+      }
+    }
+    return TRUE;
+  }
+
+  /*
+  ** The only other command we recognise is a route_request command
+  */
+  if ( RBYTE(PktCmdP->Command) != ROUTE_REQUEST )
+  {
+    rio_dprint(RIO_DEBUG_ROUTE, ("Unknown command %d received on rup %d host %d ROUTE_RUP\n", 
+	   RBYTE(PktCmdP->Command),Rup,(int)HostP));
+    return TRUE;
+  }
+      
+  RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) +
+	    (RBYTE(PktCmdP->UniqNum[1]) << 8) +
+	    (RBYTE(PktCmdP->UniqNum[2]) << 16) +
+	    (RBYTE(PktCmdP->UniqNum[3]) << 24);
+
+  /*
+  ** Determine if 8 or 16 port RTA
+  */
+  RtaType = GetUnitType(RtaUniq);
+
+  rio_dprint(RIO_DEBUG_ROUTE, ("Received a request for an ID for serial number %x\n", RtaUniq));
+
+  Mod = RBYTE(PktCmdP->ModuleTypes);
+  Mod1 = LONYBLE(Mod);
+  if (RtaType == TYPE_RTA16)
+  {
+    /*
+    ** Only one ident is set for a 16 port RTA. To make compatible
+    ** with 8 port, set 2nd ident in Mod2 to the same as Mod1.
+    */
+    Mod2 = Mod1;
+    rio_dprint(RIO_DEBUG_ROUTE, ("Backplane type is %s (all ports)\n",
+     p->RIOModuleTypes[Mod1].Name ));
+  }
+  else
+  {
+    Mod2 = HINYBLE(Mod);
+    rio_dprint(RIO_DEBUG_ROUTE, ("Module types are %s (ports 0-3) and %s (ports 4-7)\n",
+     p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name ));
+  }
+
+  if ( RtaUniq == 0xffffffff )
+  {
+      ShowPacket( DBG_SPECIAL, PacketP );
+  }
+
+  /*
+  ** try to unhook a command block from the command free list.
+  */
+  if ( !(CmdBlkP = RIOGetCmdBlk()) )
+  {
+    rio_dprint(RIO_DEBUG_ROUTE, ("No command blocks to route RTA! come back later.\n"));
+    return 0;
+  }
+
+  /*
+  ** Fill in the default info on the command block
+  */
+  CmdBlkP->Packet.dest_unit = Rup;
+  CmdBlkP->Packet.dest_port = ROUTE_RUP;
+  CmdBlkP->Packet.src_unit = HOST_ID;
+  CmdBlkP->Packet.src_port = ROUTE_RUP;
+  CmdBlkP->Packet.len = PKT_CMD_BIT | 1;
+  CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
+  PktReplyP = (struct PktCmd_M *)CmdBlkP->Packet.data;
+
+  if (! RIOBootOk(p, HostP, RtaUniq))
+  {
+    rio_dprint(RIO_DEBUG_ROUTE, ("RTA %x tried to get an ID, but does not belong - FOAD it!\n",
+	  RtaUniq));
+    PktReplyP->Command = ROUTE_FOAD;
+    HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7);
+    RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+    return TRUE;
+  }
+
+  /*
+  ** Check to see if the RTA is configured for this host
+  */
+  for ( ThisUnit=0; ThisUnit<MAX_RUP; ThisUnit++ )
+  {
+    rio_dprint(RIO_DEBUG_ROUTE, ("Entry %d Flags=%s %s UniqueNum=0x%x\n",
+			ThisUnit,
+			HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE ?
+					    "Slot-In-Use":"Not In Use",
+			HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? 
+					    "Slot-Tentative":"Not Tentative",
+			HostP->Mapping[ThisUnit].RtaUniqueNum ));
+
+    /*
+    ** We have an entry for it.
+    */
+    if ( (HostP->Mapping[ThisUnit].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) &&
+         (HostP->Mapping[ThisUnit].RtaUniqueNum == RtaUniq) )
+    {
+      if (RtaType == TYPE_RTA16)
+      {
+	  ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1;
+          rio_dprint(RIO_DEBUG_ROUTE, ("Found unit 0x%x at slots %d+%d\n",
+					    RtaUniq,ThisUnit,ThisUnit2));
+      }
+      else
+          rio_dprint(RIO_DEBUG_ROUTE, ("Found unit 0x%x at slot %d\n",
+					    RtaUniq,ThisUnit));
+      /*
+      ** If we have no knowledge of booting it, then the host has
+      ** been re-booted, and so we must kill the RTA, so that it
+      ** will be booted again (potentially with new bins)
+      ** and it will then re-ask for an ID, which we will service.
+      */
+      if ( (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) && 
+	  !(HostP->Mapping[ThisUnit].Flags & RTA_BOOTED) )
+      {
+	if ( !(HostP->Mapping[ThisUnit].Flags & MSG_DONE) )
+	{
+	    if ( !p->RIONoMessage )
+	        cprintf("RTA '%s' is being updated.\n",HostP->Mapping[ThisUnit].Name);
+	    HostP->Mapping[ThisUnit].Flags |= MSG_DONE;
+	}
+	PktReplyP->Command = ROUTE_FOAD;
+	HostP->Copy("RT_FOAD",PktReplyP->CommandText,7);
+	RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+	return TRUE;
+      }
+
+      /*
+      ** Send the ID (entry) to this RTA. The ID number is implicit as
+      ** the offset into the table. It is worth noting at this stage
+      ** that offset zero in the table contains the entries for the
+      ** RTA with ID 1!!!!
+      */
+      PktReplyP->Command = ROUTE_ALLOCATE;
+      PktReplyP->IDNum   = ThisUnit+1;
+      if (RtaType == TYPE_RTA16)
+      {
+        if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE)
+	    /*
+	    ** Adjust the phb and tx pkt dest_units for 2nd block of 8
+	    ** only if the RTA has ports associated (SLOT_IN_USE)
+	    */
+	    RIOFixPhbs(p, HostP, ThisUnit2);
+	    PktReplyP->IDNum2  = ThisUnit2+1;
+	    rio_dprint(RIO_DEBUG_ROUTE, ("RTA '%s' has been allocated IDs %d+%d\n",
+	          HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2));
+      }
+      else
+      {
+	    PktReplyP->IDNum2 = ROUTE_NO_ID;
+	    rio_dprint(RIO_DEBUG_ROUTE, ("RTA '%s' has been allocated ID %d\n",
+	          HostP->Mapping[ThisUnit].Name,PktReplyP->IDNum));
+      }
+      HostP->Copy("RT_ALLOCAT",PktReplyP->CommandText,10);
+
+      RIOQueueCmdBlk( HostP, Rup, CmdBlkP);
+
+      /*
+      ** If this is a freshly booted RTA, then we need to re-open
+      ** the ports, if any where open, so that data may once more
+      ** flow around the system!
+      */
+      if ( (HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) &&
+	   (HostP->Mapping[ThisUnit].SysPort != NO_PORT) )
+      {
+	/*
+	** look at the ports associated with this beast and
+	** see if any where open. If they was, then re-open
+	** them, using the info from the tty flags.
+	*/
+	for ( port=0; port<PORTS_PER_RTA; port++ )
+	{
+	  PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort];
+	  if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) )
+	  {
+	    rio_dprint(RIO_DEBUG_ROUTE, ("Re-opened this port\n"));
+	    rio_spin_lock_irqsave(&PortP->portSem, flags);
+	    PortP->MagicFlags |= MAGIC_REBOOT;
+	    rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	  }
+	}
+	if (RtaType == TYPE_RTA16)
+	{
+	  for ( port=0; port<PORTS_PER_RTA; port++ )
+	  {
+	    PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort];
+	    if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) )
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("Re-opened this port\n"));
+	      rio_spin_lock_irqsave(&PortP->portSem, flags);
+	      PortP->MagicFlags |= MAGIC_REBOOT;
+	      rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	    }
+	  }
+	}
+      }
+
+      /*
+      ** keep a copy of the module types!
+      */
+      HostP->UnixRups[ThisUnit].ModTypes = Mod;
+      if (RtaType == TYPE_RTA16)
+	      HostP->UnixRups[ThisUnit2].ModTypes = Mod;
+
+      /*
+      ** If either of the modules on this unit is read-only or write-only
+      ** or none-xprint, then we need to transfer that info over to the
+      ** relevent ports.
+      */
+      if ( HostP->Mapping[ThisUnit].SysPort != NO_PORT )
+      {
+        for ( port=0; port<PORTS_PER_MODULE; port++ )
+	{
+	  p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
+	  p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]->Config |=
+	   p->RIOModuleTypes[Mod1].Flags[port];
+	  p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
+	  p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
+	}
+	if (RtaType == TYPE_RTA16)
+	{
+          for ( port=0; port<PORTS_PER_MODULE; port++ )
+	  {
+	    p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
+	    p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];
+	    p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
+	    p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
+          }
+	}
+      }
+
+      /*
+      ** Job done, get on with the interrupts!
+      */
+      return TRUE;
+    }
+  }
+  /*
+  ** There is no table entry for this RTA at all.
+  **
+  ** Lets check to see if we actually booted this unit - if not,
+  ** then we reset it and it will go round the loop of being booted
+  ** we can then worry about trying to fit it into the table.
+  */
+  for ( ThisUnit=0; ThisUnit<HostP->NumExtraBooted; ThisUnit++ )
+    if ( HostP->ExtraUnits[ThisUnit] == RtaUniq )
+      break;
+  if ( ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS )
+  {
+    /*
+    ** if the unit wasn't in the table, and the table wasn't full, then
+    ** we reset the unit, because we didn't boot it.
+    ** However, if the table is full, it could be that we did boot
+    ** this unit, and so we won't reboot it, because it isn't really
+    ** all that disasterous to keep the old bins in most cases. This
+    ** is a rather tacky feature, but we are on the edge of reallity
+    ** here, because the implication is that someone has connected
+    ** 16+MAX_EXTRA_UNITS onto one host.
+    */
+    static int UnknownMesgDone = 0;
+
+    if ( !UnknownMesgDone )
+    {
+	if (! p->RIONoMessage)
+	    cprintf("One or more unknown RTAs are being updated.\n");
+	UnknownMesgDone = 1;
+    }
+
+    PktReplyP->Command = ROUTE_FOAD;
+    HostP->Copy("RT_FOAD",PktReplyP->CommandText,7);
+  }
+  else
+  {
+    /*
+    ** we did boot it (as an extra), and there may now be a table
+    ** slot free (because of a delete), so we will try to make
+    ** a tentative entry for it, so that the configurator can see it
+    ** and fill in the details for us.
+    */
+    if (RtaType == TYPE_RTA16)
+    {
+	if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0)
+	{
+	    RIODefaultName(p, HostP, ThisUnit);
+	    FillSlot(ThisUnit, ThisUnit2, RtaUniq, HostP);
+	}
+    }
+    else
+    {
+	if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0)
+	{
+	    RIODefaultName(p, HostP, ThisUnit);
+	    FillSlot(ThisUnit, 0, RtaUniq, HostP);
+	}
+    }
+    PktReplyP->Command = ROUTE_USED;
+    HostP->Copy("RT_USED",PktReplyP->CommandText,7);
+  }
+  RIOQueueCmdBlk( HostP, Rup, CmdBlkP);
+  return TRUE;
+}
+
+
+void
+RIOFixPhbs(p, HostP, unit)
+struct rio_info *p;
+struct Host *HostP;
+uint unit;
+{
+	ushort			link, port;
+	struct Port		*PortP;
+	unsigned long flags;
+	int PortN = HostP->Mapping[unit].SysPort;
+
+	rio_dprint(RIO_DEBUG_ROUTE, ("RIOFixPhbs unit %d sysport %d\n", unit, PortN));
+
+	if (PortN != -1) {
+		ushort		dest_unit = HostP->Mapping[unit].ID2;
+
+		/*
+		** Get the link number used for the 1st 8 phbs on this unit.
+		*/
+		PortP = p->RIOPortp[HostP->Mapping[dest_unit - 1].SysPort];
+
+		link = RWORD(PortP->PhbP->link);
+
+		for (port = 0; port < PORTS_PER_RTA; port++, PortN++) {
+			ushort		dest_port = port + 8;
+#if 0
+			uint		PktInt;
+#endif
+			WORD		*TxPktP;
+			PKT		*Pkt;
+
+			PortP = p->RIOPortp[PortN];
+
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+			/*
+			** If RTA is not powered on, the tx packets will be
+			** unset, so go no further.
+			*/
+			if (PortP->TxStart == 0) {
+					rio_dprint(RIO_DEBUG_ROUTE, ("Tx pkts not set up yet\n"));
+					break;
+			}
+
+			/*
+			** For the second slot of a 16 port RTA, the driver needs to
+			** sort out the phb to port mappings. The dest_unit for this
+			** group of 8 phbs is set to the dest_unit of the accompanying
+			** 8 port block. The dest_port of the second unit is set to
+			** be in the range 8-15 (i.e. 8 is added). Thus, for a 16 port
+			** RTA with IDs 5 and 6, traffic bound for port 6 of unit 6
+			** (being the second map ID) will be sent to dest_unit 5, port
+			** 14. When this RTA is deleted, dest_unit for ID 6 will be
+			** restored, and the dest_port will be reduced by 8.
+			** Transmit packets also have a destination field which needs
+			** adjusting in the same manner.
+			** Note that the unit/port bytes in 'dest' are swapped.
+			** We also need to adjust the phb and rup link numbers for the
+			** second block of 8 ttys.
+			*/
+			for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) {
+				/*
+				** *TxPktP is the pointer to the transmit packet on the host
+				** card. This needs to be translated into a 32 bit pointer
+				** so it can be accessed from the driver.
+				*/
+				Pkt = (PKT *) RIO_PTR(HostP->Caddr,RINDW(TxPktP));
+
+				/*
+				** If the packet is used, reset it.
+				*/
+				Pkt = (PKT *)((uint)Pkt & ~PKT_IN_USE);
+				WBYTE(Pkt->dest_unit, dest_unit);
+				WBYTE(Pkt->dest_port, dest_port);
+			}
+			rio_dprint(RIO_DEBUG_ROUTE, ("phb dest: Old %x:%x New %x:%x\n",
+					RWORD(PortP->PhbP->destination) & 0xff,
+					(RWORD(PortP->PhbP->destination) >> 8) & 0xff,
+					dest_unit, dest_port));
+			WWORD(PortP->PhbP->destination, dest_unit + (dest_port << 8));
+			WWORD(PortP->PhbP->link, link);
+
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		}
+		/*
+		** Now make sure the range of ports to be serviced includes
+		** the 2nd 8 on this 16 port RTA.
+		*/
+		if (link > 3) return;
+		if (((unit * 8) + 7) > RWORD(HostP->LinkStrP[link].last_port)) {
+			rio_dprint(RIO_DEBUG_ROUTE, ("last port on host link %d: %d\n", link, (unit * 8) + 7));
+			WWORD(HostP->LinkStrP[link].last_port, (unit * 8) + 7);
+		}
+	}
+}
+
+/*
+** Check to see if the new disconnection has isolated this unit.
+** If it has, then invalidate all its link information, and tell
+** the world about it. This is done to ensure that the configurator
+** only gets up-to-date information about what is going on.
+*/
+int
+RIOCheckIsolated(p, HostP, UnitId)
+struct rio_info *	p;
+struct Host *HostP;
+uint UnitId;
+{
+	unsigned long flags;
+	rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckUnitId( UnitId );
+#endif
+	if ( RIOCheck( HostP, UnitId ) ) {
+		rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated\n",UnitId));
+		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+		return(0);
+	}
+
+	RIOIsolate(p, HostP, UnitId );
+	RIOSetChange(p);
+	rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+	return 1;
+}
+
+/*
+** Invalidate all the link interconnectivity of this unit, and of
+** all the units attached to it. This will mean that the entire
+** subnet will re-introduce itself.
+*/
+int
+RIOIsolate(p, HostP, UnitId)
+struct rio_info *	p;
+struct Host *		HostP;
+uint UnitId; 
+{
+	uint link, unit;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckUnitId( UnitId );
+#endif
+	UnitId--;		/* this trick relies on the Unit Id being UNSIGNED! */
+
+	if ( UnitId > MAX_RUP )		/* dontcha just lurv unsigned maths! */
+		return(0);
+
+	if ( HostP->Mapping[UnitId].Flags & BEEN_HERE )
+		return(0);
+
+	HostP->Mapping[UnitId].Flags |= BEEN_HERE;
+
+	if ( p->RIOPrintDisabled == DO_PRINT )
+		rio_dprint(RIO_DEBUG_ROUTE, ("RIOMesgIsolated %s",HostP->Mapping[UnitId].Name));
+
+	for ( link=0; link<LINKS_PER_UNIT; link++) {
+		unit = HostP->Mapping[UnitId].Topology[link].Unit;
+		HostP->Mapping[UnitId].Topology[link].Unit = ROUTE_DISCONNECT;
+		HostP->Mapping[UnitId].Topology[link].Link = NO_LINK;
+		RIOIsolate(p, HostP, unit );
+	}
+	HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+	return 1;
+}
+
+int
+RIOCheck(HostP, UnitId)
+struct Host *HostP;
+uint UnitId;
+{
+  unsigned char link;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckUnitId( UnitId );
+#endif
+/* 	rio_dprint(RIO_DEBUG_ROUTE, ("Check to see if unit %d has a route to the host\n",UnitId)); */
+	rio_dprint(RIO_DEBUG_ROUTE, ("RIOCheck : UnitID = %d\n",UnitId));
+
+	if ( UnitId == HOST_ID ) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated - it IS the host!\n", UnitId)); */
+		return 1;
+	}
+
+	UnitId--;
+
+	if ( UnitId >= MAX_RUP ) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d - ignored.\n", UnitId)); */
+		return 0;
+	}
+
+	for ( link=0; link<LINKS_PER_UNIT; link++ ) {
+		if ( HostP->Mapping[UnitId].Topology[link].Unit==HOST_ID ) {
+			/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected directly to host via link (%c).\n", 
+						UnitId, 'A'+link)); */
+			return 1;
+		}
+	}
+
+	if ( HostP->Mapping[UnitId].Flags & BEEN_HERE ) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Been to Unit %d before - ignoring\n", UnitId)); */
+		return 0;
+	}
+
+	HostP->Mapping[UnitId].Flags |= BEEN_HERE;
+
+	for ( link=0; link < LINKS_PER_UNIT; link++ ) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d check link (%c)\n", UnitId,'A'+link)); */
+		if ( RIOCheck( HostP, HostP->Mapping[UnitId].Topology[link].Unit ) ) {
+			/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected to something that knows the host via link (%c)\n", UnitId,link+'A')); */
+			HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+			return 1;
+		}
+	}
+
+	HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+
+	/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d DOESNT KNOW THE HOST!\n", UnitId)); */
+	
+	return 0;
+}
+
+/*
+** Returns the type of unit (host, 16/8 port RTA)
+*/
+
+uint
+GetUnitType(Uniq)
+uint Uniq;
+{
+	switch ( (Uniq >> 28) & 0xf)
+	{
+		case RIO_AT:
+		case RIO_MCA:
+		case RIO_EISA:
+		case RIO_PCI:
+			rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: Host\n"));
+			return(TYPE_HOST);
+		case RIO_RTA_16:
+			rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: 16 port RTA\n"));
+			return(TYPE_RTA16);
+		case RIO_RTA:
+			rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: 8 port RTA\n"));
+			return(TYPE_RTA8);
+		default :
+			rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: Unrecognised\n"));
+			return(99);
+	}
+}
+
+int
+RIOSetChange(p)
+struct rio_info *	p;
+{
+	if ( p->RIOQuickCheck != NOT_CHANGED )
+		return(0);
+	p->RIOQuickCheck = CHANGED;
+	if ( p->RIOSignalProcess ) {
+		rio_dprint(RIO_DEBUG_ROUTE, ("Send SIG-HUP"));
+		/*
+		psignal( RIOSignalProcess, SIGHUP );
+		*/
+	}
+	return(0);
+}
+
+void
+RIOConCon(p, HostP, FromId, FromLink, ToId, ToLink, Change)
+struct rio_info *	p;
+struct Host *HostP;
+uint FromId;
+uint FromLink;
+uint ToId;
+uint ToLink;
+int Change; 
+{
+    char *FromName;
+    char *FromType;
+    char *ToName;
+    char *ToType;
+    unsigned int tp;
+
+/*
+** 15.10.1998 ARG - ESIL 0759
+** (Part) fix for port being trashed when opened whilst RTA "disconnected"
+**
+** What's this doing in here anyway ?
+** It was causing the port to be 'unmapped' if opened whilst RTA "disconnected"
+**
+** 09.12.1998 ARG - ESIL 0776 - part fix
+** Okay, We've found out what this was all about now !
+** Someone had botched this to use RIOHalted to indicated the number of RTAs
+** 'disconnected'. The value in RIOHalted was then being used in the
+** 'RIO_QUICK_CHECK' ioctl. A none zero value indicating that a least one RTA
+** is 'disconnected'. The change was put in to satisfy a customer's needs.
+** Having taken this bit of code out 'RIO_QUICK_CHECK' now no longer works for
+** the customer.
+**
+    if (Change == CONNECT) {
+		if (p->RIOHalted) p->RIOHalted --;
+	 }
+	 else {
+		p->RIOHalted ++;
+	 }
+**
+** So - we need to implement it slightly differently - a new member of the
+** rio_info struct - RIORtaDisCons (RIO RTA connections) keeps track of RTA
+** connections and disconnections. 
+*/
+    if (Change == CONNECT) {
+		if (p->RIORtaDisCons) p->RIORtaDisCons--;
+	 }
+	 else {
+		p->RIORtaDisCons++;
+	 }
+
+    if ( p->RIOPrintDisabled == DONT_PRINT )
+		return;
+
+    if ( FromId > ToId ) {
+		tp = FromId;
+		FromId = ToId;
+		ToId = tp;
+		tp = FromLink;
+		FromLink = ToLink;
+		ToLink = tp;
+    }
+
+    FromName = FromId ? HostP->Mapping[FromId-1].Name : HostP->Name;
+    FromType = FromId ? "RTA" : "HOST";
+    ToName = ToId ? HostP->Mapping[ToId-1].Name : HostP->Name;
+    ToType = ToId ? "RTA" : "HOST";
+
+    rio_dprint(RIO_DEBUG_ROUTE, ("Link between %s '%s' (%c) and %s '%s' (%c) %s.\n",
+			    FromType, FromName, 'A'+FromLink,
+			    ToType,   ToName,   'A'+ToLink,
+			    (Change==CONNECT) ? "established" : "disconnected"));
+    cprintf("Link between %s '%s' (%c) and %s '%s' (%c) %s.\n",
+			    FromType, FromName, 'A'+FromLink,
+			    ToType,   ToName,   'A'+ToLink,
+			    (Change==CONNECT) ? "established" : "disconnected");
+}
+
+/*
+** RIORemoveFromSavedTable :
+**
+** Delete and RTA entry from the saved table given to us
+** by the configuration program.
+*/
+int
+RIORemoveFromSavedTable(struct rio_info *p, struct Map *pMap)
+{
+    int		entry;
+
+    /*
+    ** We loop for all entries even after finding an entry and
+    ** zeroing it because we may have two entries to delete if
+    ** its a 16 port RTA.
+    */
+    for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++)
+    {
+	if (p->RIOSavedTable[entry].RtaUniqueNum == pMap->RtaUniqueNum)
+	{
+	    bzero((caddr_t)&p->RIOSavedTable[entry], sizeof(struct Map));
+	}
+    }
+    return 0;
+}
+
+
+/*
+** RIOCheckDisconnected :
+**
+** Scan the unit links to and return zero if the unit is completely
+** disconnected.
+*/
+int
+RIOFreeDisconnected(struct rio_info *p, struct Host *HostP, int unit)
+{
+    int		link;
+
+
+    rio_dprint(RIO_DEBUG_ROUTE, ("RIOFreeDisconnect unit %d\n",unit));
+    /*
+    ** If the slot is tentative and does not belong to the
+    ** second half of a 16 port RTA then scan to see if
+    ** is disconnected.
+    */
+    for (link = 0; link < LINKS_PER_UNIT; link++)
+    {
+	if (HostP->Mapping[unit].Topology[link].Unit != ROUTE_DISCONNECT)
+	    break;
+    }
+
+    /*
+    ** If not all links are disconnected then we can forget about it.
+    */
+    if (link < LINKS_PER_UNIT)
+	    return 1;
+
+#if NEED_TO_FIX_THIS
+    /* Ok so all the links are disconnected. But we may have only just
+    ** made this slot tentative and not yet received a topology update.
+    ** Lets check how long ago we made it tentative.
+    */
+    rio_dprint(RIO_DEBUG_ROUTE, ("Just about to check LBOLT on entry %d\n",unit));
+    if (drv_getparm(LBOLT, (ulong_t *) &current_time))
+        rio_dprint(RIO_DEBUG_ROUTE, ("drv_getparm(LBOLT,....) Failed.\n"));
+
+    elapse_time = current_time - TentTime[unit];
+    rio_dprint(RIO_DEBUG_ROUTE, ("elapse %d = current %d - tent %d (%d usec)\n",
+        elapse_time, current_time, TentTime[unit],drv_hztousec(elapse_time)));
+    if (drv_hztousec(elapse_time) < WAIT_TO_FINISH)
+    {
+        rio_dprint(RIO_DEBUG_ROUTE, ("Skipping slot %d, not timed out yet %d\n"
+            ,unit,drv_hztousec(elapse_time)));
+        return 1;
+    }
+#endif
+
+    /*
+    ** We have found an usable slot.
+    ** If it is half of a 16 port RTA then delete the other half.
+    */
+    if (HostP->Mapping[unit].ID2 != 0)
+    {
+	int nOther = (HostP->Mapping[unit].ID2) -1;
+
+	rio_dprint(RIO_DEBUG_ROUTE, ("RioFreedis second slot %d.\n",nOther));
+	bzero((caddr_t)&HostP->Mapping[nOther], sizeof(struct Map));
+    }
+    RIORemoveFromSavedTable(p, &HostP->Mapping[unit]);
+
+    return 0;
+}
+
+
+/*
+** RIOFindFreeID :
+**
+** This function scans the given host table for either one
+** or two free unit ID's.
+*/
+int
+RIOFindFreeID(struct rio_info *p, struct Host *HostP, uint *pID1, uint *pID2)
+{
+    int unit,tempID;
+
+    /*
+    ** Initialise the ID's to MAX_RUP.
+    ** We do this to make the loop for setting the ID's as simple as
+    ** possible.
+    */
+    *pID1 = MAX_RUP;
+    if (pID2 != NULL)
+	*pID2 = MAX_RUP;
+
+    /*
+    ** Scan all entries of the host mapping table for free slots.
+    ** We scan for free slots first and then if that is not successful
+    ** we start all over again looking for tentative slots we can re-use.
+    */
+    for (unit = 0; unit < MAX_RUP; unit++)
+    {
+	rio_dprint(RIO_DEBUG_ROUTE, ("Scanning unit %d\n",unit));
+	/*
+	** If the flags are zero then the slot is empty.
+	*/
+	if (HostP->Mapping[unit].Flags == 0)
+	{
+	    rio_dprint(RIO_DEBUG_ROUTE, ("      This slot is empty.\n"));
+	    /*
+	    ** If we haven't allocated the first ID then do it now.
+	    */
+	    if (*pID1 == MAX_RUP)
+	    {
+		rio_dprint(RIO_DEBUG_ROUTE, ("Make tentative entry for first unit %d\n", unit));
+		*pID1 = unit;
+
+		/*
+		** If the second ID is not needed then we can return
+		** now.
+		*/
+		if (pID2 == NULL)
+		    return 0;
+	    }
+	    else
+	    {
+		/*
+		** Allocate the second slot and return.
+		*/
+		rio_dprint(RIO_DEBUG_ROUTE, ("Make tentative entry for second unit %d\n", unit));
+		*pID2 = unit;
+		return 0;
+	    }
+	}
+    }
+
+    /*
+    ** If we manage to come out of the free slot loop then we
+    ** need to start all over again looking for tentative slots
+    ** that we can re-use.
+    */
+    rio_dprint(RIO_DEBUG_ROUTE, ("Starting to scan for tentative slots\n"));
+    for (unit = 0; unit < MAX_RUP; unit++)
+    {
+	if (((HostP->Mapping[unit].Flags & SLOT_TENTATIVE) ||
+	                       (HostP->Mapping[unit].Flags == 0))  && ! 
+	   (HostP->Mapping[unit].Flags & RTA16_SECOND_SLOT ))
+	{
+	    rio_dprint(RIO_DEBUG_ROUTE, ("    Slot %d looks promising.\n",unit));
+
+	    if(unit == *pID1)
+	    {
+	    	rio_dprint(RIO_DEBUG_ROUTE, ("    No it isn't, its the 1st half\n"));
+		continue;
+	    }
+
+	    /*
+	    ** Slot is Tentative or Empty, but not a tentative second 
+	    ** slot of a 16 porter.
+	    ** Attempt to free up this slot (and its parnter if
+	    ** it is a 16 port slot. The second slot will become
+	    ** empty after a call to RIOFreeDisconnected so thats why
+	    ** we look for empty slots above  as well).
+	    */
+	    if (HostP->Mapping[unit].Flags != 0) 
+	    	if (RIOFreeDisconnected(p, HostP, unit) != 0)
+			    continue;
+	    /*
+	    ** If we haven't allocated the first ID then do it now.
+	    */
+	    if (*pID1 == MAX_RUP)
+	    {
+		rio_dprint(RIO_DEBUG_ROUTE, ("Grab tentative entry for first unit %d\n", unit));
+		*pID1 = unit;
+
+		/*
+		** Clear out this slot now that we intend to use it.
+		*/
+		bzero(&HostP->Mapping[unit], sizeof(struct Map));
+
+		/*
+		** If the second ID is not needed then we can return
+		** now.
+		*/
+		if (pID2 == NULL)
+		    return 0;
+	    }
+	    else
+	    {
+		/*
+		** Allocate the second slot and return.
+		*/
+		rio_dprint(RIO_DEBUG_ROUTE, ("Grab tentative/empty  entry for second unit %d\n",
+		      unit));
+		*pID2 = unit;
+
+		/*
+		** Clear out this slot now that we intend to use it.
+		*/
+		bzero(&HostP->Mapping[unit], sizeof(struct Map));
+
+		/* At this point under the right(wrong?) conditions
+		** we may have a first unit ID being higher than the
+		** second unit ID. This is a bad idea if we are about
+		** to fill the slots with a 16 port RTA.
+		** Better check and swap them over.
+		*/
+
+		if (*pID1 > *pID2)
+		{
+			rio_dprint(RIO_DEBUG_ROUTE, ("Swapping IDS %d %d\n",*pID1,*pID2));
+			tempID = *pID1;
+			*pID1 = *pID2;
+			*pID2 = tempID;
+		}
+		return 0;
+	    }
+	}
+    }
+
+    /*
+    ** If we manage to get to the end of the second loop then we
+    ** can give up and return a failure.
+    */
+    return 1;
+}
+
+
+/*
+** The link switch scenario.
+**
+** Rta Wun (A) is connected to Tuw (A).
+** The tables are all up to date, and the system is OK.
+**
+** If Wun (A) is now moved to Wun (B) before Wun (A) can
+** become disconnected, then the follow happens:
+**
+** Tuw (A) spots the change of unit:link at the other end
+** of its link and Tuw sends a topology packet reflecting
+** the change: Tuw (A) now disconnected from Wun (A), and
+** this is closely followed by a packet indicating that 
+** Tuw (A) is now connected to Wun (B).
+**
+** Wun (B) will spot that it has now become connected, and
+** Wun will send a topology packet, which indicates that
+** both Wun (A) and Wun (B) is connected to Tuw (A).
+**
+** Eventually Wun (A) realises that it is now disconnected
+** and Wun will send out a topology packet indicating that
+** Wun (A) is now disconnected.
+*/
diff -urN linux-2.2.15-pre2/drivers/char/rio/riospace.h linux/drivers/char/rio/riospace.h
--- linux-2.2.15-pre2/drivers/char/rio/riospace.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riospace.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,161 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riospace.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)riospace.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_riospace_h__
+#define __rio_riospace_h__
+
+#ifdef SCCS_LABELS
+static char *_riospace_h_sccs_ = "@(#)riospace.h	1.2";
+#endif
+
+#define	RIO_LOCATOR_LEN	16
+#define	MAX_RIO_BOARDS	4
+
+/*
+** DONT change this file. At all. Unless you can rebuild the entire
+** device driver, which you probably can't, then the rest of the
+** driver won't see any changes you make here. So don't make any.
+** In particular, it won't be able to see changes to RIO_SLOTS
+*/
+
+struct Conf
+{
+	char         Locator[24];
+	unsigned int StartupTime;
+	unsigned int SlowCook;
+	unsigned int IntrPollTime;
+	unsigned int BreakInterval;
+	unsigned int Timer;
+	unsigned int RtaLoadBase;
+	unsigned int HostLoadBase;
+	unsigned int XpHz;
+	unsigned int XpCps;
+	char         *XpOn;
+	char         *XpOff;
+	unsigned int MaxXpCps;
+	unsigned int MinXpCps;
+	unsigned int SpinCmds;
+	unsigned int FirstAddr;
+	unsigned int LastAddr;
+	unsigned int BufferSize;
+	unsigned int LowWater;
+	unsigned int LineLength;
+	unsigned int CmdTime;
+};
+
+/*
+**	Board types - these MUST correspond to product codes!
+*/ 
+#define	RIO_EMPTY	0x0
+#define	RIO_EISA	0x3
+#define	RIO_RTA_16	0x9
+#define	RIO_AT		0xA
+#define	RIO_MCA		0xB
+#define	RIO_PCI		0xD
+#define	RIO_RTA		0xE
+
+/*
+**	Board data structure. This is used for configuration info
+*/
+struct	Brd
+{
+    unsigned char Type;	/* RIO_EISA, RIO_MCA, RIO_AT, RIO_EMPTY... */
+    unsigned char Ivec;	/* POLLED or ivec number */
+    unsigned char Mode;	/* Control stuff, see below */
+};
+
+struct	Board
+{
+    char       Locator[RIO_LOCATOR_LEN];
+    int        NumSlots;
+    struct Brd Boards[MAX_RIO_BOARDS];
+};
+
+#define	BOOT_FROM_LINK		0x00
+#define	BOOT_FROM_RAM		0x01
+#define	EXTERNAL_BUS_OFF	0x00
+#define	EXTERNAL_BUS_ON		0x02
+#define	INTERRUPT_DISABLE	0x00
+#define	INTERRUPT_ENABLE	0x04
+#define	BYTE_OPERATION		0x00
+#define	WORD_OPERATION		0x08
+#define	POLLED			INTERRUPT_DISABLE
+#define	IRQ_15			(0x00 | INTERRUPT_ENABLE)
+#define	IRQ_12			(0x10 | INTERRUPT_ENABLE)
+#define	IRQ_11			(0x20 | INTERRUPT_ENABLE)
+#define	IRQ_9			(0x30 | INTERRUPT_ENABLE)
+#define	SLOW_LINKS		0x00
+#define	FAST_LINKS		0x40
+#define	SLOW_AT_BUS		0x00
+#define	FAST_AT_BUS		0x80
+#define	SLOW_PCI_TP		0x00
+#define	FAST_PCI_TP		0x80
+/*
+**	Debug levels
+*/
+#define	DBG_NONE	0x00000000
+
+#define	DBG_INIT	0x00000001
+#define	DBG_OPEN	0x00000002
+#define	DBG_CLOSE	0x00000004
+#define	DBG_IOCTL	0x00000008
+
+#define	DBG_READ	0x00000010
+#define	DBG_WRITE	0x00000020
+#define	DBG_INTR	0x00000040
+#define	DBG_PROC	0x00000080
+
+#define	DBG_PARAM	0x00000100
+#define	DBG_CMD		0x00000200
+#define	DBG_XPRINT	0x00000400
+#define	DBG_POLL	0x00000800
+
+#define	DBG_DAEMON	0x00001000
+#define	DBG_FAIL	0x00002000
+#define DBG_MODEM	0x00004000
+#define	DBG_LIST	0x00008000
+
+#define	DBG_ROUTE	0x00010000
+#define DBG_UTIL        0x00020000
+#define DBG_BOOT	0x00040000
+#define DBG_BUFFER	0x00080000
+
+#define	DBG_MON		0x00100000
+#define DBG_SPECIAL     0x00200000
+#define	DBG_VPIX	0x00400000
+#define	DBG_FLUSH	0x00800000
+
+#define	DBG_QENABLE	0x01000000
+
+#define	DBG_ALWAYS	0x80000000
+
+#endif /* __rio_riospace_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/riotable.c linux/drivers/char/rio/riotable.c
--- linux-2.2.15-pre2/drivers/char/rio/riotable.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riotable.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1058 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riotable.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:47
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)riotable.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riotable_c_sccs_ = "@(#)riotable.c	1.2";
+#endif
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+#include "protsts.h"
+
+/*
+** A configuration table has been loaded. It is now up to us
+** to sort it out and use the information contained therein.
+*/
+int
+RIONewTable(p)
+struct rio_info *	p;
+{
+	int Host, Host1, Host2, NameIsUnique, Entry, SubEnt;
+	struct Map *MapP;
+	struct Map *HostMapP;
+	struct Host *HostP;
+
+	char *cptr;
+
+	/*
+	** We have been sent a new table to install. We need to break
+	** it down into little bits and spread it around a bit to see
+	** what we have got.
+	*/
+	/*
+	** Things to check:
+	** (things marked 'xx' aren't checked any more!)
+	** (1)	That there are no booted Hosts/RTAs out there.
+	** (2)	That the names are properly formed
+	** (3)	That blank entries really are.
+	** xx (4)	That hosts mentioned in the table actually exist. xx
+	** (5)	That the IDs are unique (per host).
+	** (6)	That host IDs are zero
+	** (7)	That port numbers are valid
+	** (8)	That port numbers aren't duplicated
+	** (9)	That names aren't duplicated
+	** xx (10) That hosts that actually exist are mentioned in the table. xx
+	*/
+	rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(1)\n")); 
+	if ( p->RIOSystemUp ) {		/* (1) */
+		p->RIOError.Error = HOST_HAS_ALREADY_BEEN_BOOTED;
+		return EBUSY;
+	}
+
+	p->RIOError.Error = NOTHING_WRONG_AT_ALL;
+	p->RIOError.Entry = -1;
+	p->RIOError.Other = -1;
+
+	for ( Entry=0; Entry<TOTAL_MAP_ENTRIES; Entry++ ) {
+		MapP = &p->RIOConnectTable[Entry];
+		if ((MapP->Flags & RTA16_SECOND_SLOT) == 0) {
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(2)\n"));
+			cptr = MapP->Name;		/* (2) */
+			cptr[MAX_NAME_LEN-1]='\0';
+			if ( cptr[0]=='\0' ) {
+				bcopy(MapP->RtaUniqueNum?"RTA	NN":"HOST NN",MapP->Name,8);
+				MapP->Name[5] = '0'+Entry/10;
+				MapP->Name[6] = '0'+Entry%10;
+			}
+			while ( *cptr ) {
+				if ( *cptr<' ' || *cptr>'~' ) {
+					p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+					p->RIOError.Entry = Entry;
+					return ENXIO;
+				}
+				cptr++;
+			}
+		}
+
+		/*
+		** If the entry saved was a tentative entry then just forget
+		** about it.
+		*/
+		if ( MapP->Flags & SLOT_TENTATIVE ) {
+			MapP->HostUniqueNum = 0;
+			MapP->RtaUniqueNum = 0;
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(3)\n"));
+		if ( !MapP->RtaUniqueNum && !MapP->HostUniqueNum ) { /* (3) */
+			if ( MapP->ID || MapP->SysPort || MapP->Flags ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("%s pretending to be empty but isn't\n",MapP->Name));
+				p->RIOError.Error = TABLE_ENTRY_ISNT_PROPERLY_NULL;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("!RIO: Daemon: test (3) passes\n"));
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(4)\n"));
+		for ( Host=0; Host<p->RIONumHosts; Host++ ) { /* (4) */
+			if ( p->RIOHosts[Host].UniqueNum==MapP->HostUniqueNum ) {
+				HostP = &p->RIOHosts[Host];
+				/*
+				** having done the lookup, we don't really want to do
+				** it again, so hang the host number in a safe place
+				*/
+				MapP->Topology[0].Unit = Host;
+				break;
+			}
+		}
+
+		if ( Host >= p->RIONumHosts ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has unknown host unique number 0x%x\n",
+									MapP->Name,MapP->HostUniqueNum));
+			MapP->HostUniqueNum = 0;
+			/* MapP->RtaUniqueNum	= 0; */
+			/* MapP->ID			= 0; */
+			/* MapP->Flags		 = 0; */
+			/* MapP->SysPort		 = 0; */
+			/* MapP->Name[0]		 = 0; */
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(5)\n")); 
+		if ( MapP->RtaUniqueNum ) { /* (5) */
+			if ( !MapP->ID ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an ID of zero!\n",
+							MapP->Name));
+				p->RIOError.Error		 = ZERO_RTA_ID;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			if ( MapP->ID > MAX_RUP ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an illegal ID %d\n",
+							MapP->Name, MapP->ID));
+				p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			for ( SubEnt=0; SubEnt<Entry; SubEnt++ ) {
+				if ( MapP->HostUniqueNum == 
+						p->RIOConnectTable[SubEnt].HostUniqueNum && 
+						MapP->ID == p->RIOConnectTable[SubEnt].ID ) {
+					rio_dprint(RIO_DEBUG_TABLE, ("Dupl. ID number allocated to RTA %s and RTA %s\n",
+							MapP->Name,p->RIOConnectTable[SubEnt].Name));
+					p->RIOError.Error = DUPLICATED_RTA_ID;
+					p->RIOError.Entry = Entry;
+					p->RIOError.Other = SubEnt;
+					return ENXIO;
+				}
+				/*
+				** If the RtaUniqueNum is the same, it may be looking at both
+				** entries for a 16 port RTA, so check the ids
+				*/
+				if ((MapP->RtaUniqueNum == 
+						p->RIOConnectTable[SubEnt].RtaUniqueNum)
+				 		&& (MapP->ID2 != p->RIOConnectTable[SubEnt].ID)) {
+					rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n",MapP->Name));
+					rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n",
+										p->RIOConnectTable[SubEnt].Name));
+					p->RIOError.Error = DUPLICATE_UNIQUE_NUMBER;
+					p->RIOError.Entry = Entry;
+					p->RIOError.Other = SubEnt;
+					return ENXIO;
+				}
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7a)\n")); 
+			/* (7a) */
+			if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort % PORTS_PER_RTA)) {
+				rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d-RTA %s is not a multiple of %d!\n",
+					(int)MapP->SysPort,MapP->Name,PORTS_PER_RTA));
+				p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7b)\n")); 
+			/* (7b) */
+			if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort >= RIO_PORTS)) {
+				rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d for RTA %s is too big\n",
+							(int)MapP->SysPort,MapP->Name));
+				p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			for ( SubEnt=0; SubEnt<Entry; SubEnt++ ) {
+				if ( p->RIOConnectTable[SubEnt].Flags & RTA16_SECOND_SLOT )
+						continue;
+				if ( p->RIOConnectTable[SubEnt].RtaUniqueNum ) {
+					rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(8)\n")); 
+					/* (8) */
+					if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort == 
+									p->RIOConnectTable[SubEnt].SysPort) ) {
+						rio_dprint(RIO_DEBUG_TABLE, ("RTA %s:same TTY port # as RTA %s (%d)\n",
+							MapP->Name, p->RIOConnectTable[SubEnt].Name,
+							(int)MapP->SysPort));
+						p->RIOError.Error = TTY_NUMBER_IN_USE;
+						p->RIOError.Entry = Entry;
+						p->RIOError.Other = SubEnt;
+						return ENXIO;
+					}
+					rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(9)\n")); 
+					if (RIOStrCmp(MapP->Name,
+							p->RIOConnectTable[SubEnt].Name)==0 && !(MapP->Flags & RTA16_SECOND_SLOT)) { /* (9) */
+						rio_dprint(RIO_DEBUG_TABLE, ("RTA name %s used twice\n",MapP->Name));
+						p->RIOError.Error = NAME_USED_TWICE;
+						p->RIOError.Entry = Entry;
+						p->RIOError.Other = SubEnt;
+						return ENXIO;
+					}
+				}
+			}
+		}
+		else { /* (6) */
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(6)\n")); 
+			if ( MapP->ID ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO:HOST %s has been allocated ID that isn't zero!\n",
+					MapP->Name));
+				p->RIOError.Error = HOST_ID_NOT_ZERO;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			if ( MapP->SysPort != NO_PORT ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: HOST %s has been allocated port numbers!\n",
+					MapP->Name));
+				p->RIOError.Error = HOST_SYSPORT_BAD;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+		}
+	}
+
+	/*
+	** wow! if we get here then its a goody!
+	*/
+
+	/*
+	** Zero the (old) entries for each host...
+	*/
+	for ( Host=0; Host<RIO_HOSTS; Host++ ) {
+		for ( Entry=0; Entry<MAX_RUP; Entry++ ) {
+			bzero((caddr_t)&p->RIOHosts[Host].Mapping[Entry], 
+											sizeof(struct Map));
+		}
+		bzero((caddr_t)&p->RIOHosts[Host].Name[0],
+								sizeof(p->RIOHosts[Host].Name) );
+	}
+
+	/*
+	** Copy in the new table entries
+	*/
+	for ( Entry=0; Entry< TOTAL_MAP_ENTRIES; Entry++ ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: Copy table for Host entry %d\n", Entry));
+		MapP = &p->RIOConnectTable[Entry];
+
+		/*
+		** Now, if it is an empty slot ignore it!
+		*/
+		if ( MapP->HostUniqueNum==0 )
+			continue;
+
+		/*
+		** we saved the host number earlier, so grab it back
+		*/
+		HostP = &p->RIOHosts[MapP->Topology[0].Unit];
+
+		/*
+		** If it is a host, then we only need to fill in the name field.
+		*/
+		if ( MapP->ID==0 ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Host entry found. Name %s\n",MapP->Name));
+			bcopy(MapP->Name,HostP->Name,MAX_NAME_LEN);
+			continue;
+		}
+
+		/*
+		** Its an RTA entry, so fill in the host mapping entries for it
+		** and the port mapping entries. Notice that entry zero is for
+		** ID one.
+		*/
+		HostMapP = &HostP->Mapping[MapP->ID-1];
+
+		if (MapP->Flags & SLOT_IN_USE) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Rta entry found. Name %s\n",MapP->Name));
+			/*
+			** structure assign, then sort out the bits we shouldn't have done
+			*/
+			*HostMapP = *MapP;
+
+			HostMapP->Flags = SLOT_IN_USE;
+			if (MapP->Flags & RTA16_SECOND_SLOT)
+				HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+			RIOReMapPorts(p, HostP, HostMapP );
+		}
+		else {
+			rio_dprint(RIO_DEBUG_TABLE, ("TENTATIVE Rta entry found. Name %s\n",MapP->Name));
+		}
+	}
+
+	for ( Entry=0; Entry< TOTAL_MAP_ENTRIES; Entry++ ) {
+		p->RIOSavedTable[Entry] = p->RIOConnectTable[Entry];
+	}
+
+	for ( Host=0; Host<p->RIONumHosts; Host++ ) {
+		for ( SubEnt=0; SubEnt<LINKS_PER_UNIT; SubEnt++ ) {
+			p->RIOHosts[Host].Topology[SubEnt].Unit = ROUTE_DISCONNECT;
+			p->RIOHosts[Host].Topology[SubEnt].Link = NO_LINK;
+		}
+		for ( Entry=0; Entry<MAX_RUP; Entry++ ) {
+			for ( SubEnt=0; SubEnt<LINKS_PER_UNIT; SubEnt++ ) {
+				p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Unit = 
+								ROUTE_DISCONNECT;
+				p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Link = 
+								NO_LINK;
+			}
+		}
+		if ( !p->RIOHosts[Host].Name[0] ) {
+			bcopy("HOST 1",p->RIOHosts[Host].Name,7);
+			p->RIOHosts[Host].Name[5] += Host;
+		}
+		/*
+		** Check that default name assigned is unique.
+		*/
+		Host1 = Host;
+		NameIsUnique = 0;
+		while (!NameIsUnique) {
+			NameIsUnique = 1;
+			for ( Host2=0; Host2<p->RIONumHosts; Host2++ ) {
+				if (Host2 == Host)
+					continue;
+				if (RIOStrCmp(p->RIOHosts[Host].Name, p->RIOHosts[Host2].Name)
+									 == 0) {
+					NameIsUnique = 0;
+					Host1++;
+					if (Host1 >= p->RIONumHosts)
+						Host1 = 0;
+					p->RIOHosts[Host].Name[5] = '1' + Host1;
+				}
+			}
+		}
+		/*
+		** Rename host if name already used.
+		*/
+		if (Host1 != Host)
+		{
+			rio_dprint(RIO_DEBUG_TABLE, ("Default name %s already used\n", p->RIOHosts[Host].Name));
+			bcopy("HOST 1",p->RIOHosts[Host].Name,7);
+			p->RIOHosts[Host].Name[5] += Host1;
+		}
+		rio_dprint(RIO_DEBUG_TABLE, ("Assigning default name %s\n", p->RIOHosts[Host].Name));
+	}
+	return 0;
+}
+
+/*
+** User process needs the config table - build it from first
+** principles.
+*/
+int
+RIOApel(p)
+struct rio_info *	p;
+{
+	int Host;
+	int link;
+	int Rup;
+	int Next = 0;
+	struct Map *MapP;
+	struct Host *HostP;
+	int oldspl;
+
+	disable(oldspl);		/* strange but true! */
+ 
+	rio_dprint(RIO_DEBUG_TABLE, ("Generating a table to return to config.rio\n"));
+
+	bzero((caddr_t)&p->RIOConnectTable[0], 
+					sizeof(struct Map) * TOTAL_MAP_ENTRIES );
+
+	for ( Host=0; Host<RIO_HOSTS; Host++ ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("Processing host %d\n", Host));
+		HostP = &p->RIOHosts[Host];
+		MapP = &p->RIOConnectTable[Next++];
+		MapP->HostUniqueNum = HostP->UniqueNum;
+		if ( (HostP->Flags & RUN_STATE) != RC_RUNNING )
+			continue;
+		MapP->RtaUniqueNum = 0;
+		MapP->ID = 0;
+		MapP->Flags = SLOT_IN_USE;
+		MapP->SysPort = NO_PORT;
+		for ( link=0; link<LINKS_PER_UNIT; link++ )
+			MapP->Topology[link] = HostP->Topology[link];
+		bcopy(HostP->Name,MapP->Name,MAX_NAME_LEN);
+		for ( Rup=0; Rup<MAX_RUP; Rup++ ) {
+			if ( HostP->Mapping[Rup].Flags & (SLOT_IN_USE|SLOT_TENTATIVE) ) {
+				p->RIOConnectTable[Next] = HostP->Mapping[Rup];
+				if ( HostP->Mapping[Rup].Flags & SLOT_IN_USE)
+					p->RIOConnectTable[Next].Flags |= SLOT_IN_USE;
+				if ( HostP->Mapping[Rup].Flags & SLOT_TENTATIVE)
+					p->RIOConnectTable[Next].Flags |= SLOT_TENTATIVE;
+				if ( HostP->Mapping[Rup].Flags & RTA16_SECOND_SLOT )
+					p->RIOConnectTable[Next].Flags |= RTA16_SECOND_SLOT;
+				Next++;
+			}
+		}
+	}
+	restore(oldspl);
+	return 0;
+}
+
+/*
+** config.rio has taken a dislike to one of the gross maps entries.
+** if the entry is suitably inactive, then we can gob on it and remove
+** it from the table.
+*/
+int
+RIODeleteRta(p, MapP)
+struct rio_info *p;
+struct Map *MapP;
+{
+	int host, entry, port, link;
+	int SysPort;
+	struct Host *HostP;
+	struct Map *HostMapP;
+	struct Port *PortP;
+	int work_done = 0;
+	unsigned long flags;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Delete entry on host %x, rta %x\n",
+								MapP->HostUniqueNum,MapP->RtaUniqueNum));
+
+	for ( host=0; host < p->RIONumHosts; host++ ) {
+		HostP = &p->RIOHosts[host];
+
+		rio_spin_lock_irqsave( &HostP->HostLock, flags );
+
+		if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) {
+			rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+			continue;
+		}
+
+		for ( entry=0; entry<MAX_RUP; entry++ ) {
+			if ( MapP->RtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum ) {
+				HostMapP = &HostP->Mapping[entry];
+				rio_dprint(RIO_DEBUG_TABLE, ("Found entry offset %d on host %s\n", 
+						entry,HostP->Name));
+
+				/*
+				** Check all four links of the unit are disconnected
+				*/
+				for ( link=0; link< LINKS_PER_UNIT; link++ ) {
+					if ( HostMapP->Topology[link].Unit != ROUTE_DISCONNECT ) {
+						rio_dprint(RIO_DEBUG_TABLE, ("Entry is in use and cannot be deleted!\n"));
+						p->RIOError.Error = UNIT_IS_IN_USE;
+						rio_spin_unlock_irqrestore( &HostP->HostLock, flags);
+						return EBUSY;
+					}
+				}
+				/*
+				** Slot has been allocated, BUT not booted/routed/
+				** connected/selected or anything else-ed
+				*/
+				SysPort = HostMapP->SysPort;
+
+				if ( SysPort != NO_PORT ) {
+					for (port=SysPort; port < SysPort+PORTS_PER_RTA; port++) {
+						PortP = p->RIOPortp[port];
+						rio_dprint(RIO_DEBUG_TABLE, ("Unmap port\n"));
+
+						rio_spin_lock_irqsave( &PortP->portSem, flags );
+
+						PortP->Mapped = 0;
+
+						if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) {
+
+							rio_dprint(RIO_DEBUG_TABLE, ("Gob on port\n"));
+							PortP->TxBufferIn = PortP->TxBufferOut = 0;
+							/* What should I do 
+							wakeup( &PortP->TxBufferIn );
+							wakeup( &PortP->TxBufferOut);
+							*/
+							PortP->InUse = NOT_INUSE;
+							/* What should I do 
+							wakeup( &PortP->InUse );
+							signal(PortP->TtyP->t_pgrp,SIGKILL);
+							ttyflush(PortP->TtyP,(FREAD|FWRITE));
+							*/
+							PortP->State |= RIO_CLOSING | RIO_DELETED;
+						}
+
+						/*
+						** For the second slot of a 16 port RTA, the
+						** driver needs to reset the changes made to
+						** the phb to port mappings in RIORouteRup.
+						*/
+						if (PortP->SecondBlock) {
+							ushort dest_unit = HostMapP->ID;
+							ushort dest_port = port - SysPort;
+							WORD	 *TxPktP;
+							PKT	*Pkt;
+
+							for (TxPktP = PortP->TxStart;
+								TxPktP <= PortP->TxEnd; TxPktP++) {
+								/*
+								** *TxPktP is the pointer to the
+								** transmit packet on the host card.
+								** This needs to be translated into
+								** a 32 bit pointer so it can be
+								** accessed from the driver.
+								*/
+								Pkt = (PKT *) RIO_PTR(HostP->Caddr,
+								 	RWORD(*TxPktP));
+								rio_dprint(RIO_DEBUG_TABLE, (
+						"Tx packet (%x) destination: Old %x:%x New %x:%x\n",
+								 *TxPktP, Pkt->dest_unit,
+								 Pkt->dest_port, dest_unit, dest_port));
+								WWORD(Pkt->dest_unit, dest_unit);
+								WWORD(Pkt->dest_port, dest_port);
+							}
+							rio_dprint(RIO_DEBUG_TABLE, (
+						"Port %d phb destination: Old %x:%x New %x:%x\n",
+							 port, PortP->PhbP->destination & 0xff,
+							 (PortP->PhbP->destination >> 8) & 0xff,
+							 dest_unit, dest_port));
+							WWORD(PortP->PhbP->destination,
+							 dest_unit + (dest_port << 8));
+						}
+						rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+					}
+				}
+				rio_dprint(RIO_DEBUG_TABLE, ("Entry nulled.\n"));
+				bzero((char *)HostMapP,sizeof(struct Map));
+				work_done++;
+			}
+		}
+		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+	}
+
+	/* XXXXX lock me up */
+	for ( entry=0; entry< TOTAL_MAP_ENTRIES; entry++ ) {
+		if ( p->RIOSavedTable[entry].RtaUniqueNum == MapP->RtaUniqueNum ) {
+			bzero((char *)&p->RIOSavedTable[entry],sizeof(struct Map));
+			work_done++;
+		}
+		if ( p->RIOConnectTable[entry].RtaUniqueNum == MapP->RtaUniqueNum ) {
+			bzero((char *)&p->RIOConnectTable[entry],sizeof(struct Map));
+			work_done++;
+		}
+	}
+	if ( work_done )
+		return 0;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Couldn't find entry to be deleted\n"));
+	p->RIOError.Error = COULDNT_FIND_ENTRY;
+	return ENXIO;
+}
+
+int RIOAssignRta( struct rio_info *p, struct Map *MapP )
+{
+    int host;
+    struct Map *HostMapP;
+    char *sptr;
+    int	link;
+
+
+    rio_dprint(RIO_DEBUG_TABLE, ("Assign entry on host %x, rta %x, ID %d, Sysport %d\n",
+				MapP->HostUniqueNum,MapP->RtaUniqueNum,
+				MapP->ID, (int)MapP->SysPort ));
+
+    if ((MapP->ID != (ushort)-1) &&
+	((int)MapP->ID < (int)1 || (int)MapP->ID > MAX_RUP ))
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n"));
+	p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+    if (MapP->RtaUniqueNum == 0)
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Rta Unique number zero!\n"));
+	p->RIOError.Error = RTA_UNIQUE_NUMBER_ZERO;
+	return EINVAL;
+    }
+    if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA) )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Port %d not multiple of %d!\n",(int)MapP->SysPort,PORTS_PER_RTA));
+	p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+    if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS) )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Port %d not valid!\n",(int)MapP->SysPort));
+	p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+
+    /*
+    ** Copy the name across to the map entry.
+    */
+    MapP->Name[MAX_NAME_LEN-1] = '\0';
+    sptr = MapP->Name;
+    while ( *sptr )
+    {
+    if ( *sptr<' ' || *sptr>'~' )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n"));
+	p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+	return EINVAL;
+    }
+    sptr++;
+    }
+
+    for ( host=0; host < p->RIONumHosts; host++ )
+    {
+	if ( MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum )
+	{
+	    if ( (p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING )
+	    {
+		p->RIOError.Error = HOST_NOT_RUNNING;
+		return ENXIO;
+	    }
+
+	    /*
+	    ** Now we have a host we need to allocate an ID
+	    ** if the the entry does not already have one.
+	    */
+	    if (MapP->ID == (ushort)-1)
+	    {
+		int nNewID;
+
+		rio_dprint(RIO_DEBUG_TABLE, ("Attempting to get a new ID for rta \"%s\"\n",
+		      MapP->Name));
+		/*
+		** The idea here is to allow RTA's to be assigned
+		** before they actually appear on the network.
+		** This allows the addition of RTA's without having
+		** to plug them in.
+		** What we do is:
+		**  - Find a free ID and allocate it to the RTA.
+		**  - If this map entry is the second half of a
+		**    16 port entry then find the other half and
+		**    make sure the 2 cross reference each other.
+		*/
+		if (RIOFindFreeID(p, &p->RIOHosts[host], &nNewID, NULL) != 0)
+		{
+		    p->RIOError.Error = COULDNT_FIND_ENTRY;
+		    return EBUSY;
+		}
+		MapP->ID = (ushort)nNewID + 1;
+		rio_dprint(RIO_DEBUG_TABLE, ("Allocated ID %d for this new RTA.\n",MapP->ID));
+		HostMapP = &p->RIOHosts[host].Mapping[nNewID];
+		HostMapP->RtaUniqueNum = MapP->RtaUniqueNum;
+		HostMapP->HostUniqueNum = MapP->HostUniqueNum;
+		HostMapP->ID = MapP->ID;
+		for (link = 0; link < LINKS_PER_UNIT; link++)
+		{
+		    HostMapP->Topology[link].Unit = ROUTE_DISCONNECT;
+		    HostMapP->Topology[link].Link = NO_LINK;
+		}
+		if (MapP->Flags & RTA16_SECOND_SLOT)
+		{
+		    int unit;
+
+		    for (unit = 0; unit < MAX_RUP; unit++)
+			if (p->RIOHosts[host].Mapping[unit].RtaUniqueNum ==
+			    MapP->RtaUniqueNum)
+			    break;
+		    if (unit == MAX_RUP)
+		    {
+			p->RIOError.Error = COULDNT_FIND_ENTRY;
+			return EBUSY;
+		    }
+		    HostMapP->Flags |= RTA16_SECOND_SLOT;
+		    HostMapP->ID2 = MapP->ID2 = p->RIOHosts[host].Mapping[unit].ID;
+		    p->RIOHosts[host].Mapping[unit].ID2 = MapP->ID;
+		    rio_dprint(RIO_DEBUG_TABLE, ("Cross referenced id %d to ID %d.\n",
+			  MapP->ID,
+			  p->RIOHosts[host].Mapping[unit].ID));
+		}
+	    }
+
+	    HostMapP = &p->RIOHosts[host].Mapping[MapP->ID-1];
+
+	    if ( HostMapP->Flags & SLOT_IN_USE )
+	    {
+		rio_dprint(RIO_DEBUG_TABLE, ("Map table slot for ID %d is already in use.\n",MapP->ID));
+		p->RIOError.Error = ID_ALREADY_IN_USE;
+		return EBUSY;
+	    }
+
+	    /*
+	    ** Assign the sys ports and the name, and mark the slot as
+	    ** being in use.
+	    */
+	    HostMapP->SysPort = MapP->SysPort;
+	    if ((MapP->Flags & RTA16_SECOND_SLOT) == 0)
+	      CCOPY( MapP->Name, HostMapP->Name, MAX_NAME_LEN );
+	    HostMapP->Flags = SLOT_IN_USE | RTA_BOOTED;
+#if NEED_TO_FIX
+	    RIO_SV_BROADCAST(p->RIOHosts[host].svFlags[MapP->ID-1]);
+#endif
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+		HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+	    RIOReMapPorts( p, &p->RIOHosts[host], HostMapP );
+	    /*
+	    ** Adjust 2nd block of 8 phbs
+	    */
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+		RIOFixPhbs(p, &p->RIOHosts[host], HostMapP->ID - 1);
+
+	    if ( HostMapP->SysPort != NO_PORT )
+	    {
+		if ( HostMapP->SysPort < p->RIOFirstPortsBooted )
+		    p->RIOFirstPortsBooted = HostMapP->SysPort;
+		if ( HostMapP->SysPort > p->RIOLastPortsBooted )
+		    p->RIOLastPortsBooted = HostMapP->SysPort;
+	    }
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+	        rio_dprint(RIO_DEBUG_TABLE, ("Second map of RTA %s added to configuration\n",
+		 p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name));
+	    else
+	        rio_dprint(RIO_DEBUG_TABLE, ("RTA %s added to configuration\n",MapP->Name));
+	    return 0;
+	}
+    }
+    p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+    rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum));
+    return ENXIO;
+}
+
+
+int
+RIOReMapPorts(p, HostP, HostMapP)
+struct rio_info *	p;
+struct Host *HostP;
+struct Map *HostMapP; 
+{
+	register struct Port *PortP;
+	uint SubEnt;
+	uint HostPort;
+	uint SysPort;
+	ushort RtaType;
+	unsigned long flags;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckHostMapP( HostMapP );
+#endif
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d to id %d\n",(int)HostMapP->SysPort, HostMapP->ID));
+
+	/*
+	** We need to tell the UnixRups which sysport the rup corresponds to
+	*/
+	HostP->UnixRups[HostMapP->ID-1].BaseSysPort = HostMapP->SysPort;
+
+	if ( HostMapP->SysPort == NO_PORT )
+		return(0);
+
+	RtaType = GetUnitType(HostMapP->RtaUniqueNum);
+	rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d-%d\n",
+				(int)HostMapP->SysPort,(int)HostMapP->SysPort+PORTS_PER_RTA-1));
+
+	/*
+	** now map each of its eight ports
+	*/
+	for ( SubEnt=0; SubEnt<PORTS_PER_RTA; SubEnt++) {
+	  rio_dprint  (RIO_DEBUG_TABLE, ("subent = %d, HostMapP->SysPort = %d\n", 
+		  SubEnt, (int) HostMapP->SysPort));
+		SysPort = HostMapP->SysPort+SubEnt;		/* portnumber within system */
+					/* portnumber on host */
+		
+		HostPort = (HostMapP->ID-1)*PORTS_PER_RTA+SubEnt; 
+
+		rio_dprint (RIO_DEBUG_TABLE, ("c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp));
+		PortP = p->RIOPortp[SysPort];
+#if 0
+		PortP->TtyP	= &p->channel[SysPort];
+#endif
+		rio_dprint(RIO_DEBUG_TABLE, ("Map port\n"));
+
+		/*
+		** Point at all the real neat data structures
+		*/
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->HostP = HostP;
+		PortP->Caddr = HostP->Caddr;
+
+		/*
+		** The PhbP cannot be filled in yet
+		** unless the host has been booted
+		*/
+		if ((HostP->Flags & RUN_STATE) == RC_RUNNING) {
+			struct PHB *PhbP = PortP->PhbP = &HostP->PhbP[HostPort];
+			PortP->TxAdd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_add));
+			PortP->TxStart =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_start));
+			PortP->TxEnd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_end));
+			PortP->RxRemove=(WORD *)RIO_PTR(HostP->Caddr,
+									RWORD(PhbP->rx_remove));
+			PortP->RxStart =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->rx_start));
+			PortP->RxEnd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->rx_end));
+		}
+		else
+			PortP->PhbP = NULL;
+
+		/*
+		** port related flags
+		*/
+		PortP->HostPort	= HostPort;
+		/*
+		** For each part of a 16 port RTA, RupNum is ID - 1.
+		*/
+		PortP->RupNum = HostMapP->ID - 1;
+		if (HostMapP->Flags & RTA16_SECOND_SLOT) {
+			PortP->ID2			 = HostMapP->ID2 - 1;
+			PortP->SecondBlock	 = TRUE;
+		}
+		else {
+			PortP->ID2			 = 0;
+			PortP->SecondBlock	 = FALSE;
+		}
+		PortP->RtaUniqueNum	= HostMapP->RtaUniqueNum;
+
+		/*
+		** If the port was already mapped then thats all we need to do.
+		*/
+		if (PortP->Mapped) {
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			continue;
+		}
+		else HostMapP->Flags &= ~RTA_NEWBOOT;
+
+		PortP->State		 = 0;
+		PortP->Config		= 0;
+		/*
+		** Check out the module type - if it is special (read only etc.)
+		** then we need to set flags in the PortP->Config.
+		** Note: For 16 port RTA, all ports are of the same type.
+		*/
+		if (RtaType == TYPE_RTA16) {
+			PortP->Config |= p->RIOModuleTypes[HostP->UnixRups
+				[HostMapP->ID-1].ModTypes].Flags[SubEnt % PORTS_PER_MODULE];
+		} else {
+			if ( SubEnt < PORTS_PER_MODULE )
+				PortP->Config |= p->RIOModuleTypes[LONYBLE(HostP->UnixRups
+				[HostMapP->ID-1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+			else
+				PortP->Config |= p->RIOModuleTypes[HINYBLE(HostP->UnixRups
+				[HostMapP->ID-1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+		}
+
+		/*
+		** more port related flags
+		*/
+		PortP->PortState	= 0;
+		PortP->ModemLines	= 0;
+		PortP->ModemState	= 0;
+		PortP->CookMode		= COOK_WELL;
+		PortP->ParamSem		= 0;
+		PortP->FlushCmdBodge= 0;
+		PortP->WflushFlag	= 0;
+		PortP->MagicFlags	= 0;
+		PortP->Lock			= 0;
+		PortP->Store		= 0;
+		PortP->FirstOpen	= 1;
+
+		/*
+		** handle the xprint issues
+		*/
+#ifdef XPRINT_SUPPORT
+		PortP->Xprint.XpActive	= 0;
+		PortP->Xprint.XttyP = &riox_tty[SysPort];
+		/*				TO				FROM			MAXLEN */
+		RIOStrNCpy( PortP->Xprint.XpOn,	RIOConf.XpOn,	MAX_XP_CTRL_LEN );
+		RIOStrNCpy( PortP->Xprint.XpOff, RIOConf.XpOff, MAX_XP_CTRL_LEN );
+		PortP->Xprint.XpCps = RIOConf.XpCps;
+		PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+									RIOStrlen(PortP->Xprint.XpOff);
+#endif
+
+		/*
+		** Buffers 'n things
+		*/
+		PortP->RxDataStart	= 0;
+		PortP->Cor2Copy	 = 0;
+		PortP->Name		 = &HostMapP->Name[0];
+#ifdef STATS
+		bzero( (caddr_t)&PortP->Stat, sizeof(struct RIOStats) );
+#endif
+		PortP->statsGather = 0;
+		PortP->txchars = 0;
+		PortP->rxchars = 0;
+		PortP->opens = 0;
+		PortP->closes = 0;
+		PortP->ioctls = 0;
+		if ( PortP->TxRingBuffer )
+			bzero( PortP->TxRingBuffer, p->RIOBufferSize );
+		else if ( p->RIOBufferSize ) {
+			PortP->TxRingBuffer = sysbrk(p->RIOBufferSize);
+			bzero( PortP->TxRingBuffer, p->RIOBufferSize );
+		}
+		PortP->TxBufferOut	= 0;
+		PortP->TxBufferIn	 = 0;
+		PortP->Debug		= 0;
+		/*
+		** LastRxTgl stores the state of the rx toggle bit for this
+		** port, to be compared with the state of the next pkt received.
+		** If the same, we have received the same rx pkt from the RTA
+		** twice. Initialise to a value not equal to PHB_RX_TGL or 0.
+		*/
+		PortP->LastRxTgl	= ~(uchar)PHB_RX_TGL;
+
+		/*
+		** and mark the port as usable
+		*/
+		PortP->Mapped = 1;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	}
+	if ( HostMapP->SysPort < p->RIOFirstPortsMapped )
+		p->RIOFirstPortsMapped = HostMapP->SysPort;
+	if ( HostMapP->SysPort > p->RIOLastPortsMapped )
+		p->RIOLastPortsMapped = HostMapP->SysPort;
+
+	return 0;
+}
+
+int
+RIOChangeName(p, MapP)
+struct rio_info *p;
+struct Map* MapP; 
+{
+	int host;
+	struct Map *HostMapP;
+	char *sptr;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Change name entry on host %x, rta %x, ID %d, Sysport %d\n",
+								MapP->HostUniqueNum,MapP->RtaUniqueNum,
+								MapP->ID, (int)MapP->SysPort ));
+
+	if ( MapP->ID > MAX_RUP ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n"));
+		p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+		return EINVAL;
+	}
+
+	MapP->Name[MAX_NAME_LEN-1] = '\0';
+	sptr = MapP->Name;
+
+	while ( *sptr ) {
+		if ( *sptr<' ' || *sptr>'~' ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n"));
+			p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+			return EINVAL;
+		}
+		sptr++;
+	}
+
+	for ( host=0; host < p->RIONumHosts; host++ ) {
+		if ( MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum ) {
+			if ( (p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING ) {
+				p->RIOError.Error = HOST_NOT_RUNNING;
+				return ENXIO;
+			}
+			if ( MapP->ID==0 ) {
+				CCOPY( MapP->Name, p->RIOHosts[host].Name, MAX_NAME_LEN );
+				return 0;
+			}
+
+			HostMapP = &p->RIOHosts[host].Mapping[MapP->ID-1];
+
+			if ( HostMapP->RtaUniqueNum != MapP->RtaUniqueNum ) {
+				p->RIOError.Error = RTA_NUMBER_WRONG;
+				return ENXIO;
+			}
+			CCOPY( MapP->Name, HostMapP->Name, MAX_NAME_LEN );
+			return 0;
+		}
+	}
+	p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+	rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum));
+	return ENXIO;
+}
diff -urN linux-2.2.15-pre2/drivers/char/rio/riotime.h linux/drivers/char/rio/riotime.h
--- linux-2.2.15-pre2/drivers/char/rio/riotime.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riotime.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,63 @@
+/****************************************************************************
+ *******                                                              *******
+ *******            T I M E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _riotime_h
+#define _riotime_h 1
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_riotime_h_sccs = "@(#)riotime.h	1.1" ;
+#endif
+#endif
+
+#define TWO_POWER_FIFTEEN (ushort)32768
+#define RioTime()    riotime
+#define RioTimeAfter(time1,time2) ((ushort)time1 - (ushort)time2) < TWO_POWER_FIFTEEN
+#define RioTimePlus(time1,time2) ((ushort)time1 + (ushort)time2)
+
+/**************************************
+ * Convert a RIO tick (1/10th second)
+ * into transputer low priority ticks
+ *************************************/ 
+#define RioTimeToLow(time) (time*(100000 / 64))
+#define RioLowToTime(time) ((time*64)/100000)
+
+#define RIOTENTHSECOND (ushort)1
+#define RIOSECOND (ushort)(RIOTENTHSECOND * 10)
+#endif
+
+/*********** end of file ***********/
diff -urN linux-2.2.15-pre2/drivers/char/rio/riotty.c linux/drivers/char/rio/riotty.c
--- linux-2.2.15-pre2/drivers/char/rio/riotty.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riotty.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1322 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riotty.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:47
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)riotty.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riotty_c_sccs_ = "@(#)riotty.c	1.3";
+#endif
+
+
+#define __EXPLICIT_DEF_H__
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+
+
+#if 0
+static void ttyseth_pv(struct Port *, struct ttystatics *, 
+				struct termios *sg, int);
+#endif
+
+static void RIOClearUp(struct Port *PortP);
+static int RIOShortCommand(struct rio_info *p, struct Port *PortP, 
+			   int command, int len, int arg);
+
+
+extern int	conv_vb[];	/* now defined in ttymgr.c */
+extern int	conv_bv[];	/* now defined in ttymgr.c */
+ 
+/*
+** 16.09.1998 ARG - Fix to build riotty.k.o for Modular Kernel Support
+**
+** ep.def.h is necessary for Modular Kernel Support
+** DO NOT place any kernel 'extern's after this line
+** or this source file will not build riotty.k.o
+*/
+#ifdef uLYNX
+#include <ep.def.h>
+#endif
+
+#ifdef NEED_THIS2
+static struct old_sgttyb 
+default_sg = 
+{ 
+	B19200, B19200,				/* input and output speed */ 
+	'H' - '@',					/* erase char */ 
+	-1,							/* 2nd erase char */ 
+	'U' - '@',					/* kill char */ 
+	ECHO | CRMOD,				/* mode */ 
+	'C' - '@',					/* interrupt character */ 
+	'\\' - '@',					/* quit char */ 
+	'Q' - '@',					/* start char */
+	'S' - '@',					/* stop char */ 
+	'D' - '@',					/* EOF */
+	-1,							/* brk */
+	(LCRTBS | LCRTERA | LCRTKIL | LCTLECH),	/* local mode word */ 
+	'Z' - '@',					/* process stop */
+	'Y' - '@',					/* delayed stop */
+	'R' - '@',					/* reprint line */ 
+	'O' - '@',					/* flush output */
+	'W' - '@',					/* word erase */
+	'V' - '@'					/* literal next char */
+};
+#endif
+
+
+extern struct rio_info *p;
+extern void rio_inc_mod_count (void);
+
+
+int
+riotopen(struct tty_struct * tty, struct file * filp)
+{
+	register uint SysPort;
+	int Modem;
+	int repeat_this = 250;
+	struct Port *PortP;		 /* pointer to the port structure */
+	unsigned long flags;
+	int retval = 0;
+
+	SysPort = rio_minor (tty->device);
+	Modem   = rio_ismodem (tty->device);
+
+	if ( p->RIOFailed ) {
+		rio_dprint(RIO_DEBUG_TTY, ("System initialisation failed\n"));
+		pseterr(ENXIO);
+		return 0;
+	}
+
+	rio_dprint(RIO_DEBUG_TTY, ("port open SysPort %d (%s) (mapped:%d)\n",
+	       SysPort,  Modem ? "Modem" : "tty",
+				   p->RIOPortp[SysPort]->Mapped  ) );
+
+	/*
+	** Validate that we have received a legitimate request.
+	** Currently, just check that we are opening a port on
+	** a host card that actually exists, and that the port
+	** has been mapped onto a host.
+	*/
+	if (SysPort >= RIO_PORTS) {	/* out of range ? */
+		rio_dprint(RIO_DEBUG_TTY, ("Illegal port number %d\n",SysPort));
+		pseterr(ENXIO);
+		return 0;
+	}
+
+	/*
+	** Grab pointer to the port stucture
+	*/
+	PortP = p->RIOPortp[SysPort];	/* Get control struc */
+
+	if ( !PortP->Mapped ) {	/* we aren't mapped yet! */
+		/*
+		** The system doesn't know which RTA this port
+		** corresponds to.
+		*/
+		rio_dprint(RIO_DEBUG_TTY, ("port not mapped into system\n"));
+		pseterr(ENXIO);
+		return 0;
+	}
+
+	tty->driver_data = PortP;
+
+	PortP->gs.tty = tty;
+	PortP->gs.count++;
+	rio_dprint(RIO_DEBUG_TTY, ("%d bytes in tx buffer\n",
+				   PortP->gs.xmit_cnt));
+	gs_init_port (&PortP->gs);
+
+	/*
+	** If the host hasn't been booted yet, then 
+	** fail
+	*/
+	if ( (PortP->HostP->Flags & RUN_STATE) != RC_RUNNING ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Host not running\n"));
+		pseterr(ENXIO);
+		return 0;
+	}
+
+	/*
+	** If the RTA has not booted yet and the user has choosen to block
+	** until the RTA is present then we must spin here waiting for
+	** the RTA to boot.
+	*/
+#if 0
+	if (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) {
+		if (PortP->WaitUntilBooted) {
+			rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot\n"));
+			do {
+				if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+					rio_dprint(RIO_DEBUG_TTY, ("RTA EINTR in delay \n"));
+					return -EINTR;
+				}
+				if (repeat_this -- <= 0) {
+					rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot timeout\n"));
+					RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+					pseterr(EINTR);
+					return -EIO;
+				}
+			} while(!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED));
+			rio_dprint(RIO_DEBUG_TTY, ("RTA has been booted\n"));
+		} else {
+			rio_dprint(RIO_DEBUG_TTY, ("RTA never booted\n"));
+			pseterr(ENXIO);
+			return 0;
+		}
+	}
+#else
+	/* I find the above code a bit hairy. I find the below code
+           easier to read and shorter. Now, if it works too that would
+	   be great... -- REW 
+	*/
+	rio_dprint(RIO_DEBUG_TTY, ("Checking if RTA has booted... \n"));
+	while (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) {
+	  if (!PortP->WaitUntilBooted) {
+	    rio_dprint(RIO_DEBUG_TTY, ("RTA never booted\n"));
+	    return -ENXIO;
+	  }
+
+	  /* Under Linux you'd normally use a wait instead of this
+	     busy-waiting. I'll stick with the old implementation for
+	     now. --REW 
+	  */
+	  if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+	    rio_dprint(RIO_DEBUG_TTY, ("RTA_wait_for_boot: EINTR in delay \n"));
+	    return -EINTR;
+	  }
+	  if (repeat_this -- <= 0) {
+	    rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot timeout\n"));
+	    return -EIO;
+	  }
+	}
+	rio_dprint(RIO_DEBUG_TTY, ("RTA has been booted\n"));
+#endif
+#if 0
+	tp =  PortP->TtyP;		/* get tty struct */
+#endif
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	if ( p->RIOHalted ) {
+		goto bombout;
+	}
+#if 0
+	retval = gs_init_port(&PortP->gs);
+	if (retval)
+	  return retval;
+#endif
+
+	/*
+	** If the port is in the final throws of being closed,
+	** we should wait here (politely), waiting
+	** for it to finish, so that it doesn't close us!
+	*/
+	while ( (PortP->State & RIO_CLOSING) && !p->RIOHalted ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Waiting for RIO_CLOSING to go away\n"));
+		if (repeat_this -- <= 0) {
+			rio_dprint(RIO_DEBUG_TTY, ("Waiting for not idle closed broken by signal\n"));
+			RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+			retval = -EINTR;
+			goto bombout;
+		}
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+			rio_spin_lock_irqsave(&PortP->portSem, flags); 
+			retval = -EINTR;
+			goto bombout;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags); 
+	}
+
+	if ( !PortP->Mapped ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Port unmapped while closing!\n"));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		retval = -ENXIO;
+		return retval;
+	}
+
+	if ( p->RIOHalted ) {
+		goto bombout;
+	}
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,
+** we need to make sure that the flags are clear when the port is opened.
+*/
+	/* Uh? Suppose I turn these on and then another process opens
+	   the port again? The flags get cleared! Not good. -- REW */
+	if ( !(PortP->State & (RIO_LOPEN | RIO_MOPEN)) ) {
+		PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW);
+	}
+
+	if (!(PortP->firstOpen)) {	/* First time ? */
+		rio_dprint(RIO_DEBUG_TTY, ("First open for this port\n"));
+		rio_inc_mod_count ();
+
+		PortP->firstOpen++;
+		PortP->CookMode = 0; /* XXX RIOCookMode(tp); */
+		PortP->InUse = NOT_INUSE;
+
+		/* Tentative fix for bug PR27. Didn't work. */
+		/* PortP->gs.xmit_cnt = 0; */
+
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+#ifdef NEED_THIS
+		ttyseth(PortP, tp, (struct old_sgttyb *)&default_sg);
+#endif
+
+		/* Someone explain to me why this delay/config is
+                   here. If I read the docs correctly the "open"
+                   command piggybacks the parameters immediately. 
+		   -- REW */
+		RIOParam(PortP,OPEN,Modem,OK_TO_SLEEP);		/* Open the port */
+#if 0
+		/* This delay of 1 second was annoying. I removed it. -- REW */
+		RIODelay(PortP, HUNDRED_MS*10);
+		RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	/* Config the port */
+#endif
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+		/*
+		** wait for the port to be not closed.
+		*/
+		while ( !(PortP->PortState & PORT_ISOPEN) && !p->RIOHalted ) {
+			rio_dprint(RIO_DEBUG_TTY, ("Waiting for PORT_ISOPEN-currently %x\n",PortP->PortState));
+/*
+** 15.10.1998 ARG - ESIL 0759
+** (Part) fix for port being trashed when opened whilst RTA "disconnected"
+** Take out the limited wait - now wait for ever or until user
+** bangs us out.
+**
+			if (repeat_this -- <= 0) {
+				rio_dprint(RIO_DEBUG_TTY, ("Waiting for open to finish timed out.\n"));
+				RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				return -EINTR;
+			}
+**
+*/
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+				rio_dprint(RIO_DEBUG_TTY, ("Waiting for open to finish broken by signal\n"));
+				RIOPreemptiveCmd(p, PortP, FCLOSE );
+				return -EINTR;
+			}
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+		}
+
+		if ( p->RIOHalted ) {
+		  retval = -EIO;
+bombout:
+		  /* 			RIOClearUp( PortP ); */
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return retval;
+		}
+		rio_dprint(RIO_DEBUG_TTY, ("PORT_ISOPEN found\n"));
+	}
+
+#ifdef MODEM_SUPPORT 
+	if (Modem) {
+		rio_dprint(RIO_DEBUG_TTY, ("Modem - test for carrier\n"));
+		/*
+		** ACTION
+		** insert test for carrier here. -- ???
+		** I already see that test here. What's the deal? -- REW
+		*/
+		if ((tp->tm.c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD))
+		{
+			rio_dprint(RIO_DEBUG_TTY, (PortP,DBG_OPEN,"open(%d) Modem carr on\n",SysPort));
+			tp->tm.c_state |= CARR_ON;
+			wakeup((caddr_t) &tp->tm.c_canq);
+		}
+		else /* no carrier - wait for DCD */
+		{
+			while (!(tp->tm.c_state&CARR_ON) && 
+			       !(filp->f_flags&O_NONBLOCK) && !p->RIOHalted )
+			{
+				rio_dprint(RIO_DEBUG_TTY, (PortP,DBG_OPEN,"open(%d) sleeping for carr on\n",SysPort));
+				tp->tm.c_state |= WOPEN;
+				PortP->State |= RIO_WOPEN;
+				if ( sleep((caddr_t)&tp->tm.c_canq, TTIPRI|PCATCH))
+				{
+					/*
+					** ACTION: verify that this is a good thing
+					** to do here. -- ???
+					** I think it's OK. -- REW
+					*/
+					rio_dprint(RIO_DEBUG_TTY, ("open(%d) sleeping for carr broken by signal\n",
+					       SysPort));
+					RIOPreemptiveCmd( p, PortP, FCLOSE );
+					tp->tm.c_state &= ~WOPEN;
+					PortP->State &= ~RIO_WOPEN;
+					rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+					return -EINTR;
+				}
+			}
+			PortP->State &= ~RIO_WOPEN;
+		}
+		if ( RIOHalted )
+			goto bombout;
+		PortP->State |= RIO_MOPEN;
+	}
+	else
+#endif
+	{
+		/*
+		** ACTION
+		** Direct line open - force carrier (will probably mean
+		** that sleeping Modem line fubar)
+		*/
+		PortP->State |= RIO_LOPEN;
+	}
+
+	if ( p->RIOHalted ) {
+		goto bombout;
+	}
+
+	rio_dprint(RIO_DEBUG_TTY, ("high level open done\n"));
+
+#ifdef STATS
+	PortP->Stat.OpenCnt++;
+#endif
+	/*
+	** Count opens for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->opens++;
+
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	rio_dprint(RIO_DEBUG_TTY, ("Returning from open\n"));
+	return 0;
+}
+
+/*
+** RIOClose the port.
+** The operating system thinks that this is last close for the device.
+** As there are two interfaces to the port (Modem and tty), we need to
+** check that both are closed before we close the device.
+*/ 
+int
+riotclose(void  *ptr)
+{
+#if 0
+	register uint SysPort = dev;
+	struct ttystatics *tp;		/* pointer to our ttystruct */
+#endif
+	struct Port *PortP =ptr;	/* pointer to the port structure */
+	int deleted = 0;
+	int	try = 25;
+	int	repeat_this = 0xff;
+	struct tty_struct * tty;
+	unsigned long flags;
+	int Modem;
+	int rv =0;
+	
+	rio_dprint(RIO_DEBUG_TTY, ("port close SysPort %d\n",PortP->PortNum));
+
+	/* PortP = p->RIOPortp[SysPort]; */
+	rio_dprint(RIO_DEBUG_TTY, ("Port is at address 0x%x\n",(int)PortP));
+	/* tp = PortP->TtyP;*/			/* Get tty */
+	tty = PortP->gs.tty;
+	rio_dprint(RIO_DEBUG_TTY, ("TTY is at address 0x%x\n",(int)tty));
+	Modem = rio_ismodem(tty->device);
+#if 0
+	/* What F.CKING cache? Even then, a higly idle multiprocessor,
+	   system with large caches this won't work . Better find out when 
+	   this doesn't work asap, and fix the cause.  -- REW */
+	
+	RIODelay(PortP, HUNDRED_MS*10);	/* To flush the cache */
+#endif
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	/*
+	** Setting this flag will make any process trying to open
+	** this port block until we are complete closing it.
+	*/
+	PortP->State |= RIO_CLOSING;
+
+	if ( (PortP->State & RIO_DELETED) ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Close on deleted RTA\n"));
+		deleted = 1;
+	}
+	
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		rv = -EIO;
+		goto close_end;
+	}
+
+	rio_dprint(RIO_DEBUG_TTY, ("Clear bits\n"));
+	/*
+	** clear the open bits for this device
+	*/
+	PortP->State &= (Modem ? ~RIO_MOPEN : ~RIO_LOPEN);
+
+	/*
+	** If the device was open as both a Modem and a tty line
+	** then we need to wimp out here, as the port has not really
+	** been finally closed (gee, whizz!) The test here uses the
+	** bit for the OTHER mode of operation, to see if THAT is
+	** still active!
+	*/
+	if ( (PortP->State & (RIO_LOPEN|RIO_MOPEN)) ) {
+		/*
+		** The port is still open for the other task -
+		** return, pretending that we are still active.
+		*/
+		rio_dprint(RIO_DEBUG_TTY, ("Channel %d still open !\n",PortP->PortNum));
+		PortP->State &= ~RIO_CLOSING;
+		if (PortP->firstOpen)
+			PortP->firstOpen--;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return -EIO;
+	}
+
+	rio_dprint(RIO_DEBUG_TTY, ("Closing down - everything must go!\n"));
+
+	PortP->State &= ~RIO_DYNOROD;
+
+	/*
+	** This is where we wait for the port
+	** to drain down before closing. Bye-bye....
+	** (We never meant to do this)
+	*/
+	rio_dprint(RIO_DEBUG_TTY, ("Timeout 1 starts\n"));
+
+#if 0
+	if (!deleted)
+	while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted && 
+		(PortP->TxBufferIn != PortP->TxBufferOut) ) {
+		cprintf("Need to flush the ttyport\n");
+		if (repeat_this -- <= 0) {
+			rv = -EINTR;
+			rio_dprint(RIO_DEBUG_TTY, ("Waiting for not idle closed broken by signal\n"));
+			RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+			goto close_end;
+		}
+		rio_dprint(RIO_DEBUG_TTY, ("Calling timeout to flush in closing\n"));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (RIODelay_ni(PortP, HUNDRED_MS*10) == RIO_FAIL) {
+			rio_dprint(RIO_DEBUG_TTY, ("RTA EINTR in delay \n"));
+			rv = -EINTR;
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+			goto close_end;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+#endif
+	PortP->TxBufferIn = PortP->TxBufferOut = 0;
+	repeat_this = 0xff;
+
+	PortP->InUse = 0;
+	if ( (PortP->State & (RIO_LOPEN|RIO_MOPEN)) ) {
+		/*
+		** The port has been re-opened for the other task -
+		** return, pretending that we are still active.
+		*/
+		rio_dprint(RIO_DEBUG_TTY, ("Channel %d re-open!\n", PortP->PortNum));
+		PortP->State &= ~RIO_CLOSING;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (PortP->firstOpen)
+			PortP->firstOpen--;
+		return -EIO;
+	}
+
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		goto close_end;
+	}
+
+	
+
+	/* Can't call RIOShortCommand with the port locked. */
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+	if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
+	  RIOPreemptiveCmd(p, PortP,FCLOSE);
+	  goto close_end;
+	}
+
+	if (!deleted)
+	  while (try && (PortP->PortState & PORT_ISOPEN)) {
+	        try--;
+		if (try == 0) {
+		  rio_dprint(RIO_DEBUG_TTY, ("Run out of tries - force the bugger shut!\n" ));
+		  RIOPreemptiveCmd(p, PortP,FCLOSE);
+		  break;
+		}
+		rio_dprint(RIO_DEBUG_TTY, ("Close: PortState:ISOPEN is %d\n", 
+					   PortP->PortState & PORT_ISOPEN));
+
+		if ( p->RIOHalted ) {
+			RIOClearUp( PortP );
+			goto close_end;
+		}
+		RIODelay_ni(PortP, HUNDRED_MS);
+	}
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	rio_dprint(RIO_DEBUG_TTY, ("Close: try was %d on completion\n", try ));
+ 
+	/* RIOPreemptiveCmd(p, PortP, FCLOSE); */
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,** we need to make sure that the flags are clear when the port is opened.
+*/
+	PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW);
+
+
+#ifdef STATS
+	PortP->Stat.CloseCnt++;
+#endif
+	/*
+	** Count opens for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->closes++;
+
+close_end:
+	/* XXX: Why would a "DELETED" flag be reset here? I'd have
+	   thought that a "deleted" flag means that the port was
+	   permanently gone, but here we can make it reappear by it
+	   being in close during the "deletion".
+	*/
+	PortP->State &= ~(RIO_CLOSING|RIO_DELETED);
+	if (PortP->firstOpen)
+		PortP->firstOpen--;
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	rio_dprint(RIO_DEBUG_TTY, ("Return from close\n"));
+	return rv;
+}
+
+
+/*
+** decide if we need to use the line discipline.
+** This routine can return one of three values:
+** COOK_RAW if no processing has to be done by the line discipline or the card
+** COOK_WELL if the line discipline must be used to do the processing
+** COOK_MEDIUM if the card can do all the processing necessary.
+*/
+int
+RIOCookMode(struct ttystatics *tp)
+{
+	/*
+	** We cant handle tm.c_mstate != 0 on SCO
+	** We cant handle mapping
+	** We cant handle non-ttwrite line disc.
+	** We cant handle lflag XCASE
+	** We can handle oflag OPOST & (OCRNL, ONLCR, TAB3)
+	*/
+
+#ifdef CHECK
+	CheckTtyP( tp );
+#endif
+	if (!(tp->tm.c_oflag & OPOST))	/* No post processing */
+		return COOK_RAW;	/* Raw mode o/p */
+
+	if ( tp->tm.c_lflag & XCASE )
+		return COOK_WELL;	/* Use line disc */
+
+	if (tp->tm.c_oflag & ~(OPOST | ONLCR | OCRNL | TAB3 ) )
+		return COOK_WELL;	/* Use line disc for strange modes */
+
+	if ( tp->tm.c_oflag == OPOST )	/* If only OPOST is set, do RAW */
+		return COOK_RAW;
+
+	/*
+	** So, we need to output process!
+	*/
+	return COOK_MEDIUM;
+}
+
+
+static void
+RIOClearUp(PortP)
+struct Port *PortP;
+{
+	rio_dprint(RIO_DEBUG_TTY, ("RIOHalted set\n"));
+	PortP->Config = 0;	  /* Direct semaphore */
+	PortP->PortState = 0;
+	PortP->firstOpen = 0;
+	PortP->FlushCmdBodge = 0;
+	PortP->ModemState = PortP->CookMode = 0;
+	PortP->Mapped = 0;
+	PortP->WflushFlag = 0;
+	PortP->MagicFlags	= 0;
+	PortP->RxDataStart = 0;
+	PortP->TxBufferIn = 0;
+	PortP->TxBufferOut = 0;
+}
+
+/*
+** Put a command onto a port.
+** The PortPointer, command, length and arg are passed.
+** The len is the length *inclusive* of the command byte,
+** and so for a command that takes no data, len==1.
+** The arg is a single byte, and is only used if len==2.
+** Other values of len aren't allowed, and will cause
+** a panic.
+*/
+static int RIOShortCommand(struct rio_info *p, struct Port *PortP,
+		int command, int len, int arg)
+{
+	PKT *PacketP;
+	int		retries = 20; /* at 10 per second -> 2 seconds */
+	unsigned long flags;
+
+	rio_dprint(RIO_DEBUG_TTY, ("entering shortcommand.\n"));
+#ifdef CHECK
+	CheckPortP( PortP );
+	if ( len < 1 || len > 2 )
+		cprintf(("STUPID LENGTH %d\n",len));
+#endif
+
+	if ( PortP->State & RIO_DELETED ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Short command to deleted RTA ignored\n"));
+		return RIO_FAIL;
+	}
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	/*
+	** If the port is in use for pre-emptive command, then wait for it to 
+	** be free again.
+	*/
+	while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Waiting for not in use (%d)\n", 
+					   retries));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (retries-- <= 0) {
+			return RIO_FAIL;
+		}
+		if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) {
+			return RIO_FAIL;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+	if ( PortP->State & RIO_DELETED ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Short command to deleted RTA ignored\n"));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	while ( !can_add_transmit(&PacketP,PortP) && !p->RIOHalted ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Waiting to add short command to queue (%d)\n", retries));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (retries-- <= 0) {
+		  rio_dprint(RIO_DEBUG_TTY, ("out of tries. Failing\n"));
+			return RIO_FAIL;
+		}
+		if ( RIODelay_ni(PortP, HUNDRED_MS)==RIO_FAIL ) {
+			return RIO_FAIL;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+
+	if ( p->RIOHalted ) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	/*
+	** set the command byte and the argument byte
+	*/
+	WBYTE(PacketP->data[0] , command);
+
+	if ( len==2 )
+		WBYTE(PacketP->data[1] , arg);
+
+	/*
+	** set the length of the packet and set the command bit.
+	*/
+	WBYTE(PacketP->len , PKT_CMD_BIT | len);
+
+	add_transmit(PortP);
+	/*
+	** Count characters transmitted for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->txchars += len;
+
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return p->RIOHalted ? RIO_FAIL : ~RIO_FAIL;
+}
+
+
+#if 0
+/*
+** This is an ioctl interface. This is the twentieth century. You know what
+** its all about.
+*/
+int
+riotioctl(p, dev, cmd, arg)
+struct rio_info *		p;
+dev_t dev;
+register int cmd;
+register caddr_t arg;
+{
+	register struct		Port *PortP;
+	register struct		ttystatics *tp;
+	int					current;
+	int					ParamSemIncremented = 0;
+	int					old_oflag, old_cflag, old_iflag, changed, oldcook;
+	int					i;
+	unsigned char		sio_regs[5];		/* Here be magic */
+	short				vpix_cflag;
+	short				divisor;
+	int					baud;
+	uint				SysPort = dev;
+	int					Modem = rio_ismodem(dev);
+	int					ioctl_processed;
+
+	rio_dprint(RIO_DEBUG_TTY, ("port ioctl SysPort %d command 0x%x argument 0x%x %s\n",
+			SysPort,cmd,arg,Modem?"Modem":"tty"));
+
+	if ( SysPort >= RIO_PORTS ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Bad port number %d\n",SysPort));
+		return -ENXIO;
+	}
+
+	PortP = p->RIOPortp[SysPort];
+	tp = PortP->TtyP;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+#ifdef STATS
+	PortP->Stat.IoctlCnt++;
+#endif
+
+	if ( PortP->State & RIO_DELETED ) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return -EIO;
+	}
+
+
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return -EIO;
+	}
+
+	/*
+	** Count ioctls for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->ioctls++;
+
+	/*
+	** Specialix RIO Ioctl calls
+	*/
+	switch (cmd) {
+
+		case TCRIOTRIAD:
+			if ( arg )
+				PortP->State |= RIO_TRIAD_MODE;
+			else
+				PortP->State &= ~RIO_TRIAD_MODE;
+			/*
+			** Normally, when istrip is set on a port, a config is
+			** sent to the RTA instructing the CD1400 to do the
+			** stripping. In TRIAD mode, the interrupt receive routine
+			** must do the stripping instead, since it has to detect
+			** an 8 bit function key sequence. If istrip is set with
+			** TRIAD mode on(off), and 8 bit data is being read by
+			** the port, the user then turns TRIAD mode off(on), the RTA
+			** must be reconfigured (not) to do the stripping.
+			** Hence we call RIOParam here.
+			*/
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+		case TCRIOTSTATE:
+			rio_dprint(RIO_DEBUG_TTY, ("tbusy/tstop monitoring %sabled\n",
+		 		arg ? "en" : "dis"));
+			/* MonitorTstate = 0 ;*/
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP, CONFIG, Modem, OK_TO_SLEEP);
+			return 0;
+
+		case TCRIOSTATE: /* current state of Modem input pins */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOSTATE\n"));
+			if (RIOPreemptiveCmd(p, PortP, MGET) == RIO_FAIL)
+				rio_dprint(RIO_DEBUG_TTY, ("TCRIOSTATE command failed\n"));
+			PortP->State |= RIO_BUSY;
+			current = PortP->ModemState;
+			if ( copyout((caddr_t)&current, (int)arg,
+							sizeof(current))==COPYFAIL ) {
+				rio_dprint(RIO_DEBUG_TTY, ("Copyout failed\n"));
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EFAULT);
+			}
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOMBIS:		/* Set modem lines */
+		case TCRIOMBIC:		/* Clear modem lines */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOMBIS/TCRIOMBIC\n"));
+			if (cmd == TCRIOMBIS) {
+				uint		state;
+				state = (uint)arg;
+				PortP->ModemState |= (ushort)state;
+				PortP->ModemLines = (ulong) arg;
+				if (RIOPreemptiveCmd(p, PortP, MBIS) == RIO_FAIL)
+					rio_dprint(RIO_DEBUG_TTY, (
+					 "TCRIOMBIS command failed\n"));
+			}
+			else {
+				uint		state;
+
+				state = (uint)arg;
+				PortP->ModemState &= ~(ushort)state;
+				PortP->ModemLines = (ulong) arg;
+				if (RIOPreemptiveCmd(p, PortP, MBIC) == RIO_FAIL)
+					rio_dprint(RIO_DEBUG_TTY, ("TCRIOMBIC command failed\n"));
+			}
+			PortP->State |= RIO_BUSY;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOXPON: /* set Xprint ON string */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPON\n"));
+			if ( copyin((int)arg, (caddr_t)PortP->Xprint.XpOn,
+						MAX_XP_CTRL_LEN)==COPYFAIL ) {
+				rio_dprint(RIO_DEBUG_TTY, ("Copyin failed\n"));
+				PortP->Xprint.XpOn[0] = '\0';
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EFAULT);
+			}
+			PortP->Xprint.XpOn[MAX_XP_CTRL_LEN-1] = '\0';
+			PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+												RIOStrlen(PortP->Xprint.XpOff);
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOXPOFF: /* set Xprint OFF string */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPOFF\n"));
+			if ( copyin( (int)arg, (caddr_t)PortP->Xprint.XpOff,
+						MAX_XP_CTRL_LEN)==COPYFAIL ) {
+				rio_dprint(RIO_DEBUG_TTY, ("Copyin failed\n"));
+				PortP->Xprint.XpOff[0] = '\0';
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EFAULT);
+			}
+			PortP->Xprint.XpOff[MAX_XP_CTRL_LEN-1] = '\0';
+			PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+										RIOStrlen(PortP->Xprint.XpOff);
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOXPCPS: /* set Xprint CPS string */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPCPS\n"));
+			if ( (uint)arg > p->RIOConf.MaxXpCps || 
+					(uint)arg < p->RIOConf.MinXpCps ) {
+				rio_dprint(RIO_DEBUG_TTY, ("%d CPS out of range\n",arg));
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EINVAL);
+				return 0;
+			}
+			PortP->Xprint.XpCps = (uint)arg;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOXPRINT:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPRINT\n"));
+			if ( copyout((caddr_t)&PortP->Xprint, (int)arg,
+					sizeof(struct Xprint))==COPYFAIL ) {
+			        rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EFAULT);
+			}
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOIXANYON:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXANYON\n"));
+			PortP->Config |= RIO_IXANY;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOIXANYOFF:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXANYOFF\n"));
+			PortP->Config &= ~RIO_IXANY;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOIXONON:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXONON\n"));
+			PortP->Config |= RIO_IXON;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOIXONOFF:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXONOFF\n"));
+			PortP->Config &= ~RIO_IXON;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** Added support for CTS and RTS flow control ioctls :
+*/
+		case TCRIOCTSFLOWEN:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOCTSFLOWEN\n"));
+			PortP->Config |= RIO_CTSFLOW;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+		case TCRIOCTSFLOWDIS:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOCTSFLOWDIS\n"));
+			PortP->Config &= ~RIO_CTSFLOW;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+		case TCRIORTSFLOWEN:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIORTSFLOWEN\n"));
+			PortP->Config |= RIO_RTSFLOW;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+		case TCRIORTSFLOWDIS:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIORTSFLOWDIS\n"));
+			PortP->Config &= ~RIO_RTSFLOW;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+/* end ESIL 0761 part fix */
+
+	}
+
+
+	/* Lynx IOCTLS */
+	switch (cmd) {
+		case TIOCSETP:
+		case TIOCSETN:
+		case OTIOCSETP:
+		case OTIOCSETN:
+			ioctl_processed++;
+			ttyseth(PortP, tp, (struct old_sgttyb *)arg);
+			break;
+		case TCSETA:
+		case TCSETAW:
+		case TCSETAF:
+			ioctl_processed++;
+			rio_dprint(RIO_DEBUG_TTY, ("NON POSIX ioctl\n"));
+			ttyseth_pv(PortP, tp, (struct termios *)arg, 0);
+			break;
+		case TCSETAP:	/* posix tcsetattr() */
+		case TCSETAWP:	/* posix tcsetattr() */
+		case TCSETAFP:	/* posix tcsetattr() */
+			rio_dprint(RIO_DEBUG_TTY, ("NON POSIX SYSV ioctl\n"));
+			ttyseth_pv(PortP, tp, (struct termios *)arg, 1);
+			ioctl_processed++;
+			break;
+	}
+
+	/*
+	** If its any of the commands that require the port to be in the
+	** non-busy state wait until all output has drained 
+	*/
+	if (!ioctl_processed)
+	switch(cmd) {
+		case TCSETAW:
+		case TCSETAF:
+		case TCSETA:
+		case TCSBRK:
+#define OLD_POSIX ('x' << 8)
+#define OLD_POSIX_SETA (OLD_POSIX | 2)
+#define OLD_POSIX_SETAW (OLD_POSIX | 3)
+#define OLD_POSIX_SETAF (OLD_POSIX | 4)
+#define NEW_POSIX (('i' << 24) | ('X' << 16))
+#define NEW_POSIX_SETA (NEW_POSIX | 2)
+#define NEW_POSIX_SETAW (NEW_POSIX | 3)
+#define NEW_POSIX_SETAF (NEW_POSIX | 4)
+		case OLD_POSIX_SETA:
+		case OLD_POSIX_SETAW:
+		case OLD_POSIX_SETAF:
+		case NEW_POSIX_SETA:
+		case NEW_POSIX_SETAW:
+		case NEW_POSIX_SETAF:
+#ifdef TIOCSETP
+		case TIOCSETP:
+#endif
+		case TIOCSETD:
+		case TIOCSETN:
+			rio_dprint(RIO_DEBUG_TTY, ("wait for non-BUSY, semaphore set\n"));
+			/*
+			** Wait for drain here, at least as far as the double buffer
+			** being empty.
+			*/
+			/* XXX Does the above comment mean that this has
+			   still to be implemented? -- REW */
+			/* XXX Is the locking OK together with locking
+                           in txenable? (Deadlock?) -- REW */
+			
+			RIOTxEnable((char *)PortP);
+			break;
+		default:
+			break;
+	}
+
+	old_cflag = tp->tm.c_cflag;
+	old_iflag = tp->tm.c_iflag;
+	old_oflag = tp->tm.c_oflag;
+	oldcook = PortP->CookMode;
+
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		pseterr(EIO);
+		return 0;
+	}
+
+	PortP->FlushCmdBodge = 0;
+
+	/*
+	** If the port is locked, and it is reconfigured, we want
+	** to restore the state of the tty structure so the change is NOT
+	** made.
+	*/
+	if (PortP->Lock) {
+		tp->tm.c_iflag = PortP->StoredTty.iflag;
+		tp->tm.c_oflag = PortP->StoredTty.oflag;
+		tp->tm.c_cflag = PortP->StoredTty.cflag;
+		tp->tm.c_lflag = PortP->StoredTty.lflag;
+		tp->tm.c_line = PortP->StoredTty.line;
+		for (i = 0; i < NCC + 1; i++)
+			tp->tm.c_cc[i] = PortP->StoredTty.cc[i];
+	}
+	else {
+		/*
+		** If the port is set to store the parameters, and it is
+		** reconfigured, we want to save the current tty struct so it
+		** may be restored on the next open.
+		*/
+		if (PortP->Store) {
+			PortP->StoredTty.iflag = tp->tm.c_iflag;
+			PortP->StoredTty.oflag = tp->tm.c_oflag;
+			PortP->StoredTty.cflag = tp->tm.c_cflag;
+			PortP->StoredTty.lflag = tp->tm.c_lflag;
+			PortP->StoredTty.line = tp->tm.c_line;
+			for (i = 0; i < NCC + 1; i++)
+				PortP->StoredTty.cc[i] = tp->tm.c_cc[i];
+		}
+	}
+
+	changed = (tp->tm.c_cflag != old_cflag) ||
+				(tp->tm.c_iflag != old_iflag) ||
+				(tp->tm.c_oflag != old_oflag);
+
+	PortP->CookMode = RIOCookMode(tp);	/* Set new cooking mode */
+
+	rio_dprint(RIO_DEBUG_TTY, ("RIOIoctl changed %d newcook %d oldcook %d\n",
+			changed,PortP->CookMode,oldcook));
+
+#ifdef MODEM_SUPPORT
+	/*
+	** kludge to force CARR_ON if CLOCAL set
+	*/
+	if ((tp->tm.c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD))	{
+		tp->tm.c_state |= CARR_ON;
+		wakeup ((caddr_t)&tp->tm.c_canq);
+	}
+#endif
+
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		pseterr(EIO);
+		return 0;
+	}
+	/*
+	** Re-configure if modes or cooking have changed
+	*/
+	if (changed || oldcook != PortP->CookMode || (ioctl_processed)) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		rio_dprint(RIO_DEBUG_TTY, ("Ioctl changing the PORT settings\n"));
+		RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+
+	if (p->RIOHalted) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		RIOClearUp( PortP );
+		pseterr(EIO);
+		return 0;
+	}
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return 0;
+}
+
+/*
+	ttyseth -- set hardware dependant tty settings
+*/
+void
+ttyseth(PortP, s, sg)
+struct Port *		PortP;
+struct ttystatics *		s;
+struct old_sgttyb *sg;
+{
+	struct old_sgttyb *	tsg;
+	struct termios *tp = &s->tm;
+
+	tsg = &s->sg;
+
+	if (sg->sg_flags & (EVENP|ODDP))  {
+		tp->c_cflag &= PARENB;
+		if (sg->sg_flags & EVENP) {
+			if (sg->sg_flags & ODDP) {
+				tp->c_cflag &= V_CS7;
+				tp->c_cflag &= ~PARENB;
+			}
+			else {
+				tp->c_cflag &= V_CS7;
+				tp->c_cflag &= PARENB;
+				tp->c_cflag &= PARODD;
+			}
+		}
+		else if (sg->sg_flags & ODDP) {
+			tp->c_cflag &= V_CS7;
+			tp->c_cflag &= PARENB;
+			tp->c_cflag &= PARODD;
+		}
+		else {
+			tp->c_cflag &= V_CS7;
+			tp->c_cflag &= PARENB;
+		}
+	}
+/*
+ * Use ispeed as the desired speed.  Most implementations don't handle 
+ * separate input and output speeds very well. If the RIO handles this, 
+ * I will have to use separate sets of flags to store them in the 
+ * Port structure.
+ */
+	if ( !sg->sg_ospeed )
+		sg->sg_ospeed = sg->sg_ispeed;
+	else
+		sg->sg_ispeed = sg->sg_ospeed;
+	if (sg->sg_ispeed > V_EXTB ) 
+		sg->sg_ispeed = V_EXTB;
+	if (sg->sg_ispeed < V_B0)
+		sg->sg_ispeed = V_B0;
+	*tsg = *sg;
+   tp->c_cflag = (tp->c_cflag & ~V_CBAUD) | conv_bv[(int)sg->sg_ispeed];
+}
+
+/*
+	ttyseth_pv -- set hardware dependant tty settings using either the
+			POSIX termios structure or the System V termio structure.
+				sysv = 0 => (POSIX):	 struct termios *sg
+				sysv != 0 => (System V): struct termio *sg
+*/
+static void
+ttyseth_pv(PortP, s, sg, sysv)
+struct Port *PortP;
+struct ttystatics *s;
+struct termios *sg;
+int sysv;
+{
+    int speed;
+    unsigned char csize;
+    unsigned char cread;
+    unsigned int lcr_flags;
+    int ps;
+ 
+    if (sysv) {
+        /* sg points to a System V termio structure */
+        csize = ((struct termio *)sg)->c_cflag & CSIZE;
+        cread = ((struct termio *)sg)->c_cflag & CREAD;
+        speed = conv_vb[((struct termio *)sg)->c_cflag & V_CBAUD];
+    }
+    else {
+        /* sg points to a POSIX termios structure */
+        csize = sg->c_cflag & CSIZE;
+        cread = sg->c_cflag & CREAD;
+        speed = conv_vb[sg->c_cflag & V_CBAUD];
+    }
+    if (s->sg.sg_ispeed != speed || s->sg.sg_ospeed != speed) {
+        s->sg.sg_ispeed = speed;
+        s->sg.sg_ospeed = speed;
+        s->tm.c_cflag = (s->tm.c_cflag & ~V_CBAUD) |
+                         conv_bv[(int)s->sg.sg_ispeed];
+    }
+}
+#endif
diff -urN linux-2.2.15-pre2/drivers/char/rio/riotypes.h linux/drivers/char/rio/riotypes.h
--- linux-2.2.15-pre2/drivers/char/rio/riotypes.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riotypes.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,135 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      R I O T Y P E S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jon Brawn
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _riotypes_h
+#define _riotypes_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_riotypes_h_sccs = "@(#)riotypes.h	1.10"; */
+#endif
+#endif
+
+#ifdef INKERNEL
+
+#if !defined(MIPSAT)
+typedef unsigned short NUMBER_ptr;
+typedef unsigned short WORD_ptr;
+typedef unsigned short BYTE_ptr;
+typedef unsigned short char_ptr;
+typedef unsigned short Channel_ptr;
+typedef unsigned short FREE_LIST_ptr_ptr;
+typedef unsigned short FREE_LIST_ptr;
+typedef unsigned short LPB_ptr;
+typedef unsigned short Process_ptr;
+typedef unsigned short PHB_ptr;
+typedef unsigned short PKT_ptr;
+typedef unsigned short PKT_ptr_ptr;
+typedef unsigned short Q_BUF_ptr;
+typedef unsigned short Q_BUF_ptr_ptr;
+typedef unsigned short ROUTE_STR_ptr;
+typedef unsigned short RUP_ptr;
+typedef unsigned short short_ptr;
+typedef unsigned short u_short_ptr;
+typedef unsigned short ushort_ptr;
+#else
+/* MIPSAT types */
+typedef char RIO_POINTER[8];
+typedef RIO_POINTER NUMBER_ptr;
+typedef RIO_POINTER WORD_ptr;
+typedef RIO_POINTER BYTE_ptr;
+typedef RIO_POINTER char_ptr;
+typedef RIO_POINTER Channel_ptr;
+typedef RIO_POINTER FREE_LIST_ptr_ptr;
+typedef RIO_POINTER FREE_LIST_ptr;
+typedef RIO_POINTER LPB_ptr;
+typedef RIO_POINTER Process_ptr;
+typedef RIO_POINTER PHB_ptr;
+typedef RIO_POINTER PKT_ptr;
+typedef RIO_POINTER PKT_ptr_ptr;
+typedef RIO_POINTER Q_BUF_ptr;
+typedef RIO_POINTER Q_BUF_ptr_ptr;
+typedef RIO_POINTER ROUTE_STR_ptr;
+typedef RIO_POINTER RUP_ptr;
+typedef RIO_POINTER short_ptr;
+typedef RIO_POINTER u_short_ptr;
+typedef RIO_POINTER ushort_ptr;
+#endif
+
+#else /* not INKERNEL */
+typedef unsigned char   BYTE;
+typedef unsigned short  WORD;
+typedef unsigned long   DWORD;
+typedef short           NUMBER;
+typedef short           *NUMBER_ptr;
+typedef unsigned short  *WORD_ptr;
+typedef unsigned char   *BYTE_ptr;
+typedef unsigned char   uchar ;
+typedef unsigned short  ushort ;
+typedef unsigned int    uint ;
+typedef unsigned long   ulong ;
+typedef unsigned char   u_char ;
+typedef unsigned short  u_short ;
+typedef unsigned int    u_int ;
+typedef unsigned long   u_long ;
+typedef unsigned short  ERROR ;
+typedef unsigned long ID ;
+typedef char             *char_ptr;
+typedef Channel          *Channel_ptr;
+typedef struct FREE_LIST *FREE_LIST_ptr;
+typedef struct FREE_LIST **FREE_LIST_ptr_ptr;
+typedef struct LPB       *LPB_ptr;
+typedef struct Process   *Process_ptr;
+typedef struct PHB       *PHB_ptr;
+typedef struct PKT       *PKT_ptr;
+typedef struct PKT       **PKT_ptr_ptr;
+typedef struct Q_BUF     *Q_BUF_ptr;
+typedef struct Q_BUF     **Q_BUF_ptr_ptr;
+typedef struct ROUTE_STR *ROUTE_STR_ptr;
+typedef struct RUP       *RUP_ptr;
+typedef short            *short_ptr;
+typedef u_short          *u_short_ptr;
+typedef ushort           *ushort_ptr;
+typedef struct PKT	 PKT;
+typedef struct LPB	 LPB;
+typedef struct RUP	 RUP;
+#endif
+
+
+#endif /* __riotypes__ */
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/riowinif.h linux/drivers/char/rio/riowinif.h
--- linux-2.2.15-pre2/drivers/char/rio/riowinif.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riowinif.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1335 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	RIO Shared Memory Window Inteface	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	7th June 1999				*/
+/*									*/
+/*	Version		:	1.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1999	*
+ *      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.
+ *									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing RIO host card shared	memory	*/
+/*				window interface structures:		*/
+/*					PARMMAP				*/
+/*					RUP				*/
+/*					PHB				*/
+/*					LPB				*/
+/*					PKT				*/
+/*									*/
+/************************************************************************/
+
+/* History...
+
+1.0.0	07/06/99 NPV	Creation. (based on PARMMAP.H)
+
+*/
+
+#ifndef	_riowinif_h				/* If RIOWINDIF.H not already defined */
+#define	_riowinif_h    1
+
+/*****************************************************************************
+********************************             *********************************
+********************************   General   *********************************
+********************************             *********************************
+*****************************************************************************/
+
+#define	TPNULL		((_u16)(0x8000))
+
+/*****************************************************************************
+********************************              ********************************
+********************************   PARM_MAP   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+/* The PARM_MAP structure defines global values relating to the Host Card / RTA
+   and is the main structure from which all other structures are referenced. */
+
+typedef	struct	_PARM_MAP
+{
+	_u16	phb_ptr;		/* 0x00 Pointer to the PHB array */
+	_u16	phb_num_ptr;		/* 0x02 Ptr to Number of PHB's */
+	_u16	free_list;		/* 0x04 Free List pointer */
+	_u16	free_list_end;		/* 0x06 Free List End pointer */
+	_u16	q_free_list_ptr;	/* 0x08 Ptr to Q_BUF variable */
+	_u16	unit_id_ptr;		/* 0x0A Unit Id */
+	_u16	link_str_ptr;		/* 0x0C Link Structure Array */
+	_u16	bootloader_1;		/* 0x0E 1st Stage Boot Loader */
+	_u16	bootloader_2;		/* 0x10 2nd Stage Boot Loader */
+	_u16	port_route_map_ptr;	/* 0x12 Port Route Map */
+	_u16	route_ptr;		/* 0x14 Route Map */
+	_u16	map_present;		/* 0x16 Route Map present */
+	_u16	pkt_num;		/* 0x18 Total number of packets */
+	_u16	q_num;			/* 0x1A Total number of Q packets */
+	_u16	buffers_per_port;	/* 0x1C Number of buffers per port */
+	_u16	heap_size;		/* 0x1E Initial size of heap */
+	_u16	heap_left;		/* 0x20 Current Heap left */
+	_u16	error;			/* 0x22 Error code */
+	_u16	tx_max;			/* 0x24 Max number of tx pkts per phb */
+	_u16	rx_max;			/* 0x26 Max number of rx pkts per phb */
+	_u16	rx_limit;		/* 0x28 For high / low watermarks */
+	_u16	links;			/* 0x2A Links to use */
+	_u16	timer;			/* 0x2C Interrupts per second */
+	_u16	rups;			/* 0x2E Pointer to the RUPs */
+	_u16	max_phb;		/* 0x30 Mostly for debugging */
+	_u16	living;			/* 0x32 Just increments!! */
+	_u16	init_done;		/* 0x34 Initialisation over */
+	_u16	booting_link;		/* 0x36 */
+	_u16	idle_count;		/* 0x38 Idle time counter */
+	_u16	busy_count;		/* 0x3A Busy counter */
+	_u16	idle_control;		/* 0x3C Control Idle Process */
+	_u16	tx_intr;		/* 0x3E TX interrupt pending */
+	_u16	rx_intr;		/* 0x40 RX interrupt pending */
+	_u16	rup_intr;		/* 0x42 RUP interrupt pending */
+
+} PARM_MAP;
+
+/* Same thing again, but defined as offsets... */
+
+#define	PM_phb_ptr		0x00	/* 0x00 Pointer to the PHB array */
+#define	PM_phb_num_ptr		0x02	/* 0x02 Ptr to Number of PHB's */
+#define	PM_free_list		0x04	/* 0x04 Free List pointer */
+#define	PM_free_list_end	0x06	/* 0x06 Free List End pointer */
+#define	PM_q_free_list_ptr	0x08	/* 0x08 Ptr to Q_BUF variable */
+#define	PM_unit_id_ptr		0x0A	/* 0x0A Unit Id */
+#define	PM_link_str_ptr		0x0C	/* 0x0C Link Structure Array */
+#define	PM_bootloader_1		0x0E	/* 0x0E 1st Stage Boot Loader */
+#define	PM_bootloader_2		0x10	/* 0x10 2nd Stage Boot Loader */
+#define	PM_port_route_map_ptr	0x12	/* 0x12 Port Route Map */
+#define	PM_route_ptr		0x14	/* 0x14 Route Map */
+#define	PM_map_present		0x16	/* 0x16 Route Map present */
+#define	PM_pkt_num		0x18	/* 0x18 Total number of packets */
+#define	PM_q_num		0x1A	/* 0x1A Total number of Q packets */
+#define	PM_buffers_per_port	0x1C	/* 0x1C Number of buffers per port */
+#define	PM_heap_size		0x1E	/* 0x1E Initial size of heap */
+#define	PM_heap_left		0x20	/* 0x20 Current Heap left */
+#define	PM_error		0x22	/* 0x22 Error code */
+#define	PM_tx_max		0x24	/* 0x24 Max number of tx pkts per phb */
+#define	PM_rx_max		0x26	/* 0x26 Max number of rx pkts per phb */
+#define	PM_rx_limit		0x28	/* 0x28 For high / low watermarks */
+#define	PM_links		0x2A	/* 0x2A Links to use */
+#define	PM_timer		0x2C	/* 0x2C Interrupts per second */
+#define	PM_rups			0x2E	/* 0x2E Pointer to the RUPs */
+#define	PM_max_phb		0x30	/* 0x30 Mostly for debugging */
+#define	PM_living		0x32	/* 0x32 Just increments!! */
+#define	PM_init_done		0x34	/* 0x34 Initialisation over */
+#define	PM_booting_link		0x36	/* 0x36 */
+#define	PM_idle_count		0x38	/* 0x38 Idle time counter */
+#define	PM_busy_count		0x3A	/* 0x3A Busy counter */
+#define	PM_idle_control		0x3C	/* 0x3C Control Idle Process */
+#define	PM_tx_intr		0x3E	/* 0x4E TX interrupt pending */
+#define	PM_rx_intr		0x40	/* 0x40 RX interrupt pending */
+#define	PM_rup_intr		0x42	/* 0x42 RUP interrupt pending */
+#define	sizeof_PARM_MAP		0x44	/* structure size = 0x44 */
+
+/* PARM_MAP.error definitions... */
+#define	E_NO_ERROR		0x00
+#define	E_PROCESS_NOT_INIT	0x01
+#define	E_LINK_TIMEOUT		0x02
+#define	E_NO_ROUTE		0x03
+#define	E_CONFUSED		0x04
+#define	E_HOME			0x05
+#define	E_CSUM_FAIL		0x06
+#define	E_DISCONNECTED		0x07
+#define	E_BAD_RUP		0x08
+#define	E_NO_VIRGIN		0x09
+#define	E_BOOT_RUP_BUSY		0x10
+#define	E_CHANALLOC		0x80
+#define	E_POLL_ALLOC		0x81
+#define	E_LTTWAKE		0x82
+#define	E_LTT_ALLOC		0x83
+#define	E_LRT_ALLOC		0x84
+#define	E_CIRRUS		0x85
+#define	E_MONITOR		0x86
+#define	E_PHB_ALLOC		0x87
+#define	E_ARRAY_ALLOC		0x88
+#define	E_QBUF_ALLOC		0x89
+#define	E_PKT_ALLOC		0x8a
+#define	E_GET_TX_Q_BUF		0x8b
+#define	E_GET_RX_Q_BUF		0x8c
+#define	E_MEM_OUT		0x8d
+#define	E_MMU_INIT		0x8e
+#define	E_LTT_INIT		0x8f
+#define	E_LRT_INIT		0x90
+#define	E_LINK_RUN		0x91
+#define	E_MONITOR_ALLOC		0x92
+#define	E_MONITOR_INIT		0x93
+#define	E_POLL_INIT		0x94
+
+/* PARM_MAP.links definitions... */
+#define	RIO_LINK_ENABLE	0x80FF
+
+/*****************************************************************************
+**********************************         ***********************************
+**********************************   RUP   ***********************************
+**********************************         ***********************************
+*****************************************************************************/
+
+/* The RUP (Remote Unit Port) structure relates to the Remote Terminal Adapters
+   attached to the system and there is normally an array of MAX_RUPS (=16) structures
+   in a host card, defined by PARM_MAP->rup. */
+
+typedef	struct	_RUP
+{
+	_u16		txpkt;			/* 0x00 Outgoing packet */
+	_u16		rxpkt;			/* 0x02 ncoming packet */
+	_u16		link;			/* 0x04 Which link to send packet down ? */
+	_u8		rup_dest_unit[2];	/* 0x06 Destination Unit */
+	_u16		handshake;		/* 0x08 Handshaking */
+	_u16		timeout;		/* 0x0A Timeout */
+	_u16		status;			/* 0x0C Status */
+	_u16		txcontrol;		/* 0x0E Transmit control */
+	_u16		rxcontrol;		/* 0x10 Receive control */
+
+} RUP;
+
+/* Same thing again, but defined as offsets... */
+
+#define	RUP_txpkt		0x00		/* 0x00 Outgoing packet */
+#define	RUP_rxpkt		0x02		/* 0x02 Incoming packet */
+#define	RUP_link		0x04		/* 0x04 Which link to send packet down ? */
+#define	RUP_rup_dest_unit	0x06		/* 0x06 Destination Unit */
+#define	RUP_handshake		0x08		/* 0x08 Handshaking */
+#define	RUP_timeout		0x0A		/* 0x0A Timeout */
+#define	RUP_status		0x0C		/* 0x0C Status */
+#define	RUP_txcontrol		0x0E		/* 0x0E Transmit control */
+#define	RUP_rxcontrol		0x10		/* 0x10 Receive control */
+#define	sizeof_RUP		0x12		/* structure size = 0x12 */
+
+#define MAX_RUP			16
+
+/* RUP.txcontrol definitions... */
+#define	TX_RUP_INACTIVE		0		/* Nothing to transmit */
+#define	TX_PACKET_READY		1		/* Transmit packet ready */
+#define	TX_LOCK_RUP		2		/* Transmit side locked */
+
+/* RUP.txcontrol definitions... */
+#define	RX_RUP_INACTIVE		0		/* Nothing received */
+#define	RX_PACKET_READY		1		/* Packet received */
+
+#define	RUP_NO_OWNER		0xFF		/* RUP not owned by any process */
+
+/*****************************************************************************
+**********************************         ***********************************
+**********************************   PHB   ***********************************
+**********************************         ***********************************
+*****************************************************************************/
+
+/* The PHB (Port Header Block) structure relates to the serial ports attached
+   to the system and there is normally an array of MAX_PHBS (=128) structures
+   in a host card, defined by PARM_MAP->phb_ptr and PARM_MAP->phb_num_ptr. */
+
+typedef	struct	_PHB
+{
+	_u16		source;			/* 0x00 Location of the PHB in the host card */
+	_u16		handshake;		/* 0x02 Used to manage receive packet flow control */
+	_u16		status;			/* 0x04 Internal port transmit/receive status */
+	_u16		timeout;		/* 0x06 Time period to wait for an ACK */
+	_u16		link;			/* 0x08 The host link associated with the PHB */
+	_u16		destination;		/* 0x0A Location of the remote port on the network */
+
+	_u16		tx_start;		/* 0x0C first entry in the packet array for transmit packets */
+	_u16		tx_end;			/* 0x0E last entry in the packet array for transmit packets */
+	_u16		tx_add;			/* 0x10 position in the packet array for new transmit packets */
+	_u16		tx_remove;		/* 0x12 current position in the packet pointer array */
+
+	_u16		rx_start;		/* 0x14 first entry in the packet array for receive packets */
+	_u16		rx_end;			/* 0x16 last entry in the packet array for receive packets */
+	_u16		rx_add;			/* 0x18 position in the packet array for new receive packets */
+	_u16		rx_remove;		/* 0x1A current position in the packet pointer array */
+
+} PHB;
+
+/* Same thing again, but defined as offsets... */
+
+#define	PHB_source		0x00		/* 0x00 Location of the PHB in the host card */
+#define	PHB_handshake		0x02		/* 0x02 Used to manage receive packet flow control */
+#define	PHB_status		0x04		/* 0x04 Internal port transmit/receive status */
+#define	PHB_timeout		0x06		/* 0x06 Time period to wait for an ACK */
+#define	PHB_link		0x08		/* 0x08 The host link associated with the PHB */
+#define	PHB_destination		0x0A		/* 0x0A Location of the remote port on the network */
+#define	PHB_tx_start		0x0C		/* 0x0C first entry in the packet array for transmit packets */
+#define	PHB_tx_end		0x0E		/* 0x0E last entry in the packet array for transmit packets */
+#define	PHB_tx_add		0x10		/* 0x10 position in the packet array for new transmit packets */
+#define	PHB_tx_remove		0x12		/* 0x12 current position in the packet pointer array */
+#define	PHB_rx_start		0x14		/* 0x14 first entry in the packet array for receive packets */
+#define	PHB_rx_end		0x16		/* 0x16 last entry in the packet array for receive packets */
+#define	PHB_rx_add		0x18		/* 0x18 position in the packet array for new receive packets */
+#define	PHB_rx_remove		0x1A		/* 0x1A current position in the packet pointer array */
+#define	sizeof_PHB		0x1C		/* structure size = 0x1C */
+
+/* PHB.handshake definitions... */
+#define	PHB_HANDSHAKE_SET	0x0001		/* Set by LRT */
+#define	PHB_HANDSHAKE_RESET	0x0002		/* Set by ISR / driver */
+#define	PHB_HANDSHAKE_FLAGS	(PHB_HANDSHAKE_RESET|PHB_HANDSHAKE_SET)
+						/* Reset by ltt */
+
+#define	MAX_PHB			128		/* range 0-127 */
+
+/*****************************************************************************
+**********************************         ***********************************
+**********************************   LPB   ***********************************
+**********************************         ***********************************
+*****************************************************************************/
+
+/* The LPB (Link Parameter Block) structure relates to a RIO Network Link
+   and there is normally an array of MAX_LINKS (=4) structures in a host card,
+   defined by PARM_MAP->link_str_ptr. */
+
+typedef	struct	_LPB
+{
+	_u16		link_number;		/* 0x00 Link Number */
+	_u16		in_ch;			/* 0x02 Link In Channel */
+	_u16		out_ch;			/* 0x04 Link Out Channel */
+	_u8		attached_serial[4];	/* 0x06 Attached serial number */
+	_u8		attached_host_serial[4];/* 0x0A Serial number of Host who booted other end */
+	_u16		descheduled;		/* 0x0E Currently Descheduled */
+	_u16		state;			/* 0x10 Current state */
+	_u16		send_poll;		/* 0x12 Send a Poll Packet */
+	_u16		ltt_p;			/* 0x14 Process Descriptor */
+	_u16		lrt_p;			/* 0x16 Process Descriptor */
+	_u16		lrt_status;		/* 0x18 Current lrt status */
+	_u16		ltt_status;		/* 0x1A Current ltt status */
+	_u16		timeout;		/* 0x1C Timeout value */
+	_u16		topology;		/* 0x1E Topology bits */
+	_u16		mon_ltt;		/* 0x20 */
+	_u16		mon_lrt;		/* 0x22 */
+	_u16		num_pkts;		/* 0x24 */
+	_u16		add_packet_list;	/* 0x26 Add packets to here */
+	_u16		remove_packet_list;	/* 0x28 Send packets from here */
+
+	_u16		lrt_fail_chan;		/* 0x2A Lrt's failure channel */
+	_u16		ltt_fail_chan;		/* 0x2C Ltt's failure channel */
+
+	RUP		rup;			/* 0x2E RUP structure for HOST to driver comms */
+	RUP		link_rup;		/* 0x40 RUP for the link (POLL, topology etc.) */
+	_u16		attached_link;		/* 0x52 Number of attached link */
+	_u16		csum_errors;		/* 0x54 csum errors */
+	_u16		num_disconnects;	/* 0x56 number of disconnects */
+	_u16		num_sync_rcvd;		/* 0x58 # sync's received */
+	_u16		num_sync_rqst;		/* 0x5A # sync requests */
+	_u16		num_tx;			/* 0x5C Num pkts sent */
+	_u16		num_rx;			/* 0x5E Num pkts received */
+	_u16		module_attached;	/* 0x60 Module tpyes of attached */
+	_u16		led_timeout;		/* 0x62 LED timeout */
+	_u16		first_port;		/* 0x64 First port to service */
+	_u16		last_port;		/* 0x66 Last port to service */
+
+} LPB;
+
+/* Same thing again, but defined as offsets... */
+
+#define	LPB_link_number		0x00		/* 0x00 Link Number */
+#define	LPB_in_ch		0x02		/* 0x02 Link In Channel */
+#define	LPB_out_ch		0x04		/* 0x04 Link Out Channel */
+#define	LPB_attached_serial	0x06		/* 0x06 Attached serial number */
+#define	LPB_attached_host_serial 0x0A		/* 0x0A Serial number of Host who booted other end */
+#define	LPB_descheduled		0x0E		/* 0x0E Currently Descheduled */
+#define	LPB_state		0x10		/* 0x10 Current state */
+#define	LPB_send_poll		0x12		/* 0x12 Send a Poll Packet */
+#define	LPB_ltt_p		0x14		/* 0x14 Process Descriptor */
+#define	LPB_lrt_p		0x16		/* 0x16 Process Descriptor */
+#define	LPB_lrt_status		0x18		/* 0x18 Current lrt status */
+#define	LPB_ltt_status		0x1A		/* 0x1A Current ltt status */
+#define	LPB_timeout		0x1C		/* 0x1C Timeout value */
+#define	LPB_topology		0x1E		/* 0x1E Topology bits */
+#define	LPB_mon_ltt		0x20		/* 0x20 */
+#define	LPB_mon_lrt		0x22		/* 0x22 */
+#define	LPB_num_pkts		0x24		/* 0x24 */
+#define	LPB_add_packet_list	0x26		/* 0x26 Add packets to here */
+#define	LPB_remove_packet_list	0x28		/* 0x28 Send packets from here */
+#define	LPB_lrt_fail_chan	0x2A		/* 0x2A Lrt's failure channel */
+#define	LPB_ltt_fail_chan	0x2C		/* 0x2C Ltt's failure channel */
+#define	LPB_rup			0x2E		/* 0x2E RUP structure for HOST to driver comms */
+#define	LPB_link_rup		0x40		/* 0x40 RUP for the link (POLL, topology etc.) */
+#define	LPB_attached_link	0x52		/* 0x52 Number of attached link */
+#define	LPB_csum_errors		0x54		/* 0x54 csum errors */
+#define	LPB_num_disconnects	0x56		/* 0x56 number of disconnects */
+#define	LPB_num_sync_rcvd	0x58		/* 0x58 # sync's received */
+#define	LPB_num_sync_rqst	0x5A		/* 0x5A # sync requests */
+#define	LPB_num_tx		0x5C		/* 0x5C Num pkts sent */
+#define	LPB_num_rx		0x5E		/* 0x5E Num pkts received */
+#define	LPB_module_attached	0x60		/* 0x60 Module tpyes of attached */
+#define	LPB_led_timeout		0x62		/* 0x62 LED timeout */
+#define	LPB_first_port		0x64		/* 0x64 First port to service */
+#define	LPB_last_port		0x66		/* 0x66 Last port to service */
+#define	sizeof_LPB		0x68		/* structure size = 0x68 */
+
+#define	LINKS_PER_UNIT		4		/* number of links from a host */
+
+/*****************************************************************************
+********************************               *******************************
+********************************   FREE_LIST   *******************************
+********************************               *******************************
+*****************************************************************************/
+
+/* Used to overlay packet headers when allocating/freeing packets from the free list */
+
+typedef	struct	_FREE_LIST
+{
+	_u16		next;			/* 0x00 offset of next list item */
+	_u16		prev;			/* 0x02 offset of previous list item */
+
+} FREE_LIST;
+
+/* Same thing again, but defined as offsets... */
+
+#define	FL_next			0x00		/* 0x00 offset of next list item */
+#define	FL_prev			0x02		/* 0x02 offset of previous list item */
+
+/*****************************************************************************
+**********************************         ***********************************
+**********************************   PKT   ***********************************
+**********************************         ***********************************
+*****************************************************************************/
+
+/* The PKT is the main unit of communication between Host Cards and RTAs across
+   the RIO network.  */
+
+#define PKT_MAX_DATA_LEN   72			/* Size of packet data */
+
+typedef	struct	_PKT
+{
+	_u8		dest_unit;		/* 0x00 Destination Unit Id */
+	_u8		dest_port;		/* 0x01 Destination Port */
+	_u8		src_unit;		/* 0x02 Source Unit Id */
+	_u8		src_port;		/* 0x03 Source Port */
+	_u8		len;			/* 0x04 Length (in bytes) of data field */
+	_u8		control;		/* 0x05 */
+	_u8		data[PKT_MAX_DATA_LEN];	/* 0x06 Actual data */
+	_u16		csum;			/* 0x4E C-SUM */
+
+} PKT;
+
+/* Same thing again, but defined as offsets... */
+
+#define	PKT_dest_unit		0x00		/* 0x00 Destination Unit Id */
+#define	PKT_dest_port		0x01		/* 0x01 Destination Port */
+#define	PKT_src_unit		0x02		/* 0x02 Source Unit Id */
+#define	PKT_src_port		0x03		/* 0x03 Source Port */
+#define	PKT_len			0x04		/* 0x04 Length (in bytes) of data field */
+#define	PKT_control		0x05		/* 0x05 */
+#define	PKT_data		0x06		/* 0x06 Actual data */
+#define	PKT_csum		0x4E		/* 0x4E C-SUM */
+#define	sizeof_PKT		0x50		/* structure size = 0x50 */
+
+/* PKT.len definitions... */
+#define	PKT_CMD_BIT		0x80
+#define	PKT_CMD_DATA		0x80
+#define	PKT_LEN_MASK		0x7F
+
+/* PKT.control definitions... */
+#define	PKT_ACK			0x40
+#define	PKT_TGL			0x20
+#define	DATA_WNDW		0x10
+#define	PKT_TTL_MASK		0x0F
+#define	MAX_TTL			0x0F
+
+/*****************************************************************************
+*****************************                     ****************************
+*****************************   Control Packets   ****************************
+*****************************                     ****************************
+*****************************************************************************/
+
+/* The following definitions and structures define the control packets sent
+   between the driver and RIO Ports, RTAs and Host Cards. */
+
+#define	PRE_EMPTIVE		0x80			/* Pre-emptive command (sent via port's RUP) */
+
+/* "in-band" and "pre-emptive" port commands... */
+#define	OPEN			0x00			/* Driver->RIO Open a port */
+#define	CONFIG			0x01			/* Driver->RIO Configure a port */
+#define	MOPEN			0x02			/* Driver->RIO Modem open (wait for DCD) */
+#define	CLOSE			0x03			/* Driver->RIO Close a port */
+#define	WFLUSH			(0x04|PRE_EMPTIVE)	/* Driver->RIO Write flush */
+#define	RFLUSH			(0x05|PRE_EMPTIVE)	/* Driver->RIO Read flush */
+#define	RESUME			(0x06|PRE_EMPTIVE)	/* Driver->RIO Behave as if XON received */
+#define	SBREAK			0x07			/* Driver->RIO Start break */
+#define	EBREAK			0x08			/* Driver->RIO End break */
+#define	SUSPEND			(0x09|PRE_EMPTIVE)	/* Driver->RIO Behave as if XOFF received */
+#define	FCLOSE			(0x0A|PRE_EMPTIVE)	/* Driver->RIO Force close */
+#define	XPRINT			0x0B			/* Driver->RIO Xprint packet */
+#define	MBIS			(0x0C|PRE_EMPTIVE)	/* Driver->RIO Set modem lines */
+#define	MBIC			(0x0D|PRE_EMPTIVE)	/* Driver->RIO Clear modem lines */
+#define	MSET			(0x0E|PRE_EMPTIVE)	/* Driver->RIO Set modem lines */
+#define	PCLOSE			0x0F			/* Driver->RIO Pseudo close */
+#define	MGET			(0x10|PRE_EMPTIVE)	/* Driver->RIO Force update of modem status */
+#define	MEMDUMP			(0x11|PRE_EMPTIVE)	/* Driver->RIO DEBUG request for RTA memory */
+#define	READ_REGISTER		(0x12|PRE_EMPTIVE)	/* Driver->RIO DEBUG read CD1400 register */
+
+/* Remote Unit Port (RUP) packet definitions... (specified in PKT.dest_unit and PKT.src_unit) */
+#define	SYNC_RUP		0xFF			/* Download internal */
+#define	COMMAND_RUP		0xFE			/* Command ack/status */
+#define	ERROR_RUP		0xFD			/* Download internal */
+#define	POLL_RUP		0xFC			/* Download internal */
+#define	BOOT_RUP		0xFB			/* Used to boot RTAs */
+#define	ROUTE_RUP		0xFA			/* Used to specify routing/topology */
+#define	STATUS_RUP		0xF9			/* Not used */
+#define	POWER_RUP		0xF8			/* Download internal */
+
+/* COMMAND_RUP definitions... */
+#define	COMPLETE		(0x20|PRE_EMPTIVE)	/* RIO->Driver Command complete */
+#define	BREAK_RECEIVED		(0x21|PRE_EMPTIVE)	/* RIO->Driver Break received */
+#define	MODEM_STATUS		(0x22|PRE_EMPTIVE)	/* RIO->Driver Modem status change */
+
+/* BOOT_RUP definitions... */
+#define	BOOT_REQUEST		0x00			/* RIO->Driver Request for boot */
+#define	BOOT_ABORT		0x01			/* Driver->RIO Abort a boot */
+#define	BOOT_SEQUENCE		0x02			/* Driver->RIO Packet with firmware details */
+#define	BOOT_COMPLETED		0x03			/* RIO->Driver Boot completed */
+#define IFOAD			0x2F			/* Driver->RIO Shutdown/Reboot RTA (Fall Over And Die) */
+#define	IDENTIFY		0x30			/* Driver->RIO Identify RTA */
+#define	ZOMBIE			0x31			/* Driver->RIO Shutdown/Flash LEDs */
+#define	UFOAD			0x32			/* Driver->RIO Shutdown/Reboot neighbouring RTA */
+#define IWAIT			0x33			/* Driver->RIO Pause booting process */
+
+/* ROUTE_RUP definitions... */
+#define	ROUTE_REQUEST		0x00			/* RIO->Driver Request an ID */
+#define	ROUTE_FOAD		0x01			/* Driver->RIO Shutdown/reboot RTA */
+#define	ROUTE_ALREADY		0x02			/* Driver->RIO Not used */
+#define	ROUTE_USED		0x03			/* Driver->RIO Not used */
+#define	ROUTE_ALLOCATE		0x04			/* Driver->RIO Allocate RTA RUP numbers */
+#define	ROUTE_REQ_TOP		0x05			/* Driver->RIO Not used */
+#define ROUTE_TOPOLOGY		0x06			/* RIO->Driver Route/Topology status */
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   OPEN   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   Sent to open a port. 
+   Structure of configuration info used with OPEN, CONFIG and MOPEN packets... */
+
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_Cor1		(PKT_Data+1)		/* Channel Option Register 1 */
+#define	PKT_Cor2		(PKT_Data+2)		/* Channel Option Register 2 */
+#define	PKT_Cor4		(PKT_Data+3)		/* Channel Option Register 4 */
+#define	PKT_Cor5		(PKT_Data+4)		/* Channel Option Register 5 */
+#define	PKT_TxXon		(PKT_Data+5)		/* Transmit XON character */
+#define	PKT_TxXoff		(PKT_Data+6)		/* Transmit XOFF character */
+#define	PKT_RxXon		(PKT_Data+7)		/* Receive XON character */
+#define	PKT_RxXoff		(PKT_Data+8)		/* Receive XOFF character */
+#define	PKT_Lnext		(PKT_Data+9)		/* Lnext character */
+#define	PKT_TxBaud		(PKT_Data+10)		/* Transmit baud rate */
+#define	PKT_RxBaud		(PKT_Data+11)		/* Receive baud rate */
+
+/* COR1 definitions... */
+#define	COR1_PARITY		0xE0			/* Parity mask */
+#define	COR1_NONE		0x00			/* No parity */
+#define	COR1_SPACE		0x20			/* Space parity */
+#define	COR1_EVEN		0x40			/* Even parity */
+#define	COR1_MARK		0xA0			/* Mark parity */
+#define	COR1_ODD		0xC0			/* Odd parity */
+
+#define	COR1_STOPBITS		0x0C			/* Stop bits mask */
+#define	COR1_STOP1		0x00			/* 1 stop bit */
+#define	COR1_STOP1_5		0x04			/* 1.5 stop bits */
+#define	COR1_STOP2		0x08			/* 2 stop bits */
+
+#define	COR1_DATABITS		0x03			/* Data bits mask */
+#define	COR1_DATA5		0x00			/* 5 data bits */
+#define	COR1_DATA6		0x01			/* 6 data bits */
+#define	COR1_DATA7		0x02			/* 7 data bits */
+#define	COR1_DATA8		0x03			/* 8 data bits */
+
+/* COR2 definitions... */
+#define	COR2_XON_TXFLOW		0x40			/* XON/XOFF Transmit Flow */
+#define	COR2_XANY_TXFLOW	0xC0			/* XON/XANY Transmit Flow */
+#define	COR2_HUPCL		0x20			/* Hang Up On Close */
+#define	COR2_DSR_TXFLOW		0x08			/* DSR Transmit Flow Control */
+#define	COR2_RTS_RXFLOW		0x04			/* RTS Receive Flow Control */
+#define	COR2_CTS_TXFLOW		0x02			/* CTS Transmit Flow Control */
+#define	COR2_XON_RXFLOW		0x01			/* XON/XOFF Receive Flow */
+
+/* COR4 definition... */
+#define	COR4_IGNCR		0x80			/* Discard received CR */
+#define	COR4_ICRNL		0x40			/* Map received CR -> NL */
+#define	COR4_INLCR		0x20			/* Map received NL -> CR */
+#define	COR4_IGNBRK		0x10			/* Ignore Received Break */
+#define	COR4_NBRKINT		0x08			/* No interrupt on rx Break */
+#define	COR4_IGNPAR		0x04			/* ignore rx parity error chars */
+#define	COR4_PARMRK		0x02			/* Mark rx parity error chars */
+#define	COR4_RAISEMOD		0x01			/* Raise modem lines on !0 baud */
+
+/* COR5 definitions... */
+#define	COR5_ISTRIP		0x80			/* Strip input chars to 7 bits */
+#define	COR5_LNE		0x40			/* Enable LNEXT processing */
+#define	COR5_CMOE		0x20			/* Match good & error characters */
+#define	COR5_TAB3		0x10			/* TAB3 mode */
+#define	COR5_TSTATE_ON		0x08			/* Enable tbusy/tstop monitoring */
+#define	COR5_TSTATE_OFF		0x04			/* Disable tbusy/tstop monitoring */
+#define	COR5_ONLCR		0x02			/* NL -> CR NL on output */
+#define	COR5_OCRNL		0x01			/* CR -> NL on output */
+
+/* RxBaud and TxBaud definitions... */
+#define	RIO_B0			0x00			/* RTS / DTR signals dropped */
+#define	RIO_B50			0x01			/* 50 baud */
+#define	RIO_B75			0x02			/* 75 baud */
+#define	RIO_B110		0x03			/* 110 baud */
+#define	RIO_B134		0x04			/* 134.5 baud */
+#define	RIO_B150		0x05			/* 150 baud */
+#define	RIO_B200		0x06			/* 200 baud */
+#define	RIO_B300		0x07			/* 300 baud */
+#define	RIO_B600		0x08			/* 600 baud */
+#define	RIO_B1200		0x09			/* 1200 baud */
+#define	RIO_B1800		0x0A			/* 1800 baud */
+#define	RIO_B2400		0x0B			/* 2400 baud */
+#define	RIO_B4800		0x0C			/* 4800 baud */
+#define	RIO_B9600		0x0D			/* 9600 baud */
+#define	RIO_B19200		0x0E			/* 19200 baud */
+#define	RIO_B38400		0x0F			/* 38400 baud */
+#define	RIO_B56000		0x10			/* 56000 baud */
+#define	RIO_B57600		0x11			/* 57600 baud */
+#define	RIO_B64000		0x12			/* 64000 baud */
+#define	RIO_B115200		0x13			/* 115200 baud */
+#define	RIO_B2000		0x14			/* 2000 baud */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   CONFIG   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   CONFIG is sent from the driver to configure an already opened port.
+   Packet structure is same as OPEN.  */
+
+/*****************************************************************************
+*********************************           **********************************
+*********************************   MOPEN   **********************************
+*********************************           **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   MOPEN is sent from the driver to open a port attached to a modem. (in-band)
+   Packet structure is same as OPEN.  */
+
+/*****************************************************************************
+*********************************           **********************************
+*********************************   CLOSE   **********************************
+*********************************           **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   CLOSE is sent from the driver to close a previously opened port.
+   No parameters.
+ */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+/*****************************************************************************
+*********************************            *********************************
+*********************************   WFLUSH   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   WFLUSH is sent pre-emptively from the driver to flush the write buffers and
+   packets of a port.  (pre-emptive)
+   
+   WFLUSH is also sent in-band from the driver to a port as a marker to end
+   write flushing previously started by a pre-emptive WFLUSH packet. (in-band)
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   RFLUSH   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   RFLUSH is sent pre-emptively from the driver to flush the read buffers and
+   packets of a port.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   RESUME   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   RESUME is sent pre-emptively from the driver to cause a port to resume 
+   transmission of data if blocked by XOFF.  (as if XON had been received)
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   SBREAK   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   SBREAK is sent in-band from the driver to a port to suspend data and start
+   break signal transmission.
+
+   If the break delay is 0, the break signal will be acknowledged with a
+   RUP_COMMAND, COMPLETE packet and continue until an EBREAK packet is received.
+
+   Otherwise, there is no acknowledgement and the break signal will last for the
+   specified number of mS.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_BreakDelay		(PKT_Data+1)		/* Break delay in mS */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   EBREAK   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   EBREAK is sent in-band from the driver to a port to stop transmission of a
+   break signal.
+
+   No parameters.  */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   SUSPEND   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   SUSPEND is sent pre-emptively from the driver to cause a port to suspend
+   transmission of data.  (as if XOFF had been received)
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   FCLOSE   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   FCLOSE is sent pre-emptively from the driver to force close a port.
+   A force close flushes receive and transmit queues, and also lowers all output
+   modem signals if the COR5_HUPCL (Hang Up On Close) flag is set.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   XPRINT   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   XPRINT is sent as a normal I/O data packet except that the PKT_CMD_BIT of
+   the "len" field is set, and the first "data" byte is XPRINT.
+
+   The I/O data in the XPRINT packet will contain the following:
+   -	Transparent Print Start Sequence
+   -	Transparent Print Data
+   -	Transparent Print Stop Sequence.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   MBIS   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MBIS is sent pre-emptively from the driver to set a port's modem signals.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+#define	PKT_ModemSet		(PKT_Data+4)		/* Modem set signals mask */
+
+/* ModemSet definitions... */
+#define	MBIS_RTS		0x01			/* RTS modem signal */
+#define	MBIS_DTR		0x02			/* DTR modem signal */
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   MBIC   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MBIC is sent pre-emptively from the driver to clear a port's modem signals.
+   */
+#if 0   
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+#define	PKT_ModemClear		(PKT_Data+4)		/* Modem clear signals mask */
+
+/* ModemClear definitions... */
+#define	MBIC_RTS		0x01			/* RTS modem signal */
+#define	MBIC_DTR		0x02			/* DTR modem signal */
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   MSET   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MSET is sent pre-emptively from the driver to set/clear a port's modem signals. */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+#define	PKT_ModemSet		(PKT_Data+4)		/* Modem set signals mask */
+
+/* ModemSet definitions... */
+#define	MSET_RTS		0x01			/* RTS modem signal */
+#define	MSET_DTR		0x02			/* DTR modem signal */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   PCLOSE   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   PCLOSE is sent from the driver to pseudo close a previously opened port.
+   
+   The port will close when all data has been sent/received, however, the
+   port's transmit / receive and modem signals will be left enabled and the
+   port marked internally as Pseudo Closed. */
+
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   MGET   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MGET is sent pre-emptively from the driver to request the port's current modem signals. */
+
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   MEMDUMP   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MEMDUMP is sent pre-emptively from the driver to request a dump of 32 bytes
+   of the specified port's RTA address space.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#define	PKT_Address		(PKT_Data+6)		/* Requested address */
+
+/*****************************************************************************
+******************************                   *****************************
+******************************   READ_REGISTER   *****************************
+******************************                   *****************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   READ_REGISTER is sent pre-emptively from the driver to request the contents
+   of the CD1400 register specified in address.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#define	PKT_Address		(PKT_Data+6)		/* Requested address */
+
+/*****************************************************************************
+************************                            **************************
+************************   COMMAND_RUP - COMPLETE   **************************
+************************                            **************************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - COMPLETE is sent in response to all port I/O control command
+   packets, except MEMDUMP and READ_REGISTER.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#define	PKT_ModemStatus		(PKT_Data+3)		/* Modem signal status */
+#define	PKT_PortStatus		(PKT_Data+4)		/* Port signal status */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+
+/* ModemStatus definitions... */
+#define	MODEM_DSR		0x80			/* Data Set Ready modem state */
+#define	MODEM_CTS		0x40			/* Clear To Send modem state */
+#define	MODEM_RI		0x20			/* Ring Indicate modem state */
+#define	MODEM_CD		0x10			/* Carrier Detect modem state */
+#define	MODEM_TSTOP		0x08			/* Transmit Stopped state */
+#define	MODEM_TEMPTY		0x04			/* Transmit Empty state */
+#define	MODEM_DTR		0x02			/* DTR modem output state */
+#define	MODEM_RTS		0x01			/* RTS modem output state */
+
+/* PortStatus definitions... */
+#define	PORT_ISOPEN		0x01			/* Port open ? */
+#define	PORT_HUPCL		0x02			/* Hangup on close? */
+#define	PORT_MOPENPEND		0x04			/* Modem open pending */
+#define	PORT_ISPARALLEL		0x08			/* Parallel port */
+#define	PORT_BREAK		0x10			/* Port on break */
+#define	PORT_STATUSPEND		0020			/* Status packet pending */
+#define	PORT_BREAKPEND		0x40			/* Break packet pending */
+#define	PORT_MODEMPEND		0x80			/* Modem status packet pending */
+
+/*****************************************************************************
+************************                            **************************
+************************   COMMAND_RUP - COMPLETE   **************************
+************************                            **************************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - COMPLETE is sent in response to all port I/O control command
+   packets, except MEMDUMP and READ_REGISTER.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#endif
+#define	PKT_ModemStatus		(PKT_Data+3)		/* Modem signal status */
+#define	PKT_PortStatus		(PKT_Data+4)		/* Port signal status */
+#if 0
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#endif
+
+/* ModemStatus definitions... */
+#define	MODEM_DSR		0x80			/* Data Set Ready modem state */
+#define	MODEM_CTS		0x40			/* Clear To Send modem state */
+#define	MODEM_RI		0x20			/* Ring Indicate modem state */
+#define	MODEM_CD		0x10			/* Carrier Detect modem state */
+#define	MODEM_TSTOP		0x08			/* Transmit Stopped state */
+#define	MODEM_TEMPTY		0x04			/* Transmit Empty state */
+#define	MODEM_DTR		0x02			/* DTR modem output state */
+#define	MODEM_RTS		0x01			/* RTS modem output state */
+
+/* PortStatus definitions... */
+#define	PORT_ISOPEN		0x01			/* Port open ? */
+#define	PORT_HUPCL		0x02			/* Hangup on close? */
+#define	PORT_MOPENPEND		0x04			/* Modem open pending */
+#define	PORT_ISPARALLEL		0x08			/* Parallel port */
+#define	PORT_BREAK		0x10			/* Port on break */
+#define	PORT_STATUSPEND		0020			/* Status packet pending */
+#define	PORT_BREAKPEND		0x40			/* Break packet pending */
+#define	PORT_MODEMPEND		0x80			/* Modem status packet pending */
+
+/*****************************************************************************
+********************                                      ********************
+********************   COMMAND_RUP - COMPLETE - MEMDUMP   ********************
+********************                                      ********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - COMPLETE - MEMDUMP is sent as an acknowledgement for a MEMDUMP
+   port I/O control command packet.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#define	PKT_ModemStatus		(PKT_Data+3)		/* Modem signal status */
+#define	PKT_PortStatus		(PKT_Data+4)		/* Port signal status */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#define	PKT_Address		(PKT_Data+6)		/* Requested address */
+#endif
+#define	PKT_Dump		(PKT_Data+8)		/* 32bytes of requested dump data */
+
+/*****************************************************************************
+*****************                                            *****************
+*****************   COMMAND_RUP - COMPLETE - READ_REGISTER   *****************
+*****************                                            *****************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - COMPLETE - READ_REGISTER is sent as an acknowledgement for a
+   READ_REGISTER port I/O control command packet.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/*Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/*Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#endif
+#define	PKT_RegisterValue	(PKT_Data+3)		/* Modem signal status */
+#if 0
+#define	PKT_PortStatus		(PKT_Data+4)		/* Port signal status */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#endif
+
+/*****************************************************************************
+*********************                                  ***********************
+*********************   COMMAND_RUP - BREAK_RECEIVED   ***********************
+*********************                                  ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - BREAK_RECEIVED packets are sent when the port detects a receive BREAK signal.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#endif
+
+/*****************************************************************************
+*********************                                *************************
+*********************   COMMAND_RUP - MODEM_STATUS   *************************
+*********************                                *************************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - MODEM_STATUS packets are sent whenever the port detects a
+   change in the input modem signal states.
+
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#define	PKT_ModemStatus		(PKT_Data+3)		/* Modem signal status */
+#endif
+
+/*****************************************************************************
+************************                             *************************
+************************   BOOT_RUP - BOOT_REQUEST   *************************
+************************                             *************************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   BOOT_RUP - BOOT_REQUEST packets are sent to the Driver from RIO to request
+   firmware code to load onto attached RTAs.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+
+/*****************************************************************************
+************************                              ************************
+************************   BOOT_RUP - BOOT_SEQUENCE   ************************
+************************                              ************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - BOOT_SEQUENCE packets are sent from the Driver to RIO in response
+   to a BOOT_RUP - BOOT_REQUEST packet.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_NumPackets		(PKT_Data+2)		/* Packets required to load firmware */
+#define	PKT_LoadBase		(PKT_Data+4)		/* RTA firmware load address */
+#define	PKT_CodeSize		(PKT_Data+6)		/* Size of firmware in bytes */
+#define	PKT_CmdString		(PKT_Data+8)		/* Command string */
+
+/*****************************************************************************
+************************                               ***********************
+************************   BOOT_RUP - BOOT_COMPLETED   ***********************
+************************                               ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   BOOT_RUP - BOOT_COMPLETE is sent to the Driver from RIO when downloading of
+   RTA firmware has completed.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_LinkNumber		(PKT_Data+1)		/* Link number RTA booted on */
+#define	PKT_SerialNumber	(PKT_Data+2)		/* 4 byte serial number */
+
+/*****************************************************************************
+************************                               ***********************
+************************   BOOT_RUP - Packet Request   ***********************
+************************                               ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   BOOT_RUP packet without the PKT_CMD_BIT set in the PKT->len field is sent
+   from RIO to the Driver as a request for a firmware boot packet. */
+
+#define	PKT_SequenceNumber	(PKT_Data+0)		/* Packet sequence number */
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   BOOT_RUP - Packet Response   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   In response to a BOOT_RUP boot packet request, the driver fills out the response
+   packet with the 70 bytes of the requested sequence.
+   */
+#if 0
+#define	PKT_SequenceNumber	(PKT_Data+0)		/* Packet sequence number */
+#endif
+#define	PKT_FirmwarePacket	(PKT_Data+2)		/* Firmware packet */
+
+/*****************************************************************************
+****************************                      ****************************
+****************************   BOOT_RUP - IFOAD   ****************************
+****************************                      ****************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - IFOAD packets are sent from the Driver to an RTA to cause the
+   RTA to shut down and reboot.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_IfoadId1		(PKT_Data+2)		/* IFOAD Id 1 */
+#define	PKT_IfoadId2		(PKT_Data+3)		/* IFOAD Id 2 */
+
+#define	IFOADID1		0xAD
+#define	IFOADID2		0xF0
+
+/*****************************************************************************
+**************************                         ***************************
+**************************   BOOT_RUP - IDENTIFY   ***************************
+**************************                         ***************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - IDENTIFY packets are sent from the Driver to an RTA to cause the
+   RTA to flash its LEDs for a period of time.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_IdentifyId		(PKT_Data+2)		/* defines pattern to flash */
+
+/*****************************************************************************
+****************************                       ***************************
+****************************   BOOT_RUP - ZOMBIE   ***************************
+****************************                       ***************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - ZOMBIE packets are sent from the Driver to an RTA to cause the
+   RTA to shut down and flash it's LEDs.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_ZombieId1		(PKT_Data+2)		/* ZOMBIE Id 1 */
+#define	PKT_ZombieId2		(PKT_Data+3)		/* ZOMBIE Id 2 */
+
+#define	ZOMBIEID1		0x52
+#define	ZOMBIEID2		0x21
+
+/*****************************************************************************
+****************************                      ****************************
+****************************   BOOT_RUP - UFOAD   ****************************
+****************************                      ****************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - UFOAD packets are sent from the Driver to an RTA to cause the RTA
+   to ask it's neighbouring RTA to shut down and reboot.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_LinkNumber		(PKT_Data+1)		/* Link number of RTA to UFOAD */
+#endif
+#define	PKT_UfoadId1		(PKT_Data+2)		/* UFOAD Id 1 */
+#define	PKT_UfoadId2		(PKT_Data+3)		/* UFOAD Id 2 */
+
+#define	UFOADID1		0x1E
+#define	UFOADID2		0x0D
+
+/*****************************************************************************
+****************************                      ****************************
+****************************   BOOT_RUP - IWAIT   ****************************
+****************************                      ****************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - IWAIT packets are sent from the Driver to an RTA to cause the RTA
+   to pause booting on the specified link for 30 seconds.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_LinkNumber		(PKT_Data+1)		/* Link number of RTA to UFOAD */
+#endif
+#define	PKT_IwaitId1		(PKT_Data+2)		/* IWAIT Id 1 */
+#define	PKT_IwaitId2		(PKT_Data+3)		/* IWAIT Id 2 */
+
+#define	IWAITID1		0xDE
+#define	IWAITID2		0xB1
+
+/*****************************************************************************
+************************                               ***********************
+************************   ROUTE_RUP - ROUTE_REQUEST   ***********************
+************************                               ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   ROUTE_RUP - ROUTE_REQUEST packets are sent from a newly booted or connected
+   RTA to a Driver to request an ID (RUP or unit number).
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_SerialNumber	(PKT_Data+2)		/* 4 byte serial number */
+#define	PKT_ModuleTypes		(PKT_Data+6)		/* RTA Module types */
+
+/* ModuleTypes definitions... */
+#define	MOD_BLANK		0x0F			/* Blank plate attached */
+#define	MOD_RS232DB25		0x00			/* RS232 DB25 connector */
+#define	MOD_RS232RJ45		0x01			/* RS232 RJ45 connector */
+#define	MOD_RS422DB25		0x02			/* RS422 DB25 connector */
+#define	MOD_RS485DB25		0x03			/* RS485 DB25 connector */
+#define	MOD_PARALLEL		0x04			/* Centronics parallel */
+
+#define	MOD2			0x08			/* Set to indicate Rev2 module */
+
+/*****************************************************************************
+*************************                            *************************
+*************************   ROUTE_RUP - ROUTE_FOAD   *************************
+*************************                            *************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   ROUTE_RUP - ROUTE_FOAD packet is sent as a response to a ROUTE_RUP - ROUTE_REQUEST
+   packet to cause the RTA to "Fall Over And Die"., i.e. shutdown and reboot.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_RouteCmdString	(PKT_Data+2)		/* Command string */
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   ROUTE_RUP - ROUTE_ALLOCATE   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   ROUTE_RUP - ROUTE_ALLOCATE packet is sent as a response to a ROUTE_RUP - ROUTE_REQUEST
+   packet to allocate the RTA's Id number (RUP number 1..16)
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_IdNum		(PKT_Data+1)		/* RUP number for ports 1..8 */
+#if 0
+#define	PKT_RouteCmdString	(PKT_Data+2)		/* Command string */
+#endif
+#define	PKT_IdNum2		(PKT_Data+0x17)		/* RUP number for ports 9..16 */
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   ROUTE_RUP - ROUTE_TOPOLOGY   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   ROUTE_RUP - ROUTE_TOPOLOGY packet is sent to inform the driver of an RTA's
+   current link status.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_Link1Rup		(PKT_Data+2)		/* Link 1 RUP number */
+#define	PKT_Link1Link		(PKT_Data+3)		/* Link 1 link number */
+#define	PKT_Link2Rup		(PKT_Data+4)		/* Link 2 RUP number */
+#define	PKT_Link2Link		(PKT_Data+5)		/* Link 2 link number */
+#define	PKT_Link3Rup		(PKT_Data+6)		/* Link 3 RUP number */
+#define	PKT_Link3Link		(PKT_Data+7)		/* Link 3 link number */
+#define	PKT_Link4Rup		(PKT_Data+8)		/* Link 4 RUP number */
+#define	PKT_Link4Link		(PKT_Data+9)		/* Link 4 link number */
+#define	PKT_RtaVpdProm		(PKT_Data+10)		/* 32 bytes of RTA VPD PROM Contents */
+
+#endif						/* _sxwinif_h */
+
+/* End of RIOWINIF.H */
diff -urN linux-2.2.15-pre2/drivers/char/rio/riscos.h linux/drivers/char/rio/riscos.h
--- linux-2.2.15-pre2/drivers/char/rio/riscos.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riscos.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,63 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riscos.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:19
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)riscos.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_riscos_h__
+#define __rio_riscos_h__
+
+#ifdef SCCS_LABELS
+static char *_riscos_h_sccs_ = "@(#)riscos.h	1.2";
+#endif
+
+/*
+** This module used to define all those little itsy bits required for RISC/OS
+** now it's full of null macros.
+*/
+
+/*
+**	RBYTE reads a byte from a location.
+**	RWORD reads a word from a location.
+**	WBYTE writes a byte to a location.
+**	WWORD writes a word to a location.
+**	RINDW reads a word through a pointer.
+**	WINDW writes a word through a pointer.
+**	RIOSWAB swaps the two bytes of a word, if needed.
+*/
+
+#define	RIOSWAB(N)      (N)
+#define	WBYTE(A,V)	(A)=(uchar)(V)
+#define WWORD(A,V)	(A)=(ushort)(V)
+#define RBYTE(A)	(uchar)(A)
+#define RWORD(A)	(ushort)(A)
+#define RINDW(A)	(*(ushort *)(A))
+#define WINDW(A,V)	(*(ushort *)(A)=(ushort)(V))
+
+#endif /* __rio_riscos_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/rom.h linux/drivers/char/rio/rom.h
--- linux-2.2.15-pre2/drivers/char/rio/rom.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rom.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,64 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      R O M
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _rom_h
+#define _rom_h 1
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_rom_h_sccs = "@(#)rom.h	1.1" ;
+#endif
+#endif
+
+typedef struct  ROM  ROM ;
+struct  ROM  {
+                 u_short    slx ;
+                 char       pcb_letter_rev ;
+                 char       pcb_number_rev ;
+                 char       serial[4] ;
+                 char       year ;
+                 char       week ;
+             } ;
+
+#endif
+
+#define HOST_ROM    (ROM *) 0x7c00
+#define RTA_ROM	    (ROM *) 0x7801
+#define ROM_LENGTH  0x20
+
+/*********** end of file ***********/
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/route.h linux/drivers/char/rio/route.h
--- linux-2.2.15-pre2/drivers/char/rio/route.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/route.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,108 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                 R O U T E     H E A D E R
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _route_h
+#define _route_h
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_route_h_sccs = "@(#)route.h	1.3"; */
+#endif
+#endif
+
+#define MAX_LINKS 4
+#define MAX_NODES 17                          /* Maximum nodes in a subnet */
+#define NODE_BYTES ((MAX_NODES / 8) + 1)      /* Number of bytes needed for
+                                                 1 bit per node */
+#define ROUTE_DATA_SIZE  (NODE_BYTES + 2)     /* Number of bytes for complete 
+                                                 info about cost etc. */
+#define ROUTES_PER_PACKET ((PKT_MAX_DATA_LEN -2)/ ROUTE_DATA_SIZE)
+                                              /* Number of nodes we can squeeze
+                                                 into one packet */
+#define MAX_TOPOLOGY_PACKETS (MAX_NODES / ROUTES_PER_PACKET + 1)
+/************************************************
+ * Define the types of command for the ROUTE RUP.
+ ************************************************/
+#define ROUTE_REQUEST    0                    /* Request an ID */
+#define ROUTE_FOAD       1                    /* Kill the RTA */
+#define ROUTE_ALREADY    2                    /* ID given already */
+#define ROUTE_USED       3                    /* All ID's used */
+#define ROUTE_ALLOCATE   4                    /* Here it is */
+#define ROUTE_REQ_TOP    5                    /* I bet you didn't expect....
+                                                 the Topological Inquisition */
+#define ROUTE_TOPOLOGY   6                    /* Topology request answered FD */
+/*******************************************************************
+ * Define the Route Map Structure
+ *
+ * The route map gives a pointer to a Link Structure to use.
+ * This allows Disconnected Links to be checked quickly
+ ******************************************************************/
+typedef struct COST_ROUTE COST_ROUTE;
+struct COST_ROUTE {
+                      unsigned char cost;        /* Cost down this link */
+                      unsigned char route[NODE_BYTES]; /* Nodes thorough this route */
+                  } ;
+
+typedef struct ROUTE_STR ROUTE_STR ;
+struct  ROUTE_STR {
+                      COST_ROUTE cost_route[MAX_LINKS];
+                                                /* cost / route for this link */
+                      ushort favoured;          /* favoured link */
+                  } ;
+
+
+#define NO_LINK            (short) 5      /* Link unattached */
+#define ROUTE_NO_ID        (short) 100    /* No Id */
+#define ROUTE_DISCONNECT   (ushort) 0xff  /* Not connected */
+#define ROUTE_INTERCONNECT (ushort) 0x40  /* Sub-net interconnect */
+
+
+#define SYNC_RUP         (ushort) 255
+#define COMMAND_RUP      (ushort) 254
+#define ERROR_RUP        (ushort) 253
+#define POLL_RUP         (ushort) 252
+#define BOOT_RUP         (ushort) 251
+#define ROUTE_RUP        (ushort) 250
+#define STATUS_RUP       (ushort) 249
+#define POWER_RUP        (ushort) 248
+
+#define HIGHEST_RUP      (ushort) 255   /* Set to Top one */
+#define LOWEST_RUP       (ushort) 248   /* Set to bottom one */
+
+#endif
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/rtahw.h linux/drivers/char/rio/rtahw.h
--- linux-2.2.15-pre2/drivers/char/rio/rtahw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rtahw.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,75 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******                R T A    H A R D W A R E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_rtahw_h_sccs = "@(#)rtahw.h	1.5" ;
+#endif
+#endif
+
+#define	WATCHDOG_ADDR	((unsigned short *)0x7a00)
+#define RTA_LED_ADDR	((unsigned short *)0x7c00)
+#define SERIALNUM_ADDR	((unsigned char *)0x7809)
+#define LATCH_ADDR      ((unsigned char *)0x7800)
+
+/*
+** Here we define where the cd1400 chips are in memory.
+*/
+#define CD1400_ONE_ADDR		(0x7300)
+#define CD1400_TWO_ADDR		(0x7200)
+#define CD1400_THREE_ADDR	(0x7100)
+#define CD1400_FOUR_ADDR	(0x7000)
+
+/*
+** Define the different types of modules we can have
+*/
+enum module {
+    MOD_BLANK		= 0x0f,		/* Blank plate attached */
+    MOD_RS232DB25	= 0x00,		/* RS232 DB25 connector */
+    MOD_RS232RJ45	= 0x01,		/* RS232 RJ45 connector */
+    MOD_RS422DB25	= 0x02,		/* RS422 DB25 connector */
+    MOD_RS485DB25	= 0x03,		/* RS485 DB25 connector */
+    MOD_PARALLEL	= 0x04		/* Centronics parallel */
+};
+
+#define TYPE_HOST	0
+#define TYPE_RTA8	1
+#define TYPE_RTA16	2
+
+#define	WATCH_DOG	WATCHDOG_ADDR
+
+/*********** end of file ***********/
diff -urN linux-2.2.15-pre2/drivers/char/rio/rup.h linux/drivers/char/rio/rup.h
--- linux-2.2.15-pre2/drivers/char/rio/rup.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rup.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,82 @@
+/****************************************************************************
+ *******                                                              *******
+ *******               R U P   S T R U C T U R E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _rup_h
+#define _rup_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_rup_h_sccs = "@(#)rup.h	1.5"; */
+#endif
+#endif
+
+#if defined( HOST ) || defined( INKERNEL )
+#define MAX_RUP          ((short) 16) 
+#endif
+#ifdef RTA
+#define MAX_RUP          ((short) 1)
+#endif
+
+#define PKTS_PER_RUP     ((short) 2)     /* They are always used in pairs */
+
+/*************************************************
+ * Define all the  packet request stuff
+ ************************************************/
+#define TX_RUP_INACTIVE          0        /* Nothing to transmit */
+#define TX_PACKET_READY          1        /* Transmit packet ready */
+#define TX_LOCK_RUP              2        /* Transmit side locked */
+
+#define RX_RUP_INACTIVE          0        /* Nothing received */
+#define RX_PACKET_READY          1        /* Packet received */
+
+#define RUP_NO_OWNER             0xff     /* RUP not owned by any process */
+
+struct RUP {
+             PKT_ptr    txpkt;            /* Outgoing packet */
+             PKT_ptr    rxpkt;            /* Incoming packet */
+             WORD       link;             /* Which link to send down? */
+             BYTE       rup_dest_unit[2]; /* Destination unit */
+             WORD       handshake;        /* For handshaking */
+             WORD       timeout;          /* Timeout */
+             WORD       status;           /* Status */
+             WORD       txcontrol;        /* Transmit control */
+             WORD       rxcontrol;        /* Receive control */
+           };
+ 
+#endif
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/rupstat.h linux/drivers/char/rio/rupstat.h
--- linux-2.2.15-pre2/drivers/char/rio/rupstat.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rupstat.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,51 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      RUPSTAT
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _rupstat_h
+#define _rupstat_h
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_rupstat_h_sccs = "@(#)rupstat.h	1.1" ;
+#endif
+#endif
+
+#define    STATUS_SYNC    0
+#define    STATUS_REQ_TOP 1
+#define    STATUS_TOPOLOGY    2
+
+#endif
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/sam.h linux/drivers/char/rio/sam.h
--- linux-2.2.15-pre2/drivers/char/rio/sam.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/sam.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,74 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                    S A M . H
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+#ifndef _sam_h
+#define _sam_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_sam_h_sccs = "@(#)sam.h	1.3"; */
+#endif
+#endif
+
+
+#if !defined( HOST ) && !defined( INKERNEL )
+#define RTA 1
+#endif
+
+#define NUM_FREE_LIST_UNITS     500
+
+#ifndef FALSE
+#define FALSE (short)  0x00
+#endif
+#ifndef TRUE
+#define TRUE  (short)  !FALSE
+#endif
+
+#define TX    TRUE
+#define RX    FALSE
+
+
+typedef struct FREE_LIST FREE_LIST ;
+struct FREE_LIST   {
+                       FREE_LIST_ptr next ;
+                       FREE_LIST_ptr prev ;
+                   } ;
+
+
+#endif
+/*********** end of file ***********/
+
+
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/selftest.h linux/drivers/char/rio/selftest.h
--- linux-2.2.15-pre2/drivers/char/rio/selftest.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/selftest.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,73 @@
+/*
+** File:		selftest.h
+**
+** Author:		David Dix
+**
+** Created:		15th March 1993
+**
+** Last modified:	94/06/14
+**
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+*/
+
+#ifndef	_selftests_h_
+#define _selftests_h_
+
+/*
+** Selftest identifier...
+*/
+#define SELFTEST_MAGIC	0x5a5a
+
+/*
+** This is the structure of the packet that is sent back after each
+** selftest on a booting RTA.
+*/
+typedef struct {
+    short		magic;			/* Identifies packet type */
+    int			test;			/* Test number, see below */
+    unsigned int	result;			/* Result value */
+    unsigned int	dataIn;
+    unsigned int	dataOut;
+}selftestStruct;
+
+/*
+** The different tests are identified by the following data values.
+*/
+enum test {
+    TESTS_COMPLETE	= 0x00,
+    MEMTEST_ADDR	= 0x01,
+    MEMTEST_BIT		= 0x02,
+    MEMTEST_FILL	= 0x03,
+    MEMTEST_DATABUS	= 0x04,
+    MEMTEST_ADDRBUS	= 0x05,
+    CD1400_INIT		= 0x10,
+    CD1400_LOOP		= 0x11,
+    CD1400_INTERRUPT    = 0x12
+};
+
+enum result {
+    E_PORT		= 0x10,
+    E_TX		= 0x11,
+    E_RX		= 0x12,
+    E_EXCEPT		= 0x13,
+    E_COMPARE		= 0x14,
+    E_MODEM		= 0x15,
+    E_TIMEOUT		= 0x16,
+    E_INTERRUPT         = 0x17
+};
+#endif	/* _selftests_h_ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/space.h linux/drivers/char/rio/space.h
--- linux-2.2.15-pre2/drivers/char/rio/space.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/space.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,45 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: space.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:19
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)space.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_space_h__
+#define __rio_space_h__
+
+#ifdef SCCS_LABELS
+static char *_space_h_sccs_ = "@(#)space.h	1.2";
+#endif
+
+extern int rio_cntls;
+extern int rio_bases[];
+extern int rio_limits[];
+extern int rio_vects[];
+
+#endif /* __rio_space_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/sysmap.h linux/drivers/char/rio/sysmap.h
--- linux-2.2.15-pre2/drivers/char/rio/sysmap.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/sysmap.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,63 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******          S Y S T E M   M A P   H E A D E R
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_sysmap_h_sccs = "@(#)sysmap.h	1.1" ;
+#endif
+#endif
+
+#define SYSTEM_MAP_LEN     64           /* Len of System Map array */
+
+
+typedef struct SYS_MAP        SYS_MAP ;
+typedef struct SYS_MAP_LINK   SYS_MAP_LINK ;
+
+struct SYS_MAP_LINK {
+                        short id ;          /* Unit Id */
+                        short link ;        /* Id's Link */
+                        short been_here ;   /* Used by map_gen */
+                    } ;
+
+struct SYS_MAP {
+                   char         serial_num[4] ;
+                   SYS_MAP_LINK link[4] ;
+               } ;
+
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/timeouts.h linux/drivers/char/rio/timeouts.h
--- linux-2.2.15-pre2/drivers/char/rio/timeouts.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/timeouts.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,51 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******                     T I M E O U T S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_defaults_h_sccs = "@(#)timeouts.h	1.3" ;
+#endif
+#endif
+
+#define MILLISECOND           (int) (1000/64)   /* 15.625 low ticks */
+#define SECOND                (int) 15625       /* Low priority ticks */
+
+#define TX_TIMEOUT          (int) (200 * MILLISECOND)
+
+
+/*********** end of file ***********/
+
diff -urN linux-2.2.15-pre2/drivers/char/rio/top.h linux/drivers/char/rio/top.h
--- linux-2.2.15-pre2/drivers/char/rio/top.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/top.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,49 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: top.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:19
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)top.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_top_h__
+#define __rio_top_h__
+
+#ifdef SCCS_LABELS
+static char *_top_h_sccs_ = "@(#)top.h	1.2";
+#endif
+
+/*
+** Topology information
+*/
+struct Top
+{
+    uchar Unit;
+    uchar Link;
+};
+
+#endif /* __rio_top_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/typdef.h linux/drivers/char/rio/typdef.h
--- linux-2.2.15-pre2/drivers/char/rio/typdef.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/typdef.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,82 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: typdef.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:20
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)typdef.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_typdef_h__
+#define __rio_typdef_h__
+
+#ifdef SCCS_LABELS
+static char *_typdef_h_sccs_ = "@(#)typdef.h	1.2";
+#endif
+
+#undef VPIX
+
+/*
+** IT IS REALLY, REALLY, IMPORTANT THAT BYTES ARE UNSIGNED!
+**
+** These types are ONLY to be used for refering to data structures
+** on the RIO Host card!
+*/
+typedef	volatile unsigned char	BYTE;
+typedef volatile unsigned short	WORD;
+typedef volatile unsigned int	DWORD;
+typedef	volatile unsigned short RIOP;
+typedef	volatile short          NUMBER;
+
+
+/*
+** 27.01.199 ARG - mods to compile 'newutils' on LyxnOS -
+** These #defines are for the benefit of the 'libfuncs' library
+** only. They are not necessarily correct type mappings and
+** are here only to make the source compile.
+*/
+/* typedef unsigned int	uint; */
+typedef unsigned long	ulong_t;
+typedef unsigned short	ushort_t;
+typedef unsigned char	uchar_t;
+typedef unsigned char	queue_t;
+typedef unsigned char	mblk_t;
+typedef	unsigned int 	paddr_t;
+typedef unsigned char   uchar;
+
+#define	TPNULL	((ushort)(0x8000))
+
+
+/*
+** RIO structures defined in other include files.
+*/
+typedef struct PKT	 	PKT;
+typedef struct LPB	 	LPB;
+typedef struct RUP	 	RUP;
+typedef struct Port		Port;
+typedef struct DpRam		DpRam;
+
+#endif /* __rio_typdef_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/rio/unixrup.h linux/drivers/char/rio/unixrup.h
--- linux-2.2.15-pre2/drivers/char/rio/unixrup.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/unixrup.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,56 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: unixrup.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:20
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)unixrup.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_unixrup_h__
+#define __rio_unixrup_h__
+
+#ifdef SCCS_LABELS
+static char *_unixrup_h_sccs_ = "@(#)unixrup.h	1.2";
+#endif
+
+/*
+**    UnixRup data structure. This contains pointers to actual RUPs on the
+**    host card, and all the command/boot control stuff.
+*/
+struct    UnixRup
+{
+    struct CmdBlk    *CmdsWaitingP;	/* Commands waiting to be done */
+    struct CmdBlk    *CmdPendingP;	/* The command currently being sent */
+    struct RUP       *RupP;		/* the Rup to send it to */
+    uint             Id;		/* Id number */
+    uint             BaseSysPort;	/* SysPort of first tty on this RTA */
+    uint             ModTypes;		/* Modules on this RTA */
+  semtype	RupLock;		/* Lock structure for MPX */
+/*    struct lockb     RupLock;	*/	/* Lock structure for MPX */
+};
+
+#endif /* __rio_unixrup_h__ */
diff -urN linux-2.2.15-pre2/drivers/char/serial.c linux/drivers/char/serial.c
--- linux-2.2.15-pre2/drivers/char/serial.c	Tue Jan  4 10:12:15 2000
+++ linux/drivers/char/serial.c	Mon Dec  3 21:57:53 2001
@@ -1383,8 +1383,13 @@
 	if (info->state->type == PORT_16750)
 		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
 	serial_outp(info, UART_LCR, cval);		/* reset DLAB */
-	if (info->state->type != PORT_16750)
+	if (info->state->type != PORT_16750) {
+		if (fcr & UART_FCR_ENABLE_FIFO) {
+			/* emulated UARTs (Lucent Venus 167x) need two steps */
+			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+		}
 		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
+	}
 	restore_flags(flags);
 }
 
diff -urN linux-2.2.15-pre2/drivers/char/sx.c linux/drivers/char/sx.c
--- linux-2.2.15-pre2/drivers/char/sx.c	Tue Oct 26 17:53:40 1999
+++ linux/drivers/char/sx.c	Mon Dec  3 21:57:53 2001
@@ -222,140 +222,21 @@
 #include "sxboards.h"
 #include "sxwindow.h"
 
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+#include "sx.h"
+
 
 /* I don't think that this driver can handle more than 256 ports on
    one machine. You'll have to increase the number of boards in sx.h
    if you want more than 4 boards.  */
 
 
-/* ************************************************************** */
-/* * This section can be removed when 2.0 becomes outdated....  * */
-/* ************************************************************** */
-
-
-#if LINUX_VERSION_CODE < 0x020100    /* Less than 2.1.0 */
-#define TWO_ZERO
-#else
-#if LINUX_VERSION_CODE < 0x020200   /* less than 2.2.x */
-#warning "Please use a 2.2.x kernel. "
-#else
-#if LINUX_VERSION_CODE < 0x020300   /* less than 2.3.x */
-#define TWO_TWO
-#else
-#define TWO_THREE
-#endif
-#endif
-#endif
-
-#ifdef TWO_ZERO
-
-/* Here is the section that makes the 2.2 compatible driver source 
-   work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, 
-   and provide for compatibility stuff here if possible. */
-
-#include <linux/bios32.h>
-
-#define Get_user(a,b)                a = get_user(b)
-#define Put_user(a,b)                0,put_user(a,b)
-#define copy_to_user(a,b,c)          memcpy_tofs(a,b,c)
-
-static inline int copy_from_user(void *to,const void *from, int c) 
-{
-  memcpy_fromfs(to, from, c);
-  return 0;
-}
-
-#define pci_present                  pcibios_present
-#define pci_read_config_word         pcibios_read_config_word
-#define pci_read_config_dword        pcibios_read_config_dword
-
-static inline unsigned char get_irq (unsigned char bus, unsigned char fn)
-{
-	unsigned char t; 
-	pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t);
-	return t;
-}
-
-static inline void *ioremap(unsigned long base, long length)
-{
-	if (base < 0x100000) return (void *)base;
-	return vremap (base, length);
-}
-
-#define my_iounmap(x, b)             (((long)x<0x100000)?0:vfree ((void*)x))
-
-#define capable(x)                   suser()
-
-#define queue_task                   queue_task_irq_off
-#define tty_flip_buffer_push(tty)    queue_task(&tty->flip.tqueue, &tq_timer)
-#define signal_pending(current)      (current->signal & ~current->blocked)
-#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
-#define time_after(t1,t2)            (((long)t1-t2) > 0)
-
-
-#define test_and_set_bit(nr, addr)   set_bit(nr, addr)
-#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
-
-/* Not yet implemented on 2.0 */
-#define ASYNC_SPD_SHI  -1
-#define ASYNC_SPD_WARP -1
-
-
-/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
-   to the "name" field that does exist. As long as the assignments are
-   done in the right order, there is nothing to worry about. */
-#define driver_name           name 
-
-/* Should be in a header somewhere. They are in tty.h on 2.2 */
-#define TTY_HW_COOK_OUT       14 /* Flag to tell ntty what we can handle */
-#define TTY_HW_COOK_IN        15 /* in hardware - output and input       */
-
-/* The return type of a "close" routine. */
-#define INT                   void
-#define NO_ERROR              /* Nothing */
-
-#else
-
-/* The 2.2.x compatibility section. */
-#include <asm/uaccess.h>
-
-
-#define Get_user(a,b)         get_user(a,b)
-#define Put_user(a,b)         put_user(a,b)
-#define get_irq(pdev)         pdev->irq
-
-#define INT                   int
-#define NO_ERROR              0
-
-#define my_iounmap(x,b)       (iounmap((char *)(b)))
-
-#endif
-
-#ifndef TWO_THREE
-/* These are new in 2.3. The source now uses 2.3 syntax, and here is 
-   the compatibility define... */
-#define wait_queue_head_t struct wait_queue *
-#define DECLARE_MUTEX(name) struct semaphore name = MUTEX
-#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL }
-
-#endif
-
-
-
-#include "generic_serial.h"
-#include "sx.h"
-
-
-/* ************************************************************** */
-/* *                End of compatibility section..              * */
-/* ************************************************************** */
-
-
-
 /* Why the hell am I defining these here? */
 #define SX_TYPE_NORMAL 1
 #define SX_TYPE_CALLOUT 2
 
+
 #ifndef SX_NORMAL_MAJOR
 /* This allows overriding on the compiler commandline, or in a "major.h" 
    include or something like that */
@@ -368,7 +249,6 @@
 #endif
 
 
-
 /* Configurable options: 
    (Don't be too sure that it'll work if you toggle them) */
 
@@ -408,7 +288,7 @@
 static void sx_enable_rx_interrupts (void * ptr); 
 static int  sx_get_CD (void * ptr); 
 static void sx_shutdown_port (void * ptr);
-static void sx_set_real_termios (void  *ptr);
+static int  sx_set_real_termios (void  *ptr);
 static void sx_hungup (void  *ptr);
 static void sx_close (void  *ptr);
 static int sx_chars_in_buffer (void * ptr);
@@ -419,8 +299,6 @@
 static int sx_fw_open(struct inode *inode, struct file *filp);
 static INT sx_fw_release(struct inode *inode, struct file *filp);
 static int sx_init_drivers(void);
-void my_hd (unsigned char *addr, int len);
-
 
 
 static struct tty_driver sx_driver, sx_callout_driver;
@@ -591,6 +469,27 @@
 #define TIMEOUT_2 1000000
 
 
+#ifdef DEBUG
+static void my_hd (unsigned char *addr, int len)
+{
+	int i, j, ch;
+
+	for (i=0;i<len;i+=16) {
+		printk ("%08x ", (int) addr+i);
+		for (j=0;j<16;j++) {
+			printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+		}
+		for (j=0;j<16;j++) {
+			ch = addr[j+i];
+			printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+		}
+		printk ("\n");
+	}
+}
+#endif
+
+
+
 /* This needs redoing for Alpha -- REW -- Done. */
 
 inline void write_sx_byte (struct sx_board *board, int offset, u8 byte)
@@ -965,7 +864,7 @@
 /* Simon Allen's version of this routine was 225 lines long. 85 is a lot
    better. -- REW */
 
-static void sx_set_real_termios (void *ptr)
+static int sx_set_real_termios (void *ptr)
 {
 	struct sx_port *port = ptr;
 
@@ -1056,6 +955,7 @@
 	            O_OTHER(port->gs.tty));
 	/* port->c_dcd = sx_get_CD (port); */
 	func_exit ();
+	return 0;
 }
 
 
@@ -2599,7 +2499,7 @@
 }
 
 
-
+#ifdef MODULE
 void cleanup_module(void)
 {
 	int i; 
@@ -2633,33 +2533,9 @@
 	kfree (sx_termios_locked);
 	func_exit();
 }
-
-
-#ifdef DEBUG
-void my_hd (unsigned char *addr, int len)
-{
-	int i, j, ch;
-
-	for (i=0;i<len;i+=16) {
-		printk ("%08x ", (int) addr+i);
-		for (j=0;j<16;j++) {
-			printk ("%02x %s", addr[j+i], (j==7)?" ":"");
-		}
-		for (j=0;j<16;j++) {
-			ch = addr[j+i];
-			printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
-		}
-		printk ("\n");
-	}
-}
 #endif
 
-#ifdef MODULE
-#undef func_enter
-#undef func_exit
 
-#include "generic_serial.c"
-#endif
 
 
 /*
diff -urN linux-2.2.15-pre2/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.2.15-pre2/drivers/char/tty_io.c	Tue Jan  4 10:12:15 2000
+++ linux/drivers/char/tty_io.c	Mon Dec  3 21:57:53 2001
@@ -2205,6 +2205,9 @@
 #ifdef CONFIG_SX
 	sx_init();
 #endif
+#ifdef CONFIG_RIO
+	rio_init();
+#endif
 #ifdef CONFIG_8xx
         rs_8xx_init();
 #endif /* CONFIG_8xx */
diff -urN linux-2.2.15-pre2/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- linux-2.2.15-pre2/drivers/net/eepro100.c	Mon Dec  3 21:57:48 2001
+++ linux/drivers/net/eepro100.c	Mon Dec  3 21:57:53 2001
@@ -620,6 +620,54 @@
 			cards_found++;
 	}
 
+	for (; pci_index < 8; pci_index++) {
+		unsigned char pci_bus, pci_device_fn, pci_latency;
+		long ioaddr;
+		int irq;
+
+		u16 pci_command, new_command;
+
+		if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_82559ER,
+					pci_index, &pci_bus,
+					&pci_device_fn))
+		    break;
+		{
+		    struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+		    ioaddr = pdev->base_address[1];		/* Use [0] to mem-map */
+		    irq = pdev->irq;
+		}
+		/* Remove I/O space marker in bit 0. */
+		ioaddr &= ~3;
+		if (speedo_debug > 2)
+		    printk("Found Intel i82559ER PCI Speedo at I/O %#lx, IRQ %d.\n",
+			   ioaddr, irq);
+		
+		/* Get and check the bus-master and latency values. */
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+					 PCI_COMMAND, &pci_command);
+		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+		if (pci_command != new_command) {
+		    printk(KERN_INFO "  The PCI BIOS has not enabled this"
+			   " device!  Updating PCI command %4.4x->%4.4x.\n",
+			   pci_command, new_command);
+		    pcibios_write_config_word(pci_bus, pci_device_fn,
+					      PCI_COMMAND, new_command);
+		}
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+					 PCI_LATENCY_TIMER, &pci_latency);
+		if (pci_latency < 32) {
+		    printk("  PCI latency timer (CFLT) is unreasonably low at %d."
+			   "  Setting to 32 clocks.\n", pci_latency);
+		    pcibios_write_config_byte(pci_bus, pci_device_fn,
+					      PCI_LATENCY_TIMER, 32);
+		} else if (speedo_debug > 1)
+			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
+		
+		if(speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0, cards_found))
+			cards_found++;
+	}
+
 	return cards_found;
 }
 #endif
diff -urN linux-2.2.15-pre2/drivers/net/epic100.c linux/drivers/net/epic100.c
--- linux-2.2.15-pre2/drivers/net/epic100.c	Mon Dec  3 21:57:48 2001
+++ linux/drivers/net/epic100.c	Mon Dec  3 21:57:53 2001
@@ -135,8 +135,14 @@
 /* The rest of these values should never change. */
 
 static struct device *epic_probe1(int pci_bus, int pci_devfn,
+
 								  struct device *dev, long ioaddr, int irq,
 								  int chip_id, int card_idx);
+								  
+/* For 2.2 resource management we are kind of stuck with this */
+#define USE_IO
+
+								  
 #ifdef USE_IO
 #define EPIC_USE_IO
 #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0
diff -urN linux-2.2.15-pre2/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in
--- linux-2.2.15-pre2/drivers/net/irda/Config.in	Mon Jun  7 16:19:58 1999
+++ linux/drivers/net/irda/Config.in	Mon Dec  3 21:57:53 2001
@@ -6,20 +6,20 @@
 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 'NSC PC87108/PC87338' 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
+   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
+   dep_tristate '  Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA   
 fi
 
 endmenu
diff -urN linux-2.2.15-pre2/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile
--- linux-2.2.15-pre2/drivers/net/irda/Makefile	Tue Oct 26 17:53:40 1999
+++ linux/drivers/net/irda/Makefile	Mon Dec  3 21:57:53 2001
@@ -21,34 +21,18 @@
 endif
 
 ifeq ($(CONFIG_IRPORT_SIR),y)
-L_OBJS += irport.o
+LX_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
+  MX_OBJS += irport.o
   endif
 endif
 
 ifeq ($(CONFIG_NSC_FIR),y)
-L_OBJS += pc87108.o
+L_OBJS += nsc-ircc.o
 else
   ifeq ($(CONFIG_NSC_FIR),m)
-  M_OBJS += pc87108.o
+  M_OBJS += nsc-ircc.o
   endif
 endif
 
@@ -60,14 +44,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_SHARP_FIR),y)
-L_OBJS += uircc.o irport.o
-else
-  ifeq ($(CONFIG_SHARP_FIR),m)
-  M_OBJS += uircc.o irport.o
-  endif
-endif
-
 ifeq ($(CONFIG_TOSHIBA_FIR),y)
 L_OBJS += toshoboe.o
 else
@@ -93,10 +69,12 @@
 endif
 
 ifeq ($(CONFIG_SMC_IRCC_FIR),y)
-L_OBJS += irport.o smc-ircc.o
+L_OBJS += smc-ircc.o
+LX_OBJS += irport.o
 else
   ifeq ($(CONFIG_SMC_IRCC_FIR),m)
-  M_OBJS += irport.o smc-ircc.o
+  M_OBJS += smc-ircc.o
+  MX_OBJS += irport.o
   endif
 endif
 
@@ -137,6 +115,14 @@
 else
   ifeq ($(CONFIG_LITELINK_DONGLE),m)
   M_OBJS += litelink.o
+  endif
+endif
+
+ifeq ($(CONFIG_OLD_BELKIN_DONGLE),y)
+L_OBJS += old_belkin.o
+else
+  ifeq ($(CONFIG_OLD_BELKIN_DONGLE),m)
+  M_OBJS += old_belkin.o
   endif
 endif
 
diff -urN linux-2.2.15-pre2/drivers/net/irda/actisys.c linux/drivers/net/irda/actisys.c
--- linux-2.2.15-pre2/drivers/net/irda/actisys.c	Mon Jun  7 16:19:58 1999
+++ linux/drivers/net/irda/actisys.c	Mon Dec  3 21:57:53 2001
@@ -1,16 +1,18 @@
 /*********************************************************************
  *                
  * Filename:      actisys.c
- * Version:       0.8
+ * Version:       1.0
  * Description:   Implementation for the ACTiSYS IR-220L and IR-220L+ 
  *                dongles
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Status:        Beta.
+ * Authors:       Dag Brattli <dagb@cs.uit.no> (initially)
+ *		  Jean Tourrilhes <jt@hpl.hp.com> (new version)
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Sun May 16 14:35:11 1999
+ * Modified at:   Fri Dec 17 09:10:43 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1999 Jean Tourrilhes
  *      
  *     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 +25,16 @@
  *     
  ********************************************************************/
 
+/*
+ * Changelog
+ *
+ * 0.8 -> 0.9999 - Jean
+ *	o New initialisation procedure : much safer and correct
+ *	o New procedure the change speed : much faster and simpler
+ *	o Other cleanups & comments
+ *	Thanks to Lichen Wang @ Actisys for his excellent help...
+ */
+
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/tty.h>
@@ -32,42 +44,64 @@
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irda_device.h>
-#include <net/irda/dongle.h>
-
-static void actisys_reset(struct irda_device *dev);
-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_init_qos(struct irda_device *idev, struct qos_info *qos);
 
-/* These are the baudrates supported */
-static int baud_rates[] = { 9600, 19200, 57600, 115200, 38400};
+/* 
+ * Define the timing of the pulses we send to the dongle (to reset it, and
+ * to toggle speeds). Basically, the limit here is the propagation speed of
+ * the signals through the serial port, the dongle being much faster.  Any
+ * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can
+ * go through cleanly . If you are on the wild side, you can try to lower
+ * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!)
+ */
+#define MIN_DELAY 10	/* 10 us to be on the conservative side */
 
-static struct dongle dongle = {
-	ACTISYS_DONGLE,
+static int  actisys_change_speed(struct irda_task *task);
+static int  actisys_reset(struct irda_task *task);
+static void actisys_open(dongle_t *self, struct qos_info *qos);
+static void actisys_close(dongle_t *self);
+
+/* These are the baudrates supported, in the order available */
+/* Note : the 220L doesn't support 38400, but we will fix that below */
+static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
+#define MAX_SPEEDS 5
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_ACTISYS_DONGLE,
 	actisys_open,
 	actisys_close,
 	actisys_reset,
 	actisys_change_speed,
-	actisys_init_qos,
 };
 
-static struct dongle dongle_plus = {
-	ACTISYS_PLUS_DONGLE,
+static struct dongle_reg dongle_plus = {
+	Q_NULL,
+	IRDA_ACTISYS_PLUS_DONGLE,
 	actisys_open,
 	actisys_close,
 	actisys_reset,
 	actisys_change_speed,
-	actisys_init_qos,
 };
 
-__initfunc(int actisys_init(void))
+/*
+ * Function actisys_change_speed (task)
+ *
+ *	There is two model of Actisys dongle we are dealing with,
+ * the 220L and 220L+. At this point, only irattach knows with
+ * kind the user has requested (it was an argument on irattach
+ * command line).
+ *	So, we register a dongle of each sort and let irattach
+ * pick the right one...
+ */
+int __init actisys_init(void)
 {
 	int ret;
 
+	/* First, register an Actisys 220L dongle */
 	ret = irda_device_register_dongle(&dongle);
 	if (ret < 0)
 		return ret;
+	/* Now, register an Actisys 220L+ dongle */
 	ret = irda_device_register_dongle(&dongle_plus);
 	if (ret < 0) {
 		irda_device_unregister_dongle(&dongle);
@@ -78,130 +112,165 @@
 
 void actisys_cleanup(void)
 {
+	/* We have to remove both dongles */
 	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(dongle_t *self, struct qos_info *qos)
 {
-	strcat(idev->description, " <-> actisys");
+	/* Power on the dongle */
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+	/* Set the speeds we can accept */
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
 
-        idev->io.dongle_id = type;
-	idev->flags |= IFF_DONGLE;
+	/* Remove support for 38400 if this is not a 220L+ dongle */
+	if (self->issue->type == IRDA_ACTISYS_DONGLE)
+		qos->baud_rate.bits &= ~IR_38400;
+	
+	qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
 
 	MOD_INC_USE_COUNT;
 }
 
-static void actisys_close(struct irda_device *idev)
+static void actisys_close(dongle_t *self)
 {
-	/* Power off dongle */
-	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+	/* Power off the dongle */
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
 
 	MOD_DEC_USE_COUNT;
 }
 
 /*
- * Function actisys_change_speed (tty, baud)
+ * Function actisys_change_speed (task)
  *
  *    Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles.
- *    To cycle through the available baud rates, pulse RTS low for a few
- *    ms.  
+ *    To cycle through the available baud rates, pulse RTS low for a few us.
+ *
+ *	First, we reset the dongle to always start from a known state.
+ *	Then, we cycle through the speeds by pulsing RTS low and then up.
+ *	The dongle allow us to pulse quite fast, se we can set speed in one go,
+ * which is must faster ( < 100 us) and less complex than what is found
+ * in some other dongle drivers...
+ *	Note that even if the new speed is the same as the current speed,
+ * we reassert the speed. This make sure that things are all right,
+ * and it's fast anyway...
+ *	By the way, this function will work for both type of dongles,
+ * because the additional speed is at the end of the sequence...
  */
-static void actisys_change_speed(struct irda_device *idev, int baudrate)
+static int actisys_change_speed(struct irda_task *task)
 {
-        int current_baudrate;
-        int index = 0;
-	
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	current_baudrate = idev->qos.baud_rate.value;
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;	/* Target speed */
+	int ret = 0;
+	int i = 0;
+
+        IRDA_DEBUG(4, __FUNCTION__ "(), speed=%d (was %d)\n", speed, 
+		   self->speed);
+
+	/* Go to a known state by reseting the dongle */
+
+	/* Reset the dongle : set DTR low for 10 us */
+	self->set_dtr_rts(self->dev, FALSE, TRUE);
+	udelay(MIN_DELAY);
+
+	/* Go back to normal mode (we are now at 9600 b/s) */
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+ 
+	/* 
+	 * Now, we can set the speed requested. Send RTS pulses until we
+         * reach the target speed 
+	 */
+	for (i=0; i<MAX_SPEEDS; i++) {
+		if (speed == baud_rates[i]) {
+			self->speed = baud_rates[i];
+			break;
+		}
+		/* Make sure previous pulse is finished */
+		udelay(MIN_DELAY);
+
+		/* Set RTS low for 10 us */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+		udelay(MIN_DELAY);
+
+		/* Set RTS high for 10 us */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+	}
+
+	/* Check if life is sweet... */
+	if (i >= MAX_SPEEDS)
+		ret = -1;  /* This should not happen */
 
-	/* Find the correct baudrate index for the currently used baudrate */
-	while (current_baudrate != baud_rates[index])
-		index++;
-
-        DEBUG( 4, __FUNCTION__ "(), index=%d\n", index);
-
-	/* Cycle through avaiable baudrates until we reach the correct one */
-        while (current_baudrate != baudrate) {	
-                DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n",
-		      baud_rates[index]);
-		
-		/* Set DTR, clear RTS */
-		irda_device_set_dtr_rts(idev, TRUE, FALSE);
-		
-		/* Wait at a few ms */
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(2);
+	/* Basta lavoro, on se casse d'ici... */
+	irda_task_next_state(task, IRDA_TASK_DONE);
 
-		/* Set DTR, Set RTS */
-		irda_device_set_dtr_rts(idev, TRUE, TRUE);
-		
-		/* Wait at a few ms again */
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(2);
-
-                /* Go to next baudrate */
-		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]);
+	return ret;
 }
 
 /*
- * Function actisys_reset (dev)
+ * Function actisys_reset (task)
  *
  *      Reset the Actisys type dongle. Warning, this function must only be
  *      called with a process context!
  *
- *    	1. Clear DTR for a few ms.
+ * We need to do two things in this function :
+ *	o first make sure that the dongle is in a state where it can operate
+ *	o second put the dongle in a know state
  *
+ *	The dongle is powered of the RTS and DTR lines. In the dongle, there
+ * is a big capacitor to accomodate the current spikes. This capacitor
+ * takes a least 50 ms to be charged. In theory, the Bios set those lines
+ * up, so by the time we arrive here we should be set. It doesn't hurt
+ * to be on the conservative side, so we will wait...
+ *	Then, we set the speed to 9600 b/s to get in a known state (see in
+ * change_speed for details). It is needed because the IrDA stack
+ * has tried to set the speed immediately after our first return,
+ * so before we can be sure the dongle is up and running.
  */
-static void actisys_reset(struct irda_device *idev)
+static int actisys_reset(struct irda_task *task)
 {
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	/* Clear DTR */
-	irda_device_set_dtr_rts(idev, FALSE, TRUE);
+	dongle_t *self = (dongle_t *) task->instance;
+	int ret = 0;
 
-	/* Sleep 10-20 ms*/
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(2);
-	
-	/* Go back to normal mode */
-	irda_device_set_dtr_rts(idev, TRUE, TRUE);
-	
-	idev->qos.baud_rate.value = 9600;
-}
+	ASSERT(task != NULL, return -1;);
 
-/*
- * Function actisys_init_qos (qos)
- *
- *    Initialize QoS capabilities
- *
- */
-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;
+	self->reset_task = task;
 
-	/* Remove support for 38400 if this is not a 220L+ dongle */
-	if (idev->io.dongle_id == ACTISYS_DONGLE)
-		qos->baud_rate.bits &= ~IR_38400;
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Set both DTR & RTS to power up the dongle */
+		/* In theory redundant with power up in actisys_open() */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+		
+		/* Sleep 50 ms to make sure capacitor is charged */
+		ret = MSECS_TO_JIFFIES(50);
+		irda_task_next_state(task, IRDA_TASK_WAIT);
+		break;
+	case IRDA_TASK_WAIT:			
+		/* Reset the dongle : set DTR low for 10 us */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+		udelay(MIN_DELAY);
+
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
 	
-	qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		self->speed = 9600;	/* That's the default */
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
 }
 
 #ifdef MODULE
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>");
 MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver");	
 		
 /*
@@ -225,5 +294,4 @@
 {
 	actisys_cleanup();
 }
-
-#endif
+#endif /* MODULE */
diff -urN linux-2.2.15-pre2/drivers/net/irda/esi.c linux/drivers/net/irda/esi.c
--- linux-2.2.15-pre2/drivers/net/irda/esi.c	Mon Jun  7 16:19:59 1999
+++ linux/drivers/net/irda/esi.c	Mon Dec  3 21:57:53 2001
@@ -1,27 +1,33 @@
 /*********************************************************************
  *                
  * Filename:      esi.c
- * Version:       1.4
+ * Version:       1.5
  * Description:   Driver for the Extended Systems JetEye PC dongle
  * Status:        Experimental.
- * Author:        Thomas Davis, <ratbert@radiks.net>
+ * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Sun May 16 14:35:21 1999
+ * Modified at:   Fri Dec 17 09:14:04 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) 1999 Dag Brattli, <dagb@cs.uit.no>,
+ *     Copyright (c) 1998 Thomas Davis, <ratbert@radiks.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
+ *     
+ *     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, provide no 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/module.h>
@@ -34,25 +40,22 @@
 #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);
-static void esi_qos_init(struct irda_device *idev, struct qos_info *qos);
-
-static struct dongle dongle = {
-	ESI_DONGLE,
+static void esi_open(dongle_t *self, struct qos_info *qos);
+static void esi_close(dongle_t *self);
+static int  esi_change_speed(struct irda_task *task);
+static int  esi_reset(struct irda_task *task);
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_ESI_DONGLE,
 	esi_open,
 	esi_close,
 	esi_reset,
 	esi_change_speed,
-	esi_qos_init,
 };
 
-__initfunc(int esi_init(void))
+int __init esi_init(void)
 {
 	return irda_device_register_dongle(&dongle);
 }
@@ -62,38 +65,35 @@
 	irda_device_unregister_dongle(&dongle);
 }
 
-static void esi_open(struct irda_device *idev, int type)
+static void esi_open(dongle_t *self, struct qos_info *qos)
 {
-	strcat(idev->description, " <-> esi");
-
-	idev->io.dongle_id = type;
-	idev->flags |= IFF_DONGLE;
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
+	qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
 
 	MOD_INC_USE_COUNT;
 }
 
-static void esi_close(struct irda_device *idev)
+static void esi_close(dongle_t *dongle)
 {		
 	/* Power off dongle */
-	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+	dongle->set_dtr_rts(dongle->dev, FALSE, FALSE);
 
 	MOD_DEC_USE_COUNT;
 }
 
 /*
- * Function esi_change_speed (tty, baud)
+ * Function esi_change_speed (task)
  *
  *    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 int esi_change_speed(struct irda_task *task)
 {
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
 	int dtr, rts;
 	
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	switch (baud) {
+	switch (speed) {
 	case 19200:
 		dtr = TRUE;
 		rts = FALSE;
@@ -109,28 +109,31 @@
 	}
 
 	/* Change speed of dongle */
-	irda_device_set_dtr_rts(idev, dtr, rts);
-}
+	self->set_dtr_rts(self->dev, dtr, rts);
+	self->speed = speed;
 
-static void esi_reset( struct irda_device *idev)
-{
-	/* Empty */
+	irda_task_next_state(task, IRDA_TASK_DONE);
+
+	return 0;
 }
 
 /*
- * Function esi_qos_init (qos)
+ * Function esi_reset (task)
  *
- *    Init QoS capabilities for the dongle
+ *    Reset dongle;
  *
  */
-static void esi_qos_init(struct irda_device *idev, struct qos_info *qos)
+static int esi_reset(struct irda_task *task)
 {
-	qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
-	qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */
+	dongle_t *self = (dongle_t *) task->instance;
+	
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
+	irda_task_next_state(task, IRDA_TASK_DONE);
+
+	return 0;
 }
 
 #ifdef MODULE
-
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver");
 
@@ -155,6 +158,5 @@
 {
         esi_cleanup();
 }
-
-#endif
+#endif /* MODULE */
 
diff -urN linux-2.2.15-pre2/drivers/net/irda/girbil.c linux/drivers/net/irda/girbil.c
--- linux-2.2.15-pre2/drivers/net/irda/girbil.c	Mon Jun  7 16:19:59 1999
+++ linux/drivers/net/irda/girbil.c	Mon Dec  3 21:57:53 2001
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      girbil.c
- * Version:       1.1
+ * Version:       1.2
  * 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:   Tue Jun  1 08:47:41 1999
+ * Modified at:   Fri Dec 17 09:13:20 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -32,13 +32,11 @@
 #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);
-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);
-static void girbil_init_qos(struct irda_device *idev, struct qos_info *qos);
+static int  girbil_reset(struct irda_task *task);
+static void girbil_open(dongle_t *self, struct qos_info *qos);
+static void girbil_close(dongle_t *self);
+static int  girbil_change_speed(struct irda_task *task);
 
 /* Control register 1 */
 #define GIRBIL_TXEN    0x01 /* Enable transmitter */
@@ -67,16 +65,16 @@
 /* Control register 2 (0x5) */
 #define GIRBIL_LOAD    0x51 /* Load the new baud rate value */
 
-static struct dongle dongle = {
-	GIRBIL_DONGLE,
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_GIRBIL_DONGLE,
 	girbil_open,
 	girbil_close,
 	girbil_reset,
 	girbil_change_speed,
-	girbil_init_qos,
 };
 
-__initfunc(int girbil_init(void))
+int __init girbil_init(void)
 {
 	return irda_device_register_dongle(&dongle);
 }
@@ -86,20 +84,18 @@
 	irda_device_unregister_dongle(&dongle);
 }
 
-static void girbil_open(struct irda_device *idev, int type)
+static void girbil_open(dongle_t *self, struct qos_info *qos)
 {
-	strcat(idev->description, " <-> girbil");
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x03;
 
-	idev->io.dongle_id = type;
-	idev->flags |= IFF_DONGLE;
-	
 	MOD_INC_USE_COUNT;
 }
 
-static void girbil_close(struct irda_device *idev)
+static void girbil_close(dongle_t *self)
 {
 	/* Power off dongle */
-	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
 
 	MOD_DEC_USE_COUNT;
 }
@@ -107,108 +103,135 @@
 /*
  * Function girbil_change_speed (dev, speed)
  *
- *    Set the speed for the Girbil type dongle. Warning, this 
- *    function must be called with a process context!
+ *    Set the speed for the Girbil type dongle.
  *
  */
-static void girbil_change_speed(struct irda_device *idev, int speed)
+static int girbil_change_speed(struct irda_task *task)
 {
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
 	__u8 control[2];
-	
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	switch (speed) {
-	case 9600:
-	default:
-		control[0] = GIRBIL_9600;
+	int ret = 0;
+
+	self->speed_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Need to reset the dongle and go to 9600 bps before
+                   programming */
+		if (irda_task_execute(self, girbil_reset, NULL, task, 
+				      (void *) speed))
+		{
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give reset 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		}
 		break;
-	case 19200:
-		control[0] = GIRBIL_19200;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
 		break;
-	case 34800:
-		control[0] = GIRBIL_38400;
+	case IRDA_TASK_CHILD_DONE:
+		/* Set DTR and Clear RTS to enter command mode */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+
+		switch (speed) {
+		case 9600:
+		default:
+			control[0] = GIRBIL_9600;
+			break;
+		case 19200:
+			control[0] = GIRBIL_19200;
+			break;
+		case 34800:
+			control[0] = GIRBIL_38400;
+			break;
+		case 57600:
+			control[0] = GIRBIL_57600;
+			break;
+		case 115200:
+			control[0] = GIRBIL_115200;
+			break;
+		}
+		control[1] = GIRBIL_LOAD;
+		
+		/* Write control bytes */
+		self->write(self->dev, control, 2);
+		irda_task_next_state(task, IRDA_TASK_WAIT);
+		ret = MSECS_TO_JIFFIES(100);
 		break;
-	case 57600:
-		control[0] = GIRBIL_57600;
+	case IRDA_TASK_WAIT:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
 		break;
-	case 115200:
-		control[0] = GIRBIL_115200;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
 		break;
 	}
-	control[1] = GIRBIL_LOAD;
-
-	/* Set DTR and Clear RTS to enter command mode */
-	irda_device_set_dtr_rts(idev, FALSE, TRUE);
-
-	/* Write control bytes */
-	irda_device_raw_write(idev, control, 2);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(2);
-	
-	/* Go back to normal mode */
-	irda_device_set_dtr_rts(idev, TRUE, TRUE);
+	return ret;
 }
 
 /*
  * Function girbil_reset (driver)
  *
- *      This function resets the girbil dongle. Warning, this function 
- *      must be called with a process context!! 
+ *      This function resets the girbil dongle.
  *
  *      Algorithm:
  *    	  0. set RTS, and wait at least 5 ms 
  *        1. clear RTS 
  */
-void girbil_reset(struct irda_device *idev)
+static int girbil_reset(struct irda_task *task)
 {
+	dongle_t *self = (dongle_t *) task->instance;
 	__u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
+	int ret = 0;
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	/* Reset dongle */
-	irda_device_set_dtr_rts(idev, TRUE, FALSE);
-
-	/* Sleep at least 5 ms */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(20));
-	
-	/* Set DTR and clear RTS to enter command mode */
-	irda_device_set_dtr_rts(idev, FALSE, TRUE);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(20));
-
-	/* Write control byte */
-	irda_device_raw_write(idev, &control, 1);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(20));
+	self->reset_task = task;
 
-	/* Go back to normal mode */
-	irda_device_set_dtr_rts(idev, TRUE, TRUE);
-
-       	/* Make sure the IrDA chip also goes to defalt speed */
-	if (idev->change_speed)
-		idev->change_speed(idev, 9600);
-}
-
-/*
- * Function girbil_init_qos (qos)
- *
- *    Initialize QoS capabilities
- *
- */
-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 &= 0x03;
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Reset dongle */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+		/* Sleep at least 5 ms */
+		ret = MSECS_TO_JIFFIES(10);
+		break;
+	case IRDA_TASK_WAIT1:
+		/* Set DTR and clear RTS to enter command mode */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		ret = MSECS_TO_JIFFIES(10);
+		break;
+	case IRDA_TASK_WAIT2:
+		/* Write control byte */
+		self->write(self->dev, &control, 1);
+		irda_task_next_state(task, IRDA_TASK_WAIT3);
+		ret = MSECS_TO_JIFFIES(20);
+		break;
+	case IRDA_TASK_WAIT3:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
 }
 
 #ifdef MODULE
-
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver");
 	
@@ -233,5 +256,4 @@
 {
         girbil_cleanup();
 }
-
 #endif /* MODULE */
diff -urN linux-2.2.15-pre2/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
--- linux-2.2.15-pre2/drivers/net/irda/irport.c	Sun Jun 13 10:48:21 1999
+++ linux/drivers/net/irda/irport.c	Mon Dec  3 21:57:53 2001
@@ -6,11 +6,11 @@
  * Status:	  Experimental.
  * Author:	  Dag Brattli <dagb@cs.uit.no>
  * Created at:	  Sun Aug  3 13:49:59 1997
- * Modified at:   Tue Jun  1 10:02:42 1999
+ * Modified at:   Fri Jan 14 21:07:20 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:	  serial.c by Linus Torvalds 
  * 
- *     Copyright (c) 1997, 1998, 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 1998, 1999-2000 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 
@@ -47,11 +47,12 @@
 #include <linux/serial_reg.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <asm/spinlock.h>
+#include <linux/rtnetlink.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>
@@ -69,24 +70,33 @@
 
 static unsigned int qos_mtt_bits = 0x03;
 
-static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL};
+static struct irport_cb *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 void irport_write_wakeup(struct irport_cb *self);
 static int  irport_write(int iobase, int fifo_size, __u8 *buf, int len);
-static void irport_receive(struct irda_device *idev);
+static void irport_receive(struct irport_cb *self);
 
 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);
+static int  irport_net_ioctl(struct device *dev, struct ifreq *rq, 
+			     int cmd);
+static int  irport_is_receiving(struct irport_cb *self);
+static int  irport_set_dtr_rts(struct device *dev, int dtr, int rts);
+static int  irport_raw_write(struct device *dev, __u8 *buf, int len);
+static struct net_device_stats *irport_net_get_stats(struct device *dev);
+static int irport_change_speed_complete(struct irda_task *task);
+
+EXPORT_SYMBOL(irport_open);
+EXPORT_SYMBOL(irport_close);
+EXPORT_SYMBOL(irport_start);
+EXPORT_SYMBOL(irport_stop);
+EXPORT_SYMBOL(irport_interrupt);
+EXPORT_SYMBOL(irport_hard_xmit);
+EXPORT_SYMBOL(irport_change_speed);
+EXPORT_SYMBOL(irport_net_open);
+EXPORT_SYMBOL(irport_net_close);
 
-__initfunc(int irport_init(void))
+int __init irport_init(void)
 {
  	int i;
 
@@ -94,7 +104,7 @@
  		int ioaddr = io[i];
  		if (check_region(ioaddr, IO_EXTENT))
  			continue;
- 		if (irport_open(i, io[i], irq[i]) == 0)
+ 		if (irport_open(i, io[i], irq[i]) != NULL)
  			return 0;
  	}
 	/* 
@@ -114,7 +124,7 @@
 {
  	int i;
 
-        DEBUG( 4, __FUNCTION__ "()\n");
+        IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
 	for (i=0; i < 4; i++) {
  		if (dev_self[i])
@@ -123,110 +133,170 @@
 }
 #endif /* MODULE */
 
-static int irport_open(int i, unsigned int iobase, unsigned int irq)
+struct irport_cb *
+irport_open(int i, unsigned int iobase, unsigned int irq)
 {
-	struct irda_device *idev;
+	struct device *dev;
+	struct irport_cb *self;
 	int ret;
+	int err;
 
-	DEBUG( 0, __FUNCTION__ "()\n");
-
-/* 	if (irport_probe(iobase, irq) == -1) */
-/* 		return -1; */
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
 	/*
 	 *  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;
+	self = kmalloc(sizeof(struct irport_cb), GFP_KERNEL);
+	if (!self) {
+		ERROR(__FUNCTION__ "(), can't allocate memory for "
+		      "control block!\n");
+		return NULL;
 	}
-	memset(idev, 0, sizeof(struct irda_device));
-   
+	memset(self, 0, sizeof(struct irport_cb));
+	spin_lock_init(&self->lock);
+
 	/* Need to store self somewhere */
-	dev_self[i] = idev;
+	dev_self[i] = self;
+	self->priv = self;
+	self->index = i;
 
 	/* 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;
+	self->io.sir_base  = iobase;
+        self->io.sir_ext   = IO_EXTENT;
+        self->io.irq       = irq;
+        self->io.fifo_size = 16;
 
 	/* Lock the port that we need */
-	ret = check_region(idev->io.iobase2, idev->io.io_ext);
+	ret = check_region(self->io.sir_base, self->io.sir_ext);
 	if (ret < 0) { 
-		DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-		      idev->io.iobase2);
-		/* irport_cleanup(self->idev);  */
-		return -ENODEV;
+		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+			   self->io.sir_base);
+		return NULL;
 	}
-	request_region(idev->io.iobase2, idev->io.io_ext, idev->name);
+	request_region(self->io.sir_base, self->io.sir_ext, driver_name);
 
 	/* Initialize QoS for this device */
-	irda_init_max_qos_capabilies(&idev->qos);
+	irda_init_max_qos_capabilies(&self->qos);
 	
-	idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+	self->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);
+	self->qos.min_turn_time.bits = qos_mtt_bits;
+	irda_qos_bits_to_value(&self->qos);
 	
-	idev->flags = IFF_SIR|IFF_PIO;
+	self->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;
+	/* Specify how much memory we want */
+	self->rx_buff.truesize = 4000; 
+	self->tx_buff.truesize = 4000;
+	
+	/* Allocate memory if needed */
+	if (self->rx_buff.truesize > 0) {
+		self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
+						      GFP_KERNEL);
+		if (self->rx_buff.head == NULL)
+			return NULL;
+		memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+	}
+	if (self->tx_buff.truesize > 0) {
+		self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+						      GFP_KERNEL);
+		if (self->tx_buff.head == NULL) {
+			kfree(self->rx_buff.head);
+			return NULL;
+		}
+		memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+	}	
+	self->rx_buff.in_frame = FALSE;
+	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
+	self->mode = IRDA_IRLAP;
+
+	if (!(dev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return NULL;
+	}
+	/* dev_alloc doesn't clear the struct */
+	memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct device)-sizeof(char*));
+
+	self->netdev = dev;
+
+	/* May be overridden by piggyback drivers */
+ 	dev->priv = (void *) self;
+	self->interrupt    = irport_interrupt;
+	self->change_speed = irport_change_speed;
 
 	/* 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;);
+	dev->init            = irport_net_init;
+	dev->hard_start_xmit = irport_hard_xmit;
+	dev->open            = irport_net_open;
+	dev->stop            = irport_net_close;
+	dev->get_stats	     = irport_net_get_stats;
+	dev->do_ioctl        = irport_net_ioctl;
+
+	/* Make ifconfig display some details */
+	dev->base_addr = iobase;
+	dev->irq = irq;
+
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return NULL;
+	}
+	MESSAGE("IrDA: Registered device %s\n", dev->name);
+
+	return self;
+}
+
+int irport_close(struct irport_cb *self)
+{
+	ASSERT(self != NULL, return -1;);
+
+	/* We are not using any dongle anymore! */
+	if (self->dongle)
+		irda_device_dongle_cleanup(self->dongle);
+	self->dongle = NULL;
+	
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		rtnl_unlock();
+		/* Must free the old-style 2.2.x device */
+		kfree(self->netdev);
+	}
 
 	/* Release the IO-port that this driver is using */
-	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);
-
+	IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
+		   self->io.sir_base);
+	release_region(self->io.sir_base, self->io.sir_ext);
+
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
+	
+	/* Remove ourselves */
+	dev_self[self->index] = NULL;
+	kfree(self);
+	
 	return 0;
 }
 
-void irport_start(struct irda_device *idev, int iobase)
+void irport_start(struct irport_cb *self)
 {
 	unsigned long flags;
+	int iobase;
+
+	iobase = self->io.sir_base;
 
-	spin_lock_irqsave(&idev->lock, flags);
+	spin_lock_irqsave(&self->lock, flags);
 
-	irport_stop(idev, iobase);
+	irport_stop(self);
 
 	/* Initialize UART */
 	outb(UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
@@ -235,14 +305,17 @@
 	/* Turn on interrups */
 	outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
 
-	spin_unlock_irqrestore(&idev->lock, flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 }
 
-void irport_stop(struct irda_device *idev, int iobase)
+void irport_stop(struct irport_cb *self)
 {
 	unsigned long flags;
+	int iobase;
+
+	iobase = self->io.sir_base;
 
-	spin_lock_irqsave(&idev->lock, flags);
+	spin_lock_irqsave(&self->lock, flags);
 
 	/* Reset UART */
 	outb(0, iobase+UART_MCR);
@@ -250,7 +323,7 @@
 	/* Turn off interrupts */
 	outb(0, iobase+UART_IER);
 
-	spin_unlock_irqrestore(&idev->lock, flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*
@@ -261,36 +334,36 @@
  */
 int irport_probe(int iobase)
 {
-	DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
+	IRDA_DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
 
 	return 0;
 }
 
 /*
- * Function irport_change_speed (idev, speed)
+ * Function irport_change_speed (self, speed)
  *
  *    Set speed of IrDA port to specified baudrate
  *
  */
-void irport_change_speed(struct irda_device *idev, int speed)
+void irport_change_speed(void *priv, __u32 speed)
 {
+	struct irport_cb *self = (struct irport_cb *) priv;
 	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);
+	IRDA_DEBUG(2, __FUNCTION__ "(), Setting speed to: %d\n", speed);
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(self != NULL, return;);
 
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 	
 	/* Update accounting for new speed */
-	idev->io.baudrate = speed;
+	self->io.speed = speed;
 
-	spin_lock_irqsave(&idev->lock, flags);
+	spin_lock_irqsave(&self->lock, flags);
 
 	/* Turn off interrupts */
 	outb(0, iobase+UART_IER); 
@@ -304,7 +377,7 @@
 	 * 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)
+	if (self->io.speed < 38400)
 		fcr |= UART_FCR_TRIGGER_1;
 	else 
 		fcr |= UART_FCR_TRIGGER_14;
@@ -319,9 +392,82 @@
 	outb(fcr,		  iobase+UART_FCR); /* Enable FIFO's */
 
 	/* Turn on interrups */
-	outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
+	outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
+
+	spin_unlock_irqrestore(&self->lock, flags);
+}
+
+/*
+ * Function __irport_change_speed (instance, state, param)
+ *
+ *    State machine for changing speed of the device. We do it this way since
+ *    we cannot use schedule_timeout() when we are in interrupt context
+ */
+int __irport_change_speed(struct irda_task *task)
+{
+	struct irport_cb *self;
+	__u32 speed = (__u32) task->param;
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); 
+
+	self = (struct irport_cb *) task->instance;
 
-	spin_unlock_irqrestore(&idev->lock, flags);
+	ASSERT(self != NULL, return -1;);
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+	case IRDA_TASK_WAIT:
+		/* Are we ready to change speed yet? */
+		if (self->tx_buff.len > 0) {
+			task->state = IRDA_TASK_WAIT;
+
+			/* Try again later */
+			ret = MSECS_TO_JIFFIES(20);
+			break;
+		}
+
+		if (self->dongle)
+			irda_task_next_state(task, IRDA_TASK_CHILD_INIT);
+		else
+			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+		break;
+	case IRDA_TASK_CHILD_INIT:
+		/* Go to default speed */
+		self->change_speed(self->priv, 9600);
+
+		/* Change speed of dongle */
+		if (irda_task_execute(self->dongle,
+				      self->dongle->issue->change_speed, 
+				      NULL, task, (void *) speed))
+		{
+			/* Dongle need more time to change its speed */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give dongle 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		} else
+			/* Child finished immediately */
+			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+		break;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ 
+			"(), changing speed of dongle timed out!\n");
+		ret = -1;		
+		break;
+	case IRDA_TASK_CHILD_DONE:
+		/* Finally we are ready to change the speed */
+		self->change_speed(self->priv, speed);
+		
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		ret = -1;
+		break;
+	}	
+	return ret;
 }
 
 /*
@@ -331,51 +477,63 @@
  *    more packets to send, we send them here.
  *
  */
-static void irport_write_wakeup(struct irda_device *idev)
+static void irport_write_wakeup(struct irport_cb *self)
 {
 	int actual = 0;
 	int iobase;
 	int fcr;
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(self != NULL, return;);
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	iobase = self->io.sir_base;
 
 	/* Finished with frame?  */
-	if (idev->tx_buff.len > 0)  {
+	if (self->tx_buff.len > 0)  {
 		/* Write data left in transmit buffer */
-		actual = irport_write(idev->io.iobase2, idev->io.fifo_size, 
-				      idev->tx_buff.data, idev->tx_buff.len);
-		idev->tx_buff.data += actual;
-		idev->tx_buff.len  -= actual;
+		actual = irport_write(iobase, self->io.fifo_size, 
+				      self->tx_buff.data, self->tx_buff.len);
+		self->tx_buff.data += actual;
+		self->tx_buff.len  -= actual;
 	} else {
-		iobase = idev->io.iobase2;
+		
 		/* 
 		 *  Now serial buffer is almost free & we can start 
-		 *  transmission of another packet 
+		 *  transmission of another packet. But first we must check
+		 *  if we need to change the speed of the hardware
 		 */
-		idev->netdev.tbusy = 0; /* Unlock */
-		idev->stats.tx_packets++;
+		if (self->new_speed) {
+			IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
+			irda_task_execute(self, __irport_change_speed, 
+					  irport_change_speed_complete, 
+					  NULL, (void *) self->new_speed);
+			self->new_speed = 0;
+		} else {
+			self->netdev->tbusy = 0; /* Unlock */
+		
+			/* Tell network layer that we want more frames */
+			mark_bh(NET_BH);
+		}
+		self->stats.tx_packets++;
 
 		/* Schedule network layer, so we can get some more frames */
 		mark_bh(NET_BH);
 
+		/* 
+		 * Reset Rx FIFO to make sure that all reflected transmit data
+		 * is discarded. This is needed for half duplex operation
+		 */
 		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
-
-		if (idev->io.baudrate < 38400)
+		if (self->io.speed < 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); 
+		outb(UART_IER_RDI, iobase+UART_IER);
 	}
 }
 
@@ -391,8 +549,8 @@
 
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
-		return -1;
+		IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		return 0;
 	}
         
 	/* Fill FIFO with current frame */
@@ -407,6 +565,32 @@
 }
 
 /*
+ * Function irport_change_speed_complete (task)
+ *
+ *    Called when the change speed operation completes
+ *
+ */
+static int irport_change_speed_complete(struct irda_task *task)
+{
+	struct irport_cb *self;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	self = (struct irport_cb *) task->instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->netdev != NULL, return -1;);
+
+	/* Finished changing speed, so we are not busy any longer */
+	self->netdev->tbusy = 0;
+
+	/* Signal network layer so it can try to send the frame */
+	mark_bh(NET_BH);
+
+	return 0;
+}
+
+/*
  * Function irport_xmit (void)
  *
  *    Transmits the current frame until FIFO is full, then
@@ -415,49 +599,50 @@
  */
 int irport_hard_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct irda_device *idev;
+	struct irport_cb *self;
 	unsigned long flags;
-	int actual = 0;
 	int iobase;
+	__u32 speed;
 
 	ASSERT(dev != NULL, return 0;);
 	
-	idev = (struct irda_device *) dev->priv;
+	self = (struct irport_cb *) dev->priv;
+	ASSERT(self != NULL, return 0;);
 
-	ASSERT(idev != NULL, return 0;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);
-
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 
 	/* Lock transmit buffer */
 	if (irda_lock((void *) &dev->tbusy) == FALSE) {
 		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5)
+		if ((tickssofar < 5) || !dev->start)
 			return -EBUSY;
 
 		WARNING("%s: transmit timed out\n", dev->name);
-		irport_start(idev, iobase);
-		irport_change_speed(idev, idev->io.baudrate);
+		irport_start(self);
+		self->change_speed(self->priv, self->io.speed);
 
 		dev->trans_start = jiffies;
 	}
 
-	spin_lock_irqsave(&idev->lock, flags);
-	
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Init tx buffer */
-	idev->tx_buff.data = idev->tx_buff.head;
+	self->tx_buff.data = self->tx_buff.head;
 
         /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
-	idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
-					   idev->tx_buff.truesize);
+	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
+					   self->tx_buff.truesize);
 	
-	idev->tx_buff.data += actual;
-	idev->tx_buff.len  -= actual;
+	self->stats.tx_bytes += self->tx_buff.len;
 
 	/* Turn on transmit finished interrupt. Will fire immediately!  */
 	outb(UART_IER_THRI, iobase+UART_IER); 
 
-	spin_unlock_irqrestore(&idev->lock, flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 
 	dev_kfree_skb(skb);
 	
@@ -465,30 +650,31 @@
 }
         
 /*
- * Function irport_receive (void)
+ * Function irport_receive (self)
  *
  *    Receive one frame from the infrared port
  *
  */
-static void irport_receive(struct irda_device *idev) 
+static void irport_receive(struct irport_cb *self) 
 {
-	int iobase;
 	int boguscount = 0;
+	int iobase;
 
-	ASSERT(idev != NULL, return;);
+	ASSERT(self != NULL, return;);
 
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 
 	/*  
 	 * Receive all characters in Rx FIFO, unwrap and unstuff them. 
          * async_unwrap_char will deliver all found frames  
 	 */
 	do {
-		async_unwrap_char(idev, inb(iobase+UART_RX));
+		async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
+				  inb(iobase+UART_RX));
 
 		/* Make sure we don't stay here to long */
 		if (boguscount++ > 32) {
-			DEBUG(0,__FUNCTION__ "(), breaking!\n");
+			IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n");
 			break;
 		}
 	} while (inb(iobase+UART_LSR) & UART_LSR_DR);	
@@ -501,58 +687,60 @@
  */
 void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
 {
-	struct irda_device *idev = (struct irda_device *) dev_id;
+	struct device *dev = (struct device *) dev_id;
+	struct irport_cb *self;
+	int boguscount = 0;
 	int iobase;
 	int iir, lsr;
-	int boguscount = 0;
 
-	if (!idev) {
+	if (!dev) {
 		WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq);
 		return;
 	}
+	self = (struct irport_cb *) dev->priv;
 
-	spin_lock(&idev->lock);
+	spin_lock(&self->lock);
 
-	idev->netdev.interrupt = 1;
+	dev->interrupt = 1;
 
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 
 	iir = inb(iobase+UART_IIR) & UART_IIR_ID;
 	while (iir) {
 		/* Clear interrupt */
 		lsr = inb(iobase+UART_LSR);
 
-		DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
-		      iir, lsr, iobase);
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+			   iir, lsr, iobase);
 
 		switch (iir) {
 		case UART_IIR_RLSI:
-			DEBUG(0, __FUNCTION__ "(), RLSI\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n");
 			break;
 		case UART_IIR_RDI:
-			if (lsr & UART_LSR_DR)
-				/* Receive interrupt */
-				irport_receive(idev);
+			/* Receive interrupt */
+			irport_receive(self);
 			break;
 		case UART_IIR_THRI:
 			if (lsr & UART_LSR_THRE)
 				/* Transmitter ready for data */
-				irport_write_wakeup(idev);
+				irport_write_wakeup(self);
 			break;
 		default:
-			DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+			IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
 			break;
 		} 
 		
 		/* Make sure we don't stay here to long */
-		if (boguscount++ > 32)
+		if (boguscount++ > 100)
 			break;
 
  	        iir = inb(iobase + UART_IIR) & UART_IIR_ID;
 	}
-	idev->netdev.interrupt = 0;
+	dev->interrupt = 0;
 
-	spin_unlock(&idev->lock);
+	spin_unlock(&self->lock);
 }
 
 static int irport_net_init(struct device *dev)
@@ -568,64 +756,75 @@
 /*
  * Function irport_net_open (dev)
  *
- *    
- *
+ *    Network device is taken up. Usually this is done by "ifconfig irda0 up" 
+ *   
  */
-static int irport_net_open(struct device *dev)
+int irport_net_open(struct device *dev)
 {
-	struct irda_device *idev;
+	struct irport_cb *self;
 	int iobase;
 
 	ASSERT(dev != NULL, return -1;);
-	idev = (struct irda_device *) dev->priv;
+	self = (struct irport_cb *) dev->priv;
 
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 
-	if (request_irq(idev->io.irq2, irport_interrupt, 0, idev->name, 
-			(void *) idev))
+	if (request_irq(self->io.irq, self->interrupt, 0, dev->name, 
+			(void *) dev))
 		return -EAGAIN;
 
-	irport_start(idev, iobase);
-
-	MOD_INC_USE_COUNT;
+	irport_start(self);
 
 	/* 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);
+	/* 
+	 * Open new IrLAP layer instance, now that everything should be
+	 * initialized properly 
+	 */
+	self->irlap = irlap_open(dev, &self->qos);
+
+	/* FIXME: change speed of dongle */
+
+	MOD_INC_USE_COUNT;
 
 	return 0;
 }
 
 /*
- * Function irport_net_close (idev)
- *
- *    
+ * Function irport_net_close (self)
  *
+ *    Network device is taken down. Usually this is done by 
+ *    "ifconfig irda0 down" 
  */
-static int irport_net_close(struct device *dev)
+int irport_net_close(struct device *dev)
 {
-	struct irda_device *idev;
+	struct irport_cb *self;
 	int iobase;
 
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
 	ASSERT(dev != NULL, return -1;);
-	idev = (struct irda_device *) dev->priv;
+	self = (struct irport_cb *) dev->priv;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	ASSERT(self != NULL, return -1;);
 
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 
 	/* Stop device */
 	dev->tbusy = 1;
 	dev->start = 0;
 
-	irport_stop(idev, iobase);
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
+
+	irport_stop(self);
 
-	free_irq(idev->io.irq2, idev);
+	free_irq(self->io.irq, dev);
 
 	MOD_DEC_USE_COUNT;
 
@@ -633,50 +832,52 @@
 }
 
 /*
- * Function irport_wait_until_sent (idev)
+ * Function irport_wait_until_sent (self)
  *
  *    Delay exectution until finished transmitting
  *
  */
-void irport_wait_until_sent(struct irda_device *idev)
+#if 0
+void irport_wait_until_sent(struct irport_cb *self)
 {
 	int iobase;
 
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 
 	/* Wait until Tx FIFO is empty */
 	while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		DEBUG(2, __FUNCTION__ "(), waiting!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), waiting!\n");
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(MSECS_TO_JIFFIES(60));
 	}
 }
+#endif
 
 /*
- * Function irport_is_receiving (idev)
+ * Function irport_is_receiving (self)
  *
  *    Returns true is we are currently receiving data
  *
  */
-static int irport_is_receiving(struct irda_device *idev)
+static int irport_is_receiving(struct irport_cb *self)
 {
-	return (idev->rx_buff.state != OUTSIDE_FRAME);
+	return (self->rx_buff.state != OUTSIDE_FRAME);
 }
 
 /*
- * Function irtty_set_dtr_rts (tty, dtr, rts)
+ * Function irport_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)
+static int irport_set_dtr_rts(struct device *dev, int dtr, int rts)
 {
+	struct irport_cb *self = dev->priv;
 	int iobase;
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
 
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 
 	if (dtr)
 		dtr = UART_MCR_DTR;
@@ -684,21 +885,23 @@
 		rts = UART_MCR_RTS;
 
 	outb(dtr|rts|UART_MCR_OUT2, iobase+UART_MCR);
+
+	return 0;
 }
 
-static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len)
+static int irport_raw_write(struct device *dev, __u8 *buf, int len)
 {
-	int iobase;
+	struct irport_cb *self = (struct irport_cb *) dev->priv;
 	int actual = 0;
+	int iobase;
 
-	ASSERT(idev != NULL, return -1;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
 
-	iobase = idev->io.iobase2;
+	iobase = self->io.sir_base;
 
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
 		return -1;
 	}
         
@@ -712,34 +915,97 @@
 	return actual;
 }
 
-#ifdef MODULE
+/*
+ * Function irport_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+static int irport_net_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct irport_cb *self;
+	dongle_t *dongle;
+	unsigned long flags;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		irda_task_execute(self, __irport_change_speed, NULL, NULL, 
+				  (void *) irq->ifr_baudrate);
+		break;
+	case SIOCSDONGLE: /* Set dongle */
+		/* Initialize dongle */
+		dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
+		if (!dongle)
+			break;
+		
+		dongle->set_mode    = NULL;
+		dongle->read        = NULL;
+		dongle->write       = irport_raw_write;
+		dongle->set_dtr_rts = irport_set_dtr_rts;
+		
+		self->dongle = dongle;
+
+		/* Now initialize the dongle!  */
+		dongle->issue->open(dongle, &self->qos);
+		
+		/* Reset dongle */
+		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
+				  NULL);	
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = irport_is_receiving(self);
+		break;
+	case SIOCSDTRRTS:
+		irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
+
+static struct net_device_stats *irport_net_get_stats(struct device *dev)
+{
+	struct irport_cb *self = (struct irport_cb *) dev->priv;
+	
+	return &self->stats;
+}
 
+#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)
- *
- *    
- *
- */
 void cleanup_module(void)
 {
 	irport_cleanup();
 }
 
-/*
- * Function init_module (void)
- *
- *    
- */
 int init_module(void)
 {
 	return irport_init();
 }
-
 #endif /* MODULE */
 
diff -urN linux-2.2.15-pre2/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- linux-2.2.15-pre2/drivers/net/irda/irtty.c	Wed Jun  2 11:31:36 1999
+++ linux/drivers/net/irda/irtty.c	Mon Dec  3 21:57:53 2001
@@ -6,12 +6,12 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:18:38 1997
- * Modified at:   Mon May 10 15:45:50 1999
+ * Modified at:   Fri Jan 14 21:02:27 2000
  * 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-1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-2000 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 
@@ -25,46 +25,55 @@
  ********************************************************************/    
 
 #include <linux/module.h>
-#include <asm/uaccess.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
-#include <asm/segment.h>
 #include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irtty.h>
 #include <net/irda/wrapper.h>
-#include <net/irda/irlap.h>
 #include <net/irda/timer.h>
 #include <net/irda/irda_device.h>
 
 static hashbin_t *irtty = NULL;
-
 static struct tty_ldisc irda_ldisc;
 
 static int qos_mtt_bits = 0x03;      /* 5 ms or more */
 
+/* Network device fuction prototypes */
 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 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_net_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *irtty_net_get_stats(struct device *dev);
 
+/* Line discipline function prototypes */
 static int  irtty_open(struct tty_struct *tty);
 static void irtty_close(struct tty_struct *tty);
 static int  irtty_ioctl(struct tty_struct *, void *, int, void *);
 static int  irtty_receive_room(struct tty_struct *tty);
-static void irtty_change_speed(struct irda_device *dev, int baud);
 static void irtty_write_wakeup(struct tty_struct *tty);
-
 static void irtty_receive_buf(struct tty_struct *, const unsigned char *, 
 			      char *, int);
+
+/* IrDA specific function protoctypes */
+static int  irtty_is_receiving(struct irtty_cb *self);
+static int  irtty_set_dtr_rts(struct device *dev, int dtr, int rts);
+static int  irtty_raw_write(struct device *dev, __u8 *buf, int len);
+static int  irtty_raw_read(struct device *dev, __u8 *buf, int len);
+static int  irtty_set_mode(struct device *dev, int mode);
+static int  irtty_change_speed(struct irda_task *task);
+
 char *driver_name = "irtty";
 
-__initfunc(int irtty_init(void))
+int __init irtty_init(void)
 {
 	int status;
 	
@@ -91,10 +100,9 @@
 	irda_ldisc.receive_room = irtty_receive_room;
 	irda_ldisc.write_wakeup = irtty_write_wakeup;
 	
-	if (( status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)  {
-		printk(KERN_ERR 
-		       "IrDA: can't register line discipline (err = %d)\n", 
-		       status);
+	if ((status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0) {
+		ERROR("IrDA: can't register line discipline (err = %d)\n", 
+		      status);
 	}
 	
 	return status;
@@ -111,9 +119,7 @@
 {
 	int ret;
 	
-	/*
-	 *  Unregister tty line-discipline
-	 */
+	/* Unregister tty line-discipline */
 	if ((ret = tty_register_ldisc(N_IRDA, NULL))) {
 		ERROR(__FUNCTION__ 
 		      "(), can't unregister line discipline (err = %d)\n",
@@ -138,13 +144,16 @@
  */
 static int irtty_open(struct tty_struct *tty) 
 {
+	struct device *dev;
 	struct irtty_cb *self;
 	char name[16];
+	int err;
 	
 	ASSERT(tty != NULL, return -EEXIST;);
 
 	/* First make sure we're not already connected. */
 	self = (struct irtty_cb *) tty->disc_data;
+
 	if (self != NULL && self->magic == IRTTY_MAGIC)
 		return -EEXIST;
 	
@@ -166,9 +175,8 @@
 	sprintf(name, "%s%d", tty->driver.name,
 		MINOR(tty->device) - tty->driver.minor_start +
 		tty->driver.name_base);
-	
-	/* hashbin_insert( irtty, (QUEUE*) self, 0, self->name); */
-	hashbin_insert(irtty, (QUEUE*) self, (int) self, NULL);
+
+	hashbin_insert(irtty, (queue_t *) self, (int) self, NULL);
 
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
@@ -177,11 +185,7 @@
 		tty->ldisc.flush_buffer(tty);
 	
 	self->magic = IRTTY_MAGIC;
-
-	/*
-	 *  Initialize driver
-	 */
-	self->idev.rx_buff.state = OUTSIDE_FRAME;
+	self->mode = IRDA_IRLAP;
 
 	/* 
 	 *  Initialize QoS capabilities, we fill in all the stuff that
@@ -189,38 +193,69 @@
 	 *  that are not device dependent (such as link disconnect time) so
 	 *  this parameter can be set by IrLAP (or the user) instead. DB
 	 */
-	irda_init_max_qos_capabilies(&self->idev.qos);
+	irda_init_max_qos_capabilies(&self->qos);
 
 	/* The only value we must override it the baudrate */
-	self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
 		IR_115200;
-	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);
-
-	/* Specify which buffer allocation policy we need */
-	self->idev.rx_buff.flags = GFP_KERNEL;
-	self->idev.tx_buff.flags = GFP_KERNEL;
+	self->qos.min_turn_time.bits = qos_mtt_bits;
+	self->flags = IFF_SIR | IFF_PIO;
+	irda_qos_bits_to_value(&self->qos);
 
 	/* Specify how much memory we want */
-	self->idev.rx_buff.truesize = 4000; 
-	self->idev.tx_buff.truesize = 4000;
+	self->rx_buff.truesize = 4000; 
+	self->tx_buff.truesize = 4000;
+
+	/* Allocate memory if needed */
+	if (self->rx_buff.truesize > 0) {
+		self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
+						      GFP_KERNEL);
+		if (self->rx_buff.head == NULL)
+			return -ENOMEM;
+		memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+	}
+	if (self->tx_buff.truesize > 0) {
+		self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+						      GFP_KERNEL);
+		if (self->tx_buff.head == NULL) {
+			kfree(self->rx_buff.head);
+			return -ENOMEM;
+		}
+		memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+	}
+	
+	self->rx_buff.in_frame = FALSE;
+	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	if (!(dev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return -ENOMEM;
+	}
+	/* dev_alloc doesn't clear the struct */
+	memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct device)-sizeof(char*));
 
-	/* Initialize callbacks */
-	self->idev.change_speed    = irtty_change_speed;
- 	self->idev.is_receiving    = irtty_is_receiving;
-	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;
+	dev->priv = (void *) self;
+	self->netdev = dev;
 
 	/* Override the network functions we need to use */
-	self->idev.netdev.init            = irtty_net_init;
-	self->idev.netdev.hard_start_xmit = irtty_hard_xmit;
-	self->idev.netdev.open            = irtty_net_open;
-	self->idev.netdev.stop            = irtty_net_close;
+	dev->init            = irtty_net_init;
+	dev->hard_start_xmit = irtty_hard_xmit;
+	dev->open            = irtty_net_open;
+	dev->stop            = irtty_net_close;
+	dev->get_stats	     = irtty_net_get_stats;
+	dev->do_ioctl        = irtty_net_ioctl;
+
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return -1;
+	}
 
-	/* Open the IrDA device */
-	irda_device_open(&self->idev, name, self);
+	MESSAGE("IrDA: Registered device %s\n", dev->name);
 
 	MOD_INC_USE_COUNT;
 
@@ -241,39 +276,56 @@
 	/* First make sure we're connected. */
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRTTY_MAGIC, return;);
-
-	/* Remove driver */
-	irda_device_close(&self->idev);
-
+	
 	/* Stop tty */
 	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 	tty->disc_data = 0;
+	
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		rtnl_unlock();
+		/* Must free the old-style 2.2.x device */
+		kfree(self->netdev);
+	}
+	
+	/* We are not using any dongle anymore! */
+	if (self->dongle)
+		irda_device_dongle_cleanup(self->dongle);
+	self->dongle = NULL;
+
+	/* Remove speed changing task if any */
+	if (self->task)
+		irda_task_delete(self->task);
 
 	self->tty = NULL;
 	self->magic = 0;
 	
 	self = hashbin_remove(irtty, (int) self, NULL);
-	
-	if (self != NULL)
-		kfree(self);
 
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
+	
+	kfree(self);
+	
  	MOD_DEC_USE_COUNT;
 }
 
 /*
- * Function irtty_stop_receiver (irda_device, stop)
+ * Function irtty_stop_receiver (self, stop)
  *
  *    
  *
  */
-static void irtty_stop_receiver(struct irda_device *idev, int stop)
+static void irtty_stop_receiver(struct irtty_cb *self, int stop)
 {
 	struct termios old_termios;
-	struct irtty_cb *self;
 	int cflag;
 
-	self = (struct irtty_cb *) idev->priv;
-
 	old_termios = *(self->tty->termios);
 	cflag = self->tty->termios->c_cflag;
 	
@@ -287,25 +339,15 @@
 }
 
 /* 
- *  Function irtty_change_speed (self, baud)
+ *  Function irtty_do_change_speed (self, speed)
  *
- *    Change the speed of the serial port. The driver layer must check that
- *    all transmission has finished using the irtty_wait_until_sent() 
- *    function.
+ *    Change the speed of the serial port.
  */
-static void irtty_change_speed(struct irda_device *idev, int baud) 
+static void __irtty_change_speed(struct irtty_cb *self, __u32 speed)
 {
         struct termios old_termios;
-	struct irtty_cb *self;
 	int cflag;
 
-	DEBUG(4,__FUNCTION__ "(), <%ld>\n", jiffies); 
-
-	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;);
 
@@ -314,9 +356,9 @@
 
 	cflag &= ~CBAUD;
 
-	DEBUG(4, __FUNCTION__ "(), Setting speed to %d\n", baud);
+	IRDA_DEBUG(2, __FUNCTION__ "(), Setting speed to %d\n", speed);
 
-	switch (baud) {
+	switch (speed) {
 	case 1200:
 		cflag |= B1200;
 		break;
@@ -346,6 +388,96 @@
 
 	self->tty->termios->c_cflag = cflag;
 	self->tty->driver.set_termios(self->tty, &old_termios);
+
+	self->io.speed = speed;
+}
+
+/*
+ * Function irtty_change_speed (instance, state, param)
+ *
+ *    State machine for changing speed of the device. We do it this way since
+ *    we cannot use schedule_timeout() when we are in interrupt context
+ */
+static int irtty_change_speed(struct irda_task *task)
+{
+	struct irtty_cb *self;
+	__u32 speed = (__u32) task->param;
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); 
+
+	self = (struct irtty_cb *) task->instance;
+	ASSERT(self != NULL, return -1;);
+
+	/* Check if busy */
+	if (self->task && self->task != task) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		return MSECS_TO_JIFFIES(10);
+	} else
+		self->task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* 
+		 * Make sure all data is sent before changing the speed of the
+		 * serial port.
+		 */
+		if (self->tty->driver.chars_in_buffer(self->tty)) {
+			/* Keep state, and try again later */
+			ret = MSECS_TO_JIFFIES(10);
+			break;
+		} else {
+			/* Transmit buffer is now empty, but it may still
+			 * take over 13 ms for the FIFO to become empty, so
+			 * wait some more to be sure all data is sent
+			 */
+			irda_task_next_state(task, IRDA_TASK_WAIT);
+			ret = MSECS_TO_JIFFIES(13);
+		}
+	case IRDA_TASK_WAIT:
+		if (self->dongle)
+			irda_task_next_state(task, IRDA_TASK_CHILD_INIT);
+		else
+			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+		break;
+	case IRDA_TASK_CHILD_INIT:
+		/* Go to default speed */
+		__irtty_change_speed(self, 9600);
+
+		/* Change speed of dongle */
+		if (irda_task_execute(self->dongle,
+				      self->dongle->issue->change_speed, 
+				      NULL, task, (void *) speed))
+		{
+			/* Dongle need more time to change its speed */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give dongle 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		} else
+			/* Child finished immediately */
+			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+		break;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ 
+			"(), changing speed of dongle timed out!\n");
+		ret = -1;		
+		break;
+	case IRDA_TASK_CHILD_DONE:
+		/* Finally we are ready to change the speed */
+		__irtty_change_speed(self, speed);
+		
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->task = NULL;
+		ret = -1;
+		break;
+	}	
+	return ret;
 }
 
 /*
@@ -356,9 +488,11 @@
  */
 static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
 {
+	dongle_t *dongle;
+	struct irtty_info info;
 	struct irtty_cb *self;
-	int err = 0;
 	int size = _IOC_SIZE(cmd);
+	int err = 0;
 
 	self = (struct irtty_cb *) tty->disc_data;
 
@@ -366,13 +500,13 @@
 	ASSERT(self->magic == IRTTY_MAGIC, return -EBADR;);
 
 	if (_IOC_DIR(cmd) & _IOC_READ)
-		err = verify_area( VERIFY_WRITE, (void *) arg, size);
+		err = verify_area(VERIFY_WRITE, (void *) arg, size);
 	else if (_IOC_DIR(cmd) & _IOC_WRITE)
-		err = verify_area( VERIFY_READ, (void *) arg, size);
+		err = verify_area(VERIFY_READ, (void *) arg, size);
 	if (err)
 		return err;
 	
-	switch(cmd) {
+	switch (cmd) {
 	case TCGETS:
 	case TCGETA:
 		return n_tty_ioctl(tty, (struct file *) file, cmd, 
@@ -380,7 +514,34 @@
 		break;
 	case IRTTY_IOCTDONGLE:
 		/* Initialize dongle */
-		irda_device_init_dongle(&self->idev, (int) arg);
+		dongle = irda_device_dongle_init(self->netdev, (int) arg);
+		if (!dongle)
+			break;
+		
+		/* Initialize callbacks */
+		dongle->set_mode    = irtty_set_mode;
+		dongle->read        = irtty_raw_read;
+		dongle->write       = irtty_raw_write;
+		dongle->set_dtr_rts = irtty_set_dtr_rts;
+		
+		/* Bind dongle */
+		self->dongle = dongle;
+		
+		/* Now initialize the dongle!  */
+		dongle->issue->open(dongle, &self->qos);
+		
+		/* Reset dongle */
+		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
+				  NULL);		
+		break;
+	case IRTTY_IOCGET:
+		ASSERT(self->netdev != NULL, return -1;);
+
+		memset(&info, 0, sizeof(struct irtty_info)); 
+		strncpy(info.name, self->netdev->name, 5);
+
+		if (copy_to_user(arg, &info, sizeof(struct irtty_info)))
+			return -EFAULT;
 		break;
 	default:
 		return -ENOIOCTLCMD;
@@ -401,27 +562,70 @@
 {
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRTTY_MAGIC, return;);
-	
+	if (!self || !self->netdev) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), not ready yet!\n");
+		return;
+	}
+
 	/* Read the characters out of the buffer */
  	while (count--) {
 		/* 
 		 *  Characters received with a parity error, etc?
 		 */
  		if (fp && *fp++) { 
-			DEBUG( 0, "Framing or parity error!\n");
-			irda_device_set_media_busy( &self->idev, TRUE);
-
+			IRDA_DEBUG(0, "Framing or parity error!\n");
+			irda_device_set_media_busy(self->netdev, TRUE);
+			
  			cp++;
  			continue;
  		}
-		/* Unwrap and destuff one byte */
-		async_unwrap_char(&self->idev, *cp++);
+		
+		switch (self->mode) {
+		case IRDA_IRLAP:
+			/* Unwrap and destuff one byte */
+			async_unwrap_char(self->netdev, &self->stats, 
+					  &self->rx_buff, *cp++);
+			break;
+		case IRDA_RAW:
+			/* What should we do when the buffer is full? */
+			if (self->rx_buff.len == self->rx_buff.truesize)
+				self->rx_buff.len = 0;
+			
+			self->rx_buff.data[self->rx_buff.len++] = *cp++;
+			break;
+		default:
+			break;
+		}
 	}
 }
 
 /*
+ * Function irtty_change_speed_complete (task)
+ *
+ *    Called when the change speed operation completes
+ *
+ */
+static int irtty_change_speed_complete(struct irda_task *task)
+{
+	struct irtty_cb *self;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	self = (struct irtty_cb *) task->instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->netdev != NULL, return -1;);
+
+	/* Finished changing speed, so we are not busy any longer */
+	self->netdev->tbusy = 0;
+
+	/* Signal network layer so it can try to send the frame */
+	mark_bh(NET_BH);
+
+	return 0;
+}
+
+/*
  * Function irtty_hard_xmit (skb, dev)
  *
  *    Transmit frame
@@ -430,56 +634,40 @@
 static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct irtty_cb *self;
-	struct irda_device *idev;
 	int actual = 0;
+	__u32 speed;
 
-	idev = (struct irda_device *) dev->priv;
-
-	ASSERT(idev != NULL, return 0;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
-	
-	self = (struct irtty_cb *) idev->priv;
-
+	self = (struct irtty_cb *) dev->priv;
 	ASSERT(self != NULL, return 0;);
-	ASSERT(self->magic == IRTTY_MAGIC, return 0;);
 
 	/* Lock transmit buffer */
 	if (irda_lock((void *) &dev->tbusy) == FALSE)
 		return -EBUSY;
-	
+
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+
 	/* Init tx buffer*/
-	idev->tx_buff.data = idev->tx_buff.head;
+	self->tx_buff.data = self->tx_buff.head;
 	
         /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
-        idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
-					   idev->tx_buff.truesize); 
+        self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
+					   self->tx_buff.truesize); 
 
 	self->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
 
 	dev->trans_start = jiffies;
+	self->stats.tx_bytes += self->tx_buff.len;
 
 	if (self->tty->driver.write)
 		actual = self->tty->driver.write(self->tty, 0, 
-						 idev->tx_buff.data, 
-						 idev->tx_buff.len);
-
+						 self->tx_buff.data, 
+						 self->tx_buff.len);
 	/* Hide the part we just transmitted */
-	idev->tx_buff.data += actual;
-	idev->tx_buff.len -= actual;
+	self->tx_buff.data += actual;
+	self->tx_buff.len -= actual;
 
-	idev->stats.tx_packets++;
-	idev->stats.tx_bytes += idev->tx_buff.len;
-#if 0
-	/* 
-	 *  Did we transmit the whole frame? Commented out for now since
-	 *  I must check if this optimalization really works. DB.
-	 */
- 	if ((idev->tx_buff.len) == 0) {
- 		DEBUG( 4, "irtty_xmit_buf: finished with frame!\n");
- 		self->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- 		irda_unlock( &self->tbusy);
- 	}
-#endif
 	dev_kfree_skb(skb);
 
 	return 0;
@@ -493,7 +681,7 @@
 */
 static int irtty_receive_room(struct tty_struct *tty) 
 {
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 	return 65536;  /* We can handle an infinite amount of data. :-) */
 }
 
@@ -507,7 +695,6 @@
 static void irtty_write_wakeup(struct tty_struct *tty) 
 {
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
-	struct irda_device *idev;
 	int actual = 0;
 	
 	/* 
@@ -516,61 +703,49 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRTTY_MAGIC, return;);
 
-	idev = &self->idev;
-
 	/* Finished with frame?  */
-	if (idev->tx_buff.len > 0)  {
+	if (self->tx_buff.len > 0)  {
 		/* Write data left in transmit buffer */
-		actual = tty->driver.write(tty, 0, idev->tx_buff.data, 
-					   idev->tx_buff.len);
+		actual = tty->driver.write(tty, 0, self->tx_buff.data, 
+					   self->tx_buff.len);
+
+		self->tx_buff.data += actual;
+		self->tx_buff.len  -= actual;
 
-		idev->tx_buff.data += actual;
-		idev->tx_buff.len  -= actual;
+		self->stats.tx_packets++;		      
 	} else {		
 		/* 
 		 *  Now serial buffer is almost free & we can start 
 		 *  transmission of another packet 
 		 */
-		DEBUG(5, __FUNCTION__ "(), finished with frame!\n");
+		IRDA_DEBUG(5, __FUNCTION__ "(), finished with frame!\n");
 		
 		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 
-		idev->netdev.tbusy = 0; /* Unlock */
-			
-		/* Tell network layer that we want more frames */
-		mark_bh(NET_BH);
+		if (self->new_speed) {
+			IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
+			irda_task_execute(self, irtty_change_speed, 
+					  irtty_change_speed_complete, 
+					  NULL, (void *) self->new_speed);
+			self->new_speed = 0;
+		} else {
+			self->netdev->tbusy = 0; /* Unlock */
+		
+			/* Tell network layer that we want more frames */
+			mark_bh(NET_BH);
+		}
 	}
 }
 
 /*
- * Function irtty_is_receiving (idev)
+ * Function irtty_is_receiving (self)
  *
  *    Return TRUE is we are currently receiving a frame
  *
  */
-static int irtty_is_receiving(struct irda_device *idev)
-{
-	return (idev->rx_buff.state != OUTSIDE_FRAME);
-}
-
-/*
- * Function irtty_change_speed_ready (idev)
- *
- *    Are we completely finished with transmitting frames so its possible
- *    to change the speed of the serial port. Warning this function must
- *    be called with a process context!
- */
-static void irtty_wait_until_sent(struct irda_device *idev)
+static int irtty_is_receiving(struct irtty_cb *self)
 {
-	struct irtty_cb *self = (struct irtty_cb *) idev->priv;
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRTTY_MAGIC, return;);
-	
-	DEBUG(4, "Chars in buffer %d\n", 
-	      self->tty->driver.chars_in_buffer(self->tty));
-	
-	tty_wait_until_sent(self->tty, 0);
+	return (self->rx_buff.state != OUTSIDE_FRAME);
 }
 
 /*
@@ -579,15 +754,14 @@
  *    This function can be used by dongles etc. to set or reset the status
  *    of the dtr and rts lines
  */
-static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts)
+static int irtty_set_dtr_rts(struct device *dev, int dtr, int rts)
 {
-	struct tty_struct *tty;
 	struct irtty_cb *self;
+	struct tty_struct *tty;
 	mm_segment_t fs;
 	int arg = 0;
 
-	self = (struct irtty_cb *) idev->priv;
-
+	self = (struct irtty_cb *) dev->priv;
 	tty = self->tty;
 
 #ifdef TIOCM_OUT2 /* Not defined for ARM */
@@ -610,20 +784,93 @@
 	set_fs(get_ds());
 	
 	if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { 
-		ERROR(__FUNCTION__ "(), error doing ioctl!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), error doing ioctl!\n");
 	}
 	set_fs(fs);
+
+	return 0;
 }
 
-static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len)
+/*
+ * Function irtty_set_mode (self, status)
+ *
+ *    For the airport dongle, we need support for reading raw characters
+ *    from the IrDA device. This function switches between those modes. 
+ *    FALSE is the default mode, and will then treat incoming data as IrDA 
+ *    packets.
+ */
+int irtty_set_mode(struct device *dev, int mode)
 {
 	struct irtty_cb *self;
-	int actual = 0;
 
-	ASSERT(idev != NULL, return 0;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+	self = (struct irtty_cb *) dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), mode=%s\n", infrared_mode[mode]);
+	
+	/* save status for driver */
+	self->mode = mode;
 	
-	self = (struct irtty_cb *) idev->priv;
+	/* reset the buffer state */
+	self->rx_buff.data = self->rx_buff.head;
+	self->rx_buff.len = 0;
+	self->rx_buff.state = OUTSIDE_FRAME;
+
+	return 0;
+}
+
+/*
+ * Function irtty_raw_read (self, buf, len)
+ *
+ *    Receive incomming data. This function sleeps, so it must only be
+ *    called with a process context. Timeout is currently defined to be
+ *    a multiple of 10 ms.
+ */
+static int irtty_raw_read(struct device *dev, __u8 *buf, int len)
+{
+	struct irtty_cb *self;
+	int count;
+
+	self = (struct irtty_cb *) dev->priv;
+
+	ASSERT(self != NULL, return 0;);
+	ASSERT(self->magic == IRTTY_MAGIC, return 0;);
+
+	return 0;
+#if 0
+	buf = self->rx_buff.data;
+
+	/* Wait for the requested amount of data to arrive */
+	while (len < self->rx_buff.len) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(MSECS_TO_JIFFIES(10));
+
+		if (!timeout--)
+			break;
+	}
+	
+	count = self->rx_buff.len < len ? self->rx_buff.len : len;
+
+	/* 
+	 * Reset the state, this mean that a raw read is sort of a 
+	 * datagram read, and _not_ a stream style read. Be aware of the
+	 * difference. Implementing it the other way will just be painful ;-)
+	 */
+	self->rx_buff.data = self->rx_buff.head;
+	self->rx_buff.len = 0;
+	self->rx_buff.state = OUTSIDE_FRAME;
+#endif
+	/* Return the amount we were able to get */
+	return count;
+}
+
+static int irtty_raw_write(struct device *dev, __u8 *buf, int len)
+{
+	struct irtty_cb *self;
+	int actual = 0;
+
+	self = (struct irtty_cb *) dev->priv;
 
 	ASSERT(self != NULL, return 0;);
 	ASSERT(self->magic == IRTTY_MAGIC, return 0;);
@@ -646,13 +893,27 @@
 
 static int irtty_net_open(struct device *dev)
 {
-	ASSERT(dev != NULL, return -1;);
+	struct irtty_cb *self = (struct irtty_cb *) dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRTTY_MAGIC, return -1;);
 
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	
 	/* Ready to play! */
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	dev->start = 1;
 
+	/* Make sure we can receive more data */
+	irtty_stop_receiver(self, FALSE);
+
+	/* 
+	 * Open new IrLAP layer instance, now that everything should be
+	 * initialized properly 
+	 */
+	self->irlap = irlap_open(dev, &self->qos);
+
 	MOD_INC_USE_COUNT;
 
 	return 0;
@@ -660,17 +921,108 @@
 
 static int irtty_net_close(struct device *dev)
 {
-	ASSERT(dev != NULL, return -1;);
-	
+	struct irtty_cb *self = (struct irtty_cb *) dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRTTY_MAGIC, return -1;);
+
+	/* Make sure we don't receive more data */
+	irtty_stop_receiver(self, TRUE);
+
 	/* Stop device */
 	dev->tbusy = 1;
 	dev->start = 0;
 
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
+
 	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
 
+/*
+ * Function irtty_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+static int irtty_net_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct irtty_cb *self;
+	dongle_t *dongle;
+	unsigned long flags;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRTTY_MAGIC, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		irda_task_execute(self, irtty_change_speed, NULL, NULL, 
+				  (void *) irq->ifr_baudrate);
+		break;
+	case SIOCSDONGLE: /* Set dongle */
+		/* Initialize dongle */
+		dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
+		if (!dongle)
+			break;
+		
+		dongle->set_mode    = irtty_set_mode;
+		dongle->read        = irtty_raw_read;
+		dongle->write       = irtty_raw_write;
+		dongle->set_dtr_rts = irtty_set_dtr_rts;
+		
+		self->dongle = dongle;
+
+		/* Now initialize the dongle!  */
+		dongle->issue->open(dongle, &self->qos);
+		
+		/* Reset dongle */
+		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
+				  NULL);	
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = irtty_is_receiving(self);
+		break;
+	case SIOCSDTRRTS:
+		irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+		break;
+	case SIOCSMODE:
+		irtty_set_mode(dev, irq->ifr_mode);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
+
+static struct net_device_stats *irtty_net_get_stats(struct device *dev)
+{
+	struct irtty_cb *self = (struct irtty_cb *) dev->priv;
+
+	return &self->stats;
+}
+
 #ifdef MODULE
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
@@ -701,10 +1053,3 @@
 }
 
 #endif /* MODULE */
-
-
-
-
-
-
-
diff -urN linux-2.2.15-pre2/drivers/net/irda/litelink.c linux/drivers/net/irda/litelink.c
--- linux-2.2.15-pre2/drivers/net/irda/litelink.c	Mon Jun  7 16:19:59 1999
+++ linux/drivers/net/irda/litelink.c	Mon Dec  3 21:57:53 2001
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      litelink.c
- * Version:       1.0
+ * Version:       1.1
  * 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 at:   Fri Dec 17 09:14:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -37,30 +37,28 @@
 #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);
+static void litelink_open(dongle_t *self, struct qos_info *qos);
+static void litelink_close(dongle_t *self);
+static int  litelink_change_speed(struct irda_task *task);
+static int  litelink_reset(struct irda_task *task);
 
 /* These are the baudrates supported */
-static int baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
+static __u32 baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
 
-static struct dongle dongle = {
-	LITELINK_DONGLE,
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_LITELINK_DONGLE,
 	litelink_open,
 	litelink_close,
 	litelink_reset,
 	litelink_change_speed,
-	litelink_init_qos,
 };
 
-__initfunc(int litelink_init(void))
+int __init litelink_init(void)
 {
 	return irda_device_register_dongle(&dongle);
 }
@@ -70,114 +68,102 @@
 	irda_device_unregister_dongle(&dongle);
 }
 
-static void litelink_open(struct irda_device *idev, int type)
+static void litelink_open(dongle_t *self, struct qos_info *qos)
 {
-	strcat(idev->description, " <-> litelink");
-
-        idev->io.dongle_id = type;
-	idev->flags |= IFF_DONGLE;
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
 
 	MOD_INC_USE_COUNT;
 }
 
-static void litelink_close(struct irda_device *idev)
+static void litelink_close(dongle_t *self)
 {
 	/* Power off dongle */
-	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
 
 	MOD_DEC_USE_COUNT;
 }
 
 /*
- * Function litelink_change_speed (tty, baud)
+ * Function litelink_change_speed (task)
  *
  *    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)
+static int litelink_change_speed(struct irda_task *task)
 {
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
         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);
+	self->set_dtr_rts(self->dev, TRUE, FALSE);
 
 	/* Sleep a minimum of 15 us */
 	udelay(MIN_DELAY);
 
 	/* Go back to normal mode */
-	irda_device_set_dtr_rts(idev, TRUE, TRUE);
+	self->set_dtr_rts(self->dev, 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++) {
-
+	for (i=0; i<5 && baud_rates[i] != speed; i++) {
 		/* Set DTR, clear RTS */
-		irda_device_set_dtr_rts(idev, FALSE, TRUE);
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
 		
 		/* Sleep a minimum of 15 us */
 		udelay(MIN_DELAY);
 		
 		/* Set DTR, Set RTS */
-		irda_device_set_dtr_rts(idev, TRUE, TRUE);
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
 		
 		/* Sleep a minimum of 15 us */
 		udelay(MIN_DELAY);
         }
+	irda_task_next_state(task, IRDA_TASK_DONE);
+
+	return 0;
 }
 
 /*
- * Function litelink_reset (dev)
+ * Function litelink_reset (task)
  *
- *      Reset the Litelink type dongle. Warning, this function must only be
- *      called with a process context!
+ *      Reset the Litelink type dongle.
  *
  */
-static void litelink_reset(struct irda_device *idev)
+static int litelink_reset(struct irda_task *task)
 {
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
+	dongle_t *self = (dongle_t *) task->instance;
+
 	/* Power on dongle */
-	irda_device_set_dtr_rts(idev, TRUE, TRUE);
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
 
 	/* Sleep a minimum of 15 us */
 	udelay(MIN_DELAY);
 
 	/* Clear RTS to reset dongle */
-	irda_device_set_dtr_rts(idev, TRUE, FALSE);
+	self->set_dtr_rts(self->dev, TRUE, FALSE);
 
 	/* Sleep a minimum of 15 us */
 	udelay(MIN_DELAY);
 
 	/* Go back to normal mode */
-	irda_device_set_dtr_rts(idev, TRUE, TRUE);
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
 	
 	/* Sleep a minimum of 15 us */
 	udelay(MIN_DELAY);
 
 	/* This dongles speed defaults to 115200 bps */
-	idev->qos.baud_rate.value = 115200;
-}
+	self->speed = 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 */
+	irda_task_next_state(task, IRDA_TASK_DONE);
+
+	return 0;
 }
 
 #ifdef MODULE
-
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("Parallax Litelink dongle driver");	
 		
@@ -202,5 +188,4 @@
 {
 	litelink_cleanup();
 }
-
-#endif
+#endif /* MODULE */
diff -urN linux-2.2.15-pre2/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- linux-2.2.15-pre2/drivers/net/irda/nsc-ircc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/nsc-ircc.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,2074 @@
+/*********************************************************************
+ *                
+ * Filename:      nsc-ircc.c
+ * Version:       1.0
+ * Description:   Driver for the NSC PC'108 and PC'338 IrDA chipsets
+ * Status:        Stable.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sat Nov  7 21:43:15 1998
+ * Modified at:   Mon Jan 17 11:19:15 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1998-2000 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
+ *      
+ *     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 that all functions that needs to access the chip in _any_
+ *     way, must save BSR register on entry, and restore it on exit. 
+ *     It is _very_ important to follow this policy!
+ *
+ *         __u8 bank;
+ *     
+ *         bank = inb(iobase+BSR);
+ *  
+ *         do_your_stuff_here();
+ *
+ *         outb(bank, iobase+BSR);
+ *
+ *    If you find bugs in this file, its very likely that the same bug
+ *    will also be in w83977af_ir.c since the implementations are quite
+ *    similar.
+ *     
+ ********************************************************************/
+
+#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/rtnetlink.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
+#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/nsc-ircc.h>
+
+#define CHIP_IO_EXTENT 8
+#define BROKEN_DONGLE_ID
+
+static char *driver_name = "nsc-ircc";
+
+/* Module parameters */
+static int qos_mtt_bits = 0x07;  /* 1 ms or more */
+static int dongle_id = 0;
+
+/* Use BIOS settions by default, but user may supply module parameters */
+static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = { 0, 0, 0, 0, 0 };
+static unsigned int dma[] = { 0, 0, 0, 0, 0 };
+
+static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
+
+/* These are the known NSC chips */
+static nsc_chip_t chips[] = {
+	{ "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, 
+	  nsc_ircc_probe_108, nsc_ircc_init_108 },
+	{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf0, 
+	  nsc_ircc_probe_338, nsc_ircc_init_338 },
+	{ NULL }
+};
+
+/* Max 4 instances for now */
+static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
+
+static char *dongle_types[] = {
+	"Differential serial interface",
+	"Differential serial interface",
+	"Reserved",
+	"Reserved",
+	"Sharp RY5HD01",
+	"Reserved",
+	"Single-ended serial interface",
+	"Consumer-IR only",
+	"HP HSDL-2300, HP HSDL-3600/HSDL-3610",
+	"IBM31T1100 or Temic TFDS6000/TFDS6500",
+	"Reserved",
+	"Reserved",
+	"HP HSDL-1100/HSDL-2100",
+	"HP HSDL-1100/HSDL-2100"
+	"Supports SIR Mode only",
+	"No dongle connected",
+};
+
+/* Some prototypes */
+static int  nsc_ircc_open(int i, chipio_t *info);
+#ifdef MODULE
+static int  nsc_ircc_close(struct nsc_ircc_cb *self);
+#endif /* MODULE */
+static int  nsc_ircc_setup(chipio_t *info);
+static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
+static int  nsc_ircc_dma_receive(struct nsc_ircc_cb *self); 
+static int  nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase);
+static int  nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct device *dev);
+static int  nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct device *dev);
+static int  nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase);
+static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud);
+static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int  nsc_ircc_is_receiving(struct nsc_ircc_cb *self);
+static int  nsc_ircc_read_dongle_id (int iobase);
+static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id);
+
+static int  nsc_ircc_net_init(struct device *dev);
+static int  nsc_ircc_net_open(struct device *dev);
+static int  nsc_ircc_net_close(struct device *dev);
+static int  nsc_ircc_net_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *nsc_ircc_net_get_stats(struct device *dev);
+#ifdef CONFIG_APM
+static int nsc_ircc_apmproc(apm_event_t event);
+#endif /* CONFIG_APM */
+
+/*
+ * Function nsc_ircc_init ()
+ *
+ *    Initialize chip. Just try to find out how many chips we are dealing with
+ *    and where they are
+ */
+int __init nsc_ircc_init(void)
+{
+	chipio_t info;
+	nsc_chip_t *chip;
+	int ret = -ENODEV;
+	int cfg_base;
+	int cfg, id;
+	int reg;
+	int i = 0;
+
+#ifdef CONFIG_APM
+	apm_register_callback(nsc_ircc_apmproc);
+#endif /* CONFIG_APM */
+
+	/* Probe for all the NSC chipsets we know about */
+	for (chip=chips; chip->name ; chip++,i++) {
+		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", 
+			   chip->name);
+		
+		/* Try all config registers for this chip */
+		for (cfg=0; cfg<3; cfg++) {
+			cfg_base = chip->cfg[cfg];
+			if (!cfg_base)
+				continue;
+			
+			memset(&info, 0, sizeof(chipio_t));
+			info.cfg_base = cfg_base;
+			info.fir_base = io[i];
+			info.dma = dma[i];
+			info.irq = irq[i];
+
+			/* Read index register */
+			reg = inb(cfg_base);
+			if (reg == 0xff) {
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "() no chip at 0x%03x\n", cfg_base);
+				continue;
+			}
+			
+			/* Read chip identification register */
+			outb(chip->cid_index, cfg_base);
+			id = inb(cfg_base+1);
+			if ((id & chip->cid_mask) == chip->cid_value) {
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "() Found %s chip, revision=%d\n",
+					   chip->name, id & ~chip->cid_mask);
+				/* 
+				 * If the user supplies the base address, then
+				 * we init the chip, if not we probe the values
+				 * set by the BIOS
+				 */				
+				if (io[i] < 2000) {
+					chip->init(chip, &info);
+				} else
+					chip->probe(chip, &info);
+
+				if (nsc_ircc_open(i, &info) == 0)
+					ret = 0;
+				i++;
+			} else {
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "(), Wrong chip id=0x%02x\n", id);
+			}
+		} 
+		
+	}
+	return ret;
+}
+
+/*
+ * Function nsc_ircc_cleanup ()
+ *
+ *    Close all configured chips
+ *
+ */
+#ifdef MODULE
+static void nsc_ircc_cleanup(void)
+{
+	int i;
+
+#ifdef CONFIG_APM
+	apm_unregister_callback(nsc_ircc_apmproc);
+#endif /* CONFIG_APM */
+
+	for (i=0; i < 4; i++) {
+		if (dev_self[i])
+			nsc_ircc_close(dev_self[i]);
+	}
+}
+#endif /* MODULE */
+
+/*
+ * Function nsc_ircc_open (iobase, irq)
+ *
+ *    Open driver instance
+ *
+ */
+static int nsc_ircc_open(int i, chipio_t *info)
+{
+	struct device *dev;
+	struct nsc_ircc_cb *self;
+	int ret;
+	int err;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if ((nsc_ircc_setup(info)) == -1)
+		return -1;
+
+	/* Allocate new instance of the driver */
+	self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL);
+	if (self == NULL) {
+		ERROR(__FUNCTION__ "(), can't allocate memory for "
+		       "control block!\n");
+		return -ENOMEM;
+	}
+	memset(self, 0, sizeof(struct nsc_ircc_cb));
+	spin_lock_init(&self->lock);
+   
+	/* Need to store self somewhere */
+	dev_self[i] = self;
+	self->index = i;
+
+	/* Initialize IO */
+	self->io.cfg_base  = info->cfg_base;
+	self->io.fir_base  = info->fir_base;
+        self->io.irq       = info->irq;
+        self->io.fir_ext   = CHIP_IO_EXTENT;
+        self->io.dma       = info->dma;
+        self->io.fifo_size = 32;
+	
+	/* Reserve the ioports that we need */
+	ret = check_region(self->io.fir_base, self->io.fir_ext);
+	if (ret < 0) { 
+		WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
+			self->io.fir_base);
+		dev_self[i] = NULL;
+		kfree(self);
+		return -ENODEV;
+	}
+	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&self->qos);
+	
+	/* The only value we must override it the baudrate */
+	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+		IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8);
+	
+	self->qos.min_turn_time.bits = qos_mtt_bits;
+	irda_qos_bits_to_value(&self->qos);
+	
+	self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
+
+	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+	self->rx_buff.truesize = 14384; 
+	self->tx_buff.truesize = 14384;
+
+	/* Allocate memory if needed */
+	self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
+					      GFP_KERNEL|GFP_DMA);
+	if (self->rx_buff.head == NULL) {
+		kfree(self);
+		return -ENOMEM;
+	}
+	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+	
+	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+					      GFP_KERNEL|GFP_DMA);
+	if (self->tx_buff.head == NULL) {
+		kfree(self);
+		kfree(self->rx_buff.head);
+		return -ENOMEM;
+	}
+	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+
+	self->rx_buff.in_frame = FALSE;
+	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	/* Reset Tx queue info */
+	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+	self->tx_fifo.tail = self->tx_buff.head;
+
+	if (!(dev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return -ENOMEM;
+	}
+	/* dev_alloc doesn't clear the struct, so lets do a little hack */
+	memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct device)-sizeof(char*));
+
+	dev->priv = (void *) self;
+	self->netdev = dev;
+
+	/* Override the network functions we need to use */
+	dev->init            = nsc_ircc_net_init;
+	dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
+	dev->open            = nsc_ircc_net_open;
+	dev->stop            = nsc_ircc_net_close;
+	dev->do_ioctl        = nsc_ircc_net_ioctl;
+	dev->get_stats	     = nsc_ircc_net_get_stats;
+
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return -1;
+	}
+	MESSAGE("IrDA: Registered device %s\n", dev->name);
+
+	/* Check if user has supplied the dongle id or not */
+	if (!dongle_id) {
+		dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
+		
+		MESSAGE("%s, Found dongle: %s\n", driver_name,
+			dongle_types[dongle_id]);
+	} else {
+		MESSAGE("%s, Using dongle: %s\n", driver_name,
+			dongle_types[dongle_id]);
+	}
+	
+	self->io.dongle_id = dongle_id;
+	nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
+
+	return 0;
+}
+
+#ifdef MODULE
+/*
+ * Function nsc_ircc_close (self)
+ *
+ *    Close driver instance
+ *
+ */
+static int nsc_ircc_close(struct nsc_ircc_cb *self)
+{
+	int iobase;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+
+        iobase = self->io.fir_base;
+
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		rtnl_unlock();
+		/* Must free the old-style 2.2.x device */
+		kfree(self->netdev);
+	}
+
+	/* Release the PORT that this driver is using */
+	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", 
+		   self->io.fir_base);
+	release_region(self->io.fir_base, self->io.fir_ext);
+
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
+
+	dev_self[self->index] = NULL;
+	kfree(self);
+	
+	return 0;
+}
+#endif /* MODULE */
+
+/*
+ * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma)
+ *
+ *    Initialize the NSC '108 chip
+ *
+ */
+static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info)
+{
+	int cfg_base = info->cfg_base;
+	__u8 temp=0;
+
+	outb(2, cfg_base);      /* Mode Control Register (MCTL) */
+	outb(0x00, cfg_base+1); /* Disable device */
+	
+	/* Base Address and Interrupt Control Register (BAIC) */
+	outb(0, cfg_base);
+	switch (info->fir_base) {
+	case 0x3e8: outb(0x14, cfg_base+1); break;
+	case 0x2e8: outb(0x15, cfg_base+1); break;
+	case 0x3f8: outb(0x16, cfg_base+1); break;
+	case 0x2f8: outb(0x17, cfg_base+1); break;
+	default: ERROR(__FUNCTION__ "(), invalid base_address");
+	}
+	
+	/* Control Signal Routing Register (CSRT) */
+	switch (info->irq) {
+	case 3:  temp = 0x01; break;
+	case 4:  temp = 0x02; break;
+	case 5:  temp = 0x03; break;
+	case 7:  temp = 0x04; break;
+	case 9:  temp = 0x05; break;
+	case 11: temp = 0x06; break;
+	case 15: temp = 0x07; break;
+	default: ERROR(__FUNCTION__ "(), invalid irq");
+	}
+	outb(1, cfg_base);
+	
+	switch (info->dma) {	
+	case 0: outb(0x08+temp, cfg_base+1); break;
+	case 1: outb(0x10+temp, cfg_base+1); break;
+	case 3: outb(0x18+temp, cfg_base+1); break;
+	default: ERROR(__FUNCTION__ "(), invalid dma");
+	}
+	
+	outb(2, cfg_base);      /* Mode Control Register (MCTL) */
+	outb(0x03, cfg_base+1); /* Enable device */
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_probe_108 (chip, info)
+ *
+ *    
+ *
+ */
+static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) 
+{
+	int cfg_base = info->cfg_base;
+	int reg;
+
+	/* Read address and interrupt control register (BAIC) */
+	outb(CFG_BAIC, cfg_base);
+	reg = inb(cfg_base+1);
+	
+	switch (reg & 0x03) {
+	case 0:
+		info->fir_base = 0x3e8;
+		break;
+	case 1:
+		info->fir_base = 0x2e8;
+		break;
+	case 2:
+		info->fir_base = 0x3f8;
+		break;
+	case 3:
+		info->fir_base = 0x2f8;
+		break;
+	}
+	info->sir_base = info->fir_base;
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", 
+		   info->fir_base);
+
+	/* Read control signals routing register (CSRT) */
+	outb(CFG_CSRT, cfg_base);
+	reg = inb(cfg_base+1);
+
+	switch (reg & 0x07) {
+	case 0:
+		info->irq = -1;
+		break;
+	case 1:
+		info->irq = 3;
+		break;
+	case 2:
+		info->irq = 4;
+		break;
+	case 3:
+		info->irq = 5;
+		break;
+	case 4:
+		info->irq = 7;
+		break;
+	case 5:
+		info->irq = 9;
+		break;
+	case 6:
+		info->irq = 11;
+		break;
+	case 7:
+		info->irq = 15;
+		break;
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq);
+
+	/* Currently we only read Rx DMA but it will also be used for Tx */
+	switch ((reg >> 3) & 0x03) {
+	case 0:
+		info->dma = -1;
+		break;
+	case 1:
+		info->dma = 0;
+		break;
+	case 2:
+		info->dma = 1;
+		break;
+	case 3:
+		info->dma = 3;
+		break;
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma);
+
+	/* Read mode control register (MCTL) */
+	outb(CFG_MCTL, cfg_base);
+	reg = inb(cfg_base+1);
+
+	info->enabled = reg & 0x01;
+	info->suspended = !((reg >> 1) & 0x01);
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_init_338 (chip, info)
+ *
+ *    Initialize the NSC '338 chip. Remember that the 87338 needs two 
+ *    consecutive writes to the data registers while CPU interrupts are
+ *    disabled. The 97338 does not require this, but shouldn't be any
+ *    harm if we do it anyway.
+ */
+static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info) 
+{
+	/* No init yet */
+	
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_probe_338 (chip, info)
+ *
+ *    
+ *
+ */
+static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info) 
+{
+	int cfg_base = info->cfg_base;
+	int reg, com = 0;
+	int pnp;
+
+	/* Read funtion enable register (FER) */
+	outb(CFG_FER, cfg_base);
+	reg = inb(cfg_base+1);
+
+	info->enabled = (reg >> 2) & 0x01;
+
+	/* Check if we are in Legacy or PnP mode */
+	outb(CFG_PNP0, cfg_base);
+	reg = inb(cfg_base+1);
+	
+	pnp = (reg >> 4) & 0x01;
+	if (pnp) {
+		IRDA_DEBUG(2, "(), Chip is in PnP mode\n");
+		outb(0x46, cfg_base);
+		reg = (inb(cfg_base+1) & 0xfe) << 2;
+
+		outb(0x47, cfg_base);
+		reg |= ((inb(cfg_base+1) & 0xfc) << 8);
+
+		info->fir_base = reg;
+	} else {
+		/* Read function address register (FAR) */
+		outb(CFG_FAR, cfg_base);
+		reg = inb(cfg_base+1);
+		
+		switch ((reg >> 4) & 0x03) {
+		case 0:
+			info->fir_base = 0x3f8;
+			break;
+		case 1:
+			info->fir_base = 0x2f8;
+			break;
+		case 2:
+			com = 3;
+			break;
+		case 3:
+			com = 4;
+			break;
+		}
+		
+		if (com) {
+			switch ((reg >> 6) & 0x03) {
+			case 0:
+				if (com == 3)
+					info->fir_base = 0x3e8;
+				else
+					info->fir_base = 0x2e8;
+				break;
+			case 1:
+				if (com == 3)
+					info->fir_base = 0x338;
+				else
+					info->fir_base = 0x238;
+				break;
+			case 2:
+				if (com == 3)
+					info->fir_base = 0x2e8;
+				else
+					info->fir_base = 0x2e0;
+				break;
+			case 3:
+				if (com == 3)
+					info->fir_base = 0x220;
+				else
+					info->fir_base = 0x228;
+				break;
+			}
+		}
+	}
+	info->sir_base = info->fir_base;
+
+	/* Read PnP register 1 (PNP1) */
+	outb(CFG_PNP1, cfg_base);
+	reg = inb(cfg_base+1);
+	
+	info->irq = reg >> 4;
+	
+	/* Read PnP register 3 (PNP3) */
+	outb(CFG_PNP3, cfg_base);
+	reg = inb(cfg_base+1);
+
+	info->dma = (reg & 0x07) - 1;
+
+	/* Read power and test register (PTR) */
+	outb(CFG_PTR, cfg_base);
+	reg = inb(cfg_base+1);
+
+	info->suspended = reg & 0x01;
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_setup (info)
+ *
+ *    Returns non-negative on success.
+ *
+ */
+static int nsc_ircc_setup(chipio_t *info)
+{
+	int version;
+	int iobase = info->fir_base;
+
+	/* Read the Module ID */
+	switch_bank(iobase, BANK3);
+	version = inb(iobase+MID);
+
+	/* Should be 0x2? */
+	if (0x20 != (version & 0xf0)) {
+		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
+		return -1;
+	}
+	MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, 
+		info->cfg_base);
+
+	/* Switch to advanced mode */
+	switch_bank(iobase, BANK2);
+	outb(ECR1_EXT_SL, iobase+ECR1);
+	switch_bank(iobase, BANK0);
+	
+	/* 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);
+	
+	/* Set FIFO size to 32 */
+	switch_bank(iobase, BANK2);
+	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
+
+	/* IRCR2: FEND_MD is set */
+	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 */
+
+	MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
+
+	/* Enable receive interrupts */
+	switch_bank(iobase, BANK0);
+	outb(IER_RXHDL_IE, iobase+IER);
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_read_dongle_id (void)
+ *
+ * Try to read dongle indentification. This procedure needs to be executed
+ * once after power-on/reset. It also needs to be used whenever you suspect
+ * that the user may have plugged/unplugged the IrDA Dongle.
+ */
+static int nsc_ircc_read_dongle_id (int iobase)
+{
+	int dongle_id;
+	__u8 bank;
+
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
+	outb(0x00, iobase+7);
+	
+	/* ID0, 1, and 2 are pulled up/down very slowly */
+	udelay(50);
+	
+	/* IRCFG1: read the ID bits */
+	dongle_id = inb(iobase+4) & 0x0f;
+
+#ifdef BROKEN_DONGLE_ID
+	if (dongle_id == 0x0a)
+		dongle_id = 0x09;
+#endif	
+	/* Go back to  bank 0 before returning */
+	switch_bank(iobase, BANK0);
+
+	outb(bank, iobase+BSR);
+
+	return dongle_id;
+}
+
+/*
+ * Function nsc_ircc_init_dongle_interface (iobase, dongle_id)
+ *
+ *     This function initializes the dongle for the transceiver that is
+ *     used. This procedure needs to be executed once after
+ *     power-on/reset. It also needs to be used whenever you suspect that
+ *     the dongle is changed. 
+ */
+static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id)
+{
+	int bank;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG4: set according to dongle_id */
+	switch (dongle_id) {
+	case 0x00: /* same as */
+	case 0x01: /* Differential serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x02: /* same as */
+	case 0x03: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x04: /* Sharp RY5HD01 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x05: /* Reserved, but this is what the Thinkpad reports */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x06: /* Single-ended serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x07: /* Consumer-IR only */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
+			   dongle_types[dongle_id]);
+		break;
+	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
+		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
+		break;
+	case 0x0A: /* same as */
+	case 0x0B: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x0C: /* same as */
+	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
+		/* 
+		 * Set irsl0 as input, irsl[1-2] as output, and separate 
+		 * inputs are used for SIR and MIR/FIR 
+		 */
+		outb(0x48, iobase+7); 
+		break;
+	case 0x0E: /* Supports SIR Mode only */
+		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
+		break;
+	case 0x0F: /* No dongle connected */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
+			   dongle_types[dongle_id]); 
+
+		switch_bank(iobase, BANK0);
+		outb(0x62, iobase+MCR);
+		break;
+	default: 
+		IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", 
+			   dongle_id);
+	}
+	
+	/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
+	outb(0x00, iobase+4);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+	
+} /* set_up_dongle_interface */
+
+/*
+ * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id)
+ *
+ *    Change speed of the attach dongle
+ *
+ */
+static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id)
+{
+	unsigned long flags;
+	__u8 bank;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG1: set according to dongle_id */
+	switch (dongle_id) {
+	case 0x00: /* same as */
+	case 0x01: /* Differential serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x02: /* same as */
+	case 0x03: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x04: /* Sharp RY5HD01 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+			   dongle_types[dongle_id]); 
+	case 0x05: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x06: /* Single-ended serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x07: /* Consumer-IR only */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", 
+			   dongle_types[dongle_id]); 
+		outb(0x00, iobase+4);
+		if (speed > 115200)
+			outb(0x01, iobase+4);
+		break;
+	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
+		outb(0x01, iobase+4);
+
+		if (speed == 4000000) {
+			save_flags(flags);
+			cli();
+			outb(0x81, iobase+4);
+			outb(0x80, iobase+4);
+			restore_flags(flags);
+		} else
+			outb(0x00, iobase+4);
+		break;
+	case 0x0A: /* same as */
+	case 0x0B: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x0C: /* same as */
+	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
+		break;
+	case 0x0E: /* Supports SIR Mode only */
+		break;
+	case 0x0F: /* No dongle connected */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]);
+
+		switch_bank(iobase, BANK0); 
+		outb(0x62, iobase+MCR);
+		break;
+	default: 
+		IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n");
+	}
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_change_speed (self, baud)
+ *
+ *    Change the speed of the device
+ *
+ */
+static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
+{
+	struct device *dev = self->netdev;
+	__u8 mcr = MCR_SIR;
+	int iobase; 
+	__u8 bank;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed);
+
+	ASSERT(self != NULL, return;);
+
+	iobase = self->io.fir_base;
+
+	/* Update accounting for new speed */
+	self->io.speed = speed;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable interrupts */
+	switch_bank(iobase, BANK0);
+	outb(0, iobase+IER);
+
+	/* Select Bank 2 */
+	switch_bank(iobase, BANK2);
+
+	outb(0x00, iobase+BGDH);
+	switch (speed) {
+	case 9600:   outb(0x0c, iobase+BGDL); break;
+	case 19200:  outb(0x06, iobase+BGDL); break;
+	case 38400:  outb(0x03, iobase+BGDL); break;
+	case 57600:  outb(0x02, iobase+BGDL); break;
+	case 115200: outb(0x01, iobase+BGDL); break;
+	case 576000:
+		switch_bank(iobase, BANK5);
+		
+		/* IRCR2: MDRS is set */
+		outb(inb(iobase+4) | 0x04, iobase+4);
+	       
+		mcr = MCR_MIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
+		break;
+	case 1152000:
+		mcr = MCR_MIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
+		break;
+	case 4000000:
+		mcr = MCR_FIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
+		break;
+	default:
+		mcr = MCR_FIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 
+			   speed);
+		break;
+	}
+
+	/* Set appropriate speed mode */
+	switch_bank(iobase, BANK0);
+	outb(mcr | MCR_TX_DFR, iobase+MCR);
+
+	/* Give some hits to the transceiver */
+	nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id);
+
+	/* Set FIFO threshold to TX17, RX16 */
+	switch_bank(iobase, BANK0);
+	outb(0x00, iobase+FCR);
+	outb(FCR_FIFO_EN, iobase+FCR);
+	outb(FCR_RXTH|     /* Set Rx FIFO threshold */
+	     FCR_TXTH|     /* Set Tx FIFO threshold */
+	     FCR_TXSR|     /* Reset Tx FIFO */
+	     FCR_RXSR|     /* Reset Rx FIFO */
+	     FCR_FIFO_EN,  /* Enable FIFOs */
+	     iobase+FCR);
+	
+	/* Set FIFO size to 32 */
+	switch_bank(iobase, BANK2);
+	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
+	
+	self->netdev->tbusy = 0;
+	
+	/* Enable some interrupts so we can receive frames */
+	switch_bank(iobase, BANK0); 
+	if (speed > 115200) {
+		/* Install FIR xmit handler */
+		dev->hard_start_xmit = nsc_ircc_hard_xmit_fir;
+		outb(IER_SFIF_IE, iobase+IER);
+		nsc_ircc_dma_receive(self);
+	} else {
+		/* Install SIR xmit handler */
+		dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
+		outb(IER_RXHDL_IE, iobase+IER);
+	}
+    	
+	/* Restore BSR */
+	outb(bank, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_hard_xmit (skb, dev)
+ *
+ *    Transmit the frame!
+ *
+ */
+static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct device *dev)
+{
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int iobase;
+	__u32 speed;
+	__u8 bank;
+	
+	self = (struct nsc_ircc_cb *) dev->priv;
+
+	ASSERT(self != NULL, return 0;);
+
+	iobase = self->io.fir_base;
+
+	/* Lock transmit buffer */
+	if (irda_lock((void *) &dev->tbusy) == FALSE)
+		return -EBUSY;
+	
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+	
+	spin_lock_irqsave(&self->lock, flags);
+	
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	self->tx_buff.data = self->tx_buff.head;
+	
+	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
+					   self->tx_buff.truesize);
+
+	self->stats.tx_bytes += self->tx_buff.len;
+	
+	/* Add interrupt on tx low level (will fire immediately) */
+	switch_bank(iobase, BANK0);
+	outb(IER_TXLDL_IE, iobase+IER);
+	
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct device *dev)
+{
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int iobase;
+	__u32 speed;
+	__u8 bank;
+	int mtt, diff;
+	
+	self = (struct nsc_ircc_cb *) dev->priv;
+	iobase = self->io.fir_base;
+
+	/* Lock transmit buffer */
+	if (irda_lock((void *) &dev->tbusy) == FALSE)
+		return -EBUSY;
+
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Register and copy this frame to DMA memory */
+	self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
+	self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
+	self->tx_fifo.tail += skb->len;
+
+	self->stats.tx_bytes += skb->len;
+
+	memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, 
+	       skb->len);
+	
+	self->tx_fifo.len++;
+	self->tx_fifo.free++;
+
+	/* Start transmit only if there is currently no transmit going on */
+	if (self->tx_fifo.len == 1) {
+		/* Check if we must wait the min turn time or not */
+		mtt = irda_get_mtt(skb);
+		if (mtt) {
+			/* Check how much time we have used already */
+			get_fast_time(&self->now);
+			diff = self->now.tv_usec - self->stamp.tv_usec;
+			if (diff < 0) 
+				diff += 1000000;
+			
+			/* Check if the mtt is larger than the time we have
+			 * already used by all the protocol processing
+			 */
+			if (mtt > diff) {
+				mtt -= diff;
+
+				/* 
+				 * Use timer if delay larger than 125 us, and
+				 * use udelay for smaller values which should
+				 * be acceptable
+				 */
+				if (mtt > 125) {
+					/* Adjust for timer resolution */
+					mtt = mtt / 125;
+					
+					/* Setup timer */
+					switch_bank(iobase, BANK4);
+					outb(mtt & 0xff, iobase+TMRL);
+					outb((mtt >> 8) & 0x0f, iobase+TMRH);
+					
+					/* Start timer */
+					outb(IRCR1_TMR_EN, iobase+IRCR1);
+					self->io.direction = IO_XMIT;
+					
+					/* Enable timer interrupt */
+					switch_bank(iobase, BANK0);
+					outb(IER_TMR_IE, iobase+IER);
+					
+					/* Timer will take care of the rest */
+					goto out; 
+				} else
+					udelay(mtt);
+			}
+		}		
+		/* Enable DMA interrupt */
+		switch_bank(iobase, BANK0);
+		outb(IER_DMA_IE, iobase+IER);
+
+		/* Transmit frame */
+		nsc_ircc_dma_xmit(self, iobase);
+	}
+ out:
+	/* Not busy transmitting anymore if window is not full */
+	if (self->tx_fifo.free < MAX_WINDOW)
+		dev->tbusy = 0;
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	spin_unlock_irqrestore(&self->lock, flags);
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_dma_xmit (self, iobase)
+ *
+ *    Transmit data using DMA
+ *
+ */
+static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase)
+{
+	int bsr;
+
+	/* Save current bank */
+	bsr = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+	
+	self->io.direction = IO_XMIT;
+	
+	/* Choose transmit DMA channel  */ 
+	switch_bank(iobase, BANK2);
+	outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
+	
+	setup_dma(self->io.dma, 
+		  self->tx_fifo.queue[self->tx_fifo.ptr].start, 
+		  self->tx_fifo.queue[self->tx_fifo.ptr].len, 
+		  DMA_TX_MODE);
+
+	/* Enable DMA and SIR interaction pulse */
+ 	switch_bank(iobase, BANK0);	
+	outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR);
+
+	/* Restore bank register */
+	outb(bsr, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_pio_xmit (self, iobase)
+ *
+ *    Transmit data using PIO. Returns the number of bytes that actually
+ *    got transfered
+ *
+ */
+static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
+{
+	int actual = 0;
+	__u8 bank;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	switch_bank(iobase, BANK0);
+	if (!(inb_p(iobase+LSR) & LSR_TXEMP)) {
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), warning, FIFO not empty yet!\n");
+
+		/* FIFO may still be filled to the Tx interrupt threshold */
+		fifo_size -= 17;
+	}
+
+	/* Fill FIFO with current frame */
+	while ((fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb(buf[actual++], iobase+TXD);
+	}
+        
+	IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
+		   fifo_size, actual, len);
+	
+	/* Restore bank */
+	outb(bank, iobase+BSR);
+
+	return actual;
+}
+
+/*
+ * Function nsc_ircc_dma_xmit_complete (self)
+ *
+ *    The transfer of a frame in finished. This function will only be called 
+ *    by the interrupt handler
+ *
+ */
+static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self)
+{
+	int iobase;
+	__u8 bank;
+	int ret = TRUE;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	iobase = self->io.fir_base;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+        outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+	
+	/* Check for underrrun! */
+	if (inb(iobase+ASCR) & ASCR_TXUR) {
+		self->stats.tx_errors++;
+		self->stats.tx_fifo_errors++;
+		
+		/* Clear bit, by writing 1 into it */
+		outb(ASCR_TXUR, iobase+ASCR);
+	} else {
+		self->stats.tx_packets++;
+	}
+
+	/* Check if we need to change the speed */
+	if (self->new_speed) {
+		nsc_ircc_change_speed(self, self->new_speed);
+		self->new_speed = 0;
+	}
+
+	/* Finished with this frame, so prepare for next */
+	self->tx_fifo.ptr++;
+	self->tx_fifo.len--;
+
+	/* Any frames to be sent back-to-back? */
+	if (self->tx_fifo.len) {
+		nsc_ircc_dma_xmit(self, iobase);
+		
+		/* Not finished yet! */
+		ret = FALSE;
+	} else {
+		/* Reset Tx FIFO info */
+		self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+		self->tx_fifo.tail = self->tx_buff.head;
+	}
+
+	/* Make sure we have room for more frames */
+	if (self->tx_fifo.free < MAX_WINDOW) {
+		/* Not busy transmitting anymore */
+		self->netdev->tbusy = 0;
+
+		/* Tell the network layer, that we can accept more frames */
+		mark_bh(NET_BH);
+	}
+
+	/* Restore bank */
+	outb(bank, iobase+BSR);
+	
+	return ret;
+}
+
+/*
+ * Function nsc_ircc_dma_receive (self)
+ *
+ *    Get ready for receiving a frame. The device will initiate a DMA
+ *    if it starts to receive a frame.
+ *
+ */
+static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self) 
+{
+	int iobase;
+	__u8 bsr;
+
+	iobase = self->io.fir_base;
+
+	/* Reset Tx FIFO info */
+	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+	self->tx_fifo.tail = self->tx_buff.head;
+
+	/* Save current bank */
+	bsr = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+
+	/* Choose DMA Rx, DMA Fairness, and Advanced mode */
+	switch_bank(iobase, BANK2);
+	outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
+
+	self->io.direction = IO_RECV;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	/* Reset Rx FIFO. This will also flush the ST_FIFO */
+	switch_bank(iobase, BANK0);
+	outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
+
+	self->st_fifo.len = self->st_fifo.pending_bytes = 0;
+	self->st_fifo.tail = self->st_fifo.head = 0;
+	
+	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
+		  DMA_RX_MODE);
+
+	/* Enable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
+
+	/* Restore bank register */
+	outb(bsr, iobase+BSR);
+	
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_dma_receive_complete (self)
+ *
+ *    Finished with receiving frames
+ *
+ *    
+ */
+static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
+{
+	struct st_fifo *st_fifo;
+	struct sk_buff *skb;
+	__u8 status;
+	__u8 bank;
+	int len;
+
+	st_fifo = &self->st_fifo;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	/* Read all entries in status FIFO */
+	switch_bank(iobase, BANK5);
+	while (((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) && 
+	       (st_fifo->tail < MAX_WINDOW))
+	{
+		st_fifo->entries[st_fifo->tail].status = status;
+
+		len = inb(iobase+RFLFL) | (inb(iobase+RFLFH) << 8);
+		
+		st_fifo->entries[st_fifo->tail].len = len;
+		st_fifo->pending_bytes += len;
+		st_fifo->tail++;
+		st_fifo->len++;
+	}
+	/* Try to process all entries in status FIFO */
+	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->pending_bytes -= len;
+		st_fifo->head++;
+		st_fifo->len--;
+
+		/* Check for errors */
+		if (status & FRM_ST_ERR_MSK) {
+			if (status & FRM_ST_LOST_FR) {
+				/* Add number of lost frames to stats */
+				self->stats.rx_errors += len;	
+			} else {
+				/* Skip frame */
+				self->stats.rx_errors++;
+				
+				self->rx_buff.data += len;
+			
+				if (status & FRM_ST_MAX_LEN)
+					self->stats.rx_length_errors++;
+				
+				if (status & FRM_ST_PHY_ERR) 
+					self->stats.rx_frame_errors++;
+				
+				if (status & FRM_ST_BAD_CRC) 
+					self->stats.rx_crc_errors++;
+			}
+			/* The errors below can be reported in both cases */
+			if (status & FRM_ST_OVR1)
+				self->stats.rx_fifo_errors++;		       
+			
+			if (status & FRM_ST_OVR2)
+				self->stats.rx_fifo_errors++;
+		} else {
+			/*  
+			 * First we must make sure that the frame we
+			 * want to deliver is all in main memory. If we
+			 * cannot tell, then we check if the Rx FIFO is
+			 * empty. If not then we will have to take a nap
+			 * and try again later.  
+			 */
+			if (st_fifo->pending_bytes < self->io.fifo_size) {
+				switch_bank(iobase, BANK0);
+				if (inb(iobase+LSR) & LSR_RXDA) {
+					/* Put this entry back in fifo */
+					st_fifo->head--;
+					st_fifo->len++;
+					st_fifo->pending_bytes += len;
+					st_fifo->entries[st_fifo->head].status = status;
+					st_fifo->entries[st_fifo->head].len = len;
+				
+					/* Restore bank register */
+					outb(bank, iobase+BSR);
+					
+					return FALSE; /* I'll be back! */
+				}
+			}
+
+			/* 
+			 * Remember the time we received this frame, so we can
+			 * reduce the min turn time a bit since we will know
+			 * how much time we have used for protocol processing
+			 */
+			get_fast_time(&self->stamp);
+
+			skb = dev_alloc_skb(len+1);
+			if (skb == NULL)  {
+				WARNING(__FUNCTION__ "(), memory squeeze, "
+					"dropping frame.\n");
+				self->stats.rx_dropped++;
+
+				/* Restore bank register */
+				outb(bank, iobase+BSR);
+
+				return FALSE;
+			}
+			
+			/* Make sure IP header gets aligned */
+			skb_reserve(skb, 1); 
+
+			/* Copy frame without CRC */
+			if (self->io.speed < 4000000) {
+				skb_put(skb, len-2);
+				memcpy(skb->data, self->rx_buff.data, len-2);
+			} else {
+				skb_put(skb, len-4);
+				memcpy(skb->data, self->rx_buff.data, len-4);
+			}
+
+			/* Move to next frame */
+			self->rx_buff.data += len;
+			self->stats.rx_bytes += len;
+			self->stats.rx_packets++;
+
+			skb->dev = self->netdev;
+			skb->mac.raw  = skb->data;
+			skb->protocol = htons(ETH_P_IRDA);
+			netif_rx(skb);
+		}
+	}
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	return TRUE;
+}
+
+/*
+ * Function nsc_ircc_pio_receive (self)
+ *
+ *    Receive all data in receiver FIFO
+ *
+ */
+static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self) 
+{
+	__u8 byte;
+	int iobase;
+
+	iobase = self->io.fir_base;
+	
+	/*  Receive all characters in Rx FIFO */
+	do {
+		byte = inb(iobase+RXD);
+		async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
+				  byte);
+	} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */	
+}
+
+/*
+ * Function nsc_ircc_sir_interrupt (self, eir)
+ *
+ *    Handle SIR interrupt
+ *
+ */
+static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
+{
+	int actual;
+
+	/* Check if transmit FIFO is low on data */
+	if (eir & EIR_TXLDL_EV) {
+		/* Write data left in transmit buffer */
+		actual = nsc_ircc_pio_write(self->io.fir_base, 
+					   self->tx_buff.data, 
+					   self->tx_buff.len, 
+					   self->io.fifo_size);
+		self->tx_buff.data += actual;
+		self->tx_buff.len  -= actual;
+		
+		self->io.direction = IO_XMIT;
+
+		/* Check if finished */
+		if (self->tx_buff.len > 0)
+			self->ier = IER_TXLDL_IE;
+		else { 
+			self->netdev->tbusy = 0; /* Unlock */
+			self->stats.tx_packets++;
+			
+		        mark_bh(NET_BH);	
+
+			self->ier = IER_TXEMP_IE;
+		}
+			
+	}
+	/* Check if transmission has completed */
+	if (eir & EIR_TXEMP_EV) {
+		/* Check if we need to change the speed? */
+		if (self->new_speed) {
+			IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n");
+			nsc_ircc_change_speed(self, self->new_speed);
+			self->new_speed = 0;
+
+			/* Check if we are going to FIR */
+			if (self->io.speed > 115200) {
+				/* Should wait for status FIFO interrupt */
+				self->ier = IER_SFIF_IE;
+
+				/* No need to do anymore SIR stuff */
+				return;
+			}
+		}
+		/* Turn around and get ready to receive some data */
+		self->io.direction = IO_RECV;
+		self->ier = IER_RXHDL_IE;
+	}
+
+	/* Rx FIFO threshold or timeout */
+	if (eir & EIR_RXHDL_EV) {
+		nsc_ircc_pio_receive(self);
+
+		/* Keep receiving */
+		self->ier = IER_RXHDL_IE;
+	}
+}
+
+/*
+ * Function nsc_ircc_fir_interrupt (self, eir)
+ *
+ *    Handle MIR/FIR interrupt
+ *
+ */
+static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, 
+				   int eir)
+{
+	__u8 bank;
+
+	bank = inb(iobase+BSR);
+	
+	/* Status event, or end of frame detected in FIFO */
+	if (eir & (EIR_SFIF_EV|EIR_LS_EV)) {
+		if (nsc_ircc_dma_receive_complete(self, iobase)) {
+			/* Wait for next status FIFO interrupt */
+			self->ier = IER_SFIF_IE;
+		} else {
+			/* 
+			 * DMA not finished yet, so try again later, set 
+			 * timer value, resolution 125 us 
+			 */
+			switch_bank(iobase, BANK4);
+			outb(0x01, iobase+TMRL); /* 125 us */
+			outb(0x00, iobase+TMRH);
+
+			/* Start timer */
+			outb(IRCR1_TMR_EN, iobase+IRCR1);
+
+			self->ier = IER_TMR_IE;
+		}
+	} else if (eir & EIR_TMR_EV) { /* Timer finished */
+		/* Disable timer */
+		switch_bank(iobase, BANK4);
+		outb(0, iobase+IRCR1);
+
+		/* Clear timer event */
+		switch_bank(iobase, BANK0);
+		outb(ASCR_CTE, iobase+ASCR);
+
+		/* Check if this is a Tx timer interrupt */
+		if (self->io.direction == IO_XMIT) {
+			nsc_ircc_dma_xmit(self, iobase);
+
+			/*  Interrupt on DMA */
+			self->ier = IER_DMA_IE;
+		} else {
+			/* Check if DMA has now finished */
+			nsc_ircc_dma_receive_complete(self, iobase);
+
+			self->ier = IER_SFIF_IE;
+		}
+	} else if (eir & EIR_DMA_EV) { 
+		/* Finished with all transmissions? */
+		if (nsc_ircc_dma_xmit_complete(self)) {		
+			/* Check if there are more frames to be transmitted */
+			if (irda_device_txqueue_empty(self->netdev)) {
+				/* Prepare for receive */
+				nsc_ircc_dma_receive(self);
+			
+				self->ier = IER_LS_IE|IER_SFIF_IE;
+			}
+		} else {
+			/*  Not finished yet, so interrupt on DMA again */
+			self->ier = IER_DMA_IE;
+		}
+	}
+	outb(bank, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_interrupt (irq, dev_id, regs)
+ *
+ *    An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *) dev_id;
+	struct nsc_ircc_cb *self;
+	__u8 bsr, eir;
+	int iobase;
+
+	if (!dev) {
+		WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
+		return;
+	}
+	self = (struct nsc_ircc_cb *) dev->priv;
+
+	spin_lock(&self->lock);	
+	dev->interrupt = 1;
+
+	iobase = self->io.fir_base;
+
+	bsr = inb(iobase+BSR); 	/* Save current bank */
+
+	switch_bank(iobase, BANK0);	
+	self->ier = inb(iobase+IER); 
+	eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */ 
+
+	outb(0, iobase+IER); /* Disable interrupts */
+	
+	if (eir) {
+		/* Dispatch interrupt handler for the current speed */
+		if (self->io.speed > 115200)
+			nsc_ircc_fir_interrupt(self, iobase, eir);
+		else
+			nsc_ircc_sir_interrupt(self, eir);
+	}
+	
+	outb(self->ier, iobase+IER); /* Restore interrupts */
+	outb(bsr, iobase+BSR);       /* Restore bank register */
+
+	dev->interrupt = 0;
+	spin_unlock(&self->lock);
+}
+
+/*
+ * Function nsc_ircc_is_receiving (self)
+ *
+ *    Return TRUE is we are currently receiving a frame
+ *
+ */
+static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self)
+{
+	unsigned long flags;
+	int status = FALSE;
+	int iobase;
+	__u8 bank;
+
+	ASSERT(self != NULL, return FALSE;);
+
+	spin_lock_irqsave(&self->lock, flags);
+
+	if (self->io.speed > 115200) {
+		iobase = self->io.fir_base;
+
+		/* Check if rx FIFO is not empty */
+		bank = inb(iobase+BSR);
+		switch_bank(iobase, BANK2);
+		if ((inb(iobase+RXFLV) & 0x3f) != 0) {
+			/* We are receiving something */
+			status =  TRUE;
+		}
+		outb(bank, iobase+BSR);
+	} else 
+		status = (self->rx_buff.state != OUTSIDE_FRAME);
+	
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	return status;
+}
+
+/*
+ * Function nsc_ircc_net_init (dev)
+ *
+ *    Initialize network device
+ *
+ */
+static int nsc_ircc_net_init(struct device *dev)
+{
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Setup to be a normal IrDA network device driver */
+	irda_device_setup(dev);
+
+	/* Insert overrides below this line! */
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_open (dev)
+ *
+ *    Start the device
+ *
+ */
+static int nsc_ircc_net_open(struct device *dev)
+{
+	struct nsc_ircc_cb *self;
+	int iobase;
+	__u8 bank;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	
+	ASSERT(dev != NULL, return -1;);
+	self = (struct nsc_ircc_cb *) dev->priv;
+	
+	ASSERT(self != NULL, return 0;);
+	
+	iobase = self->io.fir_base;
+	
+	if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) {
+		WARNING("%s, unable to allocate irq=%d\n", driver_name, 
+			self->io.irq);
+		return -EAGAIN;
+	}
+	/*
+	 * Always allocate the DMA channel after the IRQ, and clean up on 
+	 * failure.
+	 */
+	if (request_dma(self->io.dma, dev->name)) {
+		WARNING("%s, unable to allocate dma=%d\n", driver_name, 
+			self->io.dma);
+		free_irq(self->io.irq, self);
+		return -EAGAIN;
+	}
+	
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	/* turn on interrupts */
+	switch_bank(iobase, BANK0);
+	outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	/* Ready to play! */
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* 
+	 * Open new IrLAP layer instance, now that everything should be
+	 * initialized properly 
+	 */
+	self->irlap = irlap_open(dev, &self->qos);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_close (dev)
+ *
+ *    Stop the device
+ *
+ */
+static int nsc_ircc_net_close(struct device *dev)
+{
+	struct nsc_ircc_cb *self;
+	int iobase;
+	__u8 bank;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	
+	ASSERT(dev != NULL, return -1;);
+
+	self = (struct nsc_ircc_cb *) dev->priv;
+	ASSERT(self != NULL, return 0;);
+
+	/* Stop device */
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
+	
+	iobase = self->io.fir_base;
+
+	disable_dma(self->io.dma);
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable interrupts */
+	switch_bank(iobase, BANK0);
+	outb(0, iobase+IER); 
+       
+	free_irq(self->io.irq, dev);
+	free_dma(self->io.dma);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+static int nsc_ircc_net_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		nsc_ircc_change_speed(self, irq->ifr_baudrate);
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = nsc_ircc_is_receiving(self);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
+
+static struct net_device_stats *nsc_ircc_net_get_stats(struct device *dev)
+{
+	struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv;
+	
+	return &self->stats;
+}
+
+#ifdef CONFIG_APM
+static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
+{
+	MESSAGE("%s, Suspending\n", driver_name);
+
+	if (self->io.suspended)
+		return;
+
+	nsc_ircc_net_close(self->netdev);
+
+	self->io.suspended = 1;
+}
+
+static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
+{
+	struct device *dev = self->netdev;
+	int iobase;
+
+	if (!self->io.suspended)
+		return;
+
+	iobase = self->io.fir_base;
+
+	/* Switch to advanced mode */
+	switch_bank(iobase, BANK2);
+	outb(ECR1_EXT_SL, iobase+ECR1);
+	switch_bank(iobase, BANK0);
+
+	nsc_ircc_net_open(self->netdev);
+	
+	MESSAGE("%s, Waking up\n", driver_name);
+
+	self->io.suspended = 0;
+}
+
+static int nsc_ircc_apmproc(apm_event_t event)
+{
+	static int down = 0; /* Filter out double events */
+	int i;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (!down) {			
+			for (i=0; i<4; i++) {
+				if (dev_self[i])
+					nsc_ircc_suspend(dev_self[i]);
+			}
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (down) {
+			for (i=0; i<4; i++) {
+				if (dev_self[i])
+					nsc_ircc_wakeup(dev_self[i]);
+			}
+		}
+		down = 0;
+		break;
+	}
+	return 0;
+}
+#endif /* CONFIG_APM */
+
+#ifdef MODULE
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("NSC IrDA Device Driver");
+
+MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM(io,  "1-4i");
+MODULE_PARM(irq, "1-4i");
+MODULE_PARM(dma, "1-4i");
+MODULE_PARM(dongle_id, "i");
+
+int init_module(void)
+{
+	return nsc_ircc_init();
+}
+
+void cleanup_module(void)
+{
+	nsc_ircc_cleanup();
+}
+#endif /* MODULE */
+
diff -urN linux-2.2.15-pre2/drivers/net/irda/nsc_fir.c linux/drivers/net/irda/nsc_fir.c
--- linux-2.2.15-pre2/drivers/net/irda/nsc_fir.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/nsc_fir.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1856 @@
+/*********************************************************************
+ *                
+ * Filename:      nsc_fir.c
+ * Version:       1.0
+ * Description:   Driver for the NSC PC'108 and PC'338 IrDA chipsets
+ * Status:        Stable.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sat Nov  7 21:43:15 1998
+ * Modified at:   Tue Jan 11 10:17:04 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1998-2000 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
+ *      
+ *     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 that all functions that needs to access the chip in _any_
+ *     way, must save BSR register on entry, and restore it on exit. 
+ *     It is _very_ important to follow this policy!
+ *
+ *         __u8 bank;
+ *     
+ *         bank = inb(iobase+BSR);
+ *  
+ *         do_your_stuff_here();
+ *
+ *         outb(bank, iobase+BSR);
+ *
+ *    If you find bugs in this file, its very likely that the same bug
+ *    will also be in w83977af_ir.c since the implementations are quite
+ *    similar.
+ *     
+ ********************************************************************/
+
+#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/rtnetlink.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
+#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/nsc_ircc.h>
+
+#define CHIP_IO_EXTENT 8
+#define BROKEN_DONGLE_ID
+
+/* 
+ * Define if you have multiple NSC IrDA controllers in your machine. Not
+ * enabled by default since some single chips detects at multiple addresses
+ */
+#undef  CONFIG_NSC_IRCC_MULTIPLE 
+
+static char *driver_name = "nsc_ircc";
+
+/* Module parameters */
+static int qos_mtt_bits = 0x07;  /* 1 ms or more */
+static int dongle_id = 0;
+
+static unsigned int io[]  = { 0x2f8, 0x2f8, 0x2f8, 0x2f8, 0x2f8 };
+static unsigned int io2[] = { 0x150, 0x398, 0xea, 0x15c, 0x2e };
+static unsigned int irq[] = { 3, 3, 3, 3, 3 };
+static unsigned int dma[] = { 0, 0, 0, 0, 3 };
+
+static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
+
+static char *dongle_types[] = {
+	"Differential serial interface",
+	"Differential serial interface",
+	"Reserved",
+	"Reserved",
+	"Sharp RY5HD01",
+	"Reserved",
+	"Single-ended serial interface",
+	"Consumer-IR only",
+	"HP HSDL-2300, HP HSDL-3600/HSDL-3610",
+	"IBM31T1100 or Temic TFDS6000/TFDS6500",
+	"Reserved",
+	"Reserved",
+	"HP HSDL-1100/HSDL-2100",
+	"HP HSDL-1100/HSDL-2100"
+	"Supports SIR Mode only",
+	"No dongle connected",
+};
+
+/* Some prototypes */
+static int  nsc_ircc_open(int i, unsigned int iobase, unsigned int board_addr, 
+			 unsigned int irq, unsigned int dma);
+#ifdef MODULE
+static int  nsc_ircc_close(struct nsc_ircc_cb *self);
+#endif /* MODULE */
+static int  nsc_ircc_probe(int iobase, int board_addr, int irq, int dma);
+static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
+static int  nsc_ircc_dma_receive(struct nsc_ircc_cb *self); 
+static int  nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase);
+static int  nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct device *dev);
+static int  nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct device *dev);
+static int  nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase);
+static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud);
+static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int  nsc_ircc_is_receiving(struct nsc_ircc_cb *self);
+static int  nsc_ircc_read_dongle_id (int iobase);
+static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id);
+
+static int  nsc_ircc_net_init(struct device *dev);
+static int  nsc_ircc_net_open(struct device *dev);
+static int  nsc_ircc_net_close(struct device *dev);
+static int  nsc_ircc_net_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *nsc_ircc_net_get_stats(struct device *dev);
+#ifdef CONFIG_APM
+static int nsc_ircc_apmproc(apm_event_t event);
+#endif /* CONFIG_APM */
+/*
+ * Function nsc_ircc_init ()
+ *
+ *    Initialize chip. Just try to find out how many chips we are dealing with
+ *    and where they are
+ */
+int __init nsc_ircc_init(void)
+{
+	int ret = -ENODEV;
+	int ioaddr;
+	int i;
+
+#ifdef CONFIG_APM
+	apm_register_callback(nsc_ircc_apmproc);
+#endif /* CONFIG_APM */
+
+	for (i=0; (io[i] < 2000) && (i < 5); i++) {
+		ioaddr = io[i];
+		if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
+			continue;
+		if (nsc_ircc_open(i, io[i], io2[i], irq[i], dma[i]) == 0)
+		{
+#ifdef CONFIG_NSC_IRCC_MULTIPLE
+			ret = 0;
+#else
+		        return 0;
+#endif
+		}
+	}
+	return ret;
+}
+
+/*
+ * Function nsc_ircc_cleanup ()
+ *
+ *    Close all configured chips
+ *
+ */
+#ifdef MODULE
+static void nsc_ircc_cleanup(void)
+{
+	int i;
+
+        IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+#ifdef CONFIG_APM
+	apm_unregister_callback(nsc_ircc_apmproc);
+#endif /* CONFIG_APM */
+
+
+	for (i=0; i < 5; i++) {
+		if (dev_self[i])
+			nsc_ircc_close(dev_self[i]);
+	}
+}
+#endif /* MODULE */
+
+/*
+ * Function nsc_ircc_open (iobase, irq)
+ *
+ *    Open driver instance
+ *
+ */
+static int 
+nsc_ircc_open(int i, unsigned int iobase, unsigned int board_addr, 
+	     unsigned int irq, unsigned int dma)
+{
+	struct device *dev;
+	struct nsc_ircc_cb *self;
+	int dongle_id;
+	int ret;
+	int err;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if ((dongle_id = nsc_ircc_probe(iobase, board_addr, irq, dma)) == -1)
+		return -1;
+
+	/*
+	 *  Allocate new instance of the driver
+	 */
+	self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL);
+	if (self == NULL) {
+		ERROR(__FUNCTION__ "(), can't allocate memory for "
+		       "control block!\n");
+		return -ENOMEM;
+	}
+	memset(self, 0, sizeof(struct nsc_ircc_cb));
+	spin_lock_init(&self->lock);
+   
+	/* Need to store self somewhere */
+	dev_self[i] = self;
+
+	/* Initialize IO */
+	self->io.iobase    = iobase;
+        self->io.irq       = irq;
+        self->io.io_ext    = CHIP_IO_EXTENT;
+        self->io.dma       = dma;
+        self->io.fifo_size = 32;
+
+	/* Lock the port that we need */
+	ret = check_region(self->io.iobase, self->io.io_ext);
+	if (ret < 0) { 
+		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+		      self->io.iobase);
+		/* nsc_ircc_cleanup(self->self);  */
+		return -ENODEV;
+	}
+	request_region(self->io.iobase, self->io.io_ext, driver_name);
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&self->qos);
+	
+	/* The only value we must override it the baudrate */
+	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+		IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8);
+	
+	self->qos.min_turn_time.bits = qos_mtt_bits;
+	irda_qos_bits_to_value(&self->qos);
+	
+	self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
+
+	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+	self->rx_buff.truesize = 14384; 
+	self->tx_buff.truesize = 14384;
+
+	/* Allocate memory if needed */
+	self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
+					      GFP_KERNEL|GFP_DMA);
+	if (self->rx_buff.head == NULL)
+		return -ENOMEM;
+	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+	
+	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+					      GFP_KERNEL|GFP_DMA);
+	if (self->tx_buff.head == NULL) {
+		kfree(self->rx_buff.head);
+		return -ENOMEM;
+	}
+	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+
+	self->rx_buff.in_frame = FALSE;
+	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	/* Reset Tx queue info */
+	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+	self->tx_fifo.tail = self->tx_buff.head;
+
+	if (!(dev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return -ENOMEM;
+	}
+	/* dev_alloc doesn't clear the struct, so lets do a little hack */
+	memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct device)-sizeof(char*));
+
+	dev->priv = (void *) self;
+	self->netdev = dev;
+
+	/* Override the network functions we need to use */
+	dev->init            = nsc_ircc_net_init;
+	dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
+	dev->open            = nsc_ircc_net_open;
+	dev->stop            = nsc_ircc_net_close;
+	dev->do_ioctl        = nsc_ircc_net_ioctl;
+	dev->get_stats	     = nsc_ircc_net_get_stats;
+
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return -1;
+	}
+
+	MESSAGE("IrDA: Registered device %s\n", dev->name);
+	
+	self->io.dongle_id = dongle_id;
+	nsc_ircc_init_dongle_interface(iobase, dongle_id);
+
+	return 0;
+}
+
+#ifdef MODULE
+/*
+ * Function nsc_ircc_close (self)
+ *
+ *    Close driver instance
+ *
+ */
+static int nsc_ircc_close(struct nsc_ircc_cb *self)
+{
+	int iobase;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+
+        iobase = self->io.iobase;
+
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		rtnl_unlock();
+		/* Must free the old-style 2.2.x device */
+		kfree(self->netdev);
+	}
+
+	/* Release the PORT that this driver is using */
+	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", 
+		   self->io.iobase);
+	release_region(self->io.iobase, self->io.io_ext);
+
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
+
+	kfree(self);
+
+	return 0;
+}
+#endif /* MODULE */
+
+/*
+ * Function nsc_ircc_init_807 (iobase, board_addr, irq, dma)
+ *
+ *    Initialize the NSC '108 chip
+ *
+ */
+static void nsc_ircc_init_807(int iobase, int board_addr, int irq, int dma)
+{
+	__u8 temp=0;
+
+	outb(2, board_addr);      /* Mode Control Register (MCTL) */
+	outb(0x00, board_addr+1); /* Disable device */
+	
+	/* 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: ERROR(__FUNCTION__ "(), invalid base_address");
+	}
+	
+	/* Control Signal Routing Register (CSRT) */
+	switch (irq) {
+	case 3:  temp = 0x01; break;
+	case 4:  temp = 0x02; break;
+	case 5:  temp = 0x03; break;
+	case 7:  temp = 0x04; break;
+	case 9:  temp = 0x05; break;
+	case 11: temp = 0x06; break;
+	case 15: temp = 0x07; break;
+	default: ERROR(__FUNCTION__ "(), invalid irq");
+	}
+	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;
+	default: ERROR(__FUNCTION__ "(), invalid dma");
+	}
+	
+	outb(2, board_addr);      /* Mode Control Register (MCTL) */
+	outb(0x03, board_addr+1); /* Enable device */
+}
+
+/*
+ * Function nsc_ircc_init_338 (iobase, board_addr, irq, dma)
+ *
+ *    Initialize the NSC '338 chip. Remember that the 87338 needs two 
+ *    consecutive writes to the data registers while CPU interrupts are
+ *    disabled. The 97338 does not require this, but shouldn't be any
+ *    harm if we do it anyway.
+ */
+static void nsc_ircc_init_338(int iobase, int board_addr, int irq, int dma)
+{
+	/* No init yet */
+}
+
+static int nsc_ircc_find_chip(int board_addr)
+{
+	__u8 index, id;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Read index register */
+	index = inb(board_addr);
+	if (index == 0xff) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), no chip at 0x%03x\n", 
+			   board_addr);
+		return -1;
+	}
+
+	/* Read chip identification register (SID) for the PC97338 */
+	outb(8, board_addr);
+	id = inb(board_addr+1);
+	if ((id & 0xf0) == PC97338) {
+		MESSAGE("%s, Found NSC PC97338 chip, revision=%d\n", 
+			driver_name, id & 0x0f);
+		return PC97338;		
+	} 
+
+	/* Read device identification (DID) for the PC87108 */
+	outb(5, board_addr);
+	id = inb(board_addr+1);
+	if ((id & 0xf0) == PC87108) {
+		MESSAGE("%s, Found NSC PC87108 chip, revision=%d\n", 
+			driver_name, id & 0x0f);
+		return PC87108;
+	}
+
+	return -1;
+}
+
+/*
+ * Function nsc_ircc_probe (iobase, board_addr, irq, dma)
+ *
+ *    Returns non-negative on success.
+ *
+ */
+static int nsc_ircc_probe(int iobase, int board_addr, int irq, int dma)
+{
+	int version;
+	__u8 chip;
+
+	chip = nsc_ircc_find_chip(board_addr);
+	switch (chip) {
+	case PC87108:
+		nsc_ircc_init_807(iobase, board_addr, irq, dma);
+		break;
+	case PC97338:
+		nsc_ircc_init_338(iobase, board_addr, irq, dma);
+		break;
+	default:
+		/* Found no chip */
+		return -1;
+	}
+
+	/* Read the Module ID */
+	switch_bank(iobase, BANK3);
+	version = inb(iobase+MID);
+
+	/* Should be 0x2? */
+	if (0x20 != (version & 0xf0)) {
+		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
+		return -1;
+	}
+	MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, board_addr);
+
+	/* Switch to advanced mode */
+	switch_bank(iobase, BANK2);
+	outb(ECR1_EXT_SL, iobase+ECR1);
+	switch_bank(iobase, BANK0);
+
+	/* Check if user has supplied the dongle id or not */
+	if (!dongle_id) {
+		dongle_id = nsc_ircc_read_dongle_id(iobase);
+		
+		MESSAGE("%s, Found dongle: %s\n", driver_name,
+			dongle_types[dongle_id]);
+	} else {
+		MESSAGE("%s, Using dongle: %s\n", driver_name,
+			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);
+	
+	/* Set FIFO size to 32 */
+	switch_bank(iobase, BANK2);
+	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
+
+	/* IRCR2: FEND_MD is set */
+	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 */
+
+	MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
+
+	/* Enable receive interrupts */
+	switch_bank(iobase, BANK0);
+	outb(IER_RXHDL_IE, iobase+IER);
+
+	return dongle_id;
+}
+
+/*
+ * Function nsc_ircc_read_dongle_id (void)
+ *
+ * Try to read dongle indentification. This procedure needs to be executed
+ * once after power-on/reset. It also needs to be used whenever you suspect
+ * that the user may have plugged/unplugged the IrDA Dongle.
+ * 
+ */
+static int nsc_ircc_read_dongle_id (int iobase)
+{
+	int dongle_id;
+	__u8 bank;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
+	outb(0x00, iobase+7);
+	
+	/* ID0, 1, and 2 are pulled up/down very slowly */
+	udelay(50);
+	
+	/* IRCFG1: read the ID bits */
+	dongle_id = inb(iobase+4) & 0x0f;
+
+#ifdef BROKEN_DONGLE_ID
+	if (dongle_id == 0x0a)
+		dongle_id = 0x09;
+#endif
+	
+	/* Go back to  bank 0 before returning */
+	switch_bank(iobase, BANK0);
+
+	outb(bank, iobase+BSR);
+
+	return dongle_id;
+}
+
+/*
+ * Function nsc_ircc_init_dongle_interface (iobase, dongle_id)
+ *
+ *     This function initializes the dongle for the transceiver that is
+ *     used. This procedure needs to be executed once after
+ *     power-on/reset. It also needs to be used whenever you suspect that
+ *     the dongle is changed. 
+ */
+static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id)
+{
+	int bank;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG4: set according to dongle_id */
+	switch (dongle_id) {
+	case 0x00: /* same as */
+	case 0x01: /* Differential serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x02: /* same as */
+	case 0x03: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x04: /* Sharp RY5HD01 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x05: /* Reserved, but this is what the Thinkpad reports */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x06: /* Single-ended serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x07: /* Consumer-IR only */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
+		outb_p(0x28, iobase+7); /* Set irsl[0-2] as output */
+		break;
+	case 0x0A: /* same as */
+	case 0x0B: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x0C: /* same as */
+	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
+		/* 
+		 * Set irsl0 as input, irsl[1-2] as output, and separate 
+		 * inputs are used for SIR and MIR/FIR 
+		 */
+		outb(0x48, iobase+7); 
+		break;
+	case 0x0E: /* Supports SIR Mode only */
+		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
+		break;
+	case 0x0F: /* No dongle connected */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
+			   dongle_types[dongle_id]); 
+
+		switch_bank(iobase, BANK0);
+		outb(0x62, iobase+MCR);
+		break;
+	default: 
+		IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", 
+			   dongle_id);
+	}
+	
+	/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
+	outb(0x00, iobase+4);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+	
+} /* set_up_dongle_interface */
+
+/*
+ * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id)
+ *
+ *    Change speed of the attach dongle
+ *
+ */
+static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id)
+{
+	unsigned long flags;
+	__u8 bank;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG1: set according to dongle_id */
+	switch (dongle_id) {
+	case 0x00: /* same as */
+	case 0x01: /* Differential serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x02: /* same as */
+	case 0x03: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x04: /* Sharp RY5HD01 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+			   dongle_types[dongle_id]); 
+	case 0x05: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x06: /* Single-ended serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x07: /* Consumer-IR only */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+			   dongle_types[dongle_id]); 
+	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
+		switch_bank(iobase, BANK7);
+		outb_p(0x01, iobase+4);
+
+		if (speed == 4000000) {
+			save_flags(flags);
+			cli();
+			outb(0x81, iobase+4);
+			outb(0x80, iobase+4);
+			restore_flags(flags);
+		} else
+			outb_p(0x00, iobase+4);
+		break;
+	case 0x0A: /* same as */
+	case 0x0B: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x0C: /* same as */
+	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
+		break;
+	case 0x0E: /* Supports SIR Mode only */
+		break;
+	case 0x0F: /* No dongle connected */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]);
+
+		switch_bank(iobase, BANK0); 
+		outb(0x62, iobase+MCR);
+		break;
+	default: 
+		IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n");
+	}
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_change_speed (self, baud)
+ *
+ *    Change the speed of the device
+ *
+ */
+static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
+{
+	struct device *dev = self->netdev;
+	__u8 mcr = MCR_SIR;
+	int iobase; 
+	__u8 bank;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed);
+
+	ASSERT(self != NULL, return;);
+
+	iobase = self->io.iobase;
+
+	/* Update accounting for new speed */
+	self->io.speed = speed;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable interrupts */
+	switch_bank(iobase, BANK0);
+	outb(0, iobase+IER);
+
+	/* Select Bank 2 */
+	switch_bank(iobase, BANK2);
+
+	outb(0x00, iobase+BGDH);
+	switch (speed) {
+	case 9600:   outb(0x0c, iobase+BGDL); break;
+	case 19200:  outb(0x06, iobase+BGDL); break;
+	case 38400:  outb(0x03, iobase+BGDL); break;
+	case 57600:  outb(0x02, iobase+BGDL); break;
+	case 115200: outb(0x01, iobase+BGDL); break;
+	case 576000:
+		switch_bank(iobase, BANK5);
+		
+		/* IRCR2: MDRS is set */
+		outb(inb(iobase+4) | 0x04, iobase+4);
+	       
+		mcr = MCR_MIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
+		break;
+	case 1152000:
+		mcr = MCR_MIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
+		break;
+	case 4000000:
+		mcr = MCR_FIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
+		break;
+	default:
+		mcr = MCR_FIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 
+			   speed);
+		break;
+	}
+
+	/* Set appropriate speed mode */
+	switch_bank(iobase, BANK0);
+	outb(mcr | MCR_TX_DFR, iobase+MCR);
+
+	/* Give some hits to the transceiver */
+	nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id);
+
+	/* Set FIFO threshold to TX17, RX16 */
+	switch_bank(iobase, BANK0);
+	outb(0x00, iobase+FCR);
+	outb(FCR_FIFO_EN, iobase+FCR);
+	outb(FCR_RXTH|     /* Set Rx FIFO threshold */
+	     FCR_TXTH|     /* Set Tx FIFO threshold */
+	     FCR_TXSR|     /* Reset Tx FIFO */
+	     FCR_RXSR|     /* Reset Rx FIFO */
+	     FCR_FIFO_EN,  /* Enable FIFOs */
+	     iobase+FCR);
+	
+	/* Set FIFO size to 32 */
+	switch_bank(iobase, BANK2);
+	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
+	
+	self->netdev->tbusy = 0;
+	
+	/* Enable some interrupts so we can receive frames */
+	switch_bank(iobase, BANK0); 
+	if (speed > 115200) {
+		/* Install FIR xmit handler */
+		dev->hard_start_xmit = nsc_ircc_hard_xmit_fir;
+		outb(IER_SFIF_IE, iobase+IER);
+		nsc_ircc_dma_receive(self);
+	} else {
+		/* Install SIR xmit handler */
+		dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
+		outb(IER_RXHDL_IE, iobase+IER);
+	}
+    	
+	/* Restore BSR */
+	outb(bank, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_hard_xmit (skb, dev)
+ *
+ *    Transmit the frame!
+ *
+ */
+static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct device *dev)
+{
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int iobase;
+	__u32 speed;
+	__u8 bank;
+	
+	self = (struct nsc_ircc_cb *) dev->priv;
+
+	ASSERT(self != NULL, return 0;);
+
+	iobase = self->io.iobase;
+
+	/* Lock transmit buffer */
+	if (irda_lock((void *) &dev->tbusy) == FALSE)
+		return -EBUSY;
+	
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+	
+	spin_lock_irqsave(&self->lock, flags);
+	
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	self->tx_buff.data = self->tx_buff.head;
+	
+	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
+					   self->tx_buff.truesize);
+	
+	/* Add interrupt on tx low level (will fire immediately) */
+	switch_bank(iobase, BANK0);
+	outb(IER_TXLDL_IE, iobase+IER);
+	
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct device *dev)
+{
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int iobase;
+	__u32 speed;
+	__u8 bank;
+	int mtt, diff;
+	
+	self = (struct nsc_ircc_cb *) dev->priv;
+
+	ASSERT(self != NULL, return 0;);
+
+	iobase = self->io.iobase;
+
+	/* Lock transmit buffer */
+	if (irda_lock((void *) &dev->tbusy) == FALSE)
+		return -EBUSY;
+
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Register and copy this frame to DMA memory */
+	self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
+	self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
+	self->tx_fifo.tail += skb->len;
+
+	memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, 
+	       skb->len);
+	
+	self->tx_fifo.len++;
+	self->tx_fifo.free++;
+
+	/* Start transmit only if there is currently no transmit going on */
+	if (self->tx_fifo.len == 1) {
+		/* Check if we must wait the min turn time or not */
+		mtt = irda_get_mtt(skb);
+		if (mtt) {
+			/* Check how much time we have used already */
+			get_fast_time(&self->now);
+			diff = self->now.tv_usec - self->stamp.tv_usec;
+			if (diff < 0) 
+				diff += 1000000;
+			
+			/* Check if the mtt is larger than the time we have
+			 * already used by all the protocol processing
+			 */
+			if (mtt > diff) {
+				mtt -= diff;
+
+				/* 
+				 * Use timer if delay larger than 125 us, and
+				 * use udelay for smaller values which should
+				 * be acceptable
+				 */
+				if (mtt > 125) {
+					/* Adjust for timer resolution */
+					mtt = mtt / 125;
+					
+					/* Setup timer */
+					switch_bank(iobase, BANK4);
+					outb(mtt & 0xff, iobase+TMRL);
+					outb((mtt >> 8) & 0x0f, iobase+TMRH);
+					
+					/* Start timer */
+					outb(IRCR1_TMR_EN, iobase+IRCR1);
+					self->io.direction = IO_XMIT;
+					
+					/* Enable timer interrupt */
+					switch_bank(iobase, BANK0);
+					outb(IER_TMR_IE, iobase+IER);
+					
+					/* Timer will take care of the rest */
+					goto out; 
+				} else
+					udelay(mtt);
+			}
+		}		
+		/* Enable DMA interrupt */
+		switch_bank(iobase, BANK0);
+		outb(IER_DMA_IE, iobase+IER);
+
+		/* Transmit frame */
+		nsc_ircc_dma_xmit(self, iobase);
+	}
+ out:
+	/* Not busy transmitting anymore if window is not full */
+	if (self->tx_fifo.free < MAX_WINDOW)
+		dev->tbusy = 0;
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_dma_xmit (self, iobase)
+ *
+ *    Transmit data using DMA
+ *
+ */
+static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase)
+{
+	int bsr;
+
+	/* Save current bank */
+	bsr = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+	
+	self->io.direction = IO_XMIT;
+	
+	/* Choose transmit DMA channel  */ 
+	switch_bank(iobase, BANK2);
+	outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
+	
+	setup_dma(self->io.dma, 
+		  self->tx_fifo.queue[self->tx_fifo.ptr].start, 
+		  self->tx_fifo.queue[self->tx_fifo.ptr].len, 
+		  DMA_TX_MODE);
+
+	/* Enable DMA and SIR interaction pulse */
+ 	switch_bank(iobase, BANK0);	
+	outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR);
+
+	/* Restore bank register */
+	outb(bsr, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_pio_xmit (self, iobase)
+ *
+ *    Transmit data using PIO. Returns the number of bytes that actually
+ *    got transfered
+ *
+ */
+static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
+{
+	int actual = 0;
+	__u8 bank;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	switch_bank(iobase, BANK0);
+	if (!(inb_p(iobase+LSR) & LSR_TXEMP)) {
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), warning, FIFO not empty yet!\n");
+
+		fifo_size -= 17;
+	}
+
+	/* Fill FIFO with current frame */
+	while ((fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb(buf[actual++], iobase+TXD);
+	}
+        
+	IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
+		   fifo_size, actual, len);
+	
+	/* Restore bank */
+	outb(bank, iobase+BSR);
+
+	return actual;
+}
+
+/*
+ * Function nsc_ircc_dma_xmit_complete (self)
+ *
+ *    The transfer of a frame in finished. This function will only be called 
+ *    by the interrupt handler
+ *
+ */
+static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self)
+{
+	int iobase;
+	__u8 bank;
+	int ret = TRUE;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	iobase = self->io.iobase;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+        outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+	
+	/* Check for underrrun! */
+	if (inb(iobase+ASCR) & ASCR_TXUR) {
+		self->stats.tx_errors++;
+		self->stats.tx_fifo_errors++;
+		
+		/* Clear bit, by writing 1 into it */
+		outb(ASCR_TXUR, iobase+ASCR);
+	} else {
+		self->stats.tx_packets++;
+		self->stats.tx_bytes += self->tx_buff.len;
+	}
+	
+	if (self->new_speed) {
+		nsc_ircc_change_speed(self, self->new_speed);
+		self->new_speed = 0;
+	}
+
+	/* Finished with this frame, so prepare for next */
+	self->tx_fifo.ptr++;
+	self->tx_fifo.len--;
+
+	/* Any frames to be sent back-to-back? */
+	if (self->tx_fifo.len) {
+		nsc_ircc_dma_xmit(self, iobase);
+		
+		/* Not finished yet! */
+		ret = FALSE;
+	} else {
+		/* Reset Tx FIFO info */
+		self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+		self->tx_fifo.tail = self->tx_buff.head;
+	}
+
+	/* Make sure we have room for more frames */
+	if (self->tx_fifo.free < MAX_WINDOW) {
+		/* Not busy transmitting anymore */
+		self->netdev->tbusy = 0;
+
+		/* Tell the network layer, that we can accept more frames */
+		mark_bh(NET_BH);
+	}
+
+	/* Restore bank */
+	outb(bank, iobase+BSR);
+	
+	return ret;
+}
+
+/*
+ * Function nsc_ircc_dma_receive (self)
+ *
+ *    Get ready for receiving a frame. The device will initiate a DMA
+ *    if it starts to receive a frame.
+ *
+ */
+static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self) 
+{
+	int iobase;
+	__u8 bsr;
+
+	ASSERT(self != NULL, return -1;);
+
+	iobase = self->io.iobase;
+
+	/* Reset Tx FIFO info */
+	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+	self->tx_fifo.tail = self->tx_buff.head;
+
+	/* Save current bank */
+	bsr = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+
+	/* Choose DMA Rx, DMA Fairness, and Advanced mode */
+	switch_bank(iobase, BANK2);
+	outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
+
+	self->io.direction = IO_RECV;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	/* Reset Rx FIFO. This will also flush the ST_FIFO */
+	switch_bank(iobase, BANK0);
+	outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
+	self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0;
+	
+	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
+		  DMA_RX_MODE);
+
+	/* Enable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
+
+	/* Restore bank register */
+	outb(bsr, iobase+BSR);
+	
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_dma_receive_complete (self)
+ *
+ *    Finished with receiving frames
+ *
+ *    
+ */
+static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
+{
+	struct sk_buff *skb;
+	struct st_fifo *st_fifo;
+	__u8 bank;
+	__u8 status;
+	int len;
+
+	st_fifo = &self->st_fifo;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	/* Read status FIFO */
+	switch_bank(iobase, BANK5);
+	while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) {
+		st_fifo->entries[st_fifo->tail].status = status;
+
+		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++;
+	}
+	/* Try to process all entries in status FIFO */
+	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--;
+
+		/* Check for errors */
+		if (status & FRM_ST_ERR_MSK) {
+			if (status & FRM_ST_LOST_FR) {
+				/* Add number of lost frames to stats */
+				self->stats.rx_errors += len;	
+			} else {
+				/* Skip frame */
+				self->stats.rx_errors++;
+				
+				self->rx_buff.data += len;
+			
+				if (status & FRM_ST_MAX_LEN)
+					self->stats.rx_length_errors++;
+				
+				if (status & FRM_ST_PHY_ERR) 
+					self->stats.rx_frame_errors++;
+				
+				if (status & FRM_ST_BAD_CRC) 
+					self->stats.rx_crc_errors++;
+			}
+			/* The errors below can be reported in both cases */
+			if (status & FRM_ST_OVR1)
+				self->stats.rx_fifo_errors++;		       
+			
+			if (status & FRM_ST_OVR2)
+				self->stats.rx_fifo_errors++;
+		} else {
+			/* Check if we have transfered all data to memory */
+			switch_bank(iobase, BANK0);
+			if (inb(iobase+LSR) & LSR_RXDA) {
+				/* Put this entry back in fifo */
+				st_fifo->head--;
+				st_fifo->len++;
+				st_fifo->entries[st_fifo->head].status = status;
+				st_fifo->entries[st_fifo->head].len = len;
+				
+				/* Restore bank register */
+				outb(bank, iobase+BSR);
+				
+				return FALSE; 	/* I'll be back! */
+			}
+
+			/* 
+			 * Remember when we received this frame, so we can
+			 * reduce the min turn time a bit since we will know
+			 * how much time we have used for protocol processing
+			 */
+			get_fast_time(&self->stamp);
+
+			skb = dev_alloc_skb(len+1);
+			if (skb == NULL)  {
+				WARNING(__FUNCTION__ "(), memory squeeze, "
+					"dropping frame.\n");
+				
+				/* Restore bank register */
+				outb(bank, iobase+BSR);
+				
+				return FALSE;
+			}
+			
+			/* Make sure IP header gets aligned */
+			skb_reserve(skb, 1); 
+
+			/* Copy frame without CRC */
+			if (self->io.speed < 4000000) {
+				skb_put(skb, len-2);
+				memcpy(skb->data, self->rx_buff.data, len-2);
+			} else {
+				skb_put(skb, len-4);
+				memcpy(skb->data, self->rx_buff.data, len-4);
+			}
+
+			/* Move to next frame */
+			self->rx_buff.data += len;
+			self->stats.rx_packets++;
+
+			skb->dev = self->netdev;
+			skb->mac.raw  = skb->data;
+			skb->protocol = htons(ETH_P_IRDA);
+			netif_rx(skb);
+		}
+	}
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	return TRUE;
+}
+
+/*
+ * Function nsc_ircc_pio_receive (self)
+ *
+ *    Receive all data in receiver FIFO
+ *
+ */
+static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self) 
+{
+	__u8 byte = 0x00;
+	int iobase;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	
+	iobase = self->io.iobase;
+	
+	/*  Receive all characters in Rx FIFO */
+	do {
+		byte = inb(iobase+RXD);
+		async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
+				  byte);
+	} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */	
+}
+
+/*
+ * Function nsc_ircc_sir_interrupt (self, eir)
+ *
+ *    Handle SIR interrupt
+ *
+ */
+static __u8 nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
+{
+	int actual;
+	__u8 new_ier = 0;
+
+	/* Check if transmit FIFO is low on data */
+	if (eir & EIR_TXLDL_EV) {
+		/* Write data left in transmit buffer */
+		actual = nsc_ircc_pio_write(self->io.iobase, 
+					   self->tx_buff.data, 
+					   self->tx_buff.len, 
+					   self->io.fifo_size);
+		self->tx_buff.data += actual;
+		self->tx_buff.len  -= actual;
+		
+		self->io.direction = IO_XMIT;
+
+		/* Check if finished */
+		if (self->tx_buff.len > 0)
+			new_ier |= IER_TXLDL_IE;
+		else { 
+			self->netdev->tbusy = 0; /* Unlock */
+			self->stats.tx_packets++;
+			
+		        mark_bh(NET_BH);	
+
+			new_ier |= IER_TXEMP_IE;
+		}
+			
+	}
+	/* Check if transmission has completed */
+	if (eir & EIR_TXEMP_EV) {
+		/* Check if we need to change the speed? */
+		if (self->new_speed) {
+			IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n");
+			nsc_ircc_change_speed(self, self->new_speed);
+			self->new_speed = 0;
+
+			/* Check if we are going to FIR */
+			if (self->io.speed > 115200) {
+				/* Should wait for status FIFO interrupt */
+				new_ier = IER_SFIF_IE;
+
+				/* No need to do anymore SIR stuff */
+				return;
+			}
+		}
+
+		/* Turn around and get ready to receive some data */
+		self->io.direction = IO_RECV;
+		new_ier |= IER_RXHDL_IE;
+	}
+
+	/* Rx FIFO threshold or timeout */
+	if (eir & EIR_RXHDL_EV) {
+		nsc_ircc_pio_receive(self);
+
+		/* Keep receiving */
+		new_ier |= IER_RXHDL_IE;
+	}
+	return new_ier;
+}
+
+/*
+ * Function nsc_ircc_fir_interrupt (self, eir)
+ *
+ *    Handle MIR/FIR interrupt
+ *
+ */
+static __u8 nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, 
+				   int eir)
+{
+	__u8 new_ier = 0;
+	__u8 bank;
+
+	bank = inb(iobase+BSR);
+	
+	/* Status event, or end of frame detected in FIFO */
+	if (eir & (EIR_SFIF_EV|EIR_LS_EV)) {
+		if (nsc_ircc_dma_receive_complete(self, iobase)) {
+
+			/* Wait for next status FIFO interrupt */
+			new_ier |= IER_SFIF_IE;
+		} else {
+			/* 
+			 * DMA not finished yet, so try again later, set 
+			 * timer value, resolution 125 us 
+			 */
+			switch_bank(iobase, BANK4);
+			outb(0x07, iobase+TMRL); /* 125 us * 7 = 875 us */
+			outb(0x00, iobase+TMRH);
+
+			/* Start timer */
+			outb(IRCR1_TMR_EN, iobase+IRCR1);
+
+			new_ier |= IER_TMR_IE;
+		}
+	} else if (eir & EIR_TMR_EV) { /* Timer finished */
+		/* Disable timer */
+		switch_bank(iobase, BANK4);
+		outb(0, iobase+IRCR1);
+
+		/* Clear timer event */
+		switch_bank(iobase, BANK0);
+		outb(ASCR_CTE, iobase+ASCR);
+
+		/* Check if this is a TX timer interrupt */
+		if (self->io.direction == IO_XMIT) {
+			nsc_ircc_dma_xmit(self, iobase);
+
+			/*  Interrupt on DMA */
+			new_ier |= IER_DMA_IE;
+		} else {
+			/* Check if DMA has now finished */
+			nsc_ircc_dma_receive_complete(self, iobase);
+
+			new_ier |= IER_SFIF_IE;
+		}
+	} else if (eir & EIR_DMA_EV) { /* Finished with transmission */
+		if (nsc_ircc_dma_xmit_complete(self)) {		
+			/* Check if there are more frames to be transmitted */
+			if (irda_device_txqueue_empty(self->netdev)) {
+				/* Prepare for receive */
+				nsc_ircc_dma_receive(self);
+			
+				new_ier = IER_LS_IE|IER_SFIF_IE;
+			}
+		} else {
+			/*  Not finished yet, so interrupt on DMA again */
+			new_ier |= IER_DMA_IE;
+		}
+	}
+	outb(bank, iobase+BSR);
+
+	return new_ier;
+}
+
+/*
+ * Function nsc_ircc_interrupt (irq, dev_id, regs)
+ *
+ *    An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *) dev_id;
+	struct nsc_ircc_cb *self;
+	__u8 bsr, eir, ier;
+	int iobase;
+
+	if (!dev) {
+		printk(KERN_WARNING "%s: irq %d for unknown device.\n", 
+		       driver_name, irq);
+		return;
+	}
+	self = (struct nsc_ircc_cb *) dev->priv;
+
+	spin_lock(&self->lock);	
+	dev->interrupt = 1;
+
+	iobase = self->io.iobase;
+
+	bsr = inb(iobase+BSR); 	/* Save current bank */
+
+	switch_bank(iobase, BANK0);	
+	ier = inb(iobase+IER); 
+	eir = inb(iobase+EIR) & ier; /* Mask out the interesting ones */ 
+
+	outb(0, iobase+IER); /* Disable interrupts */
+	
+	if (eir) {
+		/* Dispatch interrupt handler for the current speed */
+		if (self->io.speed > 115200)
+			ier = nsc_ircc_fir_interrupt(self, iobase, eir);
+		else
+			ier = nsc_ircc_sir_interrupt(self, eir);
+	}
+
+	outb(ier, iobase+IER);   /* Restore interrupts */
+	outb(bsr, iobase+BSR);   /* Restore bank register */
+
+	dev->interrupt = 0;
+	spin_unlock(&self->lock);
+}
+
+/*
+ * Function nsc_ircc_is_receiving (self)
+ *
+ *    Return TRUE is we are currently receiving a frame
+ *
+ */
+static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self)
+{
+	int status = FALSE;
+	int iobase;
+	__u8 bank;
+
+	ASSERT(self != NULL, return FALSE;);
+
+	if (self->io.speed > 115200) {
+		iobase = self->io.iobase;
+
+		/* Check if rx FIFO is not empty */
+		bank = inb(iobase+BSR);
+		switch_bank(iobase, BANK2);
+		if ((inb(iobase+RXFLV) & 0x3f) != 0) {
+			/* We are receiving something */
+			status =  TRUE;
+		}
+		outb(bank, iobase+BSR);
+	} else 
+		status = (self->rx_buff.state != OUTSIDE_FRAME);
+	
+	return status;
+}
+
+/*
+ * Function nsc_ircc_net_init (dev)
+ *
+ *    Initialize network device
+ *
+ */
+static int nsc_ircc_net_init(struct device *dev)
+{
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Setup to be a normal IrDA network device driver */
+	irda_device_setup(dev);
+
+	/* Insert overrides below this line! */
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_open (dev)
+ *
+ *    Start the device
+ *
+ */
+static int nsc_ircc_net_open(struct device *dev)
+{
+	struct nsc_ircc_cb *self;
+	int iobase;
+	__u8 bank;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	
+	ASSERT(dev != NULL, return -1;);
+	self = (struct nsc_ircc_cb *) dev->priv;
+	
+	ASSERT(self != NULL, return 0;);
+	
+	iobase = self->io.iobase;
+	
+	if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, 
+			(void *) dev)) 
+	{
+		return -EAGAIN;
+	}
+	/*
+	 * Always allocate the DMA channel after the IRQ, and clean up on 
+	 * failure.
+	 */
+	if (request_dma(self->io.dma, dev->name)) {
+		free_irq(self->io.irq, self);
+		return -EAGAIN;
+	}
+	
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	/* turn on interrupts */
+	switch_bank(iobase, BANK0);
+	outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	/* Ready to play! */
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* 
+	 * Open new IrLAP layer instance, now that everything should be
+	 * initialized properly 
+	 */
+	self->irlap = irlap_open(dev, &self->qos);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_close (dev)
+ *
+ *    Stop the device
+ *
+ */
+static int nsc_ircc_net_close(struct device *dev)
+{
+	struct nsc_ircc_cb *self;
+	int iobase;
+	__u8 bank;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	
+	ASSERT(dev != NULL, return -1;);
+	self = (struct nsc_ircc_cb *) dev->priv;
+	
+	ASSERT(self != NULL, return 0;);
+
+	/* Stop device */
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
+	
+	iobase = self->io.iobase;
+
+	disable_dma(self->io.dma);
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable interrupts */
+	switch_bank(iobase, BANK0);
+	outb(0, iobase+IER); 
+       
+	free_irq(self->io.irq, dev);
+	free_dma(self->io.dma);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+static int nsc_ircc_net_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		nsc_ircc_change_speed(self, irq->ifr_baudrate);
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = nsc_ircc_is_receiving(self);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
+
+static struct net_device_stats *nsc_ircc_net_get_stats(struct device *dev)
+{
+	struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv;
+	
+	return &self->stats;
+}
+
+#ifdef CONFIG_APM
+static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
+{
+	int i = 10;
+
+	MESSAGE("%s, Suspending\n", driver_name);
+
+	if (self->suspend)
+		return;
+
+	self->suspend = 1;
+}
+
+
+static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
+{
+	struct device *dev = self->netdev;
+	unsigned long flags;
+
+	if (!self->suspend)
+		return;
+
+	save_flags(flags);
+	cli();
+
+	
+	restore_flags(flags);
+	MESSAGE("%s, Waking up\n", driver_name);
+}
+
+static int nsc_ircc_apmproc(apm_event_t event)
+{
+	static int down = 0;          /* Filter out double events */
+	int i;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (!down) {			
+			for (i = 0; i < 4; i++) {
+				if (dev_self[i])
+					nsc_ircc_suspend(dev_self[i]);
+			}
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (down) {
+			for (i = 0; i < 4; i++) {
+				if (dev_self[i])
+					nsc_ircc_wakeup(dev_self[i]);
+			}
+		}
+		down = 0;
+		break;
+	}
+	return 0;
+}
+#endif /* CONFIG_APM */
+
+#ifdef MODULE
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("NSC FIR IrDA Device Driver");
+
+MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(io2, "1-4i");
+MODULE_PARM(irq, "1-4i");
+MODULE_PARM(dongle_id, "i");
+
+int init_module(void)
+{
+	return nsc_ircc_init();
+}
+
+void cleanup_module(void)
+{
+	nsc_ircc_cleanup();
+}
+#endif /* MODULE */
+
diff -urN linux-2.2.15-pre2/drivers/net/irda/old_belkin.c linux/drivers/net/irda/old_belkin.c
--- linux-2.2.15-pre2/drivers/net/irda/old_belkin.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/old_belkin.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,178 @@
+/*********************************************************************
+ *                
+ * Filename:      old_belkin.c
+ * Version:       1.1
+ * Description:   Driver for the Belkin (old) SmartBeam dongle
+ * Status:        Experimental...
+ * Author:        Jean Tourrilhes <jt@hpl.hp.com>
+ * Created at:    22/11/99
+ * Modified at:   Fri Dec 17 09:13:32 1999
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1999 Jean Tourrilhes, 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 <linux/irda.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irda_device.h>
+
+/*
+ * Belkin is selling a dongle called the SmartBeam.
+ * In fact, there is two hardware version of this dongle, of course with
+ * the same name and looking the exactly same (grrr...).
+ * I guess that I've got the old one, because inside I don't have
+ * a jumper for IrDA/ASK...
+ *
+ * As far as I can make it from info on their web site, the old dongle 
+ * support only 9600 b/s, which make our life much simpler as far as
+ * the driver is concerned, but you might not like it very much ;-)
+ * The new SmartBeam does 115 kb/s, and I've not tested it...
+ *
+ * Belkin claim that the correct driver for the old dongle (in Windows)
+ * is the generic Parallax 9500a driver, but the Linux LiteLink driver
+ * fails for me (probably because Linux-IrDA doesn't rate fallback),
+ * so I created this really dumb driver...
+ *
+ * In fact, this driver doesn't do much. The only thing it does is to
+ * prevent Linux-IrDA to use any other speed than 9600 b/s ;-) This
+ * driver is called "old_belkin" so that when the new SmartBeam is supported
+ * its driver can be called "belkin" instead of "new_belkin".
+ *
+ * Note : this driver was written without any info/help from Belkin,
+ * so a lot of info here might be totally wrong. Blame me ;-)
+ */
+
+/* Let's guess */
+#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
+
+static void old_belkin_open(dongle_t *self, struct qos_info *qos);
+static void old_belkin_close(dongle_t *self);
+static int  old_belkin_change_speed(struct irda_task *task);
+static int  old_belkin_reset(struct irda_task *task);
+
+/* These are the baudrates supported */
+/* static __u32 baud_rates[] = { 9600 }; */
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_OLD_BELKIN_DONGLE,
+	old_belkin_open,
+	old_belkin_close,
+	old_belkin_reset,
+	old_belkin_change_speed,
+};
+
+int __init old_belkin_init(void)
+{
+	return irda_device_register_dongle(&dongle);
+}
+
+void old_belkin_cleanup(void)
+{
+	irda_device_unregister_dongle(&dongle);
+}
+
+static void old_belkin_open(dongle_t *self, struct qos_info *qos)
+{
+	/* Not too fast, please... */
+	qos->baud_rate.bits &= IR_9600;
+	/* Needs at least 10 ms (totally wild guess, can do probably better) */
+	qos->min_turn_time.bits = 0x01;
+
+	MOD_INC_USE_COUNT;
+}
+
+static void old_belkin_close(dongle_t *self)
+{
+	/* Power off dongle */
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Function old_belkin_change_speed (task)
+ *
+ *    With only one speed available, not much to do...
+ */
+static int old_belkin_change_speed(struct irda_task *task)
+{
+	irda_task_next_state(task, IRDA_TASK_DONE);
+
+	return 0;
+}
+
+/*
+ * Function old_belkin_reset (task)
+ *
+ *      Reset the Old-Belkin type dongle.
+ *
+ */
+static int old_belkin_reset(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+
+	/* Power on dongle */
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+	/* Sleep a minimum of 15 us */
+	udelay(MIN_DELAY);
+
+	/* This dongles speed "defaults" to 9600 bps ;-) */
+	self->speed = 9600;
+
+	irda_task_next_state(task, IRDA_TASK_DONE);
+
+	return 0;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
+MODULE_DESCRIPTION("Belkin (old) SmartBeam dongle driver");	
+
+/*
+ * Function init_module (void)
+ *
+ *    Initialize Old-Belkin module
+ *
+ */
+int init_module(void)
+{
+	return old_belkin_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup Old-Belkin module
+ *
+ */
+void cleanup_module(void)
+{
+	old_belkin_cleanup();
+}
+#endif /* MODULE */
+
diff -urN linux-2.2.15-pre2/drivers/net/irda/pc87108.c linux/drivers/net/irda/pc87108.c
--- linux-2.2.15-pre2/drivers/net/irda/pc87108.c	Mon Jun  7 16:19:59 1999
+++ linux/drivers/net/irda/pc87108.c	Wed Dec 31 16:00:00 1969
@@ -1,1493 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      pc87108.c
- * Version:       0.8
- * Description:   FIR/MIR driver for the NS PC87108 chip
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Mon May 24 15:19:21 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
- *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
- *     Copyright (c) 1998 Actisys Corp., www.actisys.com
- *     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 that all functions that needs to access the chip in _any_
- *     way, must save BSR register on entry, and restore it on exit. 
- *     It is _very_ important to follow this policy!
- *
- *         __u8 bank;
- *     
- *         bank = inb( iobase+BSR);
- *  
- *         do_your_stuff_here();
- *
- *         outb( bank, iobase+BSR);
- *
- *    If you find bugs in this file, its very likely that the same bug
- *    will also be in w83977af_ir.c since the implementations is quite
- *    similar.
- *     
- ********************************************************************/
-
-#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 <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/pc87108.h>
-
-#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 irq[] = { 3, 0, 0, 0 };
-static unsigned int dma[] = { 0, 0, 0, 0 };
-
-static struct pc87108 *dev_self[] = { NULL, NULL, NULL, NULL};
-
-static char *dongle_types[] = {
-	"Differential serial interface",
-	"Differential serial interface",
-	"Reserved",
-	"Reserved",
-	"Sharp RY5HD01",
-	"Reserved",
-	"Single-ended serial interface",
-	"Consumer-IR only",
-	"HP HSDL-2300, HP HSDL-3600/HSDL-3610",
-	"IBM31T1100 or Temic TFDS6000/TFDS6500",
-	"Reserved",
-	"Reserved",
-	"HP HSDL-1100/HSDL-2100",
-	"HP HSDL-1100/HSDL-2100"
-	"Supports SIR Mode only",
-	"No dongle connected",
-};
-
-/* Some prototypes */
-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);
-#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_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 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);
-
-/*
- * Function pc87108_init ()
- *
- *    Initialize chip. Just try to find out how many chips we are dealing with
- *    and where they are
- */
-__initfunc(int pc87108_init(void))
-{
-	int 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)
-			return 0;
-	}
-	return -ENODEV;
-}
-
-/*
- * Function pc87108_cleanup ()
- *
- *    Close all configured chips
- *
- */
-#ifdef MODULE
-static void pc87108_cleanup(void)
-{
-	int i;
-
-        DEBUG(4, __FUNCTION__ "()\n");
-
-	for (i=0; i < 4; i++) {
-		if (dev_self[i])
-			pc87108_close(&(dev_self[i]->idev));
-	}
-}
-#endif /* MODULE */
-
-/*
- * Function pc87108_open (iobase, irq)
- *
- *    Open driver instance
- *
- */
-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");
-
-	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");
-		return -ENOMEM;
-	}
-	memset(self, 0, sizeof(struct pc87108));
-   
-	/* Need to store self somewhere */
-	dev_self[i] = self;
-
-	idev = &self->idev;
-
-	/* Initialize IO */
-	idev->io.iobase    = iobase;
-        idev->io.irq       = irq;
-        idev->io.io_ext    = CHIP_IO_EXTENT;
-        idev->io.dma       = dma;
-        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);
-		/* pc87108_cleanup( self->idev);  */
-		return -ENODEV;
-	}
-	request_region(idev->io.iobase, idev->io.io_ext, idev->name);
-
-	/* Initialize QoS for this device */
-	irda_init_max_qos_capabilies(&idev->qos);
-	
-	/* The only value we must override it the baudrate */
-	idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
-		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
-	
-	idev->qos.min_turn_time.bits = qos_mtt_bits;
-	irda_qos_bits_to_value(&idev->qos);
-	
-	idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
-
-	/* 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 = 14384; 
-	idev->tx_buff.truesize = 4000;
-	
-	/* Initialize callbacks */
-	idev->change_speed    = pc87108_change_speed;
-	idev->wait_until_sent = pc87108_wait_until_sent;
-	idev->is_receiving    = pc87108_is_receiving;
-     
-	/* Override the network functions we need to use */
-	idev->netdev.init            = pc87108_net_init;
-	idev->netdev.hard_start_xmit = pc87108_hard_xmit;
-	idev->netdev.open            = pc87108_net_open;
-	idev->netdev.stop            = pc87108_net_close;
-
-	idev->io.dongle_id = dongle_id;
-	pc87108_init_dongle_interface(iobase, dongle_id);
-
-	/* Open the IrDA device */
-	irda_device_open(idev, driver_name, self);
-	
-	return 0;
-}
-
-#ifdef MODULE
-/*
- * Function pc87108_close (idev)
- *
- *    Close driver instance
- *
- */
-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;);
-
-        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);
-
-	irda_device_close(idev);
-
-	kfree(self);
-
-	return 0;
-}
-#endif /* MODULE */
-
-/*
- * Function pc87108_probe (iobase, board_addr, irq, dma)
- *
- *    Returns non-negative on success.
- *
- */
-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");
-
-	/* 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:    ERROR(__FUNCTION__ "(), invalid base_address");
-	}
-	
-	/* Control Signal Routing Register CSRT */
-	switch (irq) {
-	case 3:  temp = 0x01; break;
-	case 4:  temp = 0x02; break;
-	case 5:  temp = 0x03; break;
-	case 7:  temp = 0x04; break;
-	case 9:  temp = 0x05; break;
-	case 11: temp = 0x06; break;
-	case 15: temp = 0x07; break;
-	default: ERROR(__FUNCTION__ "(), invalid irq");
-	}
-	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;
-	default: DEBUG( 0, __FUNCTION__ "(), invalid dma");
-	}
-
-	/* Mode Control Register MCTL */
-	outb(2, board_addr);
-	outb(0x03, board_addr+1);
-		
-	/* read the Module ID */
-	switch_bank(iobase, BANK3);
-	version = inb(iobase+MID);
-	
-	/* should be 0x2? */
-	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);
-
-	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);
-	
-	/* Set FIFO size to 32 */
-	switch_bank(iobase, BANK2);
-	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);	
-
-	/* IRCR2: FEND_MD is set */
-	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 */
-
-	/* Receiver frame length */
-	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);
-	
-	DEBUG(0, "PC87108 driver loaded. Version: 0x%02x\n", version);
-
-	/* Enable receive interrupts */
-	switch_bank(iobase, BANK0);
-	outb(IER_RXHDL_IE, iobase+IER);
-
-	return dongle_id;
-}
-
-/*
- * Function pc87108_read_dongle_id (void)
- *
- * Try to read dongle indentification. This procedure needs to be executed
- * once after power-on/reset. It also needs to be used whenever you suspect
- * that the user may have plugged/unplugged the IrDA Dongle.
- * 
- */
-static int pc87108_read_dongle_id ( int iobase)
-{
-	int dongle_id;
-	__u8 bank;
-
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	bank = inb( iobase+BSR);
-
-	/* Select Bank 7 */
-	switch_bank(iobase, BANK7);
-	
-	/* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
-	outb(0x00, iobase+7);
-	
-	/* ID0, 1, and 2 are pulled up/down very slowly */
-	udelay(50);
-	
-	/* IRCFG1: read the ID bits */
-	dongle_id = inb( iobase+4) & 0x0f;
-
-#ifdef BROKEN_DONGLE_ID
-	if (dongle_id == 0x0a)
-		dongle_id = 0x09;
-#endif
-	
-	/* Go back to  bank 0 before returning */
-	switch_bank(iobase, BANK0);
-
-	DEBUG(0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id);
-
-	outb(bank, iobase+BSR);
-
-	return dongle_id;
-}
-
-/*
- * Function pc87108_init_dongle_interface (iobase, dongle_id)
- *
- *     This function initializes the dongle for the transceiver that is
- *     used. This procedure needs to be executed once after
- *     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)
-{
-	int bank;
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-
-	/* Select Bank 7 */
-	switch_bank( iobase, BANK7);
-	
-	/* IRCFG4: set according to dongle_id */
-	switch (dongle_id) {
-	case 0x00: /* same as */
-	case 0x01: /* Differential serial interface */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x02: /* same as */
-	case 0x03: /* Reserved */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x04: /* Sharp RY5HD01 */
-		DEBUG( 0, __FUNCTION__ "(), %s not supported yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x05: /* Reserved */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x06: /* Single-ended serial interface */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x07: /* Consumer-IR only */
-		DEBUG( 0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
-		DEBUG( 0, __FUNCTION__ "(), %s not supported yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
-		outb_p( 0x28, iobase+7); /* Set irsl[0-2] as output */
-		break;
-	case 0x0A: /* same as */
-	case 0x0B: /* Reserved */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x0C: /* same as */
-	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
-		/* 
-		 * Set irsl0 as input, irsl[1-2] as output, and separate 
-		 * inputs are used for SIR and MIR/FIR 
-		 */
-		outb( 0x48, iobase+7); 
-		break;
-	case 0x0E: /* Supports SIR Mode only */
-		outb( 0x28, iobase+7); /* Set irsl[0-2] as output */
-		break;
-	case 0x0F: /* No dongle connected */
-		DEBUG( 0, __FUNCTION__ "(), %s\n",
-		       dongle_types[dongle_id]); 
-		DEBUG( 0, "***\n");
-
-		switch_bank( iobase, BANK0);
-		outb( 0x62, iobase+MCR);
-		break;
-	default: 
-		DEBUG( 0, __FUNCTION__ "(), invalid dongle_id %#x", dongle_id);
-	}
-	
-	/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
-	outb( 0x00, iobase+4);
-
-	/* Restore bank register */
-	outb( bank, iobase+BSR);
-	
-} /* set_up_dongle_interface */
-
-/*
- * Function pc87108_change_dongle_speed (iobase, speed, dongle_id)
- *
- *    Change speed of the attach dongle
- *
- */
-static void pc87108_change_dongle_speed( int iobase, int speed, int dongle_id)
-{
-	unsigned long flags;
-	__u8 bank;
-
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-
-	/* Select Bank 7 */
-	switch_bank( iobase, BANK7);
-	
-	/* IRCFG1: set according to dongle_id */
-	switch (dongle_id) {
-	case 0x00: /* same as */
-	case 0x01: /* Differential serial interface */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x02: /* same as */
-	case 0x03: /* Reserved */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x04: /* Sharp RY5HD01 */
-		DEBUG( 0, __FUNCTION__ "(), %s not supported yet\n",
-		       dongle_types[dongle_id]); 
-	case 0x05: /* Reserved */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x06: /* Single-ended serial interface */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x07: /* Consumer-IR only */
-		DEBUG( 0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
-		DEBUG( 0, __FUNCTION__ "(), %s not supported yet\n",
-		       dongle_types[dongle_id]); 
-	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
-		switch_bank( iobase, BANK7);
-		outb_p( 0x01, iobase+4);
-
-		if ( speed == 4000000) {
-			save_flags(flags);
-			cli();
-			outb( 0x81, iobase+4);
-			outb( 0x80, iobase+4);
-			restore_flags(flags);
-		}
-		else
-			outb_p( 0x00, iobase+4);
-		break;
-	case 0x0A: /* same as */
-	case 0x0B: /* Reserved */
-		DEBUG( 0, __FUNCTION__ "(), %s not defined by irda yet\n",
-		       dongle_types[dongle_id]); 
-		break;
-	case 0x0C: /* same as */
-	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
-		break;
-	case 0x0E: /* Supports SIR Mode only */
-		break;
-	case 0x0F: /* No dongle connected */
-		DEBUG( 0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-		       dongle_types[dongle_id]);
-
-		switch_bank( iobase, BANK0); 
-		outb( 0x62, iobase+MCR);
-		break;
-	default: 
-		DEBUG( 0, __FUNCTION__ "(), invalid data_rate\n");
-	}
-	/* Restore bank register */
-	outb( bank, iobase+BSR);
-}
-
-/*
- * Function pc87108_change_speed (idev, baud)
- *
- *    Change the speed of the device
- *
- */
-static void pc87108_change_speed( struct irda_device *idev, int speed)
-{
-	__u8 mcr = MCR_SIR;
-	__u8 bank;
-	int iobase; 
-
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
-
-	iobase = idev->io.iobase;
-
-	/* Update accounting for new speed */
-	idev->io.baudrate = speed;
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-
-	/* Disable interrupts */
-	switch_bank( iobase, BANK0);
-	outb( 0, iobase+IER);
-
-	  /* Select Bank 2 */
-	switch_bank( iobase, BANK2);
-
-	outb( 0x00, iobase+BGDH);
-	switch ( speed) {
-	case 9600:   outb( 0x0c, iobase+BGDL); break;
-	case 19200:  outb( 0x06, iobase+BGDL); break;
-	case 37600:  outb( 0x03, iobase+BGDL); break;
-	case 57600:  outb( 0x02, iobase+BGDL); break;
-	case 115200: outb( 0x01, iobase+BGDL); break;
-	case 576000:
-		switch_bank( iobase, BANK5);
-		
-		/* IRCR2: MDRS is set */
-		outb( inb( iobase+4) | 0x04, iobase+4);
-	       
-		mcr = MCR_MIR;
-		DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
-		break;
-	case 1152000:
-		mcr = MCR_MIR;
-		DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
-		break;
-	case 4000000:
-		mcr = MCR_FIR;
-		DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
-		break;
-	default:
-		mcr = MCR_FIR;
-		DEBUG( 0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
-		break;
-	}
-
-	/* Set appropriate speed mode */
-	switch_bank(iobase, BANK0);
-	outb(mcr | MCR_TX_DFR, iobase+MCR);
-
-	/* Give some hits to the transceiver */
-	pc87108_change_dongle_speed( iobase, speed, idev->io.dongle_id);
-
-	/* Set FIFO threshold to TX17, RX16 */
-	switch_bank( iobase, BANK0);
-	outb( FCR_RXTH|     /* Set Rx FIFO threshold */
-	      FCR_TXTH|     /* Set Tx FIFO threshold */
-	      FCR_TXSR|     /* Reset Tx FIFO */
-	      FCR_RXSR|     /* Reset Rx FIFO */
-	      FCR_FIFO_EN,  /* Enable FIFOs */
-	      iobase+FCR);
-	/* outb( 0xa7, iobase+FCR); */
-	
-	/* Set FIFO size to 32 */
-	switch_bank( iobase, BANK2);
-	outb( EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);	
-	
-	idev->netdev.tbusy = 0;
-	
-	/* Enable some interrupts so we can receive frames */
-	switch_bank( iobase, BANK0); 
-	if ( speed > 115200) {
-		outb( IER_SFIF_IE, iobase+IER);
-		pc87108_dma_receive( idev);
-	} else
-		outb( IER_RXHDL_IE, iobase+IER);
-    	
-	/* Restore BSR */
-	outb( bank, iobase+BSR);
-}
-
-/*
- * Function pc87108_hard_xmit (skb, dev)
- *
- *    Transmit the frame!
- *
- */
-static int pc87108_hard_xmit( struct sk_buff *skb, struct device *dev)
-{
-	struct irda_device *idev;
-	int iobase;
-	__u8 bank;
-	int mtt;
-	
-	idev = (struct irda_device *) dev->priv;
-
-	ASSERT( idev != NULL, return 0;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
-
-	iobase = idev->io.iobase;
-
-	DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len);
-	
-	/* Lock transmit buffer */
-	if ( irda_lock( (void *) &dev->tbusy) == FALSE)
-		return -EBUSY;
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-
-	/* Decide if we should use PIO or DMA transfer */
-	if ( idev->io.baudrate > 115200) {
-		idev->tx_buff.data = idev->tx_buff.head;
-		memcpy(idev->tx_buff.data, skb->data, skb->len);
-		idev->tx_buff.len = skb->len;
-
-		mtt = irda_get_mtt( skb);
-	        if ( mtt > 50) {
-			/* Adjust for timer resolution */
-			mtt = mtt / 125 + 1;
-
-			/* Setup timer */
-			switch_bank( iobase, BANK4);
-			outb( mtt & 0xff, iobase+TMRL);
-			outb(( mtt >> 8) & 0x0f, iobase+TMRH);
-			
-			/* Start timer */
-			outb( IRCR1_TMR_EN, iobase+IRCR1);
-			idev->io.direction = IO_XMIT;
-			
-			/* Enable timer interrupt */
-			switch_bank( iobase, BANK0);
-			outb( IER_TMR_IE, iobase+IER);
-		} else {
-			/* Use udelay for delays less than 50 us. */
-			if (mtt)
-				udelay( mtt);
-
-			/* Enable DMA interrupt */
-			switch_bank( iobase, BANK0);
-	 		outb( IER_DMA_IE, iobase+IER);
-	     		pc87108_dma_write( idev, iobase);
-		}
-        } else {
-	        idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
-						   idev->tx_buff.truesize);
-		
-		idev->tx_buff.data = idev->tx_buff.head;
-		
-		/* Add interrupt on tx low level (will fire immediately) */
-		switch_bank( iobase, BANK0);
-		outb( IER_TXLDL_IE, iobase+IER);
-	}
-	dev_kfree_skb( skb);
-
-	/* Restore bank register */
-	outb( bank, iobase+BSR);
-
-	return 0;
-}
-
-/*
- * Function pc87108_dma_xmit (idev, iobase)
- *
- *    Transmit data using DMA
- *
- */
-static void pc87108_dma_write( struct irda_device *idev, int iobase)
-{
-	int bsr;
-
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	/* Save current bank */
-	bsr = inb( iobase+BSR);
-
-	/* Disable DMA */
-	switch_bank(iobase, BANK0);
-	outb( inb( iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-
-	setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
-		  DMA_MODE_WRITE);
-	
-	idev->io.direction = IO_XMIT;
-	
-	/* Choose transmit DMA channel  */ 
-	switch_bank(iobase, BANK2);
-	outb( inb( iobase+ECR1) | ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, 
-	      iobase+ECR1);
-	
-	/* Enable DMA */
- 	switch_bank(iobase, BANK0);	
-	outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
-
-	/* Restore bank register */
-	outb(bsr, iobase+BSR);
-}
-
-/*
- * Function pc87108_pio_xmit (idev, iobase)
- *
- *    Transmit data using PIO. Returns the number of bytes that actually
- *    got transfered
- *
- */
-static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
-{
-	int actual = 0;
-	__u8 bank;
-	
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-
-	switch_bank( iobase, BANK0);
-	if (!(inb_p( iobase+LSR) & LSR_TXEMP)) {
-		DEBUG( 4, __FUNCTION__ "(), warning, FIFO not empty yet!\n");
-
-		fifo_size -= 17;
-		DEBUG( 4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size);
-	}
-
-	/* Fill FIFO with current frame */
-	while ((fifo_size-- > 0) && (actual < len)) {
-		/* Transmit next byte */
-		outb(buf[actual++], iobase+TXD);
-	}
-        
-	DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-	      fifo_size, actual, len);
-
-	/* Restore bank */
-	outb(bank, iobase+BSR);
-
-	return actual;
-}
-
-/*
- * Function pc87108_dma_xmit_complete (idev)
- *
- *    The transfer of a frame in finished. This function will only be called 
- *    by the interrupt handler
- *
- */
-static void pc87108_dma_xmit_complete( struct irda_device *idev)
-{
-	int iobase;
-	__u8 bank;
-
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
-
-	iobase = idev->io.iobase;
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-
-	/* Disable DMA */
-	switch_bank( iobase, BANK0);
-	outb( inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-	
-	/* Check for underrrun! */
-	if ( inb( iobase+ASCR) & ASCR_TXUR) {
-		idev->stats.tx_errors++;
-		idev->stats.tx_fifo_errors++;
-		
-		/* Clear bit, by writing 1 into it */
-		outb( ASCR_TXUR, iobase+ASCR);
-	} 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);
-
-	/* Restore bank */
-	outb( bank, iobase+BSR);
-}
-
-/*
- * Function pc87108_dma_receive (idev)
- *
- *    Get ready for receiving a frame. The device will initiate a DMA
- *    if it starts to receive a frame.
- *
- */
-static int pc87108_dma_receive(struct irda_device *idev) 
-{
-	struct pc87108 *self;
-	int iobase;
-	__u8 bsr;
-
-	ASSERT(idev != NULL, return -1;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
-
-	DEBUG(4, __FUNCTION__ "\n");
-
-	self = idev->priv;
-	iobase = idev->io.iobase;
-
-	/* Save current bank */
-	bsr = inb(iobase+BSR);
-
-	/* Disable DMA */
-	switch_bank(iobase, BANK0);
-	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-
-	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;
-
-	/* Reset Rx FIFO. This will also flush the ST_FIFO */
-	outb(FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
-	self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0;
-
-	/* Choose DMA Rx, DMA Fairness, and Advanced mode */
-	switch_bank(iobase, BANK2);
-	outb((inb( iobase+ECR1) & ~ECR1_DMASWP)|ECR1_DMANF|ECR1_EXT_SL, 
-	     iobase+ECR1);
-	
-	/* enable DMA */
-	switch_bank(iobase, BANK0);
-	outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
-
-	/* Restore bank register */
-	outb(bsr, iobase+BSR);
-	
-	DEBUG(4, __FUNCTION__ "(), done!\n");	
-	
-	return 0;
-}
-
-/*
- * Function pc87108_dma_receive_complete (idev)
- *
- *    Finished with receiving frames
- *
- *    
- */
-static int pc87108_dma_receive_complete(struct irda_device *idev, int iobase)
-{
-	struct sk_buff *skb;
-	struct pc87108 *self;
-	struct st_fifo *st_fifo;
-	int len;
-	__u8 bank;
-	__u8 status;
-
-	self = idev->priv;
-	st_fifo = &self->st_fifo;
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-	
-	/* Read status FIFO */
-	switch_bank(iobase, BANK5);
-	while (( status = inb( iobase+FRM_ST)) & FRM_ST_VLD) {
-		st_fifo->entries[ st_fifo->tail].status = status;
-
-		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++;
-	}
-	
-	/* Try to process all entries in status FIFO */
-	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;
-		st_fifo->head++;
-		st_fifo->len--;
-
-		/* Check for errors */
-		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 {
-				/* Skip frame */
-				idev->stats.rx_errors++;
-				
-				idev->rx_buff.data += len;
-			
-				if (status & FRM_ST_MAX_LEN)
-					idev->stats.rx_length_errors++;
-				
-				if (status & FRM_ST_PHY_ERR) 
-					idev->stats.rx_frame_errors++;
-				
-				if (status & FRM_ST_BAD_CRC) 
-					idev->stats.rx_crc_errors++;
-			}
-			/* The errors below can be reported in both cases */
-			if (status & FRM_ST_OVR1)
-				idev->stats.rx_fifo_errors++;
-			
-			if (status & FRM_ST_OVR2)
-				idev->stats.rx_fifo_errors++;
-			
-		} else {
-			/* Check if we have transfered all data to memory */
-			if (inb(iobase+LSR) & LSR_RXDA) {
-				/* Put this entry back in fifo */
-				st_fifo->head--;
-				st_fifo->len++;
-				st_fifo->entries[st_fifo->head].status = status;
-				st_fifo->entries[st_fifo->head].len = len;
-
-				/* Restore bank register */
-				outb(bank, iobase+BSR);
-			
-				return FALSE; 	/* I'll be back! */
-			}
-
-			/* Should be OK then */			
-			skb = dev_alloc_skb(len+1);
-			if (skb == NULL)  {
-				printk( KERN_INFO __FUNCTION__ 
-					"(), memory squeeze, dropping frame.\n");
-				/* Restore bank register */
-				outb( bank, iobase+BSR);
-
-				return FALSE;
-			}
-			
-			/* Make sure IP header gets aligned */
-			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);
-			} else {
-				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);
-		}
-	}
-	/* Restore bank register */
-	outb(bank, iobase+BSR);
-
-	return TRUE;
-}
-
-/*
- * Function pc87108_pio_receive (idev)
- *
- *    Receive all data in receiver FIFO
- *
- */
-static void pc87108_pio_receive( struct irda_device *idev) 
-{
-	__u8 byte = 0x00;
-	int iobase;
-
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	iobase = idev->io.iobase;
-	
-	/*  Receive all characters in Rx FIFO */
-	do {
-		byte = inb(iobase+RXD);
-		async_unwrap_char(idev, byte);
-
-	} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */	
-}
-
-/*
- * Function pc87108_sir_interrupt (idev, eir)
- *
- *    Handle SIR interrupt
- *
- */
-static __u8 pc87108_sir_interrupt(struct irda_device *idev, int eir)
-{
-	int actual;
-	__u8 new_ier = 0;
-
-	/* Transmit FIFO low on data */
-	if ( eir & EIR_TXLDL_EV) {
-		/* Write data left in transmit buffer */
-		actual = pc87108_pio_write(idev->io.iobase, 
-					   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)
-			new_ier |= IER_TXLDL_IE;
-		else { 
-			idev->netdev.tbusy = 0; /* Unlock */
-			idev->stats.tx_packets++;
-			
-		        mark_bh(NET_BH);	
-
-			new_ier |= IER_TXEMP_IE;
-		}
-			
-	}
-	/* Check if transmission has completed */
-	if ( eir & EIR_TXEMP_EV) {
-		
-		/* Turn around and get ready to receive some data */
-		idev->io.direction = IO_RECV;
-		new_ier |= IER_RXHDL_IE;
-	}
-
-	/* Rx FIFO threshold or timeout */
-	if ( eir & EIR_RXHDL_EV) {
-		pc87108_pio_receive( idev);
-
-		/* Keep receiving */
-		new_ier |= IER_RXHDL_IE;
-	}
-	return new_ier;
-}
-
-/*
- * Function pc87108_fir_interrupt (idev, eir)
- *
- *    Handle MIR/FIR interrupt
- *
- */
-static __u8 pc87108_fir_interrupt( struct irda_device *idev, int iobase,
-				   int eir)
-{
-	__u8 new_ier = 0;
-	__u8 bank;
-
-	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)) {
-
-			/* Wait for next status FIFO interrupt */
-			new_ier |= IER_SFIF_IE;
-		} else {
-			/* DMA not finished yet */
-
-			/* Set timer value, resolution 125 us */
-			switch_bank( iobase, BANK4);
-			outb( 0x0f, iobase+TMRL); /* 125 us */
-			outb( 0x00, iobase+TMRH);
-
-			/* Start timer */
-			outb( IRCR1_TMR_EN, iobase+IRCR1);
-
-			new_ier |= IER_TMR_IE;
-		}
-	}
-	/* Timer finished */
-	if ( eir & EIR_TMR_EV) {
-		/* Disable timer */
-		switch_bank( iobase, BANK4);
-		outb( 0, iobase+IRCR1);
-
-		/* Clear timer event */
-		switch_bank(iobase, BANK0);
-		outb( ASCR_CTE, iobase+ASCR);
-
-		/* Check if this is a TX timer interrupt */
-		if ( idev->io.direction == IO_XMIT) {
-			pc87108_dma_write( idev, iobase);
-
-			/*  Interrupt on DMA */
-			new_ier |= IER_DMA_IE;
-		} else {
-			/* Check if DMA has now finished */
-			pc87108_dma_receive_complete( idev, iobase);
-
-			new_ier |= IER_SFIF_IE;
-		}
-	}	
-	/* Finished with transmission */
-	if ( eir & EIR_DMA_EV) {
-		pc87108_dma_xmit_complete( idev);
-		
-		/* Check if there are more frames to be transmitted */
-		if ( irda_device_txqueue_empty( idev)) {
-			/* Prepare for receive */
-			pc87108_dma_receive( idev);
-			
-			new_ier = IER_LS_IE|IER_SFIF_IE;
-		}
-	}
-	outb( bank, iobase+BSR);
-
-	return new_ier;
-}
-
-/*
- * Function pc87108_interrupt (irq, dev_id, regs)
- *
- *    An interrupt from the chip has arrived. Time to do some work
- *
- */
-static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	__u8 bsr, eir, ier;
-	int iobase;
-
-	struct irda_device *idev = (struct irda_device *) dev_id;
-
-	if (idev == NULL) {
-		printk( KERN_WARNING "%s: irq %d for unknown device.\n", 
-			driver_name, irq);
-		return;
-	}
-
-	idev->netdev.interrupt = 1;
-
-	iobase = idev->io.iobase;
-
-	/* Save current bank */
-	bsr = inb( iobase+BSR);
-
-	switch_bank( iobase, BANK0);	
-	ier = inb( iobase+IER); 
-	eir = inb( iobase+EIR) & ier; /* Mask out the interesting ones */ 
-
-	outb( 0, iobase+IER); /* Disable interrupts */
-	
-	if ( eir) {
-		/* Dispatch interrupt handler for the current speed */
-		if ( idev->io.baudrate > 115200)
-			ier = pc87108_fir_interrupt( idev, iobase, eir);
-		else
-			ier = pc87108_sir_interrupt( idev, eir);
-	}
-
-	outb( ier, iobase+IER);   /* Restore interrupts */
-	outb( bsr, iobase+BSR);   /* Restore bank register */
-
-	idev->netdev.interrupt = 0;
-}
-
-/*
- * Function pc87108_wait_until_sent (idev)
- *
- *    This function should put the current thread to sleep until all data 
- *    have been sent, so it is safe to f.eks. change the speed.
- */
-static void pc87108_wait_until_sent( struct irda_device *idev)
-{
-	/* Just delay 60 ms */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(6);
-}
-
-/*
- * Function pc87108_is_receiving (idev)
- *
- *    Return TRUE is we are currently receiving a frame
- *
- */
-static int pc87108_is_receiving( struct irda_device *idev)
-{
-	int status = FALSE;
-	int iobase;
-	__u8 bank;
-
-	ASSERT( idev != NULL, return FALSE;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
-
-	if ( idev->io.baudrate > 115200) {
-		iobase = idev->io.iobase;
-
-		/* Check if rx FIFO is not empty */
-		bank = inb( iobase+BSR);
-		switch_bank( iobase, BANK2);
-		if (( inb( iobase+RXFLV) & 0x3f) != 0) {
-			/* We are receiving something */
-			status =  TRUE;
-		}
-		outb( bank, iobase+BSR);
-	} else 
-		status = ( idev->rx_buff.state != OUTSIDE_FRAME);
-	
-	return status;
-}
-
-/*
- * Function pc87108_net_init (dev)
- *
- *    Initialize network device
- *
- */
-static int pc87108_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;
-}
-
-
-/*
- * Function pc87108_net_open (dev)
- *
- *    Start the device
- *
- */
-static int pc87108_net_open( struct device *dev)
-{
-	struct irda_device *idev;
-	int iobase;
-	__u8 bank;
-	
-	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;);
-	
-	iobase = idev->io.iobase;
-
-	if (request_irq( idev->io.irq, pc87108_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;
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-	
-	/* turn on interrupts */
-	switch_bank( iobase, BANK0);
-	outb( IER_LS_IE | IER_RXHDL_IE, iobase+IER);
-
-	/* Restore bank register */
-	outb( bank, iobase+BSR);
-
-	MOD_INC_USE_COUNT;
-
-	return 0;
-}
-
-/*
- * Function pc87108_net_close (dev)
- *
- *    Stop the device
- *
- */
-static int pc87108_net_close(struct device *dev)
-{
-	struct irda_device *idev;
-	int iobase;
-	__u8 bank;
-
-	DEBUG( 4, __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);
-
-	/* Save current bank */
-	bank = inb( iobase+BSR);
-
-	/* Disable interrupts */
-	switch_bank( iobase, BANK0);
-	outb( 0, iobase+IER); 
-       
-	free_irq( idev->io.irq, idev);
-	free_dma( idev->io.dma);
-
-	/* Restore bank register */
-	outb( bank, iobase+BSR);
-
-	MOD_DEC_USE_COUNT;
-
-	return 0;
-}
-
-#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)
- *
- *    
- *
- */
-int init_module(void)
-{
-	return pc87108_init();
-}
-
-/*
- * Function cleanup_module (void)
- *
- *    
- *
- */
-void cleanup_module(void)
-{
-	pc87108_cleanup();
-}
-#endif /* MODULE */
-
diff -urN linux-2.2.15-pre2/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
--- linux-2.2.15-pre2/drivers/net/irda/smc-ircc.c	Mon Jun  7 16:19:59 1999
+++ linux/drivers/net/irda/smc-ircc.c	Mon Dec  3 21:57:53 2001
@@ -1,26 +1,35 @@
 /*********************************************************************
  *                
  * Filename:      smc-ircc.c
- * Version:       0.1
- * Description:   Driver for the SMC Infrared Communications Controller (SMC)
+ * Version:       0.3
+ * Description:   Driver for the SMC Infrared Communications Controller
  * Status:        Experimental.
  * Author:        Thomas Davis (tadavis@jps.net)
  * Created at:    
- * Modified at:   Wed May 19 15:30:08 1999
+ * Modified at:   Fri Jan 14 15:39:14 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Thomas Davis, All Rights Reserved.
+ *     Copyright (c) 1999-2000 Dag Brattli
+ *     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.
+ * 
+ *     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
  *
- *     Applicable Models : Fujitsu Lifebook 635t
- *			   Sony PCG-505TX (gets DMA wrong.)
+ *     SIO's: SMC FDC37N869, FDC37C669
+ *     Applicable Models : Fujitsu Lifebook 635t, Sony PCG-505TX
  *
  ********************************************************************/
 
@@ -33,14 +42,17 @@
 #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 <linux/rtnetlink.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
 #include <net/irda/wrapper.h>
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
@@ -54,46 +66,40 @@
 
 #define CHIP_IO_EXTENT 8
 
-static unsigned int io[]  = { 0x2e8, 0x140, ~0, ~0 };
-static unsigned int io2[] = { 0x2f8, 0x3e8, 0, 0};
+static unsigned int io[]  = { ~0, ~0 }; 
+static unsigned int io2[] = { 0, 0 };
 
-static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL};
+static struct ircc_cb *dev_self[] = { 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 int  ircc_open(int i, unsigned int iobase, unsigned int board_addr);
+#ifdef MODULE
+static int  ircc_close(struct ircc_cb *self);
+#endif /* MODULE */
+static int  ircc_probe(int iobase, int board_addr);
+static int  ircc_probe_smc(int cfg_base, int *ioaddr, int *ioaddr2);
+static int  ircc_dma_receive(struct ircc_cb *self); 
+static int  ircc_dma_receive_complete(struct ircc_cb *self, int iobase);
+static int  ircc_hard_xmit(struct sk_buff *skb, struct device *dev);
+static void ircc_dma_xmit(struct ircc_cb *self, int iobase);
+static void ircc_change_speed(void *priv, __u32 speed);
 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_is_receiving(struct ircc_cb *self);
+
+static int  ircc_net_open(struct device *dev);
+static int  ircc_net_close(struct device *dev);
+#ifdef CONFIG_APM
+static int  ircc_apmproc(apm_event_t event);
+#endif /* CONFIG_APM */
 
-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)
+static inline void register_bank(int iobase, int bank)
 {
-        outb(value, port+offset);
+        outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)),
+               iobase+IRCC_MASTER);
 }
 
 /*
@@ -102,21 +108,33 @@
  *    Initialize chip. Just try to find out how many chips we are dealing with
  *    and where they are
  */
-__initfunc(int ircc_init(void))
+int __init ircc_init(void)
 {
+	static int smcreg[] = { 0x3f0, 0x370 };
+	int fir_base, sir_base;
+	int ret = -ENODEV;
+	int conf_reg;
 	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");
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	return -ENODEV;
+        for (i=0; i<2; i++) {
+		conf_reg = smcreg[i];
+		
+                /* First we check if the user has supplied parameters */
+                if (io[i] < 2000) {
+                         fir_base = io[i];
+                         sir_base = io2[i];
+                } else if (ircc_probe_smc(conf_reg, &fir_base, &sir_base) < 0)
+                        continue;
+		if (check_region(fir_base, CHIP_IO_EXTENT) < 0)
+                        continue;
+                if (check_region(sir_base, CHIP_IO_EXTENT) < 0)
+                        continue;
+		if (ircc_open(i, fir_base, sir_base) == 0)
+                        ret = 0; 
+	}
+	return ret;
 }
 
 /*
@@ -130,13 +148,12 @@
 {
 	int i;
 
-	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	for ( i=0; i < 4; i++) {
-		if ( dev_self[i])
-			ircc_close( &(dev_self[i]->idev));
+	for (i=0; i < 2; i++) {
+		if (dev_self[i])
+			ircc_close(dev_self[i]);
 	}
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
 }
 #endif /* MODULE */
 
@@ -146,166 +163,217 @@
  *    Open driver instance
  *
  */
-static int ircc_open( int i, unsigned int iobase, unsigned int iobase2)
+static int ircc_open(int i, unsigned int fir_base, unsigned int sir_base)
 {
 	struct ircc_cb *self;
-	struct irda_device *idev;
-	int ret;
+        struct irport_cb *irport;
 	int config;
+	int ret;
 
-	DEBUG( ircc_debug, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	if ((config = ircc_probe( iobase, iobase2)) == -1) {
-	        DEBUG(ircc_debug, 
-		      __FUNCTION__ ": addr 0x%04x - no device found!\n", iobase);
+	if ((config = ircc_probe(fir_base, sir_base)) == -1) {
+	        IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), addr 0x%04x - no device found!\n", fir_base);
 		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");
+	self = kmalloc(sizeof(struct ircc_cb), GFP_KERNEL);
+	if (self == NULL) {
+		ERROR("%s, Can't allocate memory for control block!\n",
+                      driver_name);
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct ircc_cb));
+	spin_lock_init(&self->lock);
    
 	/* Need to store self somewhere */
 	dev_self[i] = self;
 
-	idev = &self->idev;
+	irport = irport_open(i, sir_base, config >> 4 & 0x0f);
+	if (!irport)
+		return -ENODEV;
+
+	/* Steal the network device from irport */
+	self->netdev = irport->netdev;
+	self->irport = irport;
+	irport->priv = self;
 
 	/* Initialize IO */
-	idev->io.iobase    = iobase;
-        idev->io.iobase2   = iobase2; /* Used by irport */
-        idev->io.irq       = config >> 4 & 0x0f;
+	self->io.fir_base  = fir_base;
+        self->io.sir_base  = sir_base; /* Used by irport */
+        self->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;
+	        MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
+			driver_name, self->io.irq, ircc_irq);
+		self->io.irq = ircc_irq;
+	}
+        self->io.fir_ext   = CHIP_IO_EXTENT;
+        self->io.sir_ext   = 8;       /* Used by irport */
+        self->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;
+	        MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
+			driver_name, self->io.dma, ircc_dma);
+		self->io.dma = ircc_dma;
 	}
-        idev->io.fifo_size = 16;
+        self->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);  */
+	ret = check_region(self->io.fir_base, self->io.fir_ext);
+	if (ret < 0) { 
+		IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n",
+			   self->io.fir_base);
+                kfree(self);
 		return -ENODEV;
 	}
-	request_region( idev->io.iobase, idev->io.io_ext, idev->name);
-        request_region( idev->io.iobase2, idev->io.io_ext2, idev->name);
+	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 
 	/* Initialize QoS for this device */
-	irda_init_max_qos_capabilies( &idev->qos);
+	irda_init_max_qos_capabilies(&irport->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|
+	irport->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);
+	irport->qos.min_turn_time.bits = 0x07;
+	irda_qos_bits_to_value(&irport->qos);
 
-	idev->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO;
+	irport->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;
+	self->rx_buff.truesize = 4000; 
+	self->tx_buff.truesize = 4000;
+
+	self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
+					      GFP_KERNEL|GFP_DMA);
+	if (self->rx_buff.head == NULL)
+		return -ENOMEM;
+	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
 	
-	/* 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;
+	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+					      GFP_KERNEL|GFP_DMA);
+	if (self->tx_buff.head == NULL) {
+		kfree(self->rx_buff.head);
+		return -ENOMEM;
+	}
+	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
 
-	irport_start(idev, iobase2);
+	self->rx_buff.in_frame = FALSE;
+	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	/* Override the speed change function, since we must control it now */
+	irport->change_speed = &ircc_change_speed;
+	irport->interrupt    = &ircc_interrupt;
+	self->netdev->open   = &ircc_net_open;
+	self->netdev->stop   = &ircc_net_close;
+
+	irport_start(self->irport);
 
-	/* Open the IrDA device */
-	irda_device_open( idev, driver_name, self);
-	
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
 	return 0;
 }
 
 /*
- * Function ircc_close (idev)
+ * Function ircc_close (self)
  *
  *    Close driver instance
  *
  */
-static int ircc_close( struct irda_device *idev)
+#ifdef MODULE
+static int ircc_close(struct ircc_cb *self)
 {
 	int iobase;
 
-	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	ASSERT( idev != NULL, return -1;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
 
-        iobase = idev->io.iobase;
+        iobase = self->io.fir_base;
 
-	irport_stop(idev, idev->io.iobase2);
+	irport_close(self->irport);
 
+	/* Stop interrupts */
 	register_bank(iobase, 0);
-	serial_out(iobase, UART_IER, 0);
-	serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+	outb(0, iobase+IRCC_IER);
+	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
 
+#if 0
+	/* Reset to SIR mode */
 	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);
- 
+        outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
+        outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
+#endif
 	/* Release the PORT that this driver is using */
-	DEBUG( ircc_debug, 
-	       __FUNCTION__ ": releasing 0x%03x\n", idev->io.iobase);
+	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", 
+		   self->io.fir_base);
 
-	release_region( idev->io.iobase, idev->io.io_ext);
+	release_region(self->io.fir_base, self->io.fir_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);
-	}
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
 
-	irda_device_close( idev);
+	kfree(self);
 
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
 	return 0;
 }
+#endif /* MODULE */
+
+/*
+ * Function ircc_probe_smc (ioaddr, ioaddr2)
+ *
+ *    Probe the SMC Chip for an IrDA port
+ *
+ */
+static int ircc_probe_smc(int cfg_base, int *fir_base, int *sir_base)
+{
+	__u8 devid, mode;
+	int ret = -ENODEV;
+	int fir_io;
+	
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	/* Enter configuration */
+	outb(0x55, cfg_base);
+	outb(0x55, cfg_base);
+	
+	outb(0x0d, cfg_base);
+	devid = inb(cfg_base+1);
+	IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
+	
+	/* Check for expected device ID; are there others? */
+	if (devid == 0x29 || devid == 0x04) {    
+		outb(0x0c, cfg_base);
+		mode = inb(cfg_base+1);
+		mode = (mode & 0x38) >> 3;
+		
+		/* Value for IR port */
+		if (mode && mode < 4) {
+			/* SIR iobase */
+			outb(0x25, cfg_base);
+			*sir_base = inb(cfg_base+1) << 2;
+
+		       	/* FIR iobase */
+			outb(0x2b, cfg_base);
+			fir_io = inb(cfg_base+1) << 3;
+			if (fir_io) {
+				ret = 0;
+				*fir_base = fir_io;
+			}
+		}
+	}
+	
+	/* Exit configuration */
+	outb(0xaa, cfg_base);
+
+	return ret;
+}
 
 /*
  * Function ircc_probe (iobase, board_addr, irq, dma)
@@ -313,135 +381,135 @@
  *    Returns non-negative on success.
  *
  */
-static int ircc_probe( int iobase, int iobase2) 
+static int ircc_probe(int fir_base, int sir_base) 
 {
-	int version = 1;
 	int low, high, chip, config, dma, irq;
-	
-	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	int iobase = fir_base;
+	int version = 1;
+
+	IRDA_DEBUG(0, __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);
+	high = inb(iobase+IRCC_ID_HIGH);
+	low = inb(iobase+IRCC_ID_LOW);
+	chip = inb(iobase+IRCC_CHIP_ID);
+	version = inb(iobase+IRCC_VERSION);
+	config = inb(iobase+IRCC_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 {
+        if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) { 
+                MESSAGE("SMC IrDA Controller found; IrCC version %d.%d, "
+			"port 0x%03x, dma=%d, irq=%d\n",
+			chip & 0x0f, version, iobase, dma, irq);
+	} else
 		return -1;
-	}
-
-	serial_out(iobase, UART_MASTER, 0);
 
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	/* Power on device */
+	outb(0, iobase+IRCC_MASTER);
 
 	return config;
 }
 
 /*
- * Function ircc_change_speed (idev, baud)
+ * Function ircc_change_speed (self, baud)
  *
  *    Change the speed of the device
  *
  */
-static void ircc_change_speed( struct irda_device *idev, int speed)
+static void ircc_change_speed(void *priv, __u32 speed)
 {
-	struct ircc_cb *self;
-	int iobase, ir_mode, select, fast; 
+	int iobase, ir_mode, ctrl, fast; 
+	struct ircc_cb *self = (struct ircc_cb *) priv;
+	struct device *dev;
 
-	DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(self != NULL, return;);
 
-	self = idev->priv;
-	iobase = idev->io.iobase;
+	dev = self->netdev;
+	iobase = self->io.fir_base;
 
 	/* Update accounting for new speed */
-	idev->io.baudrate = speed;
+	self->io.speed = speed;
+
+	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
 
-	switch ( speed) {
+	switch (speed) {
 	case 9600:
 	case 19200:
-	case 37600:
+	case 38400:
 	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;
+	case 115200:		
+		ir_mode = IRCC_CFGA_IRDA_SIR_A;
+		ctrl = 0;
+		fast = 0;
 		break;
-
 	case 576000:		
-		ir_mode = UART_CFGA_IRDA_HDLC;
-		select = 0;
+		ir_mode = IRCC_CFGA_IRDA_HDLC;
+		ctrl = IRCC_CRC;
 		fast = 0;
-		DEBUG( ircc_debug, __FUNCTION__ ": handling baud of 576000\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
 		break;
 	case 1152000:
-		ir_mode = UART_CFGA_IRDA_HDLC;
-		select = UART_1152;
+		ir_mode = IRCC_CFGA_IRDA_HDLC;
+		ctrl = IRCC_1152 | IRCC_CRC;
 		fast = 0;
-		DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 1152000\n");
+		IRDA_DEBUG(0, __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");
+		ir_mode = IRCC_CFGA_IRDA_4PPM;
+		ctrl = IRCC_CRC;
+		fast = IRCC_LCR_A_FAST;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ ": unknown baud rate of %d\n", speed);
+		IRDA_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));
+	register_bank(iobase, 0);
+	outb(0, iobase+IRCC_IER);
+	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
 
-	serial_out(iobase, UART_SCE_CFGB,
-		   ((serial_in(iobase, UART_SCE_CFGB) & 0x3f) | UART_CFGB_IR));
+	/* Make special FIR init if necessary */
+	if (speed > 115200) {
+		irport_stop(self->irport);
 
-	(void) serial_in(iobase, UART_FIFO_THRESHOLD);
-	serial_out(iobase, UART_FIFO_THRESHOLD, 64);
+		/* Install FIR transmit handler */
+		dev->hard_start_xmit = &ircc_hard_xmit;
+	} else {
+		/* Install SIR transmit handler */
+		dev->hard_start_xmit = &irport_hard_xmit;
+		irport_start(self->irport);
+		
+	        IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), using irport to change speed to %d\n", speed);
+		irport_change_speed(self->irport, speed);
+	}	
+	dev->tbusy = 0;
+#if 0	
+	register_bank(iobase, 1);
+	outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), 
+	     iobase+IRCC_SCE_CFGA);
 
+#ifdef SMC_669 /* Uses pin 88/89 for Rx/Tx */
+	outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), 
+	     iobase+IRCC_SCE_CFGB);
+#else	
+	outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+	     iobase+IRCC_SCE_CFGB);
+#endif	
+	(void) inb(iobase+IRCC_FIFO_THRESHOLD);
+	outb(64, iobase+IRCC_FIFO_THRESHOLD);
+	
 	register_bank(iobase, 4);
-
-	serial_out(iobase, UART_CONTROL,
-		   (serial_in(iobase, UART_CONTROL) & 0x30) 
-		   | select | UART_CRC );
-
+	outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);
+	
 	register_bank(iobase, 0);
-
-	serial_out(iobase, UART_LCR_A, fast);
-
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	outb(fast, iobase+IRCC_LCR_A);
+#endif
 }
 
 /*
@@ -450,270 +518,242 @@
  *    Transmit the frame!
  *
  */
-static int ircc_hard_xmit( struct sk_buff *skb, struct device *dev)
+static int ircc_hard_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct irda_device *idev;
+	struct irport_cb *irport;
+	struct ircc_cb *self;
 	int iobase;
 	int mtt;
+	__u32 speed;
 
-	DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
-	idev = (struct irda_device *) dev->priv;
+	irport = (struct irport_cb *) dev->priv;
+	self = (struct ircc_cb *) irport->priv;
 
-	ASSERT( idev != NULL, return 0;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+	ASSERT(self != NULL, return 0;);
 
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
-	DEBUG(ircc_debug+1, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len);
+	IRDA_DEBUG(2, __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);
-	}
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
 	
-	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);
+	memcpy(self->tx_buff.head, skb->data, skb->len);
 
 	/* Make sure that the length is a multiple of 16 bits */
-	if ( skb->len & 0x01)
+	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);
+	self->tx_buff.len = skb->len;
+	self->tx_buff.data = self->tx_buff.head;
 	
-	/* Use udelay for delays less than 50 us. */
-	if (mtt)
-		udelay( mtt);
+	mtt = irda_get_mtt(skb);	
+	if (mtt) {
+		/* OH BUGGER ME! */
+		udelay(mtt);
+	}
 	
-	ircc_dma_write( idev, iobase);
+	ircc_dma_xmit(self, iobase);
 	
-	dev_kfree_skb( skb);
+	dev_kfree_skb(skb);
 
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
 	return 0;
 }
 
 /*
- * Function ircc_dma_xmit (idev, iobase)
+ * Function ircc_dma_xmit (self, iobase)
  *
  *    Transmit data using DMA
  *
  */
-static void ircc_dma_write( struct irda_device *idev, int iobase)
+static void ircc_dma_xmit(struct ircc_cb *self, int iobase)
 {
-	struct ircc_cb *self;
-
-	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(2, __FUNCTION__ "\n");
 
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(self != NULL, return;);
 
-	self = idev->priv;
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
-	setup_dma( idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
-		   DMA_MODE_WRITE);
+	setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, 
+		  DMA_TX_MODE);
 	
-	idev->io.direction = IO_XMIT;
-
-	serial_out(idev->io.iobase2, 4, 0x08);
+	self->io.direction = IO_XMIT;
 
+ 	outb(0x08, self->io.sir_base+4);
+	
 	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);
+	outb((inb(iobase+IRCC_CONTROL) & 0xf0), iobase+IRCC_CONTROL);
+	
+	outb(2, iobase+IRCC_BOF_COUNT_LO);
+	outb(0, iobase+IRCC_BRICKWALL_CNT_LO);
 #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);
+	outb(self->tx_buff.len >> 8, iobase+IRCC_BRICKWALL_TX_CNT_HI);
+	outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
 #else
-	serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0);
-	serial_out(iobase, UART_TX_SIZE_LO, 0);
+	outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI);
+	outb(0, iobase+IRCC_TX_SIZE_LO);
 #endif
 
 	register_bank(iobase, 1);
-	serial_out(iobase, UART_SCE_CFGB,
-		   serial_in(iobase, UART_SCE_CFGB) | UART_CFGB_DMA_ENABLE);
+	outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE,
+	     iobase+IRCC_SCE_CFGB);
 
 	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);
+	outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
+	outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
 
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
 }
 
 /*
- * Function ircc_dma_xmit_complete (idev)
+ * Function ircc_dma_xmit_complete (self)
  *
  *    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)
+static void ircc_dma_xmit_complete(struct ircc_cb *self, 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;);
+	IRDA_DEBUG(2, __FUNCTION__ "\n");
 
-	register_bank(idev->io.iobase, 1);
+	ASSERT(self != NULL, return;);
 
-	serial_out(idev->io.iobase, UART_SCE_CFGB,
-		   serial_in(idev->io.iobase, UART_SCE_CFGB) &
-		   ~UART_CFGB_DMA_ENABLE);
+	register_bank(self->io.fir_base, 1);
 
-	d = get_dma_residue(idev->io.dma);
+	outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & IRCC_CFGB_DMA_ENABLE,
+	     self->io.fir_base+IRCC_SCE_CFGB);
 
-	DEBUG(ircc_debug, __FUNCTION__ ": dma residue = %d, len=%d, sent=%d\n", 
-	      d, idev->tx_buff.len, idev->tx_buff.len - d);
+	d = get_dma_residue(self->io.dma);
 
-	self = idev->priv;
+	IRDA_DEBUG(0, __FUNCTION__ 
+		   ": dma residue = %d, len=%d, sent=%d\n", 
+		   d, self->tx_buff.len, self->tx_buff.len - d);
 
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Check for underrrun! */
-	if ( underrun) {
-		idev->stats.tx_errors++;
-		idev->stats.tx_fifo_errors++;		
+	if (underrun) {
+		self->irport->stats.tx_errors++;
+		self->irport->stats.tx_fifo_errors++;		
 	} else {
-		idev->stats.tx_packets++;
-		idev->stats.tx_bytes +=  idev->tx_buff.len;
+		self->irport->stats.tx_packets++;
+		self->irport->stats.tx_bytes +=  self->tx_buff.len;
+	}
+
+	if (self->new_speed) {
+		ircc_change_speed(self, self->new_speed);
+		
+		self->new_speed = 0;
 	}
 
 	/* Unlock tx_buff and request another frame */
-	idev->netdev.tbusy = 0; /* Unlock */
-	idev->media_busy = FALSE;
+	self->netdev->tbusy = 0; /* Unlock */
 	
 	/* Tell the network layer, that we can accept more frames */
-	mark_bh( NET_BH);
-
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	mark_bh(NET_BH);
 }
 
 /*
- * Function ircc_dma_receive (idev)
+ * Function ircc_dma_receive (self)
  *
  *    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) 
+static int ircc_dma_receive(struct ircc_cb *self) 
 {
-	struct ircc_cb *self;
 	int iobase;
 
-	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(2, __FUNCTION__ "\n");
 
-	ASSERT( idev != NULL, return -1;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
 
-	self = idev->priv;
-	iobase= idev->io.iobase;
+	iobase= self->io.fir_base;
 
-	setup_dma( idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, 
-		   DMA_MODE_READ);
+	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
+		   DMA_RX_MODE);
 	
 	/* driver->media_busy = FALSE; */
-	idev->io.direction = IO_RECV;
-	idev->rx_buff.data = idev->rx_buff.head;
+	self->io.direction = IO_RECV;
+	self->rx_buff.data = self->rx_buff.head;
 #if 0
-	idev->rx_buff.offset = 0;
+	self->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);
+	outb(inb(iobase+IRCC_CONTROL) & 0xf0, iobase+IRCC_CONTROL);
+	outb(2, iobase+IRCC_BOF_COUNT_LO);
+	outb(0, iobase+IRCC_BRICKWALL_CNT_LO);
+	outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI);
+	outb(0, iobase+IRCC_TX_SIZE_LO);
+	outb(0, iobase+IRCC_RX_SIZE_HI);
+	outb(0, iobase+IRCC_RX_SIZE_LO);
 
 	register_bank(iobase, 0);
-	serial_out(iobase, 
-		   UART_LCR_B, UART_LCR_B_SCE_RECEIVE | UART_LCR_B_SIP_ENABLE);
+	outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, 
+	     iobase+IRCC_LCR_B);
 	
 	register_bank(iobase, 1);
-	serial_out(iobase, UART_SCE_CFGB,
-		   serial_in(iobase, UART_SCE_CFGB) | 
-		   UART_CFGB_DMA_ENABLE | UART_CFGB_DMA_BURST);
+	outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | 
+	     IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
 
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
 	return 0;
 }
 
 /*
- * Function ircc_dma_receive_complete (idev)
+ * Function ircc_dma_receive_complete (self)
  *
  *    Finished with receiving frames
  *
  *    
  */
-static int ircc_dma_receive_complete( struct irda_device *idev, int iobase)
+static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
 {
 	struct sk_buff *skb;
-	struct ircc_cb *self;
 	int len, msgcnt;
 
-	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(2, __FUNCTION__ "\n");
 
-	self = idev->priv;
+	msgcnt = inb(self->io.fir_base+IRCC_LCR_B) & 0x08;
 
-	msgcnt = serial_in(idev->io.iobase, UART_LCR_B) & 0x08;
+	IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n",
+		   get_dma_residue(self->io.dma));
 
-	DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n",
-	      get_dma_residue(idev->io.dma));
+	len = self->rx_buff.truesize - get_dma_residue(self->io.dma) - 4;
 
-	len = idev->rx_buff.truesize - get_dma_residue(idev->io.dma) - 4;
+	IRDA_DEBUG(0, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
 
-	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");
+	skb = dev_alloc_skb(len+1);
+	if (!skb)  {
+		WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n");
 		return FALSE;
 	}
 			
 	/* Make sure IP header gets aligned */
-	skb_reserve( skb, 1); 
-	skb_put( skb, len);
+	skb_reserve(skb, 1); 
+	skb_put(skb, len);
 
-	memcpy(skb->data, idev->rx_buff.data, len);
-	idev->stats.rx_packets++;
+	memcpy(skb->data, self->rx_buff.data, len);
+	self->irport->stats.rx_packets++;
 
-	skb->dev = &idev->netdev;
+	skb->dev = self->netdev;
 	skb->mac.raw  = skb->data;
 	skb->protocol = htons(ETH_P_IRDA);
-	netif_rx( skb);
+	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);
+	register_bank(self->io.fir_base, 1);
+	outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
+	     self->io.fir_base+IRCC_SCE_CFGB);
 
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
 	return TRUE;
 }
 
@@ -725,176 +765,126 @@
  */
 static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct device *dev = (struct device *) dev_id;
+	struct irport_cb *irport;
+	struct ircc_cb *self;
 	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);
+	if (dev == 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);
+	irport = (struct irport_cb *) dev->priv;
+	self = (struct ircc_cb *) irport->priv;
+
+	/* Check if we should use the SIR interrupt handler */
+	if (self->io.speed < 576000) {
+		irport_interrupt(irq, dev_id, regs);
+		return;
 	}
 
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
-	idev->netdev.interrupt = 1;
+	dev->interrupt = 1;
 
-	serial_out(iobase, UART_MASTER, 0);
+	outb(0, iobase+IRCC_MASTER);
 
 	register_bank(iobase, 0);
+	iir = inb(iobase+IRCC_IIR);
 
-	iir = serial_in(iobase, UART_IIR);
+	/* Disable interrupts */
+	outb(0, iobase+IRCC_IER);
 
-	serial_out(iobase, UART_IER, 0);
+	IRDA_DEBUG(0, __FUNCTION__ "(), iir = 0x%02x\n", iir);
 
-	DEBUG(ircc_debug, __FUNCTION__ ": iir = 0x%02x\n", iir);
+	if (iir & IRCC_IIR_EOM) {
+	        IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_EOM\n");
 
-	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 (self->io.direction == IO_RECV)
+			ircc_dma_receive_complete(self, iobase);
+		else
+			ircc_dma_xmit_complete(self, iobase);
+		
+		ircc_dma_receive(self);
 	}
-
-	if (iir & UART_IIR_ACTIVE_FRAME) {
-	        DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_ACTIVE_FRAME\n");
-		idev->rx_buff.state = INSIDE_FRAME;
+	if (iir & IRCC_IIR_ACTIVE_FRAME) {
+	        IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_ACTIVE_FRAME\n");
+		self->rx_buff.state = INSIDE_FRAME;
 #if 0
-		ircc_dma_receive(idev);
+		ircc_dma_receive(self);
 #endif
 	}
-
-	if (iir & UART_IIR_RAW_MODE) {
-		DEBUG(ircc_debug, __FUNCTION__ ": IIR RAW mode interrupt.\n");
+	if (iir & IRCC_IIR_RAW_MODE) {
+		IRDA_DEBUG(0, __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");
-}
+	outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
+	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
 
-/*
- * 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");
+	dev->interrupt = 0;
 }
 
 /*
- * Function ircc_is_receiving (idev)
+ * Function ircc_is_receiving (self)
  *
  *    Return TRUE is we are currently receiving a frame
  *
  */
-static int ircc_is_receiving( struct irda_device *idev)
+static int ircc_is_receiving(struct ircc_cb *self)
 {
 	int status = FALSE;
 	/* int iobase; */
 
-	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	ASSERT( idev != NULL, return FALSE;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	ASSERT(self != NULL, return FALSE;);
 
-	DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n",
-	      get_dma_residue(idev->io.dma));
+	IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n",
+		   get_dma_residue(self->io.dma));
 
-	status = ( idev->rx_buff.state != OUTSIDE_FRAME);
+	status = (self->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)
+static int ircc_net_open(struct device *dev)
 {
-	struct irda_device *idev;
+	struct irport_cb *irport;
+	struct ircc_cb *self;
 	int iobase;
+
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 	
-	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;);
+	ASSERT(dev != NULL, return -1;);
+	irport = (struct irport_cb *) dev->priv;
+	self = (struct ircc_cb *) irport->priv;
+
+	ASSERT(self != NULL, return 0;);
 	
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
+
+	irport_net_open(dev); /* irport allocates the irq */
 
-	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);
+	if (request_dma(self->io.dma, dev->name)) {
+		irport_net_close(dev);
+
 		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;
 }
 
@@ -906,64 +896,108 @@
  */
 static int ircc_net_close(struct device *dev)
 {
-	struct irda_device *idev;
+	struct irport_cb *irport;
+	struct ircc_cb *self;
 	int iobase;
 
-	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 	
-	/* Stop device */
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	ASSERT( dev != NULL, return -1;);
-	idev = (struct irda_device *) dev->priv;
+	ASSERT(dev != NULL, return -1;);
+	irport = (struct irport_cb *) dev->priv;
+	self = (struct ircc_cb *) irport->priv;
 	
-	ASSERT( idev != NULL, return 0;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+	ASSERT(self != NULL, return 0;);
 	
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
-	disable_dma( idev->io.dma);
+	irport_net_close(dev);
 
-	/* Disable interrupts */
-       
-	free_irq( idev->io.irq, idev);
-	free_dma( idev->io.dma);
+	disable_dma(self->io.dma);
+
+	free_dma(self->io.dma);
 
 	MOD_DEC_USE_COUNT;
 
-	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
 	return 0;
 }
 
-#ifdef MODULE
+#ifdef CONFIG_APM
+static void ircc_suspend(struct ircc_cb *self)
+{
+	int i = 10;
 
+	MESSAGE("%s, Suspending\n", driver_name);
+
+	if (self->io.suspended)
+		return;
+
+	ircc_net_close(self->netdev);
+
+	self->io.suspended = 1;
+}
+
+static void ircc_wakeup(struct ircc_cb *self)
+{
+	struct device *dev = self->netdev;
+	unsigned long flags;
+
+	if (!self->io.suspended)
+		return;
+
+	save_flags(flags);
+	cli();
+
+	ircc_net_open(self->netdev);
+	
+	restore_flags(flags);
+	MESSAGE("%s, Waking up\n", driver_name);
+}
+
+static int ircc_apmproc(apm_event_t event)
+{
+	static int down = 0;          /* Filter out double events */
+	int i;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (!down) {			
+			for (i=0; i<4; i++) {
+				if (dev_self[i])
+					nsc_ircc_suspend(dev_self[i]);
+			}
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (down) {
+			for (i=0; i<4; i++) {
+				if (dev_self[i])
+					nsc_ircc_wakeup(dev_self[i]);
+			}
+		}
+		down = 0;
+		break;
+	}
+	return 0;
+}
+#endif /* CONFIG_APM */
+
+#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
+#endif /* MODULE */
diff -urN linux-2.2.15-pre2/drivers/net/irda/tekram.c linux/drivers/net/irda/tekram.c
--- linux-2.2.15-pre2/drivers/net/irda/tekram.c	Mon Jun  7 16:19:59 1999
+++ linux/drivers/net/irda/tekram.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Sun May 16 14:33:42 1999
+ * Modified at:   Fri Dec 17 09:13:09 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -29,15 +29,14 @@
 #include <linux/init.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 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);
-static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos);
+static void tekram_open(dongle_t *self, struct qos_info *qos);
+static void tekram_close(dongle_t *self);
+static int  tekram_change_speed(struct irda_task *task);
+static int  tekram_reset(struct irda_task *task);
 
 #define TEKRAM_115200 0x00
 #define TEKRAM_57600  0x01
@@ -47,16 +46,16 @@
 
 #define TEKRAM_PW     0x10 /* Pulse select bit */
 
-static struct dongle dongle = {
-	TEKRAM_DONGLE,
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_TEKRAM_DONGLE,
 	tekram_open,
 	tekram_close,
 	tekram_reset,
 	tekram_change_speed,
-	tekram_init_qos,
 };
 
-__initfunc(int tekram_init(void))
+int __init tekram_init(void)
 {
 	return irda_device_register_dongle(&dongle);
 }
@@ -66,26 +65,34 @@
 	irda_device_unregister_dongle(&dongle);
 }
 
-static void tekram_open(struct irda_device *idev, int type)
+static void tekram_open(dongle_t *self, struct qos_info *qos)
 {
-	strcat(idev->description, " <-> tekram");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */	
+	irda_qos_bits_to_value(qos);
 
-	idev->io.dongle_id = type;
-	idev->flags |= IFF_DONGLE;
-	
 	MOD_INC_USE_COUNT;
 }
 
-static void tekram_close(struct irda_device *idev)
-{		
+static void tekram_close(dongle_t *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
 	/* Power off dongle */
-	irda_device_set_dtr_rts(idev, FALSE, FALSE);
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	if (self->reset_task)
+		irda_task_delete(self->reset_task);
+	if (self->speed_task)
+		irda_task_delete(self->speed_task);
 
 	MOD_DEC_USE_COUNT;
 }
 
 /*
- * Function tekram_change_speed (tty, baud)
+ * Function tekram_change_speed (dev, state, speed)
  *
  *    Set the speed for the Tekram IRMate 210 type dongle. Warning, this 
  *    function must be called with a process context!
@@ -100,16 +107,24 @@
  *    6. wait at least 50 us, new setting (baud rate, etc) takes effect here 
  *       after
  */
-static void tekram_change_speed(struct irda_device *idev, int baud)
+static int tekram_change_speed(struct irda_task *task)
 {
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
 	__u8 byte;
+	int ret = 0;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(task != NULL, return -1;);
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	if (self->speed_task && self->speed_task != task) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		return MSECS_TO_JIFFIES(10);
+	} else
+		self->speed_task = task;
 
-	switch (baud) {
+	switch (speed) {
 	default:
 	case 9600:
 		byte = TEKRAM_PW|TEKRAM_9600;
@@ -124,28 +139,62 @@
 		byte = TEKRAM_PW|TEKRAM_57600;
 		break;
 	case 115200:
-		byte = TEKRAM_PW|TEKRAM_115200;
+		byte = TEKRAM_115200;
 		break;
 	}
 
-	/* Need to reset the dongle and go to 9600 bps before programming */
-	tekram_reset(idev);
-	
-	/* Set DTR, Clear RTS */
-	irda_device_set_dtr_rts(idev, TRUE, FALSE);
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+	case IRDA_TASK_CHILD_INIT:		
+		/* 
+		 * Need to reset the dongle and go to 9600 bps before
+                 * programming 
+		 */
+		if (irda_task_execute(self, tekram_reset, NULL, task, 
+				      (void *) speed))
+		{
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give reset 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		} else
+			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+		break;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
+		break;
+	case IRDA_TASK_CHILD_DONE:
+		/* Set DTR, Clear RTS */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
 	
-	/* Wait at least 7us */
-	udelay(7);
+		/* Wait at least 7us */
+		udelay(14);
 
-	/* Write control byte */
-	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 */
-	irda_device_set_dtr_rts(idev, TRUE, TRUE);
+		/* Write control byte */
+		self->write(self->dev, &byte, 1);
+		
+		irda_task_next_state(task, IRDA_TASK_WAIT);
+
+		/* Wait at least 100 ms */
+		ret = MSECS_TO_JIFFIES(150);
+		break;
+	case IRDA_TASK_WAIT:
+		/* Set DTR, Set RTS */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
 }
 
 /*
@@ -161,50 +210,61 @@
  *        3. clear DTR to SPACE state, wait at least 50 us for further 
  *         operation
  */
-void tekram_reset(struct irda_device *idev)
+int tekram_reset(struct irda_task *task)
 {
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	dongle_t *self = (dongle_t *) task->instance;
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(task != NULL, return -1;);
+
+	if (self->reset_task && self->reset_task != task) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		return MSECS_TO_JIFFIES(10);
+	} else
+		self->reset_task = task;
 	
 	/* Power off dongle */
-	irda_device_set_dtr_rts(idev, FALSE, FALSE);
-
-	/* Sleep 50 ms */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(50));
+	//self->set_dtr_rts(self->dev, FALSE, FALSE);
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
 
-	/* Clear DTR, Set RTS */
-	irda_device_set_dtr_rts(idev, FALSE, TRUE); 
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
 
-	/* Should sleep 1 ms, but 10-20 should not do any harm */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(20));
+		/* Sleep 50 ms */
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT1:
+		/* Clear DTR, Set RTS */
+		self->set_dtr_rts(self->dev, FALSE, TRUE); 
 
-	/* Set DTR, Set RTS */
-	irda_device_set_dtr_rts(idev, TRUE, TRUE);
-	
-	udelay(50);
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		
+		/* Should sleep 1 ms */
+		ret = MSECS_TO_JIFFIES(1);
+		break;
+	case IRDA_TASK_WAIT2:
+		/* Set DTR, Set RTS */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
 	
-	/* Make sure the IrDA chip also goes to defalt speed */
-	if (idev->change_speed)
-		idev->change_speed(idev, 9600);
-}
+		/* Wait at least 50 us */
+		udelay(75);
 
-/*
- * Function tekram_init_qos (qos)
- *
- *    Initialize QoS capabilities
- *
- */
-static void tekram_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 &= 0x01; /* Needs at least 10 ms */
-	irda_qos_bits_to_value(qos);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);		
+		self->reset_task = NULL;
+		ret = -1;
+	}
+	return ret;
 }
 
 #ifdef MODULE
-
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver");
 		
@@ -229,5 +289,4 @@
 {
         tekram_cleanup();
 }
-
 #endif /* MODULE */
diff -urN linux-2.2.15-pre2/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- linux-2.2.15-pre2/drivers/net/irda/toshoboe.c	Mon Aug  9 12:04:39 1999
+++ linux/drivers/net/irda/toshoboe.c	Mon Dec  3 21:57:53 2001
@@ -7,8 +7,10 @@
  * Status:        Experimental.
  * Author:        James McKenzie <james@fishsoup.dhs.org>
  * Created at:    Sat May 8  12:35:27 1999
+ * Modified:      Paul Bristow <paul.bristow@technologist.com>
+ * Modified:      Mon Nov 11 19:10:05 1999
  * 
- *     Copyright (c) 1999 James McKenzie, All Rights Reserved.
+ *     Copyright (c) 1999-2000 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 
@@ -28,32 +30,13 @@
 /* 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
- * 
- */
+static char *rcsid = "$Id: toshoboe.c,v 1.91 1999/06/29 14:21:06 root Exp $";
 
 /* 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
+#define ONETASK 
 
 /* To adjust the number of tasks in use edit toshoboe.h */
 
@@ -83,6 +66,7 @@
 #include <linux/malloc.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/rtnetlink.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -93,6 +77,10 @@
 #include <net/irda/irlap_frame.h>
 #include <net/irda/irda_device.h>
 
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
 #include <net/irda/toshoboe.h>
 
 static char *driver_name = "toshoboe";
@@ -100,11 +88,13 @@
 static struct toshoboe_cb *dev_self[NSELFS + 1] =
 {NULL, NULL, NULL, NULL, NULL};
 
+static int max_baud = 4000000;
+
 /* Shutdown the chip and point the taskfile reg somewhere else */
-static void 
+static void
 toshoboe_stopchip (struct toshoboe_cb *self)
 {
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
   outb_p (0x0e, OBOE_REG_11);
 
@@ -117,16 +107,19 @@
   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 
+static void
 toshoboe_setbaud (struct toshoboe_cb *self, int baud)
 {
-  DEBUG (4, __FUNCTION__ "()\n");
+  unsigned long flags;
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
-  printk (KERN_WARNING "ToshOboe: seting baud to %d\n", baud);
+  printk (KERN_WARNING "ToshOboe: setting baud to %d\n", baud);
 
+  save_flags (flags);
   cli ();
   switch (baud)
     {
@@ -177,21 +170,22 @@
       break;
     }
 
-  sti ();
+  restore_flags (flags);
 
   outb_p (0x00, OBOE_RST);
   outb_p (0x80, OBOE_RST);
   outb_p (0x01, OBOE_REG_9);
 
+  self->io.speed = baud;
 }
 
 /* Wake the chip up and get it looking at the taskfile */
-static void 
+static void
 toshoboe_startchip (struct toshoboe_cb *self)
 {
   __u32 physaddr;
 
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
 
   outb_p (0, OBOE_LOCK);
@@ -217,19 +211,19 @@
 }
 
 /*Let the chip look at memory */
-static void 
+static void
 toshoboe_enablebm (struct toshoboe_cb *self)
 {
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
   pci_set_master (self->pdev);
 }
 
 /*Don't let the chip look at memory */
-static void 
+static void
 toshoboe_disablebm (struct toshoboe_cb *self)
 {
   __u8 command;
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
   pci_read_config_byte (self->pdev, PCI_COMMAND, &command);
   command &= ~PCI_COMMAND_MASTER;
@@ -238,13 +232,15 @@
 }
 
 /*setup the taskfile */
-static void 
+static void
 toshoboe_initbuffs (struct toshoboe_cb *self)
 {
   int i;
+  unsigned long flags;
 
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
+  save_flags (flags);
   cli ();
 
   for (i = 0; i < TX_SLOTS; ++i)
@@ -261,25 +257,30 @@
       self->taskfile->recv[i].buffer = virt_to_bus (self->recv_bufs[i]);
     }
 
-  sti ();
+  restore_flags (flags);
 }
 
-
 /*Transmit something */
-static int 
+static int
 toshoboe_hard_xmit (struct sk_buff *skb, struct device *dev)
 {
-  struct irda_device *idev;
   struct toshoboe_cb *self;
+  __u32 speed;
   int mtt, len;
 
-  idev = (struct irda_device *) dev->priv;
-  ASSERT (idev != NULL, return 0;);
-  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+  self = (struct toshoboe_cb *) dev->priv;
+
+  ASSERT (self != NULL, return 0;
+    );
 
-  self = idev->priv;
-  ASSERT (self != NULL, return 0;);
+  /* Check if we need to change the speed */
+  if ((speed = irda_get_speed(skb)) != self->io.speed)
+	  self->new_speed = speed;
 
+  if (self->stopped) {
+	  dev_kfree_skb(skb);
+    return 0;
+  }
 
 #ifdef ONETASK
   if (self->txpending)
@@ -343,27 +344,21 @@
 }
 
 /*interrupt handler */
-static void 
+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;
+  struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
   __u8 irqstat;
   struct sk_buff *skb;
 
-  if (idev == NULL)
+  if (self == 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");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
   irqstat = inb_p (OBOE_ISR);
 
@@ -379,12 +374,17 @@
     {
       self->txpending--;
 
-      idev->stats.tx_packets++;
+      self->stats.tx_packets++;
 
-      idev->media_busy = FALSE;
-      idev->netdev.tbusy = 0;
+      if (self->new_speed) {
+	      toshoboe_setbaud(self, self->new_speed);
 
-      mark_bh (NET_BH);
+	      self->new_speed = 0;
+      }
+      self->netdev->tbusy = 0; /* Unlock */
+      
+      /* Tell network layer that we want more frames */
+      mark_bh(NET_BH);
     }
 
   if (irqstat & OBOE_ISR_RXDONE)
@@ -399,8 +399,9 @@
 #endif
         {
           int len = self->taskfile->recv[self->rxs].len;
-	
-	  if (len>2) len-=2;
+
+          if (len > 2)
+            len -= 2;
 
           skb = dev_alloc_skb (len + 1);
           if (skb)
@@ -410,8 +411,8 @@
               skb_put (skb, len);
               memcpy (skb->data, self->recv_bufs[self->rxs], len);
 
-              idev->stats.rx_packets++;
-              skb->dev = &idev->netdev;
+              self->stats.rx_packets++;
+              skb->dev = self->netdev;
               skb->mac.raw = skb->data;
               skb->protocol = htons (ETH_P_IRDA);
             }
@@ -421,8 +422,6 @@
                       "(), memory squeeze, dropping frame.\n");
             }
 
-
-
           self->taskfile->recv[self->rxs].control = 0x83;
           self->taskfile->recv[self->rxs].len = 0x0;
 
@@ -448,76 +447,18 @@
     {
       /*FIXME: I think this is a TX or RX error of some sort */
 
-      idev->stats.tx_errors++;
-      idev->stats.rx_errors++;
+      self->stats.tx_errors++;
+      self->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 
+static int
 toshoboe_net_init (struct device *dev)
 {
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
   /* Setup to be a normal IrDA network device driver */
   irda_device_setup (dev);
@@ -527,37 +468,12 @@
 }
 
 
-
-
-static int 
-toshoboe_net_open (struct device *dev)
+static void 
+toshoboe_initptrs (struct toshoboe_cb *self)
 {
-  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);
-
 
+  unsigned long flags;
+  save_flags (flags);
   cli ();
 
   /*FIXME: need to test this carefully to check which one */
@@ -580,45 +496,88 @@
 
   self->txpending = 0;
 
-  sti ();
+  restore_flags (flags);
+
+}
 
 
+static int
+toshoboe_net_open (struct device *dev)
+{
+  struct toshoboe_cb *self;
+
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (dev != NULL, return -1;
+    );
+  self = (struct toshoboe_cb *) dev->priv;
+
+  ASSERT (self != NULL, return 0;
+    );
+
+  if (self->stopped)
+    return 0;
+
+  if (request_irq (self->io.irq, toshoboe_interrupt,
+                   SA_SHIRQ | SA_INTERRUPT, dev->name, (void *) self))
+    {
+
+      return -EAGAIN;
+    }
+
+  toshoboe_initbuffs (self);
+  toshoboe_enablebm (self);
+  toshoboe_startchip (self);
+  toshoboe_initptrs (self);
+
+  /* Ready to play! */
   dev->tbusy = 0;
   dev->interrupt = 0;
   dev->start = 1;
+  
+  /* 
+   * Open new IrLAP layer instance, now that everything should be
+   * initialized properly 
+   */
+  self->irlap = irlap_open(dev, &self->qos);	
 
+  self->open = 1;
+	
   MOD_INC_USE_COUNT;
 
   return 0;
 
 }
 
-static int 
+static int
 toshoboe_net_close (struct device *dev)
 {
-  struct irda_device *idev;
   struct toshoboe_cb *self;
 
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_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;);
+  ASSERT (dev != NULL, return -1;
+    );
+  self = (struct toshoboe_cb *) dev->priv;
 
+  /* Stop device */
   dev->tbusy = 1;
   dev->start = 0;
+  
+  /* Stop and remove instance of IrLAP */
+  if (self->irlap)
+	  irlap_close(self->irlap);
+  self->irlap = NULL;
 
+  self->open = 0;
 
-  self = idev->priv;
-
-  ASSERT (self != NULL, return 0;);
+  free_irq (self->io.irq, (void *) self);
 
-  free_irq (idev->io.irq, (void *) idev);
-
-  toshoboe_stopchip (self);
-  toshoboe_disablebm (self);
+  if (!self->stopped)
+    {
+      toshoboe_stopchip (self);
+      toshoboe_disablebm (self);
+    }
 
   MOD_DEC_USE_COUNT;
 
@@ -626,28 +585,73 @@
 
 }
 
+/*
+ * Function toshoboe_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+static int toshoboe_net_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct toshoboe_cb *self;
+	unsigned long flags;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = dev->priv;
 
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		/* toshoboe_setbaud(self, irq->ifr_baudrate); */
+                /* Just change speed once - inserted by Paul Bristow */
+	        self->new_speed = irq->ifr_baudrate;
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = 0; /* Can't tell */
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
 
 #ifdef MODULE
 
-static int 
-toshoboe_close (struct irda_device *idev)
+MODULE_PARM (max_baud, "i");
+
+static int
+toshoboe_close (struct toshoboe_cb *self)
 {
-  struct toshoboe_cb *self;
   int i;
 
-  DEBUG (4, __FUNCTION__ "()\n");
-
-  ASSERT (idev != NULL, return -1;);
-  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
-  self = idev->priv;
+  ASSERT (self != NULL, return -1;
+    );
 
-  ASSERT (self != NULL, return -1;);
-
-  toshoboe_stopchip (self);
+  if (!self->stopped)
+    {
+      toshoboe_stopchip (self);
+      toshoboe_disablebm (self);
+    }
 
-  release_region (idev->io.iobase, idev->io.io_ext);
+  release_region (self->io.sir_base, self->io.sir_ext);
 
 
   for (i = 0; i < TX_SLOTS; ++i)
@@ -662,14 +666,19 @@
       self->recv_bufs[i] = NULL;
     }
 
+  if (self->netdev) {
+	  /* Remove netdevice */
+	  rtnl_lock();
+	  unregister_netdevice(self->netdev);
+	  rtnl_unlock();
+	  /* Must free the old-style 2.2.x device */
+	  kfree(self->netdev);
+  }
 
   kfree (self->taskfilebuf);
   self->taskfilebuf = NULL;
   self->taskfile = NULL;
 
-
-  irda_device_close (idev);
-
   return (0);
 
 }
@@ -678,16 +687,16 @@
 
 
 
-static int 
+static int
 toshoboe_open (struct pci_dev *pci_dev)
 {
   struct toshoboe_cb *self;
-  struct irda_device *idev;
+  struct device *dev;
   int i = 0;
-  int ok=0;
+  int ok = 0;
+  int err;
 
-
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
   while (dev_self[i])
     i++;
@@ -709,26 +718,24 @@
 
   memset (self, 0, sizeof (struct toshoboe_cb));
 
+  dev_self[i] = self;           /*This needs moving if we ever get more than one chip */
 
-  dev_self[i] = self;
-
+  self->open = 0;
+  self->stopped = 0;
   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;
+  self->io.sir_base = self->base;
+  self->io.irq = pci_dev->irq;
+  self->io.sir_ext = CHIP_IO_EXTENT;
+  self->io.speed = 9600;
 
   /* Lock the port that we need */
-  i = check_region (idev->io.iobase, idev->io.io_ext);
+  i = check_region (self->io.sir_base, self->io.sir_ext);
   if (i < 0)
     {
-      DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-             idev->io.iobase);
+      IRDA_DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+             self->io.sir_base);
 
       dev_self[i] = NULL;
       kfree (self);
@@ -736,55 +743,52 @@
       return -ENODEV;
     }
 
-  request_region (idev->io.iobase, idev->io.io_ext, driver_name);
 
-  irda_init_max_qos_capabilies (&idev->qos);
+  irda_init_max_qos_capabilies (&self->qos);
+  self->qos.baud_rate.bits = 0;
 
-  idev->qos.baud_rate.bits = IR_2400 | /*IR_4800 | */ IR_9600 | IR_19200 |
-    IR_115200;
+  if (max_baud >= 2400)
+    self->qos.baud_rate.bits |= IR_2400;
+  /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */
+  if (max_baud >= 9600)
+    self->qos.baud_rate.bits |= IR_9600;
+  if (max_baud >= 19200)
+    self->qos.baud_rate.bits |= IR_19200;
+  if (max_baud >= 115200)
+    self->qos.baud_rate.bits |= IR_115200;
 #ifdef ENABLE_FAST
- idev->qos.baud_rate.bits|= IR_576000 | IR_1152000 | (IR_4000000 << 8);
+  if (max_baud >= 576000)
+    self->qos.baud_rate.bits |= IR_576000;
+  if (max_baud >= 1152000)
+    self->qos.baud_rate.bits |= IR_1152000;
+  if (max_baud >= 4000000)
+    self->qos.baud_rate.bits |= (IR_4000000 << 8);
 #endif
 
-  idev->qos.min_turn_time.bits = 0xff;  /*FIXME: what does this do? */
 
-  irda_qos_bits_to_value (&idev->qos);
+  self->qos.min_turn_time.bits = 0xff;  /*FIXME: what does this do? */
 
-  idev->flags = IFF_SIR | IFF_DMA | IFF_PIO;
+  irda_qos_bits_to_value (&self->qos);
+
+  self->flags = IFF_SIR | IFF_DMA | IFF_PIO;
 
 #ifdef ENABLE_FAST
-  idev->flags |= IFF_FIR;
+  if (max_baud >= 576000)
+    self->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;
-  }
+  self->taskfilebuf = kmalloc (OBOE_TASK_BUF_LEN, GFP_KERNEL);
+  if (!self->taskfilebuf)
+    {
+      printk (KERN_ERR "toshoboe: kmalloc for DMA failed()\n");
+      kfree (self);
+      return -ENOMEM;
+    }
 
 
   memset (self->taskfilebuf, 0, OBOE_TASK_BUF_LEN);
@@ -803,29 +807,61 @@
   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++;
+      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 (self->recv_bufs[i])
+        ok++;
     }
 
-  if (ok!=RX_SLOTS+TX_SLOTS) {
-	printk(KERN_ERR  "toshoboe: kmalloc for buffers failed()\n");
+  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]);
 
-  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;
 
-	kfree(self);
-	return -ENOMEM;
+    }
 
-  }
+  request_region (self->io.sir_base, self->io.sir_ext, driver_name);
 
+  if (!(dev = dev_alloc("irda%d", &err))) {
+	  ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+	  return -ENOMEM;
+  }
+  /* dev_alloc doesn't clear the struct, so lets do a little hack */
+  memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct device)-sizeof(char*));
 
-  irda_device_open (idev, driver_name, self);
+  dev->priv = (void *) self;
+  self->netdev = dev;
+  
+  MESSAGE("IrDA: Registered device %s\n", dev->name);
+
+  dev->init = toshoboe_net_init;
+  dev->hard_start_xmit = toshoboe_hard_xmit;
+  dev->open = toshoboe_net_open;
+  dev->stop = toshoboe_net_close;
+  dev->do_ioctl = toshoboe_net_ioctl;
+
+  rtnl_lock();
+  err = register_netdevice(dev);
+  rtnl_unlock();
+  if (err) {
+	  ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+	  return -1;
+  }
 
   printk (KERN_WARNING "ToshOboe: Using ");
 #ifdef ONETASK
@@ -838,7 +874,119 @@
   return (0);
 }
 
-__initfunc (int toshoboe_init (void))
+#ifdef CONFIG_APM
+static void 
+toshoboe_gotosleep (struct toshoboe_cb *self)
+{
+  int i = 10;
+
+  printk (KERN_WARNING "ToshOboe: suspending\n");
+
+  if (self->stopped)
+    return;
+
+  self->stopped = 1;
+
+  if (!self->open)
+    return;
+
+/*FIXME: can't sleep here wait one second */
+
+  while ((i--) && (self->txpending))
+    udelay (100000);
+
+  toshoboe_stopchip (self);
+  toshoboe_disablebm (self);
+
+  self->txpending = 0;
+
+}
+
+
+static void 
+toshoboe_wakeup (struct toshoboe_cb *self)
+{
+  struct device *dev = self->netdev;
+  unsigned long flags;
+
+  if (!self->stopped)
+    return;
+
+  if (!self->open)
+    {
+      self->stopped = 0;
+      return;
+    }
+
+  save_flags (flags);
+  cli ();
+
+  toshoboe_initbuffs (self);
+  toshoboe_enablebm (self);
+  toshoboe_startchip (self);
+
+  toshoboe_setbaud (self, self->io.speed);
+
+  toshoboe_initptrs (self);
+
+  dev->tbusy = 0;
+  dev->interrupt = 0;
+  dev->start = 1;
+  self->stopped = 0;
+
+  restore_flags (flags);
+  printk (KERN_WARNING "ToshOboe: waking up\n");
+
+}
+
+static int 
+toshoboe_apmproc (apm_event_t event)
+{
+  static int down = 0;          /*Filter out double events */
+  int i;
+
+  switch (event)
+    {
+    case APM_SYS_SUSPEND:
+    case APM_USER_SUSPEND:
+      if (!down)
+        {
+
+          for (i = 0; i < 4; i++)
+            {
+              if (dev_self[i])
+                toshoboe_gotosleep (dev_self[i]);
+            }
+
+        }
+      down = 1;
+      break;
+    case APM_NORMAL_RESUME:
+    case APM_CRITICAL_RESUME:
+      if (down)
+        {
+
+
+
+          for (i = 0; i < 4; i++)
+            {
+              if (dev_self[i])
+                toshoboe_wakeup (dev_self[i]);
+            }
+
+
+
+        }
+      down = 0;
+      break;
+    }
+  return 0;
+}
+
+
+#endif
+
+int __init toshoboe_init (void)
 {
   struct pci_dev *pci_dev = NULL;
   int found = 0;
@@ -860,38 +1008,49 @@
     }
   while (pci_dev);
 
+
   if (found)
-    return 0;
+    {
+#ifdef CONFIG_APM
+      apm_register_callback (toshoboe_apmproc);
+#endif
+      return 0;
+    }
 
   return -ENODEV;
 }
 
 #ifdef MODULE
 
-static void 
+static void
 toshoboe_cleanup (void)
 {
   int i;
 
-  DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
   for (i = 0; i < 4; i++)
     {
       if (dev_self[i])
-        toshoboe_close (&(dev_self[i]->idev));
+        toshoboe_close (dev_self[i]);
     }
+
+#ifdef CONFIG_APM
+  apm_unregister_callback (toshoboe_apmproc);
+#endif
+
 }
 
 
 
-int 
+int
 init_module (void)
 {
   return toshoboe_init ();
 }
 
 
-void 
+void
 cleanup_module (void)
 {
   toshoboe_cleanup ();
diff -urN linux-2.2.15-pre2/drivers/net/irda/uircc.c linux/drivers/net/irda/uircc.c
--- linux-2.2.15-pre2/drivers/net/irda/uircc.c	Mon Jun  7 16:19:59 1999
+++ linux/drivers/net/irda/uircc.c	Wed Dec 31 16:00:00 1969
@@ -1,953 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      uircc.c
- * Version:       0.3
- * Description:   Driver for the Sharp Universal Infrared 
- *                Communications Controller (UIRCC v 1.3)
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Dec 26 10:59:03 1998
- * Modified at:   Wed May 19 15:29:56 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
- *      
- *     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.
- *
- *     Applicable Models : Tecra 510CDT, 500C Series, 530CDT, 520CDT,
- *     740CDT, Portege 300CT, 660CDT, Satellite 220C Series, 
- *     Satellite Pro, 440C Series, 470CDT, 460C Series, 480C Series
- *
- ********************************************************************/
-
-#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/uircc.h>
-#include <net/irda/irport.h>
-
-static char *driver_name = "uircc";
-
-#define CHIP_IO_EXTENT 16
-
-static unsigned int io[]  = { 0x300, ~0, ~0, ~0 };
-static unsigned int io2[] = { 0x3e8, 0, 0, 0};
-static unsigned int irq[] = { 11, 0, 0, 0 };
-static unsigned int dma[] = { 5, 0, 0, 0 };
-
-static struct uircc_cb *dev_self[] = { NULL, NULL, NULL, NULL};
-
-/* Some prototypes */
-static int  uircc_open(int i, unsigned int iobase, unsigned int board_addr, 
-		       unsigned int irq, unsigned int dma);
-#ifdef MODULE
-static int  uircc_close(struct irda_device *idev);
-#endif /* MODULE */
-static int  uircc_probe(int iobase, int board_addr, int irq, int dma);
-static int  uircc_dma_receive(struct irda_device *idev); 
-static int  uircc_dma_receive_complete(struct irda_device *idev, int iobase);
-static int  uircc_hard_xmit(struct sk_buff *skb, struct device *dev);
-static void uircc_dma_write(struct irda_device *idev, int iobase);
-static void uircc_change_speed(struct irda_device *idev, int baud);
-static void uircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void uircc_wait_until_sent(struct irda_device *idev);
-static int  uircc_is_receiving(struct irda_device *idev);
-static int uircc_toshiba_cmd(int *retval, int arg0, int arg1, int arg2);
-static int  uircc_net_init(struct device *dev);
-static int  uircc_net_open(struct device *dev);
-static int  uircc_net_close(struct device *dev);
-
-/*
- * Function uircc_init ()
- *
- *    Initialize chip. Just try to find out how many chips we are dealing with
- *    and where they are
- */
-__initfunc(int uircc_init(void))
-{
-	int i;
-
-	for ( i=0; (io[i] < 2000) && (i < 4); i++) {
-		int ioaddr = io[i];
-		if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
-			continue;
-		if (uircc_open(i, io[i], io2[i], irq[i], dma[i]) == 0)
-			return 0;
-	}
-	return -ENODEV;
-}
-
-/*
- * Function uircc_cleanup ()
- *
- *    Close all configured chips
- *
- */
-#ifdef MODULE
-static void uircc_cleanup(void)
-{
-	int i;
-
-        DEBUG(4, __FUNCTION__ "()\n");
-
-	for (i=0; i < 4; i++) {
-		if (dev_self[i])
-			uircc_close(&(dev_self[i]->idev));
-	}
-}
-#endif /* MODULE */
-
-/*
- * Function uircc_open (iobase, irq)
- *
- *    Open driver instance
- *
- */
-static int uircc_open(int i, unsigned int iobase, unsigned int iobase2, 
-		      unsigned int irq, unsigned int dma)
-{
-	struct uircc_cb *self;
-	struct irda_device *idev;
-	int ret;
-
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	if ((uircc_probe(iobase, iobase2, irq, dma)) == -1)
-		return -1;
-	
-	/*
-	 *  Allocate new instance of the driver
-	 */
-	self = kmalloc( sizeof(struct uircc_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 uircc_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       = irq;
-        idev->io.io_ext    = CHIP_IO_EXTENT;
-        idev->io.io_ext2   = 8;       /* Used by irport */
-        idev->io.dma       = 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);
-		/* uircc_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);
-		/* uircc_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);
-	
-	/* 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 = 0x0f;
-	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    = uircc_change_speed;
-	idev->wait_until_sent = uircc_wait_until_sent;
-	idev->is_receiving    = uircc_is_receiving;
-     
-	/* Override the network functions we need to use */
-	idev->netdev.init            = uircc_net_init;
-	idev->netdev.hard_start_xmit = uircc_hard_xmit;
-	idev->netdev.open            = uircc_net_open;
-	idev->netdev.stop            = uircc_net_close;
-
-	irport_start(idev, iobase2);
-
-	/* Open the IrDA device */
-	irda_device_open(idev, driver_name, self);
-	
-	return 0;
-}
-
-/*
- * Function uircc_close (idev)
- *
- *    Close driver instance
- *
- */
-#ifdef MODULE
-static int uircc_close(struct irda_device *idev)
-{
-	struct uircc_cb *self;
-	int iobase;
-	int status;
-
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(idev != NULL, return -1;);
-	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);
-
-	/* Disable modem */
-	outb(0x00, iobase+UIRCC_CR10);
-
-	irport_stop(idev, idev->io.iobase2);
-
-	/* 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);
-
-	if (idev->io.iobase2) {
-		DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", 
-		      idev->io.iobase2);
-		release_region(idev->io.iobase2, idev->io.io_ext2);
-	}
-	irda_device_close(idev);
-
-	kfree(self);
-
-	return 0;
-}
-#endif /* MODULE */
-
-/*
- * Function uircc_probe (iobase, board_addr, irq, dma)
- *
- *    Returns non-negative on success.
- *
- */
-static int uircc_probe(int iobase, int iobase2, int irq, int dma) 
-{
-	int version;
-	
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	/* read the chip version, should be 0x03 */
-	version = inb(iobase+UIRCC_SR8);
-
-	if (version != 0x03) {
-		DEBUG(0, __FUNCTION__ "(), Wrong chip version");	
-		return -1;
-	}
-        printk(KERN_INFO "Sharp UIRCC IrDA driver loaded. Version: 0x%02x\n",
-	       version);
-
-	/* Reset chip */
-	outb(UIRCC_CR0_SYS_RST, iobase+UIRCC_CR0);
-
-	/* Initialize some registers */
-	outb(0x03, iobase+UIRCC_CR15);
-	outb(0, iobase+UIRCC_CR11);
-	outb(0, iobase+UIRCC_CR9);
-
-	DEBUG(0, __FUNCTION__ "(), sr15=%#x\n", inb(iobase+UIRCC_SR15));
-
-	/* Enable DMA single mode */
-	outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, 
-	     iobase+UIRCC_CR1);
-
-	/* Disable interrupts */
-	outb(0xff, iobase+UIRCC_CR2); 
-
-	/* Set self poll address */
-
-	return 0;
-}
-
-/*
- * Function uircc_change_speed (idev, baud)
- *
- *    Change the speed of the device
- *
- */
-static void uircc_change_speed(struct irda_device *idev, int speed)
-{
-	struct uircc_cb *self;
-	int iobase; 
-	int modem = UIRCC_CR10_SIR;
-	int status;
-
-	DEBUG(0, __FUNCTION__ "()\n");
-
-	/* Just test the high speed stuff */
-	/*speed = 4000000;*/
-
-	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;
-
-	/* Disable interrupts */	
-	outb(0xff, iobase+UIRCC_CR2);
-
-	switch (speed) {
-	case 9600:
-	case 19200:
-	case 37600:
-	case 57600:
-	case 115200:
- 		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);
-
-		modem = UIRCC_CR10_SIR;
-		break;
-	case 576000:		
-		
-		DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
-		break;
-	case 1152000:
-
-		DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
-		break;
-	case 4000000:
-		irport_stop(idev, idev->io.iobase2);
-
-		/* Some magic to disable SIR and enable FIR */
-		uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001);
-
-		modem = UIRCC_CR10_FIR;
-		DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
-
-		/* Set self pole address */
-		//outb(0xfe, iobase+UIRCC_CR8);
-
-	 	/* outb(0x10, iobase+UIRCC_CR11); */
-		break;
-	default:
-		DEBUG( 0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
-		break;
-	}
-
-	/* Set appropriate speed mode */
-	outb(modem, iobase+UIRCC_CR10);
-
-	idev->netdev.tbusy = 0;
-	
-	/* Enable some interrupts so we can receive frames */
-	if (speed > 115200) {
-		/* Enable DMA single mode */
-		outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, 
-		     iobase+UIRCC_CR1);
-
- 		/* Enable all interrupts  */
-		outb(0, iobase+UIRCC_CR2); 
- 		uircc_dma_receive(idev);
- 	}    	
-}
-
-/*
- * Function uircc_hard_xmit (skb, dev)
- *
- *    Transmit the frame!
- *
- */
-static int uircc_hard_xmit(struct sk_buff *skb, struct device *dev)
-{
-	struct irda_device *idev;
-	int iobase;
-	int mtt;
-	
-	idev = (struct irda_device *) dev->priv;
-
-	ASSERT(idev != NULL, return 0;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);
-
-	iobase = idev->io.iobase;
-
-	DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len);
-	
-	/* Reset carrier latch */
-	/*outb(0x02, iobase+UIRCC_CR0);*/
-
-	/* Use irport for SIR speeds */
-	if (idev->io.baudrate <= 115200) {
-		return irport_hard_xmit(skb, dev);
-	}
-	
-	DEBUG(0, __FUNCTION__ "(), sr0=%#x, sr1=%#x, sr2=%#x, sr3=%#x, sr10=%#x, sr11=%#x\n",
-	      inb(iobase+UIRCC_SR0), inb(iobase+UIRCC_SR3),
-	      inb(iobase+UIRCC_SR2), inb(iobase+UIRCC_SR3), 
-	      inb(iobase+UIRCC_SR10), inb(iobase+UIRCC_SR11));
-
-	/* Lock transmit buffer */
-	if (irda_lock((void *) &dev->tbusy) == FALSE)
-		return -EBUSY;
-
-	memcpy(idev->tx_buff.data, 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;
-	
-	mtt = irda_get_mtt(skb);
-	
-	/* Use udelay for delays less than 50 us. */
-	if (mtt)
-		udelay(mtt);
-	
-	/* Enable transmit interrupts */
- 	outb(0, iobase+UIRCC_CR2);
-
-	uircc_dma_write(idev, iobase);
-	
-	dev_kfree_skb(skb);
-
-	return 0;
-}
-
-/*
- * Function uircc_dma_write (idev, iobase)
- *
- *    Transmit data using DMA
- *
- */
-static void uircc_dma_write(struct irda_device *idev, int iobase)
-{
-	struct uircc_cb *self;
-
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-
-	self = idev->priv;
-
-	/* Receiving disable */
-	self->cr3 &= ~UIRCC_CR3_RECV_EN;
-	outb(self->cr3, iobase+UIRCC_CR3);
-
-	/* Set modem */
-	outb(0x80, iobase+UIRCC_CR10);
-
-	/* Enable transmit DMA */
-	outb(UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, iobase+UIRCC_CR1);
-
-	ASSERT((((__u32)(idev->tx_buff.data)) & 0x01) != 0x01, return;);
-
-	setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
-		  DMA_MODE_WRITE);
-	
-	idev->io.direction = IO_XMIT;
-
-	/* Set frame length (should be the real length without padding */
-	outb(idev->tx_buff.len & 0xff, iobase+UIRCC_CR4); /* Low byte */
-	outb(idev->tx_buff.len >> 8, iobase+UIRCC_CR5);   /* High byte */
-
-	/* Enable transmit and transmit CRC */
-	self->cr3 |= (UIRCC_CR3_XMIT_EN|UIRCC_CR3_TX_CRC_EN);
-	outb(self->cr3, iobase+UIRCC_CR3);
-}
-
-/*
- * Function uircc_dma_xmit_complete (idev)
- *
- *    The transfer of a frame in finished. This function will only be called 
- *    by the interrupt handler
- *
- */
-static void uircc_dma_xmit_complete( struct irda_device *idev, int underrun)
-{
-	struct uircc_cb *self;
-	int iobase;
-	int len;
-
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-
-	self = idev->priv;
-
-	iobase = idev->io.iobase;
-
-	/* Select TX counter */
-	outb(UIRCC_CR0_CNT_SWT, iobase+UIRCC_CR0);
-
-	/* Read TX length counter */
-	len  = inb(iobase+UIRCC_SR4);      /* Low byte */
-	len |= inb(iobase+UIRCC_SR5) << 8; /* High byte */
-
-	DEBUG(4, __FUNCTION__ "(), sent %d bytes\n", len);
-
-	/* Disable transmit */
-	self->cr3 &= ~UIRCC_CR3_XMIT_EN;
-	outb(self->cr3, iobase+UIRCC_CR3);
-
-	/* Transmit reset (just to be sure) */
-	outb(UIRCC_CR0_XMIT_RST, iobase+UIRCC_CR0);
-	
-	/* 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);
-}
-
-/*
- * Function uircc_dma_receive (idev)
- *
- *    Get ready for receiving a frame. The device will initiate a DMA
- *    if it starts to receive a frame.
- *
- */
-static int uircc_dma_receive(struct irda_device *idev) 
-{
-	struct uircc_cb *self;
-	int iobase;
-
-	ASSERT(idev != NULL, return -1;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
-
-	DEBUG(4, __FUNCTION__ "\n");
-
-	self = idev->priv;
-	iobase= idev->io.iobase;
-
-	/* Transmit disable */
-	/* self->cr3 &= ~UIRCC_CR3_XMIT_EN; */
-	self->cr3 = 0;
-	outb(self->cr3, iobase+UIRCC_CR3);
-
-	/* Transmit reset (just in case) */
-	outb(UIRCC_CR0_XMIT_RST|0x17, iobase+UIRCC_CR0);
-
-	/* Set modem */
-	outb(0x08, iobase+UIRCC_CR10);
-
-	/* Enable receiving with CRC */
-	self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN);
-	outb(self->cr3, iobase+UIRCC_CR3);
-
-	/* Make sure Rx DMA is set */
- 	outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_MUST_SET, iobase+UIRCC_CR1);
-
-	/* Rx reset */
-	/* outb(UIRCC_CR0_RECV_RST, iobase+UIRCC_CR0); */
-
-	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
-	/* Enable receiving with CRC */
-	self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN);
-	outb(self->cr3, iobase+UIRCC_CR3);
-#endif
-	DEBUG(4, __FUNCTION__ "(), cr3=%#x\n", self->cr3);
-	
-	/* Address check? */
-
-	return 0;
-}
-
-/*
- * Function uircc_dma_receive_complete (idev)
- *
- *    Finished with receiving frames
- *
- *    
- */
-static int uircc_dma_receive_complete(struct irda_device *idev, int iobase)
-{
-	struct sk_buff *skb;
-	struct uircc_cb *self;
-	int len;
-
-	self = idev->priv;
-
-	DEBUG(0, __FUNCTION__ "()\n");
-
-	/* Check for CRC or framing error */
-	if (inb(iobase+UIRCC_SR0) & UIRCC_SR0_RX_CRCFRM) {
-		DEBUG(0, __FUNCTION__ "(), CRC or FRAME error\n");
-		return -1;
-	}
-
-	/* Select receive length counter */
-	outb(0x00, iobase+UIRCC_CR0);
-
-	/* Read frame length */
-	len = inb(iobase+UIRCC_SR4);       /* Low byte */
-	len |= inb(iobase+UIRCC_SR5) << 8; /* High byte */
-
-	DEBUG(0, __FUNCTION__ "(), len=%d\n", len);
-
-	/* Receiving disable */
-	self->cr3 &= ~UIRCC_CR3_RECV_EN;
-	outb(self->cr3, iobase+UIRCC_CR3);
-
-	skb = dev_alloc_skb(len+1);
-	if (skb == NULL)  {
-		printk(KERN_INFO __FUNCTION__ 
-		       "(), memory squeeze, dropping frame.\n");
-				/* Restore bank register */
-		return FALSE;
-	}
-			
-	/* Make sure IP header gets aligned */
-	skb_reserve(skb, 1);
-
-	/* Copy frame without CRC */
-	/* if ( idev->io.baudrate < 4000000) { */
-/* 		skb_put( skb, len-2); */
-/* 		memcpy( skb->data, idev->rx_buff.head, len-2); */
-/* 	} else { */
-/* 		skb_put( skb, len-4); */
-/* 		memcpy( skb->data, idev->rx_buff.head, len-4); */
-/* 	} */
-
-	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);
-
-	return TRUE;
-}
-
-/*
- * Function uircc_interrupt (irq, dev_id, regs)
- *
- *    An interrupt from the chip has arrived. Time to do some work
- *
- */
-static void uircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	__u8 sr3;
-	int iobase;
-
-	struct irda_device *idev = (struct irda_device *) dev_id;
-
-	if (idev == NULL) {
-		printk( KERN_WARNING "%s: irq %d for unknown device.\n", 
-			driver_name, irq);
-		return;
-	}
-	
-	if (idev->io.baudrate <= 115200)
-		return irport_interrupt( irq, dev_id, regs);
-
-	iobase = idev->io.iobase;
-
-	/* Read interrupt status */
-	sr3 = inb( iobase+UIRCC_SR3); 
-	if (!sr3) {
-		DEBUG(4,"**\n");
-		return;
-	}
-	idev->netdev.interrupt = 1;
-
-	DEBUG(4, __FUNCTION__ "(), sr3=%#x, sr2=%#x, sr10=%#x\n", 
-	      inb( iobase+UIRCC_SR3), inb( iobase+UIRCC_SR2), 
-	      inb( iobase+UIRCC_SR10));
-
-	/*
-	 *  Check what interrupt this is. The UIRCC will not report two
-	 *  different interrupts at the same time!
-	 */
-	switch(sr3) {
-	case UIRCC_SR3_RX_EOF: /* Check for end of frame */
-		uircc_dma_receive_complete(idev, iobase);
-		break;
-	case UIRCC_SR3_TXUR:   /* Check for transmit underrun */
-		uircc_dma_xmit_complete(idev, TRUE);
-		uircc_dma_receive(idev);
-		outb(0, iobase+UIRCC_CR2); 
-		break;
-	case UIRCC_SR3_TX_DONE:
-		uircc_dma_xmit_complete(idev, FALSE);
-		uircc_dma_receive(idev);
-
-		outb(0x0d, iobase+UIRCC_CR2);
-		break;
-	case UIRCC_SR3_TMR_OUT:
-		/* Disable timer */
-		outb(inb(iobase+UIRCC_CR11) & ~UIRCC_CR11_TMR_EN, 
-		     iobase+UIRCC_CR11);
-		break;
-	default:
-		DEBUG(0, __FUNCTION__ "(), unknown interrupt status=%#x\n",
-		      sr3);
-		break;
-	}	
-	idev->netdev.interrupt = 0;
-}
-
-/*
- * Function uircc_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 uircc_wait_until_sent( struct irda_device *idev)
-{
-	/* Just delay 60 ms */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(6);
-}
-
-/*
- * Function uircc_is_receiving (idev)
- *
- *    Return TRUE is we are currently receiving a frame
- *
- */
-static int uircc_is_receiving( struct irda_device *idev)
-{
-	int status = FALSE;
-	/* int iobase; */
-
-	ASSERT(idev != NULL, return FALSE;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
-
-	if (idev->io.baudrate > 115200) {
-		
-	} else 
-		status = (idev->rx_buff.state != OUTSIDE_FRAME);
-	
-	return status;
-}
-
-/*
- * Function uircc_net_init (dev)
- *
- *    Initialize network device
- *
- */
-static int uircc_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;
-}
-
-
-/*
- * Function uircc_net_open (dev)
- *
- *    Start the device
- *
- */
-static int uircc_net_open(struct device *dev)
-{
-	struct irda_device *idev;
-	int iobase;
-	
-	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;);
-	
-	iobase = idev->io.iobase;
-
-	if (request_irq(idev->io.irq, uircc_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;
-
-	return 0;
-}
-
-/*
- * Function uircc_net_close (dev)
- *
- *    Stop the device
- *
- */
-static int uircc_net_close(struct device *dev)
-{
-	struct irda_device *idev;
-	int iobase;
-
-	DEBUG(4, __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;
-
-	return 0;
-}
-
-/*
- * Function uircc_toshiba_cmd (arg0, arg1, arg2)
- *
- *    disable FIR: uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000);
- *    enable  FIR: uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001);
- *    IRDA status: uircc_toshiba_cmd(&status, 0xfefe, 0x001b, 0x0000);
- */
-static int uircc_toshiba_cmd(int *retval, int arg0, int arg1, int arg2)
-{
-	char return_code = 0;
-
-	__asm__ volatile ("inb   $0xb2,%%al; "
-			  "movb  %%ah,%%al;  "
-			  : /* Output */
-			  "=al"  (return_code),
-			  "=ecx" (*retval)
-			  : /* Input */
-			  "ax" (arg0),
-			  "bx" (arg1),
-			  "cx" (arg2)
-		);
-	/*
-	 * Return
-	 * 0x00 = OK
-	 * 0x80 = Function not supported by system
-	 * 0x83 = Input data error
-	 */
-	return (int) return_code;
-}
-
-#ifdef MODULE
-
-/*
- * Function init_module (void)
- *
- *    
- *
- */
-int init_module(void)
-{
-	return uircc_init();
-}
-
-/*
- * Function cleanup_module (void)
- *
- *    
- *
- */
-void cleanup_module(void)
-{
-	uircc_cleanup();
-}
-#endif /* MODULE */
-
diff -urN linux-2.2.15-pre2/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- linux-2.2.15-pre2/drivers/net/irda/w83977af_ir.c	Mon Jun  7 16:19:59 1999
+++ linux/drivers/net/irda/w83977af_ir.c	Mon Dec  3 21:57:53 2001
@@ -6,23 +6,23 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Fri May 21 22:18:19 1999
+ * Modified at:   Tue Jan 11 13:09:48 2000
  * 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-2000 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1998-1999 Rebel.com
  *      
  *     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 Paul VanderSpek nor Corel Computer Corp. admit liability
- *     nor provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
+ *     Neither Paul VanderSpek nor Rebel.com admit liability nor provide
+ *     warranty for any of this software. This material is provided "AS-IS"
+ *     and at no charge.
  *     
  *     If you find bugs in this file, its very likely that the same bug
- *     will also be in pc87108.c since the implementations is quite
+ *     will also be in pc87108.c since the implementations are quite
  *     similar.
  *
  *     Notice that all functions that needs to access the chip in _any_
@@ -49,6 +49,7 @@
 #include <linux/delay.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
+#include <linux/rtnetlink.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -61,43 +62,50 @@
 #include <net/irda/w83977af.h>
 #include <net/irda/w83977af_ir.h>
 
-#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 */
+#ifdef  CONFIG_ARCH_VNC            /* Adjust to NetWinder differences */
+#undef  CONFIG_VNC_TX_DMA_PROBLEMS /* Not needed */
+#define CONFIG_VNC_RX_DMA_PROBLEMS /* Must have this one! */
+#endif
+#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 */
+static int  qos_mtt_bits = 0x07;   /* 1 ms or more */
 
 #define CHIP_IO_EXTENT 8
 
 static unsigned int io[] = { 0x180, ~0, ~0, ~0 };
+#ifdef CONFIG_ARCH_VNC             /* Adjust to NetWinder differences */
 static unsigned int irq[] = { 6, 0, 0, 0 };
-static unsigned int dma[] = 
-{ 1, 0, 0, 0 };
+#else
+static unsigned int irq[] = { 11, 0, 0, 0 };
+#endif
+static unsigned int dma[] = { 1, 0, 0, 0 };
+static unsigned int efbase[] = { W977_EFIO_BASE, W977_EFIO2_BASE };
+static unsigned int efio = W977_EFIO_BASE;
 
 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_close(struct w83977af_ir *self);
 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_dma_receive(struct w83977af_ir *self); 
+static int  w83977af_dma_receive_complete(struct w83977af_ir *self);
 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_dma_write(struct w83977af_ir *self, int iobase);
+static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed);
 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 int  w83977af_is_receiving(struct w83977af_ir *self);
 
 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_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *w83977af_net_get_stats(struct device *dev);
 
 /*
  * Function w83977af_init ()
@@ -105,17 +113,17 @@
  *    Initialize chip. Just try to find out how many chips we are dealing with
  *    and where they are
  */
-__initfunc(int w83977af_init(void))
+int __init w83977af_init(void)
 {
         int i;
 
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
 	for (i=0; (io[i] < 2000) && (i < 4); i++) { 
 		int ioaddr = io[i];
 		if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
 			continue;
-		if (w83977af_open( i, io[i], irq[i], dma[i]) == 0)
+		if (w83977af_open(i, io[i], irq[i], dma[i]) == 0)
 			return 0;
 	}
 	return -ENODEV;
@@ -132,11 +140,11 @@
 {
 	int i;
 
-        DEBUG(4, __FUNCTION__ "()\n");
+        IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	for (i=0; i < 4; i++) {
 		if (dev_self[i])
-			w83977af_close(&(dev_self[i]->idev));
+			w83977af_close(dev_self[i]);
 	}
 }
 #endif /* MODULE */
@@ -147,14 +155,15 @@
  *    Open driver instance
  *
  */
-int w83977af_open( int i, unsigned int iobase, unsigned int irq, 
-		   unsigned int dma)
+int w83977af_open(int i, unsigned int iobase, unsigned int irq, 
+		  unsigned int dma)
 {
-	struct irda_device *idev;
+	struct device *dev;
         struct w83977af_ir *self;
 	int ret;
+	int err;
 
-	DEBUG( 0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
 	if (w83977af_probe(iobase, irq, dma) == -1)
 		return -1;
@@ -173,222 +182,254 @@
 	/* Need to store self somewhere */
 	dev_self[i] = self;
 
-	idev = &self->idev;
-
 	/* Initialize IO */
-	idev->io.iobase    = iobase;
-        idev->io.irq       = irq;
-        idev->io.io_ext    = CHIP_IO_EXTENT;
-        idev->io.dma       = dma;
-        idev->io.fifo_size = 32;
+	self->io.fir_base   = iobase;
+        self->io.irq       = irq;
+        self->io.fir_ext   = CHIP_IO_EXTENT;
+        self->io.dma       = dma;
+        self->io.fifo_size = 32;
 
 	/* Lock the port that we need */
-	ret = check_region(idev->io.iobase, idev->io.io_ext);
+	ret = check_region(self->io.fir_base, self->io.fir_ext);
 	if (ret < 0) { 
-		DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-		       idev->io.iobase);
-		/* w83977af_cleanup( self->idev);  */
+		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+		      self->io.fir_base);
+		/* w83977af_cleanup( self);  */
 		return -ENODEV;
 	}
-	request_region(idev->io.iobase, idev->io.io_ext, idev->name);
+	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 
 	/* Initialize QoS for this device */
-	irda_init_max_qos_capabilies(&idev->qos);
+	irda_init_max_qos_capabilies(&self->qos);
 	
 	/* The only value we must override it the baudrate */
 
 	/* FIXME: The HP HDLS-1100 does not support 1152000! */
-	idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
 		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 = qos_mtt_bits;
-	irda_qos_bits_to_value(&idev->qos);
+	self->qos.min_turn_time.bits = qos_mtt_bits;
+	irda_qos_bits_to_value(&self->qos);
 	
-	idev->flags = IFF_FIR|IFF_MIR|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;
+	self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
 
 	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
-	idev->rx_buff.truesize = 14384; 
-	idev->tx_buff.truesize = 4000;
+	self->rx_buff.truesize = 14384; 
+	self->tx_buff.truesize = 4000;
+	
+	/* Allocate memory if needed */
+	self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
+					      GFP_KERNEL|GFP_DMA);
+	if (self->rx_buff.head == NULL)
+		return -ENOMEM;
+
+	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+	
+	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+					      GFP_KERNEL|GFP_DMA);
+	if (self->tx_buff.head == NULL) {
+		kfree(self->rx_buff.head);
+		return -ENOMEM;
+	}
+	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+
+	self->rx_buff.in_frame = FALSE;
+	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
 	
-	/* Initialize callbacks */
-	idev->change_speed    = w83977af_change_speed;
-	idev->wait_until_sent = w83977af_wait_until_sent;
-        idev->is_receiving    = w83977af_is_receiving;
+	if (!(dev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return -ENOMEM;
+	}
+	/* dev_alloc doesn't clear the struct, so lets do a little hack */
+	memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct device)-sizeof(char*));
+
+	dev->priv = (void *) self;
+	self->netdev = dev;
 
 	/* Override the network functions we need to use */
-	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;
+	dev->init            = w83977af_net_init;
+	dev->hard_start_xmit = w83977af_hard_xmit;
+	dev->open            = w83977af_net_open;
+	dev->stop            = w83977af_net_close;
+	dev->do_ioctl        = w83977af_net_ioctl;
+	dev->get_stats	     = w83977af_net_get_stats;
+
+	rtnl_lock();
+	err = register_netdev(dev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return -1;
+	}
 
-	/* Open the IrDA device */
-	irda_device_open(idev, driver_name, self);
+	MESSAGE("IrDA: Registered device %s\n", dev->name);
 	
 	return 0;
 }
 
 /*
- * Function w83977af_close (idev)
+ * Function w83977af_close (self)
  *
  *    Close driver instance
  *
  */
-static int w83977af_close( struct irda_device *idev)
+static int w83977af_close(struct w83977af_ir *self)
 {
-	struct w83977af_ir *self;
 	int iobase;
 
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
-	ASSERT(idev != NULL, return -1;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
-
-        iobase = idev->io.iobase;
-	self = (struct w83977af_ir *) idev->priv;
+        iobase = self->io.fir_base;
 
 #ifdef CONFIG_USE_W977_PNP
 	/* enter PnP configuration mode */
-	w977_efm_enter();
+	w977_efm_enter(efio);
 
-	w977_select_device(W977_DEVICE_IR);
+	w977_select_device(W977_DEVICE_IR, efio);
 
 	/* Deactivate device */
-	w977_write_reg(0x30, 0x00);
+	w977_write_reg(0x30, 0x00, efio);
 
-	w977_efm_exit();
+	w977_efm_exit(efio);
 #endif /* CONFIG_USE_W977_PNP */
+
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		rtnl_unlock();
+		/* Must free the old-style 2.2.x device */
+		kfree(self->netdev);
+	}
+
 	/* Release the PORT that this driver is using */
-	DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
-	      idev->io.iobase);
-	release_region(idev->io.iobase, idev->io.io_ext);
+	IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
+	      self->io.fir_base);
+	release_region(self->io.fir_base, self->io.fir_ext);
 
-	irda_device_close(idev);
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
 
 	kfree(self);
 
 	return 0;
 }
 
-/*
- * Function w83977af_probe (iobase, irq, dma)
- *
- *    Returns non-negative on success.
- *
- */
 int w83977af_probe( int iobase, int irq, int dma)
 {
-	int version;
-	
-	DEBUG( 0, __FUNCTION__ "()\n");
+  	int version;
+	int i;
+  	
+ 	for (i=0; i < 2; i++) {
+ 		IRDA_DEBUG( 0, __FUNCTION__ "()\n");
 #ifdef CONFIG_USE_W977_PNP
-	/* Enter PnP configuration mode */
-	w977_efm_enter();
-
-	w977_select_device(W977_DEVICE_IR);
-
-	/* Configure PnP port, IRQ, and DMA channel */
-	w977_write_reg(0x60, (iobase >> 8) & 0xff);
-	w977_write_reg(0x61, (iobase) & 0xff);
-
-	w977_write_reg(0x70, irq);
-#ifdef CONFIG_NETWINDER
-	w977_write_reg(0x74, dma+1); /* Netwinder uses 1 higher than Linux */
+ 		/* Enter PnP configuration mode */
+		w977_efm_enter(efbase[i]);
+  
+ 		w977_select_device(W977_DEVICE_IR, efbase[i]);
+  
+ 		/* Configure PnP port, IRQ, and DMA channel */
+ 		w977_write_reg(0x60, (iobase >> 8) & 0xff, efbase[i]);
+ 		w977_write_reg(0x61, (iobase) & 0xff, efbase[i]);
+  
+ 		w977_write_reg(0x70, irq, efbase[i]);
+#ifdef CONFIG_ARCH_VNC
+		/* Netwinder uses 1 higher than Linux */
+ 		w977_write_reg(0x74, dma+1, efbase[i]);
 #else
-	w977_write_reg(0x74, dma);   
-#endif
-	w977_write_reg(0x75, 0x04);  /* Disable Tx DMA */
-	
-	/* Set append hardware CRC, enable IR bank selection */	
-	w977_write_reg(0xf0, APEDCRC|ENBNKSEL);
-
-	/* Activate device */
-	w977_write_reg(0x30, 0x01);
-
-	w977_efm_exit();
-#endif
- 	/* Disable Advanced mode */
- 	switch_bank(iobase, SET2);
- 	outb(iobase+2, 0x00);  
-
-	/* Turn on UART (global) interrupts */
-	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);
-
-	/* Set default IR-mode */
-	switch_bank(iobase, SET0);
-	outb(HCR_SIR, iobase+HCR);
-
-	/* Read the Advanced IR ID */
-	switch_bank(iobase, SET3);
-	version = inb(iobase+AUID);
-	
-	/* Should be 0x1? */
-	if (0x10 != (version & 0xf0)) {
-		DEBUG( 0, __FUNCTION__ "(), Wrong chip version");	
-		return -1;
-	}
-	
-	/* Set FIFO size to 32 */
-	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);
-
-	/* Receiver frame length */
-	switch_bank(iobase, SET4);
-	outb(2048 & 0xff, iobase+6);
-	outb((2048 >> 8) & 0x1f, iobase+7);
-
-	/* 
-	 * Init HP HSDL-1100 transceiver. 
-	 * 
-	 * Set IRX_MSL since we have 2 * receive paths IRRX, and
-	 * IRRXH. Clear IRSL0D since we want IRSL0 * to be a input pin used
-	 * for IRRXH 
-	 *
-	 *   IRRX  pin 37 connected to receiver 
-	 *   IRTX  pin 38 connected to transmitter
-	 *   FIRRX pin 39 connected to receiver      (IRSL0) 
-	 *   CIRRX pin 40 connected to pin 37
-	 */
-	switch_bank(iobase, SET7);
-	outb(0x40, iobase+7);
-		
-	DEBUG(0, "W83977AF (IR) driver loaded. Version: 0x%02x\n", version);
-	
-	return 0;
+ 		w977_write_reg(0x74, dma, efbase[i]);   
+#endif /*CONFIG_ARCH_VNC */
+ 		w977_write_reg(0x75, 0x04, efbase[i]);  /* Disable Tx DMA */
+  	
+ 		/* Set append hardware CRC, enable IR bank selection */	
+ 		w977_write_reg(0xf0, APEDCRC|ENBNKSEL, efbase[i]);
+  
+ 		/* Activate device */
+ 		w977_write_reg(0x30, 0x01, efbase[i]);
+  
+ 		w977_efm_exit(efbase[i]);
+#endif /* CONFIG_USE_W977_PNP */
+  		/* Disable Advanced mode */
+  		switch_bank(iobase, SET2);
+  		outb(iobase+2, 0x00);  
+ 
+ 		/* Turn on UART (global) interrupts */
+ 		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);
+  
+  		/* Set default IR-mode */
+  		switch_bank(iobase, SET0);
+  		outb(HCR_SIR, iobase+HCR);
+  
+  		/* Read the Advanced IR ID */
+  		switch_bank(iobase, SET3);
+  		version = inb(iobase+AUID);
+  	
+  		/* Should be 0x1? */
+  		if (0x10 == (version & 0xf0)) {
+ 			efio = efbase[i];
+ 
+ 			/* Set FIFO size to 32 */
+ 			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);
+ 
+ 			/* Receiver frame length */
+ 			switch_bank(iobase, SET4);
+			outb(2048 & 0xff, iobase+6);
+			outb((2048 >> 8) & 0x1f, iobase+7);
+
+			/* 
+			 * Init HP HSDL-1100 transceiver. 
+			 * 
+			 * Set IRX_MSL since we have 2 * receive paths IRRX, 
+			 * and IRRXH. Clear IRSL0D since we want IRSL0 * to 
+			 * be a input pin used for IRRXH 
+			 *
+			 *   IRRX  pin 37 connected to receiver 
+			 *   IRTX  pin 38 connected to transmitter
+			 *   FIRRX pin 39 connected to receiver      (IRSL0) 
+			 *   CIRRX pin 40 connected to pin 37
+			 */
+			switch_bank(iobase, SET7);
+			outb(0x40, iobase+7);
+			
+			MESSAGE("W83977AF (IR) driver loaded. "
+				"Version: 0x%02x\n", version);
+			
+			return 0;
+		} else {
+			/* Try next extented function register address */
+			IRDA_DEBUG( 0, __FUNCTION__ "(), Wrong chip version");
+		}
+  	}   	
+	return -1;
 }
 
-/*
- * Function w83977af_change_speed (idev, baud)
- *
- *    Change the speed of the device
- *
- */
-void w83977af_change_speed(struct irda_device *idev, int speed)
+void w83977af_change_speed(struct w83977af_ir *self, __u32 speed)
 {
 	int ir_mode = HCR_SIR;
 	int iobase; 
 	__u8 set;
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Update accounting for new speed */
-	idev->io.baudrate = speed;
+	self->io.speed = speed;
 
 	/* Save current bank */
 	set = inb(iobase+SSR);
@@ -404,24 +445,24 @@
 	switch (speed) {
 	case 9600:   outb(0x0c, iobase+ABLL); break;
 	case 19200:  outb(0x06, iobase+ABLL); break;
-	case 37600:  outb(0x03, iobase+ABLL); break;
+	case 38400:  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");
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
 		break;
 	case 1152000:
 		ir_mode = HCR_MIR_1152;
-		DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
 		break;
 	case 4000000:
 		ir_mode = HCR_FIR;
-		DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
 		break;
 	default:
 		ir_mode = HCR_FIR;
-		DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
 		break;
 	}
 
@@ -435,18 +476,17 @@
 	
 	/* set FIFO threshold to TX17, RX16 */
 	switch_bank(iobase, SET0);
-
 	outb(0x00, iobase+UFR);        /* Reset */
 	outb(UFR_EN_FIFO, iobase+UFR); /* First we must enable FIFO */
 	outb(0xa7, iobase+UFR);
 
-	idev->netdev.tbusy = 0;
+	self->netdev->tbusy = 0;
 	
 	/* Enable some interrupts so we can receive frames */
 	switch_bank(iobase, SET0);
 	if (speed > PIO_MAX_SPEED) {
 		outb(ICR_EFSFI, iobase+ICR);
-		w83977af_dma_receive(idev);
+		w83977af_dma_receive(self);
 	} else
 		outb(ICR_ERBRI, iobase+ICR);
     	
@@ -462,32 +502,35 @@
  */
 int w83977af_hard_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct irda_device *idev;
+	struct w83977af_ir *self;
+	__u32 speed;
 	int iobase;
 	__u8 set;
 	int mtt;
 	
-	idev = (struct irda_device *) dev->priv;
-
-	ASSERT(idev != NULL, return 0;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+	self = (struct w83977af_ir *) dev->priv;
 
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
-	DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len);
+	IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, 
+		   (int) skb->len);
 	
 	/* Lock transmit buffer */
 	if (irda_lock((void *) &dev->tbusy) == FALSE)
 		return -EBUSY;
 
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+
 	/* Save current set */
 	set = inb(iobase+SSR);
 	
 	/* Decide if we should use PIO or DMA transfer */
-	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;
+	if (self->io.speed > PIO_MAX_SPEED) {
+		self->tx_buff.data = self->tx_buff.head;
+		memcpy(self->tx_buff.data, skb->data, skb->len);
+		self->tx_buff.len = skb->len;
 		
 		mtt = irda_get_mtt(skb);
 #ifdef CONFIG_USE_INTERNAL_TIMER
@@ -502,28 +545,28 @@
 			
 			/* Start timer */
 			outb(IR_MSL_EN_TMR, iobase+IR_MSL);
-			idev->io.direction = IO_XMIT;
+			self->io.direction = IO_XMIT;
 			
 			/* Enable timer interrupt */
 			switch_bank(iobase, SET0);
 			outb(ICR_ETMRI, iobase+ICR);
 		} else {
 #endif
-			DEBUG(4,__FUNCTION__ "(%ld), mtt=%d\n", jiffies, mtt);
+			IRDA_DEBUG(4,__FUNCTION__ "(%ld), mtt=%d\n", jiffies, mtt);
 			if (mtt)
 				udelay(mtt);
 
 			/* Enable DMA interrupt */
 			switch_bank(iobase, SET0);
 	 		outb(ICR_EDMAI, iobase+ICR);
-	     		w83977af_dma_write(idev, iobase);
+	     		w83977af_dma_write(self, 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, 
-						   idev->tx_buff.truesize);
+		self->tx_buff.data = self->tx_buff.head;
+		self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
+						   self->tx_buff.truesize);
 		
 		/* Add interrupt on tx low level (will fire immediately) */
 		switch_bank(iobase, SET0);
@@ -538,19 +581,19 @@
 }
 
 /*
- * Function w83977af_dma_write (idev, iobase)
+ * Function w83977af_dma_write (self, iobase)
  *
  *    Send frame using DMA
  *
  */
-static void w83977af_dma_write(struct irda_device *idev, int iobase)
+static void w83977af_dma_write(struct w83977af_ir *self, int iobase)
 {
 	__u8 set;
-#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+#ifdef CONFIG_VNC_TX_DMA_PROBLEMS
 	unsigned long flags;
 	__u8 hcr;
 #endif
-        DEBUG(4, __FUNCTION__ "(), len=%d\n", idev->tx_buff.len);
+        IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", self->tx_buff.len);
 
 	/* Save current set */
 	set = inb(iobase+SSR);
@@ -562,27 +605,27 @@
 	/* Choose transmit DMA channel  */ 
 	switch_bank(iobase, SET2);
 	outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1);
-#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+#ifdef CONFIG_VNC_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);
+	disable_dma(self->io.dma);
+	clear_dma_ff(self->io.dma);
+	set_dma_mode(self->io.dma, DMA_MODE_READ);
+	set_dma_addr(self->io.dma, virt_to_bus(self->tx_buff.data));
+	set_dma_count(self->io.dma, self->tx_buff.len);
 #else
-	setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
+	setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, 
 		  DMA_MODE_WRITE);	
 #endif
-	idev->io.direction = IO_XMIT;
+	self->io.direction = IO_XMIT;
 	
 	/* Enable DMA */
  	switch_bank(iobase, SET0);
-#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+#ifdef CONFIG_VNC_TX_DMA_PROBLEMS
 	hcr = inb(iobase+HCR);
 	outb(hcr | HCR_EN_DMA, iobase+HCR);
-	enable_dma(idev->io.dma);
+	enable_dma(self->io.dma);
 	restore_flags(flags);
 #else	
 	outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR);
@@ -603,17 +646,19 @@
 	int actual = 0;
 	__u8 set;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	/* Save current bank */
 	set = inb(iobase+SSR);
 
 	switch_bank(iobase, SET0);
 	if (!(inb_p(iobase+USR) & USR_TSRE)) {
-		DEBUG(4, __FUNCTION__ "(), warning, FIFO not empty yet!\n");
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), warning, FIFO not empty yet!\n");
 
 		fifo_size -= 17;
-		DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size);
+		IRDA_DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", 
+			   fifo_size);
 	}
 
 	/* Fill FIFO with current frame */
@@ -622,8 +667,8 @@
 		outb(buf[actual++], iobase+TBR);
 	}
         
-	DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-	       fifo_size, actual, len);
+	IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
+		   fifo_size, actual, len);
 
 	/* Restore bank */
 	outb(set, iobase+SSR);
@@ -632,23 +677,22 @@
 }
 
 /*
- * Function w83977af_dma_xmit_complete (idev)
+ * Function w83977af_dma_xmit_complete (self)
  *
  *    The transfer of a frame in finished. So do the necessary things
  *
  *    
  */
-void w83977af_dma_xmit_complete(struct irda_device *idev)
+void w83977af_dma_xmit_complete(struct w83977af_ir *self)
 {
 	int iobase;
 	__u8 set;
 
-	DEBUG(4, __FUNCTION__ "(%ld)\n", jiffies);
+	IRDA_DEBUG(4, __FUNCTION__ "(%ld)\n", jiffies);
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(self != NULL, return;);
 
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Save current set */
 	set = inb(iobase+SSR);
@@ -659,19 +703,24 @@
 	
 	/* Check for underrrun! */
 	if (inb(iobase+AUDR) & AUDR_UNDR) {
-		DEBUG(0, __FUNCTION__ "(), Transmit underrun!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), Transmit underrun!\n");
 		
-		idev->stats.tx_errors++;
-		idev->stats.tx_fifo_errors++;
+		self->stats.tx_errors++;
+		self->stats.tx_fifo_errors++;
 
 		/* Clear bit, by writing 1 to it */
 		outb(AUDR_UNDR, iobase+AUDR);
 	} else
-		idev->stats.tx_packets++;
+		self->stats.tx_packets++;
+
+	
+	if (self->new_speed) {
+		w83977af_change_speed(self, self->new_speed);
+		self->new_speed = 0;
+	}
 
 	/* Unlock tx_buff and request another frame */
-	idev->netdev.tbusy = 0; /* Unlock */
-	idev->media_busy = FALSE;
+	self->netdev->tbusy = 0; /* Unlock */
 	
 	/* Tell the network layer, that we want more frames */
 	mark_bh(NET_BH);
@@ -681,29 +730,25 @@
 }
 
 /*
- * Function w83977af_dma_receive (idev)
+ * Function w83977af_dma_receive (self)
  *
  *    Get ready for receiving a frame. The device will initiate a DMA
  *    if it starts to receive a frame.
  *
  */
-int w83977af_dma_receive(struct irda_device *idev) 
+int w83977af_dma_receive(struct w83977af_ir *self) 
 {
-	struct w83977af_ir *self;
 	int iobase;
 	__u8 set;
-#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
+#ifdef CONFIG_VNC_RX_DMA_PROBLEMS
 	unsigned long flags;
 	__u8 hcr;
 #endif
+	ASSERT(self != NULL, return -1;);
 
-	ASSERT(idev != NULL, return -1;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+	IRDA_DEBUG(4, __FUNCTION__ "\n");
 
-	DEBUG(4, __FUNCTION__ "\n");
-
-	self = idev->priv;
-	iobase= idev->io.iobase;
+	iobase= self->io.fir_base;
 
 	/* Save current set */
 	set = inb(iobase+SSR);
@@ -717,20 +762,20 @@
 	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;
+	self->io.direction = IO_RECV;
+	self->rx_buff.data = self->rx_buff.head;
 
-#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
+#ifdef CONFIG_VNC_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(self->io.dma);
+	clear_dma_ff(self->io.dma);
+	set_dma_mode(self->io.dma, DMA_MODE_READ);
+	set_dma_addr(self->io.dma, virt_to_bus(self->rx_buff.data));
+	set_dma_count(self->io.dma, self->rx_buff.truesize);
 #else
-	setup_dma(idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, 
+	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
 		  DMA_MODE_READ);
 #endif
 	/* 
@@ -744,10 +789,10 @@
 	
 	/* Enable DMA */
 	switch_bank(iobase, SET0);
-#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
+#ifdef CONFIG_VNC_RX_DMA_PROBLEMS
 	hcr = inb(iobase+HCR);
 	outb(hcr | HCR_EN_DMA, iobase+HCR);
-	enable_dma(idev->io.dma);
+	enable_dma(self->io.dma);
 	restore_flags(flags);
 #else	
 	outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR);
@@ -759,32 +804,30 @@
 }
 
 /*
- * Function w83977af_receive_complete (idev)
+ * Function w83977af_receive_complete (self)
  *
  *    Finished with receiving a frame
  *
  */
-int w83977af_dma_receive_complete(struct irda_device *idev)
+int w83977af_dma_receive_complete(struct w83977af_ir *self)
 {
 	struct sk_buff *skb;
-	struct w83977af_ir *self;
 	struct st_fifo *st_fifo;
 	int len;
 	int iobase;
 	__u8 set;
 	__u8 status;
 
-	DEBUG(4, __FUNCTION__ "\n");
+	IRDA_DEBUG(4, __FUNCTION__ "\n");
 
-	self = idev->priv;
 	st_fifo = &self->st_fifo;
 
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Save current set */
 	set = inb(iobase+SSR);
 	
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Read status FIFO */
 	switch_bank(iobase, SET5);
@@ -809,28 +852,28 @@
 		if (status & FS_FO_ERR_MSK) {
 			if (status & FS_FO_LST_FR) {
 				/* Add number of lost frames to stats */
-				idev->stats.rx_errors += len;	
+				self->stats.rx_errors += len;	
 			} else {
 				/* Skip frame */
-				idev->stats.rx_errors++;
+				self->stats.rx_errors++;
 				
-				idev->rx_buff.data += len;
+				self->rx_buff.data += len;
 				
 				if (status & FS_FO_MX_LEX)
-					idev->stats.rx_length_errors++;
+					self->stats.rx_length_errors++;
 				
 				if (status & FS_FO_PHY_ERR) 
-					idev->stats.rx_frame_errors++;
+					self->stats.rx_frame_errors++;
 				
 				if (status & FS_FO_CRC_ERR) 
-					idev->stats.rx_crc_errors++;
+					self->stats.rx_crc_errors++;
 			}
 			/* The errors below can be reported in both cases */
 			if (status & FS_FO_RX_OV)
-				idev->stats.rx_fifo_errors++;
+				self->stats.rx_fifo_errors++;
 			
 			if (status & FS_FO_FSF_OV)
-				idev->stats.rx_fifo_errors++;
+				self->stats.rx_fifo_errors++;
 			
 		} else {
 			/* Check if we have transfered all data to memory */
@@ -866,19 +909,19 @@
 			skb_reserve(skb, 1); 
 			
 			/* Copy frame without CRC */
-			if (idev->io.baudrate < 4000000) {
+			if (self->io.speed < 4000000) {
 				skb_put(skb, len-2);
-				memcpy(skb->data, idev->rx_buff.data, len-2);
+				memcpy(skb->data, self->rx_buff.data, len-2);
 			} else {
 				skb_put(skb, len-4);
-				memcpy(skb->data, idev->rx_buff.data, len-4);
+				memcpy(skb->data, self->rx_buff.data, len-4);
 			}
 
 			/* Move to next frame */
-			idev->rx_buff.data += len;
-			idev->stats.rx_packets++;
+			self->rx_buff.data += len;
+			self->stats.rx_packets++;
 			
-			skb->dev = &idev->netdev;
+			skb->dev = self->netdev;
 			skb->mac.raw  = skb->data;
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
@@ -891,61 +934,61 @@
 }
 
 /*
- * Function pc87108_pio_receive (idev)
+ * Function pc87108_pio_receive (self)
  *
  *    Receive all data in receiver FIFO
  *
  */
-static void w83977af_pio_receive(struct irda_device *idev) 
+static void w83977af_pio_receive(struct w83977af_ir *self) 
 {
 	__u8 byte = 0x00;
 	int iobase;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT(idev != NULL, return;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(self != NULL, return;);
 	
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 	
 	/*  Receive all characters in Rx FIFO */
 	do {
 		byte = inb(iobase+RBR);
-		async_unwrap_char(idev, byte);
+		async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
+				  byte);
 	} while (inb(iobase+USR) & USR_RDR); /* Data available */	
 }
 
 /*
- * Function w83977af_sir_interrupt (idev, eir)
+ * Function w83977af_sir_interrupt (self, eir)
  *
  *    Handle SIR interrupt
  *
  */
-static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
+static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr)
 {
 	int actual;
 	__u8 new_icr = 0;
 	__u8 set;
 	int iobase;
 
-	DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr);
+	IRDA_DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr);
 	
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 	/* Transmit FIFO low on data */
 	if (isr & ISR_TXTH_I) {
 		/* Write data left in transmit buffer */
-		actual = w83977af_pio_write(idev->io.iobase, 
-					    idev->tx_buff.data, 
-					    idev->tx_buff.len, 
-					    idev->io.fifo_size);
+		actual = w83977af_pio_write(self->io.fir_base, 
+					    self->tx_buff.data, 
+					    self->tx_buff.len, 
+					    self->io.fifo_size);
 
-		idev->tx_buff.data += actual;
-		idev->tx_buff.len  -= actual;
+		self->tx_buff.data += actual;
+		self->tx_buff.len  -= actual;
 		
-		idev->io.direction = IO_XMIT;
+		self->io.direction = IO_XMIT;
 
 		/* Check if finished */
-		if (idev->tx_buff.len > 0) {
+		if (self->tx_buff.len > 0) {
 			new_icr |= ICR_ETXTHI;
 		} else {
 			set = inb(iobase+SSR);
@@ -953,8 +996,8 @@
 			outb(AUDR_SFEND, iobase+AUDR);
 			outb(set, iobase+SSR); 
 
-			idev->netdev.tbusy = 0; /* Unlock */
-			idev->stats.tx_packets++;
+			self->netdev->tbusy = 0; /* Unlock */
+			self->stats.tx_packets++;
 
 			/* Schedule network layer */
 		        mark_bh(NET_BH);	
@@ -963,16 +1006,23 @@
 		}
 	}
 	/* Check if transmission has completed */
-	if (isr & ISR_TXEMP_I) {
-		
+	if (isr & ISR_TXEMP_I) {		
+		/* Check if we need to change the speed? */
+		if (self->new_speed) {
+			IRDA_DEBUG(2, __FUNCTION__ 
+				   "(), Changing speed!\n");
+			w83977af_change_speed(self, self->new_speed);
+			self->new_speed = 0;
+		}
+
 		/* Turn around and get ready to receive some data */
-		idev->io.direction = IO_RECV;
+		self->io.direction = IO_RECV;
 		new_icr |= ICR_ERBRI;
 	}
 
 	/* Rx FIFO threshold or timeout */
 	if (isr & ISR_RXTH_I) {
-		w83977af_pio_receive(idev);
+		w83977af_pio_receive(self);
 
 		/* Keep receiving */
 		new_icr |= ICR_ERBRI;
@@ -981,23 +1031,23 @@
 }
 
 /*
- * Function pc87108_fir_interrupt (idev, eir)
+ * Function pc87108_fir_interrupt (self, eir)
  *
  *    Handle MIR/FIR interrupt
  *
  */
-static __u8 w83977af_fir_interrupt(struct irda_device *idev, int isr)
+static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr)
 {
 	__u8 new_icr = 0;
 	__u8 set;
 	int iobase;
 
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 	set = inb(iobase+SSR);
 	
 	/* End of frame detected in FIFO */
 	if (isr & (ISR_FEND_I|ISR_FSF_I)) {
-		if (w83977af_dma_receive_complete(idev)) {
+		if (w83977af_dma_receive_complete(self)) {
 			
 			/* Wait for next status FIFO interrupt */
 			new_icr |= ICR_EFSFI;
@@ -1026,29 +1076,29 @@
 /* 		outb(ASCR_CTE, iobase+ASCR); */
 
 		/* Check if this is a TX timer interrupt */
-		if (idev->io.direction == IO_XMIT) {
-			w83977af_dma_write(idev, iobase);
+		if (self->io.direction == IO_XMIT) {
+			w83977af_dma_write(self, iobase);
 
 			new_icr |= ICR_EDMAI;
 		} else {
 			/* Check if DMA has now finished */
-			w83977af_dma_receive_complete(idev);
+			w83977af_dma_receive_complete(self);
 
 			new_icr |= ICR_EFSFI;
 		}
 	}	
 	/* Finished with DMA */
 	if (isr & ISR_DMA_I) {
-		w83977af_dma_xmit_complete(idev);
+		w83977af_dma_xmit_complete(self);
 
 		/* Check if there are more frames to be transmitted */
-		/* if (irda_device_txqueue_empty(idev)) { */
+		/* if (irda_device_txqueue_empty(self)) { */
 		
 		/* Prepare for receive 
 		 * 
 		 * ** Netwinder Tx DMA likes that we do this anyway **
 		 */
-		w83977af_dma_receive(idev);
+		w83977af_dma_receive(self);
 		new_icr = ICR_EFSFI;
 	       /* } */
 	}
@@ -1060,27 +1110,28 @@
 }
 
 /*
- * Function pc87108_interrupt (irq, dev_id, regs)
+ * Function w83977af_interrupt (irq, dev_id, regs)
  *
  *    An interrupt from the chip has arrived. Time to do some work
  *
  */
 static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct device *dev = (struct device *) dev_id;
+	struct w83977af_ir *self;
 	__u8 set, icr, isr;
 	int iobase;
 
-	struct irda_device *idev = (struct irda_device *) dev_id;
-
-	if (idev == NULL) {
+	if (!dev) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n", 
 			driver_name, irq);
 		return;
 	}
+	self = (struct w83977af_ir *) dev->priv;
 
-	idev->netdev.interrupt = 1;
+	dev->interrupt = 1;
 
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Save current bank */
 	set = inb(iobase+SSR);
@@ -1093,47 +1144,34 @@
 	
 	if (isr) {
 		/* Dispatch interrupt handler for the current speed */
-		if (idev->io.baudrate > PIO_MAX_SPEED )
-			icr = w83977af_fir_interrupt(idev, isr);
+		if (self->io.speed > PIO_MAX_SPEED )
+			icr = w83977af_fir_interrupt(self, isr);
 		else
-			icr = w83977af_sir_interrupt(idev, isr);
+			icr = w83977af_sir_interrupt(self, isr);
 	}
 
 	outb(icr, iobase+ICR);    /* Restore (new) interrupts */
 	outb(set, iobase+SSR);    /* Restore bank register */
 
-	idev->netdev.interrupt = 0;
-}
-
-/*
- * Function w83977af_wait_until_sent (idev)
- *
- *    This function should put the current thread to sleep until all data 
- *    have been sent, so it is safe to f.eks. change the speed.
- */
-static void w83977af_wait_until_sent(struct irda_device *idev)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(60*HZ/1000);
+	self->netdev->interrupt = 0;
 }
 
 /*
- * Function w83977af_is_receiving (idev)
+ * Function w83977af_is_receiving (self)
  *
  *    Return TRUE is we are currently receiving a frame
  *
  */
-static int w83977af_is_receiving(struct irda_device *idev)
+static int w83977af_is_receiving(struct w83977af_ir *self)
 {
 	int status = FALSE;
 	int iobase;
 	__u8 set;
 
-	ASSERT(idev != NULL, return FALSE;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	ASSERT(self != NULL, return FALSE;);
 
-	if (idev->io.baudrate > 115200) {
-		iobase = idev->io.iobase;
+	if (self->io.speed > 115200) {
+		iobase = self->io.fir_base;
 
 		/* Check if rx FIFO is not empty */
 		set = inb(iobase+SSR);
@@ -1144,7 +1182,7 @@
 		}
 		outb(set, iobase+SSR);
 	} else 
-		status = (idev->rx_buff.state != OUTSIDE_FRAME);
+		status = (self->rx_buff.state != OUTSIDE_FRAME);
 	
 	return status;
 }
@@ -1157,7 +1195,7 @@
  */
 static int w83977af_net_init(struct device *dev)
 {
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
 	/* Set up to be a normal IrDA network device driver */
 	irda_device_setup(dev);
@@ -1176,52 +1214,57 @@
  */
 static int w83977af_net_open(struct device *dev)
 {
-	struct irda_device *idev;
+	struct w83977af_ir *self;
 	int iobase;
 	__u8 set;
 	
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 	
 	ASSERT(dev != NULL, return -1;);
-	idev = (struct irda_device *) dev->priv;
+	self = (struct w83977af_ir *) dev->priv;
 	
-	ASSERT(idev != NULL, return 0;);
-	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+	ASSERT(self != NULL, return 0;);
 	
-	iobase = idev->io.iobase;
+	iobase = self->io.fir_base;
 
-	if (request_irq(idev->io.irq, w83977af_interrupt, 0, idev->name, 
-			 (void *) idev)) {
+	if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name, 
+			(void *) dev)) {
 		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);
+	if (request_dma(self->io.dma, dev->name)) {
+		free_irq(self->io.irq, self);
 		return -EAGAIN;
 	}
 		
-	/* Ready to play! */
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-
 	/* Save current set */
 	set = inb(iobase+SSR);
 
  	/* Enable some interrupts so we can receive frames again */
  	switch_bank(iobase, SET0);
- 	if (idev->io.baudrate > 115200) {
+ 	if (self->io.speed > 115200) {
  		outb(ICR_EFSFI, iobase+ICR);
- 		w83977af_dma_receive(idev);
+ 		w83977af_dma_receive(self);
  	} else
  		outb(ICR_ERBRI, iobase+ICR);
 
 	/* Restore bank register */
 	outb(set, iobase+SSR);
 
+	/* Ready to play! */
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* 
+	 * Open new IrLAP layer instance, now that everything should be
+	 * initialized properly 
+	 */
+	self->irlap = irlap_open(dev, &self->qos);
+
 	MOD_INC_USE_COUNT;
 
 	return 0;
@@ -1235,25 +1278,30 @@
  */
 static int w83977af_net_close(struct device *dev)
 {
-	struct irda_device *idev;
+	struct w83977af_ir *self;
 	int iobase;
 	__u8 set;
 
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(dev != NULL, return -1;);
+	
+	self = (struct w83977af_ir *) dev->priv;
 	
+	ASSERT(self != NULL, return 0;);
+	
+	iobase = self->io.fir_base;
+
 	/* 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;
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
 
-	disable_dma(idev->io.dma);
+	disable_dma(self->io.dma);
 
 	/* Save current set */
 	set = inb(iobase+SSR);
@@ -1262,8 +1310,8 @@
 	switch_bank(iobase, SET0);
 	outb(0, iobase+ICR); 
 
-	free_irq(idev->io.irq, idev);
-	free_dma(idev->io.dma);
+	free_irq(self->io.irq, dev);
+	free_dma(self->io.dma);
 
 	/* Restore bank register */
 	outb(set, iobase+SSR);
@@ -1273,12 +1321,66 @@
 	return 0;
 }
 
+/*
+ * Function w83977af_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+static int w83977af_net_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct w83977af_ir *self;
+	unsigned long flags;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		w83977af_change_speed(self, irq->ifr_baudrate);
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = w83977af_is_receiving(self);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
+
+static struct net_device_stats *w83977af_net_get_stats(struct device *dev)
+{
+	struct w83977af_ir *self = (struct w83977af_ir *) dev->priv;
+	
+	return &self->stats;
+}
+
 #ifdef MODULE
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("Winbond W83977AF 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 -urN linux-2.2.15-pre2/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c
--- linux-2.2.15-pre2/drivers/net/sdlamain.c	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sdlamain.c	Mon Dec  3 21:57:53 2001
@@ -133,7 +133,7 @@
 #ifdef MODULE
 int init_module (void)
 #else
-int wanpipe_init(void)
+int wanpipe_init2(void)
 #endif
 {
 	int cnt, err = 0;
diff -urN linux-2.2.15-pre2/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- linux-2.2.15-pre2/drivers/pci/oldproc.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/pci/oldproc.c	Mon Dec  3 21:57:53 2001
@@ -423,6 +423,7 @@
 	DEVICE( LITEON,		LITEON_LNE100TX,"LNE100TX"),
 	DEVICE( NP,		NP_PCI_FDDI,	"NP-PCI"),       
 	DEVICE( ATT,		ATT_L56XMF,	"L56xMF"),
+	DEVICE( ATT,		ATT_L56DVP,	"L56DV+P"),
 	DEVICE( SPECIALIX,	SPECIALIX_IO8,	"IO8+/PCI"),
 	DEVICE( SPECIALIX,	SPECIALIX_XIO,	"XIO/SIO host"),
 	DEVICE( SPECIALIX,	SPECIALIX_RIO,	"RIO host"),
@@ -515,6 +516,7 @@
 	DEVICE( INTEL,		INTEL_82430,	"82430ZX Aries"),
 	DEVICE( INTEL,		INTEL_82434,	"82434LX Mercury/Neptune"),
 	DEVICE( INTEL,		INTEL_I960,	"i960"),
+	DEVICE( INTEL,		INTEL_82559ER,	"82559ER"),
 	DEVICE( INTEL,		INTEL_82092AA_0,"82092AA PCMCIA bridge"),
 	DEVICE( INTEL,		INTEL_82092AA_1,"82092AA EIDE"),
 	DEVICE( INTEL,		INTEL_7116,	"SAA7116"),
diff -urN linux-2.2.15-pre2/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- linux-2.2.15-pre2/drivers/scsi/aic7xxx.c	Tue Jan  4 10:12:19 2000
+++ linux/drivers/scsi/aic7xxx.c	Mon Dec  3 21:57:53 2001
@@ -270,7 +270,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.21"
+#define AIC7XXX_C_VERSION  "5.1.23"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -5141,7 +5141,7 @@
         else if (scb->flags & SCB_MSGOUT_PPR)
         {
           unsigned int max_sync, period;
-          unsigned char options = p->transinfo[tindex].goal_options;
+          unsigned char options = 0;
 
           if (p->features & AHC_ULTRA2)
           {
@@ -5152,9 +5152,10 @@
                   (p->dev_flags[tindex] & DEVICE_SCSI_3) &&
                   (p->transinfo[tindex].goal_width ==
                    MSG_EXT_WDTR_BUS_16_BIT) &&
-                  (options != 0) )
+                  (p->transinfo[tindex].goal_options != 0) )
               {
                 max_sync = AHC_SYNCRATE_ULTRA3;
+                options = p->transinfo[tindex].goal_options;
               }
               else
               {
@@ -5662,16 +5663,6 @@
           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;
@@ -7329,10 +7320,16 @@
   };
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
-#define CLOCK_PULSE(p) \
-  while ((aic_inb(p, SEECTL) & SEERDY) == 0)        \
-  {                                                \
-    ;  /* Do nothing */                                \
+#define CLOCK_PULSE(p)                                               \
+  {                                                                  \
+    int limit = 0;                                                   \
+    while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)) \
+    {                                                                \
+      mb();                                                          \
+      pause_sequencer(p);  /* This is just to generate some PCI */   \
+                           /* so the PCI read is flushed */          \
+      udelay(10);  /* Do nothing */                                  \
+    }                                                                \
   }
 
   /*
@@ -8664,15 +8661,15 @@
       if (!have_seeprom)
       {
         p->sc_size = 128;
-        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+        have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                     scarray, p->sc_size, p->sc_type);
         if (!have_seeprom)
         {
           if(p->sc_type == C46)
-            have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+            have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                         scarray, p->sc_size, C56_66);
           else
-            have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+            have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                         scarray, p->sc_size, C46);
         }
       }
diff -urN linux-2.2.15-pre2/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- linux-2.2.15-pre2/drivers/scsi/megaraid.c	Tue Jan  4 10:12:20 2000
+++ linux/drivers/scsi/megaraid.c	Mon Dec  3 21:57:53 2001
@@ -2,14 +2,14 @@
  *
  *                    Linux MegaRAID device driver
  *
- * Copyright 1998 American Megatrends Inc.
+ * Copyright 1999 American Megatrends Inc.
  *
  *              This program is free software; you can redistribute it and/or
  *              modify it under the terms of the GNU General Public License
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : 1.05
+ * Version : 1.07
  * 
  * Description: Linux device driver for AMI MegaRAID controller
  *
@@ -120,6 +120,9 @@
  *      also enables the driver to handle large amount of I/O requests for
  *      long duration of time.
  *
+ * Version 1.07
+ *    Removed the usage of uaccess.h file for kernel versions less than
+ *    2.0.36, as this file is not present in those versions.
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
@@ -135,7 +138,7 @@
 #define CRLFSTR "\n"
 #define IOCTL_CMD_NEW  0x81
 
-#define MEGARAID_VERSION "v1.05 (October 27, 1999)"
+#define MEGARAID_VERSION "v107 (December 22, 1999)"
 
 
 #include <linux/config.h>
@@ -178,7 +181,9 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#if LINUX_VERSION_CODE > 0x020024
 #include <asm/uaccess.h>
+#endif
 
 #include "sd.h"
 #include "scsi.h"
@@ -265,7 +270,6 @@
 
 
 
-
 #if LINUX_VERSION_CODE > 0x020100
 #  include <asm/spinlock.h>
 #  include <linux/smp.h>
@@ -304,6 +308,7 @@
        cli();
 #  define DRIVER_UNLOCK(p) \
        restore_flags(cpu_flags);
+#  define IO_LOCK_T unsigned long io_flags = 0;
 #  define IO_LOCK(p)   DRIVER_LOCK(p)
 #  define IO_UNLOCK(p) DRIVER_UNLOCK(p)
 #  define le32_to_cpu(x) (x)
@@ -329,6 +334,7 @@
 /*  Use "megaraid=skipXX" as LILO option to prohibit driver from scanning
     XX scsi id on each channel.  Used for Madrona motherboard, where SAF_TE
     processor id cannot be scanned */
+
 static char *megaraid;
 #if LINUX_VERSION_CODE > 0x20100
 #ifdef MODULE
@@ -350,7 +356,6 @@
 #if SERDEBUG
 volatile static spinlock_t serial_lock;
 #endif
-//volatile static spinlock_t mega_lock;
 
 struct proc_dir_entry proc_scsi_megaraid =
 {
@@ -593,7 +598,6 @@
   }
 
   SCpnt = pScb->SCpnt;
-  /*freeSCB(megaCfg, pScb);*/ /*delay this to the end of this func.*/
   pthru = &pScb->pthru;
   mbox = (mega_mailbox *) &pScb->mboxData;
 
@@ -708,13 +712,11 @@
 
   if ( islogical ) {
 	lun = (SCpnt->target * 8) + lun;
-#if 1
         if ( lun > FC_MAX_LOGICAL_DRIVES ){
             SCpnt->result = (DID_BAD_TARGET << 16);
             callDone (SCpnt);
             return NULL;
         }
-#endif
   }
   /*-----------------------------------------------------
    *
@@ -878,7 +880,6 @@
     return NULL;
   }
 
-
   mboxdata = (u8 *) & pScb->mboxData;
   mbox = (mega_ioctl_mbox *) & pScb->mboxData;
   mailbox = (mega_mailbox *) & pScb->mboxData;
@@ -913,6 +914,14 @@
   }
   /* else normal (nonpassthru) command */
 
+#if LINUX_VERSION_CODE > 0x020024
+/*
+ * usage of the function copy from user is used in case of data more than
+ * 4KB.  This is used only with adapters which supports more than 8 logical
+ * drives.  This feature is disabled on kernels earlier or same as 2.0.36
+ * as the uaccess.h file is not available with those kernels.
+ */
+
   if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) { 
             /* use external data area for large xfers  */
      /* If cmnd[0] is set to IOCTL_CMD_NEW then *
@@ -938,6 +947,7 @@
       copy_from_user(kern_area,user_area,xfer_size);
       pScb->kern_area = kern_area;
   }
+#endif
 
   mbox->cmd = data[0];
   mbox->channel = data[1];
@@ -998,7 +1008,9 @@
  *--------------------------------------------------------------------*/
 static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
 {
+#if LINUX_VERSION_CODE >= 0x20100
   IO_LOCK_T
+#endif
   mega_host_config    *megaCfg;
   u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
   u32 dword=0;
@@ -1011,7 +1023,6 @@
   megaCfg = (mega_host_config *) devp;
   mbox = (mega_mailbox *)tmpBox;
 
-
   if (megaCfg->host->irq == irq) {
 
     if (megaCfg->flag & IN_ISR) {
@@ -1031,10 +1042,6 @@
       if (dword != 0x10001234) {
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
-//#if LINUX_VERSION_CODE >= 0x20100
-//        IO_UNLOCK;
-//#endif
-//	break;
 	return;
       }
     }
@@ -1043,10 +1050,6 @@
       if ((byte & VALID_INTR_BYTE) == 0) {
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
-//#if LINUX_VERSION_CODE >= 0x20100
-//	IO_UNLOCK;
-//#endif
-//	break;
 	return;
       }
       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
@@ -1110,9 +1113,6 @@
  */
 	if (pScb->state == SCB_ABORTED) {
           SCpnt = pScb->SCpnt;
-#if DEBUG
-printk("megaraid_isr:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); 
-#endif
 	}
 	if (pScb->state == SCB_RESET) {
           SCpnt = pScb->SCpnt;
@@ -1211,9 +1211,6 @@
 #endif
 
   /* Wait until mailbox is free */
-#if 0
-  while (mega_busyWaitMbox (megaCfg))
-#endif
   if (mega_busyWaitMbox (megaCfg)) {
     printk("Blocked mailbox......!!\n");
     udelay(1000);
@@ -1266,7 +1263,6 @@
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
-//	mega_rundoneq (megaCfg);
       }
 
       WRINDOOR (megaCfg, phys_mbox | 0x2);
@@ -1285,7 +1281,6 @@
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
-//	mega_rundoneq (megaCfg);
       }
       else {
 	TRACE (("Error: NULL pScb!\n"));
@@ -1424,7 +1419,6 @@
   u32 paddr;
   u8 retval;
 
-
   /* Initialize adapter inquiry mailbox*/
   paddr = virt_to_bus (megaCfg->mega_buffer);
   mbox = (mega_mailbox *) mboxData;
@@ -1496,25 +1490,6 @@
     megaCfg->host->can_queue = MAX_COMMANDS-1;
   }
 
-#if 0 
-  int i;
-  printk (KERN_DEBUG "---- Logical drive info from enquiry3 struct----\n");
-  for (i = 0; i < megaCfg->numldrv; i++) {
-    printk ("%d: size: %d prop: %x state: %x\n", i,
-	    enquiry3Pnt->lDrvSize[i],
-	    enquiry3Pnt->lDrvProp[i],
-	    enquiry3Pnt->lDrvState[i]);
-  }
-
-  printk (KERN_DEBUG "---- Physical drive info ----\n");
-  for (i = 0; i < FC_MAX_PHYSICAL_DEVICES; i++) {
-    if (i && !(i % 8))
-      printk ("\n");
-    printk ("%d: %x   ", i, enquiry3Pnt->pDrvState[i]);
-  }
-  printk ("\n");
-#endif
-
 #ifdef HP			/* use HP firmware and bios version encoding */
   sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
 	   megaCfg->productInfo.FwVer[2],
@@ -1573,10 +1548,6 @@
 
 #if LINUX_VERSION_CODE < 0x20100
   while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
-
-#if 0
-  } /* keep auto-indenters happy */
-#endif
 #else
   
   struct pci_dev *pdev = pci_devices;
@@ -1590,7 +1561,7 @@
       pcibios_read_config_word (pciBus, pciDevFun,
 				PCI_CONF_AMISIG,
 				&magic);
-      if (magic != AMI_SIGNATURE) {
+      if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471) ){
         pciIdx++;
 	continue;		/* not an AMI board */
       }
@@ -1602,6 +1573,21 @@
 	    PCI_SLOT (pciDevFun),
 	    PCI_FUNC (pciDevFun));
 
+    /*
+     *	Dont crash on boot with AMI cards configured for I2O. 
+     *  (our I2O code will find them then they will fail oddly until
+     *   we figure why they upset our I2O code). This driver will die
+     *   if it tries to boot an I2O mode board and we dont stop it now.
+     *     - Alan Cox , Red Hat Software, Jan 2000
+     */
+     	    
+    if((pdev->class >> 8) == 0x0E00)	/* Intelligent I/O */
+    {
+    	printk( KERN_INFO "megaraid: Board configured for I2O, ignoring this card. Reconfigure the card\n"
+		KERN_INFO "megaraid: in the BIOS for \"mass storage\" to use it with this driver.\n");
+	continue;
+    }		
+
     /* Read the base port and IRQ from PCI */
 #if LINUX_VERSION_CODE < 0x20100
     pcibios_read_config_dword (pciBus, pciDevFun,
@@ -1824,9 +1810,6 @@
 
   /* If driver in abort or reset.. cancel this command */
   if (megaCfg->flag & IN_ABORT) {
-#if DEBUG
-printk("mq: got a request while in abort\n");
-#endif
     SCpnt->result = (DID_ABORT << 16);
     /* Add Scsi_Command to end of completed queue */
     if( megaCfg->qCompletedH == NULL ) {
@@ -1843,9 +1826,6 @@
     return 0;
   }
   else if (megaCfg->flag & IN_RESET) {
-#if DEBUG
-printk("mq: got a request while in reset\n");
-#endif
     SCpnt->result = (DID_RESET << 16);
     /* Add Scsi_Command to end of completed queue */
     if( megaCfg->qCompletedH == NULL ) {
@@ -1878,16 +1858,9 @@
     megaCfg->qPendingT->next = NULL;
     megaCfg->qPcnt++;
 
-
-    /* Issue any pending command to the card if not in ISR */
-//    if (!(megaCfg->flag & IN_ISR)) {
       mega_runpendq(megaCfg);
-//    }
-/* 
- * try running the pend queue, irrespective of the driver's context.
- * -cn 
- */
 
+#if LINUX_VERSION_CODE > 0x020024
     if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
     {  /* user data from external user buffer */
           char *user_area;
@@ -1905,6 +1878,7 @@
 
           mega_freeSCB(megaCfg, pScb);
     }
+#endif
   }
 
   megaCfg->flag &= ~IN_QUEUE;
@@ -1959,9 +1933,6 @@
 
   megaCfg->flag |= IN_ABORT;
 
-#if DEBUG
-printk("ma:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); 
-#endif
   for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
     if (pScb->SCpnt == SCpnt) {
       /* Found an aborting command */
@@ -2013,20 +1984,6 @@
     }
   }
 
-#if 0
-  TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",
-	  SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
-	  SCpnt->lun));
-  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
-    if (pScb->SCpnt == SCpnt) { 
-      ser_printk("** %d<%x>  %c\n", pScb->SCpnt->pid, pScb->idx+1,
-		 pScb->state == SCB_ACTIVE ? 'A' : 'I');
-#if DEBUG
-      showMbox(pScb);
-#endif
-    }
-  }
-#endif
   megaCfg->flag &= ~IN_ABORT;
 
 #if DEBUG
@@ -2044,12 +2001,11 @@
   megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
   megaCfg->qCcnt--;
 
-  SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
+  SCpnt->host_scribble = (unsigned char *) NULL ;
   /* Callback */
   callDone (SCpnt);
 }
   mega_rundoneq(megaCfg);
-
 
   return rc;
 }
diff -urN linux-2.2.15-pre2/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- linux-2.2.15-pre2/drivers/scsi/megaraid.h	Tue Jan  4 10:12:20 2000
+++ linux/drivers/scsi/megaraid.h	Mon Dec  3 21:57:53 2001
@@ -12,7 +12,6 @@
 #define BOARD_QUARTZ            0x08000000L
 #define BOARD_40LD              0x04000000L
 
-#ifndef HOSTS_C
 #define SCB_FREE     0x0
 #define SCB_ACTIVE   0x1
 #define SCB_WAITQ    0x2
@@ -20,7 +19,6 @@
 #define SCB_COMPLETE 0x4
 #define SCB_ABORTED  0x5
 #define SCB_RESET    0x6
-#endif
 
 #define MEGA_CMD_TIMEOUT        10
 
@@ -109,6 +107,7 @@
 #define PCI_CONF_IRQ_OFFSET        0x3c
 #define PCI_CONF_AMISIG            0xa0
 #define AMI_SIGNATURE              0x3344
+#define AMI_SIGNATURE_471          0xCCCC
 
 #if LINUX_VERSION_CODE < 0x20100
 #define MEGARAID \
diff -urN linux-2.2.15-pre2/fs/Config.in linux/fs/Config.in
--- linux-2.2.15-pre2/fs/Config.in	Mon Aug  9 12:04:40 1999
+++ linux/fs/Config.in	Mon Dec  3 21:57:53 2001
@@ -42,9 +42,9 @@
   bool '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'QNX filesystem support (EXPERIMENTAL)' CONFIG_QNX4FS_FS
+  tristate 'QNX4 filesystem support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS
   if [ "$CONFIG_QNX4FS_FS" != "n" ]; then
-    bool '   QNXFS read-write support (FOR TESTING ONLY)' CONFIG_QNX4FS_RW
+    bool '   QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW
   fi    
 fi
 tristate 'ROM filesystem support' CONFIG_ROMFS_FS
diff -urN linux-2.2.15-pre2/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.2.15-pre2/fs/binfmt_elf.c	Sun Jun 13 10:50:04 1999
+++ linux/fs/binfmt_elf.c	Mon Dec  3 21:57:53 2001
@@ -243,9 +243,10 @@
 
 	/* Now read in all of the header information */
 
-	size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum;
-	if (size > ELF_EXEC_PAGESIZE)
+	if (interp_elf_ex->e_phnum < 1 || interp_elf_ex->e_phnum >
+	    ELF_EXEC_PAGESIZE / sizeof(struct elf_phdr))
 		goto out;
+	size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum;
 	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
 	if (!elf_phdata)
 		goto out;
@@ -333,6 +334,11 @@
 			MAP_FIXED|MAP_PRIVATE, 0);
 
 	*interp_load_addr = load_addr;
+	/*
+	 * AUDIT: is everything deallocated properly if this happens
+	 * to be ~0UL? We'd better switch to out-of-band error reporting.
+	 * Also for a.out.
+	 */
 	error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
 
 out_close:
@@ -447,10 +453,13 @@
 
 	/* Now read in all of the header information */
 
+	if (elf_ex.e_phentsize != sizeof(struct elf_phdr) ||
+	    elf_ex.e_phnum < 1 ||
+	    elf_ex.e_phnum > 65536 / sizeof(struct elf_phdr))
+		goto out;
+
 	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;
@@ -476,8 +485,10 @@
 
 	for (i = 0; i < elf_ex.e_phnum; i++) {
 		if (elf_ppnt->p_type == PT_INTERP) {
-			retval = -EINVAL;
-		  	if (elf_interpreter)
+			retval = -ENOEXEC;
+		  	if (elf_interpreter ||
+			    elf_ppnt->p_filesz < 2 ||
+			    elf_ppnt->p_filesz > PAGE_SIZE)
 				goto out_free_interp;
 
 			/* This is the program interpreter used for
@@ -496,6 +507,7 @@
 					   elf_ppnt->p_filesz, 1);
 			if (retval < 0)
 				goto out_free_interp;
+			elf_interpreter[elf_ppnt->p_filesz - 1] = 0;
 			/* If the program interpreter is one of these two,
 			 * then assume an iBCS2 image. Otherwise assume
 			 * a native linux image.
@@ -685,14 +697,17 @@
 						    &interp_load_addr);
 
 		dput(interpreter_dentry);
-		kfree(elf_interpreter);
 
 		if (elf_entry == ~0UL) {
-			printk(KERN_ERR "Unable to load interpreter\n");
+			printk(KERN_ERR "Unable to load interpreter %.128s\n",
+				elf_interpreter);
+			kfree(elf_interpreter);
 			kfree(elf_phdata);
 			send_sig(SIGSEGV, current, 0);
 			return 0;
 		}
+
+		kfree(elf_interpreter);
 	}
 
 	kfree(elf_phdata);
diff -urN linux-2.2.15-pre2/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.2.15-pre2/fs/proc/array.c	Tue Jan  4 10:12:23 2000
+++ linux/fs/proc/array.c	Mon Dec  3 21:57:53 2001
@@ -1450,7 +1450,7 @@
 		case PROC_PID_CPU:
 			return 0;	
 	}
-	if(capable(CAP_DAC_OVERRIDE) || (current->fsuid == euid && ok))
+	if ((current->fsuid == euid && ok) || capable(CAP_DAC_OVERRIDE))
 		return 0;
 	return 1;
 }
diff -urN linux-2.2.15-pre2/fs/qnx4/BUGS linux/fs/qnx4/BUGS
--- linux-2.2.15-pre2/fs/qnx4/BUGS	Mon Aug 31 13:01:35 1998
+++ linux/fs/qnx4/BUGS	Mon Dec  3 21:57:53 2001
@@ -1,4 +1,13 @@
-Last update: 03-07-1998
+Last update: 1999-12-23
+
+- Fragmented files and directories were incorrectly handled.
+  Fixed 1999-12-23, Anders.
+
+- readdir sometimes returned the same dir entry more than once.
+  Fixed 1999-12-13, Anders.
+
+- File names with a length of exactly 16 chars were handled incorrectly.
+  Fixed 1999-12-11, Anders.
 
 - Files in a subdir can't be accessed, I think that the inode information
   is not correctly copied at some point. Solved 06-06-1998, Richard.
diff -urN linux-2.2.15-pre2/fs/qnx4/README linux/fs/qnx4/README
--- linux-2.2.15-pre2/fs/qnx4/README	Mon Aug 31 13:01:35 1998
+++ linux/fs/qnx4/README	Mon Dec  3 21:57:53 2001
@@ -1,9 +1,9 @@
 
   This is a snapshot of the QNX4 filesystem for Linux.
-  Please send diffs and remarks to <qnxfs@rtc-one.net> .
+  Please send diffs and remarks to <al@alarsen.net> .
   
 Credits :
 
 Richard "Scuba" A. Frowijn     <scuba@wxs.nl>
 Frank "Jedi/Sector One" Denis  <j@4u.net>
-
+Anders Larsen                  <al@alarsen.net> (Maintainer)
diff -urN linux-2.2.15-pre2/fs/qnx4/TODO linux/fs/qnx4/TODO
--- linux-2.2.15-pre2/fs/qnx4/TODO	Mon Aug 31 13:01:35 1998
+++ linux/fs/qnx4/TODO	Mon Dec  3 21:57:53 2001
@@ -1,5 +1,8 @@
 Name       : QNX4 TODO list
-Last update: 29-06-1998
+Last update: 1999-12-23
+
+    - Writing is still unsupported (it may compile, but it certainly won't
+      bring you any joy).
 
     - qnx4_checkroot (inode.c), currently there's a look for the '/' in
       the root direntry, if so then the current mounted device is a qnx4
@@ -11,10 +14,6 @@
       
     - Bitmap functions. To find out the free space, largest free block, etc.
       Partly done (RO), Richard, 05/06/1998. Optimized 20-06-1998, Frank.
-    
-    - Symbolic links. symlinks.c have to be rewritten.
-    
-    - Extended files.
     
     - Complete write, unlink and truncate functions : the bitmap should be
 updated.
diff -urN linux-2.2.15-pre2/fs/qnx4/bitmap.c linux/fs/qnx4/bitmap.c
--- linux-2.2.15-pre2/fs/qnx4/bitmap.c	Tue Sep  1 10:43:13 1998
+++ linux/fs/qnx4/bitmap.c	Mon Dec  3 21:57:53 2001
@@ -1,7 +1,7 @@
 /* 
  * QNX4 file system, Linux implementation.
  * 
- * Version : 0.1
+ * Version : 0.2.1
  * 
  * Using parts of the xiafs filesystem.
  * 
@@ -81,12 +81,14 @@
 	return total_free;
 }
 
-unsigned long qnx4_count_free_inodes(struct super_block *sb)
+int qnx4_bmap(struct inode *inode, int block)
 {
-	return qnx4_count_free_blocks(sb) * QNX4_INODES_PER_BLOCK;	/* FIXME */
+   return qnx4_block_map( inode, block );
 }
 
-int qnx4_is_free(struct super_block *sb, int block)
+#ifdef CONFIG_QNX4FS_RW
+
+int qnx4_is_free(struct super_block *sb, long block)
 {
 	int start = sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk - 1;
 	int size = sb->u.qnx4_sb.BitMap->di_size;
@@ -114,17 +116,6 @@
 
 	return ret;
 }
-
-int qnx4_bmap(struct inode *inode, int block)
-{
-   QNX4DEBUG(("qnx4: bmap on block [%d]\n", block));
-   if (block < 0) {
-      return 0;
-   }
-   return !qnx4_is_free(inode->i_sb, block);
-}
-
-#ifdef CONFIG_QNX4FS_RW
 
 int qnx4_set_bitmap(struct super_block *sb, int block, int busy)
 {
diff -urN linux-2.2.15-pre2/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- linux-2.2.15-pre2/fs/qnx4/dir.c	Tue Oct 26 17:53:42 1999
+++ linux/fs/qnx4/dir.c	Mon Dec  3 21:57:53 2001
@@ -1,7 +1,7 @@
 /* 
  * QNX4 file system, Linux implementation.
  * 
- * Version : 0.1
+ * Version : 0.2.1
  * 
  * Using parts of the xiafs filesystem.
  * 
@@ -20,55 +20,57 @@
 
 #include <asm/segment.h>
 
-static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir);
-
 static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	unsigned int offset;
 	struct buffer_head *bh;
 	struct qnx4_inode_entry *de;
-	long blknum;
-	int i;
+	struct qnx4_link_info *le;
+	unsigned long blknum;
+	int ix, ino;
 	int size;
 
-	blknum = inode->u.qnx4_i.i_first_xtnt.xtnt_blk - 1 +
-	    ((filp->f_pos >> 6) >> 3);
-
 	QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
 	QNX4DEBUG(("filp->f_pos         = %ld\n", (long) filp->f_pos));
-	QNX4DEBUG(("BlkNum              = %ld\n", (long) blknum));
 
 	while (filp->f_pos < inode->i_size) {
+		blknum = qnx4_block_map( inode, filp->f_pos / QNX4_BLOCK_SIZE );
 		bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
-		if(bh==NULL)
-		{
+		if(bh==NULL) {
 			printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
 			break;
 		}
-		i = (filp->f_pos - (((filp->f_pos >> 6) >> 3) << 9)) & 0x3f;
-		while (i < QNX4_INODES_PER_BLOCK) {
-			offset = i * QNX4_DIR_ENTRY_SIZE;
+		ix = (filp->f_pos / QNX4_DIR_ENTRY_SIZE - (filp->f_pos / QNX4_BLOCK_SIZE) * QNX4_INODES_PER_BLOCK) % QNX4_INODES_PER_BLOCK;
+		while (ix < QNX4_INODES_PER_BLOCK) {
+			offset = ix * QNX4_DIR_ENTRY_SIZE;
 			de = (struct qnx4_inode_entry *) (bh->b_data + offset);
 			size = strlen(de->di_fname);
 			if (size) {
-
-				QNX4DEBUG(("qnx4_readdir:%s\n", de->di_fname));
-
-				if ((de->di_mode) || (de->di_status == QNX4_FILE_LINK)) {
-					if (de->di_status) {
-						if (filldir(dirent, de->di_fname, size, filp->f_pos, de->di_first_xtnt.xtnt_blk) < 0) {
-							brelse(bh);
-							return 0;
-						}
+				if ( !(de->di_status & QNX4_FILE_LINK) && size > QNX4_SHORT_NAME_MAX )
+					size = QNX4_SHORT_NAME_MAX;
+				else if ( size > QNX4_NAME_MAX )
+					size = QNX4_NAME_MAX;
+				if ( ( de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK) ) != 0 ) {
+					QNX4DEBUG(("qnx4_readdir:%.*s\n", size, de->di_fname));
+					if ( ( de->di_status & QNX4_FILE_LINK ) == 0 )
+						ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1;
+					else {
+						le  = (struct qnx4_link_info*)de;
+						ino = ( le->dl_inode_blk - 1 ) *
+							QNX4_INODES_PER_BLOCK +
+							le->dl_inode_ndx;
+					}
+					if (filldir(dirent, de->di_fname, size, filp->f_pos, ino) < 0) {
+						brelse(bh);
+						return 0;
 					}
 				}
 			}
-			i++;
+			ix++;
 			filp->f_pos += QNX4_DIR_ENTRY_SIZE;
 		}
 		brelse(bh);
-		blknum++;
 	}
 	UPDATE_ATIME(inode);
 
@@ -77,52 +79,19 @@
 
 static struct file_operations qnx4_dir_operations =
 {
-	NULL,			/* lseek - default */
-	NULL,			/* read */
-	NULL,			/* write - bad */
-	qnx4_readdir,		/* readdir */
-	NULL,			/* poll - default */
-	NULL,			/* ioctl - default */
-	NULL,			/* mmap */
-	NULL,			/* no special open code */
-        NULL,                   /* no special flush code */
-	NULL,			/* no special release code */
-	file_fsync,		/* default fsync */
-	NULL,			/* default fasync */
-	NULL,			/* default check_media_change */
-	NULL,			/* default revalidate */
+	readdir:		qnx4_readdir,
+	fsync:			file_fsync,
 };
 
 struct inode_operations qnx4_dir_inode_operations =
 {
-	&qnx4_dir_operations,
-#ifdef CONFIG_QNX4FS_RW
-	qnx4_create,
-#else
-	NULL,			/* create */
-#endif
-	qnx4_lookup,
-	NULL,			/* link */
+	default_file_ops:	&qnx4_dir_operations,
 #ifdef CONFIG_QNX4FS_RW
-	qnx4_unlink,		/* unlink */
-#else
-	NULL,
+	create:			qnx4_create,
 #endif
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
+	lookup:			qnx4_lookup,
 #ifdef CONFIG_QNX4FS_RW
-	qnx4_rmdir,		/* rmdir */
-#else
-	NULL,
+	unlink:			qnx4_unlink,
+	rmdir:			qnx4_rmdir,
 #endif
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* bmap */
-	NULL,			/* truncate */
-	NULL,			/* permission */
-	NULL			/* smap */
 };
diff -urN linux-2.2.15-pre2/fs/qnx4/file.c linux/fs/qnx4/file.c
--- linux-2.2.15-pre2/fs/qnx4/file.c	Fri Mar 26 13:57:41 1999
+++ linux/fs/qnx4/file.c	Mon Dec  3 21:57:53 2001
@@ -1,7 +1,7 @@
 /* 
  * QNX4 file system, Linux implementation.
  * 
- * Version : 0.1
+ * Version : 0.2.1
  * 
  * Using parts of the xiafs filesystem.
  * 
@@ -34,9 +34,8 @@
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
 
-static int qnx4_readpage(struct file *file, struct page *page);
-
 #ifdef CONFIG_QNX4FS_RW
+
 static ssize_t qnx4_file_write(struct file *filp, const char *buf,
 			       size_t count, loff_t * ppos)
 {
@@ -145,115 +144,27 @@
 #endif
 
 /*
- * We have moostly NULL's here: the current defaults are ok for
+ * We have mostly NULL's here: the current defaults are ok for
  * the qnx4 filesystem.
  */
 static struct file_operations qnx4_file_operations =
 {
-	NULL,			/* lseek - default */
-	generic_file_read,	/* read */
+	read:		generic_file_read,
 #ifdef CONFIG_QNX4FS_RW
-	qnx4_file_write,	/* write */
-#else
-	NULL,
+	write:		qnx4_file_write,
 #endif
-	NULL,			/* readdir - bad */
-	NULL,			/* poll - default */
-	NULL,			/* ioctl - default */
-	generic_file_mmap,	/* mmap */
-	NULL,			/* no special open is needed */
-        NULL,                   /* no special flush code */
-	NULL,			/* release */
+	mmap:		generic_file_mmap,
 #ifdef CONFIG_QNX4FS_RW   
-	qnx4_sync_file,	        /* fsync */
-#else
-        NULL,
+	fsync:		qnx4_sync_file,
 #endif
-	NULL,			/* fasync */
-	NULL,			/* check_media_change */
-	NULL,			/* revalidate */
-	NULL			/* lock */
 };
 
 struct inode_operations qnx4_file_inode_operations =
 {
-	&qnx4_file_operations,	/* default file operations */
-	NULL,			/* create? It's not a directory */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	qnx4_readpage,		/* readpage */
-	NULL,			/* writepage */
-	qnx4_bmap,	        /* bmap */
+	default_file_ops:	&qnx4_file_operations,
+	readpage:		generic_readpage,
+	bmap:			qnx4_bmap,
 #ifdef CONFIG_QNX4FS_RW
-	qnx4_truncate,		/* truncate */
-#else
-	NULL,
+	truncate:		qnx4_truncate,
 #endif
-	NULL,			/* permission */
-	NULL			/* smap */
 };
-
-static int qnx4_readpage(struct file *file, struct page *page)
-{
-	struct dentry *dentry = file->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	struct qnx4_inode_info *qnx4_ino = &inode->u.qnx4_i;
-	unsigned long buf;
-	unsigned long offset, avail, readlen;
-	unsigned long start;
-	unsigned long count;
-	struct buffer_head *bh;
-	int res = -EIO;
-
-	QNX4DEBUG(("qnx4: readpage offset=[%ld]\n", (long) page->offset));
-
-	if (qnx4_ino->i_xblk != 0) {
-		printk("qnx4: sorry, this file is extended, don't know how to handle it (yet) !\n");
-		return -EIO;
-	}
-	atomic_inc(&page->count);
-	set_bit(PG_locked, &page->flags);
-	buf = page_address(page);
-	clear_bit(PG_uptodate, &page->flags);
-	clear_bit(PG_error, &page->flags);
-	offset = page->offset;
-
-	if (offset < inode->i_size) {
-		res = 0;
-		avail = inode->i_size - offset;
-		readlen = MIN(avail, PAGE_SIZE);
-		start = qnx4_ino->i_first_xtnt.xtnt_blk + (offset >> 9) - 1;
-		count = PAGE_SIZE / QNX4_BLOCK_SIZE;
-		do {
-			QNX4DEBUG(("qnx4: reading page starting at [%ld]\n", (long) start));
-			if ((bh = bread(inode->i_dev, start, QNX4_BLOCK_SIZE)) == NULL) {
-				printk("qnx4: data corrupted or I/O error.\n");
-				res = -EIO;
-			} else {
-				memcpy((void *) buf, bh->b_data, QNX4_BLOCK_SIZE);
-			}
-			buf += QNX4_BLOCK_SIZE;
-			start++;
-			count--;
-		} while (count != 0);
-	}
-	if (res != 0) {
-		set_bit(PG_error, &page->flags);
-		memset((void *) buf, 0, PAGE_SIZE);
-	} else {
-		set_bit(PG_uptodate, &page->flags);
-	}
-	clear_bit(PG_locked, &page->flags);
-	wake_up(&page->wait);
-/*  free_page(buf); */
-
-	return res;
-}
diff -urN linux-2.2.15-pre2/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- linux-2.2.15-pre2/fs/qnx4/inode.c	Tue Oct 26 17:53:42 1999
+++ linux/fs/qnx4/inode.c	Mon Dec  3 21:57:53 2001
@@ -1,7 +1,7 @@
 /* 
  * QNX4 file system, Linux implementation.
  * 
- * Version : 0.1
+ * Version : 0.2.1
  * 
  * Using parts of the xiafs filesystem.
  * 
@@ -127,30 +127,18 @@
 
 static struct super_operations qnx4_sops =
 {
-	qnx4_read_inode,
+	read_inode:		qnx4_read_inode,
 #ifdef CONFIG_QNX4FS_RW
-	qnx4_write_inode,
-#else
-	NULL,
+	write_inode:		qnx4_write_inode,
+	put_inode:		qnx4_put_inode,
+	delete_inode:		qnx4_delete_inode,
 #endif
+	put_super:		qnx4_put_super,
 #ifdef CONFIG_QNX4FS_RW
-	qnx4_put_inode,
-	qnx4_delete_inode,
-	NULL,			/* notify_change */
-#else
-	NULL,			/* put_inode */
-	NULL,			/* delete_inode */
-	NULL,			/* notify_change */
+	write_super:		qnx4_write_super,
 #endif
-	qnx4_put_super,
-#ifdef CONFIG_QNX4FS_RW
-	qnx4_write_super,
-#else
-	NULL,
-#endif
-	qnx4_statfs,
-	qnx4_remount,
-	NULL			/* clear_inode */
+	statfs:			qnx4_statfs,
+	remount_fs:		qnx4_remount,
 };
 
 static int qnx4_remount(struct super_block *sb, int *flags, char *data)
@@ -167,23 +155,16 @@
 	return 0;
 }
 
-struct buffer_head *inode_getblk(struct inode *inode, int nr,
+struct buffer_head *qnx4_getblk(struct inode *inode, int nr,
 				 int create)
 {
-	int tmp;
-	int tst;
 	struct buffer_head *result = NULL;
 
-	tst = nr;
-      repeat:
-	tmp = tst;
-	if (tmp) {
-		result = getblk(inode->i_dev, tmp, QNX4_BLOCK_SIZE);
-		if (tmp == tst) {
-			return result;
-		}
-		brelse(result);
-		goto repeat;
+	if ( nr >= 0 )
+		nr = qnx4_block_map( inode, nr );
+	if (nr) {
+		result = getblk(inode->i_dev, nr, QNX4_BLOCK_SIZE);
+		return result;
 	}
 	if (!create) {
 		return NULL;
@@ -210,7 +191,7 @@
 {
 	struct buffer_head *bh;
 
-	bh = inode_getblk(inode, block, create);
+	bh = qnx4_getblk(inode, block, create);
 	if (!bh || buffer_uptodate(bh)) {
 		return bh;
 	}
@@ -224,19 +205,72 @@
 	return NULL;
 }
 
+unsigned long qnx4_block_map( struct inode *inode, long iblock )
+{
+	int ix;
+	long offset, i_xblk;
+	unsigned long block = 0;
+	struct buffer_head *bh = 0;
+	struct qnx4_xblk *xblk = 0;
+	struct qnx4_inode_info *qnx4_inode = &inode->u.qnx4_i;
+	qnx4_nxtnt_t nxtnt = qnx4_inode->i_num_xtnts;
+
+	if ( iblock < qnx4_inode->i_first_xtnt.xtnt_size ) {
+		// iblock is in the first extent. This is easy.
+		block = qnx4_inode->i_first_xtnt.xtnt_blk + iblock - 1;
+	} else {
+		// iblock is beyond first extent. We have to follow the extent chain.
+		i_xblk = qnx4_inode->i_xblk;
+		offset = iblock - qnx4_inode->i_first_xtnt.xtnt_size;
+		ix = 0;
+		while ( --nxtnt > 0 ) {
+			if ( ix == 0 ) {
+				// read next xtnt block.
+				bh = bread( inode->i_dev, i_xblk - 1, QNX4_BLOCK_SIZE );
+				if ( !bh ) {
+					QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
+					return -EIO;
+				}
+				xblk = (struct qnx4_xblk*)bh->b_data;
+				if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) {
+					QNX4DEBUG(("qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk));
+					return -EIO;
+				}
+			}
+			if ( offset < xblk->xblk_xtnts[ix].xtnt_size ) {
+				// got it!
+				block = xblk->xblk_xtnts[ix].xtnt_blk + offset - 1;
+				break;
+			}
+			offset -= xblk->xblk_xtnts[ix].xtnt_size;
+			if ( ++ix >= xblk->xblk_num_xtnts ) {
+				i_xblk = xblk->xblk_next_xblk;
+				ix = 0;
+				brelse( bh );
+				bh = 0;
+			}
+		}
+		if ( bh )
+			brelse( bh );
+	}
+
+	QNX4DEBUG(("qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block));
+	return block;
+}
+
 static int qnx4_statfs(struct super_block *sb,
 		       struct statfs *buf, int bufsize)
 {
 	struct statfs tmp;
 
 	memset(&tmp, 0, sizeof tmp);
-	tmp.f_type = sb->s_magic;
-	tmp.f_bsize = sb->s_blocksize;
-	tmp.f_blocks = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
-	tmp.f_bfree = qnx4_count_free_blocks(sb);
-	tmp.f_bavail = tmp.f_bfree;
-	tmp.f_files = 0x00;	/* change this !!! */
-	tmp.f_ffree = qnx4_count_free_inodes(sb);
+	tmp.f_type    = sb->s_magic;
+	tmp.f_bsize   = sb->s_blocksize;
+	tmp.f_blocks  = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
+	tmp.f_bfree   = qnx4_count_free_blocks(sb);
+	tmp.f_bavail  = tmp.f_bfree;
+	tmp.f_files   = -1;	/* we don't count files */
+	tmp.f_ffree   = -1;	/* inodes are allocated dynamically */
 	tmp.f_namelen = QNX4_NAME_MAX;
 
 	return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
@@ -247,7 +281,7 @@
  * it really _is_ a qnx4 filesystem, and to check the size
  * of the directory entry.
  */
-static const char *qnx4_checkroot(struct super_block *s)
+static const char *qnx4_checkroot(struct super_block *sb)
 {
 	struct buffer_head *bh;
 	struct qnx4_inode_entry *rootdir;
@@ -255,14 +289,14 @@
 	int i, j;
 	int found = 0;
 
-	if (*(s->u.qnx4_sb.sb->RootDir.di_fname) != '/') {
+	if (*(sb->u.qnx4_sb.sb->RootDir.di_fname) != '/') {
 		return "no qnx4 filesystem (no root dir).";
 	} else {
 		QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", kdevname(s->s_dev)));
-		rd = s->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_blk - 1;
-		rl = s->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_size;
+		rd = sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_blk - 1;
+		rl = sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_size;
 		for (j = 0; j < rl; j++) {
-			bh = bread(s->s_dev, rd + j, QNX4_BLOCK_SIZE);	/* root dir, first block */
+			bh = bread(sb->s_dev, rd + j, QNX4_BLOCK_SIZE);	/* root dir, first block */
 			if (bh == NULL) {
 				return "unable to read root entry.";
 			}
@@ -272,13 +306,12 @@
 					QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname));
 					if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) {
 						found = 1;
-						s->u.qnx4_sb.BitMap = rootdir;	/* keep bitmap inode known */
+						sb->u.qnx4_sb.BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL );
+						memcpy( sb->u.qnx4_sb.BitMap, rootdir, sizeof( struct qnx4_inode_entry ) );	/* keep bitmap inode known */
 						break;
 					}
 				}
 			}
-			/* WAIT! s->u.qnx4_sb.BitMap points into bh->b_data
-			   and now we release bh?? */
 			brelse(bh);
 			if (found != 0) {
 				break;
@@ -376,6 +409,7 @@
 
 static void qnx4_put_super(struct super_block *sb)
 {
+	kfree_s( sb->u.qnx4_sb.BitMap, sizeof( struct qnx4_inode_entry ) );
 	MOD_DEC_USE_COUNT;
 	return;
 }
@@ -455,7 +489,7 @@
 
 __initfunc(int init_qnx4_fs(void))
 {
-	printk("QNX4 filesystem v0.2 registered.\n");
+	printk("QNX4 filesystem v0.2.1 registered.\n");
 	return register_filesystem(&qnx4_fs_type);
 }
 
diff -urN linux-2.2.15-pre2/fs/qnx4/namei.c linux/fs/qnx4/namei.c
--- linux-2.2.15-pre2/fs/qnx4/namei.c	Mon May 10 14:14:28 1999
+++ linux/fs/qnx4/namei.c	Mon Dec  3 21:57:53 2001
@@ -1,7 +1,7 @@
 /* 
  * QNX4 file system, Linux implementation.
  * 
- * Version : 0.1
+ * Version : 0.2.1
  * 
  * Using parts of the xiafs filesystem.
  * 
@@ -33,7 +33,7 @@
 		      struct buffer_head *bh, unsigned long *offset)
 {
 	struct qnx4_inode_entry *de;
-	int namelen;
+	int namelen, thislen;
 
 	if (bh == NULL) {
 		printk("qnx4: matching unassigned buffer !\n");
@@ -41,23 +41,24 @@
 	}
 	de = (struct qnx4_inode_entry *) (bh->b_data + *offset);
 	*offset += QNX4_DIR_ENTRY_SIZE;
-	if ((de->di_status & 0x08) == 0x08) {
+	if ((de->di_status & QNX4_FILE_LINK) != 0) {
 		namelen = QNX4_NAME_MAX;
 	} else {
-		namelen = _SHORT_NAME_MAX;
+		namelen = QNX4_SHORT_NAME_MAX;
 	}
 	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
 	if (!len && (de->di_fname[0] == '.') && (de->di_fname[1] == '\0')) {
 		return 1;
 	}
-	if (len != strlen(de->di_fname)) {
+	thislen = strlen( de->di_fname );
+	if ( thislen > namelen )
+		thislen = namelen;
+	if (len != thislen) {
 		return 0;
 	}
 	if (strncmp(name, de->di_fname, len) == 0) {
-		if ((de->di_mode) || (de->di_status == QNX4_FILE_LINK)) {
-			if (de->di_status) {
-				return 1;
-			}
+		if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) {
+			return 1;
 		}
 	}
 	return 0;
@@ -75,19 +76,19 @@
 		return NULL;
 	}
 	bh = NULL;
-	blkofs = dir->u.qnx4_i.i_first_xtnt.xtnt_blk - 1;
-	offset = block = 0;
-	while (block * QNX4_BLOCK_SIZE + offset < dir->i_size) {
+	block = blkofs = offset = 0;
+	while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) {
 		if (!bh) {
-			bh = qnx4_bread(dir, block + blkofs, 0);
+			bh = qnx4_bread(dir, blkofs, 0);
 			if (!bh) {
-				block++;
+				blkofs++;
 				continue;
 			}
 		}
 		*res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
 		if (qnx4_match(len, name, bh, &offset)) {
-			*ino = (block + blkofs) * QNX4_INODES_PER_BLOCK +
+			block = qnx4_block_map( dir, blkofs );
+			*ino = block * QNX4_INODES_PER_BLOCK +
 			    (offset / QNX4_DIR_ENTRY_SIZE) - 1;
 			return bh;
 		}
@@ -97,7 +98,7 @@
 		brelse(bh);
 		bh = NULL;
 		offset = 0;
-		block++;
+		blkofs++;
 	}
 	brelse(bh);
 	*res_dir = NULL;
diff -urN linux-2.2.15-pre2/fs/qnx4/symlinks.c linux/fs/qnx4/symlinks.c
--- linux-2.2.15-pre2/fs/qnx4/symlinks.c	Mon Aug  9 12:04:41 1999
+++ linux/fs/qnx4/symlinks.c	Mon Dec  3 21:57:53 2001
@@ -1,7 +1,7 @@
 /* 
  * QNX4 file system, Linux implementation.
  * 
- * Version : 0.1
+ * Version : 0.2.1
  * 
  * Using parts of the xiafs filesystem.
  * 
@@ -11,8 +11,6 @@
  * 21-06-1998 by Frank Denis : ugly changes to make it compile on Linux 2.1.99+
  */
 
-/* THIS FILE HAS TO BE REWRITTEN */
-
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -30,49 +28,27 @@
  */
 struct inode_operations qnx4_symlink_inode_operations =
 {
-	NULL,			/* no file-operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	qnx4_readlink,		/* readlink */
-	qnx4_follow_link,	/* follow_link */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* bmap */
-	NULL,			/* truncate */
-	NULL			/* permission */
+	readlink:	qnx4_readlink,
+	follow_link:	qnx4_follow_link,
 };
 
 static struct dentry *qnx4_follow_link(struct dentry *dentry,
 				       struct dentry *base, unsigned int follow)
 {
-#if 0
 	struct inode *inode = dentry->d_inode;
 	struct buffer_head *bh;
 
-	if (!inode) {
+	if ( !inode ) {
 		return ERR_PTR(-ENOENT);
 	}
-	if (current->link_count > 5) {
-		return ERR_PTR(-ELOOP);
-	}
-	if (!(bh = qnx4_bread(inode, 0, 0))) {
+	if ( !( bh = qnx4_bread( inode, 0, 0 ) ) ) {
+		dput( base );
 		return ERR_PTR(-EIO);
 	}
-	current->link_count++;
-	current->link_count--;
-	brelse(bh);
-	return 0;
-#else
-	printk("qnx4: qnx4_follow_link needs to be fixed.\n");
-	return ERR_PTR(-EIO);
-#endif
+	UPDATE_ATIME( inode );
+	base = lookup_dentry( bh->b_data, base, follow );
+	brelse( bh );
+	return base;
 }
 
 static int qnx4_readlink(struct dentry *dentry, char *buffer, int buflen)
@@ -81,36 +57,27 @@
 	struct buffer_head *bh;
 	int i;
 	char c;
-	struct qnx4_inode_info *qnx4_ino;
 
 	QNX4DEBUG(("qnx4: qnx4_readlink() called\n"));
 
 	if (buffer == NULL || inode == NULL || !S_ISLNK(inode->i_mode)) {
 		return -EINVAL;
 	}
-	qnx4_ino = &inode->u.qnx4_i;
 	if (buflen > 1023) {
 		buflen = 1023;
 	}
-	bh = bread(inode->i_dev, qnx4_ino->i_first_xtnt.xtnt_blk,
-		   QNX4_BLOCK_SIZE);
+	bh = qnx4_bread( inode, 0, 0 );
 	if (bh == NULL) {
 		QNX4DEBUG(("qnx4: NULL symlink bh\n"));
 		return 0;
 	}
 	QNX4DEBUG(("qnx4: qnx4_bread sym called -> [%s]\n",
 		   bh->b_data));
-	if (bh->b_data[0] != 0) {
-		i = 0;
-		while (i < buflen && (c = bh->b_data[i])) {
-			i++;
-			put_user(c, buffer++);
-		}
-		brelse(bh);
-		return i;
-	} else {
-		brelse(bh);
-		memcpy(buffer, "fixme", 5);
-		return 5;
+	i = 0;
+	while (i < buflen && (c = bh->b_data[i])) {
+		i++;
+		put_user(c, buffer++);
 	}
+	brelse(bh);
+	return i;
 }
diff -urN linux-2.2.15-pre2/include/linux/compatmac.h linux/include/linux/compatmac.h
--- linux-2.2.15-pre2/include/linux/compatmac.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/compatmac.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,163 @@
+  /* 
+   * This header tries to allow you to write 2.3-compatible drivers, 
+   * but (using this header) still allows you to run them on 2.2 and 
+   * 2.0 kernels. 
+   *
+   * Sometimes, a #define replaces a "construct" that older kernels
+   * had. For example, 
+   *
+   *       DECLARE_MUTEX(name);
+   *
+   * replaces the older 
+   *
+   *       struct semaphore name = MUTEX;
+   *
+   * This file then declares the DECLARE_MUTEX macro to compile into the 
+   * older version. 
+   * 
+   * In some cases, a macro or function changes the number of arguments.
+   * In that case, there is nothing we can do except define an access 
+   * macro that provides the same functionality on both versions of Linux. 
+   * 
+   * This is the case for example with the "get_user" macro 2.0 kernels use:
+   *
+   *          a = get_user (b);
+   *  
+   * while newer kernels use 
+   * 
+   *          get_user (a,b);
+   *
+   * This is unfortunate. We therefore define "Get_user (a,b)" which looks
+   * almost the same as the 2.2+ construct, and translates into the 
+   * appropriate sequence for earlier constructs. 
+   * 
+   * Supported by this file are the 2.0 kernels, 2.2 kernels, and the 
+   * most recent 2.3 kernel. 2.3 support will be dropped as soon when 2.4
+   * comes out. 2.0 support may someday be dropped. But then again, maybe 
+   * not. 
+   *
+   * I'll try to maintain this, provided that Linus agrees with the setup. 
+   * Feel free to mail updates or suggestions. 
+   *
+   * -- R.E.Wolff@BitWizard.nl
+   *
+   */
+
+#ifndef COMPATMAC_H
+#define COMPATMAC_H
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < 0x020100    /* Less than 2.1.0 */
+#define TWO_ZERO
+#else
+#if LINUX_VERSION_CODE < 0x020200   /* less than 2.2.x */
+#warning "Please use a 2.2.x kernel. "
+#else
+#if LINUX_VERSION_CODE < 0x020300   /* less than 2.3.x */
+#define TWO_TWO
+#else
+#define TWO_THREE
+#endif
+#endif
+#endif
+
+#ifdef TWO_ZERO
+
+/* Here is the section that makes the 2.2 compatible driver source 
+   work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, 
+   and provide for compatibility stuff here if possible. */
+
+/* Some 200 days (on intel) */
+#define MAX_SCHEDULE_TIMEOUT     ((long)(~0UL>>1))
+
+#include <linux/bios32.h>
+
+#define Get_user(a,b)                a = get_user(b)
+#define Put_user(a,b)                0,put_user(a,b)
+#define copy_to_user(a,b,c)          memcpy_tofs(a,b,c)
+
+static inline int copy_from_user(void *to,const void *from, int c) 
+{
+  memcpy_fromfs(to, from, c);
+  return 0;
+}
+
+#define pci_present                  pcibios_present
+#define pci_read_config_word         pcibios_read_config_word
+#define pci_read_config_dword        pcibios_read_config_dword
+
+static inline unsigned char get_irq (unsigned char bus, unsigned char fn)
+{
+	unsigned char t; 
+	pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t);
+	return t;
+}
+
+static inline void *ioremap(unsigned long base, long length)
+{
+	if (base < 0x100000) return (void *)base;
+	return vremap (base, length);
+}
+
+#define my_iounmap(x, b)             (((long)x<0x100000)?0:vfree ((void*)x))
+
+#define capable(x)                   suser()
+
+#define queue_task                   queue_task_irq_off
+#define tty_flip_buffer_push(tty)    queue_task(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current)      (current->signal & ~current->blocked)
+#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2)            (((long)t1-t2) > 0)
+
+
+#define test_and_set_bit(nr, addr)   set_bit(nr, addr)
+#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
+
+/* Not yet implemented on 2.0 */
+#define ASYNC_SPD_SHI  -1
+#define ASYNC_SPD_WARP -1
+
+
+/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
+   to the "name" field that does exist. As long as the assignments are
+   done in the right order, there is nothing to worry about. */
+#define driver_name           name 
+
+/* Should be in a header somewhere. They are in tty.h on 2.2 */
+#define TTY_HW_COOK_OUT       14 /* Flag to tell ntty what we can handle */
+#define TTY_HW_COOK_IN        15 /* in hardware - output and input       */
+
+/* The return type of a "close" routine. */
+#define INT                   void
+#define NO_ERROR              /* Nothing */
+
+#else
+
+/* The 2.2.x compatibility section. */
+#include <asm/uaccess.h>
+
+
+#define Get_user(a,b)         get_user(a,b)
+#define Put_user(a,b)         put_user(a,b)
+#define get_irq(pdev)         pdev->irq
+
+#define INT                   int
+#define NO_ERROR              0
+
+#define my_iounmap(x,b)       (iounmap((char *)(b)))
+
+#endif
+
+#ifndef TWO_THREE
+/* These are new in 2.3. The source now uses 2.3 syntax, and here is 
+   the compatibility define... */
+#define wait_queue_head_t     struct wait_queue *
+#define DECLARE_MUTEX(name)   struct semaphore name = MUTEX
+#define DECLARE_WAITQUEUE(wait, current) \
+                              struct wait_queue wait = { current, NULL }
+
+#endif
+
+
+#endif
diff -urN linux-2.2.15-pre2/include/linux/generic_serial.h linux/include/linux/generic_serial.h
--- linux-2.2.15-pre2/include/linux/generic_serial.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/generic_serial.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,105 @@
+/*
+ *  generic_serial.h
+ *
+ *  Copyright (C) 1998 R.E.Wolff@BitWizard.nl
+ *
+ *  written for the SX serial driver.
+ *     Contains the code that should be shared over all the serial drivers.
+ *
+ *  Version 0.1 -- December, 1998.
+ */
+
+#ifndef GENERIC_SERIAL_H
+#define GENERIC_SERIAL_H
+
+
+
+
+struct real_driver {
+  void                    (*disable_tx_interrupts) (void *);
+  void                    (*enable_tx_interrupts) (void *);
+  void                    (*disable_rx_interrupts) (void *);
+  void                    (*enable_rx_interrupts) (void *);
+  int                     (*get_CD) (void *);
+  void                    (*shutdown_port) (void*);
+  int                     (*set_real_termios) (void*);
+  int                     (*chars_in_buffer) (void*);
+  void                    (*close) (void*);
+  void                    (*hungup) (void*);
+  void                    (*getserial) (void*, struct serial_struct *sp);
+};
+
+
+
+struct gs_port {
+  int                     magic;
+  unsigned char           *xmit_buf; 
+  int                     xmit_head;
+  int                     xmit_tail;
+  int                     xmit_cnt;
+  /*  struct semaphore        port_write_sem; */
+  int                     flags;
+  struct termios          normal_termios;
+  struct termios          callout_termios;
+  wait_queue_head_t       open_wait;
+  wait_queue_head_t       close_wait;
+  long                    session;
+  long                    pgrp;
+  int                     count;
+  int                     blocked_open;
+  struct tty_struct       *tty;
+  int                     event;
+  unsigned short          closing_wait;
+  int                     close_delay;
+  struct real_driver      *rd;
+  int                     wakeup_chars;
+  int                     baud_base;
+  int                     baud;
+  int                     custom_divisor;
+};
+
+
+/* Flags */
+/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
+   used in serial.c, but they are also used in all other serial drivers. 
+   Make sure they don't clash with these here... */
+#define GS_TX_INTEN      0x00800000
+#define GS_RX_INTEN      0x00400000
+#define GS_ACTIVE        0x00200000
+
+
+
+#define GS_TYPE_NORMAL   1
+#define GS_TYPE_CALLOUT  2
+
+
+#define GS_DEBUG_FLUSH   0x00000001
+#define GS_DEBUG_BTR     0x00000002
+#define GS_DEBUG_TERMIOS 0x00000004
+#define GS_DEBUG_STUFF   0x00000008
+#define GS_DEBUG_CLOSE   0x00000010
+#define GS_DEBUG_FLOW    0x00000020
+
+
+void gs_put_char(struct tty_struct *tty, unsigned char ch);
+int  gs_write(struct tty_struct *tty, int from_user, 
+             const unsigned char *buf, int count);
+int  gs_write_room(struct tty_struct *tty);
+int  gs_chars_in_buffer(struct tty_struct *tty);
+void gs_flush_buffer(struct tty_struct *tty);
+void gs_flush_chars(struct tty_struct *tty);
+void gs_stop(struct tty_struct *tty);
+void gs_start(struct tty_struct *tty);
+void gs_hangup(struct tty_struct *tty);
+void gs_do_softint(void *private_);
+int  block_til_ready(void *port, struct file *filp);
+void gs_close(struct tty_struct *tty, struct file *filp);
+void gs_set_termios (struct tty_struct * tty, 
+                     struct termios * old_termios);
+int  gs_init_port(struct gs_port *port);
+int  gs_setserial(struct gs_port *port, struct serial_struct *sp);
+void gs_getserial(struct gs_port *port, struct serial_struct *sp);
+
+extern int gs_debug;
+
+#endif
diff -urN linux-2.2.15-pre2/include/linux/irda.h linux/include/linux/irda.h
--- linux-2.2.15-pre2/include/linux/irda.h	Sat Apr 24 17:49:37 1999
+++ linux/include/linux/irda.h	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Mar  8 14:06:12 1999
- * Modified at:   Mon Mar 22 14:14:54 1999
+ * Modified at:   Sat Dec 25 16:06:42 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -19,7 +19,7 @@
  *     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.
- *     
+ *
  ********************************************************************/
 
 #ifndef KERNEL_IRDA_H
@@ -44,17 +44,36 @@
 #define HINT_OBEX        0x20
 
 /* IrLMP character code values */
-#define CS_ASCII       0x00
-#define	CS_ISO_8859_1  0x01
-#define	CS_ISO_8859_2  0x02
-#define	CS_ISO_8859_3  0x03
-#define	CS_ISO_8859_4  0x04
-#define	CS_ISO_8859_5  0x05
-#define	CS_ISO_8859_6  0x06
-#define	CS_ISO_8859_7  0x07
-#define	CS_ISO_8859_8  0x08
-#define	CS_ISO_8859_9  0x09
-#define CS_UNICODE     0xff
+#define CS_ASCII         0x00
+#define	CS_ISO_8859_1    0x01
+#define	CS_ISO_8859_2    0x02
+#define	CS_ISO_8859_3    0x03
+#define	CS_ISO_8859_4    0x04
+#define	CS_ISO_8859_5    0x05
+#define	CS_ISO_8859_6    0x06
+#define	CS_ISO_8859_7    0x07
+#define	CS_ISO_8859_8    0x08
+#define	CS_ISO_8859_9    0x09
+#define CS_UNICODE       0xff
+
+/* These are the currently known dongles */
+typedef enum {
+	IRDA_TEKRAM_DONGLE       = 0,
+	IRDA_ESI_DONGLE          = 1,
+	IRDA_ACTISYS_DONGLE      = 2,
+	IRDA_ACTISYS_PLUS_DONGLE = 3,
+	IRDA_GIRBIL_DONGLE       = 4,
+	IRDA_LITELINK_DONGLE     = 5,
+	IRDA_AIRPORT_DONGLE      = 6,
+	IRDA_OLD_BELKIN_DONGLE   = 7,
+} IRDA_DONGLE;
+
+/* Protocol types to be used for SOCK_DGRAM */
+enum {
+	IRDAPROTO_UNITDATA = 0,
+	IRDAPROTO_ULTRA    = 1,
+	IRDAPROTO_MAX
+};
 
 #define SOL_IRLMP      266 /* Same as SOL_IRDA for now */
 #define SOL_IRTTP      266 /* Same as SOL_IRDA for now */
@@ -62,37 +81,39 @@
 #define IRLMP_ENUMDEVICES        1
 #define IRLMP_IAS_SET            2
 #define IRLMP_IAS_QUERY          3
-#define IRLMP_DISCOVERY_MASK_SET 4
-
-#define IRTTP_QOS_SET            5
-#define IRTTP_QOS_GET            6
-#define IRTTP_MAX_SDU_SIZE       7
-
-#define IAS_MAX_STRING           256
-#define IAS_MAX_OCTET_STRING     1024
-#define IAS_MAX_CLASSNAME        64
-#define IAS_MAX_ATTRIBNAME       256
+#define IRLMP_HINTS_SET          4
+#define IRLMP_QOS_SET            5
+#define IRLMP_QOS_GET            6
+#define IRLMP_MAX_SDU_SIZE       7
+#define IRLMP_IAS_GET            8
+
+#define IRTTP_MAX_SDU_SIZE IRLMP_MAX_SDU_SIZE /* Compatibility */
+
+#define IAS_MAX_STRING         256
+#define IAS_MAX_OCTET_STRING  1024
+#define IAS_MAX_CLASSNAME       64
+#define IAS_MAX_ATTRIBNAME     256
 
-#define LSAP_ANY                 0xff
+#define LSAP_ANY              0xff
 
 struct sockaddr_irda {
-	sa_family_t   sir_family;   /* AF_IRDA */
-	unsigned char sir_lsap_sel; /* LSAP/TSAP selector */
-	unsigned int  sir_addr;     /* Device address */
-	char          sir_name[25]; /* Usually <service>:IrDA:TinyTP */
+	sa_family_t sir_family;   /* AF_IRDA */
+	__u8        sir_lsap_sel; /* LSAP selector */
+	__u32       sir_addr;     /* Device address */
+	char        sir_name[25]; /* Usually <service>:IrDA:TinyTP */
 };
 
 struct irda_device_info {
-	unsigned int  saddr;       /* Address of remote device */
-	unsigned int  daddr;       /* Link where it was discovered */
-	char          info[22];     /* Description */
-	unsigned char charset;      /* Charset used for description */
-	unsigned char hints[2];     /* Hint bits */
+	__u32       saddr;    /* Address of local interface */
+	__u32       daddr;    /* Address of remote device */
+	char        info[22]; /* Description */
+	__u8        charset;  /* Charset used for description */
+	__u8        hints[2]; /* Hint bits */
 };
 
 struct irda_device_list {
-       unsigned int len;
-       struct irda_device_info dev[0];
+       __u32 len;
+       struct irda_device_info dev[1];
 };
 
 struct irda_ias_set {
@@ -103,15 +124,71 @@
 		unsigned int irda_attrib_int;
 		struct {
 			unsigned short len;
-			u_char OctetSeq[IAS_MAX_OCTET_STRING];
+			__u8 octet_seq[IAS_MAX_OCTET_STRING];
 		} irda_attrib_octet_seq;
 		struct {
-			unsigned char len;
-			unsigned char charset;
-			unsigned char string[IAS_MAX_STRING];
+			__u8 len;
+			__u8 charset;
+			__u8 string[IAS_MAX_STRING];
 		} irda_attrib_string;
 	} attribute;
 };
+
+/* Some private IOCTL's (max 16) */
+#define SIOCSDONGLE    (SIOCDEVPRIVATE + 0)
+#define SIOCGDONGLE    (SIOCDEVPRIVATE + 1)
+#define SIOCSBANDWIDTH (SIOCDEVPRIVATE + 2)
+#define SIOCSMEDIABUSY (SIOCDEVPRIVATE + 3)
+#define SIOCGMEDIABUSY (SIOCDEVPRIVATE + 4)
+#define SIOCGRECEIVING (SIOCDEVPRIVATE + 5)
+#define SIOCSMODE      (SIOCDEVPRIVATE + 6)
+#define SIOCGMODE      (SIOCDEVPRIVATE + 7)
+#define SIOCSDTRRTS    (SIOCDEVPRIVATE + 8)
+#define SIOCGQOS       (SIOCDEVPRIVATE + 9)
+
+/* No reason to include <linux/if.h> just because of this one ;-) */
+#define IRNAMSIZ 16 
+
+/* IrDA quality of service information (must not exceed 16 bytes) */
+struct if_irda_qos {
+	unsigned long  baudrate;
+	unsigned short data_size;
+	unsigned short window_size;
+	unsigned short min_turn_time;
+	unsigned short max_turn_time;
+	unsigned char  add_bofs;
+	unsigned char  link_disc;
+};
+
+/* For setting RTS and DTR lines of a dongle */
+struct if_irda_line {
+	__u8 dtr;
+	__u8 rts;
+};
+
+/* IrDA interface configuration (data part must not exceed 16 bytes) */
+struct if_irda_req {
+	union {
+		char ifrn_name[IRNAMSIZ];  /* if name, e.g. "irda0" */
+	} ifr_ifrn;
+	
+	/* Data part */
+	union {
+		struct if_irda_line ifru_line;
+		struct if_irda_qos  ifru_qos;
+		unsigned short      ifru_flags;
+		unsigned int        ifru_receiving;
+		unsigned int        ifru_mode;
+		unsigned int        ifru_dongle;
+	} ifr_ifru;
+};
+
+#define ifr_baudrate  ifr_ifru.ifru_qos.baudrate
+#define ifr_receiving ifr_ifru.ifru_receiving 
+#define ifr_dongle    ifr_ifru.ifru_dongle
+#define ifr_mode      ifr_ifru.ifru_mode
+#define ifr_dtr       ifr_ifru.ifru_line.dtr
+#define ifr_rts       ifr_ifru.ifru_line.rts
 
 #endif /* KERNEL_IRDA_H */
 
diff -urN linux-2.2.15-pre2/include/linux/pci.h linux/include/linux/pci.h
--- linux-2.2.15-pre2/include/linux/pci.h	Tue Jan  4 10:12:25 2000
+++ linux/include/linux/pci.h	Mon Dec  3 21:57:53 2001
@@ -889,6 +889,7 @@
 
 #define PCI_VENDOR_ID_ATT		0x11c1
 #define PCI_DEVICE_ID_ATT_L56XMF	0x0440
+#define PCI_DEVICE_ID_ATT_L56DVP	0x0480
 
 #define PCI_VENDOR_ID_SPECIALIX		0x11cb
 #define PCI_DEVICE_ID_SPECIALIX_IO8	0x2000
@@ -1082,6 +1083,7 @@
 #define PCI_DEVICE_ID_INTEL_82430	0x0486
 #define PCI_DEVICE_ID_INTEL_82434	0x04a3
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
+#define PCI_DEVICE_ID_INTEL_82559ER	0x1209
 #define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
 #define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
 #define PCI_DEVICE_ID_INTEL_7116	0x1223
diff -urN linux-2.2.15-pre2/include/linux/qnx4_fs.h linux/include/linux/qnx4_fs.h
--- linux-2.2.15-pre2/include/linux/qnx4_fs.h	Fri Apr 23 21:20:38 1999
+++ linux/include/linux/qnx4_fs.h	Mon Dec  3 21:57:53 2001
@@ -2,8 +2,8 @@
  *  Name                         : qnx4_fs.h
  *  Author                       : Richard Frowijn
  *  Function                     : qnx4 global filesystem definitions
- *  Version                      : 1.0
- *  Last modified                : 23-03-1998
+ *  Version                      : 1.0.2
+ *  Last modified                : 2000-01-15
  *
  *  History                      : 23-03-1998 created
  */
@@ -14,7 +14,7 @@
 
 #define QNX4_ROOT_INO 1
 
-#define _MAX_XTNTS_PER_XBLK	60
+#define QNX4_MAX_XTNTS_PER_XBLK	60
 /* for di_status */
 #define QNX4_FILE_USED          0x01
 #define QNX4_FILE_MODIFIED      0x02
@@ -34,48 +34,48 @@
 #define QNX4_INODES_PER_BLOCK   0x08	/* 512 / 64 */
 
 /* for filenames */
-#define _SHORT_NAME_MAX        16
-#define QNX4_NAME_MAX          48
+#define QNX4_SHORT_NAME_MAX	16
+#define QNX4_NAME_MAX		48
 
 /*
  * This is the original qnx4 inode layout on disk.
  */
 struct qnx4_inode_entry {
-	char di_fname[16];
-	off_t di_size;
-	_xtnt_t di_first_xtnt;
-	long di_xblk;
-	time_t di_ftime;
-	time_t di_mtime;
-	time_t di_atime;
-	time_t di_ctime;
-	_nxtnt_t di_num_xtnts;
-	mode_t di_mode;
-	muid_t di_uid;
-	mgid_t di_gid;
-	nlink_t di_nlink;
-	char di_zero[4];
-	_ftype_t di_type;
-	unsigned char di_status;
+	char		di_fname[QNX4_SHORT_NAME_MAX];
+	qnx4_off_t	di_size;
+	qnx4_xtnt_t	di_first_xtnt;
+	__u32		di_xblk;
+	__s32		di_ftime;
+	__s32		di_mtime;
+	__s32		di_atime;
+	__s32		di_ctime;
+	qnx4_nxtnt_t	di_num_xtnts;
+	qnx4_mode_t	di_mode;
+	qnx4_muid_t	di_uid;
+	qnx4_mgid_t	di_gid;
+	qnx4_nlink_t	di_nlink;
+	__u8		di_zero[4];
+	qnx4_ftype_t	di_type;
+	__u8		di_status;
 };
 
 struct qnx4_link_info {
-	char dl_fname[QNX4_NAME_MAX];
-	long dl_inode_blk;
-	unsigned char dl_inode_ndx;
-	unsigned char dl_spare[10];
-	unsigned char dl_status;
+	char		dl_fname[QNX4_NAME_MAX];
+	__u32		dl_inode_blk;
+	__u8		dl_inode_ndx;
+	__u8		dl_spare[10];
+	__u8		dl_status;
 };
 
 struct qnx4_xblk {
-	long xblk_next_xblk;
-	long xblk_prev_xblk;
-	unsigned char xblk_num_xtnts;
-	char xblk_spare[3];
-	long xblk_num_blocks;
-	_xtnt_t xblk_xnts[_MAX_XTNTS_PER_XBLK];
-	char xblk_signature[8];
-	_xtnt_t xblk_first_xtnt;
+	__u32		xblk_next_xblk;
+	__u32		xblk_prev_xblk;
+	__u8		xblk_num_xtnts;
+	__u8		xblk_spare[3];
+	__s32		xblk_num_blocks;
+	qnx4_xtnt_t	xblk_xtnts[QNX4_MAX_XTNTS_PER_XBLK];
+	char		xblk_signature[8];
+	qnx4_xtnt_t	xblk_first_xtnt;
 };
 
 struct qnx4_super_block {
@@ -96,8 +96,8 @@
 #endif
 
 extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry);
-extern unsigned long qnx4_count_free_inodes(struct super_block *sb);
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
+extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
 
 extern struct buffer_head *qnx4_getblk(struct inode *, int, int);
 extern struct buffer_head *qnx4_bread(struct inode *, int, int);
@@ -107,8 +107,8 @@
 extern struct inode_operations qnx4_file_inode_operations;
 extern struct inode_operations qnx4_dir_inode_operations;
 extern struct inode_operations qnx4_symlink_inode_operations;
-extern int qnx4_is_free(struct super_block *sb, int block);
-extern int qnx4_set_bitmap(struct super_block *sb, int block, int busy);
+extern int qnx4_is_free(struct super_block *sb, long block);
+extern int qnx4_set_bitmap(struct super_block *sb, long block, int busy);
 extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode);
 extern void qnx4_truncate(struct inode *inode);
 extern void qnx4_free_inode(struct inode *inode);
@@ -116,7 +116,7 @@
 extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry);
 extern int qnx4_sync_file(struct file *file, struct dentry *dentry);
 extern int qnx4_sync_inode(struct inode *inode);
-extern int qnx4_bmap(struct inode *inode, int block);
+extern int qnx4_bmap(struct inode *inode, int iblock);
 
 #endif				/* __KERNEL__ */
 
diff -urN linux-2.2.15-pre2/include/linux/qnx4_fs_i.h linux/include/linux/qnx4_fs_i.h
--- linux-2.2.15-pre2/include/linux/qnx4_fs_i.h	Mon Aug 31 13:01:35 1998
+++ linux/include/linux/qnx4_fs_i.h	Mon Dec  3 21:57:53 2001
@@ -2,11 +2,11 @@
  *  Name                         : qnx4_fs_i.h
  *  Author                       : Richard Frowijn
  *  Function                     : qnx4 inode definitions
- *  Version                      : 1.0
- *  Last modified                : 25-05-1998
- * 
+ *  Version                      : 1.0.2
+ *  Last modified                : 2000-01-06
+ *
  *  History                      : 23-03-1998 created
- * 
+ *
  */
 #ifndef _QNX4_FS_I
 #define _QNX4_FS_I
@@ -14,25 +14,25 @@
 #include <linux/qnxtypes.h>
 
 /*
- * qnx4 fs inode entry 
+ * qnx4 fs inode entry
  */
 struct qnx4_inode_info {
-	char i_reserved[16];	/* 16 */
-	off_t i_size;		/*  4 */
-	_xtnt_t i_first_xtnt;	/*  8 */
-	long i_xblk;		/*  4 */
-	time_t i_ftime;		/*  4 */
-	time_t i_mtime;		/*  4 */
-	time_t i_atime;		/*  4 */
-	time_t i_ctime;		/*  4 */
-	_nxtnt_t i_num_xtnts;	/*  2 */
-	mode_t i_mode;		/*  2 */
-	muid_t i_uid;		/*  2 */
-	mgid_t i_gid;		/*  2 */
-	nlink_t i_nlink;	/*  2 */
-	char i_zero[4];		/*  4 */
-	_ftype_t i_type;	/*  1 */
-	unsigned char i_status;	/*  1 */
+	char		i_reserved[16];	/* 16 */
+	qnx4_off_t	i_size;		/*  4 */
+	qnx4_xtnt_t	i_first_xtnt;	/*  8 */
+	__u32		i_xblk;		/*  4 */
+	__s32		i_ftime;	/*  4 */
+	__s32		i_mtime;	/*  4 */
+	__s32		i_atime;	/*  4 */
+	__s32		i_ctime;	/*  4 */
+	qnx4_nxtnt_t	i_num_xtnts;	/*  2 */
+	qnx4_mode_t	i_mode;		/*  2 */
+	qnx4_muid_t	i_uid;		/*  2 */
+	qnx4_mgid_t	i_gid;		/*  2 */
+	qnx4_nlink_t	i_nlink;	/*  2 */
+	__u8		i_zero[4];	/*  4 */
+	qnx4_ftype_t	i_type;		/*  1 */
+	__u8		i_status;	/*  1 */
 };
 
 #endif
diff -urN linux-2.2.15-pre2/include/linux/qnx4_fs_sb.h linux/include/linux/qnx4_fs_sb.h
--- linux-2.2.15-pre2/include/linux/qnx4_fs_sb.h	Mon Aug 31 13:01:35 1998
+++ linux/include/linux/qnx4_fs_sb.h	Mon Dec  3 21:57:53 2001
@@ -2,8 +2,8 @@
  *  Name                         : qnx4_fs_sb.h
  *  Author                       : Richard Frowijn
  *  Function                     : qnx4 superblock definitions
- *  Version                      : 1.0
- *  Last modified                : 20-05-1998
+ *  Version                      : 1.0.2
+ *  Last modified                : 2000-01-06
  * 
  *  History                      : 23-03-1998 created
  * 
@@ -11,17 +11,17 @@
 #ifndef _QNX4_FS_SB
 #define _QNX4_FS_SB
 
-#include <linux/qnxtypes.h>
+#include <linux/qnx4_fs.h>
 
 /*
  * qnx4 super-block data in memory
  */
 
 struct qnx4_sb_info {
-	struct buffer_head *sb_buf;	/* superblock buffer */
-	struct qnx4_super_block *sb;	/* our superblock */
-	unsigned int Version;	/* may be useful */
-	struct qnx4_inode_entry *BitMap;	/* useful */
+	struct buffer_head	*sb_buf;	/* superblock buffer */
+	struct qnx4_super_block	*sb;		/* our superblock */
+	unsigned int		Version;	/* may be useful */
+	struct qnx4_inode_entry	*BitMap;	/* useful */
 };
 
 #endif
diff -urN linux-2.2.15-pre2/include/linux/qnxtypes.h linux/include/linux/qnxtypes.h
--- linux-2.2.15-pre2/include/linux/qnxtypes.h	Mon Aug 31 13:01:35 1998
+++ linux/include/linux/qnxtypes.h	Mon Dec  3 21:57:53 2001
@@ -2,27 +2,28 @@
  *  Name                         : qnxtypes.h
  *  Author                       : Richard Frowijn
  *  Function                     : standard qnx types
- *  Version                      : 1.0
- *  Last modified                : 22-03-1998
- * 
+ *  Version                      : 1.0.2
+ *  Last modified                : 2000-01-06
+ *
  *  History                      : 22-03-1998 created
- * 
+ *
  */
 
 #ifndef _QNX4TYPES_H
 #define _QNX4TYPES_H
 
-typedef unsigned short _nxtnt_t;
-typedef unsigned char _ftype_t;
+typedef __u16 qnx4_nxtnt_t;
+typedef __u8  qnx4_ftype_t;
 
 typedef struct {
-	long xtnt_blk;
-	long xtnt_size;
-} _xtnt_t;
+	__u32 xtnt_blk;
+	__u32 xtnt_size;
+} qnx4_xtnt_t;
 
-typedef unsigned short muid_t;
-typedef unsigned short mgid_t;
-typedef unsigned long qnx_off_t;
-typedef unsigned short qnx_nlink_t;
+typedef __u16 qnx4_mode_t;
+typedef __u16 qnx4_muid_t;
+typedef __u16 qnx4_mgid_t;
+typedef __u32 qnx4_off_t;
+typedef __u16 qnx4_nlink_t;
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/discovery.h linux/include/net/irda/discovery.h
--- linux-2.2.15-pre2/include/net/irda/discovery.h	Sat Apr 24 17:50:05 1999
+++ linux/include/net/irda/discovery.h	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr  6 16:53:53 1999
- * Modified at:   Thu Apr 22 11:04:56 1999
+ * Modified at:   Tue Oct  5 10:05:10 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -39,28 +39,30 @@
 #define DISCOVERY_EXPIRE_TIMEOUT 6*HZ
 #define DISCOVERY_DEFAULT_SLOTS  0
 
+#define NICKNAME_MAX_LEN 21
+
 /*
  * The DISCOVERY structure is used for both discovery requests and responses
  */
 typedef struct {
-	QUEUE queue;             /* Must be first! */
+	queue_t q;               /* Must be first! */
 
 	__u32      saddr;        /* Which link the device was discovered */
 	__u32      daddr;        /* Remote device address */
 	LAP_REASON condition;    /* More info about the discovery */
 
 	__u16_host_order hints;  /* Discovery hint bits */
-	__u8       charset;
-	char       info[32];     /* Usually the name of the device */
-	__u8       info_len;     /* Length of device info field */
+	__u8       charset;      /* Encoding of nickname */
+	char       nickname[22]; /* The name of the device (21 bytes + \0) */
+	int        name_len;     /* Lenght of nickname */
 
 	int        gen_addr_bit; /* Need to generate a new device address? */
 	int        nslots;       /* Number of slots to use when discovering */
-	int        timestamp;    /* Time discovered */
+	unsigned long timestamp; /* Time discovered */
 } discovery_t;
 
 void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery);
 void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log);
-void irlmp_expire_discoveries(hashbin_t *log, int saddr, int force);
+void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force);
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/dongle.h linux/include/net/irda/dongle.h
--- linux-2.2.15-pre2/include/net/irda/dongle.h	Tue Oct 26 17:53:42 1999
+++ linux/include/net/irda/dongle.h	Wed Dec 31 16:00:00 1969
@@ -1,52 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      dongle.h
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Wed Oct 21 22:47:12 1998
- * Modified at:   Sun May 16 13:40:03 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
- *      
- *     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.
- *     
- ********************************************************************/
-
-#ifndef DONGLE_H
-#define DONGLE_H
-
-#include <net/irda/qos.h>
-
-/* These are the currently known dongles */
-typedef enum {
-	TEKRAM_DONGLE,
-	ESI_DONGLE,
-	ACTISYS_DONGLE,
-	ACTISYS_PLUS_DONGLE,
-	GIRBIL_DONGLE,
-	LITELINK_DONGLE,
-	AIRPORT_DONGLE,
-} IRDA_DONGLE;
-
-struct irda_device;
-
-struct dongle {
-	IRDA_DONGLE type;
-	void (*open)(struct irda_device *, int type);
-	void (*close)(struct irda_device *);
-	void (*reset)( struct irda_device *);
-	void (*change_speed)( struct irda_device *, int baudrate);
-	void (*qos_init)( struct irda_device *, struct qos_info *);
-};
-
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/ircomm_common.h linux/include/net/irda/ircomm_common.h
--- linux-2.2.15-pre2/include/net/irda/ircomm_common.h	Mon Jun  7 16:19:59 1999
+++ linux/include/net/irda/ircomm_common.h	Wed Dec 31 16:00:00 1969
@@ -1,270 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      ircomm_common.h
- * Version:       
- * Description:   An implementation of IrCOMM service interface and state machine 
- * Status:        Experimental.
- * Author:        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
- *     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, Takahide Higuchi, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRCOMM_H
-#define IRCOMM_H
-
-/* #define DEBUG(n, args...) printk( KERN_DEBUG args) */ /* enable all debug message */
-
-#include <linux/types.h>
-#include <net/irda/irmod.h> 
-
-typedef enum {
-        COMM_IDLE,
-
-	COMM_DISCOVERY_WAIT,
-	COMM_QUERYPARAM_WAIT,
-	COMM_QUERYLSAP_WAIT,
-
-	COMM_WAITI,
-	COMM_WAITR,
-	COMM_CONN,
-} IRCOMM_STATE;
-
-/* IrCOMM Events */
-typedef enum {
-	IRCOMM_CONNECT_REQUEST,
-	TTP_CONNECT_INDICATION,
-	LMP_CONNECT_INDICATION,
-
-	TTP_CONNECT_CONFIRM,
-	TTP_DISCONNECT_INDICATION,
-	LMP_CONNECT_CONFIRM,
-	LMP_DISCONNECT_INDICATION,
-
-	IRCOMM_CONNECT_RESPONSE,
-	IRCOMM_DISCONNECT_REQUEST,
-
-	TTP_DATA_INDICATION,
-	IRCOMM_DATA_REQUEST,
-	LMP_DATA_INDICATION,
-	IRCOMM_CONTROL_REQUEST,
-	
-	DISCOVERY_INDICATION,
-	GOT_PARAMETERS,
-	GOT_LSAPSEL,
-	QUERYIAS_ERROR,
-
-} IRCOMM_EVENT;
-
-typedef enum {
-	TX_READY,
-	TX_BUSY,
-
-	IAS_PARAM,
-	CONTROL_CHANNEL,
-} IRCOMM_CMD;
-
-
-
-#define IRCOMM_MAGIC            0x434f4d4d
-#define COMM_INIT_CTRL_PARAM    3          /* length of initial control parameters */
-#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 */
-
-
-
-
-#define UNKNOWN         0x00            /* not defined yet. */
-/* we use 9wire if servicetype=DEFAULT, but is it good? */
-#define DEFAULT         0x0a            /* private number */
-#define THREE_WIRE_RAW	0x01		/* bit 0 */
-#define THREE_WIRE	0x02		/* bit 1 */
-#define NINE_WIRE	0x04		/* bit 2 */
-#define CENTRONICS	0x08		/* bit 3 */
-
-#define SERIAL		0x01		/* bit 0 */
-#define PARALLEL	0x02		/* bit 1 */
-
-
-#define SERVICETYPE 0x00
-#define PORT_TYPE 0x01
-#define PORT_NAME 0x02
-#define FIXED_PORT_NAME 0x82
-
-#define DATA_RATE 0x10
-#define DATA_FORMAT 0x11
-#define FLOW_CONTROL 0x12
-#define XON_XOFF_CHAR 0x13
-#define ENQ_ACK_CHAR 0x14
-#define LINESTATUS 0x15
-#define BREAK_SIGNAL 0x16
-
-#define DTELINE_STATE 0x20
-#define DCELINE_STATE 0x21
-#define POLL_FOR_LINE_SETTINGS 0x22
-
-#define STATUS_QUERY 0x30
-#define SET_BUSY_TIMEOUT 0x31
-#define IEEE1284_MODE_SUPPORT 0x32
-#define IEEE1284_DEVICEID 0x33
-#define IEEE1284_MODE 0x34
-#define IEEE1284_ECP_EPP_DATA_TRANSFER 0x35
-
-/*  parameters of FLOW_CONTROL  */
-
-#define USE_RTS 0x08  /* use RTS on output */
-#define USE_CTS 0x04  /* use CTS on input */
-#define USE_DTR 0x20  /* use DTR on output */
-
-/*  parameters of DTELINE_STATE  */
-
-#define DELTA_DTR 0x01
-#define DELTA_RTS 0x02
-#define MCR_DTR 0x04
-#define MCR_RTS 0x08
-
-/*  parameters of DCELINE_STATE  */
-
-#define DELTA_CTS 0x01
-#define DELTA_DSR 0x02
-#define DELTA_RI  0x04 
-#define DELTA_DCD 0x08
-#define MSR_CTS   0x10
-#define MSR_DSR   0x20
-#define MSR_RI    0x40 
-#define MSR_DCD   0x80
-
-/*  parameters of DATA_FORMAT */
-
-#define IRCOMM_WLEN5   0x00       /* word length is 5bit */
-#define IRCOMM_WLEN6   0x01       /* word length is 6bit */
-#define IRCOMM_WLEN7   0x02       /* word length is 7bit */
-#define IRCOMM_WLEN8   0x03       /* word length is 8bit */
-
-#define IRCOMM_STOP2   0x04       /* 2 stop bits mode */
-#define IRCOMM_PARENB  0x08       /* parity enable */
-#define IRCOMM_PARODD  0x00       /*  odd parity */
-#define IRCOMM_PAREVEN 0x10       /*  even parity */
-#define IRCOMM_PARMARK 0x20
-#define IRCOMM_PARSPC  0x30
-
-/*  parameters of LINE_STATUS */
-
-#define LSR_OE     0x02    /* Overrun error indicator */
-#define LSR_PE     0x04    /* Parity error indicator */
-#define LSR_FE     0x08    /* Frame error indicator */
-#define LSR_BI     0x01    /* Break interrupt indicator */
-
-
-struct ircomm_cb {
-	int magic;
-	int state;          /* Current state of IrCOMM layer: 
-			     *  DISCOVERY,COMM_IDLE, COMM_WAITR,
-			     *  COMM_WAITI, COMM_CONN
-			     */
-	int in_use;
-	int null_modem_mode;     /* switch for null modem emulation */
-	int ttp_stop;
-
-	__u32 tx_max_sdu_size;          
-	__u32 rx_max_sdu_size;
-	__u8 max_header_size;
-
- 	__u32 daddr;        /* Device address of the peer device */ 
-	__u32 saddr;
-	__u32 skey;
-	__u32 ckey;
-	int                 queryias_lock;
-	int                 ias_type;
-	int disconnect_priority; /* P_NORMAL or P_HIGH. see irttp.h */
-	struct notify_t notify;     /* container of callbacks */
-	void (*d_handler)(struct ircomm_cb *self);
-
-	int control_ch_pending;
-	struct sk_buff *ctrl_skb;   /* queue of control channel */
-
-	__u8 dlsap;          /* IrLMP dlsap */
-	__u8 lsap;           /* sap of local device */ 
-	struct tsap_cb *tsap;          /* IrTTP/LMP handle */
-	struct qos_info *qos;         /* Quality of Service */
-	int reason;          /* I don't know about reason: 
-				see Irlmp.c or somewhere :p)*/ 
-	int peer_cap;        /* capability of peer device */
-
-	struct wait_queue   *discovery_wait;
-	struct wait_queue   *ias_wait;
-
-	/* statistics */
-	int                 tx_packets;
-	int                 rx_packets;
-	int                 tx_controls;
-	int                 pending_control_tuples;
-	int                 ignored_control_tuples;
-
-	__u8 pi ;            /* instruction of control channel*/ 
-
-	__u8 port_type;
-	__u8 peer_port_type;
-
-	__u8 servicetype;    
-	__u8 peer_servicetype;    
-	__u8 data_format;   
-	__u8 peer_data_format;   
-	__u8 flow_ctrl;
-	__u8 peer_flow_ctrl;
-	__u8 line_status;
-	__u8 peer_line_status;
-	__u8 break_signal;
-	__u8 peer_break_signal;
-	__u8 dte;
-	__u8 peer_dte;
-	__u8 dce;
-	__u8 peer_dce;
-	__u8 xon_char;
-	__u8 xoff_char;
-	__u8 peer_xon_char;
-	__u8 peer_xoff_char;
-	__u8 enq_char;
-	__u8 ack_char;
-	__u8 peer_enq_char;
-	__u8 peer_ack_char;
-	__u8 busy_timeout;
-	__u8 peer_busy_timeout;
-	__u8 ecp_epp_mode;
-	__u8 peer_ecp_epp_mode;
-	__u8 channel_or_addr;
-	__u8 peer_channel_or_addr;
-	
-	__u32 data_rate;
-	__u32 peer_data_rate;
-	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,
-			     __u32 maxsdusize);
-void ircomm_disconnect_request(struct ircomm_cb *self,
-			       struct sk_buff *userdata, int priority);
-int ircomm_data_request(struct ircomm_cb *self,
-			struct sk_buff *userdata);
-void ircomm_control_request(struct ircomm_cb *self, __u8 instruction);
-
-void ircomm_parse_tuples(struct ircomm_cb *self, struct sk_buff *skb, int type);
-
-struct ircomm_cb *ircomm_open_instance(struct notify_t notify);
-int ircomm_close_instance(struct ircomm_cb *self);
-
-
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/ircomm_core.h linux/include/net/irda/ircomm_core.h
--- linux-2.2.15-pre2/include/net/irda/ircomm_core.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/ircomm_core.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,107 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_core.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Wed Jun  9 08:58:43 1999
+ * Modified at:   Mon Dec 13 11:52:29 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
+ *     
+ ********************************************************************/
+
+#ifndef IRCOMM_CORE_H
+#define IRCOMM_CORE_H
+
+#include <net/irda/irda.h>
+#include <net/irda/ircomm_event.h>
+
+#define IRCOMM_MAGIC 0x98347298
+#define IRCOMM_HEADER_SIZE 1
+
+struct ircomm_cb;   /* Forward decl. */
+
+/*
+ * A small call-table, so we don't have to check the service-type whenever
+ * we want to do something
+ */
+typedef struct {
+	int (*data_request)(struct ircomm_cb *, struct sk_buff *, int clen);
+	int (*connect_request)(struct ircomm_cb *, struct sk_buff *, 
+			       struct ircomm_info *);
+	int (*connect_response)(struct ircomm_cb *, struct sk_buff *);
+	int (*disconnect_request)(struct ircomm_cb *, struct sk_buff *, 
+				  struct ircomm_info *);	
+} call_t;
+
+struct ircomm_cb {
+	queue_t queue;
+	magic_t magic;
+
+	notify_t notify;
+	call_t   issue;
+
+	int state;
+	int line;            /* Which TTY line we are using */
+
+	struct tsap_cb *tsap;
+	struct lsap_cb *lsap;
+	
+	__u8 dlsap_sel;      /* Destination LSAP/TSAP selector */
+	__u8 slsap_sel;      /* Source LSAP/TSAP selector */
+
+	__u32 saddr;         /* Source device address (link we are using) */
+	__u32 daddr;         /* Destination device address */
+
+	int max_header_size; /* Header space we must reserve for each frame */
+	int max_data_size;   /* The amount of data we can fill in each frame */
+
+	LOCAL_FLOW flow_status; /* Used by ircomm_lmp */
+	int pkt_count;          /* Number of frames we have sent to IrLAP */
+
+	__u8 service_type;
+};
+
+extern hashbin_t *ircomm;
+
+struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line);
+int ircomm_close(struct ircomm_cb *self);
+
+int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb);
+void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb);
+void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb);
+int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb);
+int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, 
+			   __u32 saddr, __u32 daddr, struct sk_buff *skb,
+			   __u8 service_type);
+void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
+			       struct ircomm_info *info);
+void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
+			    struct ircomm_info *info);
+int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata);
+int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata);
+void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
+				  struct ircomm_info *info);
+void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow);
+
+#define ircomm_is_connected(self) (self->state == IRCOMM_CONN)
+
+#endif
diff -urN linux-2.2.15-pre2/include/net/irda/ircomm_event.h linux/include/net/irda/ircomm_event.h
--- linux-2.2.15-pre2/include/net/irda/ircomm_event.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/ircomm_event.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,84 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_event.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sun Jun  6 23:51:13 1999
+ * Modified at:   Thu Jun 10 08:36:25 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
+ *     
+ ********************************************************************/
+
+#ifndef IRCOMM_EVENT_H
+#define IRCOMM_EVENT_H
+
+typedef enum {
+        IRCOMM_IDLE,
+        IRCOMM_WAITI,
+        IRCOMM_WAITR,
+        IRCOMM_CONN,
+} IRCOMM_STATE;
+
+/* IrCOMM Events */
+typedef enum {
+        IRCOMM_CONNECT_REQUEST,
+        IRCOMM_CONNECT_RESPONSE,
+        IRCOMM_TTP_CONNECT_INDICATION,
+	IRCOMM_LMP_CONNECT_INDICATION,
+        IRCOMM_TTP_CONNECT_CONFIRM,
+	IRCOMM_LMP_CONNECT_CONFIRM,
+
+        IRCOMM_LMP_DISCONNECT_INDICATION,
+	IRCOMM_TTP_DISCONNECT_INDICATION,
+        IRCOMM_DISCONNECT_REQUEST,
+
+        IRCOMM_TTP_DATA_INDICATION,
+	IRCOMM_LMP_DATA_INDICATION,
+        IRCOMM_DATA_REQUEST,
+        IRCOMM_CONTROL_REQUEST,
+        IRCOMM_CONTROL_INDICATION,
+} IRCOMM_EVENT;
+
+/*
+ * Used for passing information through the state-machine
+ */
+struct ircomm_info {
+        __u32     saddr;               /* Source device address */
+        __u32     daddr;               /* Destination device address */
+        __u8      dlsap_sel;
+        LM_REASON reason;              /* Reason for disconnect */
+	__u32     max_data_size;
+	__u32     max_header_size;
+
+	struct qos_info *qos;
+};
+
+extern char *ircomm_state[];
+extern char *ircomm_event[];
+
+struct ircomm_cb;   /* Forward decl. */
+
+int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
+		    struct sk_buff *skb, struct ircomm_info *info);
+void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state);
+
+#endif
diff -urN linux-2.2.15-pre2/include/net/irda/ircomm_lmp.h linux/include/net/irda/ircomm_lmp.h
--- linux-2.2.15-pre2/include/net/irda/ircomm_lmp.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/ircomm_lmp.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,65 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_lmp.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Wed Jun  9 10:06:07 1999
+ * Modified at:   Fri Aug 13 07:32:32 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
+ *     
+ ********************************************************************/
+
+#ifndef IRCOMM_LMP_H
+#define IRCOMM_LMP_H
+
+#include <net/irda/ircomm_core.h>
+#include <net/irda/ircomm_event.h>
+
+int ircomm_open_lsap(struct ircomm_cb *self);
+int  ircomm_lmp_connect_request(struct ircomm_cb *self, 
+				struct sk_buff *userdata, 
+				struct ircomm_info *info);
+int  ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *skb);
+int  ircomm_lmp_disconnect_request(struct ircomm_cb *self, 
+				   struct sk_buff *userdata, 
+				   struct ircomm_info *info);
+int  ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb, 
+			     int clen);
+int  ircomm_lmp_control_request(struct ircomm_cb *self, 
+			       struct sk_buff *userdata);
+int  ircomm_lmp_data_indication(void *instance, void *sap,
+				struct sk_buff *skb);
+void ircomm_lmp_connect_confirm(void *instance, void *sap,
+				struct qos_info *qos, 
+				__u32 max_sdu_size, 
+				__u8 max_header_size,
+				struct sk_buff *skb);
+void ircomm_lmp_connect_indication(void *instance, void *sap,
+				   struct qos_info *qos,
+				   __u32 max_sdu_size,
+				   __u8 max_header_size,
+				   struct sk_buff *skb);
+void ircomm_lmp_disconnect_indication(void *instance, void *sap, 
+				      LM_REASON reason,
+				      struct sk_buff *skb);
+
+#endif
diff -urN linux-2.2.15-pre2/include/net/irda/ircomm_param.h linux/include/net/irda/ircomm_param.h
--- linux-2.2.15-pre2/include/net/irda/ircomm_param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/ircomm_param.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,150 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_param.h
+ * Version:       1.0
+ * Description:   Parameter handling for the IrCOMM protocol
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Mon Jun  7 08:47:28 1999
+ * Modified at:   Wed Aug 25 13:46:33 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
+ *     
+ ********************************************************************/
+
+#ifndef IRCOMM_PARAMS_H
+#define IRCOMM_PARAMS_H
+
+#include <net/irda/parameters.h>
+
+/* Parameters common to all service types */
+#define IRCOMM_SERVICE_TYPE     0x00
+#define IRCOMM_PORT_TYPE        0x01 /* Only used in LM-IAS */
+#define IRCOMM_PORT_NAME        0x02 /* Only used in LM-IAS */
+
+/* Parameters for both 3 wire and 9 wire */
+#define IRCOMM_DATA_RATE        0x10
+#define IRCOMM_DATA_FORMAT      0x11
+#define IRCOMM_FLOW_CONTROL     0x12
+#define IRCOMM_XON_XOFF         0x13
+#define IRCOMM_ENQ_ACK          0x14
+#define IRCOMM_LINE_STATUS      0x15
+#define IRCOMM_BREAK            0x16
+
+/* Parameters for 9 wire */
+#define IRCOMM_DTE              0x20
+#define IRCOMM_DCE              0x21
+#define IRCOMM_POLL             0x22
+
+/* Service type (details) */
+#define IRCOMM_3_WIRE_RAW       0x01
+#define IRCOMM_3_WIRE           0x02
+#define IRCOMM_9_WIRE           0x04
+#define IRCOMM_CENTRONICS       0x08
+
+/* Port type (details) */
+#define IRCOMM_SERIAL           0x00
+#define IRCOMM_PARALLEL         0x01
+
+/* Data format (details) */
+#define IRCOMM_WSIZE_5          0x00
+#define IRCOMM_WSIZE_6          0x01
+#define IRCOMM_WSIZE_7          0x02
+#define IRCOMM_WSIZE_8          0x03
+
+#define IRCOMM_1_STOP_BIT       0x00
+#define IRCOMM_2_STOP_BIT       0x04 /* 1.5 if char len 5 */
+
+#define IRCOMM_PARITY_DISABLE   0x00
+#define IRCOMM_PARITY_ENABLE    0x08
+
+#define IRCOMM_PARITY_ODD       0x00
+#define IRCOMM_PARITY_EVEN      0x10
+#define IRCOMM_PARITY_MARK      0x20
+#define IRCOMM_PARITY_SPACE     0x30
+
+/* Flow control */
+#define IRCOMM_XON_XOFF_IN      0x01
+#define IRCOMM_XON_XOFF_OUT     0x02
+#define IRCOMM_RTS_CTS_IN       0x04
+#define IRCOMM_RTS_CTS_OUT      0x08
+#define IRCOMM_DSR_DTR_IN       0x10
+#define IRCOMM_DSR_DTR_OUT      0x20
+#define IRCOMM_ENQ_ACK_IN       0x40
+#define IRCOMM_ENQ_ACK_OUT      0x80
+
+/* Line status */
+#define IRCOMM_OVERRUN_ERROR    0x02
+#define IRCOMM_PARITY_ERROR     0x04
+#define IRCOMM_FRAMING_ERROR    0x08
+
+/* DTE (Data terminal equipment) line settings */
+#define IRCOMM_DELTA_DTR        0x01
+#define IRCOMM_DELTA_RTS        0x02
+#define IRCOMM_DTR              0x04
+#define IRCOMM_RTS              0x08
+
+/* DCE (Data communications equipment) line settings */
+#define IRCOMM_DELTA_CTS        0x01  /* Clear to send has changed */
+#define IRCOMM_DELTA_DSR        0x02  /* Data set ready has changed */
+#define IRCOMM_DELTA_RI         0x04  /* Ring indicator has changed */
+#define IRCOMM_DELTA_CD         0x08  /* Carrier detect has changed */
+#define IRCOMM_CTS              0x10  /* Clear to send is high */
+#define IRCOMM_DSR              0x20  /* Data set ready is high */
+#define IRCOMM_RI               0x40  /* Ring indicator is high */
+#define IRCOMM_CD               0x80  /* Carrier detect is high */
+#define IRCOMM_DCE_DELTA_ANY    0x0f
+
+/*
+ * Parameter state
+ */
+struct ircomm_params {
+	/* General control params */
+	__u8  service_type;
+	__u8  port_type;
+	char  port_name[32];
+
+	/* Control params for 3- and 9-wire service type */
+	__u32 data_rate;         /* Data rate in bps */
+	__u8  data_format;
+	__u8  flow_control;
+	char  xonxoff[2];
+	char  enqack[2];
+	__u8  line_status;
+	__u8  _break;
+
+	__u8  null_modem;
+
+	/* Control params for 9-wire service type */
+	__u8 dte;
+	__u8 dce;
+	__u8 poll;
+
+	/* Control params for Centronics service type */
+};
+
+struct ircomm_tty_cb; /* Forward decl. */
+
+int ircomm_param_flush(struct ircomm_tty_cb *self);
+int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush);
+
+extern pi_param_info_t ircomm_param_info;
+
+#endif /* IRCOMM_PARAMS_H */
+
diff -urN linux-2.2.15-pre2/include/net/irda/ircomm_ttp.h linux/include/net/irda/ircomm_ttp.h
--- linux-2.2.15-pre2/include/net/irda/ircomm_ttp.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/ircomm_ttp.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,70 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_ttp.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Wed Jun  9 10:06:07 1999
+ * Modified at:   Fri Aug 13 07:32:22 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
+ *     
+ ********************************************************************/
+
+#ifndef IRCOMM_TTP_H
+#define IRCOMM_TTP_H
+
+#include <net/irda/ircomm_core.h>
+#include <net/irda/ircomm_event.h>
+
+int  ircomm_open_tsap(struct ircomm_cb *self);
+int  ircomm_ttp_connect_request(struct ircomm_cb *self, 
+				struct sk_buff *userdata, 
+				struct ircomm_info *info);
+int  ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb);
+int  ircomm_ttp_disconnect_request(struct ircomm_cb *self, 
+				   struct sk_buff *userdata, 
+				   struct ircomm_info *info);
+int  ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb, 
+			     int clen);
+int  ircomm_ttp_control_request(struct ircomm_cb *self, 
+			       struct sk_buff *userdata);
+int  ircomm_ttp_data_indication(void *instance, void *sap,
+				struct sk_buff *skb);
+void ircomm_ttp_connect_confirm(void *instance, void *sap,
+				struct qos_info *qos, 
+				__u32 max_sdu_size, 
+				__u8 max_header_size,
+				struct sk_buff *skb);
+void ircomm_ttp_connect_indication(void *instance, void *sap,
+				   struct qos_info *qos,
+				   __u32 max_sdu_size,
+				   __u8 max_header_size,
+				   struct sk_buff *skb);
+void ircomm_ttp_disconnect_indication(void *instance, void *sap, 
+				      LM_REASON reason,
+				      struct sk_buff *skb);
+void ircomm_ttp_flow_indication(void *instance, void *sap, LOCAL_FLOW cmd);
+
+#endif
+
+
+
+
diff -urN linux-2.2.15-pre2/include/net/irda/ircomm_tty.h linux/include/net/irda/ircomm_tty.h
--- linux-2.2.15-pre2/include/net/irda/ircomm_tty.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/ircomm_tty.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,121 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_tty.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sun Jun  6 23:24:22 1999
+ * Modified at:   Sun Dec 12 15:57:38 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
+ *     
+ ********************************************************************/
+
+#ifndef IRCOMM_TTY_H
+#define IRCOMM_TTY_H
+
+#include <linux/serial.h>
+#include <linux/termios.h>
+#include <linux/timer.h>
+
+#include <net/irda/irias_object.h>
+#include <net/irda/ircomm_core.h>
+#include <net/irda/ircomm_param.h>
+
+#define IRCOMM_TTY_PORTS 32
+#define IRCOMM_TTY_MAGIC 0x3432
+#define IRCOMM_TTY_MAJOR 161
+#define IRCOMM_TTY_MINOR 0
+
+/*
+ * IrCOMM TTY driver state
+ */
+struct ircomm_tty_cb {
+	queue_t queue;            /* Must be first */
+	magic_t magic;
+
+	int state;                /* Connect state */
+
+	struct tty_struct *tty;
+	struct ircomm_cb *ircomm; /* IrCOMM layer instance */
+
+	struct sk_buff *tx_skb;   /* Transmit buffer */
+	struct sk_buff *ctrl_skb; /* Control data buffer */
+
+	/* Parameters */
+	struct ircomm_params settings;
+
+	__u8 service_type;        /* The service that we support */
+	int client;               /* True if we are a client */
+	LOCAL_FLOW flow;          /* IrTTP flow status */
+
+	int line;
+	__u32 flags;
+
+	__u8 dlsap_sel;
+	__u8 slsap_sel;
+
+	__u32 saddr;
+	__u32 daddr;
+
+	__u32 max_data_size;   /* Max data we can transmit in one packet */
+	__u32 max_header_size; /* The amount of header space we must reserve */
+
+	struct iriap_cb *iriap; /* Instance used for querying remote IAS */
+	struct ias_object* obj;
+	int skey;
+	int ckey;
+
+	struct termios	  normal_termios;
+	struct termios	  callout_termios;
+
+	struct wait_queue *open_wait;
+	struct wait_queue *close_wait;
+	struct timer_list watchdog_timer;
+	struct tq_struct  tqueue;
+
+        unsigned short    close_delay;
+        unsigned short    closing_wait; /* time to wait before closing */
+
+	long session;           /* Session of opening process */
+	long pgrp;		/* pgrp of opening process */
+	int  open_count;
+	int  blocked_open;	/* # of blocked opens */
+};
+
+void ircomm_tty_start(struct tty_struct *tty);
+void ircomm_tty_stop(struct tty_struct *tty);
+void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self);
+
+extern void ircomm_tty_change_speed(struct ircomm_tty_cb *self);
+extern int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file, 
+			    unsigned int cmd, unsigned long arg);
+extern void ircomm_tty_set_termios(struct tty_struct *tty, 
+				   struct termios *old_termios);
+extern hashbin_t *ircomm_tty;
+
+#endif
+
+
+
+
+
+
+
diff -urN linux-2.2.15-pre2/include/net/irda/ircomm_tty_attach.h linux/include/net/irda/ircomm_tty_attach.h
--- linux-2.2.15-pre2/include/net/irda/ircomm_tty_attach.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/ircomm_tty_attach.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,96 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_tty_attach.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Wed Jun  9 15:55:18 1999
+ * Modified at:   Fri Dec 10 21:04:55 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
+ *     
+ ********************************************************************/
+
+#ifndef IRCOMM_TTY_ATTACH_H
+#define IRCOMM_TTY_ATTACH_H
+
+#include <net/irda/ircomm_tty.h>
+
+typedef enum {
+        IRCOMM_TTY_IDLE,
+	IRCOMM_TTY_SEARCH,
+        IRCOMM_TTY_QUERY_PARAMETERS,
+	IRCOMM_TTY_QUERY_LSAP_SEL,
+	IRCOMM_TTY_SETUP,
+        IRCOMM_TTY_READY,
+} IRCOMM_TTY_STATE;
+
+/* IrCOMM TTY Events */
+typedef enum {
+	IRCOMM_TTY_ATTACH_CABLE,
+	IRCOMM_TTY_DETACH_CABLE,
+	IRCOMM_TTY_DATA_REQUEST,
+	IRCOMM_TTY_DATA_INDICATION,
+	IRCOMM_TTY_DISCOVERY_REQUEST,
+	IRCOMM_TTY_DISCOVERY_INDICATION,
+	IRCOMM_TTY_CONNECT_CONFIRM,
+	IRCOMM_TTY_CONNECT_INDICATION,
+	IRCOMM_TTY_DISCONNECT_REQUEST,
+	IRCOMM_TTY_DISCONNECT_INDICATION,
+	IRCOMM_TTY_WD_TIMER_EXPIRED,
+	IRCOMM_TTY_GOT_PARAMETERS,
+	IRCOMM_TTY_GOT_LSAPSEL,
+} IRCOMM_TTY_EVENT;
+
+/* Used for passing information through the state-machine */
+struct ircomm_tty_info {
+        __u32     saddr;               /* Source device address */
+        __u32     daddr;               /* Destination device address */
+        __u8      dlsap_sel;
+};
+
+extern char *ircomm_state[];
+extern char *ircomm_event[];
+extern char *ircomm_tty_state[];
+
+int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
+			struct sk_buff *skb, struct ircomm_tty_info *info);
+void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state);
+
+
+int  ircomm_tty_attach_cable(struct ircomm_tty_cb *self);
+void ircomm_tty_detach_cable(struct ircomm_tty_cb *self);
+void ircomm_tty_connect_confirm(void *instance, void *sap, 
+				struct qos_info *qos, 
+				__u32 max_sdu_size, 
+				__u8 max_header_size, 
+				struct sk_buff *skb);
+void ircomm_tty_disconnect_indication(void *instance, void *sap, 
+				      LM_REASON reason,
+				      struct sk_buff *skb);
+void ircomm_tty_connect_indication(void *instance, void *sap, 
+				   struct qos_info *qos, 
+				   __u32 max_sdu_size,
+				   __u8 max_header_size, 
+				   struct sk_buff *skb);
+int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self);
+void ircomm_tty_link_established(struct ircomm_tty_cb *self);
+
+#endif /* IRCOMM_TTY_ATTACH_H */
diff -urN linux-2.2.15-pre2/include/net/irda/irda.h linux/include/net/irda/irda.h
--- linux-2.2.15-pre2/include/net/irda/irda.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/irda.h	Mon Dec  3 21:57:53 2001
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      irda.h
- * Version:       
- * Description:   
- * Status:        Experimental.
+ * Version:       1.0
+ * Description:   IrDA common include file for kernel internal use
+ * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Mon May 10 09:51:13 1999
+ * Modified at:   Sat Dec 25 18:58:49 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -28,6 +28,10 @@
 #include <linux/config.h>
 #include <linux/skbuff.h>
 #include <linux/kernel.h>
+#include <linux/if.h>
+#include <linux/irda.h>
+
+typedef __u32 magic_t;
 
 #include <net/irda/qos.h>
 #include <net/irda/irqueue.h>
@@ -40,8 +44,16 @@
 #define FALSE 0
 #endif
 
-#define ALIGN __attribute__((aligned))
-#define PACK __attribute__((packed))
+#ifndef IRDA_MIN /* Lets not mix this MIN with other header files */
+#define IRDA_MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef ALIGN
+#  define ALIGN __attribute__((aligned))
+#endif
+#ifndef PACK
+#  define PACK __attribute__((packed))
+#endif
 
 
 #ifdef CONFIG_IRDA_DEBUG
@@ -51,14 +63,14 @@
 /* use 0 for production, 1 for verification, >2 for debug */
 #define IRDA_DEBUG_LEVEL 0
 
-#define DEBUG(n, args...) if (irda_debug >= (n)) printk(KERN_DEBUG args)
+#define IRDA_DEBUG(n, args...) (irda_debug >= (n)) ? (printk(KERN_DEBUG args)) : 0
 #define ASSERT(expr, func) \
 if(!(expr)) { \
         printk( "Assertion failed! %s,%s,%s,line=%d\n",\
         #expr,__FILE__,__FUNCTION__,__LINE__); \
         ##func}
 #else
-#define DEBUG(n, args...)
+#define IRDA_DEBUG(n, args...)
 #define ASSERT(expr, func)
 #endif /* CONFIG_IRDA_DEBUG */
 
@@ -66,12 +78,13 @@
 #define MESSAGE(args...) printk(KERN_INFO args)
 #define ERROR(args...)   printk(KERN_ERR args)
 
-#define MSECS_TO_JIFFIES(ms) (ms*HZ/1000)
+#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000)
 
 /*
- *  Magic numbers used by Linux/IR. Random numbers which must be unique to 
+ *  Magic numbers used by Linux-IrDA. Random numbers which must be unique to 
  *  give the best protection
  */
+
 #define IRTTY_MAGIC        0x2357
 #define LAP_MAGIC          0x1357
 #define LMP_MAGIC          0x4321
@@ -86,8 +99,9 @@
 #define IRLAN_MAGIC        0x754
 #define IAS_OBJECT_MAGIC   0x34234
 #define IAS_ATTRIB_MAGIC   0x45232
+#define IRDA_TASK_MAGIC    0x38423
 
-#define IAS_DEVICE_ID 0x5342 
+#define IAS_DEVICE_ID 0x0000 /* Defined by IrDA, IrLMP section 4.1 (page 68) */
 #define IAS_PNP_ID    0xd342
 #define IAS_OBEX_ID   0x34323
 #define IAS_IRLAN_ID  0x34234
@@ -102,7 +116,9 @@
 	__u32 saddr;          /* my local address */
 	__u32 daddr;          /* peer address */
 
-	struct ias_object *ias_obj;
+	struct lsap_cb *lsap; /* LSAP used by Ultra */
+	__u8  pid;            /* Protocol IP (PID) used by Ultra */
+
 	struct tsap_cb *tsap; /* TSAP used by this connection */
 	__u8 dtsap_sel;       /* remote TSAP address */
 	__u8 stsap_sel;       /* local TSAP address */
@@ -119,9 +135,13 @@
 	__u32 ckey;           /* IrLMP client handle */
 	__u32 skey;           /* IrLMP service handle */
 
+	struct ias_object *ias_obj;   /* Our service name + lsap in IAS */
+	struct iriap_cb *iriap;	      /* Used to query remote IAS */
+	struct ias_value *ias_result; /* Used by getsockopt(IRLMP_IAS_QUERY) */
+
 	int nslots;           /* Number of slots to use for discovery */
 
-	int errno;
+	int errno;            /* status of the IAS query */
 
 	struct sock *sk;
 	struct wait_queue *ias_wait;       /* Wait for LM-IAS answer */
@@ -141,39 +161,17 @@
 	__u8  byte[2];
 } __u16_host_order;
 
-/*
- *  Information monitored by some layers
+/* 
+ * Per-packet information we need to hide inside sk_buff 
+ * (must not exceed 48 bytes, check with struct sk_buff) 
  */
-struct irda_statistics
-{
-        int     rx_packets;             /* total packets received       */
-        int     tx_packets;             /* total packets transmitted    */
-        int     rx_errors;              /* bad packets received         */
-        int     tx_errors;              /* packet transmit problems     */
-        int     rx_dropped;             /* no space in linux buffers    */
-        int     tx_dropped;             /* no space available in linux  */
-	int     rx_compressed;
-	int     tx_compressed;
-	int     rx_bytes;               /* total bytes received         */
-	int     tx_bytes;               /* total bytes transmitted      */
-
-        int     multicast;              /* multicast packets received   */
-        int     collisions;
-	
-        /* detailed rx_errors: */
-        int     rx_length_errors;
-        int     rx_over_errors;         /* receiver ring buff overflow  */
-        int     rx_crc_errors;          /* recved pkt with crc error    */
-        int     rx_frame_errors;        /* recv'd frame alignment error */
-        int     rx_fifo_errors;         /* recv'r fifo overrun          */
-        int     rx_missed_errors;       /* receiver missed packet       */
-
-        /* detailed tx_errors */
-        int     tx_aborted_errors;
-        int     tx_carrier_errors;
-        int     tx_fifo_errors;
-        int     tx_heartbeat_errors;
-        int     tx_window_errors;
+struct irda_skb_cb {
+	magic_t magic;     /* Be sure that we can trust the information */
+	__u32   speed;     /* The Speed this frame should be sent with */
+	__u16     mtt;     /* Minimum turn around time */
+	int     xbofs;     /* Number of xbofs required, used by SIR mode */
+	__u8     line;     /* Used by IrCOMM in IrLPT mode */
+	void (*destructor)(struct sk_buff *skb); /* Used for flow control */
 };
 
 /* Misc status information */
@@ -222,21 +220,21 @@
 /*
  *  Notify structure used between transport and link management layers
  */
-struct notify_t {
+typedef struct {
 	int (*data_indication)(void *priv, void *sap, struct sk_buff *skb);
 	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,
 				__u8 max_header_size, struct sk_buff *skb);
 	void (*connect_indication)(void *instance, void *sap, 
-				   struct qos_info *qos, __u32 max_sdu_size,
+				   struct qos_info *qos, __u32 max_sdu_size, 
 				   __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);
 	void *instance; /* Layer instance pointer */
 	char name[16];  /* Name of layer */
-};
+} notify_t;
 
 #define NOTIFY_MAX_NAME 16
 
diff -urN linux-2.2.15-pre2/include/net/irda/irda_device.h linux/include/net/irda/irda_device.h
--- linux-2.2.15-pre2/include/net/irda/irda_device.h	Mon Jun  7 16:19:59 1999
+++ linux/include/net/irda/irda_device.h	Mon Dec  3 21:57:53 2001
@@ -1,17 +1,16 @@
 /*********************************************************************
  *                
  * Filename:      irda_device.h
- * Version:       
- * Description:   
+ * Version:       0.9
+ * Description:   Contains various declarations used by the drivers
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr 14 12:41:42 1998
- * Modified at:   Wed May 19 08:44:48 1999
+ * Modified at:   Fri Jan 14 10:46:56 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
  *     Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
- *     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 
@@ -35,12 +34,11 @@
 
 #include <linux/tty.h>
 #include <linux/netdevice.h>
-
 #include <asm/spinlock.h>
+#include <linux/irda.h>
 
 #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>
 
@@ -53,34 +51,97 @@
 #define IFF_DMA		0x0020 /* Supports DMA transfer of data */
 #define IFF_SHM         0x0040 /* Supports shared memory data transfers */
 #define IFF_DONGLE      0x0080 /* Interface has a dongle attached */
-#define IFF_AIR         0x0100 /* Supports A(dvanced)IR standards */
+#define IFF_AIR         0x0100 /* Supports Advanced IR (AIR) standards */
 
 #define IO_XMIT 0x01
 #define IO_RECV 0x02
 
-struct dongle_q {
-	QUEUE q;
-	struct dongle *dongle;
+typedef enum {
+	IRDA_IRLAP, /* IrDA mode, and deliver to IrLAP */
+	IRDA_RAW,   /* IrDA mode */
+	SHARP_ASK,
+	TV_REMOTE,  /* Also known as Consumer Electronics IR */
+} INFRARED_MODE;
+
+typedef enum {
+	IRDA_TASK_INIT,        /* All tasks are initialized with this state */
+	IRDA_TASK_DONE,        /* Signals that the task is finished */
+	IRDA_TASK_WAIT,
+	IRDA_TASK_WAIT1,
+	IRDA_TASK_WAIT2,
+	IRDA_TASK_WAIT3,
+	IRDA_TASK_CHILD_INIT,  /* Initializing child task */
+	IRDA_TASK_CHILD_WAIT,  /* Waiting for child task to finish */
+	IRDA_TASK_CHILD_DONE   /* Child task is finished */
+} TASK_STATE;
+
+struct irda_task;
+typedef int (*TASK_CALLBACK) (struct irda_task *task);
+
+struct irda_task {
+	queue_t q;
+	magic_t magic;
+
+	TASK_STATE state;
+	TASK_CALLBACK function;
+	TASK_CALLBACK finished;
+
+	struct irda_task *parent;
+	struct timer_list timer;
+
+	void *instance; /* Instance being called */
+	void *param;    /* Parameter to be used by instance */
+};
+
+/* Dongle info */
+struct dongle_reg;
+typedef struct {
+	struct dongle_reg *issue;     /* Registration info */
+	struct device *dev;           /* Device we are attached to */
+	struct irda_task *speed_task; /* Task handling speed change */
+	struct irda_task *reset_task; /* Task handling reset */
+	__u32 speed;                  /* Current speed */
+
+	/* Callbacks to the IrDA device driver */
+	int (*set_mode)(struct device *, int mode);
+	int (*read)(struct device *dev, __u8 *buf, int len);
+	int (*write)(struct device *dev, __u8 *buf, int len);
+	int (*set_dtr_rts)(struct device *dev, int dtr, int rts);
+} dongle_t;
+
+/* Dongle registration info */
+struct dongle_reg {
+	queue_t q;         /* Must be first */
+	IRDA_DONGLE type;
+
+	void (*open)(dongle_t *dongle, struct qos_info *qos);
+	void (*close)(dongle_t *dongle);
+	int  (*reset)(struct irda_task *task);
+	int  (*change_speed)(struct irda_task *task);
 };
 
 /* Chip specific info */
-struct chipio_t {
-        int iobase, iobase2;  /* IO base */
-        int io_ext, io_ext2;  /* Length of iobase */
-	int membase;          /* Shared memory base */
+typedef struct {
+	int cfg_base;         /* Config register IO base */
+        int sir_base;         /* SIR IO base */
+	int fir_base;         /* FIR IO base */
+	int mem_base;         /* Shared memory base */
+        int sir_ext;          /* Length of SIR iobase */
+	int fir_ext;          /* Length of FIR iobase */
         int irq, irq2;        /* Interrupts used */
+        int dma, dma2;        /* DMA channel(s) used */
         int fifo_size;        /* FIFO size */
-
-        int dma, dma2;        /* DMA channel used */
         int irqflags;         /* interrupt flags (ie, SA_SHIRQ|SA_INTERRUPT) */
 	int direction;        /* Link direction, used by some FIR drivers */
-
-	int baudrate;         /* Currently used baudrate */
+	int enabled;          /* Powered on? */
+	int suspended;        /* Suspended by APM */
+	__u32 speed;          /* Currently used speed */
+	__u32 new_speed;      /* Speed we must change to when Tx is finished */
 	int dongle_id;        /* Dongle or transceiver currently used */
-};
+} chipio_t;
 
 /* IO buffer specific info (inspired by struct sk_buff) */
-struct iobuff_t {
+typedef struct {
 	int state;            /* Receiving state (transmit state not used) */
 	int in_frame;         /* True if receiving frame */
 
@@ -91,116 +152,95 @@
 	int len;	      /* length of data */
 	int truesize;	      /* total size of buffer */
 	__u16 fcs;
-
-	int flags;            /* Allocation flags (GFP_KERNEL | GFP_DMA ) */
-};
-
-/* 
- * This structure contains data that _we_ would have liked to be in the device
- * structure, but we don't want to mess it up more than it is already. Better 
- * to keep the data in separate structures! This structure abstracts common 
- * stuff from IrDA port implementations.
- */
-struct irda_device {
-	QUEUE q;               /* Must be first */
-
-        int  magic;	       /* Our magic bullet */
-	char name[16];         /* Name of device "irda0" */
-	char description[32];  /* Something like "irda0 <-> ttyS0" */
-
-	struct irlap_cb *irlap; /* The link layer we are connected to  */
-	struct device netdev;   /* Yes! we are some kind of netdevice */
-	struct enet_statistics stats;
-
- 	int flags;            /* Interface flags (see defs above) */
-
- 	void *priv;           /* Pointer to low level implementation */
-
-	struct qos_info qos;  /* QoS capabilities for this device */
-
-	struct chipio_t io;
-	struct iobuff_t tx_buff;
-	struct iobuff_t rx_buff;
-
-	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 *idev, int baud);
- 	int  (*is_receiving)(struct irda_device *);    /* receiving? */
-	void (*set_dtr_rts)(struct irda_device *idev, int dtr, int rts);
-	int  (*raw_write)(struct irda_device *idev, __u8 *buf, int len);
-	void (*wait_until_sent)(struct irda_device *);
-	void (*set_caddr)(struct irda_device *);      /* Set connection addr */
-};
-
-extern hashbin_t *irda_device;
+} iobuff_t;
 
 /* Function prototypes */
 int  irda_device_init(void);
 void irda_device_cleanup(void);
 
-int  irda_device_open(struct irda_device *, char *name, void *priv);
-void irda_device_close(struct irda_device *);
-
 /* Interface to be uses by IrLAP */
-inline void irda_device_set_media_busy(struct irda_device *, int status);
-inline int  irda_device_is_media_busy(struct irda_device *);
-inline int  irda_device_is_receiving(struct irda_device *);
-inline void irda_device_change_speed(struct irda_device *, int);
-
-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);
+void irda_device_set_media_busy(struct device *dev, int status);
+int  irda_device_is_media_busy(struct device *dev);
+int  irda_device_is_receiving(struct device *dev);
+
+/* Interface for internal use */
+int  irda_device_txqueue_empty(struct device *dev);
+int  irda_device_set_raw_mode(struct device* self, int status);
+int  irda_device_set_dtr_rts(struct device *dev, int dtr, int rts);
+int  irda_device_change_speed(struct device *dev, __u32 speed);
+int  irda_device_setup(struct device *dev);
+
+/* Dongle interface */
+void irda_device_unregister_dongle(struct dongle_reg *dongle);
+int  irda_device_register_dongle(struct dongle_reg *dongle);
+dongle_t *irda_device_dongle_init(struct device *dev, int type);
+int irda_device_dongle_cleanup(dongle_t *dongle);
 
 void setup_dma(int channel, char *buffer, int count, int mode);
 
+void irda_task_delete(struct irda_task *task);
+int  irda_task_kick(struct irda_task *task);
+struct irda_task *irda_task_execute(void *instance, TASK_CALLBACK function, 
+				    TASK_CALLBACK finished, 
+				    struct irda_task *parent, void *param);
+void irda_task_next_state(struct irda_task *task, TASK_STATE state);
+
+extern const char *infrared_mode[];
+
 /*
  * Function irda_get_mtt (skb)
  *
  *    Utility function for getting the minimum turnaround time out of 
  *    the skb, where it has been hidden in the cb field.
  */
+#define irda_get_mtt(skb) (                                                 \
+        IRDA_MIN(10000,                                                     \
+                  (((struct irda_skb_cb *) skb->cb)->magic == LAP_MAGIC) ?  \
+                          ((struct irda_skb_cb *)(skb->cb))->mtt : 10000    \
+                 )							    \
+)
+
+#if 0
 extern inline __u16 irda_get_mtt(struct sk_buff *skb)
 {
 	__u16 mtt;
 
-	if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC)
+	if (((struct irda_skb_cb *)(skb->cb))->magic != LAP_MAGIC)
 		mtt = 10000;
 	else
-		mtt = ((struct irlap_skb_cb *)(skb->cb))->mtt;
+		mtt = ((struct irda_skb_cb *)(skb->cb))->mtt;
 
 	ASSERT(mtt <= 10000, return 10000;);
 	
 	return mtt;
 }
+#endif
 
-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);
-}
+/*
+ * Function irda_get_speed (skb)
+ *
+ *    Extact the speed this frame should be sent out with from the skb
+ *
+ */
+#define irda_get_speed(skb) (	                                        \
+	(((struct irda_skb_cb*) skb->cb)->magic == LAP_MAGIC) ? 	\
+                  ((struct irda_skb_cb *)(skb->cb))->speed : 9600 	\
+)
 
-extern inline int irda_device_raw_write(struct irda_device *self, __u8 *buf,
-					int len)
+#if 0
+extern inline __u32 irda_get_speed(struct sk_buff *skb)
 {
-	int ret = -1;
+	__u32 speed;
 
-	if (self->raw_write)
-		ret = self->raw_write(self, buf, len);
-	return ret;
-}
+	if (((struct irda_skb_cb *)(skb->cb))->magic != LAP_MAGIC)
+		speed = 9600;
+	else
+		speed = ((struct irda_skb_cb *)(skb->cb))->speed;
 
+	return speed;
+}
 #endif
+
+#endif /* IRDA_DEVICE_H */
 
 
diff -urN linux-2.2.15-pre2/include/net/irda/iriap.h linux/include/net/irda/iriap.h
--- linux-2.2.15-pre2/include/net/irda/iriap.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/iriap.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Sun May  9 10:56:57 1999
+ * Modified at:   Sat Dec 25 16:42:09 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997, 1999 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 
@@ -57,9 +58,9 @@
 				 struct ias_value *value, void *priv);
 
 struct iriap_cb {
-	QUEUE queue; /* Must be first */
-	
-	int          magic;  /* Magic cookie */
+	queue_t q;      /* Must be first */	
+	magic_t magic;  /* Magic cookie */
+
 	int          mode;   /* Client or server */
 
 	__u32        saddr;
@@ -79,32 +80,38 @@
 	IRIAP_STATE r_connect_state;
 	
 	CONFIRM_CALLBACK confirm;
-	void *priv;
+	void *priv;                /* Used to identify client */
 
 	__u8 max_header_size;
+	__u32 max_data_size;
 	
 	struct timer_list watchdog_timer;
 };
 
 int  iriap_init(void);
 void iriap_cleanup(void);
-void iriap_getvaluebyclass_request( char *name, char *attr, 
-				    __u32 saddr, __u32 daddr,
-				    CONFIRM_CALLBACK callback, void *priv);
-void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb);
 
+struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, 
+			    CONFIRM_CALLBACK callback);
+void iriap_close(struct iriap_cb *self);
+
+int iriap_getvaluebyclass_request(struct iriap_cb *self, 
+				  __u32 saddr, __u32 daddr,
+				  char *name, char *attr);
+void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb);
+void iriap_connect_request(struct iriap_cb *self);
 void iriap_send_ack( struct iriap_cb *self);
 void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb);
 
 void iriap_register_server(void);
 
-void iriap_watchdog_timer_expired( unsigned long data);
+void iriap_watchdog_timer_expired(void *data);
 
-static inline void iriap_start_watchdog_timer( struct iriap_cb *self, 
-					       int timeout) 
+static inline void iriap_start_watchdog_timer(struct iriap_cb *self, 
+					      int timeout) 
 {
-	irda_start_timer( &self->watchdog_timer, timeout, 
-			  (unsigned long) self, iriap_watchdog_timer_expired);
+	irda_start_timer(&self->watchdog_timer, timeout, self, 
+			 iriap_watchdog_timer_expired);
 }
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/iriap_event.h linux/include/net/irda/iriap_event.h
--- linux-2.2.15-pre2/include/net/irda/iriap_event.h	Thu Dec 17 09:01:03 1998
+++ linux/include/net/irda/iriap_event.h	Mon Dec  3 21:57:53 2001
@@ -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 Sep  4 13:19:28 1998
+ * Modified at:   Sun Oct 31 22:02:54 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 
@@ -65,20 +65,21 @@
 	IAP_LM_CONNECT_CONFIRM,
 } IRIAP_EVENT;
 
-void iriap_next_client_state   ( struct iriap_cb *self, IRIAP_STATE state);
-void iriap_next_call_state     ( struct iriap_cb *self, IRIAP_STATE state);
-void iriap_next_server_state   ( struct iriap_cb *self, IRIAP_STATE state);
-void iriap_next_r_connect_state( struct iriap_cb *self, IRIAP_STATE state);
-
-
-void iriap_do_client_event( struct iriap_cb *self, IRIAP_EVENT event, 
-			    struct sk_buff *skb);
-void iriap_do_call_event  ( struct iriap_cb *self, IRIAP_EVENT event, 
-			    struct sk_buff *skb);
-
-void iriap_do_server_event   ( struct iriap_cb *self, IRIAP_EVENT event, 
-			       struct sk_buff *skb);
-void iriap_do_r_connect_event( struct iriap_cb *self, IRIAP_EVENT event, 
-			       struct sk_buff *skb);
+void iriap_next_client_state   (struct iriap_cb *self, IRIAP_STATE state);
+void iriap_next_call_state     (struct iriap_cb *self, IRIAP_STATE state);
+void iriap_next_server_state   (struct iriap_cb *self, IRIAP_STATE state);
+void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state);
+
+
+void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event, 
+			   struct sk_buff *skb);
+void iriap_do_call_event  (struct iriap_cb *self, IRIAP_EVENT event, 
+			   struct sk_buff *skb);
+
+void iriap_do_server_event   (struct iriap_cb *self, IRIAP_EVENT event, 
+			      struct sk_buff *skb);
+void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event, 
+			      struct sk_buff *skb);
+
+#endif /* IRIAP_FSM_H */
 
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/irias_object.h linux/include/net/irda/irias_object.h
--- linux-2.2.15-pre2/include/net/irda/irias_object.h	Sun Mar  7 15:26:43 1999
+++ linux/include/net/irda/irias_object.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct  1 22:49:50 1998
- * Modified at:   Wed Feb  3 10:38:02 1999
+ * Modified at:   Wed Dec 15 11:20:57 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 
@@ -25,6 +25,7 @@
 #ifndef LM_IAS_OBJECT_H
 #define LM_IAS_OBJECT_H
 
+#include <net/irda/irda.h>
 #include <net/irda/irqueue.h>
 
 /* LM-IAS Attribute types */
@@ -37,8 +38,8 @@
  *  LM-IAS Object
  */
 struct ias_object {
-	QUEUE queue;     /* Must be first! */
-	int magic;
+	queue_t q;     /* Must be first! */
+	magic_t magic;
 	
 	char  *name;
 	int   id;
@@ -65,19 +66,19 @@
  *  Attributes used by LM-IAS objects
  */
 struct ias_attrib {
-	QUEUE queue; /* Must be first! */
+	queue_t q; /* Must be first! */
 	int magic;
 
         char *name;   	         /* Attribute name */
 	struct ias_value *value; /* Attribute value */
 };
 
-char *strdup( char *str);
+char *strdup(char *str);
 
-struct ias_object *irias_new_object( char *name, int id);
-void irias_insert_object( struct ias_object *obj);
-void __irias_delete_object( struct ias_object *obj);
-void irias_delete_object( char *name);
+struct ias_object *irias_new_object(char *name, int id);
+void irias_insert_object(struct ias_object *obj);
+int  irias_delete_object(struct ias_object *obj);
+void __irias_delete_object(struct ias_object *obj);
 
 void irias_add_integer_attrib(struct ias_object *obj, char *name, int value);
 void irias_add_string_attrib(struct ias_object *obj, char *name, char *value);
@@ -85,13 +86,14 @@
 			     int len);
 int irias_object_change_attribute(char *obj_name, char *attrib_name, 
 				  struct ias_value *new_value);
-struct ias_object *irias_find_object( char *name);
-struct ias_attrib *irias_find_attrib( struct ias_object *obj, char *name);
+struct ias_object *irias_find_object(char *name);
+struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name);
 
-struct ias_value *irias_new_string_value( char *string);
-struct ias_value *irias_new_integer_value( int integer);
-struct ias_value *irias_new_octseq_value( __u8 *octseq , int len);
-void irias_delete_value( struct ias_value *value);
+struct ias_value *irias_new_string_value(char *string);
+struct ias_value *irias_new_integer_value(int integer);
+struct ias_value *irias_new_octseq_value(__u8 *octseq , int len);
+struct ias_value *irias_new_missing_value(void);
+void irias_delete_value(struct ias_value *value);
 
 extern struct ias_value missing;
 extern hashbin_t *objects;
diff -urN linux-2.2.15-pre2/include/net/irda/irlan_common.h linux/include/net/irda/irlan_common.h
--- linux-2.2.15-pre2/include/net/irda/irlan_common.h	Mon Jun  7 16:19:59 1999
+++ linux/include/net/irda/irlan_common.h	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Mon May 31 13:54:20 1999
+ * Modified at:   Sun Oct 31 19:41:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -127,6 +127,8 @@
 	int tx_busy;
 	struct sk_buff_head txq; /* Transmit control queue */
 
+	struct iriap_cb *iriap;
+
 	struct timer_list kick_timer;
 };
 
@@ -159,7 +161,7 @@
  *  IrLAN control block
  */
 struct irlan_cb {
-	QUEUE queue; /* Must be first */
+	queue_t q; /* Must be first */
 
 	int    magic;
 	char   ifname[9];
diff -urN linux-2.2.15-pre2/include/net/irda/irlap.h linux/include/net/irda/irlap.h
--- linux-2.2.15-pre2/include/net/irda/irlap.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/irlap.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Sun May  9 11:38:18 1999
+ * Modified at:   Fri Dec 10 13:21:17 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 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,9 +32,12 @@
 #include <linux/netdevice.h>
 #include <linux/ppp_defs.h>
 #include <linux/ppp-comp.h>
+#include <linux/timer.h>
 
 #include <net/irda/irlap_event.h>
 
+#define CONFIG_IRDA_DYNAMIC_WINDOW 1
+
 #define LAP_RELIABLE   1
 #define LAP_UNRELIABLE 0
 
@@ -54,7 +58,7 @@
 #define XID_FORMAT 0x01       /* Discovery XID format */
 
 #define LAP_WINDOW_SIZE 8
-#define MAX_CONNECTIONS 1
+#define LAP_MAX_QUEUE  10
 
 #define NR_EXPECTED     1
 #define NR_UNEXPECTED   0
@@ -65,6 +69,7 @@
 #define NS_INVALID     -1
 
 #ifdef CONFIG_IRDA_COMPRESSION
+
 /*  
  *  Just some shortcuts (may give you strange compiler errors if you change 
  *  them :-)
@@ -76,7 +81,7 @@
 #define irda_incomp      (*self->decompressor.cp->incomp)
 
 struct irda_compressor {
-	QUEUE queue;
+	queue_t q;
 
 	struct compressor *cp;
 	void *state; /* Not used by IrDA */
@@ -85,12 +90,10 @@
 
 /* Main structure of IrLAP */
 struct irlap_cb {
-	QUEUE q; /* Must be first */
+	queue_t q;     /* Must be first */
+	magic_t magic;
 
-	int magic;
-
-	struct irda_device *irdev;
-	struct device      *netdev;
+	struct device  *netdev;
 
 	/* Connection state */
 	volatile IRLAP_STATE state;       /* Current state */
@@ -104,13 +107,18 @@
 	struct timer_list wd_timer;
 	struct timer_list backoff_timer;
 
+	/* Media busy stuff */
+	struct timer_list media_busy_timer;
+	int media_busy;
+
 	/* Timeouts which will be different with different turn time */
 	int slot_timeout;
 	int poll_timeout;
 	int final_timeout;
 	int wd_timeout;
 
-	struct sk_buff_head tx_list;  /* Frames to be transmitted */
+	struct sk_buff_head txq;  /* Frames to be transmitted */
+	struct sk_buff_head txq_ultra;
 
  	__u8    caddr;        /* Connection address */
 	__u32   saddr;        /* Source device address */
@@ -126,7 +134,7 @@
 #ifdef CONFIG_IRDA_FAST_RR
 	int     fast_RR_timeout;
 	int     fast_RR;      
-#endif
+#endif /* CONFIG_IRDA_FAST_RR */
 	
 	int N1; /* N1 * F-timer = Negitiated link disconnect warning threshold */
 	int N2; /* N2 * F-timer = Negitiated link disconnect time */
@@ -136,14 +144,16 @@
 	int     remote_busy;
 	int     xmitflag;
 
-	__u8    vs;           /* Next frame to be sent */
-	__u8    vr;           /* Next frame to be received */
-/* 	int     tmp; */
-	__u8    va;           /* Last frame acked */
- 	int     window;       /* Nr of I-frames allowed to send */
-	int     window_size;  /* Current negotiated window size */
-	int     window_bytes; /* Number of bytes allowed to send */
-	int     bytes_left;   /* Number of bytes allowed to transmit */
+	__u8    vs;            /* Next frame to be sent */
+	__u8    vr;            /* Next frame to be received */
+	__u8    va;            /* Last frame acked */
+ 	int     window;        /* Nr of I-frames allowed to send */
+	int     window_size;   /* Current negotiated window size */
+
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+	__u32   line_capacity; /* Number of bytes allowed to send */
+	__u32   bytes_left;    /* Number of bytes still allowed to transmit */
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 
 	struct sk_buff_head wx_list;
 
@@ -158,21 +168,22 @@
 	hashbin_t   *discovery_log;
  	discovery_t *discovery_cmd;
 
-	struct qos_info qos_tx;    /* QoS requested by peer */
-	struct qos_info qos_rx;    /* QoS requested by self */
+	__u32 speed; 
+
+	struct qos_info  qos_tx;   /* QoS requested by peer */
+	struct qos_info  qos_rx;   /* QoS requested by self */
+	struct qos_info *qos_dev;  /* QoS supported by device */
 
-	struct notify_t notify; /* Callbacks to IrLMP */
+	notify_t notify; /* Callbacks to IrLMP */
 
 	int    mtt_required;  /* Minumum turnaround time required */
 	int    xbofs_delay;   /* Nr of XBOF's used to MTT */
 	int    bofs_count;    /* Negotiated extra BOFs */
 
- 	struct irda_statistics stats;
-
 #ifdef CONFIG_IRDA_COMPRESSION
 	struct irda_compressor compressor;
         struct irda_compressor decompressor;
-#endif
+#endif /* CONFIG_IRDA_COMPRESSION */
 };
 
 extern hashbin_t *irlap;
@@ -180,55 +191,56 @@
 /* 
  *  Function prototypes 
  */
+int irlap_init(void);
+void irlap_cleanup(void);
 
-int irlap_init( void);
-void irlap_cleanup( void);
+struct irlap_cb *irlap_open(struct device *dev, struct qos_info *qos);
+void irlap_close(struct irlap_cb *self);
 
-struct irlap_cb *irlap_open( struct irda_device *dev);
-void irlap_close( struct irlap_cb *self);
+void irlap_connect_request(struct irlap_cb *self, __u32 daddr, 
+			   struct qos_info *qos, int sniff);
+void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb);
+void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb);
+void irlap_connect_confirm(struct irlap_cb *, struct sk_buff *skb);
 
-void irlap_connect_request( struct irlap_cb *self, __u32 daddr, 
-			    struct qos_info *qos, int sniff);
-void irlap_connect_response( struct irlap_cb *self, struct sk_buff *skb);
-void irlap_connect_indication( struct irlap_cb *self, struct sk_buff *skb);
-void irlap_connect_confirm( struct irlap_cb *, struct sk_buff *skb);
+void irlap_data_indication(struct irlap_cb *, struct sk_buff *, int unreliable);
+void irlap_data_request(struct irlap_cb *, struct sk_buff *, int unreliable);
 
-inline void irlap_data_indication( struct irlap_cb *, struct sk_buff *);
-inline void irlap_unit_data_indication( struct irlap_cb *, struct sk_buff *);
-inline void irlap_data_request( struct irlap_cb *, struct sk_buff *, 
-				int reliable);
+#ifdef CONFIG_IRDA_ULTRA
+void irlap_unitdata_request(struct irlap_cb *, struct sk_buff *);
+void irlap_unitdata_indication(struct irlap_cb *, struct sk_buff *);
+#endif /* CONFIG_IRDA_ULTRA */
 
-void irlap_disconnect_request( struct irlap_cb *);
-void irlap_disconnect_indication( struct irlap_cb *, LAP_REASON reason);
+void irlap_disconnect_request(struct irlap_cb *);
+void irlap_disconnect_indication(struct irlap_cb *, LAP_REASON reason);
 
-void irlap_status_indication( int quality_of_link);
+void irlap_status_indication(int quality_of_link);
 
-void irlap_test_request( __u8 *info, int len);
+void irlap_test_request(__u8 *info, int len);
 
 void irlap_discovery_request(struct irlap_cb *, discovery_t *discovery);
 void irlap_discovery_confirm(struct irlap_cb *, hashbin_t *discovery_log);
 void irlap_discovery_indication(struct irlap_cb *, discovery_t *discovery);
 
-void irlap_reset_indication( struct irlap_cb *self);
+void irlap_reset_indication(struct irlap_cb *self);
 void irlap_reset_confirm(void);
 
-void irlap_update_nr_received( struct irlap_cb *, int nr);
-int irlap_validate_nr_received( struct irlap_cb *, int nr);
-int irlap_validate_ns_received( struct irlap_cb *, int ns);
+void irlap_update_nr_received(struct irlap_cb *, int nr);
+int irlap_validate_nr_received(struct irlap_cb *, int nr);
+int irlap_validate_ns_received(struct irlap_cb *, int ns);
 
-int  irlap_generate_rand_time_slot( int S, int s);
-void irlap_initiate_connection_state( struct irlap_cb *);
+int  irlap_generate_rand_time_slot(int S, int s);
+void irlap_initiate_connection_state(struct irlap_cb *);
 void irlap_flush_all_queues(struct irlap_cb *);
-void irlap_change_speed(struct irlap_cb *, int);
+void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now);
 void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *);
 
 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 *);
+void irlap_apply_connection_parameters(struct irlap_cb *self);
+void irlap_set_local_busy(struct irlap_cb *self, int status);
 
-extern inline __u8 irlap_get_header_size(struct irlap_cb *self)
-{
-	return 2;
-}
+#define IRLAP_GET_HEADER_SIZE(self) 2 /* Will be different when we get VFIR */
+#define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/irlap_event.h linux/include/net/irda/irlap_event.h
--- linux-2.2.15-pre2/include/net/irda/irlap_event.h	Thu Apr 15 05:42:41 1999
+++ linux/include/net/irda/irlap_event.h	Mon Dec  3 21:57:53 2001
@@ -1,25 +1,33 @@
 /*********************************************************************
  *                
+ *                
  * Filename:      irlap_event.h
  * Version:       0.1
  * Description:   
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Tue Apr  6 17:10:38 1999
+ * Modified at:   Tue Dec 21 11:20:30 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 
  *     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
+ *     
  ********************************************************************/
 
 #ifndef IRLAP_EVENT_H
@@ -62,6 +70,7 @@
 
 	/* Send events */
 	SEND_I_CMD,
+	SEND_UI_FRAME,
 
 	/* Receive events */
 	RECV_DISCOVERY_XID_CMD,
@@ -71,14 +80,20 @@
 	RECV_TEST_RSP,
 	RECV_UA_RSP,
 	RECV_DM_RSP,
+	RECV_RD_RSP,
 	RECV_I_CMD,
 	RECV_I_RSP,
 	RECV_UI_FRAME,
 	RECV_FRMR_RSP,
 	RECV_RR_CMD,
 	RECV_RR_RSP,
-	RECV_RNR_FRAME,
-	RECV_DISC_FRAME,
+	RECV_RNR_CMD,
+	RECV_RNR_RSP,
+	RECV_REJ_CMD,
+	RECV_REJ_RSP,
+	RECV_SREJ_CMD,
+	RECV_SREJ_RSP,
+	RECV_DISC_CMD,
 
 	/* Timer events */
 	SLOT_TIMER_EXPIRED,
@@ -115,9 +130,11 @@
 
 extern const char *irlap_state[];
 
-void irlap_do_event( struct irlap_cb *self, IRLAP_EVENT event, 
-		     struct sk_buff *skb, struct irlap_info *info);
-void irlap_next_state( struct irlap_cb *self, IRLAP_STATE state);
-void irlap_print_event( IRLAP_EVENT event);
+void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, 
+		    struct sk_buff *skb, struct irlap_info *info);
+void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state);
+void irlap_print_event(IRLAP_EVENT event);
+
+extern int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb);
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/irlap_frame.h linux/include/net/irda/irlap_frame.h
--- linux-2.2.15-pre2/include/net/irda/irlap_frame.h	Sat Apr 24 17:50:06 1999
+++ linux/include/net/irda/irlap_frame.h	Mon Dec  3 21:57:53 2001
@@ -2,24 +2,31 @@
  *                
  * Filename:      irlap_frame.h
  * Version:       0.9
- * Description:   Build and transmit IrLAP frames
+ * Description:   IrLAP frame declarations
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Fri Apr 23 09:33:55 1999
+ * Modified at:   Sat Dec 25 21:07:26 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 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 
  *     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
+ *     
  ********************************************************************/
 
 #ifndef IRLAP_FRAME_H
@@ -73,7 +80,6 @@
 	__u8  flags; /* Discovery flags */
 	__u8  slotnr;
 	__u8  version;
-	__u8  discovery_info[0];
 } PACK;
 
 struct test_frame {
@@ -81,7 +87,6 @@
 	__u8 control;
 	__u32 saddr;         /* Source device address */
 	__u32 daddr;         /* Destination device address */
-	__u8 info[0];        /* Information */
 } PACK;
 
 struct ua_frame {
@@ -90,13 +95,11 @@
 
 	__u32 saddr; /* Source device address */
 	__u32 daddr; /* Dest device address */
-	__u8  params[0];
 } PACK;
 	
 struct i_frame {
 	__u8 caddr;
 	__u8 control;
-	__u8 data[0];
 } PACK;
 
 struct snrm_frame {
@@ -105,37 +108,31 @@
 	__u32 saddr;
 	__u32 daddr;
 	__u8  ncaddr;
-	__u8  params[0];
 } PACK;
 
-/* Per-packet information we need to hide inside sk_buff */
-struct irlap_skb_cb {
-	int magic; /* Be sure that we can trust the information */
-	int mtt;   /* minimum turn around time */
-	int xbofs; /* number of xbofs required */
-	int vs;    /* next frame to send */
-	int vr;    /* next frame to receive */
-};
-
-void irlap_send_discovery_xid_frame( struct irlap_cb *, int S, __u8 s, 
-				     __u8 command, discovery_t *discovery);
-void irlap_send_snrm_frame( struct irlap_cb *, struct qos_info *);
-void irlap_send_test_frame(struct irlap_cb *self, __u32 daddr, 
+void irlap_send_discovery_xid_frame(struct irlap_cb *, int S, __u8 s, 
+				    __u8 command, discovery_t *discovery);
+void irlap_send_snrm_frame(struct irlap_cb *, struct qos_info *);
+void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, 
 			   struct sk_buff *cmd);
-void irlap_send_ua_response_frame( struct irlap_cb *, struct qos_info *);
-void irlap_send_ui_frame( struct irlap_cb *self, struct sk_buff *skb,
-			  int command);
-void irlap_send_dm_frame( struct irlap_cb *);
-void irlap_send_disc_frame( struct irlap_cb *);
-void irlap_send_rr_frame( struct irlap_cb *, int command);
-
-void irlap_send_data_primary( struct irlap_cb *, struct sk_buff *);
-void irlap_send_data_primary_poll( struct irlap_cb *, struct sk_buff *);
-void irlap_send_data_secondary( struct irlap_cb *, struct sk_buff *);
-void irlap_send_data_secondary_final( struct irlap_cb *, struct sk_buff *);
-void irlap_resend_rejected_frames( struct irlap_cb *, int command);
+void irlap_send_ua_response_frame(struct irlap_cb *, struct qos_info *);
+void irlap_send_dm_frame(struct irlap_cb *self);
+void irlap_send_rd_frame(struct irlap_cb *self);
+void irlap_send_disc_frame(struct irlap_cb *self);
+void irlap_send_rr_frame(struct irlap_cb *self, int command);
+
+void irlap_send_data_primary(struct irlap_cb *, struct sk_buff *);
+void irlap_send_data_primary_poll(struct irlap_cb *, struct sk_buff *);
+void irlap_send_data_secondary(struct irlap_cb *, struct sk_buff *);
+void irlap_send_data_secondary_final(struct irlap_cb *, struct sk_buff *);
+void irlap_resend_rejected_frames(struct irlap_cb *, int command);
+void irlap_resend_rejected_frame(struct irlap_cb *self, int command);
+
+void irlap_send_i_frame(struct irlap_cb *, struct sk_buff *, int command);
+void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
+			 __u8 caddr, int command);
 
-void irlap_send_i_frame( struct irlap_cb *, struct sk_buff *, int command);
-void irlap_send_ui_frame( struct irlap_cb *, struct sk_buff *, int command);
+extern int irlap_insert_qos_negotiation_params(struct irlap_cb *self, 
+					       struct sk_buff *skb);
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/irlmp.h linux/include/net/irda/irlmp.h
--- linux-2.2.15-pre2/include/net/irda/irlmp.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/irlmp.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Sun May  9 11:01:34 1999
+ * Modified at:   Fri Dec 10 13:23:01 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 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 
@@ -41,17 +42,14 @@
 #define LSAP_MASK     0x7f
 #define LSAP_IAS      0x00
 #define LSAP_ANY      0xff
+#define LSAP_MAX      0x6f /* 0x70-0x7f are reserved */
+#define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */
 
 #define DEV_ADDR_ANY  0xffffffff
 
-/* Predefined LSAPs used by the various servers */
-#define TSAP_IRLAN    0x05
-#define LSAP_IRLPT    0x06
-#define TSAP_IROBEX   0x07
-#define TSAP_IRCOMM   0x08
-
 #define LMP_HEADER          2    /* Dest LSAP + Source LSAP */
 #define LMP_CONTROL_HEADER  4
+#define LMP_PID_HEADER      1    /* Used by Ultra */
 #define LMP_MAX_HEADER      (LMP_CONTROL_HEADER+LAP_MAX_HEADER)
 
 #define LM_MAX_CONNECTIONS  10
@@ -77,13 +75,13 @@
 typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *);
 
 typedef struct {
-	QUEUE queue; /* Must be first */
+	queue_t queue; /* Must be first */
 
 	__u16 hints; /* Hint bits */
 } irlmp_service_t;
 
 typedef struct {
-	QUEUE queue; /* Must be first */
+	queue_t queue; /* Must be first */
 
 	__u16 hint_mask;
 
@@ -97,24 +95,23 @@
  *  Information about each logical LSAP connection
  */
 struct lsap_cb {
-	QUEUE queue;      /* Must be first */
-
-	int   magic;
-
-	int   connected;
-	int   persistent;
-
-	struct irda_statistics stats;
+	queue_t queue;      /* Must be first */
+	magic_t magic;
 
-	__u8  slsap_sel;   /* Source (this) LSAP address */
-	__u8  dlsap_sel;   /* Destination LSAP address (if connected) */
+	int  connected;
+	int  persistent;
 
-	struct sk_buff *tmp_skb; /* Store skb here while connecting */
+	__u8 slsap_sel;   /* Source (this) LSAP address */
+	__u8 dlsap_sel;   /* Destination LSAP address (if connected) */
+#ifdef CONFIG_IRDA_ULTRA
+	__u8 pid;         /* Used by connectionless LSAP */
+#endif /* CONFIG_IRDA_ULTRA */
+	struct sk_buff *conn_skb; /* Store skb here while connecting */
 
 	struct timer_list watchdog_timer;
 
 	IRLMP_STATE     lsap_state;  /* Connection state */
-	struct notify_t notify;      /* Indication/Confirm entry points */
+	notify_t        notify;      /* Indication/Confirm entry points */
 	struct qos_info qos;         /* QoS for this connection */
 
 	struct lap_cb *lap; /* Pointer to LAP connection structure */
@@ -124,15 +121,16 @@
  *  Information about each registred IrLAP layer
  */
 struct lap_cb {
-	QUEUE queue;      /* Must be first */
+	queue_t queue; /* Must be first */
+	magic_t magic;
 
-	int magic;
 	int reason;    /* LAP disconnect reason */
 
 	IRLMP_STATE lap_state;
 
-	struct irlap_cb *irlap;    /* Instance of IrLAP layer */
+	struct irlap_cb *irlap;   /* Instance of IrLAP layer */
 	hashbin_t *lsaps;         /* LSAP associated with this link */
+	int refcount;
 
 	__u8  caddr;  /* Connection address */
  	__u32 saddr;  /* Source device address */
@@ -157,7 +155,7 @@
  *  Main structure for IrLMP
  */
 struct irlmp_cb {
-	int magic;
+	magic_t magic;
 
 	__u8 conflict_flag;
 	
@@ -187,7 +185,7 @@
 /* Prototype declarations */
 int  irlmp_init(void);
 void irlmp_cleanup(void);
-struct lsap_cb *irlmp_open_lsap( __u8 slsap, struct notify_t *notify);
+struct lsap_cb *irlmp_open_lsap(__u8 slsap, notify_t *notify, __u8 pid);
 void irlmp_close_lsap( struct lsap_cb *self);
 
 __u16 irlmp_service_to_hint(int service);
@@ -199,30 +197,36 @@
 int irlmp_update_client(__u32 handle, __u16 hint_mask, 
 			DISCOVERY_CALLBACK1, DISCOVERY_CALLBACK2);
 
-void irlmp_register_link(struct irlap_cb *, __u32 saddr, struct notify_t *);
+void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *);
 void irlmp_unregister_link(__u32 saddr);
 
 int  irlmp_connect_request(struct lsap_cb *, __u8 dlsap_sel, 
 			   __u32 saddr, __u32 daddr,
 			   struct qos_info *, struct sk_buff *);
 void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb);
-void irlmp_connect_response(struct lsap_cb *, struct sk_buff *);
+int  irlmp_connect_response(struct lsap_cb *, struct sk_buff *);
 void irlmp_connect_confirm(struct lsap_cb *, struct sk_buff *);
 struct lsap_cb *irlmp_dup(struct lsap_cb *self, void *instance);
 
 void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, 
 				 struct sk_buff *userdata);
-void irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata);
+int  irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata);
 
 void irlmp_discovery_confirm(hashbin_t *discovery_log);
 void irlmp_discovery_request(int nslots);
 void irlmp_do_discovery(int nslots);
 discovery_t *irlmp_get_discovery_response(void);
 
-void irlmp_data_request(struct lsap_cb *, struct sk_buff *);
-inline void irlmp_udata_request(struct lsap_cb *, struct sk_buff *);
-inline void irlmp_data_indication(struct lsap_cb *, struct sk_buff *);
-inline void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *);
+int  irlmp_data_request(struct lsap_cb *, struct sk_buff *);
+void irlmp_data_indication(struct lsap_cb *, struct sk_buff *);
+
+int  irlmp_udata_request(struct lsap_cb *, struct sk_buff *);
+void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *);
+
+#ifdef CONFIG_IRDA_ULTRA
+int  irlmp_connless_data_request(struct lsap_cb *, struct sk_buff *);
+void irlmp_connless_data_indication(struct lsap_cb *, struct sk_buff *);
+#endif /* CONFIG_IRDA_ULTRA */
 
 void irlmp_status_request(void);
 void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock);
@@ -235,10 +239,20 @@
 __u32 irlmp_get_daddr(struct lsap_cb *self);
 
 extern char *lmp_reasons[];
+extern int sysctl_discovery_timeout;
 extern int sysctl_discovery_slots;
 extern int sysctl_discovery;
 extern struct irlmp_cb *irlmp;
 
 static inline hashbin_t *irlmp_get_cachelog(void) { return irlmp->cachelog; }
+
+static inline int irlmp_get_lap_tx_queue_len(struct lsap_cb *self)
+{
+	ASSERT(self != NULL, return 0;);
+	ASSERT(self->lap != NULL, return 0;);
+	ASSERT(self->lap->irlap != NULL, return 0;);
+
+	return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap);
+}
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/irlmp_event.h linux/include/net/irda/irlmp_event.h
--- linux-2.2.15-pre2/include/net/irda/irlmp_event.h	Thu Apr 15 05:42:41 1999
+++ linux/include/net/irda/irlmp_event.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Thu Feb 25 20:49:16 1999
+ * Modified at:   Thu Jul  8 12:18:54 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 
@@ -98,17 +99,21 @@
 extern const char *irlmp_state[];
 extern const char *irlsap_state[];
 
-void irlmp_watchdog_timer_expired( unsigned long data);
-void irlmp_discovery_timer_expired( unsigned long data);
-void irlmp_idle_timer_expired( unsigned long data);
-
-void irlmp_next_station_state( IRLMP_STATE state);
-void irlmp_next_lsap_state( struct lsap_cb *self, LSAP_STATE state);
-void irlmp_next_lap_state( struct lap_cb *self, IRLMP_STATE state);
-
-void irlmp_do_lap_event( struct lap_cb *self, IRLMP_EVENT event, 
-			 struct sk_buff *skb);
-void irlmp_do_lsap_event( struct lsap_cb *self, IRLMP_EVENT event, 
-			  struct sk_buff *skb);
+void irlmp_watchdog_timer_expired(void *data);
+void irlmp_discovery_timer_expired(void *data);
+void irlmp_idle_timer_expired(void *data);
+
+void irlmp_next_station_state(IRLMP_STATE state);
+void irlmp_next_lsap_state(struct lsap_cb *self, LSAP_STATE state);
+void irlmp_next_lap_state(struct lap_cb *self, IRLMP_STATE state);
+
+void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, 
+			struct sk_buff *skb);
+int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, 
+			struct sk_buff *skb);
+
+#endif /* IRLMP_EVENT_H */
+
+
+
 
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/irlmp_frame.h linux/include/net/irda/irlmp_frame.h
--- linux-2.2.15-pre2/include/net/irda/irlmp_frame.h	Thu Apr 15 05:42:41 1999
+++ linux/include/net/irda/irlmp_frame.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 02:09:59 1997
- * Modified at:   Tue Apr  6 17:12:57 1999
+ * Modified at:   Fri Dec 10 13:21:53 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 
@@ -42,8 +43,12 @@
 				int expedited, struct sk_buff *skb);
 void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, 
 			__u8 opcode, struct sk_buff *skb);
-void irlmp_link_data_indication(struct lap_cb *, int reliable, 
-				struct sk_buff *);
+void irlmp_link_data_indication(struct lap_cb *, struct sk_buff *, 
+				int unreliable);
+#ifdef CONFIG_IRDA_ULTRA
+void irlmp_link_unitdata_indication(struct lap_cb *, struct sk_buff *);
+#endif /* CONFIG_IRDA_ULTRA */
+
 void irlmp_link_connect_indication(struct lap_cb *, __u32 saddr, __u32 daddr,
 				   struct qos_info *qos, struct sk_buff *skb);
 void irlmp_link_connect_request(__u32 daddr);
diff -urN linux-2.2.15-pre2/include/net/irda/irlpt_cli.h linux/include/net/irda/irlpt_cli.h
--- linux-2.2.15-pre2/include/net/irda/irlpt_cli.h	Sat Apr 24 17:50:06 1999
+++ linux/include/net/irda/irlpt_cli.h	Wed Dec 31 16:00:00 1969
@@ -1,49 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irlpt_cli.h
- * Version:       0.1
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Wed Apr 21 16:46:26 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>
- *     Copyright (c) 1998, 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.
- *  
- *     I, Thomas Davis, provide no warranty for any of this software. This
- *     material is provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#ifndef IRLPT_CLIENT_H
-#define IRLPT_CLIENT_H
-
-/* Debug function */
-
-/* int  client_init( struct device *dev); */
-
-/*
- * if it's static, it doesn't go in here.
- */
-
-void irlpt_client_get_value_confirm(int result, __u16 obj_id, 
-				    struct ias_value *value, 
-				    void *priv);
-void irlpt_client_connect_indication( void *instance, 
-				      void *sap, 
-				      struct qos_info *qos, 
-				      int max_seg_size,
-				      struct sk_buff *skb);
-void irlpt_client_connect_request( struct irlpt_cb *self);
-
-extern hashbin_t *irlpt_clients;
-
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/irlpt_cli_fsm.h linux/include/net/irda/irlpt_cli_fsm.h
--- linux-2.2.15-pre2/include/net/irda/irlpt_cli_fsm.h	Sun Mar  7 15:26:43 1999
+++ linux/include/net/irda/irlpt_cli_fsm.h	Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irlpt_cli_fsm.h
- * Version:       0.1
- * Sources:       irlan_event.h
- * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, 
- *		All Rights Reserved.
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.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, provide no warranty for any of this software. 
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLPT_EVENT_H
-#define IRLPT_EVENT_H
-
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-
-extern void irlpt_client_do_event( struct irlpt_cb *self,  
-				   IRLPT_EVENT event, 
-				   struct sk_buff *skb, 
-				   struct irlpt_info *info);
-extern void irlpt_client_next_state( struct irlpt_cb *self, 
-				     IRLPT_CLIENT_STATE state);
-
-#endif
-
diff -urN linux-2.2.15-pre2/include/net/irda/irlpt_common.h linux/include/net/irda/irlpt_common.h
--- linux-2.2.15-pre2/include/net/irda/irlpt_common.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/irlpt_common.h	Wed Dec 31 16:00:00 1969
@@ -1,190 +0,0 @@
-/*********************************************************************
- *
- * Filename:      irlpt_common.h
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Thomas Davis, <ratbert@radiks.net>
- * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Sun Mar  8 23:44:19 1998
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * Sources:	  irlan.c
- *
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>,
- *			   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
- *     published by the Free Software Foundation; either version 2 of
- *     the License, or (at your option) any later version.
- *
- *     I, Thomas Davis, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLPT_COMMON_H
-#define IRLPT_COMMON_H
-
-#include <net/irda/qos.h>
-#include <net/irda/irmod.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/miscdevice.h>
-
-#include <linux/poll.h>
-
-extern char *irlpt_service_type[];
-extern char *irlpt_port_type[];
-extern char *irlpt_connected[];
-extern char *irlpt_reasons[];
-extern char *irlpt_client_fsm_state[];
-extern char *irlpt_server_fsm_state[];
-extern char *irlpt_fsm_event[];
-
-extern struct wait_queue *lpt_wait;
-
-extern struct irlpt_cb *irlpt_find_handle(unsigned int minor);
-extern void irlpt_flow_control(struct sk_buff *skb);
-
-extern ssize_t irlpt_read( struct file *file, char *buffer, 
-			   size_t count, loff_t *noidea);
-extern ssize_t irlpt_write(struct file *file, const char *buffer, 
-			   size_t count, loff_t *noidea);
-extern loff_t irlpt_seek(struct file *, loff_t, int);
-extern int irlpt_open(struct inode * inode, struct file *file);
-extern int irlpt_close(struct inode *inode, struct file *file);
-extern u_int irlpt_poll(struct file *file, poll_table *wait);
-
-/* FSM definitions */
-
-typedef enum {
-        IRLPT_CLIENT_IDLE,
-	IRLPT_CLIENT_QUERY,
-	IRLPT_CLIENT_READY,
-	IRLPT_CLIENT_WAITI,
-	IRLPT_CLIENT_CONN,
-} IRLPT_CLIENT_STATE;
-
-typedef enum {
-	IRLPT_SERVER_IDLE,
-	IRLPT_SERVER_CONN,
-} IRLPT_SERVER_STATE;
-    
-/* IrLPT Events */
-
-typedef enum {
-	QUERY_REMOTE_IAS,
-	IAS_PROVIDER_AVAIL,
-	IAS_PROVIDER_NOT_AVAIL,
-	LAP_DISCONNECT,
-	LMP_CONNECT,
-	LMP_DISCONNECT,
-	LMP_CONNECT_INDICATION,
-	LMP_DISCONNECT_INDICATION,
-        IRLPT_DISCOVERY_INDICATION,
-	IRLPT_CONNECT_REQUEST,
-	IRLPT_DISCONNECT_REQUEST,
-	CLIENT_DATA_INDICATION,
-} IRLPT_EVENT;
-
-struct irlpt_info {
-	struct lsap_cb *lsap;
-	__u8 dlsap_sel;
-	__u32 daddr;
-	__u32 saddr;
-};
-
-/* Command packet types */
-
-#define IRLPT_MAX_PACKET 1024
-#define IRLPT_MAX_HEADER LMP_MAX_HEADER
-#define IRLPT_MAX_DEVICES 3
-#define IRLPT_MAGIC 0x0755
-
-typedef enum {
-	IRLPT_DISCONNECTED,
-	IRLPT_WAITING,
-	IRLPT_CONNECTED,
-	IRLPT_FLUSHED,
-} IRLPT_SERVER_STATUS;
-
-#define IRLPT_LSAP      0x09
-
-#define PI_SERVICE_TYPE	0x00
-
-#define IRLPT_UNKNOWN         0x00            /* not defined yet. */
-#define IRLPT_THREE_WIRE_RAW  0x01		/* bit 0 */
-#define IRLPT_THREE_WIRE      0x02		/* bit 1 */
-#define IRLPT_NINE_WIRE	      0x04		/* bit 2 */
-#define IRLPT_CENTRONICS      0x08		/* bit 3 */
-#define IRLPT_SERVER_MODE     0xFF            /* our own flag */
-
-#define PI_PORT_TYPE	0x01
-
-#define IRLPT_SERIAL	0x01		/* bit 0 */
-#define IRLPT_PARALLEL	0x02		/* bit 1 */
-
-#define PI_PORT_NAME	0x02
-
-#define PI_CRITICAL	0x80
-
-struct irlpt_cb {
-	QUEUE queue;		/* must be first. */
-
-	int magic;		/* magic used to detect corruption of 
-				   the struct */
-	__u32 daddr;		/* address of remote printer */
-	__u32 saddr;            /* my local address. */
-
-	struct timer_list retry_timer;
-	
-	int volatile state;	/* Current state of IrCOMM layer */
-	int open_retries;
-        int in_use;		/* flag to prevent re-use */
-        char ifname[16];		/* name of the allocated instance, 
-				   and registered device. */
-	struct lsap_cb *lsap;	/* lmp handle */
-
-	__u8 dlsap_sel;		/* remote LSAP selector address */
-	__u8 slsap_sel;		/* local LSAP selectoraddress */
-	__u8 servicetype;	/* Type of remote service, ie THREE_WIRE_RAW */
-	__u8 porttype;		/* type of remote port. */
-
-	struct miscdevice ir_dev; /* used to register the misc device. */
-
-	int count;                /* open count */
-	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 */
-	struct wait_queue *write_wait;
-	struct wait_queue *ex_wait;
-
-	/* this is used to remove the printer when it's gone */
-	struct timer_list lpt_timer;
-	void (*timeout) (unsigned long data);
-
-	void (*do_event) (struct irlpt_cb *self, IRLPT_EVENT event, 
-			  struct sk_buff *skb,
-			  struct irlpt_info *info);
-
-	/* this is used by the server side of the system */
-
-        IRLPT_SERVER_STATE connected;
-
-	int eof;
-	int service_LSAP;
-
-	struct sk_buff_head rx_queue; /* read buffer queue */
-};
-
-/* Debug function */
-void irlpt_dump_buffer(struct sk_buff *);
-
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/irlpt_server.h linux/include/net/irda/irlpt_server.h
--- linux-2.2.15-pre2/include/net/irda/irlpt_server.h	Sun Mar  7 15:26:43 1999
+++ linux/include/net/irda/irlpt_server.h	Wed Dec 31 16:00:00 1969
@@ -1,42 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irlpt_server.h
- * Version:       0.1
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Tue Sep 22 11:41:42 1998
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>
- *     Copyright (c) 1998, 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.
- *  
- *     I, Thomas Davis, provide no warranty for any of this software. This
- *     material is provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#ifndef IRLPT_SERVER_H
-#define IRLPT_SERVER_H
-
-#include "qos.h"
-#include "irmod.h"
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/miscdevice.h>
-
-/* int  server_init( struct device *dev); */
-
-extern struct irlpt_cb *irlpt_server;
-
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/irlpt_server_fsm.h linux/include/net/irda/irlpt_server_fsm.h
--- linux-2.2.15-pre2/include/net/irda/irlpt_server_fsm.h	Sun Mar  7 15:26:43 1999
+++ linux/include/net/irda/irlpt_server_fsm.h	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      server_server_fsm.h
- * Version:       0.1
- * Sources:       irlan_event.h
- * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, 
- *		All Rights Reserved.
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.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, provide no warranty for any of this software. 
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLPT_EVENT_H
-#define IRLPT_EVENT_H
-
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-
-void irlpt_server_do_event( struct irlpt_cb *self, 
-			    IRLPT_EVENT event, 
-			    struct sk_buff *skb, 
-			    struct irlpt_info *info);
-void irlpt_server_next_state( struct irlpt_cb *self, 
-			      IRLPT_SERVER_STATE state);
-
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/irmod.h linux/include/net/irda/irmod.h
--- linux-2.2.15-pre2/include/net/irda/irmod.h	Sat Apr 24 17:50:06 1999
+++ linux/include/net/irda/irmod.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:58:52 1997
- * Modified at:   Fri Apr  9 11:13:39 1999
+ * Modified at:   Sun Oct 31 20:01:17 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 
@@ -42,10 +42,10 @@
 	EVENT_REQUEST_MODULE,
 	EVENT_IRLAN_START,
 	EVENT_IRLAN_STOP,
-	EVENT_IRLPT_START,
-	EVENT_IRLPT_STOP,
-	EVENT_IROBEX_START,
-	EVENT_IROBEX_STOP,
+	EVENT_IRLPT_START,  /* Obsolete */
+	EVENT_IRLPT_STOP,   /* Obsolete */
+	EVENT_IROBEX_START, /* Obsolete */
+	EVENT_IROBEX_STOP,  /* Obsolete */
 	EVENT_IRDA_STOP,
 	EVENT_NEED_PROCESS_CONTEXT,
 } IRMGR_EVENT;
@@ -69,7 +69,7 @@
  *  addtional information
  */
 struct irda_event {
-	QUEUE q; /* Must be first */
+	queue_t q; /* Must be first */
 	
 	struct irmanager_event event;
 };
@@ -78,7 +78,7 @@
  *  Funtions with needs to be called with a process context
  */
 struct irda_todo {
-	QUEUE q; /* Must be first */
+	queue_t q; /* Must be first */
 
 	void *self;
 	TODO_CALLBACK callback;
@@ -94,8 +94,8 @@
 
 	int in_use;
 
-	QUEUE *event_queue; /* Events queued for the irmanager */
-	QUEUE *todo_queue;  /* Todo list */
+	queue_t *event_queue; /* Events queued for the irmanager */
+	queue_t *todo_queue;  /* Todo list */
 };
 
 int irmod_init_module(void);
@@ -110,7 +110,7 @@
 static inline int irda_lock(int *lock) 
 {
 	if (test_and_set_bit( 0, (void *) lock))  {
-		DEBUG(3, __FUNCTION__ 
+		IRDA_DEBUG(3, __FUNCTION__ 
 		      "(), Trying to lock, already locked variable!\n");
 		return FALSE;
         }  
@@ -119,7 +119,7 @@
 
 inline int irda_unlock(int *lock);
 
-void irda_notify_init(struct notify_t *notify);
+void irda_notify_init(notify_t *notify);
 
 void irda_execute_as_process(void *self, TODO_CALLBACK callback, __u32 param);
 void irmanager_notify(struct irmanager_event *event);
diff -urN linux-2.2.15-pre2/include/net/irda/irport.h linux/include/net/irda/irport.h
--- linux-2.2.15-pre2/include/net/irda/irport.h	Mon Jun  7 16:19:59 1999
+++ linux/include/net/irda/irport.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug  3 13:49:59 1997
- * Modified at:   Wed May 19 15:31:16 1999
+ * Modified at:   Fri Jan 14 10:21:10 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1997, 1998-2000 Dag Brattli <dagb@cs.uit.no>
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -29,6 +29,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
+#include <asm/spinlock.h>
 
 #include <net/irda/irda_device.h>
 
@@ -49,14 +50,40 @@
 
 #define FRAME_MAX_SIZE 2048
 
-void irport_start(struct irda_device *idev, int iobase);
-void irport_stop(struct irda_device *idev, int iobase);
-int  irport_probe(int iobase);
-
-void irport_change_speed(struct irda_device *idev, int speed);
+struct irport_cb {
+	struct device *netdev; /* Yes! we are some kind of netdevice */
+	struct net_device_stats stats;
+
+	struct irlap_cb *irlap;    /* The link layer we are attached to */
+
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
+
+	struct qos_info qos;       /* QoS capabilities for this device */
+	dongle_t *dongle;          /* Dongle driver */
+
+ 	__u32 flags;               /* Interface flags */
+	__u32 new_speed;
+	int mode;
+	int index;                 /* Instance index */
+
+	spinlock_t lock;           /* For serializing operations */
+
+	/* For piggyback drivers */
+	void *priv;                
+	void (*change_speed)(void *priv, __u32 speed);
+	void (*interrupt)(int irq, void *dev_id, struct pt_regs *regs);
+};
+
+struct irport_cb *irport_open(int i, unsigned int iobase, unsigned int irq);
+int  irport_close(struct irport_cb *self);
+void irport_start(struct irport_cb *self);
+void irport_stop(struct irport_cb *self);
+void irport_change_speed(void *priv, __u32 speed);
 void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
 int  irport_hard_xmit(struct sk_buff *skb, struct device *dev);
-void irport_wait_until_sent(struct irda_device *idev);
+int  irport_net_open(struct device *dev);
+int  irport_net_close(struct device *dev);
 
-#endif
+#endif /* IRPORT_H */
diff -urN linux-2.2.15-pre2/include/net/irda/irqueue.h linux/include/net/irda/irqueue.h
--- linux-2.2.15-pre2/include/net/irda/irqueue.h	Mon Jun  7 16:19:59 1999
+++ linux/include/net/irda/irqueue.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Jun  9 13:26:50 1998
- * Modified at:   Tue May 25 07:54:41 1999
+ * Modified at:   Thu Oct  7 13:25:16 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (C) 1998, Aage Kvalnes <aage@cs.uit.no>
+ *     Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no>
  *     Copyright (c) 1998, Dag Brattli
  *     All Rights Reserved.
  *      
@@ -53,56 +53,49 @@
 #define ALIGN __attribute__((aligned))
 #endif
 
-typedef void (*FREE_FUNC)( void *arg);
+#define Q_NULL { NULL, NULL, "", 0 }
+
+typedef void (*FREE_FUNC)(void *arg);
 
 /*
  * Hashbin
  */
 #define GET_HASHBIN(x) ( x & HASHBIN_MASK )
 
-#define QUEUE struct queue_t
-struct queue_t {
-	QUEUE* q_next;
-	QUEUE* q_prev;
+struct irqueue {
+	struct irqueue *q_next;
+	struct irqueue *q_prev;
 
-	char   q_name[ NAME_SIZE];
+	char   q_name[NAME_SIZE];
 	__u32  q_hash;
 };
+typedef struct irqueue queue_t;
 
 typedef struct hashbin_t {
-	int    magic;
-	int    hb_type;
-	int    hb_size;
-	spinlock_t hb_mutex[ HASHBIN_SIZE ] ALIGN;
-	QUEUE*     hb_queue[ HASHBIN_SIZE ] ALIGN;
+	__u32      magic;
+	int        hb_type;
+	int        hb_size;
+	spinlock_t hb_mutex[HASHBIN_SIZE] ALIGN;
+	queue_t   *hb_queue[HASHBIN_SIZE] ALIGN;
 
-	QUEUE* hb_current;
+	queue_t* hb_current;
 } hashbin_t;
 
-hashbin_t *hashbin_new( int type);
-int      hashbin_delete( hashbin_t* hashbin, FREE_FUNC func);
-int      hashbin_clear( hashbin_t* hashbin, FREE_FUNC free_func);
-void     hashbin_insert( hashbin_t* hashbin, QUEUE* entry, __u32 hashv, 
-			 char* name);
-void*    hashbin_find( hashbin_t* hashbin, __u32 hashv, char* name);
-void*    hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name);
-void*    hashbin_remove_first( hashbin_t *hashbin);
-QUEUE   *hashbin_get_first( hashbin_t *hashbin);
-QUEUE   *hashbin_get_next( hashbin_t *hashbin);
-
-void enqueue_last(QUEUE **queue, QUEUE* element);
-void enqueue_first(QUEUE **queue, QUEUE* element);
-QUEUE *dequeue_first(QUEUE **queue);
+hashbin_t *hashbin_new(int type);
+int      hashbin_delete(hashbin_t* hashbin, FREE_FUNC func);
+int      hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func);
+void     hashbin_insert(hashbin_t* hashbin, queue_t* entry, __u32 hashv, 
+			char* name);
+void*    hashbin_find(hashbin_t* hashbin, __u32 hashv, char* name);
+void*    hashbin_remove(hashbin_t* hashbin, __u32 hashv, char* name);
+void*    hashbin_remove_first(hashbin_t *hashbin);
+queue_t *hashbin_get_first(hashbin_t *hashbin);
+queue_t *hashbin_get_next(hashbin_t *hashbin);
+
+void enqueue_last(queue_t **queue, queue_t* element);
+void enqueue_first(queue_t **queue, queue_t* element);
+queue_t *dequeue_first(queue_t **queue);
 
-/*
- * Function hashbin_get_size (hashbin)
- *
- *    Returns the number of elements in the hashbin
- *
- */
-extern __inline__ int  hashbin_get_size( hashbin_t* hashbin) 
-{
-	return hashbin->hb_size;
-}
+#define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/irttp.h linux/include/net/irda/irttp.h
--- linux-2.2.15-pre2/include/net/irda/irttp.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/irttp.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Mon May 10 19:14:51 1999
+ * Modified at:   Sun Dec 12 13:09:07 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 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 
@@ -41,26 +42,29 @@
 #define TTP_PARAMETERS         0x80
 #define TTP_MORE               0x80
 
-#define DEFAULT_INITIAL_CREDIT 22
+#define DEFAULT_INITIAL_CREDIT 14
 
-#define LOW_THRESHOLD   4
-#define HIGH_THRESHOLD  8
-#define TTP_MAX_QUEUE  22
+#define TTP_LOW_THRESHOLD       4
+#define TTP_HIGH_THRESHOLD     10
+#define TTP_MAX_QUEUE          14
 
 /* Some priorities for disconnect requests */
 #define P_NORMAL    0
 #define P_HIGH      1
 
-#define SAR_DISABLE 0
-#define SAR_UNBOUND 0xffffffff
+#define TTP_SAR_DISABLE 0
+#define TTP_SAR_UNBOUND 0xffffffff
+
+/* Parameters */
+#define TTP_MAX_SDU_SIZE 0x01
 
 /*
  *  This structure contains all data assosiated with one instance of a TTP 
  *  connection.
  */
 struct tsap_cb {
-	QUEUE queue;          /* For linking it into the hashbin */
-	int  magic;           /* Just in case */
+	queue_t q;            /* Must be first */
+	magic_t magic;        /* Just in case */
 
 	__u8 stsap_sel;       /* Source TSAP */
 	__u8 dtsap_sel;       /* Destination TSAP */
@@ -82,9 +86,9 @@
 	int rx_queue_lock;
 	spinlock_t lock;
 
-	struct notify_t notify;       /* Callbacks to client layer */
+	notify_t notify;       /* Callbacks to client layer */
 
-	struct irda_statistics stats;
+	struct net_device_stats stats;
 	struct timer_list todo_timer; 
 	
 	__u32 max_seg_size;     /* Max data that fit into an IrLAP frame */
@@ -103,16 +107,14 @@
 };
 
 struct irttp_cb {
-	int magic;
-	
+	magic_t    magic;	
 	hashbin_t *tsaps;
 };
 
 int  irttp_init(void);
 void irttp_cleanup(void);
 
-struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, 
-				struct notify_t *notify);
+struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify);
 int irttp_close_tsap(struct tsap_cb *self);
 
 int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb);
@@ -122,12 +124,12 @@
 			  __u32 saddr, __u32 daddr,
 			  struct qos_info *qos, __u32 max_sdu_size, 
 			  struct sk_buff *userdata);
-void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, 
+int 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);
-void irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *skb,
-			      int priority);
+int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *skb,
+			     int priority);
 void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow);
+struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
 
 static __inline __u32 irttp_get_saddr(struct tsap_cb *self)
 {
@@ -137,6 +139,11 @@
 static __inline __u32 irttp_get_daddr(struct tsap_cb *self)
 {
 	return irlmp_get_daddr(self->lsap);
+}
+
+static __inline __u32 irttp_get_max_seg_size(struct tsap_cb *self)
+{
+	return self->max_seg_size;
 }
 
 extern struct irttp_cb *irttp;
diff -urN linux-2.2.15-pre2/include/net/irda/irtty.h linux/include/net/irda/irtty.h
--- linux-2.2.15-pre2/include/net/irda/irtty.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/irtty.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Mon May 10 13:22:23 1999
+ * Modified at:   Tue Jan 11 12:32:03 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  *  
- *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 1999-2000 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,30 +28,48 @@
 #include <linux/if.h>
 #include <linux/skbuff.h>
 #include <linux/termios.h>
+#include <linux/netdevice.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irqueue.h>
 #include <net/irda/irda_device.h>
 
+/* Used by ioctl */
+struct irtty_info {
+	char name[6];
+};
+
 #define IRTTY_IOC_MAGIC 'e'
 #define IRTTY_IOCTDONGLE  _IO(IRTTY_IOC_MAGIC, 1)
-#define IRTTY_IOC_MAXNR   1
-
-#ifndef N_IRDA
-#define N_IRDA         11   /* This one should go in </asm/termio.h> */
-#endif
+#define IRTTY_IOCGET     _IOR(IRTTY_IOC_MAGIC, 2, struct irtty_info)
+#define IRTTY_IOC_MAXNR   2
 
 struct irtty_cb {
-	QUEUE q; /* Must be first */
+	queue_t q;     /* Must be first */
+	magic_t magic;
+
+	struct device *netdev; /* Yes! we are some kind of netdevice */
+	struct irda_task *task;
+	struct net_device_stats stats;
+
+	struct tty_struct  *tty;
+	struct irlap_cb    *irlap; /* The link layer we are binded to */
+
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
+
+	struct qos_info qos;       /* QoS capabilities for this device */
+	dongle_t *dongle;          /* Dongle driver */
+
+	__u32 new_speed;
+ 	__u32 flags;               /* Interface flags */
 
-	int	magic;
-	
-	struct  tty_struct  *tty;  /* Ptr to TTY structure */
-	struct  irda_device idev;
+	INFRARED_MODE mode;
 };
  
-int irtty_register_dongle(struct dongle *dongle);
-void irtty_unregister_dongle(struct dongle *dongle);
+int irtty_register_dongle(struct dongle_reg *dongle);
+void irtty_unregister_dongle(struct dongle_reg *dongle);
 
 #endif
 
diff -urN linux-2.2.15-pre2/include/net/irda/irvtd.h linux/include/net/irda/irvtd.h
--- linux-2.2.15-pre2/include/net/irda/irvtd.h	Mon Jun  7 16:19:59 1999
+++ linux/include/net/irda/irvtd.h	Wed Dec 31 16:00:00 1969
@@ -1,95 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irvtd.h
- * Version:       0.1
- * Sources:       irlpt.h
- * 
- *     Copyright (c) 1998, Takahide Higuchi <thiguchi@pluto.dti.ne.jp>,
- *     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, Takahide Higuchi, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRVTD_H
-#define IRVTD_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <linux/tqueue.h>
-#include <linux/serial.h>
-
-#include <net/irda/irmod.h>
-#include <net/irda/qos.h>
-#include <net/irda/ircomm_common.h>
-
-
-#define IRVTD_MAGIC 0xff545943  /* random */
-#define COMM_MAX_TTY 1
-#define IRVTD_RX_QUEUE_HIGH 10
-#define IRVTD_RX_QUEUE_LOW  2
-
-#define IRCOMM_MAJOR  60;  /* Zero means automatic allocation
-                              60,61,62,and 63 is reserved for experiment */
-#define IRVTD_MINOR 64
-
-
-
-struct irvtd_cb {
-
-        int magic;          /* magic used to detect corruption of the struct */
-
-	/* if daddr is NULL, remote device have not been discovered yet */
-
-	int tx_disable;
-	int rx_disable;
-	struct sk_buff *txbuff;     
-	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
-	 */
-
-	int flags;
-	struct tty_struct *tty;
-
-	int line;
-	int count;                /* open count */
-	int blocked_open;
-	struct wait_queue       *open_wait;
-	struct wait_queue       *close_wait;
-	struct wait_queue       *delta_msr_wait;
-	struct wait_queue       *tx_wait;
-
-	struct timer_list       tx_timer;
-	struct timer_list       rx_timer;
-
-	long pgrp;
-	long session;  
-	unsigned short  closing_wait;     /* time to wait before closing */
-	unsigned short  close_delay;
-	
-	int custom_divisor;
-	int mcr;
-	int msr;
-	int cts_stoptx;
-	int ttp_stoptx;
-	int ttp_stoprx;
-	int disconnect_pend;
-	struct serial_icounter_struct icount;
-	int read_status_mask;
-	int ignore_status_mask;
-};
-
-
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/nsc-ircc.h linux/include/net/irda/nsc-ircc.h
--- linux-2.2.15-pre2/include/net/irda/nsc-ircc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/nsc-ircc.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,265 @@
+/*********************************************************************
+ *                
+ * Filename:      nsc-ircc.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Fri Nov 13 14:37:40 1998
+ * Modified at:   Thu Jan 13 18:27:38 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1998-2000 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
+ *      
+ *     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.
+ *     
+ ********************************************************************/
+
+#ifndef NSC_IRCC_H
+#define NSC_IRCC_H
+
+#include <linux/time.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+
+/* DMA modes needed */
+#define DMA_TX_MODE     0x08    /* Mem to I/O, ++, demand. */
+#define DMA_RX_MODE     0x04    /* I/O to mem, ++, demand. */
+
+/* Config registers for the '108 */
+#define CFG_BAIC 0x00
+#define CFG_CSRT 0x01
+#define CFG_MCTL 0x02
+
+/* Config registers for the '338 */
+#define CFG_FER  0x00
+#define CFG_FAR  0x01
+#define CFG_PTR  0x02
+#define CFG_PNP0 0x1b
+#define CFG_PNP1 0x1c
+#define CFG_PNP3 0x4f
+
+/* Flags for configuration register CRF0 */
+#define APEDCRC		0x02
+#define ENBNKSEL	0x01
+
+/* Set 0 */
+#define TXD             0x00 /* Transmit data port */
+#define RXD             0x00 /* Receive data port */
+
+/* Register 1 */
+#define IER		0x01 /* Interrupt Enable Register*/
+#define IER_RXHDL_IE    0x01 /* Receiver high data level interrupt */
+#define IER_TXLDL_IE    0x02 /* Transeiver low data level interrupt */
+#define IER_LS_IE	0x04//* Link Status Interrupt */
+#define IER_ETXURI      0x04 /* Tx underrun */
+#define IER_DMA_IE	0x10 /* DMA finished interrupt */
+#define IER_TXEMP_IE    0x20
+#define IER_SFIF_IE     0x40 /* Frame status FIFO intr */
+#define IER_TMR_IE      0x80 /* Timer event */
+
+#define FCR		0x02 /* (write only) */
+#define FCR_FIFO_EN     0x01 /* Enable FIFO's */
+#define FCR_RXSR        0x02 /* Rx FIFO soft reset */
+#define FCR_TXSR        0x04 /* Tx FIFO soft reset */
+#define FCR_RXTH	0x40 /* Rx FIFO threshold (set to 16) */
+#define FCR_TXTH	0x20 /* Tx FIFO threshold (set to 17) */
+
+#define EIR		0x02 /* (read only) */
+#define EIR_RXHDL_EV	0x01
+#define EIR_TXLDL_EV    0x02
+#define EIR_LS_EV	0x04
+#define EIR_DMA_EV	0x10
+#define EIR_TXEMP_EV	0x20
+#define EIR_SFIF_EV     0x40
+#define EIR_TMR_EV      0x80
+
+#define LCR             0x03 /* Link control register */
+#define LCR_WLS_8       0x03 /* 8 bits */
+
+#define BSR 	        0x03 /* Bank select register */
+#define BSR_BKSE        0x80
+#define BANK0 	        LCR_WLS_8 /* Must make sure that we set 8N1 */
+#define BANK1	        0x80
+#define BANK2	        0xe0
+#define BANK3	        0xe4
+#define BANK4	        0xe8
+#define BANK5	        0xec
+#define BANK6	        0xf0
+#define BANK7     	0xf4
+
+#define MCR		0x04 /* Mode Control Register */
+#define MCR_MODE_MASK	~(0xd0)
+#define MCR_UART        0x00
+#define MCR_RESERVED  	0x20	
+#define MCR_SHARP_IR    0x40
+#define MCR_SIR         0x60
+#define MCR_MIR  	0x80
+#define MCR_FIR		0xa0
+#define MCR_CEIR        0xb0
+#define MCR_IR_PLS      0x10
+#define MCR_DMA_EN	0x04
+#define MCR_EN_IRQ	0x08
+#define MCR_TX_DFR	0x08
+
+#define LSR             0x05 /* Link status register */
+#define LSR_RXDA        0x01 /* Receiver data available */
+#define LSR_TXRDY       0x20 /* Transmitter ready */
+#define LSR_TXEMP       0x40 /* Transmitter empty */
+
+#define ASCR            0x07 /* Auxillary Status and Control Register */
+#define ASCR_RXF_TOUT   0x01 /* Rx FIFO timeout */
+#define ASCR_FEND_INF   0x02 /* Frame end bytes in rx FIFO */
+#define ASCR_S_EOT      0x04 /* Set end of transmission */
+#define ASCT_RXBSY      0x20 /* Rx busy */
+#define ASCR_TXUR       0x40 /* Transeiver underrun */
+#define ASCR_CTE        0x80 /* Clear timer event */
+
+/* Bank 2 */
+#define BGDL            0x00 /* Baud Generator Divisor Port (Low Byte) */
+#define BGDH            0x01 /* Baud Generator Divisor Port (High Byte) */
+
+#define ECR1		0x02 /* Extended Control Register 1 */
+#define ECR1_EXT_SL	0x01 /* Extended Mode Select */
+#define ECR1_DMANF	0x02 /* DMA Fairness */
+#define ECR1_DMATH      0x04 /* DMA Threshold */
+#define ECR1_DMASWP	0x08 /* DMA Swap */
+
+#define EXCR2		0x04
+#define EXCR2_TFSIZ	0x01 /* Rx FIFO size = 32 */
+#define EXCR2_RFSIZ	0x04 /* Tx FIFO size = 32 */
+
+#define TXFLV           0x06 /* Tx FIFO level */
+#define RXFLV           0x07 /* Rx FIFO level */
+
+/* Bank 3 */
+#define MID		0x00
+
+/* Bank 4 */
+#define TMRL            0x00 /* Timer low byte */
+#define TMRH            0x01 /* Timer high byte */
+#define IRCR1           0x02 /* Infrared control register 1 */
+#define IRCR1_TMR_EN    0x01 /* Timer enable */
+
+#define TFRLL		0x04
+#define TFRLH		0x05
+#define RFRLL		0x06
+#define RFRLH		0x07
+
+/* Bank 5 */
+#define IRCR2           0x04 /* Infrared control register 2 */
+#define IRCR2_MDRS      0x04 /* MIR data rate select */
+#define IRCR2_FEND_MD   0x20 /* */
+
+#define FRM_ST          0x05 /* Frame status FIFO */
+#define FRM_ST_VLD      0x80 /* Frame status FIFO data valid */
+#define FRM_ST_ERR_MSK  0x5f
+#define FRM_ST_LOST_FR  0x40 /* Frame lost */
+#define FRM_ST_MAX_LEN  0x10 /* Max frame len exceeded */
+#define FRM_ST_PHY_ERR  0x08 /* Physical layer error */
+#define FRM_ST_BAD_CRC  0x04 
+#define FRM_ST_OVR1     0x02 /* Rx FIFO overrun */
+#define FRM_ST_OVR2     0x01 /* Frame status FIFO overrun */
+
+#define RFLFL           0x06
+#define RFLFH           0x07
+
+/* Bank 6 */
+#define IR_CFG2		0x00
+#define IR_CFG2_DIS_CRC	0x02
+
+/* Bank 7 */
+#define IRM_CR		0x07 /* Infrared module control register */
+#define IRM_CR_IRX_MSL	0x40
+#define IRM_CR_AF_MNT   0x80 /* Automatic format */
+
+/* NSC chip information */
+struct nsc_chip {
+	char *name;          /* Name of chipset */
+	int cfg[3];          /* Config registers */
+	u_int8_t cid_index;  /* Chip identification index reg */
+	u_int8_t cid_value;  /* Chip identification expected value */
+	u_int8_t cid_mask;   /* Chip identification revision mask */
+
+	/* Functions for probing and initializing the specific chip */
+	int (*probe)(struct nsc_chip *chip, chipio_t *info);
+	int (*init)(struct nsc_chip *chip, chipio_t *info);
+};
+typedef struct nsc_chip nsc_chip_t;
+
+/* For storing entries in the status FIFO */
+struct st_fifo_entry {
+	int status;
+	int len;
+};
+
+#define MAX_WINDOW 7
+
+struct st_fifo {
+	struct st_fifo_entry entries[MAX_WINDOW];
+	int pending_bytes;
+	int head;
+	int tail;
+	int len;
+};
+
+struct frame_cb {
+	void *start; /* Start of frame in DMA mem */
+	int len;     /* Lenght of frame in DMA mem */
+};
+
+struct tx_fifo {
+	struct frame_cb queue[MAX_WINDOW]; /* Info about frames in queue */
+	int             ptr;               /* Currently being sent */
+	int             len;               /* Lenght of queue */
+	int             free;              /* Next free slot */
+	void           *tail;              /* Next free start in DMA mem */
+};
+
+/* Private data for each instance */
+struct nsc_ircc_cb {
+	struct st_fifo st_fifo;    /* Info about received frames */
+	struct tx_fifo tx_fifo;    /* Info about frames to be transmitted */
+
+	int tx_buff_offsets[10];   /* Offsets between frames in tx_buff */
+	int tx_len;                /* Number of frames in tx_buff */
+
+	struct device *netdev;     /* Yes! we are some kind of netdevice */
+	struct net_device_stats stats;
+	
+	struct irlap_cb *irlap;    /* The link layer we are binded to */
+	struct qos_info qos;       /* QoS capabilities for this device */
+	
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
+
+	__u8 ier;                  /* Interrupt enable register */
+
+	struct timeval stamp;
+	struct timeval now;
+
+	spinlock_t lock;           /* For serializing operations */
+	
+	__u32 flags;               /* Interface flags */
+	__u32 new_speed;
+	int index;                 /* Instance index */
+};
+
+static inline void switch_bank(int iobase, int bank)
+{
+		outb(bank, iobase+BSR);
+}
+
+#endif /* NSC_IRCC_H */
diff -urN linux-2.2.15-pre2/include/net/irda/nsc_fir.h linux/include/net/irda/nsc_fir.h
--- linux-2.2.15-pre2/include/net/irda/nsc_fir.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/nsc_fir.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,238 @@
+/*********************************************************************
+ *                
+ * Filename:      nsc_fir.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Fri Nov 13 14:37:40 1998
+ * Modified at:   Tue Jan 11 10:19:50 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1998-2000 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
+ *      
+ *     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.
+ *     
+ ********************************************************************/
+
+#ifndef NSC_IRCC_H
+#define NSC_IRCC_H
+
+#include <linux/time.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+
+#define PC87108         0x10
+#define PC97338         0xb0
+
+/* DMA modes needed */
+#define DMA_TX_MODE     0x08    /* Mem to I/O, ++, demand. */
+#define DMA_RX_MODE     0x04    /* I/O to mem, ++, demand. */
+
+/* Flags for configuration register CRF0 */
+#define APEDCRC		0x02
+#define ENBNKSEL	0x01
+
+/* Set 0 */
+#define TXD             0x00 /* Transmit data port */
+#define RXD             0x00 /* Receive data port */
+
+/* Register 1 */
+#define IER		0x01 /* Interrupt Enable Register*/
+#define IER_RXHDL_IE    0x01 /* Receiver high data level interrupt */
+#define IER_TXLDL_IE    0x02 /* Transeiver low data level interrupt */
+#define IER_LS_IE	0x04//* Link Status Interrupt */
+#define IER_ETXURI      0x04 /* Tx underrun */
+#define IER_DMA_IE	0x10 /* DMA finished interrupt */
+#define IER_TXEMP_IE    0x20
+#define IER_SFIF_IE     0x40 /* Frame status FIFO intr */
+#define IER_TMR_IE      0x80 /* Timer event */
+
+#define FCR		0x02 /* (write only) */
+#define FCR_FIFO_EN     0x01 /* Enable FIFO's */
+#define FCR_RXSR        0x02 /* Rx FIFO soft reset */
+#define FCR_TXSR        0x04 /* Tx FIFO soft reset */
+#define FCR_RXTH	0x40 /* Rx FIFO threshold (set to 16) */
+#define FCR_TXTH	0x20 /* Tx FIFO threshold (set to 17) */
+
+#define EIR		0x02 /* (read only) */
+#define EIR_RXHDL_EV	0x01
+#define EIR_TXLDL_EV    0x02
+#define EIR_LS_EV	0x04
+#define EIR_DMA_EV	0x10
+#define EIR_TXEMP_EV	0x20
+#define EIR_SFIF_EV     0x40
+#define EIR_TMR_EV      0x80
+
+#define LCR             0x03 /* Link control register */
+#define LCR_WLS_8       0x03 /* 8 bits */
+
+#define BSR 	        0x03 /* Bank select register */
+#define BSR_BKSE        0x80
+#define BANK0 	        LCR_WLS_8 /* Must make sure that we set 8N1 */
+#define BANK1	        0x80
+#define BANK2	        0xe0
+#define BANK3	        0xe4
+#define BANK4	        0xe8
+#define BANK5	        0xec
+#define BANK6	        0xf0
+#define BANK7     	0xf4
+
+#define MCR		0x04 /* Mode Control Register */
+#define MCR_MODE_MASK	~(0xd0)
+#define MCR_UART        0x00
+#define MCR_RESERVED  	0x20	
+#define MCR_SHARP_IR    0x40
+#define MCR_SIR         0x60
+#define MCR_MIR  	0x80
+#define MCR_FIR		0xa0
+#define MCR_CEIR        0xb0
+#define MCR_IR_PLS      0x10
+#define MCR_DMA_EN	0x04
+#define MCR_EN_IRQ	0x08
+#define MCR_TX_DFR	0x08
+
+#define LSR             0x05 /* Link status register */
+#define LSR_RXDA        0x01 /* Receiver data available */
+#define LSR_TXRDY       0x20 /* Transmitter ready */
+#define LSR_TXEMP       0x40 /* Transmitter empty */
+
+#define ASCR            0x07 /* Auxillary Status and Control Register */
+#define ASCR_RXF_TOUT   0x01 /* Rx FIFO timeout */
+#define ASCR_FEND_INF   0x02 /* Frame end bytes in rx FIFO */
+#define ASCR_S_EOT      0x04 /* Set end of transmission */
+#define ASCT_RXBSY      0x20 /* Rx busy */
+#define ASCR_TXUR       0x40 /* Transeiver underrun */
+#define ASCR_CTE        0x80 /* Clear timer event */
+
+/* Bank 2 */
+#define BGDL            0x00 /* Baud Generator Divisor Port (Low Byte) */
+#define BGDH            0x01 /* Baud Generator Divisor Port (High Byte) */
+
+#define ECR1		0x02 /* Extended Control Register 1 */
+#define ECR1_EXT_SL	0x01 /* Extended Mode Select */
+#define ECR1_DMANF	0x02 /* DMA Fairness */
+#define ECR1_DMATH      0x04 /* DMA Threshold */
+#define ECR1_DMASWP	0x08 /* DMA Swap */
+
+#define EXCR2		0x04
+#define EXCR2_TFSIZ	0x01 /* Rx FIFO size = 32 */
+#define EXCR2_RFSIZ	0x04 /* Tx FIFO size = 32 */
+
+#define TXFLV           0x06 /* Tx FIFO level */
+#define RXFLV           0x07 /* Rx FIFO level */
+
+/* Bank 3 */
+#define MID		0x00
+
+/* Bank 4 */
+#define TMRL            0x00 /* Timer low byte */
+#define TMRH            0x01 /* Timer high byte */
+#define IRCR1           0x02 /* Infrared control register 1 */
+#define IRCR1_TMR_EN    0x01 /* Timer enable */
+
+#define TFRLL		0x04
+#define TFRLH		0x05
+#define RFRLL		0x06
+#define RFRLH		0x07
+
+/* Bank 5 */
+#define IRCR2           0x04 /* Infrared control register 2 */
+#define IRCR2_MDRS      0x04 /* MIR data rate select */
+#define IRCR2_FEND_MD   0x20 /* */
+
+#define FRM_ST          0x05 /* Frame status FIFO */
+#define FRM_ST_VLD      0x80 /* Frame status FIFO data valid */
+#define FRM_ST_ERR_MSK  0x5f
+#define FRM_ST_LOST_FR  0x40 /* Frame lost */
+#define FRM_ST_MAX_LEN  0x10 /* Max frame len exceeded */
+#define FRM_ST_PHY_ERR  0x08 /* Physical layer error */
+#define FRM_ST_BAD_CRC  0x04 
+#define FRM_ST_OVR1     0x02 /* Rx FIFO overrun */
+#define FRM_ST_OVR2     0x01 /* Frame status FIFO overrun */
+
+#define RFLFL           0x06
+#define RFLFH           0x07
+
+/* Bank 6 */
+#define IR_CFG2		0x00
+#define IR_CFG2_DIS_CRC	0x02
+
+/* Bank 7 */
+#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;
+};
+
+struct frame_cb {
+	void *start; /* Start of frame in DMA mem */
+	int len;     /* Lenght of frame in DMA mem */
+};
+
+#define MAX_WINDOW 7
+
+struct tx_fifo {
+	struct frame_cb queue[MAX_WINDOW]; /* Info about frames in queue */
+	int             ptr;               /* Currently being sent */
+	int             len;               /* Lenght of queue */
+	int             free;              /* Next free slot */
+	void           *tail;              /* Next free start in DMA mem */
+};
+
+/* Private data for each instance */
+struct nsc_ircc_cb {
+	struct st_fifo st_fifo;    /* Info about received frames */
+	struct tx_fifo tx_fifo;    /* Info about frames to be transmitted */
+
+	int tx_buff_offsets[10];   /* Offsets between frames in tx_buff */
+	int tx_len;                /* Number of frames in tx_buff */
+
+	struct device *netdev;     /* Yes! we are some kind of netdevice */
+	struct net_device_stats stats;
+	
+	struct irlap_cb *irlap;    /* The link layer we are binded to */
+	
+	struct chipio_t io;        /* IrDA controller information */
+	struct iobuff_t tx_buff;   /* Transmit buffer */
+	struct iobuff_t rx_buff;   /* Receive buffer */
+	struct qos_info qos;       /* QoS capabilities for this device */
+
+	struct timeval  stamp;
+	struct timeval  now;
+
+	spinlock_t lock;           /* For serializing operations */
+	
+	__u32 flags;               /* Interface flags */
+	__u32 new_speed;
+	int suspend;
+};
+
+static inline void switch_bank(int iobase, int bank)
+{
+		outb(bank, iobase+BSR);
+}
+
+#endif /* NSC_IRCC_H */
diff -urN linux-2.2.15-pre2/include/net/irda/parameters.h linux/include/net/irda/parameters.h
--- linux-2.2.15-pre2/include/net/irda/parameters.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/parameters.h	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,105 @@
+/*********************************************************************
+ *                
+ * Filename:      parameters.h
+ * Version:       1.0
+ * Description:   A more general way to handle (pi,pl,pv) parameters
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Mon Jun  7 08:47:28 1999
+ * Modified at:   Mon Dec 13 11:51:59 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
+ *     
+ ********************************************************************/
+
+#ifndef IRDA_PARAMS_H
+#define IRDA_PARAMS_H
+
+/*
+ *  The currently supported types. Beware not to change the sequence since
+ *  it a good reason why the sized integers has a value equal to their size
+ */
+typedef enum {
+	PV_INTEGER,      /* Integer of any (pl) length */
+	PV_INT_8_BITS,   /* Integer of 8 bits in length */
+	PV_INT_16_BITS,  /* Integer of 16 bits in length */
+	PV_STRING,       /* \0 terminated string */
+	PV_INT_32_BITS,  /* Integer of 32 bits in length */
+	PV_OCT_SEQ,      /* Octet sequence */
+	PV_NO_VALUE      /* Does not contain any value (pl=0) */
+} PV_TYPE;
+
+/* Bit 7 of type field */
+#define PV_BIG_ENDIAN    0x80 
+#define PV_LITTLE_ENDIAN 0x00
+#define PV_MASK          0x7f   /* To mask away endian bit */
+
+#define PV_PUT 0
+#define PV_GET 1
+
+typedef union {
+	char   *c;
+	__u8    b;
+	__u16   s;
+	__u32   i;
+	__u8  *bp;
+	__u16 *sp;
+	__u32 *ip;
+} pv_t;
+
+typedef struct {
+	__u8 pi;
+	__u8 pl;
+	pv_t pv;
+} param_t;
+
+typedef int (*PI_HANDLER)(void *self, param_t *param, int get);
+typedef int (*PV_HANDLER)(void *self, __u8 *buf, int len, __u8 pi,
+			  PV_TYPE type, PI_HANDLER func);
+
+typedef struct {
+	PI_HANDLER func;  /* Handler for this parameter identifier */
+	PV_TYPE    type;  /* Data type for this parameter */
+} pi_minor_info_t;
+
+typedef struct {
+	pi_minor_info_t *pi_minor_call_table;
+	int len;
+} pi_major_info_t;
+
+typedef struct {
+	pi_major_info_t *tables;
+	int              len;
+	__u8             pi_mask;
+	int              pi_major_offset;
+} pi_param_info_t;
+
+int irda_param_pack(__u8 *buf, char *fmt, ...);
+int irda_param_unpack(__u8 *buf, char *fmt, ...);
+
+int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, 
+		      pi_param_info_t *info);
+int irda_param_extract(void *self, __u8 *buf, int len, pi_param_info_t *info);
+int irda_param_extract_all(void *self, __u8 *buf, int len, 
+			   pi_param_info_t *info);
+
+#define irda_param_insert_byte(buf,pi,pv) irda_param_pack(buf,"bbb",pi,1,pv)
+
+#endif /* IRDA_PARAMS_H */
+
diff -urN linux-2.2.15-pre2/include/net/irda/pc87108.h linux/include/net/irda/pc87108.h
--- linux-2.2.15-pre2/include/net/irda/pc87108.h	Sun Mar  7 15:26:44 1999
+++ linux/include/net/irda/pc87108.h	Wed Dec 31 16:00:00 1969
@@ -1,194 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      pc87108.h
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Fri Nov 13 14:37:40 1998
- * Modified at:   Mon Jan 25 23:10:25 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998 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
- *      
- *     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.
- *     
- ********************************************************************/
-
-#ifndef PC87108_H
-#define PC87108_H
-
-#include <asm/io.h>
-
-/* Flags for configuration register CRF0 */
-#define APEDCRC		0x02
-#define ENBNKSEL	0x01
-
-/* Set 0 */
-#define TXD             0x00 /* Transmit data port */
-#define RXD             0x00 /* Receive data port */
-
-/* Register 1 */
-#define IER		0x01 /* Interrupt Enable Register*/
-#define IER_RXHDL_IE    0x01 /* Receiver high data level interrupt */
-#define IER_TXLDL_IE    0x02 /* Transeiver low data level interrupt */
-#define IER_LS_IE	0x04//* Link Status Interrupt */
-#define IER_ETXURI      0x04 /* Tx underrun */
-#define IER_DMA_IE	0x10 /* DMA finished interrupt */
-#define IER_TXEMP_IE    0x20
-#define IER_SFIF_IE     0x40 /* Frame status FIFO intr */
-#define IER_TMR_IE      0x80 /* Timer event */
-
-#define FCR		0x02 /* (write only) */
-#define FCR_FIFO_EN     0x01 /* Enable FIFO's */
-#define FCR_RXSR        0x02 /* Rx FIFO soft reset */
-#define FCR_TXSR        0x04 /* Tx FIFO soft reset */
-#define FCR_RXTH	0x80 /* Rx FIFO threshold (set to 16) */
-#define FCR_TXTH	0x20 /* Tx FIFO threshold (set to 17) */
-
-#define EIR		0x02 /* (read only) */
-#define EIR_RXHDL_EV	0x01
-#define EIR_TXLDL_EV    0x02
-#define EIR_LS_EV	0x04
-#define EIR_DMA_EV	0x10
-#define EIR_TXEMP_EV	0x20
-#define EIR_SFIF_EV     0x40
-#define EIR_TMR_EV      0x80
-
-#define LCR             0x03 /* Link control register */
-#define LCR_WLS_8       0x03 /* 8 bits */
-
-#define BSR 	        0x03 /* Bank select register */
-#define BSR_BKSE        0x80
-#define BANK0 	        LCR_WLS_8 /* Must make sure that we set 8N1 */
-#define BANK1	        0x80
-#define BANK2	        0xe0
-#define BANK3	        0xe4
-#define BANK4	        0xe8
-#define BANK5	        0xec
-#define BANK6	        0xf0
-#define BANK7     	0xf4
-
-#define MCR		0x04 /* Mode Control Register */
-#define MCR_MODE_MASK	~(0xd0)
-#define MCR_UART        0x00
-#define MCR_RESERVED  	0x20	
-#define MCR_SHARP_IR    0x40
-#define MCR_SIR         0x60
-#define MCR_MIR  	0x80
-#define MCR_FIR		0xa0
-#define MCR_CEIR        0xb0
-#define MCR_DMA_EN	0x04
-#define MCR_EN_IRQ	0x08
-#define MCR_TX_DFR	0x08
-
-#define LSR             0x05 /* Link status register */
-#define LSR_RXDA        0x01 /* Receiver data available */
-#define LSR_TXRDY       0x20 /* Transmitter ready */
-#define LSR_TXEMP       0x40 /* Transmitter empty */
-
-#define ASCR            0x07 /* Auxillary Status and Control Register */
-#define ASCR_RXF_TOUT   0x01 /* Rx FIFO timeout */
-#define ASCR_FEND_INF   0x02 /* Frame end bytes in rx FIFO */
-#define ASCR_S_EOT      0x04 /* Set end of transmission */
-#define ASCT_RXBSY      0x20 /* Rx busy */
-#define ASCR_TXUR       0x40 /* Transeiver underrun */
-#define ASCR_CTE        0x80 /* Clear timer event */
-
-/* Bank 2 */
-#define BGDL            0x00 /* Baud Generator Divisor Port (Low Byte) */
-#define BGDH            0x01 /* Baud Generator Divisor Port (High Byte) */
-
-#define ECR1		0x02 /* Extended Control Register 1 */
-#define ECR1_EXT_SL	0x01 /* Extended Mode Select */
-#define ECR1_DMANF	0x02 /* DMA Fairness */
-#define ECR1_DMATH      0x04
-#define ECR1_DMASWP	0x08 /* DMA Swap */
-
-#define EXCR2		0x04
-#define EXCR2_TFSIZ	0x01 /* Rx FIFO size = 32 */
-#define EXCR2_RFSIZ	0x04 /* Tx FIFO size = 32 */
-
-#define TXFLV           0x06 /* Tx FIFO level */
-#define RXFLV           0x07 /* Rx FIFO level */
-
-/* Bank 3 */
-#define MID		0x00
-
-/* Bank 4 */
-#define TMRL            0x00 /* Timer low byte */
-#define TMRH            0x01 /* Timer high byte */
-#define IRCR1           0x02 /* Infrared control register 1 */
-#define IRCR1_TMR_EN    0x01 /* Timer enable */
-
-#define TFRLL		0x04
-#define TFRLH		0x05
-#define RFRLL		0x06
-#define RFRLH		0x07
-
-/* Bank 5 */
-#define IRCR2           0x04 /* Infrared control register 2 */
-#define IRCR2_MDRS      0x04 /* MIR data rate select */
-#define IRCR2_FEND_MD   0x20 /* */
-
-#define FRM_ST          0x05 /* Frame status FIFO */
-#define FRM_ST_VLD      0x80 /* Frame status FIFO data valid */
-#define FRM_ST_ERR_MSK  0x5f
-#define FRM_ST_LOST_FR  0x40 /* Frame lost */
-#define FRM_ST_MAX_LEN  0x10 /* Max frame len exceeded */
-#define FRM_ST_PHY_ERR  0x08 /* Physical layer error */
-#define FRM_ST_BAD_CRC  0x04 
-#define FRM_ST_OVR1     0x02 /* Receive overrun */
-#define FRM_ST_OVR2     0x01 /* Frame status FIFO overrun */
-
-#define RFLFL           0x06
-#define RFLFH           0x07
-
-/* Bank 6 */
-#define IR_CFG2		0x00
-#define IR_CFG2_DIS_CRC	0x02
-
-/* Bank 7 */
-#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 pc87108 {
-	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 bank)
-{
-		outb( bank, iobase+BSR);
-}
-
-#endif
diff -urN linux-2.2.15-pre2/include/net/irda/qos.h linux/include/net/irda/qos.h
--- linux-2.2.15-pre2/include/net/irda/qos.h	Tue May 11 10:36:39 1999
+++ linux/include/net/irda/qos.h	Mon Dec  3 21:57:53 2001
@@ -1,33 +1,41 @@
 /*********************************************************************
  *                
  * Filename:      qos.h
- * Version:       0.1
+ * Version:       1.0
  * Description:   Quality of Service definitions
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Sep 19 23:21:09 1997
- * Modified at:   Wed Dec  9 10:32:47 1998
+ * Modified at:   Thu Dec  2 13:51:54 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     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.
- *
- *     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
+ *     
  ********************************************************************/
 
-#ifndef QOS_H
-#define QOS_H
+#ifndef IRDA_QOS_H
+#define IRDA_QOS_H
 
 #include <linux/config.h>
 #include <linux/skbuff.h>
 
+#include <net/irda/parameters.h>
+
 #define PI_BAUD_RATE     0x01
 #define PI_MAX_TURN_TIME 0x82
 #define PI_DATA_SIZE     0x83
@@ -41,26 +49,27 @@
 #define IR_115200_MAX 0x3f
 
 /* Baud rates (first byte) */
-#define IR_2400    0x01
-#define IR_9600    0x02
-#define IR_19200   0x04
-#define IR_38400   0x08
-#define IR_57600   0x10
-#define IR_115200  0x20
-#define IR_576000  0x40
-#define IR_1152000 0x80
+#define IR_2400     0x01
+#define IR_9600     0x02
+#define IR_19200    0x04
+#define IR_38400    0x08
+#define IR_57600    0x10
+#define IR_115200   0x20
+#define IR_576000   0x40
+#define IR_1152000  0x80
 
 /* Baud rates (second byte) */
-#define IR_4000000 0x01
+#define IR_4000000  0x01
+#define IR_16000000 0x02
 
 /* Quality of Service information */
 typedef struct {
-	int value;
+	__u32 value;
 	__u16 bits; /* LSB is first byte, MSB is second byte */
 } qos_value_t;
 
 struct qos_info {
-	int  magic;
+	magic_t magic;
 
 	qos_value_t baud_rate;       /* IR_11520O | ... */
 	qos_value_t max_turn_time;
@@ -77,24 +86,25 @@
 #endif
 };
 
-extern int baud_rates[];
-extern int data_size[];
-extern int min_turn_time[];
-extern int add_bofs[];
-extern int compression[];
-
-void irda_init_max_qos_capabilies( struct qos_info *qos);
-void irda_qos_compute_intersection( struct qos_info *, struct qos_info *);
-int  irda_insert_qos_negotiation_params( struct qos_info *qos, __u8 *fp);
-void irda_qos_negotiate( struct qos_info *qos_rx, struct qos_info *qos_tx,
-			 struct sk_buff *skb);
-
-int msb_index ( __u16 byte);
-int byte_value( __u8 byte, int *array);
-int value_index( int value, int *array);
-int index_value( int index, int *array);
+extern __u32 baud_rates[];
+extern __u32 data_sizes[];
+extern __u32 min_turn_times[];
+extern __u32 add_bofs[];
+extern __u32 compressions[];
+
+void irda_init_max_qos_capabilies(struct qos_info *qos);
+void irda_qos_compute_intersection(struct qos_info *, struct qos_info *);
+
+__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time);
+__u32 irlap_requested_line_capacity(struct qos_info *qos);
+__u32 irlap_min_turn_time_in_bytes(__u32 speed, __u32 min_turn_time);
+
+int msb_index(__u16 byte);
+int value_index(__u32 value, __u32 *array);
+__u32 byte_value(__u8 byte, __u32 *array);
+__u32 index_value(int index, __u32 *array);
 
-void irda_qos_bits_to_value( struct qos_info *qos);
+void irda_qos_bits_to_value(struct qos_info *qos);
 
 #endif
 
diff -urN linux-2.2.15-pre2/include/net/irda/smc-ircc.h linux/include/net/irda/smc-ircc.h
--- linux-2.2.15-pre2/include/net/irda/smc-ircc.h	Mon Jun  7 16:19:59 1999
+++ linux/include/net/irda/smc-ircc.h	Mon Dec  3 21:57:53 2001
@@ -1,138 +1,147 @@
 /*********************************************************************
  *                
- * Filename:      smc.h
- * Version:       
- * Description:   
+ * Filename:      smc-ircc.h
+ * Version:       0.3
+ * Description:   Definitions for the SMC IrCC chipset
  * Status:        Experimental.
  * Author:        Thomas Davis (tadavis@jps.net)
  *
- *     Copyright (c) 1998, 1999 Thomas Davis (tadavis@jps.net>
+ *     Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no>
+ *     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.
+ * 
+ *     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
  *
  ********************************************************************/
 
 #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
+#include <asm/spinlock.h>
 
-/* 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
+#include <net/irda/irport.h>
 
-/* Register block 1 */
+/* DMA modes needed */
+#define DMA_TX_MODE              0x08    /* Mem to I/O, ++, demand. */
+#define DMA_RX_MODE              0x04    /* I/O to mem, ++, demand. */
+
+#define IRCC_MASTER              0x07
+#define IRCC_MASTER_POWERDOWN	 1<<7
+#define IRCC_MASTER_RESET        1<<6
+#define IRCC_MASTER_INT_EN       1<<5
+#define IRCC_MASTER_ERROR_RESET	 1<<4
 
-#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 0 */
+#define IRCC_IIR                 0x01
+#define IRCC_IER                 0x02
+#define IRCC_LSR                 0x03
+#define IRCC_LCR_A               0x04
+#define IRCC_LCR_B               0x05
+#define IRCC_BSR                 0x06
+
+#define IRCC_IIR_ACTIVE_FRAME    1<<7
+#define IRCC_IIR_EOM             1<<6
+#define IRCC_IIR_RAW_MODE        1<<5
+#define IRCC_IIR_FIFO		 1<<4
+
+#define IRCC_IER_ACTIVE_FRAME	 1<<7
+#define IRCC_IER_EOM 		 1<<6
+#define IRCC_IER_RAW_MODE        1<<5
+#define IRCC_IER_FIFO		 1<<4
+
+#define IRCC_LSR_UNDERRUN        1<<7
+#define IRCC_LSR_OVERRUN         1<<6
+#define IRCC_LSR_FRAME_ERROR     1<<5
+#define IRCC_LSR_SIZE_ERROR      1<<4
+#define IRCC_LSR_CRC_ERROR       1<<3
+#define IRCC_LSR_FRAME_ABORT 	 1<<2
+
+#define IRCC_LCR_A_FIFO_RESET    1<<7
+#define IRCC_LCR_A_FAST          1<<6
+#define IRCC_LCR_A_GP_DATA       1<<5
+#define IRCC_LCR_A_RAW_TX        1<<4
+#define IRCC_LCR_A_RAW_RX        1<<3
+#define IRCC_LCR_A_ABORT         1<<2
+#define IRCC_LCR_A_DATA_DONE     1<<1
+
+#define IRCC_LCR_B_SCE_DISABLED  0x00<<6
+#define IRCC_LCR_B_SCE_TRANSMIT  0x01<<6
+#define IRCC_LCR_B_SCE_RECEIVE	 0x02<<6
+#define IRCC_LCR_B_SCE_UNDEFINED 0x03<<6
+#define IRCC_LCR_B_SIP_ENABLE	 1<<5
+#define IRCC_LCR_B_BRICK_WALL    1<<4
+
+#define IRCC_BSR_NOT_EMPTY	 1<<7
+#define IRCC_BSR_FIFO_FULL	 1<<6
+#define IRCC_BSR_TIMEOUT	 1<<5
 
-/* Register block 2 - Consumer IR - not used */
+/* Register block 1 */
+#define IRCC_SCE_CFGA	         0x00
+#define IRCC_SCE_CFGB	         0x01
+#define IRCC_FIFO_THRESHOLD	 0x02
+
+#define IRCC_CFGA_AUX_IR	 0x01<<7
+#define IRCC_CFGA_HALF_DUPLEX	 0x01<<2
+#define IRCC_CFGA_TX_POLARITY	 0x01<<1
+#define IRCC_CFGA_RX_POLARITY	 0x01
+
+#define IRCC_CFGA_COM		 0x00<<3
+#define IRCC_CFGA_IRDA_SIR_A	 0x01<<3
+#define IRCC_CFGA_ASK_SIR	 0x02<<3
+#define IRCC_CFGA_IRDA_SIR_B	 0x03<<3
+#define IRCC_CFGA_IRDA_HDLC 	 0x04<<3
+#define IRCC_CFGA_IRDA_4PPM 	 0x05<<3
+#define IRCC_CFGA_CONSUMER	 0x06<<3
+#define IRCC_CFGA_RAW_IR	 0x07<<3
+#define IRCC_CFGA_OTHER		 0x08<<3
+
+#define IRCC_IR_HDLC             0x04
+#define IRCC_IR_4PPM             0x01
+#define IRCC_IR_CONSUMER         0x02
+
+#define IRCC_CFGB_LOOPBACK       0x01<<5
+#define IRCC_CFGB_LPBCK_TX_CRC	 0x01<<4
+#define IRCC_CFGB_NOWAIT	 0x01<<3
+#define IRCC_CFGB_STRING_MOVE	 0x01<<2
+#define IRCC_CFGB_DMA_BURST 	 0x01<<1
+#define IRCC_CFGB_DMA_ENABLE	 0x01
+
+#define IRCC_CFGB_MUX_COM        0x00<<6
+#define IRCC_CFGB_MUX_IR         0x01<<6
+#define IRCC_CFGB_MUX_AUX        0x02<<6
+#define IRCC_CFGB_MUX_INACTIVE	 0x03<<6
 
 /* 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 */
+#define IRCC_ID_HIGH	         0x00   /* 0x10 */
+#define IRCC_ID_LOW	         0x01   /* 0xB8 */
+#define IRCC_CHIP_ID 	         0x02   /* 0xF1 */
+#define IRCC_VERSION	         0x03   /* 0x01 */
+#define IRCC_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 IRCC_CONTROL             0x00
+#define IRCC_BOF_COUNT_LO        0x01
+#define IRCC_BRICKWALL_CNT_LO    0x02
+#define IRCC_BRICKWALL_TX_CNT_HI 0x03
+#define IRCC_TX_SIZE_LO          0x04
+#define IRCC_RX_SIZE_HI          0x05
+#define IRCC_RX_SIZE_LO          0x06
 
-#define UART_1152     0x01<<7
-#define UART_CRC      0x01<<6
+#define IRCC_1152                0x01<<7
+#define IRCC_CRC                 0x01<<6
 
 /* For storing entries in the status FIFO */
 struct st_fifo_entry {
@@ -149,12 +158,24 @@
 
 /* Private data for each instance */
 struct ircc_cb {
-	struct st_fifo st_fifo;
+	struct device *netdev;     /* Yes! we are some kind of netdevice */
+	struct irlap_cb    *irlap; /* The link layer we are binded to */
+	
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
+
+	struct irport_cb *irport;
+
+	spinlock_t lock;           /* For serializing operations */
+	
+	__u32 new_speed;
+	__u32 flags;               /* Interface flags */
 
-	int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
-	int tx_len;          /* Number of frames in tx_buff */
+	struct st_fifo st_fifo;
 
-	struct irda_device idev;
+	int tx_buff_offsets[10];   /* Offsets between frames in tx_buff */
+	int tx_len;                /* Number of frames in tx_buff */
 };
 
-#endif
+#endif /* SMC_IRCC_H */
diff -urN linux-2.2.15-pre2/include/net/irda/timer.h linux/include/net/irda/timer.h
--- linux-2.2.15-pre2/include/net/irda/timer.h	Thu Apr 15 05:42:42 1999
+++ linux/include/net/irda/timer.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Tue Apr  6 16:17:16 1999
+ * Modified at:   Thu Oct  7 12:25:24 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 
@@ -26,6 +26,8 @@
 #ifndef TIMER_H
 #define TIMER_H
 
+#include <linux/netdevice.h>
+
 #include <asm/param.h>  /* for HZ */
 
 #include <net/irda/irda.h>
@@ -37,28 +39,34 @@
 /* 
  *  Timeout definitions, some defined in IrLAP p. 92
  */
-#define POLL_TIMEOUT        450*HZ/1000    /* Must never exceed 500 ms */
-#define FINAL_TIMEOUT       500*HZ/1000    /* Must never exceed 500 ms */
+#define POLL_TIMEOUT        (450*HZ/1000)    /* Must never exceed 500 ms */
+#define FINAL_TIMEOUT       (500*HZ/1000)    /* Must never exceed 500 ms */
 
 /* 
  *  Normally twice of p-timer. Note 3, IrLAP p. 60 suggests at least twice 
  *  duration of the P-timer.
  */
-#define WD_TIMEOUT          POLL_TIMEOUT*2
-#define MEDIABUSY_TIMEOUT   500*HZ/1000    /* 500 msec */
+#define WD_TIMEOUT          (POLL_TIMEOUT*2)
+#define MEDIABUSY_TIMEOUT   (500*HZ/1000)    /* 500 msec */
 
 /*
  *  Slot timer must never exceed 85 ms, and must always be at least 25 ms, 
- *  suggested to  75-85 msec by IrDA lite
+ *  suggested to  75-85 msec by IrDA lite. This doesn't work with a lot of
+ *  devices, and other stackes uses a lot more, so it's best we do it as well
  */
-#define SLOT_TIMEOUT            80*HZ/1000
-#define QUERY_TIMEOUT           HZ          /* 1 sec */
+#define SLOT_TIMEOUT            (90*HZ/1000)
 
-#define WATCHDOG_TIMEOUT        20*HZ       /* 20 sec */
+/* 
+ *  We set the query timeout to 100 ms and then expect the value to be 
+ *  multiplied with the number of slots to product the actual timeout value
+ */
+#define QUERY_TIMEOUT           (HZ/10)       
 
-typedef void (*TIMER_CALLBACK)(unsigned long);
+#define WATCHDOG_TIMEOUT        (20*HZ)       /* 20 sec */
 
-void irda_start_timer(struct timer_list *ptimer, int timeout, int data,
+typedef void (*TIMER_CALLBACK)(void *);
+
+void irda_start_timer(struct timer_list *ptimer, int timeout, void* data,
 		      TIMER_CALLBACK callback);
 
 inline void irlap_start_slot_timer(struct irlap_cb *self, int timeout);
@@ -67,16 +75,13 @@
 inline void irlap_start_wd_timer(struct irlap_cb *self, int timeout);
 inline void irlap_start_backoff_timer(struct irlap_cb *self, int timeout);
 
-inline void irda_device_start_mbusy_timer(struct irda_device *self);
+void irlap_start_mbusy_timer(struct irlap_cb *);
 
 struct lsap_cb;
 struct lap_cb;
 inline void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout);
 inline void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout);
 inline void irlmp_start_idle_timer(struct lap_cb *, int timeout);
-
-struct irobex_cb;
-inline void irobex_start_watchdog_timer(struct irobex_cb *, int timeout);
 
 #endif
 
diff -urN linux-2.2.15-pre2/include/net/irda/toshoboe.h linux/include/net/irda/toshoboe.h
--- linux-2.2.15-pre2/include/net/irda/toshoboe.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/toshoboe.h	Mon Dec  3 21:57:53 2001
@@ -8,7 +8,7 @@
  * Author:        James McKenzie <james@fishsoup.dhs.org>
  * Created at:    Sat May 8  12:35:27 1999
  * 
- *     Copyright (c) 1999 James McKenzie, All Rights Reserved.
+ *     Copyright (c) 1999-2000 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 
@@ -23,16 +23,6 @@
  *
  ********************************************************************/
 
-/*
- * $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
 
@@ -148,7 +138,17 @@
 
 struct toshoboe_cb
   {
-    struct irda_device idev;    /*IRDA device */
+    struct device *netdev;      /* Yes! we are some kind of netdevice */
+    struct net_device_stats stats;
+
+    struct irlap_cb    *irlap;  /* The link layer we are binded to */
+    struct qos_info     qos;    /* QoS capabilities for this device */
+
+    chipio_t io;                /* IrDA controller information */
+
+    __u32 flags;                /* Interface flags */
+    __u32 new_speed;
+
     struct pci_dev *pdev;       /*PCI device */
     int base;                   /*IO base */
     int txpending;              /*how many tx's are pending */
@@ -157,6 +157,8 @@
     struct OboeTaskFile *taskfile;  /*The taskfile   */
     void *xmit_bufs[TX_SLOTS];  /*The buffers   */
     void *recv_bufs[RX_SLOTS];
+    int open;
+    int stopped;		/*Stopped by some or other APM stuff*/
   };
 
 
diff -urN linux-2.2.15-pre2/include/net/irda/uircc.h linux/include/net/irda/uircc.h
--- linux-2.2.15-pre2/include/net/irda/uircc.h	Thu Apr 15 05:42:42 1999
+++ linux/include/net/irda/uircc.h	Wed Dec 31 16:00:00 1969
@@ -1,123 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      uircc.h
- * Version:       0.1
- * Description:   Driver for the Sharp Universal Infrared 
- *                Communications Controller (UIRCC)
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Dec 26 11:00:49 1998
- * Modified at:   Thu Mar 11 01:37:20 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998 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.
- *     
- ********************************************************************/
-
-#ifndef UIRCC_H
-#define UIRCC_H
-
-/* Control registers (write only) */
-#define UIRCC_CR0           0x00 /* Control register 0 */
-#define UIRCC_CR0_XMIT_RST  0x20 /* Transmit reset */
-#define UIRCC_CR0_RECV_RST  0x10 /* Receive reset */
-#define UIRCC_CR0_TMR_RST   0x08 /* Timer reset */
-#define UIRCC_CR0_SYS_RST   0x04 /* System reset */
-#define UIRCC_CR0_CARR_RST  0x02 /* Carrier latch reset */
-#define UIRCC_CR0_CNT_SWT   0x01 /* Transmit/receive length counter reset */
-
-#define UIRCC_CR1           0x01 /* Transmit/receive mode setting register */
-#define UIRCC_CR1_RX_DMA    0x80 /* Rx DMA mode */
-#define UIRCC_CR1_TX_DMA    0x20 /* Tx DMA mode */
-#define UIRCC_CR1_DMA_BRST  0x10 /* DMA burst mode */
-#define UIRCC_CR1_MUST_SET  0x0c /* Must be set */
-
-#define UIRCC_CR2           0x02 /* Interrupt mask register */
-#define UIRCC_CR2_RECV_OVR  0x40 /* Receive overrun error */
-#define UIRCC_CR2_RECV_FRM  0x20 /* Receive frame error */
-#define UIRCC_CR2_RECV_END  0x10 /* Receive end */
-#define UIRCC_CR2_TMR_OUT   0x08 /* Timer time-out */
-#define UIRCC_CR2_XMIT_UNR  0x04 /* Transmit under-run error */
-#define UIRCC_CR2_XMIT_END  0x01 /* Transmit end */
-#define UIRCC_CR2_RECV_MASK 0x70
-#define UIRCC_CR2_XMIT_MASK 0x05
-
-#define UIRCC_CR3           0x03 /* Transmit/receive control */
-#define UIRCC_CR3_XMIT_EN   0x80 /* Transmit enable */
-#define UIRCC_CR3_TX_CRC_EN 0x40 /* Transmit UIRCC_CRC enable */
-#define UIRCC_CR3_RECV_EN   0x20 /* Receive enable */
-#define UIRCC_CR3_RX_CRC_EN 0x10 /* Receive CRC enable */
-#define UIRCC_CR3_ADDR_CMP  0x08 /* Address comparison enable */
-#define UIRCC_CR3_MCAST_EN  0x04 /* Multicast enable */
-
-#define UIRCC_CR4           0x04 /* Transmit data length low byte */
-#define UIRCC_CR5           0x05 /* Transmit data length high byte */
-#define UIRCC_CR6           0x06 /* Transmit data writing low byte */
-#define UIRCC_CR7           0x07 /* Transmit data writing high byte */
-
-#define UIRCC_CR8           0x08 /* Self pole address */
-
-#define UIRCC_CR9           0x09 /* System control 1 */
-
-#define UIRCC_CR10          0x0a /* Modem selection */
-#define UIRCC_CR10_SIR      0x22 /* Set SIR mode */
-#define UIRCC_CR10_FIR      0x88 /* Set FIR mode */
-
-#define UIRCC_CR11          0x0b /* System control 2 (same as SR11) */
-#define UIRCC_CR11_TMR_EN   0x08
-
-#define UIRCC_CR12          0x0c /* Timer counter initial value (low byte) */
-#define UIRCC_CR13          0x0d /* Timer counter initial value (high byte) */
-#define UIRCC_CR15          0x0f
-
-/* Status registers (read only) */
-#define UIRCC_SR0           0x00 /* Transmit/receive status register */
-#define UIRCC_SR0_RX_RDY    0x80 /* Received data ready */
-#define UIRCC_SR0_RX_OVR    0x40 /* Receive overrun error */
-#define UIRCC_SR0_RX_CRCFRM 0x20 /* Receive CRC or framing error */
-
-#define UIRCC_SR2           0x02 /* Interrupt mask status */
-
-#define UIRCC_SR3           0x03 /* Interrupt factor register */
-#define UIRCC_SR3_RX_OVR_ER 0x40 /* Receive overrun error */
-#define UIRCC_SR3_RX_FRM_ER 0x20 /* Receive frameing error */
-#define UIRCC_SR3_RX_EOF    0x10 /* Receive end of frame */
-#define UIRCC_SR3_TMR_OUT   0x08 /* Timer timeout */
-#define UIRCC_SR3_TXUR      0x04 /* Transmit underrun */
-#define UIRCC_SR3_TX_DONE   0x01 /* Transmit all sent */
-
-#define UIRCC_SR4           0x04 /* TX/RX data length counter low byte */
-#define UIRCC_SR5           0x05 /* TX/RX data length counter high byte */
-
-#define UIRCC_SR8           0x08 /* Chip version */
-
-#define UIRCC_SR9           0x09 /* System status 1 */
-
-#define UIRCC_SR10          0x0a /* Modem select status */
-#define UIRCC_SR11          0x0b
-#define UIRCC_SR12          0x0c /* Timer counter status (low byte) */
-#define UIRCC_SR13          0x0d /* Timer counter status (high byte) */
-#define UIRCC_SR15          0x0f
-
-/* Private data for each instance */
-struct uircc_cb {
-	struct irda_device idev;
-	
-	__u8 cr3;                 /* Copy of register sr3 */
-};
-
-#define CR3_SET
-
-#endif
-
-
-
diff -urN linux-2.2.15-pre2/include/net/irda/w83977af.h linux/include/net/irda/w83977af.h
--- linux-2.2.15-pre2/include/net/irda/w83977af.h	Thu Dec 17 09:01:03 1998
+++ linux/include/net/irda/w83977af.h	Mon Dec  3 21:57:53 2001
@@ -1,54 +1,53 @@
 #ifndef W83977AF_H
 #define W83977AF_H
 
-#define W977_EFER 0x370
-#define W977_EFIR 0x370
-#define W977_EFDR 0x371
+#define W977_EFIO_BASE 0x370
+#define W977_EFIO2_BASE 0x3f0
 #define W977_DEVICE_IR 0x06
 
 
 /*
  * Enter extended function mode
  */
-static inline void w977_efm_enter(void)
+static inline void w977_efm_enter(unsigned int efio)
 {
-        outb(0x87, W977_EFER);
-        outb(0x87, W977_EFER);
+        outb(0x87, efio);
+        outb(0x87, efio);
 }
 
 /*
  * Select a device to configure 
  */
 
-static inline void w977_select_device(__u8 devnum)
+static inline void w977_select_device(__u8 devnum, unsigned int efio)
 {
-	outb(0x07, W977_EFIR);
-	outb(devnum, W977_EFDR);
+	outb(0x07, efio);
+	outb(devnum, efio+1);
 } 
 
 /* 
  * Write a byte to a register
  */
-static inline void w977_write_reg(__u8 reg, __u8 value)
+static inline void w977_write_reg(__u8 reg, __u8 value, unsigned int efio)
 {
-	outb(reg, W977_EFIR);
-	outb(value, W977_EFDR);
+	outb(reg, efio);
+	outb(value, efio+1);
 }
 
 /*
  * read a byte from a register
  */
-static inline __u8 w977_read_reg(__u8 reg)
+static inline __u8 w977_read_reg(__u8 reg, unsigned int efio)
 {
-	outb(reg, W977_EFIR);
-	return inb(W977_EFDR);
+	outb(reg, efio);
+	return inb(efio+1);
 }
 
 /*
  * Exit extended function mode
  */
-static inline void w977_efm_exit(void)
+static inline void w977_efm_exit(unsigned int efio)
 {
-	outb(0xAA, W977_EFER);
+	outb(0xAA, efio);
 }
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/w83977af_ir.h linux/include/net/irda/w83977af_ir.h
--- linux-2.2.15-pre2/include/net/irda/w83977af_ir.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/w83977af_ir.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Thu Nov 19 13:55:34 1998
- * Modified at:   Mon May  3 12:07:25 1999
+ * Modified at:   Tue Jan 11 13:08:19 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-2000 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 
@@ -170,12 +170,23 @@
 	int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
 	int tx_len;          /* Number of frames in tx_buff */
 
-	struct irda_device idev;
+	struct device *netdev; /* Yes! we are some kind of netdevice */
+	struct net_device_stats stats;
+	
+	struct irlap_cb    *irlap; /* The link layer we are binded to */
+	struct qos_info     qos;   /* QoS capabilities for this device */
+	
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
+	
+	__u32 flags;               /* Interface flags */
+	__u32 new_speed;
 };
 
 static inline void switch_bank( int iobase, int set)
 {
-	outb( set, iobase+SSR);
+	outb(set, iobase+SSR);
 }
 
 #endif
diff -urN linux-2.2.15-pre2/include/net/irda/wrapper.h linux/include/net/irda/wrapper.h
--- linux-2.2.15-pre2/include/net/irda/wrapper.h	Sun May 30 10:17:03 1999
+++ linux/include/net/irda/wrapper.h	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Mon May  3 09:02:36 1999
+ * Modified at:   Tue Jan 11 12:37:29 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -28,6 +28,7 @@
 
 #include <linux/types.h>
 #include <linux/skbuff.h>
+#include <linux/netdevice.h>
 
 #include <net/irda/irda_device.h>
 
@@ -51,6 +52,9 @@
 
 /* Proto definitions */
 int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize);
-inline void async_unwrap_char(struct irda_device *idev, __u8 byte);
+void async_bump(struct device *dev, struct net_device_stats *stats,
+		__u8 *buf, int len);
+void async_unwrap_char(struct device *dev, struct net_device_stats *stats,
+		       iobuff_t *buf, __u8 byte);
 
 #endif
diff -urN linux-2.2.15-pre2/init/main.c linux/init/main.c
--- linux-2.2.15-pre2/init/main.c	Mon Dec  3 21:57:48 2001
+++ linux/init/main.c	Mon Dec  3 21:57:53 2001
@@ -1432,6 +1432,10 @@
 	/* .. filesystems .. */
 	filesystem_setup();
 
+#ifdef CONFIG_IRDA
+	irda_device_init(); /* Must be done after protocol initialization */
+#endif
+
 	/* Mount the root filesystem.. */
 	mount_root();
 
diff -urN linux-2.2.15-pre2/net/core/filter.c linux/net/core/filter.c
--- linux-2.2.15-pre2/net/core/filter.c	Sat May 15 17:43:52 1999
+++ linux/net/core/filter.c	Mon Dec  3 21:57:53 2001
@@ -49,7 +49,7 @@
 	else if (k>=SKF_LL_OFF)
 		ptr = skb->mac.raw + k - SKF_LL_OFF;
 
-	if (ptr<skb->head && ptr < skb->tail)
+	if (ptr >= skb->head && ptr < skb->tail)
 		return ptr;
 	return NULL;
 }
diff -urN linux-2.2.15-pre2/net/irda/Config.in linux/net/irda/Config.in
--- linux-2.2.15-pre2/net/irda/Config.in	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/Config.in	Mon Dec  3 21:57:53 2001
@@ -2,31 +2,30 @@
 # IrDA protocol configuration
 #
 
-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_NET
+   mainmenu_option next_comment
+   comment 'IrDA (infrared) 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
+      bool '  Ultra (connectionless) protocol' CONFIG_IRDA_ULTRA
+      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
 
-    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 -urN linux-2.2.15-pre2/net/irda/Makefile linux/net/irda/Makefile
--- linux-2.2.15-pre2/net/irda/Makefile	Thu Apr 15 05:42:42 1999
+++ linux/net/irda/Makefile	Mon Dec  3 21:57:53 2001
@@ -7,7 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-ALL_SUB_DIRS := irlan ircomm irlpt compressors
+ALL_SUB_DIRS := irlan ircomm compressors
 SUB_DIRS :=
 MOD_SUB_DIRS :=
 OX_OBJS :=
@@ -16,7 +16,7 @@
 O_OBJS	 := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \
             irlap.o irlap_event.o irlap_frame.o timer.o qos.o irqueue.o \
             irttp.o irda_device.o irias_object.o crc.o wrapper.o af_irda.o \
-	    discovery.o
+	    discovery.o parameters.o
 OX_OBJS := irmod.o
 
 MOD_LIST_NAME := IRDA_MODULES
@@ -46,15 +46,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_IRLPT),y)
-SUB_DIRS += irlpt
-O_OBJS += irlpt/irlpt.o
-else
-  ifeq ($(CONFIG_IRLPT),m)
-  MOD_IN_SUB_DIRS += irlpt
-  endif
-endif
-
 ifeq ($(CONFIG_IRDA_COMPRESSION),y)
 SUB_DIRS += compressors
 MOD_IN_SUB_DIRS += compressors
@@ -70,7 +61,7 @@
 
 ifeq ($(CONFIG_IRCOMM),y)
 SUB_DIRS += ircomm
-O_OBJS += ircomm/ircomm_n_vtd.o
+O_OBJS += ircomm/ircomm_and_tty.o
 else
   ifeq ($(CONFIG_IRCOMM),m)
   MOD_SUB_DIRS += ircomm
diff -urN linux-2.2.15-pre2/net/irda/af_irda.c linux/net/irda/af_irda.c
--- linux-2.2.15-pre2/net/irda/af_irda.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/af_irda.c	Mon Dec  3 21:57:53 2001
@@ -1,25 +1,44 @@
 /*********************************************************************
  *                
  * Filename:      af_irda.c
- * Version:       0.6
+ * Version:       0.9
  * Description:   IrDA sockets implementation
- * Status:        Experimental.
+ * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 31 10:12:43 1998
- * Modified at:   Wed May 19 16:12:06 1999
+ * Modified at:   Sat Dec 25 21:10:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
  * 
- *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
- *      
+ *     Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1999 Jean Tourrilhes <jeant@rockfort.hpl.hp.com>
+ *     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.
+ * 
+ *     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
+ *
+ *     Linux-IrDA now supports four different types of IrDA sockets:
+ *
+ *     o SOCK_STREAM:    TinyTP connections with SAR disabled. The
+ *                       max SDU size is 0 for conn. of this type
+ *     o SOCK_SEQPACKET: TinyTP connections with SAR enabled. TTP may 
+ *                       fragment the messages, but will preserve
+ *                       the message boundaries
+ *     o SOCK_DGRAM:     IRDAPROTO_UNITDATA: TinyTP connections with Unitdata 
+ *                       (unreliable) transfers
+ *                       IRDAPROTO_ULTRA: Connectionless and unreliable data
  *     
  ********************************************************************/
 
@@ -39,6 +58,7 @@
 #include <net/irda/irda.h>
 #include <net/irda/iriap.h>
 #include <net/irda/irias_object.h>
+#include <net/irda/irlmp.h>
 #include <net/irda/irttp.h>
 #include <net/irda/discovery.h>
 
@@ -47,8 +67,17 @@
 extern int  irlap_driver_rcv(struct sk_buff *, struct device *, 
 			     struct packet_type *);
 
+static int irda_create(struct socket *sock, int protocol);
+
 static struct proto_ops irda_stream_ops;
+static struct proto_ops irda_seqpacket_ops;
 static struct proto_ops irda_dgram_ops;
+
+#ifdef CONFIG_IRDA_ULTRA
+static struct proto_ops irda_ultra_ops;
+#define ULTRA_MAX_DATA 382
+#endif /* CONFIG_IRDA_ULTRA */
+
 static hashbin_t *cachelog = NULL;
 static struct wait_queue *discovery_wait; /* Wait for discovery */
 
@@ -66,8 +95,6 @@
 	struct sock *sk;
 	int err;
 
-	DEBUG(1, __FUNCTION__ "()\n");
-
 	self = (struct irda_sock *) instance;
 	ASSERT(self != NULL, return -1;);
 
@@ -76,7 +103,7 @@
 
 	err = sock_queue_rcv_skb(sk, skb);
 	if (err) {
-		DEBUG(1, __FUNCTION__ "(), error: no more mem!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), error: no more mem!\n");
 		self->rx_flow = FLOW_STOP;
 
 		/* When we return error, TTP will need to requeue the skb */
@@ -98,7 +125,7 @@
 	struct irda_sock *self;
 	struct sock *sk;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	self = (struct irda_sock *) instance;
 
@@ -107,7 +134,7 @@
 		return;
 
 	sk->state     = TCP_CLOSE;
-        sk->err       = reason;
+        sk->err       = ECONNRESET;
         sk->shutdown |= SEND_SHUTDOWN;
 	if (!sk->dead) {
 		sk->state_change(sk);
@@ -129,10 +156,14 @@
 	struct irda_sock *self;
 	struct sock *sk;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	self = (struct irda_sock *) instance;
 
+	sk = self->sk;
+	if (sk == NULL)
+		return;
+
 	/* How much header space do we need to reserve */
 	self->max_header_size = max_header_size;
 
@@ -140,19 +171,30 @@
 	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
+	switch (sk->type) {
+	case SOCK_STREAM:
+		if (max_sdu_size != 0) {
+			ERROR(__FUNCTION__ "(), max_sdu_size must be 0\n");
+			return;
+		}
+		self->max_data_size = irttp_get_max_seg_size(self->tsap);
+		break;
+	case SOCK_SEQPACKET:
+		if (max_sdu_size == 0) {
+			ERROR(__FUNCTION__ "(), max_sdu_size cannot be 0\n");
+			return;
+		}
 		self->max_data_size = max_sdu_size;
+		break;
+	default:
+		self->max_data_size = irttp_get_max_seg_size(self->tsap);
+	};
 
-	DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+	IRDA_DEBUG(2, __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! */
@@ -173,9 +215,13 @@
 	struct irda_sock *self;
 	struct sock *sk;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	self = (struct irda_sock *) instance;
+ 	self = (struct irda_sock *) instance;
+
+	sk = self->sk;
+	if (sk == NULL)
+		return;
 
 	/* How much header space do we need to reserve */
 	self->max_header_size = max_header_size;
@@ -184,21 +230,31 @@
 	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
+	switch (sk->type) {
+	case SOCK_STREAM:
+		if (max_sdu_size != 0) {
+			ERROR(__FUNCTION__ "(), max_sdu_size must be 0\n");
+			return;
+		}
+		self->max_data_size = irttp_get_max_seg_size(self->tsap);
+		break;
+	case SOCK_SEQPACKET:
+		if (max_sdu_size == 0) {
+			ERROR(__FUNCTION__ "(), max_sdu_size cannot be 0\n");
+			return;
+		}
 		self->max_data_size = max_sdu_size;
+		break;
+	default:
+		self->max_data_size = irttp_get_max_seg_size(self->tsap);
+	};
 
-	DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+	IRDA_DEBUG(2, __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);
-
 	sk->state_change(sk);
 }
 
@@ -212,13 +268,13 @@
 {
 	struct sk_buff *skb;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 
 	skb = dev_alloc_skb(64);
 	if (skb == NULL) {
-		DEBUG(0, __FUNCTION__ "() Unable to allocate sk_buff!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "() Unable to allocate sk_buff!\n");
 		return;
 	}
 
@@ -228,7 +284,6 @@
 	irttp_connect_response(self->tsap, self->max_sdu_size_rx, skb);
 }
 
-
 /*
  * Function irda_flow_indication (instance, sap, flow)
  *
@@ -240,7 +295,7 @@
 	struct irda_sock *self;
 	struct sock *sk;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
 	self = (struct irda_sock *) instance;
 	ASSERT(self != NULL, return;);
@@ -250,43 +305,53 @@
 	
 	switch (flow) {
 	case FLOW_STOP:
-		DEBUG(1, __FUNCTION__ "(), IrTTP wants us to slow down\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), IrTTP wants us to slow down\n");
 		self->tx_flow = flow;
 		break;
 	case FLOW_START:
 		self->tx_flow = flow;
-		DEBUG(1, __FUNCTION__ "(), IrTTP wants us to start again\n");
+		IRDA_DEBUG(1, __FUNCTION__ 
+			   "(), IrTTP wants us to start again\n");
 		wake_up_interruptible(sk->sleep);
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), Unknown flow command!\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Unknown flow command!\n");
+		/* Unknown flow command, better stop */
+		self->tx_flow = flow;
+		break;
 	}
 }
 
 /*
- * Function irda_get_value_confirm (obj_id, value, priv)
+ * Function irda_getvalue_confirm (obj_id, value, priv)
  *
  *    Got answer from remote LM-IAS
  *
  */
-static void irda_get_value_confirm(int result, __u16 obj_id, 
-				   struct ias_value *value, void *priv)
+static void irda_getvalue_confirm(int result, __u16 obj_id, 
+				  struct ias_value *value, void *priv)
 {
 	struct irda_sock *self;
 	
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(priv != NULL, return;);
 	self = (struct irda_sock *) priv;
 	
-	if (!self)
+	if (!self) {
+		WARNING(__FUNCTION__ "(), lost myself!\n");
 		return;
+	}
+
+	/* We probably don't need to make any more queries */
+	iriap_close(self->iriap);
+	self->iriap = NULL;
+
+	self->errno = result;
 
 	/* Check if request succeeded */
 	if (result != IAS_SUCCESS) {
-		DEBUG(0, __FUNCTION__ "(), IAS query failed!\n");
-
-		self->errno = result;
+		IRDA_DEBUG(0, __FUNCTION__ "(), IAS query failed!\n");
 
 		/* Wake up any processes waiting for result */
 		wake_up_interruptible(&self->ias_wait);
@@ -296,7 +361,7 @@
 
 	switch (value->type) {
 	case IAS_INTEGER:
-		DEBUG(4, __FUNCTION__ "() int=%d\n", value->t.integer);
+		IRDA_DEBUG(4, __FUNCTION__ "() int=%d\n", value->t.integer);
 		
 		if (value->t.integer != -1) {
 			self->dtsap_sel = value->t.integer;
@@ -304,9 +369,11 @@
 			self->dtsap_sel = 0;
 		break;
 	default:
-		DEBUG(0, __FUNCTION__ "(), bad type!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), bad type!\n");
 		break;
 	}
+	irias_delete_value(value);
+
 	/* Wake up any processes waiting for result */
 	wake_up_interruptible(&self->ias_wait);
 }
@@ -319,7 +386,7 @@
  */
 static void irda_discovery_indication(hashbin_t *log)
 {
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	cachelog = log;
 
@@ -335,16 +402,20 @@
  */
 static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name)
 {
-	struct notify_t notify;
-	
-	DEBUG(1, __FUNCTION__ "()\n");
+	notify_t notify;
 
+	if (self->tsap) {
+		WARNING(__FUNCTION__ "(), busy!\n");
+		return -EBUSY;
+	}
+	
 	/* Initialize callbacks to be used by the IrDA stack */
 	irda_notify_init(&notify);
 	notify.connect_confirm       = irda_connect_confirm;
 	notify.connect_indication    = irda_connect_indication;
 	notify.disconnect_indication = irda_disconnect_indication;
 	notify.data_indication       = irda_data_indication;
+	notify.udata_indication	     = irda_data_indication;
 	notify.flow_indication       = irda_flow_indication;
 	notify.instance = self;
 	strncpy(notify.name, name, NOTIFY_MAX_NAME);
@@ -352,8 +423,8 @@
 	self->tsap = irttp_open_tsap(tsap_sel, DEFAULT_INITIAL_CREDIT,
 				     &notify);	
 	if (self->tsap == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Unable to allocate TSAP!\n");
-		return -1;
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Unable to allocate TSAP!\n");
+		return -ENOMEM;
 	}
 	/* Remember which TSAP selector we actually got */
 	self->stsap_sel = self->tsap->stsap_sel;
@@ -362,6 +433,38 @@
 }
 
 /*
+ * Function irda_open_lsap (self)
+ *
+ *    Open local Link Service Access Point (LSAP). Used for opening Ultra
+ *    sockets
+ */
+#ifdef CONFIG_IRDA_ULTRA
+static int irda_open_lsap(struct irda_sock *self, int pid)
+{
+	notify_t notify;
+
+	if (self->lsap) {
+		WARNING(__FUNCTION__ "(), busy!\n");
+		return -EBUSY;
+	}
+	
+	/* Initialize callbacks to be used by the IrDA stack */
+	irda_notify_init(&notify);
+	notify.udata_indication	= irda_data_indication;
+	notify.instance = self;
+	strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME);
+
+	self->lsap = irlmp_open_lsap(LSAP_CONNLESS, &notify, pid);	
+	if (self->lsap == NULL) {
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Unable to allocate LSAP!\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IRDA_ULTRA */
+
+/*
  * Function irda_find_lsap_sel (self, name)
  *
  *    Try to lookup LSAP selector in remote LM-IAS
@@ -369,14 +472,21 @@
  */
 static int irda_find_lsap_sel(struct irda_sock *self, char *name)
 {
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "(), name=%s\n", name);
 
 	ASSERT(self != NULL, return -1;);
 
+	if (self->iriap) {
+		WARNING(__FUNCTION__ "(), busy with a previous query\n");
+		return -EBUSY;
+	}
+
+	self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+				 irda_getvalue_confirm);
+
 	/* Query remote LM-IAS */
-	iriap_getvaluebyclass_request(name, "IrDA:TinyTP:LsapSel",
-				      self->saddr, self->daddr,
-				      irda_get_value_confirm, self);
+	iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
+				      name, "IrDA:TinyTP:LsapSel");
 	/* Wait for answer */
 	interruptible_sleep_on(&self->ias_wait);
 
@@ -386,6 +496,104 @@
 	return -ENETUNREACH; /* May not be true */
 }
 
+ /*
+ * Function irda_discover_daddr_and_lsap_sel (self, name)
+ *
+ *    This try to find a device with the requested service.
+ *
+ * It basically look into the discovery log. For each address in the list,
+ * it queries the LM-IAS of the device to find if this device offer
+ * the requested service.
+ * If there is more than one node supporting the service, we complain
+ * to the user (it should move devices around).
+ * The, we set both the destination address and the lsap selector to point
+ * on the service on the unique device we have found.
+ *
+ * Note : this function fails if there is more than one device in range,
+ * because IrLMP doesn't disconnect the LAP when the last LSAP is closed.
+ * Moreover, we would need to wait the LAP disconnection...
+ */
+static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
+{
+	discovery_t *discovery;
+	int err = -ENETUNREACH;
+	__u32	daddr = 0x0;		/* Address we found the service on */
+	__u8	dtsap_sel = 0x0;	/* TSAP associated with it */
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), name=%s\n", name);
+
+	ASSERT(self != NULL, return -1;);
+
+	/* Tell IrLMP we want to be notified */
+	irlmp_update_client(self->ckey, self->mask, NULL, 
+			    irda_discovery_indication);
+	
+	/* Do some discovery */
+	irlmp_discovery_request(self->nslots);
+		
+	/* Check if the we got some results */
+	if (!cachelog)
+		/* Wait for answer */
+		/*interruptible_sleep_on(&self->discovery_wait);*/
+		return -EAGAIN;
+
+	/* 
+	 * Now, check all discovered devices (if any), and connect
+	 * client only about the services that the client is
+	 * interested in...
+	 */
+	discovery = (discovery_t *) hashbin_get_first(cachelog);
+	while (discovery != NULL) {
+		/* Mask out the ones we don't want */
+		if (discovery->hints.word & self->mask) {
+			/* Try this address */
+			self->daddr = discovery->daddr;
+			self->saddr = 0x0;
+			IRDA_DEBUG(1, __FUNCTION__ "(), trying daddr = %08x\n",
+				   self->daddr);
+
+			/* Query remote LM-IAS for this service */
+			err = irda_find_lsap_sel(self, name);
+			if (err == 0) {
+				/* We found the requested service */
+				if(daddr != 0x0) {
+					IRDA_DEBUG(0, __FUNCTION__
+						   "(), discovered service ''%s'' in two different devices !!!\n",
+						   name);
+					return(-ENOTUNIQ);
+				}
+				/* First time we foun that one, save it ! */
+				daddr = self->daddr;
+				dtsap_sel = self->dtsap_sel;
+			}
+		}
+
+		/* Next node, maybe we will be more lucky...  */
+		discovery = (discovery_t *) hashbin_get_next(cachelog);
+	}
+	cachelog = NULL;
+
+	/* Check out what we found */
+	if(daddr == 0x0) {
+		IRDA_DEBUG(0, __FUNCTION__
+			   "(), cannot discover service ''%s'' in any device !!!\n",
+			   name);
+		self->daddr = 0;	/* Guessing */
+		return(-ENETUNREACH);
+	}
+
+	/* Revert back to discovered device & service */
+	self->daddr = daddr;
+	self->saddr = 0x0;
+	self->dtsap_sel = dtsap_sel;
+
+	IRDA_DEBUG(0, __FUNCTION__ 
+		   "(), discovered requested service ''%s'' at address %08x\n",
+		   name, self->daddr);
+
+	return 0;
+}
+
 /*
  * Function irda_getname (sock, uaddr, uaddr_len, peer)
  *
@@ -411,8 +619,8 @@
 		saddr.sir_addr = sk->protinfo.irda->saddr;
 	}
 	
-	DEBUG(1, __FUNCTION__ "(), tsap_sel = %#x\n", saddr.sir_lsap_sel);
-	DEBUG(1, __FUNCTION__ "(), addr = %08x\n", saddr.sir_addr);
+	IRDA_DEBUG(1, __FUNCTION__ "(), tsap_sel = %#x\n", saddr.sir_lsap_sel);
+	IRDA_DEBUG(1, __FUNCTION__ "(), addr = %08x\n", saddr.sir_addr);
 
 	if (*uaddr_len > sizeof (struct sockaddr_irda))
 		*uaddr_len = sizeof (struct sockaddr_irda);
@@ -427,16 +635,20 @@
  *    Just move to the listen state
  *
  */
-static int irda_listen( struct socket *sock, int backlog)
+static int irda_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if ((sk->type != SOCK_STREAM) && (sk->type != SOCK_SEQPACKET) &&
+	    (sk->type != SOCK_DGRAM))
+		return -EOPNOTSUPP;
 
-	if (sk->type == SOCK_STREAM && sk->state != TCP_LISTEN) {
+	if (sk->state != TCP_LISTEN) {
 		sk->max_ack_backlog = backlog;
 		sk->state           = TCP_LISTEN;
-
+		
 		return 0;
 	}
 	
@@ -457,24 +669,49 @@
 	__u16 hints = 0;
 	int err;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
 
-	if ((addr_len < sizeof(struct sockaddr_irda)) || 
-	    (addr_len > sizeof(struct sockaddr_irda)))
+	if (addr_len != sizeof(struct sockaddr_irda))
 		return -EINVAL;
 
+#ifdef CONFIG_IRDA_ULTRA
+	/* Special care for Ultra sockets */
+	if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA)) {
+		self->pid = addr->sir_lsap_sel;
+		if (self->pid & 0x80) {
+			IRDA_DEBUG(0, __FUNCTION__ 
+				   "(), extension in PID not supp!\n");
+			return -EOPNOTSUPP;
+		}
+		err = irda_open_lsap(self, self->pid);
+		if (err < 0)
+			return err;
+		
+		self->max_data_size = ULTRA_MAX_DATA - LMP_PID_HEADER;
+		self->max_header_size = IRDA_MAX_HEADER + LMP_PID_HEADER;
+
+		/* Pretend we are connected */
+		sock->state = SS_CONNECTED;
+		sk->state   = TCP_ESTABLISHED;
+
+		return 0;
+	}
+#endif /* CONFIG_IRDA_ULTRA */
+
 	err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name);
 	if (err < 0)
-		return -ENOMEM;
+		return err;
 	
 	/*  Register with LM-IAS */
 	self->ias_obj = irias_new_object(addr->sir_name, jiffies);
 	irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel", 
 				 self->stsap_sel);
 	irias_insert_object(self->ias_obj);
+	
+#if 1 /* Will be removed in near future */
 
 	/* Fill in some default hint bits values */
 	if (strncmp(addr->sir_name, "OBEX", 4) == 0)
@@ -482,7 +719,7 @@
 	
 	if (hints)
 		self->skey = irlmp_register_service(hints);
-
+#endif
 	return 0;
 }
 
@@ -498,20 +735,30 @@
 	struct sock *sk = sock->sk;
 	struct sock *newsk;
 	struct sk_buff *skb;
+#if 0 /* Linux 2.3 only */
+	int err;
+#endif
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
-
+#if 0 /* Linux 2.3 only */
+	err = irda_create(newsock, sk->protocol);
+	if (err)
+		return err;
+#endif
 	if (sock->state != SS_UNCONNECTED)
 		return -EINVAL;
 
 	if ((sk = sock->sk) == NULL)
 		return -EINVAL;
 
-	if (sk->type != SOCK_STREAM)
+	if ((sk->type != SOCK_STREAM) && (sk->type != SOCK_SEQPACKET) &&
+	    (sk->type != SOCK_DGRAM))
 		return -EOPNOTSUPP;
 
-	if (sk->state != TCP_LISTEN)
+	if (sk->state != TCP_LISTEN) 
 		return -EINVAL;
 
 	/*
@@ -538,7 +785,7 @@
 	/* Now attach up the new socket */
 	new->tsap = irttp_dup(self->tsap, new);
 	if (!new->tsap) {
-		DEBUG(0, __FUNCTION__ "(), dup failed!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n");
 		return -1;
 	}
 		
@@ -584,9 +831,13 @@
 	struct irda_sock *self;
 	int err;
 
-	self = sk->protinfo.irda;
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	self = sk->protinfo.irda;
+	
+	/* Don't allow connect for Ultra sockets */
+	if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA))
+		return -ESOCKTNOSUPPORT;
 
 	if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
 		sock->state = SS_CONNECTED;
@@ -607,18 +858,26 @@
 	if (addr_len != sizeof(struct sockaddr_irda))
 		return -EINVAL;
 
-	/* Check if user supplied the required destination device address */
-	if (!addr->sir_addr)
-		return -EINVAL;
-
-	self->daddr = addr->sir_addr;
-	DEBUG(1, __FUNCTION__ "(), daddr = %08x\n", self->daddr);
-
-	/* Query remote LM-IAS */
-	err = irda_find_lsap_sel(self, addr->sir_name);
-	if (err) {
-		DEBUG(0, __FUNCTION__ "(), connect failed!\n");
-		return err;
+	/* Check if user supplied any destination device address */
+	if (!addr->sir_addr) {
+		/* Try to find one suitable */
+		err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);
+		if (err) {
+			IRDA_DEBUG(0, __FUNCTION__ 
+				   "(), auto-connect failed!\n");
+			return -EINVAL;
+		}
+	} else {
+		/* Use the one provided by the user */
+		self->daddr = addr->sir_addr;
+		IRDA_DEBUG(1, __FUNCTION__ "(), daddr = %08x\n", self->daddr);
+		
+		/* Query remote LM-IAS */
+		err = irda_find_lsap_sel(self, addr->sir_name);
+		if (err) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");
+			return err;
+		}
 	}
 
 	/* Check if we have opened a local TSAP */
@@ -634,7 +893,7 @@
 				    self->saddr, self->daddr, NULL, 
 				    self->max_sdu_size_rx, NULL);
 	if (err) {
-		DEBUG(0, __FUNCTION__ "(), connect failed!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");
 		return err;
 	}
 
@@ -678,12 +937,13 @@
 	struct sock *sk;
 	struct irda_sock *self;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
 	/* Check for valid socket type */
 	switch (sock->type) {
-	case SOCK_STREAM:   /* FALLTHROUGH */
-	case SOCK_SEQPACKET:
+	case SOCK_STREAM:     /* For TTP connections with SAR disabled */
+	case SOCK_SEQPACKET:  /* For TTP connections with SAR enabled */
+	case SOCK_DGRAM:      /* For TTP Unitdata or LMP Ultra transfers */
 		break;
 	default:
 		return -ESOCKTNOSUPPORT;
@@ -700,13 +960,37 @@
 
 	self->sk = sk;
 	sk->protinfo.irda = self;
-
 	sock_init_data(sock, sk);
 
-	if (sock->type == SOCK_STREAM)
+	switch (sock->type) {
+	case SOCK_STREAM:
 		sock->ops = &irda_stream_ops;
-	else
-		sock->ops = &irda_dgram_ops;
+		self->max_sdu_size_rx = TTP_SAR_DISABLE;
+		break;
+	case SOCK_SEQPACKET:
+		sock->ops = &irda_seqpacket_ops;
+		self->max_sdu_size_rx = TTP_SAR_UNBOUND;
+		break;
+	case SOCK_DGRAM:
+		switch (protocol) {
+#ifdef CONFIG_IRDA_ULTRA
+		case IRDAPROTO_ULTRA:
+			sock->ops = &irda_ultra_ops;
+			break;
+#endif /* CONFIG_IRDA_ULTRA */
+		case IRDAPROTO_UNITDATA:
+			sock->ops = &irda_dgram_ops;
+			/* We let Unitdata conn. be like seqpack conn. */
+			self->max_sdu_size_rx = TTP_SAR_UNBOUND;
+			break;
+		default:
+			ERROR(__FUNCTION__ "(), protocol not supported!\n");
+			return -ESOCKTNOSUPPORT;
+		}
+		break;
+	default:
+		return -ESOCKTNOSUPPORT;
+	}		
 
 	sk->protocol = protocol;
 
@@ -714,8 +998,8 @@
 	self->ckey = irlmp_register_client(0, NULL, NULL);
 	self->mask = 0xffff;
 	self->rx_flow = self->tx_flow = FLOW_START;
-	self->max_sdu_size_rx = SAR_DISABLE; /* Default value */
 	self->nslots = DISCOVERY_DEFAULT_SLOTS;
+	self->daddr = DEV_ADDR_ANY;
 
 	/* Notify that we are using the irda module, so nobody removes it */
 	irda_mod_inc_use_count();
@@ -731,7 +1015,7 @@
  */
 void irda_destroy_socket(struct irda_sock *self)
 {
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 
@@ -741,14 +1025,22 @@
 
 	/* Unregister with LM-IAS */
 	if (self->ias_obj)
-		irias_delete_object(self->ias_obj->name);
+		irias_delete_object(self->ias_obj);
+
+	if (self->iriap) 
+		iriap_close(self->iriap);
 
 	if (self->tsap) {
 		irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
 		irttp_close_tsap(self->tsap);
 		self->tsap = NULL;
 	}
-
+#ifdef CONFIG_IRDA_ULTRA
+	if (self->lsap) {
+		irlmp_close_lsap(self->lsap);
+		self->lsap = NULL;
+	}
+#endif /* CONFIG_IRDA_ULTRA */
 	kfree(self);
 
 	/* Notify that we are not using the irda module anymore */
@@ -767,7 +1059,7 @@
 {
 	struct sock *sk = sock->sk;
 	
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
         if (sk == NULL) 
 		return 0;
@@ -788,20 +1080,20 @@
 /*
  * Function irda_sendmsg (sock, msg, len, scm)
  *
- *    Send message down to TinyTP
- *
+ *    Send message down to TinyTP. This function is used for both STREAM and
+ *    SEQPACK services. This is possible since it forces the client to 
+ *    fragment the message if necessary
  */
 static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len, 
 			struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
-/* 	struct sockaddr_irda *addr = (struct sockaddr_irda *) msg->msg_name; */
 	struct irda_sock *self;
 	struct sk_buff *skb;
 	unsigned char *asmptr;
 	int err;
 
-	DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
+	IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
 
 	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
@@ -811,12 +1103,15 @@
 		return -EPIPE;
 	}
 
+	if (sk->state != TCP_ESTABLISHED)
+		return -ENOTCONN;
+
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
 
 	/* Check if IrTTP is wants us to slow down */
 	while (self->tx_flow == FLOW_STOP) {
-		DEBUG(2, __FUNCTION__ "(), IrTTP is busy, going to sleep!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IrTTP is busy, going to sleep!\n");
 		interruptible_sleep_on(sk->sleep);
 		
 		/* Check if we are still connected */
@@ -826,9 +1121,9 @@
 
 	/* 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);
+		IRDA_DEBUG(2, __FUNCTION__ 
+			   "(), Chopping frame from %d to %d bytes!\n", len, 
+			   self->max_data_size);
 		len = self->max_data_size;
 	}
 
@@ -839,7 +1134,6 @@
 
 	skb_reserve(skb, self->max_header_size);
 	
-	DEBUG(4, __FUNCTION__ "(), appending user data\n");
 	asmptr = skb->h.raw = skb_put(skb, len);
 	memcpy_fromiovec(asmptr, msg->msg_iov, len);
 
@@ -849,17 +1143,18 @@
 	 */
 	err = irttp_data_request(self->tsap, skb);
 	if (err) {
-		DEBUG(0, __FUNCTION__ "(), err=%d\n", err);
+		IRDA_DEBUG(0, __FUNCTION__ "(), err=%d\n", err);
 		return err;
 	}
+	/* Tell client how much data we actually sent */
 	return len;
 }
 
 /*
- * Function irda_recvmsg (sock, msg, size, flags, scm)
- *
- *    Try to receive message and copy it to user
+ * Function irda_recvmsg_dgram (sock, msg, size, flags, scm)
  *
+ *    Try to receive message and copy it to user. The frame is discarded
+ *    after being read, regardless of how much the user actually read
  */
 static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg, 
 			      int size, int flags, struct scm_cookie *scm)
@@ -869,7 +1164,7 @@
 	struct sk_buff *skb;
 	int copied, err;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
@@ -883,6 +1178,9 @@
 	copied     = skb->len;
 	
 	if (copied > size) {
+		IRDA_DEBUG(2, __FUNCTION__ 
+			   "(), Received truncated frame (%d < %d)!\n",
+			   copied, size);
 		copied = size;
 		msg->msg_flags |= MSG_TRUNC;
 	}
@@ -898,7 +1196,7 @@
 	 */
 	if (self->rx_flow == FLOW_STOP) {
 		if ((atomic_read(&sk->rmem_alloc) << 2) <= sk->rcvbuf) {
-			DEBUG(2, __FUNCTION__ "(), Starting IrTTP\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), Starting IrTTP\n");
 			self->rx_flow = FLOW_START;
 			irttp_flow_request(self->tsap, FLOW_START);
 		}
@@ -937,7 +1235,7 @@
 	int copied = 0;
 	int target = 1;
 
-	DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
@@ -951,14 +1249,8 @@
 	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;
@@ -973,32 +1265,20 @@
 			 */
 			
 			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);
@@ -1009,33 +1289,20 @@
 		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");
+				IRDA_DEBUG(1, __FUNCTION__ "(), back on q!\n");
 				skb_queue_head(&sk->receive_queue, skb);
 				break;
 			}
 
-			kfree_skb(skb);
-			
-/* 			if (scm->fp) */
-/* 				break; */
+			kfree_skb(skb);			
 		} 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); */
+			IRDA_DEBUG(0, __FUNCTION__ "() questionable!?\n");
 
 			/* put message back and return */
 			skb_queue_head(&sk->receive_queue, skb);
@@ -1051,29 +1318,171 @@
 	 */
 	if (self->rx_flow == FLOW_STOP) {
 		if ((atomic_read(&sk->rmem_alloc) << 2) <= sk->rcvbuf) {
-			DEBUG(2, __FUNCTION__ "(), Starting IrTTP\n");
+			IRDA_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_sendmsg_dgram (sock, msg, len, scm)
+ *
+ *    Send message down to TinyTP for the unreliable sequenced
+ *    packet service...
+ *
+ */
+static int irda_sendmsg_dgram(struct socket *sock, struct msghdr *msg,
+			      int len, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct irda_sock *self;
+	struct sk_buff *skb;
+	unsigned char *asmptr;
+	int err;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
+	
+	if (msg->msg_flags & ~MSG_DONTWAIT)
+		return -EINVAL;
+
+	if (sk->shutdown & SEND_SHUTDOWN) {
+		send_sig(SIGPIPE, current, 0);
+		return -EPIPE;
+	}
+
+	if (sk->state != TCP_ESTABLISHED)
+		return -ENOTCONN;
+
+	self = sk->protinfo.irda;
+	ASSERT(self != NULL, return -1;);
+
+	/*  
+	 * Check that we don't send out to big frames. This is an unreliable 
+	 * service, so we have no fragmentation and no coalescence 
+	 */
+	if (len > self->max_data_size) {
+		IRDA_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, self->max_header_size);
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(), appending user data\n");
+	asmptr = skb->h.raw = skb_put(skb, len);
+	memcpy_fromiovec(asmptr, msg->msg_iov, len);
+
+	/* 
+	 * Just send the message to TinyTP, and let it deal with possible 
+	 * errors. No need to duplicate all that here
+	 */
+	err = irttp_udata_request(self->tsap, skb);
+	if (err) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), err=%d\n", err);
+		return err;
+	}
+	return len;
+}
+
+/*
+ * Function irda_sendmsg_ultra (sock, msg, len, scm)
+ *
+ *    Send message down to IrLMP for the unreliable Ultra
+ *    packet service...
+ */
+#ifdef CONFIG_IRDA_ULTRA
+static int irda_sendmsg_ultra(struct socket *sock, struct msghdr *msg,
+			      int len, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct irda_sock *self;
+	struct sk_buff *skb;
+	unsigned char *asmptr;
+	int err;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
+	
+	if (msg->msg_flags & ~MSG_DONTWAIT)
+		return -EINVAL;
+
+	if (sk->shutdown & SEND_SHUTDOWN) {
+		send_sig(SIGPIPE, current, 0);
+		return -EPIPE;
+	}
+
+	self = sk->protinfo.irda;
+	ASSERT(self != NULL, return -1;);
+
+	/*  
+	 * Check that we don't send out to big frames. This is an unreliable 
+	 * service, so we have no fragmentation and no coalescence 
+	 */
+	if (len > self->max_data_size) {
+		IRDA_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, self->max_header_size);
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(), appending user data\n");
+	asmptr = skb->h.raw = skb_put(skb, len);
+	memcpy_fromiovec(asmptr, msg->msg_iov, len);
+
+	err = irlmp_connless_data_request(self->lsap, skb);
+	if (err) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), err=%d\n", err);
+		return err;
+	}
+	return len;
+}
+#endif /* CONFIG_IRDA_ULTRA */
+
+/*
  * Function irda_shutdown (sk, how)
  *
  *    
  *
  */
-static int irda_shutdown( struct socket *sk, int how)
+static int irda_shutdown(struct socket *sock, int how)
 {
-	DEBUG( 0, __FUNCTION__ "()\n");
+	struct irda_sock *self;
+	struct sock *sk = sock->sk;
 
-        /* FIXME - generate DM and RNR states */
-        return -EOPNOTSUPP;
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	self = sk->protinfo.irda;
+	ASSERT(self != NULL, return -1;);
+
+	sk->state       = TCP_CLOSE;
+	sk->shutdown   |= SEND_SHUTDOWN;
+	sk->state_change(sk);
+
+	if (self->iriap) 
+		iriap_close(self->iriap);
+	
+	if (self->tsap) {
+		irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
+		irttp_close_tsap(self->tsap);
+		self->tsap = NULL;
+	}
+
+        return 0;
 }
 
 /*
@@ -1088,7 +1497,7 @@
 	struct sock *sk = sock->sk;
 	unsigned int mask;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	poll_wait(file, sk->sleep, wait);
 	mask = 0;
@@ -1100,9 +1509,10 @@
 		mask |= POLLHUP;
 
 	/* readable? */
-	if (!skb_queue_empty(&sk->receive_queue))
+	if (!skb_queue_empty(&sk->receive_queue)) {
+		IRDA_DEBUG(4, "Socket is readable\n");
 		mask |= POLLIN | POLLRDNORM;
-
+	}
 	/* Connection-based need to check for termination and startup */
 	if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)
 		mask |= POLLHUP;
@@ -1127,7 +1537,7 @@
 {
 	struct sock *sk = sock->sk;
 
-	DEBUG(4, __FUNCTION__ "(), cmd=%#x\n", cmd);
+	IRDA_DEBUG(4, __FUNCTION__ "(), cmd=%#x\n", cmd);
 	
 	switch (cmd) {
 	case TIOCOUTQ: {
@@ -1155,7 +1565,8 @@
 		if (sk != NULL) {
 			if (sk->stamp.tv_sec == 0)
 				return -ENOENT;
-			if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+			if (copy_to_user((void *)arg, &sk->stamp, 
+					 sizeof(struct timeval)))
 				return -EFAULT;
 			return 0;
 		}
@@ -1171,10 +1582,9 @@
 	case SIOCSIFNETMASK:
 	case SIOCGIFMETRIC:
 	case SIOCSIFMETRIC:
-		return -EINVAL;
-		
+		return -EINVAL;		
 	default:
-		DEBUG(1, __FUNCTION__ "(), doing device ioctl!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), doing device ioctl!\n");
 		return dev_ioctl(cmd, (void *) arg);
 	}
 
@@ -1193,29 +1603,110 @@
 {
  	struct sock *sk = sock->sk;
 	struct irda_sock *self;
+	struct irda_ias_set	ias_opt;
+	struct ias_object      *ias_obj;
 	int opt;
 	
-	DEBUG(0, __FUNCTION__ "()\n");
-
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
 
 	if (level != SOL_IRLMP)
 		return -ENOPROTOOPT;
+		
+	switch (optname) {
+	case IRLMP_IAS_SET:
+		if (optlen != sizeof(struct irda_ias_set))
+			return -EINVAL;
 	
-	if (optlen < sizeof(int))
-		return -EINVAL;
+		/* Copy query to the driver. */
+		if (copy_from_user(&ias_opt, (char *)optval, optlen))
+		  	return -EFAULT;
+
+		/* Find the object we target */
+		ias_obj = irias_find_object(ias_opt.irda_class_name);
+		if(ias_obj == (struct ias_object *) NULL) {
+			/* Create a new object */
+			ias_obj = irias_new_object(ias_opt.irda_class_name,
+						   jiffies);
+		}
+
+		/* Do we have it already ? */
+		if(irias_find_attrib(ias_obj, ias_opt.irda_attrib_name))
+			return -EINVAL;
+
+		/* Look at the type */
+		switch(ias_opt.irda_attrib_type) {
+		case IAS_INTEGER:
+			/* Add an integer attribute */
+			irias_add_integer_attrib(ias_obj,
+						 ias_opt.irda_attrib_name, 
+					 ias_opt.attribute.irda_attrib_int);
+			break;
+		case IAS_OCT_SEQ:
+			/* Check length */
+			if(ias_opt.attribute.irda_attrib_octet_seq.len >
+			   IAS_MAX_OCTET_STRING)
+				return -EINVAL;
+			/* Add an octet sequence attribute */
+			irias_add_octseq_attrib(
+			      ias_obj,
+			      ias_opt.irda_attrib_name, 
+			      ias_opt.attribute.irda_attrib_octet_seq.octet_seq,
+			      ias_opt.attribute.irda_attrib_octet_seq.len);
+			break;
+		case IAS_STRING:
+			/* Should check charset & co */
+			/* Check length */
+			if(ias_opt.attribute.irda_attrib_string.len >
+			   IAS_MAX_STRING)
+				return -EINVAL;
+			/* NULL terminate the string (avoid troubles) */
+			ias_opt.attribute.irda_attrib_string.string[ias_opt.attribute.irda_attrib_string.len] = '\0';
+			/* Add a string attribute */
+			irias_add_string_attrib(
+				ias_obj,
+				ias_opt.irda_attrib_name, 
+				ias_opt.attribute.irda_attrib_string.string);
+			break;
+		default :
+			return -EINVAL;
+		}
+		irias_insert_object(ias_obj);
+		break;
+
+		IRDA_DEBUG(0, __FUNCTION__ "(), sorry not impl. yet!\n");
+		return -ENOPROTOOPT;
+	case IRLMP_MAX_SDU_SIZE:
+		if (optlen < sizeof(int))
+			return -EINVAL;
 	
-	if (get_user(opt, (int *)optval))
-		return -EFAULT;
+		if (get_user(opt, (int *)optval))
+			return -EFAULT;
+		
+		/* Only possible for a seqpacket service (TTP with SAR) */
+		if (sk->type != SOCK_SEQPACKET) {
+			IRDA_DEBUG(2, __FUNCTION__ 
+				   "(), setting max_sdu_size = %d\n", opt);
+			self->max_sdu_size_rx = opt;
+		} else {
+			WARNING(__FUNCTION__ 
+				"(), not allowed to set MAXSDUSIZE for this "
+				"socket type!\n");
+			return -ENOPROTOOPT;
+		}
+		break;
+	case IRLMP_HINTS_SET:
+		if (optlen < sizeof(int))
+			return -EINVAL;
 	
-	switch (optname) {
-	case IRLMP_IAS_SET:
-		DEBUG(0, __FUNCTION__ "(), sorry not impl. yet!\n");
-		return 0;
-	case IRTTP_MAX_SDU_SIZE:
-		DEBUG(0, __FUNCTION__ "(), setting max_sdu_size = %d\n", opt);
-		self->max_sdu_size_rx = opt;
+		if (get_user(opt, (int *)optval))
+			return -EFAULT;
+
+		/* Unregister any old registration */
+		if (self->skey)
+			irlmp_unregister_service(self->skey);
+
+		self->skey = irlmp_register_service((__u16) opt);
 		break;
 	default:
 		return -ENOPROTOOPT;
@@ -1223,6 +1714,104 @@
 	return 0;
 }
 
+ /*
+ * Function irda_simple_getvalue_confirm (obj_id, value, priv)
+ *
+ *    Got answer from remote LM-IAS, just copy object to requester...
+ *
+ * Note : duplicate from above, but we need our own version that
+ * doesn't touch the dtsap_sel and save the full value structure...
+ */
+static void irda_simple_getvalue_confirm(int result, __u16 obj_id, 
+					  struct ias_value *value, void *priv)
+{
+	struct irda_sock *self;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(priv != NULL, return;);
+	self = (struct irda_sock *) priv;
+	
+	if (!self) {
+		WARNING(__FUNCTION__ "(), lost myself!\n");
+		return;
+	}
+
+	/* We probably don't need to make any more queries */
+	iriap_close(self->iriap);
+	self->iriap = NULL;
+
+	/* Check if request succeeded */
+	if (result != IAS_SUCCESS) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), IAS query failed!\n");
+
+		self->errno = -EHOSTUNREACH;
+
+		/* Wake up any processes waiting for result */
+		wake_up_interruptible(&self->ias_wait);
+
+		return;
+	}
+
+	/* Clone the object (so the requester can free it) */
+	self->ias_result = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
+	memcpy(self->ias_result, value, sizeof(struct ias_value));
+	irias_delete_value(value);
+
+	self->errno = 0;
+
+	/* Wake up any processes waiting for result */
+	wake_up_interruptible(&self->ias_wait);
+}
+
+/*
+ * Function irda_extract_ias_value(ias_opt, ias_value)
+ *
+ *    Translate internal IAS value structure to the user space representation
+ *
+ * The external representation of IAS values, as we exchange them with
+ * user space program is quite different from the internal representation,
+ * as stored in the IAS database (because we need a flat structure for
+ * crossing kernel boundary).
+ * This function transform the former in the latter. We also check
+ * that the value type is valid.
+ */
+static int irda_extract_ias_value(struct irda_ias_set *ias_opt,
+				  struct ias_value *ias_value)
+{
+	/* Look at the type */
+	switch (ias_value->type) {
+	case IAS_INTEGER:
+		/* Copy the integer */
+		ias_opt->attribute.irda_attrib_int = ias_value->t.integer;
+		break;
+	case IAS_OCT_SEQ:
+		/* Set length */
+		ias_opt->attribute.irda_attrib_octet_seq.len = ias_value->len;
+		/* Copy over */
+		memcpy(ias_opt->attribute.irda_attrib_octet_seq.octet_seq,
+		       ias_value->t.oct_seq, ias_value->len);
+		break;
+	case IAS_STRING:
+		/* Set length */
+		ias_opt->attribute.irda_attrib_string.len = ias_value->len;
+		ias_opt->attribute.irda_attrib_string.charset = ias_value->charset;
+		/* Copy over */
+		memcpy(ias_opt->attribute.irda_attrib_string.string,
+		       ias_value->t.string, ias_value->len);
+		/* NULL terminate the string (avoid troubles) */
+		ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0';
+		break;
+	default :
+		return -EINVAL;
+	}
+	
+	/* Copy type over */
+	ias_opt->irda_attrib_type = ias_value->type;
+	
+	return 0;
+}
+
 /*
  * Function irda_getsockopt (sock, level, optname, optval, optlen)
  *
@@ -1234,15 +1823,16 @@
 {
 	struct sock *sk = sock->sk;
 	struct irda_sock *self;
-	struct irda_device_list *list;
-	__u8 optbuf[sizeof(struct irda_device_list) +
-		   sizeof(struct irda_device_info)*10];
+	struct irda_device_list list;
+	struct irda_device_info *info;
 	discovery_t *discovery;
+	struct irda_ias_set	ias_opt;	/* IAS get/query params */
+	struct ias_object *	ias_obj;	/* Object in IAS */
+	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
 	int val = 0;
 	int len = 0;
-	int i = 0;
-
-	DEBUG(1, __FUNCTION__ "()\n");
+	int err;
+	int offset, total;
 
 	self = sk->protinfo.irda;
 
@@ -1254,26 +1844,26 @@
 
 	switch (optname) {
 	case IRLMP_ENUMDEVICES:
-		DEBUG(1, __FUNCTION__ "(), IRLMP_ENUMDEVICES\n");
-		
 		/* Tell IrLMP we want to be notified */
 		irlmp_update_client(self->ckey, self->mask, NULL, 
 				    irda_discovery_indication);
-
+		
 		/* Do some discovery */
 		irlmp_discovery_request(self->nslots);
+		
+		/* Check if the we got some results */
+		if (!cachelog)
+			return -EAGAIN;
+
+		info = &list.dev[0];
+
+		/* Offset to first device entry */
+		offset = sizeof(struct irda_device_list) - 
+			sizeof(struct irda_device_info);
 
-		/* Devices my be discovered already */
-		if (!cachelog) {
-			DEBUG(2, __FUNCTION__ "(), no log!\n");
-
-			/* Sleep until device(s) discovered */
-			interruptible_sleep_on(&discovery_wait);
-			if (!cachelog)
-				return -1;
-		}
+		total = offset;   /* Initialized to size of the device list */
+		list.len = 0;     /* Initialize lenght of list */
 
-		list = (struct irda_device_list *) optbuf;
 		/* 
 		 * Now, check all discovered devices (if any), and notify
 		 * client only about the services that the client is
@@ -1283,35 +1873,41 @@
 		while (discovery != NULL) {
 			/* Mask out the ones we don't want */
 			if (discovery->hints.word & self->mask) {
-				/* Copy discovery information */
-				list->dev[i].saddr = discovery->saddr;
-				list->dev[i].daddr = discovery->daddr;
-				list->dev[i].charset = discovery->charset;
-				list->dev[i].hints[0] = discovery->hints.byte[0];
-				list->dev[i].hints[1] = discovery->hints.byte[1];
-				strncpy(list->dev[i].info, discovery->info, 22);
-				if (++i >= 10)
+				/* Check if room for this device entry */
+				if (len-total<sizeof(struct irda_device_info))
 					break;
+
+				/* Copy discovery information */
+				info->saddr = discovery->saddr;
+				info->daddr = discovery->daddr;
+				info->charset = discovery->charset;
+				info->hints[0] = discovery->hints.byte[0];
+				info->hints[1] = discovery->hints.byte[1];
+				strncpy(info->info, discovery->nickname,
+					NICKNAME_MAX_LEN);
+
+				if (copy_to_user(optval+total, info, 
+						 sizeof(struct irda_device_info)))
+					return -EFAULT;
+				list.len++;
+				total += sizeof(struct irda_device_info);
 			}
 			discovery = (discovery_t *) hashbin_get_next(cachelog);
 		}
 		cachelog = NULL;
 
-		list->len = i;
-		len = sizeof(struct irda_device_list) +
-			sizeof(struct irda_device_info) * i;
-
-		DEBUG(1, __FUNCTION__ "(), len=%d, i=%d\n", len, i);
-
-		if (put_user(len, optlen))
+		/* Write total number of bytes used back to client */
+		if (put_user(total, optlen))
 			return -EFAULT;
-		
-		if (copy_to_user(optval, &optbuf, len))
+
+		/* Write total list length back to client */
+		if (copy_to_user(optval, &list, 
+				 sizeof(struct irda_device_list) -
+				 sizeof(struct irda_device_info)))
 			return -EFAULT;
 		break;
-	case IRTTP_MAX_SDU_SIZE:
+	case IRLMP_MAX_SDU_SIZE:
 		val = self->max_data_size;
-		DEBUG(0, __FUNCTION__ "(), getting max_sdu_size = %d\n", val);
 		len = sizeof(int);
 		if (put_user(len, optlen))
 			return -EFAULT;
@@ -1319,10 +1915,95 @@
 		if (copy_to_user(optval, &val, len))
 			return -EFAULT;
 		break;
+	case IRLMP_IAS_GET:
+		/* The user want an object from our local IAS database.
+		 * We just need to query the IAS and return the value
+		 * that we found */
+
+		/* Check that the user has allocated the right space for us */
+		if (len != sizeof(ias_opt))
+			return -EINVAL;
+
+		/* Copy query to the driver. */
+		if (copy_from_user((char *) &ias_opt, (char *)optval, len))
+		  	return -EFAULT;
+
+		/* Find the object we target */
+		ias_obj = irias_find_object(ias_opt.irda_class_name);
+		if(ias_obj == (struct ias_object *) NULL)
+			return -EINVAL;
+
+		/* Find the attribute (in the object) we target */
+		ias_attr = irias_find_attrib(ias_obj,
+					     ias_opt.irda_attrib_name); 
+		if(ias_attr == (struct ias_attrib *) NULL)
+			return -EINVAL;
+
+		/* Translate from internal to user structure */
+		err = irda_extract_ias_value(&ias_opt, ias_attr->value);
+		if(err)
+			return err;
+
+		/* Copy reply to the user */
+		if (copy_to_user((char *)optval, (char *) &ias_opt,
+				 sizeof(ias_opt)))
+		  	return -EFAULT;
+		/* Note : don't need to put optlen, we checked it */
+		break;
+	case IRLMP_IAS_QUERY:
+		/* The user want an object from a remote IAS database.
+		 * We need to use IAP to query the remote database and
+		 * then wait for the answer to come back. */
+
+		/* Check that the user has allocated the right space for us */
+		if (len != sizeof(ias_opt))
+			return -EINVAL;
+
+		/* Copy query to the driver. */
+		if (copy_from_user((char *) &ias_opt, (char *)optval, len))
+		  	return -EFAULT;
+
+		/* Check that we can proceed with IAP */
+		if (self->iriap) {
+			WARNING(__FUNCTION__
+				"(), busy with a previous query\n");
+			return -EBUSY;
+		}
+
+		self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+					 irda_simple_getvalue_confirm);
+
+		/* Treat unexpected signals as disconnect */
+		self->errno = -EHOSTUNREACH;
+
+		/* Query remote LM-IAS */
+		iriap_getvaluebyclass_request(self->iriap, 
+					      self->saddr, self->daddr,
+					      ias_opt.irda_class_name,
+					      ias_opt.irda_attrib_name);
+		/* Wait for answer */
+		interruptible_sleep_on(&self->ias_wait);
+		/* Check what happened */
+		if (self->errno)
+			return (self->errno);
+
+		/* Translate from internal to user structure */
+		err = irda_extract_ias_value(&ias_opt, self->ias_result);
+		if (self->ias_result)
+			kfree(self->ias_result);
+		if (err)
+			return err;
+
+		/* Copy reply to the user */
+		if (copy_to_user((char *)optval, (char *) &ias_opt,
+				 sizeof(ias_opt)))
+		  	return -EFAULT;
+		/* Note : don't need to put optlen, we checked it */
+		break;
 	default:
 		return -ENOPROTOOPT;
 	}
-
+	
 	return 0;
 }
 
@@ -1350,12 +2031,12 @@
 	irda_getsockopt,
 	sock_no_fcntl,
 	irda_sendmsg,
-	irda_recvmsg_stream
+	irda_recvmsg_stream,
 };
 
-static struct proto_ops irda_dgram_ops = {
+static struct proto_ops irda_seqpacket_ops = {
 	PF_IRDA,
-	
+       
 	sock_no_dup,
 	irda_release,
 	irda_bind,
@@ -1371,13 +2052,57 @@
 	irda_getsockopt,
 	sock_no_fcntl,
 	irda_sendmsg,
-	irda_recvmsg_dgram
+	irda_recvmsg_dgram,
+};
+
+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_dgram,
+	irda_recvmsg_dgram,
 };
 
+#ifdef CONFIG_IRDA_ULTRA
+static struct proto_ops irda_ultra_ops = {
+	PF_IRDA,
+       
+	sock_no_dup,
+	irda_release,
+	irda_bind,
+	sock_no_connect,
+	sock_no_socketpair,
+	sock_no_accept,
+	irda_getname,
+	datagram_poll,
+	irda_ioctl,
+	sock_no_listen,
+	irda_shutdown,
+	irda_setsockopt,
+	irda_getsockopt,
+	sock_no_fcntl,
+	irda_sendmsg_ultra,
+	irda_recvmsg_dgram,
+};
+#endif /* CONFIG_IRDA_ULTRA */
+
 /*
  * Function irda_device_event (this, event, ptr)
  *
- *    
+ *    Called when a device is taken up or down
  *
  */
 static int irda_device_event(struct notifier_block *this, unsigned long event,
@@ -1385,19 +2110,17 @@
 {
 	struct device *dev = (struct device *) ptr;
 	
-	DEBUG(3, __FUNCTION__ "()\n");
-	
         /* Reject non IrDA devices */
 	if (dev->type != ARPHRD_IRDA) 
 		return NOTIFY_DONE;
 	
         switch (event) {
 	case NETDEV_UP:
-		DEBUG(3, __FUNCTION__ "(), NETDEV_UP\n");
+		IRDA_DEBUG(3, __FUNCTION__ "(), NETDEV_UP\n");
 		/* irda_dev_device_up(dev); */
 		break;
 	case NETDEV_DOWN:
-		DEBUG(3, __FUNCTION__ "(), NETDEV_DOWN\n");
+		IRDA_DEBUG(3, __FUNCTION__ "(), NETDEV_DOWN\n");
 		/* irda_kill_by_device(dev); */
 		/* irda_rt_device_down(dev); */
 		/* irda_dev_device_down(dev); */
@@ -1430,16 +2153,14 @@
  *    Initialize IrDA protocol layer
  *
  */
-__initfunc(void irda_proto_init(struct net_proto *pro))
+void __init irda_proto_init(struct net_proto *pro)
 {
-	DEBUG( 4, __FUNCTION__ "\n");
-
 	sock_register(&irda_family_ops);
 
 	irda_packet_type.type = htons(ETH_P_IRDA);
         dev_add_pack(&irda_packet_type);
 
-	register_netdevice_notifier( &irda_dev_notifier);
+	register_netdevice_notifier(&irda_dev_notifier);
 
 	irda_init();
 }
@@ -1453,8 +2174,6 @@
 #ifdef MODULE
 void irda_proto_cleanup(void)
 {
-	DEBUG( 4, __FUNCTION__ "\n");
-
 	irda_packet_type.type = htons(ETH_P_IRDA);
         dev_remove_pack(&irda_packet_type);
 
diff -urN linux-2.2.15-pre2/net/irda/compressors/Config.in linux/net/irda/compressors/Config.in
--- linux-2.2.15-pre2/net/irda/compressors/Config.in	Thu Dec 17 09:01:03 1998
+++ linux/net/irda/compressors/Config.in	Mon Dec  3 21:57:53 2001
@@ -1,9 +1,11 @@
 
-bool 'IrLAP compression' CONFIG_IRDA_COMPRESSION
+bool '  IrLAP compression' CONFIG_IRDA_COMPRESSION
 
-if [ "$CONFIG_IRDA_COMPRESSION" != "n" ] ; then
-        comment '   IrDA compressors'
-        dep_tristate '   Deflate compression (experimental)' CONFIG_IRDA_DEFLATE $CONFIG_IRDA
-#	tristate '   BZIP2 compression' CONFIG_IRDA_BZIP2
-#	tristate '   BSD compression' CONFIG_IRDA_BSD
+if [ "$CONFIG_IRDA_COMPRESSION" != "n" ]; then
+   comment '    IrDA compressors'
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      dep_tristate '    Deflate compression (EXPERIMENTAL)' CONFIG_IRDA_DEFLATE $CONFIG_IRDA
+   fi
+#   tristate '    BZIP2 compression' CONFIG_IRDA_BZIP2
+#   tristate '    BSD compression' CONFIG_IRDA_BSD
 fi
diff -urN linux-2.2.15-pre2/net/irda/compressors/irda_deflate.c linux/net/irda/compressors/irda_deflate.c
--- linux-2.2.15-pre2/net/irda/compressors/irda_deflate.c	Fri Dec 18 08:06:39 1998
+++ linux/net/irda/compressors/irda_deflate.c	Mon Dec  3 21:57:53 2001
@@ -54,7 +54,6 @@
 #include <linux/malloc.h>
 #include <linux/vmalloc.h> 
 #include <linux/errno.h>
-#include <linux/sched.h>	/* to get the struct task_struct */
 #include <linux/string.h>	/* used in new tty drivers */
 #include <linux/signal.h>	/* used in new tty drivers */
 
@@ -595,7 +594,7 @@
 	z_comp_stats,		/* decomp_stat */
 };
 
-__initfunc(int irda_deflate_init(void))
+int __init irda_deflate_init(void)
 {
         int answer = irda_register_compressor ( &irda_deflate);
         if (answer == 0)
diff -urN linux-2.2.15-pre2/net/irda/discovery.c linux/net/irda/discovery.c
--- linux-2.2.15-pre2/net/irda/discovery.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/discovery.c	Mon Dec  3 21:57:53 2001
@@ -6,8 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr  6 15:33:50 1999
- * Modified at:   Fri May 28 20:46:38 1999
+ * Modified at:   Sat Oct  9 17:11:31 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * Modified at:   Fri May 28  3:11 CST 1999
+ * Modified by:   Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
  *     
@@ -28,8 +30,8 @@
  *     
  ********************************************************************/
 
+#include <linux/string.h>
 #include <linux/socket.h>
-#include <linux/irda.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irlmp.h>
@@ -63,7 +65,7 @@
 			discovery = (discovery_t *) hashbin_get_next(cachelog);
 			
 			if ((node->daddr == new->daddr) || 
-			    (strcmp(node->info, new->info) == 0))
+			    (strcmp(node->nickname, new->nickname) == 0))
 			{
 				/* This discovery is a previous discovery 
 				 * from the same device, so just remove it
@@ -75,7 +77,7 @@
 
 
 	/* Insert the new and updated version */
-	hashbin_insert(cachelog, (QUEUE *) new, new->daddr, NULL);
+	hashbin_insert(cachelog, (queue_t *) new, new->daddr, NULL);
 
 	spin_unlock_irqrestore(&irlmp->lock, flags);
 }
@@ -90,7 +92,7 @@
 {
 	discovery_t *discovery;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	/*
 	 *  If log is missing this means that IrLAP was unable to perform the
@@ -119,11 +121,11 @@
  *    Go through all discoveries and expire all that has stayed to long
  *
  */
-void irlmp_expire_discoveries(hashbin_t *log, int saddr, int force)
+void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force)
 {
 	discovery_t *discovery, *curr;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
@@ -157,10 +159,10 @@
 
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
-		DEBUG(0, "Discovery:\n");
-		DEBUG(0, "  daddr=%08x\n", discovery->daddr);
-		DEBUG(0, "  saddr=%08x\n", discovery->saddr); 
-		DEBUG(0, "  name=%s\n", discovery->info);
+		IRDA_DEBUG(0, "Discovery:\n");
+		IRDA_DEBUG(0, "  daddr=%08x\n", discovery->daddr);
+		IRDA_DEBUG(0, "  saddr=%08x\n", discovery->saddr); 
+		IRDA_DEBUG(0, "  nickname=%s\n", discovery->nickname);
 
 		discovery = (discovery_t *) hashbin_get_next(log);
 	}
@@ -175,19 +177,19 @@
  */
 __u32 irlmp_find_device(hashbin_t *cachelog, char *name, __u32 *saddr)
 {
-	discovery_t *d;
 	unsigned long flags;
+	discovery_t *d;
 
 	spin_lock_irqsave(&irlmp->lock, flags);
 
 	/* Look at all discoveries for that link */
 	d = (discovery_t *) hashbin_get_first(cachelog);
 	while (d != NULL) {
-		DEBUG(1, "Discovery:\n");
-		DEBUG(1, "  daddr=%08x\n", d->daddr);
-		DEBUG(1, "  name=%s\n", d->info);
+		IRDA_DEBUG(1, "Discovery:\n");
+		IRDA_DEBUG(1, "  daddr=%08x\n", d->daddr);
+		IRDA_DEBUG(1, "  nickname=%s\n", d->nickname);
 		
-		if (strcmp(name, d->info) == 0) {
+		if (strcmp(name, d->nickname) == 0) {
 			*saddr = d->saddr;
 			
 			spin_unlock_irqrestore(&irlmp->lock, flags);
@@ -224,7 +226,7 @@
 	
 	discovery = (discovery_t *) hashbin_get_first(cachelog);
 	while ( discovery != NULL) {
-		len += sprintf(buf+len, "name: %s,", discovery->info);
+		len += sprintf(buf+len, "nickname: %s,", discovery->nickname);
 		
 		len += sprintf(buf+len, " hint: 0x%02x%02x", 
 			       discovery->hints.byte[0], 
diff -urN linux-2.2.15-pre2/net/irda/ircomm/Config.in linux/net/irda/ircomm/Config.in
--- linux-2.2.15-pre2/net/irda/ircomm/Config.in	Thu Dec 17 09:01:03 1998
+++ linux/net/irda/ircomm/Config.in	Mon Dec  3 21:57:53 2001
@@ -1,3 +1,3 @@
 
-dep_tristate 'IrCOMM protocol' CONFIG_IRCOMM $CONFIG_IRDA
+dep_tristate '  IrCOMM protocol' CONFIG_IRCOMM $CONFIG_IRDA
 
diff -urN linux-2.2.15-pre2/net/irda/ircomm/Makefile linux/net/irda/ircomm/Makefile
--- linux-2.2.15-pre2/net/irda/ircomm/Makefile	Thu Apr 15 05:42:42 1999
+++ linux/net/irda/ircomm/Makefile	Mon Dec  3 21:57:53 2001
@@ -7,10 +7,10 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-O_TARGET := ircomm_n_vtd.o
-O_OBJS	 := ircomm_common.o irvtd_driver.o
-M_OBJS   := ircomm.o ircomm_tty.o
-MI_OBJS  := ircomm_common.o irvtd_driver.o
+O_TARGET := ircomm_and_tty.o
+O_OBJS	 := ircomm_param.o ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o
+M_OBJS   := ircomm.o ircomm-tty.o
+MI_OBJS  := ircomm_param.o ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o
 
 OX_OBJS  += 
 
@@ -18,10 +18,12 @@
 
 ifeq ($(CONFIG_IRCOMM),m)
 ircomm.o:  $(MI_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ ircomm_common.o
+	$(LD) $(LD_RFLAG) -r -o $@ ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o
+
+ircomm-tty.o: $(MI_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o ircomm_param.o
+
 
-ircomm_tty.o: $(MI_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ irvtd_driver.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_common.c linux/net/irda/ircomm/ircomm_common.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_common.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/ircomm/ircomm_common.c	Wed Dec 31 16:00:00 1969
@@ -1,1921 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      ircomm_common.c
- * Version:       
- * Description:   An implementation of IrCOMM service interface, 
- *                state machine, and incidental function(s).
- * Status:        Experimental.
- * Author:        Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
- * Source:        irlpt_event.c
- *
- *     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
- *     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, Takahide Higuchi, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-/*
- *    Reference: 
- *    "'IrCOMM':Serial and Parallel Port Emulation Over IR(Wire Replacement)"
- *    version 1.0, which is available at http://www.irda.org/.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irias_object.h>
-
-#include <net/irda/ircomm_common.h>
-
-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, 
-				       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_waiti( struct ircomm_cb *self, IRCOMM_EVENT event, 
-				struct sk_buff *skb );
-static void ircomm_state_waitr( struct ircomm_cb *self, IRCOMM_EVENT event, 
-				struct sk_buff *skb );
-static void ircomm_state_conn( struct ircomm_cb *self, IRCOMM_EVENT event, 
-			       struct sk_buff *skb );
-static void ircomm_do_event( struct ircomm_cb *self, IRCOMM_EVENT event,
-			     struct sk_buff *skb);
-static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state);
-
-static void ircomm_discovery_indication(discovery_t *discovery);
-static void ircomm_tx_controlchannel(struct ircomm_cb *self );
-static int ircomm_proc_read(char *buf, char **start, off_t offset,
-			    int len, int unused);
-
-static void start_discovering(struct ircomm_cb *self);
-static void query_lsapsel(struct ircomm_cb * self);
-static void query_parameters(struct ircomm_cb *self);
-static void queryias_done(struct ircomm_cb *self);
-static void ircomm_getvalue_confirm(int result, __u16 obj_id, 
-				    struct ias_value *value, void *priv);
-
-
-struct ircomm_cb *discovering_instance;
-
-/*
- * debug parameter ircomm_cs:
- *  0 = client/server, 1 = client only 2 = server only
- * usage for example: 
- *  insmod ircomm ircomm_cs=1
- *  LILO boot : Linux ircomm_cs=2   etc.
- */
-
-static int ircomm_cs = 0;
-MODULE_PARM(ircomm_cs, "i");
-
-
-
-static char *ircommstate[] = {
-	"IDLE",
-
-	"DISCOVERY_WAIT",
-	"QUERYPARAM_WAIT",
-	"QUERYLSAP_WAIT",
-
-	"WAITI",
-	"WAITR",
-	"CONN",
-};
-
-static char *ircommservicetype[] = {
-	"N/A",
-	"THREE_WIRE_RAW",
-	"THREE_WIRE",
-	"NINE_WIRE",
-	"CENTRONICS",
-};
-static char *ircommporttype[] = {
-	"Unknown",
-	"SERIAL",
-	"PARALLEL",
-};
-
-
-struct ircomm_cb **ircomm = NULL;
-
-static char *ircommevent[] = {
-	"IRCOMM_CONNECT_REQUEST",
-	"TTP_CONNECT_INDICATION",
-	"LMP_CONNECT_INDICATION",
-
-	"TTP_CONNECT_CONFIRM",
-	"TTP_DISCONNECT_INDICATION",
-	"LMP_CONNECT_CONFIRM",
-	"LMP_DISCONNECT_INDICATION",
-
-	"IRCOMM_CONNECT_RESPONSE",
-	"IRCOMM_DISCONNECT_REQUEST",
-
-	"TTP_DATA_INDICATION",
-	"IRCOMM_DATA_REQUEST",
-	"LMP_DATA_INDICATION",
-	"IRCOMM_CONTROL_REQUEST",
-
-	"DISCOVERY_INDICATION",
-	"GOT_PARAMETERS",
-	"GOT_LSAPSEL",
-	"QUERYIAS_ERROR",
-};
-
-#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry *proc_irda;
-#endif
-
-static void (*state[])( struct ircomm_cb *self, IRCOMM_EVENT event,
-			struct sk_buff *skb) = 
-{
-	ircomm_state_idle,
-
-	ircomm_state_discoverywait,
-	ircomm_state_queryparamwait,
-	ircomm_state_querylsapwait,
-
-	ircomm_state_waiti,
-	ircomm_state_waitr,
-	ircomm_state_conn,
-};
-
-__initfunc(int ircomm_init(void))
-{
-	int i;
-
-	printk( "Linux-IrDA: IrCOMM protocol ( revision:%s ) \n",
-		revision_date);
-	DEBUG( 4, __FUNCTION__"()\n");
-
-	/* allocate master array */
-
-	ircomm = (struct ircomm_cb **) kmalloc( sizeof(struct ircomm_cb *) *
-						IRCOMM_MAX_CONNECTION,
-						GFP_KERNEL);
-	if ( ircomm == NULL) {
-		printk( KERN_ERR __FUNCTION__"(): kmalloc failed!\n");
-		return -ENOMEM;
-	}
-
-	memset( ircomm, 0, sizeof(struct ircomm_cb *) * IRCOMM_MAX_CONNECTION);
-
-	/* initialize structures */
-	   
-	for(i = 0;i < IRCOMM_MAX_CONNECTION; i++){
-		ircomm[i] = kmalloc( sizeof(struct ircomm_cb), GFP_KERNEL );
-
-		if(!ircomm[i]){
-			printk( KERN_ERR __FUNCTION__"(): kmalloc failed!\n");
-			return -ENOMEM;
-		} 
-
-		
-		memset( ircomm[i], 0, sizeof(struct ircomm_cb));
-
-		ircomm[i]->magic = IRCOMM_MAGIC;
-		/* default settings */
-		ircomm[i]->data_format = CS8;
-		ircomm[i]->flow_ctrl = USE_RTS|USE_DTR;  /*TODO: is this OK? */
-		ircomm[i]->xon_char = 0x11; 
-		ircomm[i]->xoff_char = 0x13;
-		ircomm[i]->enq_char = 0x05;
-		ircomm[i]->ack_char = 0x06;  
-
-		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_MAX_HEADER_SIZE);
-
-	}
-
-	/*
-	 * we register /proc/irda/ircomm
-	 */
-
-#ifdef CONFIG_PROC_FS
-	create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
-#endif /* CONFIG_PROC_FS */
-
-	discovering_instance = NULL;
-	return 0;
-}
-
-#ifdef MODULE
-void ircomm_cleanup(void)
-{
-	int i;
-
-	DEBUG( 4, "ircomm:cleanup_module\n");
-	/*
-	 * free some resources
-	 */
-	if (ircomm) {
-		for (i=0; i<IRCOMM_MAX_CONNECTION; i++) {
-			if (ircomm[i]) {
-
-				if(ircomm[i]->ctrl_skb){
-					dev_kfree_skb(ircomm[i]->ctrl_skb);
-
-					ircomm[i]->ctrl_skb = NULL;
-				}
-
-				DEBUG( 4, "freeing structures(%d)\n",i);
-				kfree(ircomm[i]);
-				ircomm[i] = NULL;
-			}
-		}
-		DEBUG( 4, "freeing master array\n");
-		kfree(ircomm);
-		ircomm = NULL;
-	}
-
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("ircomm", proc_irda);
-#endif /* CONFIG_PROC_FS */
-}
-#endif /* MODULE */
-
-/*
- * ---------------------------------------------------------------------- 
- * callbacks which accept incoming indication/confirm from IrTTP  (or IrLMP)
- * ---------------------------------------------------------------------- 
- */
-
-static int ircomm_accept_data_indication(void *instance, void *sap, 
-					 struct sk_buff *skb)
-{
-	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;);
-       
-	DEBUG(4,__FUNCTION__"():\n");
-	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 max_sdu_size, 
-					  __u8 max_header_size,
-					  struct sk_buff *skb)
-{
-	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;);
-
-	DEBUG(0,__FUNCTION__"(): got connected!\n");
-
-	if (max_sdu_size == SAR_DISABLE)
-		self->tx_max_sdu_size =(qos->data_size.value - max_header_size
-					- COMM_HEADER_SIZE);
-	else {
-		ASSERT(max_sdu_size >= COMM_DEFAULT_SDU_SIZE, return;);
-		/* use fragmentation */
-		self->tx_max_sdu_size = max_sdu_size - COMM_HEADER_SIZE;
-	}
-
-	self->qos = qos;
-	self->max_header_size = max_header_size + COMM_HEADER_SIZE;
-	self->null_modem_mode = 0;         /* disable null modem emulation */
-
-	ircomm_do_event(self, TTP_CONNECT_CONFIRM, skb);
-}
-
-static void ircomm_accept_connect_indication(void *instance, void *sap,
-					     struct qos_info *qos,
-					     __u32 max_sdu_size,
-					     __u8 max_header_size,
-					     struct sk_buff *skb)
-{
-	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;);
-
-	DEBUG(0,__FUNCTION__"()\n");
-
-	if (max_sdu_size == SAR_DISABLE)
-		self->tx_max_sdu_size =(qos->data_size.value - max_header_size
-					- COMM_HEADER_SIZE);
-	else
-		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 */
-	wake_up_interruptible( &self->discovery_wait);
-	wake_up_interruptible( &self->ias_wait);
-
-}
-
-static void ircomm_accept_disconnect_indication(void *instance, void *sap, 
-					 LM_REASON reason,
-					 struct sk_buff *skb)
-{
-	struct ircomm_cb *self = (struct ircomm_cb *)instance;
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-
-	DEBUG(0,__FUNCTION__"():\n");
-	ircomm_do_event( self, TTP_DISCONNECT_INDICATION, skb);
-
-}
-
-static void ircomm_accept_flow_indication( void *instance, void *sap,
-					   LOCAL_FLOW cmd)
-{
-	IRCOMM_CMD command;
-	struct ircomm_cb *self = (struct ircomm_cb *)instance;
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-
-	switch(cmd){
-	case FLOW_START:
-		DEBUG(4,__FUNCTION__"():START\n"); 
-		command = TX_READY;
-		self->ttp_stop = 0;
-		if(self->notify.flow_indication)
-			self->notify.flow_indication( self->notify.instance, 
-						      self, command);
-		break;
-		
-	case FLOW_STOP:
-		DEBUG(4,__FUNCTION__":STOP\n"); 
-		command = TX_BUSY;
-		self->ttp_stop = 1;
-		if(self->notify.flow_indication)
-			self->notify.flow_indication( self->notify.instance, 
-						      self, command);
-		break;
-
-	default:
-		DEBUG(0,__FUNCTION__"();unknown status!\n"); 
-	}
-
-}
-
-
-/*
- * ircomm_discovery_indication()
- *    Remote device is discovered, try query the remote IAS to see which
- *    device it is, and which services it has.
- */
-
-static void ircomm_discovery_indication(discovery_t *discovery)
-{
-	struct ircomm_cb *self;
-
-	self = discovering_instance;
-	if(self == NULL)
-		return;
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
-	self->daddr = discovery->daddr;
-	self->saddr = discovery->saddr;
-
-	DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr);
-
-	ircomm_do_event(self, DISCOVERY_INDICATION, NULL);
-	return;
-}
-
-/*
- * ircomm_getvalue_confirm()
- * handler for iriap_getvaluebyclass_request() 
- */
-static void ircomm_getvalue_confirm(int result, __u16 obj_id, 
-				    struct ias_value *value, void *priv)
-{
-	struct ircomm_cb *self = (struct ircomm_cb *) priv;
-	struct sk_buff *skb= NULL;
-	__u8 *frame;
-	__u8 servicetype = 0 ;
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-
-	/* Check if request succeeded */
-	if (result != IAS_SUCCESS) {
-		DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
-		ircomm_do_event(self, QUERYIAS_ERROR, NULL);
-		return;
-	}
-
-	DEBUG(4, __FUNCTION__"():type(%d)\n", value->type);
-
-	self->ias_type = value->type;
-	switch(value->type){
- 	case IAS_OCT_SEQ:
-		
-		DEBUG(4, __FUNCTION__"():got octet sequence:\n");
-#if 0
-		{
-			int i;
-			for ( i=0;i<value->len;i++)
-				printk("%02x",
-				       (__u8)(*(value->t.oct_seq + i)));
-			printk("\n");
-		}
-#endif
-		skb = dev_alloc_skb((value->len) + 2);
-		ASSERT(skb != NULL, ircomm_do_event(self, QUERYIAS_ERROR, NULL);return;);
-		frame = skb_put(skb,2);
-		/* MSB first */
-		frame[0] = ( value->len >> 8 ) & 0xff;
-		frame[1] = value->len & 0xff;
-		
-		frame = skb_put(skb,value->len);
-		memcpy(frame, value->t.oct_seq, value->len);
-		ircomm_parse_tuples(self, skb, IAS_PARAM);
-		kfree_skb(skb);
-
-		/* 
-		 * check if servicetype we want is available 
-		 */
-
-		DEBUG(0,__FUNCTION__"():peer capability is:\n");
-		DEBUG(0,"3wire raw: %s\n",
-		      ((self->peer_servicetype & THREE_WIRE_RAW) ? "yes":"no"));
-		DEBUG(0,"3wire    : %s\n",
-		      ((self->peer_servicetype & THREE_WIRE) ? "yes":"no"));
-		DEBUG(0,"9wire    : %s\n",
-		      ((self->peer_servicetype & NINE_WIRE) ? "yes":"no"));
-		DEBUG(0,"IEEE1284 : %s\n",
-		      ((self->peer_servicetype & CENTRONICS) ? "yes":"no"));
-
-		self->servicetype &= self->peer_servicetype;
-		if(!(self->servicetype)){
-			DEBUG(0,__FUNCTION__"(): servicetype mismatch!\n");
-			ircomm_do_event(self, QUERYIAS_ERROR, NULL);
-			break;
-		}
-
-		/*
-		 * then choose better one 
-		 */
-		if(self->servicetype & THREE_WIRE_RAW)
-			servicetype = THREE_WIRE_RAW;
-		if(self->servicetype & THREE_WIRE)
-			servicetype = THREE_WIRE;
-		if(self->servicetype & NINE_WIRE)
-			servicetype = NINE_WIRE;
-		if(self->servicetype & CENTRONICS)
-			servicetype = CENTRONICS;
-
-		self->servicetype = servicetype;
-
-		/* enter next state */
-		ircomm_do_event(self, GOT_PARAMETERS, NULL);
-		break;
-
-	case IAS_INTEGER:
-		/* LsapSel seems to be sent to me */	
-		DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer);
-
-		if ( value->t.integer == -1){
-			DEBUG( 0, __FUNCTION__"():invalid value!\n");
-			ircomm_do_event(self, QUERYIAS_ERROR, NULL);
-			return;
-		}
-		self->dlsap = value->t.integer;
-		ircomm_do_event(self, GOT_LSAPSEL, NULL);
-		break;
-
-	case IAS_MISSING:
-		DEBUG( 0, __FUNCTION__":got IAS_MISSING\n");
-		ircomm_do_event(self, QUERYIAS_ERROR, NULL);
-		break;
-   
-	default:
-		DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n");
-		ircomm_do_event(self, QUERYIAS_ERROR, NULL);
-		break;
-	}
-}
-
-
-
-/* 
- * ----------------------------------------------------------------------
- * Impl. of actions (descrived in section 7.4 of the reference)
- * ----------------------------------------------------------------------
- */
-
-static void issue_connect_request(struct ircomm_cb *self,
-				  struct sk_buff *userdata )
-{
-	/* TODO: we have to send/build userdata field which contains 
-	   InitialControlParameters */
-
-	switch(self->servicetype){
-	case THREE_WIRE_RAW:
-		DEBUG(0, __FUNCTION__"():THREE_WIRE_RAW is not implemented\n");
-		break;
-
-	case DEFAULT: 
-	case THREE_WIRE:
-	case NINE_WIRE:
-	case CENTRONICS:
-
-		irttp_connect_request(self->tsap, self->dlsap, 
-				      self->saddr, self->daddr, 
-				      NULL, self->rx_max_sdu_size, userdata); 
-		break;
-
-	default:
-		printk(KERN_ERR __FUNCTION__"():Illegal servicetype %d\n"
-		       ,self->servicetype);
-	}
-}	
-
-static void disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb)
-{
-
-	/*
-	 * Not implemented parameter"Reason".That is optional.
-	 * What is reason? maybe discribed in irmod.h?
-	 */
-
-	if(self->notify.disconnect_indication)
-		self->notify.disconnect_indication( self->notify.instance,
-						    self,
-						    self->reason, skb);
-						    
-}
-
-static void connect_indication(struct ircomm_cb *self, struct qos_info *qos, 
-			       struct sk_buff *skb)
-{
-
-/* If controlparameters don't exist, we use the servicetype"DEFAULT".*/
-/* 	if( !ircomm_parse_controlchannel( self, data)) */
-/* 		self->servicetype = DEFAULT;     TODOD:fix this! TH */
-
-	if (self->notify.connect_indication)
-		self->notify.connect_indication(self->notify.instance, self, 
-						qos, self->tx_max_sdu_size,
-						self->max_header_size, skb);
-}
-    
-#if 0
-/*   it's for THREE_WIRE_RAW.*/
-static void connect_indication_three_wire_raw(void)
-{ 
-	DEBUG(0,"ircomm:connect_indication_threewire():not implemented!");
-}    
-#endif 
-
-
-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, 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->rx_max_sdu_size, skb);
-}
-
-static void issue_disconnect_request(struct ircomm_cb *self,
-				     struct sk_buff *userdata)
-{
-	if(self->servicetype == THREE_WIRE_RAW){
-		DEBUG(0,__FUNCTION__"():3wireraw is not implemented\n");
-	}
-	else
-		irttp_disconnect_request(self->tsap, userdata, 
-					 self->disconnect_priority);
-}
-    
-static void issue_data_request(struct ircomm_cb *self,
-			       struct sk_buff *userdata )
-{
-	int err;
-
-	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){
-		printk(KERN_ERR __FUNCTION__":ttp_data_request failed\n");
-		if (userdata)
-			dev_kfree_skb( userdata);
-	}
-	self->tx_packets++;
-}
-
-static void issue_control_request(struct ircomm_cb *self,
-				  struct sk_buff *userdata)
-{
-	int err;
-
-	DEBUG(4,__FUNCTION__"()\n"); 
-	if (self->servicetype == THREE_WIRE_RAW) {
-		DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented\n");
-		
-	}
-	else 
-	{
-		err = irttp_data_request(self->tsap,userdata);
-		if(err)
-		{
-			printk( __FUNCTION__"():ttp_data_request failed\n");
-			if(userdata)
-				dev_kfree_skb(userdata);
-		}
-		else
-			self->tx_controls++;
-
-		self->pending_control_tuples = 0;
-	}
-}
-
-static void process_data(struct ircomm_cb *self, struct sk_buff *skb )
-{
-	
-	DEBUG(4,__FUNCTION__":skb->len=%d, ircomm header = 1, clen=%d\n",
-	      (int)skb->len ,(int)skb->data[0]);
-
-	/* we have to parse control channel when receiving.  (see
-	 * page17 of IrCOMM standard) but it is not parsed here since
-	 * upper layer may have some receive buffer.
-	 *
-	 * hence upper layer have to parse it when it consumes a packet.
-	 *   -- TH
-	 */
-
- 	/* ircomm_parse_control(self, skb, CONTROL_CHANNEL); */
-
-	if (self->notify.data_indication && skb->len)
-		self->notify.data_indication(self->notify.instance, self,
-					     skb);
-}
-
-int ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
-{
-	/* Not implemented yet:THREE_WIRE_RAW service uses this function.  */
-	DEBUG(0,"ircomm_data_indication:not implemented yet!\n");
-
-	return 0;
-}
-
-
-/* 
- * ----------------------------------------------------------------------
- * Implementation of state chart,
- * descrived in section 7.1 of the specification.
- * ----------------------------------------------------------------------
- */
-
-static void ircomm_do_event( struct ircomm_cb *self, IRCOMM_EVENT event,
-			     struct sk_buff *skb) 
-{
-	
-	DEBUG( 4, __FUNCTION__": STATE = %s, EVENT = %s\n",
-	       ircommstate[self->state], ircommevent[event]);
-	(*state[self->state])(self, event, skb);
-}
-
-static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state) 
-{
-	self->state = state;
-	DEBUG( 0, __FUNCTION__": NEXT STATE=%d(%s), servicetype=(%d)\n", 
-	       (int)state, ircommstate[self->state],self->servicetype);
-}
-
-
-
-/*
- * ircomm_state_idle
- */
-
-static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, 
-			       struct sk_buff *skb )
-{
-	switch (event){
-	case IRCOMM_CONNECT_REQUEST:
-
-		/* ircomm_next_state(self, COMM_WAITI); */
-		/* issue_connect_request( self, skb ); */
-
-		ircomm_next_state(self, COMM_DISCOVERY_WAIT);
-		start_discovering(self);
-		break;
-		
-	case TTP_CONNECT_INDICATION:
-
-		ircomm_next_state(self, COMM_WAITR);
-		connect_indication( self, self->qos, skb);
-		break;
-
-	case LMP_CONNECT_INDICATION:
-
-		DEBUG(0,__FUNCTION__"():LMP_CONNECT_IND is notimplemented!");
- 		/* connect_indication_three_wire_raw(); */
- 		/* ircomm_next_state(self, COMM_WAITR); */
-		break;
-
-	default:
-		DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
-		      event, ircommevent[event]);
-	}
-}
-
-/*
- * ircomm_state_discoverywait
- */
-static void ircomm_state_discoverywait(struct ircomm_cb *self, 
-				       IRCOMM_EVENT event, 
-				       struct sk_buff *skb )
-{
-	switch(event){
-
-	case TTP_CONNECT_INDICATION:
-
-		ircomm_next_state(self, COMM_WAITR);
-		queryias_done(self);
-		connect_indication( self, self->qos, skb);
-		break;
-
-	case DISCOVERY_INDICATION:
-		ircomm_next_state(self, COMM_QUERYPARAM_WAIT);
-		query_parameters(self);
-		break;
-
-	case IRCOMM_DISCONNECT_REQUEST:
-		ircomm_next_state(self, COMM_IDLE);
-		queryias_done(self);
-		break;
-
-	case QUERYIAS_ERROR:
-		ircomm_next_state(self, COMM_IDLE);
-		disconnect_indication(self, NULL);
-		queryias_done(self);
-		break;
-
-	default:
-		DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
-		      event, ircommevent[event]);
-	}
-}
-
-/*
- * ircomm_state_queryparamwait
- */
-
-static void ircomm_state_queryparamwait(struct ircomm_cb *self, 
-					IRCOMM_EVENT event, 
-					struct sk_buff *skb)
-{
-	switch (event) {
-	case TTP_CONNECT_INDICATION:
-
-		ircomm_next_state(self, COMM_WAITR);
-		connect_indication( self, self->qos, skb);
-		break;
-
-	case GOT_PARAMETERS:
-		
-		ircomm_next_state(self, COMM_QUERYLSAP_WAIT);
-		query_lsapsel( self );
-		break;
-
-	case IRCOMM_DISCONNECT_REQUEST:
-		ircomm_next_state(self, COMM_IDLE);
-		queryias_done(self);
-		break;
-
-	case QUERYIAS_ERROR:
-		ircomm_next_state(self, COMM_IDLE);
-		disconnect_indication(self, NULL);
-		queryias_done(self);
-		break;
-
-	default:
-		DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
-		      event, ircommevent[event]);
-	}
-}
-
-/*
- * ircomm_state_querylsapwait
- */
-
-static void ircomm_state_querylsapwait(struct ircomm_cb *self, 
-				       IRCOMM_EVENT event, 
-				       struct sk_buff *skb )
-{
-	switch (event) {
-
-	case TTP_CONNECT_INDICATION:
-
-		ircomm_next_state(self, COMM_WAITR);
-		connect_indication( self, self->qos, skb);
-		break;
-
-	case GOT_LSAPSEL:
-		
-		ircomm_next_state(self, COMM_WAITI);
-		queryias_done(self);
-		issue_connect_request( self, skb );
-		break;
-
-	case IRCOMM_DISCONNECT_REQUEST:
-		ircomm_next_state(self, COMM_IDLE);
-		queryias_done(self);
-		break;
-
-	case QUERYIAS_ERROR:
-		ircomm_next_state(self, COMM_IDLE);
-		disconnect_indication(self, NULL);
-		queryias_done(self);
-		break;
-
-
-	default:
-		DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
-		      event, ircommevent[event]);
-	}
-}
-
-/*
- * ircomm_state_waiti
- */
-
-static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, 
-			  struct sk_buff *skb )
-{
-	switch (event) {
-	case TTP_CONNECT_CONFIRM:
-		ircomm_next_state(self, COMM_CONN);
-		connect_confirm(self, skb );
-		break;
-	case TTP_DISCONNECT_INDICATION:
-		ircomm_next_state(self, COMM_IDLE);
-		disconnect_indication(self, skb);
-		break;
-/* 	case LMP_CONNECT_CONFIRM: */
-/* 		ircomm_connect_cnfirmation; */
-/* 		ircomm_next_state(self, COMM_CONN); */
-/* 		break; */
-/* 	case LMP_DISCONNECT_INDICATION: */
-/* 		ircomm_disconnect_ind; */
-/* 		ircomm_next_state(self, COMM_IDLE); */
-/* 		break; */
-	default:
-		DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
-		      event, ircommevent[event]);
-	}
-}
-
-/*
- * ircomm_state_waitr
- */
-static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, 
-			       struct sk_buff *skb ) 
-{
-	switch (event) {
-	case IRCOMM_CONNECT_RESPONSE:
-
-	        /* issue_connect_response */
-		
-		if (self->servicetype==THREE_WIRE_RAW) {
-			DEBUG(0,__FUNCTION__"():3WIRE_RAW is not implemented\n");
-			/* irlmp_connect_response(Vpeersap,
-			 *                         ACCEPT,null);
-			 */
-		} else {
-			ircomm_next_state(self, COMM_CONN);
-			issue_connect_response(self, skb);
-		}
-		break;
-
-	case IRCOMM_DISCONNECT_REQUEST:
-		ircomm_next_state(self, COMM_IDLE);
-		issue_disconnect_request(self, skb);
-		queryias_done(self);
-		break;
-
-	case TTP_DISCONNECT_INDICATION:
-		ircomm_next_state(self, COMM_IDLE);
-		disconnect_indication(self, skb);
-		break;
-
-	case DISCOVERY_INDICATION:
-		DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
-		queryias_done(self);
-		break;
-	case GOT_PARAMETERS:
-		DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
-		queryias_done(self);
-		break;
-	case GOT_LSAPSEL:
-		DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
-		queryias_done(self);
-		break;
-
-/* 	case LMP_DISCONNECT_INDICATION: */
-/* 		disconnect_indication();		 */
-/* 		ircomm_next_state(self, COMM_IDLE);		 */
-/* 		break; */
-	default:
-		DEBUG(0,"ircomm_state_waitr:unknown event =%d(%s)\n",
-		      event, ircommevent[event]);
-	}
-}
-
-/*
- * ircomm_state_conn
- */
-
-static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, 
-			      struct sk_buff *skb )
-{
-	switch (event) {
-	case TTP_DATA_INDICATION:
-		process_data(self, skb);
-		break;
-	case IRCOMM_DATA_REQUEST:
-		issue_data_request(self, skb);
-		break;
-/* 	case LMP_DATA_INDICATION: */
-/* 		ircomm_data_indicated(); */
-/* 		break; */
-	case IRCOMM_CONTROL_REQUEST:
-		issue_control_request(self, skb);
-		break;
-	case TTP_DISCONNECT_INDICATION:
-		ircomm_next_state(self, COMM_IDLE);
-		disconnect_indication(self, skb);
-		break;
-	case IRCOMM_DISCONNECT_REQUEST:
-		ircomm_next_state(self, COMM_IDLE);
-		issue_disconnect_request(self, skb);
-		queryias_done(self);
-		break;
-/* 	case LM_DISCONNECT_INDICATION: */
-/* 		disconnect_indication(); */
-/* 		ircomm_next_state(self, COMM_IDLE); */
-/* 		break; */
-
-	case DISCOVERY_INDICATION:
-		DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
-		queryias_done(self);
-		break;
-	case GOT_PARAMETERS:
-		DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
-		queryias_done(self);
-		break;
-	case GOT_LSAPSEL:
-		DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
-		queryias_done(self);
-		break;
-
-	default:
-		DEBUG(0,"ircomm_state_conn:unknown event =%d(%s)\n",
-		      event, ircommevent[event]);
-	}
-}
-
-/*
- *  ----------------------------------------------------------------------
- *  IrCOMM service interfaces and supporting functions
- *
- *  ----------------------------------------------------------------------
- */
-
-/*
- * Function start_discovering (self)
- *
- *    Start discovering and enter DISCOVERY_WAIT state
- *
- */
-static void start_discovering(struct ircomm_cb *self)
-{
-	__u16  hints; 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-	DEBUG(4,__FUNCTION__"():servicetype = %d\n",self->servicetype);
-	
-
-	hints = irlmp_service_to_hint(S_COMM);
-
-	DEBUG(1,__FUNCTION__"():start discovering..\n");
-	switch (ircomm_cs) {
-	case 0:
-		MOD_INC_USE_COUNT;
-		self->queryias_lock = 1;
-		discovering_instance = self;
-		self->skey = irlmp_register_service(hints);
-		self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
-					     NULL);
-		break;
-		
-	case 1:    /* client only */
-		MOD_INC_USE_COUNT;
-		self->queryias_lock = 1;
-		discovering_instance = self;
-		DEBUG( 0, __FUNCTION__"():client only mode\n");
-		self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
-					     NULL);
-		break;
-
-	case 2:     /*  server only  */
-	default:
-		DEBUG( 0, __FUNCTION__"():server only mode\n");
-		self->skey = irlmp_register_service(hints);
-		discovering_instance = NULL;
-		break;
-	}
-	
-	return;
-}
-
-/*
- * queryias_done(self)
- *
- * 
- */
-
-/*
- * 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){
-		self->queryias_lock = 0;
-		discovering_instance = NULL;
-		MOD_DEC_USE_COUNT;
-		irlmp_unregister_client(self->ckey);
-	}
-	if (ircomm_cs != 1)
-		irlmp_unregister_service(self->skey);
-	return;
-}
-
-
-
-static void query_parameters(struct ircomm_cb *self)
-{
-
-	DEBUG(0, __FUNCTION__"():querying IAS: Parameters..\n");
-	iriap_getvaluebyclass_request( "IrDA:IrCOMM", "Parameters",
-				       self->saddr, self->daddr,
-				       ircomm_getvalue_confirm, self );
-}
-
-static void query_lsapsel(struct ircomm_cb * self)
-{
-	DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
-
-	if (!(self->servicetype & THREE_WIRE_RAW)) {
-		iriap_getvaluebyclass_request( 
-			"IrDA:IrCOMM", "IrDA:TinyTP:LsapSel",
-			self->saddr, self->daddr,
-			ircomm_getvalue_confirm, self );
-	} else {
-		DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n");
-	}
-}
-
-/*
- * 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)
-{
-	/*
-	 * TODO:build a packet which contains "initial control parameters"
-	 * and send it with connect_request
-	 */
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-
-
-	DEBUG(1, __FUNCTION__"():sending connect_request...\n");
-
-	self->servicetype= servicetype;
-	/* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
-
-	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 max_sdu_size)
-{
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-	/* ASSERT( userdata != NULL, return;); */
-
-	DEBUG(4,"ircomm_connect_response:\n");
-
-	/*
-	 * TODO:build a packet which contains "initial control parameters"
-	 * and send it with connect_response
-	 */
-
-	if (!userdata){
-		/* FIXME: check for errors and initialize? DB */
-		userdata = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
-		if (userdata == NULL)
-			return;
-
-		skb_reserve(userdata,COMM_MAX_HEADER_SIZE);
-	}
-
-	/* enable null-modem emulation (i.e. server mode )*/
-	self->null_modem_mode = 1;
-
-	self->rx_max_sdu_size = max_sdu_size;
-	
-	ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata);
-}	
-
-void ircomm_disconnect_request(struct ircomm_cb *self, 
-			       struct sk_buff *userdata,
-			       int priority)
-{
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-	DEBUG(0,__FUNCTION__"()\n");
-
-#if 0
-	/* unregister layer */
-	switch (ircomm_cs) {
-	case 1:    /* client only */
-		irlmp_unregister_client(ckey);
-		break;
-
-	case 2:     /*  server only  */
-		irlmp_unregister_service(skey);
-		break;
-	case 0:
-	default:
-		irlmp_unregister_client(ckey);
-		irlmp_unregister_service(skey);
-		break;
-	}
-#endif
-
-	self->disconnect_priority = priority;
-	if(priority != P_HIGH)
-		self->disconnect_priority = P_NORMAL;
-
-	ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata);
-}	
-
-
-int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *userdata)
-{
-	__u8 * frame;
-
-	DEBUG(4,__FUNCTION__"()\n");
-	ASSERT( self != NULL, return -EFAULT;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return -EFAULT;);
-	ASSERT( userdata != NULL, return -EFAULT;);
-	
-
-	if(self->state != COMM_CONN){
-		DEBUG(4,__FUNCTION__"():not connected, data is ignored\n");
-		return -EINVAL;
-	}
-
-	if(self->ttp_stop)
-		return -EBUSY;
-
-	if(self->control_ch_pending){
-		/* send control_channel */
-		ircomm_tx_controlchannel(self);
-	}
-
-	if(self->ttp_stop)
-		return -EBUSY;
-
-	/* add "clen" field */
-	frame = skb_push(userdata,1);
-	frame[0]=0;          /* without control channel */
-
-	ircomm_do_event(self, IRCOMM_DATA_REQUEST, userdata);
-	return 0;
-}
-
-/*
- *  ----------------------------------------------------------------------
- *  IrCOMM_control.req and friends
- *
- *  ----------------------------------------------------------------------
- */
-
-
-static void ircomm_tx_controlchannel(struct ircomm_cb *self )
-{
-
-	__u8 clen;
-	struct sk_buff *skb = self->ctrl_skb;
-	
-	DEBUG(4,__FUNCTION__"()\n");
-	/* 'self' should have been checked */
-	ASSERT(!self->ttp_stop, return ;);
-	ASSERT(self->state == COMM_CONN, return ;);
-
-	/* add "clen" field */
-
-	clen=skb->len;
-	ASSERT(clen != 0,return;);
-
-	skb_push(skb,1);
-	skb->data[0]=clen;
-
-#if 0
-	printk("tx_ctrl:");
-	{
-		int i;
-		for ( i=0;i<skb->len;i++)
-			printk("%02x", skb->data[i]);
-		printk("\n");
-	}
-#endif
-	
-	ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb);
-	self->control_ch_pending = 0;
-
-	skb = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
-	ASSERT(skb != NULL, return ;);
-
-	skb_reserve(skb,COMM_MAX_HEADER_SIZE);
-	self->ctrl_skb = skb;
-}
-
-
-static void append_tuple(struct ircomm_cb *self, __u8 instruction, __u8 pl , 
-			 __u8 *value)
-{
-	__u8 *frame;
-	struct sk_buff *skb;
-	int i,c = 0;
-	unsigned long flags;
-
-	save_flags(flags);cli();
-
-	skb = self->ctrl_skb;
-	ASSERT(skb != NULL, return;);
-	
-	if(skb_tailroom(skb) < (pl+2)){
-		DEBUG(0, __FUNCTION__"there's no room.. ignore it\n");
-		self->ignored_control_tuples++;
-		restore_flags(flags);
-		return;
-	}
-
-	frame = skb_put(skb,pl+2);
-	frame[c++] = instruction;     /* PI */
-	frame[c++] = pl;              /* PL */
-	for(i=0; i < pl ; i++)
-		frame[c++] = *value++;   /* PV */
-	restore_flags(flags);	
-	self->pending_control_tuples++;
-	self->control_ch_pending = 1;
-}
-
-/*
- * 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)
-{
-
-	__u8  pv[32];      /* 32 max, for PORT_NAME */
-	__u8  *value = &pv[0];
-	__u32 temp;
-	int notsupp=0;
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-
-	if(self->servicetype == THREE_WIRE_RAW){
-		DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW shuold not use me!\n");
-		return;
-	}
-
-	DEBUG(4,__FUNCTION__"()\n");
-
-	/* find parameter and its length */
-
-	if(self->servicetype == THREE_WIRE) goto threewire;
-	if(self->servicetype == NINE_WIRE) goto ninewire;
-
-
-	/* FIXME: centronics service is not fully implemented yet*/
-	switch(instruction){
-	case IEEE1284_MODE_SUPPORT:
-	case IEEE1284_DEVICEID:
-		append_tuple(self,instruction,0,NULL);
-		break;
-	case STATUS_QUERY:
-		append_tuple(self,instruction,0,NULL);
-		break;
-	case SET_BUSY_TIMEOUT:
-		value[0] = self->busy_timeout;
-		append_tuple(self,instruction,1,value);
-		break;
- 	case IEEE1284_ECP_EPP_DATA_TRANSFER: 
-		value[0] = self->ecp_epp_mode;
-		value[1] = self->channel_or_addr;
-		append_tuple(self,instruction,2,value); 
-		break; 
-	default:
-		notsupp=1;
-	}
-
- ninewire:
-	switch(instruction){
-	case POLL_FOR_LINE_SETTINGS:
-		append_tuple(self,instruction,0,NULL);
-		break;
-	case DTELINE_STATE:		
-		if(self->null_modem_mode){
-			/* null modem emulation */
-
-			/* output RTS as CTS */
-
-			if(self->dte & DELTA_RTS)
-				value[0] = DELTA_CTS;
-			if(self->dte & MCR_RTS)
-				value[0] |= MSR_CTS;
-
-			/* output DTR as {DSR & CD & RI} */
-
-			if(self->dte & DELTA_DTR)
-				value[0] |= (DELTA_DSR|DELTA_RI|DELTA_DCD);
-			if(self->dte & MCR_DTR)
-				value[0] |= (MSR_DSR|MSR_RI|MSR_DCD);
-			append_tuple(self,DCELINE_STATE,1,value);
-		}else{
-			value[0] = self->dte;
-			append_tuple(self,instruction,1,value);
-		}
-		self->dte &= ~(DELTA_RTS|DELTA_DTR);
-		break;
-
-	case DCELINE_STATE:		
-		value[0] = self->dce;
-		append_tuple(self,instruction,1,value);
-		break;
-
-	default:
-		notsupp=1;
-	}
-
- threewire:
-	switch(instruction){
-
-	case SERVICETYPE:
-		value[0] = self->servicetype;
-		append_tuple(self,instruction,1,value);
-		break;
-
-	case DATA_FORMAT:
-		value[0] = self->data_format;
-		append_tuple(self,instruction,1,value);
-		break;
-
-	case FLOW_CONTROL:
-		if(self->null_modem_mode){
-			/* inside out */
-			value[0]  = (self->flow_ctrl & 0x55) << 1;
-			value[0] |= (self->flow_ctrl & 0xAA) >> 1;
-		}else{
-			value[0] = self->flow_ctrl;
-		}
-		append_tuple(self,instruction,1,value);
-		break;
-
-	case LINESTATUS:
-		value[0] = self->line_status;
-		append_tuple(self,instruction,1,value);
-		break;
-
-	case BREAK_SIGNAL:
-		value[0] = self->break_signal;
-		append_tuple(self,instruction,1,value);
-		break;
-
-	case XON_XOFF_CHAR:
-		value[0] = self->xon_char;
-		value[1] = self->xoff_char;
-		append_tuple(self,instruction,2,value); 
-		break; 
-
-	case ENQ_ACK_CHAR:
-		value[0] = self->enq_char;
-		value[1] = self->ack_char;
-		append_tuple(self,instruction,2,value); 
-		break; 
-
-	case DATA_RATE:
-		temp = self->data_rate;
-		value[3] = (__u8)((temp >> 24) & 0x000000ff);
-		value[2] = (__u8)((temp >> 16) & 0x000000ff);
-		value[1] = (__u8)((temp >> 8) & 0x000000ff);
-		value[0] = (__u8)(temp & 0x000000ff);
- 		append_tuple(self,instruction,4,value);
- 		break;
-#if 0
-	case PORT_NAME:
-	case FIXED_PORT_NAME:
-		temp = strlen(&self->port_name);
-		if(temp < 32){
-			value = (__u8) (self->port_name);
-			append_tuple(self,instruction,temp,value);
-		}else
-			DEBUG(0,__FUNCTION__"() PORT_NAME:too long\n");
-#endif
-		break;
-
-	default:
-		if(notsupp)
-			DEBUG(0,__FUNCTION__"():instruction(0x%02x)is not"
-			      "implemented\n",instruction);
-	}
-
-
-}
-
-void ircomm_parse_tuples(struct ircomm_cb *self, struct sk_buff *skb, int type)
-{
-
-	__u8 *data;
-	__u8 pi,plen;
-	int clen = 0;
-	int indicate=0;
-
-	ASSERT(skb != NULL, return;);
-	ASSERT(self != NULL, return ;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return ;);
-
-
-#ifdef IRCOMM_DEBUG_TUPLE
-	DEBUG(0, __FUNCTION__"():tuple sequence is:\n");
-	{
-		int i;
-		for ( i=0;i< skb->len;i++)
-			printk("%02x", (__u8)(skb->data[i]));
-		printk("\n");
-	}
-#endif
-
-	data = skb->data;
-	if(type == IAS_PARAM)
-	{
-		clen = (data[0] << 8) & 0xff00;
-		clen |= data[1] & 0x00ff;
-		ASSERT( clen <= (skb->len - 2) && clen <= 1024, goto corrupted;);
-		DEBUG(4, __FUNCTION__"():IAS_PARAM len = %d\n",clen );
-		skb_pull( skb, 2);
-	}
-	else
-	{
-		/* CONTROL_CHANNEL */
-		clen = data[0];
-		ASSERT( clen < skb->len, goto corrupted;);
-		DEBUG(4, __FUNCTION__"():CONTROL_CHANNEL:len = %d\n",clen );
-		skb_pull( skb, 1);
-	}
-
-	while( clen >= 2 ){
-		data = skb->data;
-		indicate = 0;
-
-		/* 
-		 * parse controlparameters and set value into structure 
-		 */
-		pi = data[0];
-		plen = data[1];
-
-		ASSERT( clen >= 2+plen, goto corrupted; );
-		DEBUG(4, __FUNCTION__"():instruction=0x%02x,len=%d\n",
-		      pi, plen) ;
-
-
-		switch(pi)
-		{
-		case POLL_FOR_LINE_SETTINGS:
-			ircomm_control_request(self, DTELINE_STATE);
-			break;
-		
-		case SERVICETYPE:
-			self->peer_servicetype = data[2];
-			break;
-
-		case PORT_TYPE:
-			self->peer_port_type = data[2];
-			break;
-
-		case DATA_FORMAT:   
-			self->peer_data_format = data[2];
-			break;
-
-		case FLOW_CONTROL:
-			self->peer_flow_ctrl = data[2];
-			indicate = 1;
-			break;
-
-		case LINESTATUS:
-			self->peer_line_status = data[2];
-			indicate = 1;
-			break;
-
-		case BREAK_SIGNAL:
-			self->peer_break_signal = data[2];
-			/* indicate = 1; */
-			break;
-
-		case DCELINE_STATE:
-			self->peer_dce = data[2];
-			indicate = 1;
-			break;
-
-		case DTELINE_STATE:
-			if(self->null_modem_mode){
-				/* input DTR as {DSR & CD & RI} */
-				self->peer_dce = 0;
-				if(data[2] & DELTA_DTR)
-					self->peer_dce |= (DELTA_DSR|
-							   DELTA_RI|
-							   DELTA_DCD);
-				if(data[2] & MCR_DTR)
-					self->peer_dce |= (MSR_DSR|
-							   MSR_RI|
-							   MSR_DCD);
-				/* rts as cts */
-				if(data[2] & DELTA_RTS)
-					self->peer_dce |= DELTA_CTS;
-				if(data[2] & MCR_RTS)
-					self->peer_dce |= MSR_CTS;
-			}else{
-				self->peer_dte = data[2];
-			}
-			indicate = 1;			
-			break;
-			
-		case XON_XOFF_CHAR:
-			self->peer_xon_char = data[2];
-			self->peer_xoff_char = data[3];
-			indicate = 1;
-			break;
-
-		case ENQ_ACK_CHAR:
-			self->peer_enq_char = data[2];
-			self->peer_ack_char = data[3];
-			indicate = 1;
-			break;
-
-		case DATA_RATE:
-			self->peer_data_rate = (  data[5]<<24
-						  & data[4]<<16
-						  & data[3]<<8
-						  & data[2]);
-			indicate = 1;
-			break;
-
-		case PORT_NAME:
-			ASSERT(plen <= 32 , goto corrupted;);
-			memcpy(self->port_name, data + 2, plen);
-			*(__u8 *)(self->port_name+plen) = 0;
-			break;
-
-		case FIXED_PORT_NAME:
-			ASSERT(plen <= 32 , goto corrupted;);
-			memcpy(self->port_name, data + 2, plen);
-			*(__u8 *)(self->port_name+plen) = 0;
-			/* 
-			 * We should not connect if user of IrCOMM can't
-			 * recognize the port name
-			 */
-			self->port_name_critical = TRUE;
-			break;
-
-		default:
-			DEBUG(0, __FUNCTION__
-			      "():not implemented (PI=%d)\n", pi);
-		}
-
-
-		if(indicate && 
-		   self->notify.flow_indication && type == CONTROL_CHANNEL)
-		{
-			DEBUG(4,__FUNCTION__":indicating..:\n");
-			self->pi = pi;
-			if(self->notify.flow_indication)
-				self->notify.flow_indication(self->notify.instance,
-							     self,
-							     CONTROL_CHANNEL);
-		}
-		skb_pull(skb, 2+plen);
-		clen -= (2+plen);
-	}
-
-	return;
-
- corrupted:
-	skb_pull(skb, skb->len);   /* remove suspicious data */
-	return;
-}
-
-/*
- * ----------------------------------------------------------------------
- * Function ircomm_open_instance() ,ircomm_close_instance() and friends
- *
- * ircomm_open_instance discoveres the peer device and then issues a
- * connect request
- * ----------------------------------------------------------------------
- */
-
-
-
-struct ircomm_cb * ircomm_open_instance( struct notify_t client_notify)
-{
-	int i;
-	struct ircomm_cb *self = NULL;
-	struct notify_t notify;
-	unsigned long flags;
-
-	ASSERT(ircomm != NULL,return NULL;);
-	DEBUG(0,__FUNCTION__"():\n");
-
-	/* find free handle */
-
-	save_flags(flags);
-	cli();
-	for(i = 0; i < IRCOMM_MAX_CONNECTION; i++){
-		ASSERT(ircomm[i] != NULL,return(NULL););
-		if(!ircomm[i]->in_use){
-			self = ircomm[i];
-			break;
-		}
-	}
-
-	if (!self){
-		DEBUG(0,__FUNCTION__"():no free handle!\n");
-		return (NULL);
-	}
-
-	self->in_use = 1;
-	restore_flags(flags);
-
-	self->notify = client_notify;
-	self->ttp_stop = 0;
-	self->control_ch_pending = 0;
-
-	/* register callbacks */
-
-	irda_notify_init(&notify);
-	notify.data_indication = ircomm_accept_data_indication;
-	notify.connect_confirm = ircomm_accept_connect_confirm;
-	notify.connect_indication = ircomm_accept_connect_indication;
-	notify.flow_indication = ircomm_accept_flow_indication;
-	notify.disconnect_indication = ircomm_accept_disconnect_indication;
-	notify.instance = self;
-	strncpy( notify.name, "IrCOMM", NOTIFY_MAX_NAME);
-
-	self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
-				     &notify);
-	if(!self->tsap){
-		DEBUG(0,__FUNCTION__"failed to allocate tsap\n");
-		return NULL;
-	}
-
-	ircomm_next_state(self, COMM_IDLE);	
-	return (self);
-}
-
-int ircomm_close_instance(struct ircomm_cb *self)
-{
-	ASSERT( self != NULL, return -EIO;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return -EIO;);
-	ASSERT( self->ctrl_skb != NULL, return -EIO;);
-
-	DEBUG(0,__FUNCTION__"()\n");
-
-	/* shutdown ircomm layer */
-	if(self->state != COMM_IDLE && self->state != COMM_WAITI)
-	{
-		DEBUG(0,__FUNCTION__"():force disconnecting..\n");
-		ircomm_disconnect_request(self, NULL, P_HIGH);
-	}
-
-	skb_trim(self->ctrl_skb,0);
-	/* remove a tsap */
-	if(self->tsap)
-		irttp_close_tsap(self->tsap);
-	self->tsap = NULL;
-	self->in_use = 0;
-	return 0;
-}
-
-
-/*
- * ----------------------------------------------------------------------
- * Function init_module(void) ,cleanup_module()
- *
- *   Initializes the ircomm control structure
- *   These Function are called when you insmod / rmmod .
- * ----------------------------------------------------------------------
- */
-
-#ifdef MODULE
-int init_module(void) 
-{
-	int err;
-
-	err = ircomm_init();
-
-	DEBUG( 4, __FUNCTION__"():done.\n");
-	return err;
-}
-	
-void cleanup_module(void)
-{
-	ircomm_cleanup();
-	DEBUG( 4, __FUNCTION__"():done.\n");
-}
-#endif /* MODULE */
-
-/************************************************************
- *     proc stuff
- ************************************************************/
-
-#ifdef CONFIG_PROC_FS
-
-/*
- * Function proc_ircomm_read (buf, start, offset, len, unused)
- *
- * this function is called if there is a access on /proc/irda/comm .
- *
- */
-int ircomm_proc_read(char *buf, char **start, off_t offset,
-		     int len, int unused)
-{
-	int i, index;
-
-	len = 0;
-	for (i=0; i<IRCOMM_MAX_CONNECTION; i++) {
-
-		len += sprintf(buf+len, "instance %d:\n",i);
-		if(ircomm[i]->in_use == 0){
-			len += sprintf(buf+len, "\tunused\n");
-			continue;
-		}
-
-		if (ircomm[i] == NULL || ircomm[i]->magic != IRCOMM_MAGIC) {
-			len += sprintf(buf+len, "\tbroken???\n");
-			continue;
-		}
-
-		switch (ircomm[i]->servicetype) {
-		case UNKNOWN:
-			index = 0;
-			break;
-		case THREE_WIRE_RAW:
-			index = 1;
-			break;
-		case THREE_WIRE:
-			index = 2;
-			break;
-		case NINE_WIRE:
-			index = 3;
-			break;
-		case CENTRONICS:
-			index = 4;
-			break;
-		default:
-			index = 0;
-			break;
-		}
-		len += sprintf(buf+len, "    service: %s  ",
-			       ircommservicetype[index]);
-		if(!index)
-			continue;
-
-		len += sprintf(buf+len, "porttype: %s  ",
-			       ircommporttype[ircomm[i]->port_type]);
-		len += sprintf(buf+len, "state: %s  ",
-			       ircommstate[ircomm[i]->state]);
-		len += sprintf(buf+len, "user: %s\n",
-			       ircomm[i]->notify.name);
-		
-		len += sprintf(buf+len, "    tx packets: %d  ",
-			       ircomm[i]->tx_packets);
-		len += sprintf(buf+len, "rx packets: %d  ",
-			       ircomm[i]->rx_packets);
-		len += sprintf(buf+len, "tx controls: %d\n",
-			       ircomm[i]->tx_controls);
-		
-		len += sprintf(buf+len, "    pending tuples: %d  ",
-			       ircomm[i]->pending_control_tuples);
-		len += sprintf(buf+len, "    ignored tuples: %d\n",
-			       ircomm[i]->ignored_control_tuples);
-		
-		len += sprintf(buf+len, "    nullmodem emulation: %s  ",
-			       (ircomm[i]->null_modem_mode ? "yes":"no"));
-		len += sprintf(buf+len, "IrTTP: %s\n",
-			       (ircomm[i]->ttp_stop ? "BUSY":"READY"));
-
-		len += sprintf(buf+len, "    Peer capability: ");
-		if(ircomm[i]->peer_cap & THREE_WIRE_RAW)
-			len += sprintf(buf+len, "3wire-raw ");
-		if(ircomm[i]->peer_cap & THREE_WIRE)
-			len += sprintf(buf+len, "3wire ");
-		if(ircomm[i]->peer_cap & NINE_WIRE)
-			len += sprintf(buf+len, "9wire ");
-		if(ircomm[i]->peer_cap & CENTRONICS)
-			len += sprintf(buf+len, "centronics");
-
-		len += sprintf(buf+len, "\n    Port name: %s\n",
-			       (ircomm[i]->port_name));
-	}
-
-	return len;
-}
-
-#endif /* CONFIG_PROC_FS */
-
-
-
-
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_core.c linux/net/irda/ircomm/ircomm_core.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_core.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/ircomm_core.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,527 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_core.c
+ * Version:       1.0
+ * Description:   IrCOMM service interface
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sun Jun  6 20:37:34 1999
+ * Modified at:   Tue Dec 21 13:26:41 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/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irlmp.h>
+#include <net/irda/iriap.h>
+#include <net/irda/irttp.h>
+#include <net/irda/irias_object.h>
+
+#include <net/irda/ircomm_event.h>
+#include <net/irda/ircomm_lmp.h>
+#include <net/irda/ircomm_ttp.h>
+#include <net/irda/ircomm_param.h>
+#include <net/irda/ircomm_core.h>
+
+static int __ircomm_close(struct ircomm_cb *self);
+static void ircomm_control_indication(struct ircomm_cb *self, 
+				      struct sk_buff *skb, int clen);
+
+#ifdef CONFIG_PROC_FS
+static int ircomm_proc_read(char *buf, char **start, off_t offset, int len, 
+			    int unused);
+
+extern struct proc_dir_entry *proc_irda;
+#endif /* CONFIG_PROC_FS */
+
+hashbin_t *ircomm = NULL;
+
+int __init ircomm_init(void)
+{
+	ircomm = hashbin_new(HB_LOCAL); 
+	if (ircomm == NULL) {
+		ERROR(__FUNCTION__ "(), can't allocate hashbin!\n");
+		return -ENOMEM;
+	}
+	
+#ifdef CONFIG_PROC_FS
+	create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
+#endif /* CONFIG_PROC_FS */
+	
+	MESSAGE("IrCOMM protocol (Dag Brattli)\n");
+		
+	return 0;
+}
+
+#ifdef MODULE
+void ircomm_cleanup(void)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
+
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("ircomm", proc_irda);
+#endif /* CONFIG_PROC_FS */
+}
+#endif /* MODULE */
+
+/*
+ * Function ircomm_open (client_notify)
+ *
+ *    Start a new IrCOMM instance
+ *
+ */
+struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
+{
+	struct ircomm_cb *self = NULL;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), service_type=0x%02x\n",
+		   service_type);
+
+	ASSERT(ircomm != NULL, return NULL;);
+
+	self = kmalloc(sizeof(struct ircomm_cb), GFP_ATOMIC);
+	if (self == NULL)
+		return NULL;
+
+	memset(self, 0, sizeof(struct ircomm_cb));
+
+	self->notify = *notify;
+	self->magic = IRCOMM_MAGIC;
+
+	/* Check if we should use IrLMP or IrTTP */
+	if (service_type & IRCOMM_3_WIRE_RAW) {
+		self->flow_status = FLOW_START;
+		ret = ircomm_open_lsap(self);
+	} else
+		ret = ircomm_open_tsap(self);
+
+	if (ret < 0)
+		return NULL;
+
+	self->service_type = service_type;
+	self->line = line;
+
+	hashbin_insert(ircomm, (queue_t *) self, line, NULL);
+
+	ircomm_next_state(self, IRCOMM_IDLE);	
+
+	return self;
+}
+
+/*
+ * Function ircomm_close_instance (self)
+ *
+ *    Remove IrCOMM instance
+ *
+ */
+static int __ircomm_close(struct ircomm_cb *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__"()\n");
+
+	/* Disconnect link if any */
+	ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
+
+	/* Remove TSAP */
+	if (self->tsap) {
+		irttp_close_tsap(self->tsap);
+		self->tsap = NULL;
+	}
+
+	/* Remove LSAP */
+	if (self->lsap) {
+		irlmp_close_lsap(self->lsap);
+		self->lsap = NULL;
+	}
+	self->magic = 0;
+
+	kfree(self);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_close (self)
+ *
+ *    Closes and removes the specified IrCOMM instance
+ *
+ */
+int ircomm_close(struct ircomm_cb *self)
+{
+	struct ircomm_cb *entry;
+
+	ASSERT(self != NULL, return -EIO;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	entry = hashbin_remove(ircomm, self->line, NULL);
+
+	ASSERT(entry == self, return -1;);
+	
+        return __ircomm_close(self);
+}
+
+/*
+ * Function ircomm_connect_request (self, service_type)
+ *
+ *    Impl. of this function is differ from one of the reference. This
+ *    function does discovery as well as sending connect request
+ * 
+ */
+int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, 
+			   __u32 saddr, __u32 daddr, struct sk_buff *skb,
+			   __u8 service_type)
+{
+	struct ircomm_info info;
+	int ret;
+
+	IRDA_DEBUG(2 , __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+
+	self->service_type= service_type;
+
+	info.dlsap_sel = dlsap_sel;
+	info.saddr = saddr;
+	info.daddr = daddr;
+
+	ret = ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, skb, &info);
+
+	return ret;
+}
+
+/*
+ * Function ircomm_connect_indication (self, qos, skb)
+ *
+ *    Notify user layer about the incomming connection
+ *
+ */
+void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
+			       struct ircomm_info *info)
+{
+	int clen = 0;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* Check if the packet contains data on the control channel */
+	if (skb->len > 0)
+		clen = skb->data[0];
+	
+	/* 
+	 * If there are any data hiding in the control channel, we must 
+	 * deliver it first. The side effect is that the control channel 
+	 * will be removed from the skb
+	 */
+	if (self->notify.connect_indication)
+		self->notify.connect_indication(self->notify.instance, self, 
+						info->qos, info->max_data_size,
+						info->max_header_size, skb);
+	else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+		dev_kfree_skb(skb);
+	}
+}
+
+/*
+ * Function ircomm_connect_response (self, userdata, max_sdu_size)
+ *
+ *    User accepts connection
+ *
+ */
+int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
+{
+	int ret;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
+
+	return ret;
+}	
+
+/*
+ * Function connect_confirm (self, skb)
+ *
+ *    Notify user layer that the link is now connected
+ *
+ */
+void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
+			    struct ircomm_info *info)
+{
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+
+	if (self->notify.connect_confirm )
+		self->notify.connect_confirm(self->notify.instance,
+					     self, info->qos, 
+					     info->max_data_size,
+					     info->max_header_size, skb);
+	else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+		dev_kfree_skb(skb);
+	}
+}
+
+/*
+ * Function ircomm_data_request (self, userdata)
+ *
+ *    Send IrCOMM data to peer device
+ *
+ */
+int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb)
+{
+	int ret;
+
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return -EFAULT;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
+	ASSERT(skb != NULL, return -EFAULT;);
+	
+	ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL);
+
+	return ret;
+}
+
+/*
+ * Function ircomm_data_indication (self, skb)
+ *
+ *    Data arrived, so deliver it to user
+ *
+ */
+void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
+{	
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+
+	ASSERT(skb->len > 0, return;);
+
+	if (self->notify.data_indication)
+		self->notify.data_indication(self->notify.instance, self, skb);
+	else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+		dev_kfree_skb(skb);
+	}
+}
+
+/*
+ * Function ircomm_process_data (self, skb)
+ *
+ *    Data arrived which may contain control channel data
+ *
+ */
+void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
+{
+	int clen;
+
+	ASSERT(skb->len > 0, return;);
+
+	clen = skb->data[0];
+
+	/* 
+	 * If there are any data hiding in the control channel, we must 
+	 * deliver it first. The side effect is that the control channel 
+	 * will be removed from the skb
+	 */
+	if (clen > 0)
+		ircomm_control_indication(self, skb, clen);
+
+	/* Remove control channel from data channel */
+	skb_pull(skb, clen+1);
+
+	if (skb->len)
+		ircomm_data_indication(self, skb);		
+	else {
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), data was control info only!\n");
+		dev_kfree_skb(skb);
+	}
+}
+
+/*
+ * Function ircomm_control_request (self, params)
+ *
+ *    Send control data to peer device
+ *
+ */
+int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb)
+{
+	int ret;
+	
+	IRDA_DEBUG(2, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return -EFAULT;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
+	ASSERT(skb != NULL, return -EFAULT;);
+	
+	ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL);
+
+	return ret;
+}
+
+/*
+ * Function ircomm_control_indication (self, skb)
+ *
+ *    Data has arrived on the control channel
+ *
+ */
+static void ircomm_control_indication(struct ircomm_cb *self, 
+				      struct sk_buff *skb, int clen)
+{
+	struct sk_buff *ctrl_skb;
+
+	IRDA_DEBUG(2, __FUNCTION__"()\n");	
+
+	ctrl_skb = skb_clone(skb, GFP_ATOMIC);
+	if (!ctrl_skb)
+		return;
+
+	/* Remove data channel from control channel */
+	skb_trim(ctrl_skb, clen+1);
+	
+	/* Use udata for delivering data on the control channel */
+	if (self->notify.udata_indication)
+		self->notify.udata_indication(self->notify.instance, self, 
+					      ctrl_skb);
+	else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+		dev_kfree_skb(skb);
+	}
+}
+
+/*
+ * Function ircomm_disconnect_request (self, userdata, priority)
+ *
+ *    User layer wants to disconnect the IrCOMM connection
+ *
+ */
+int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata)
+{
+	struct ircomm_info info;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+
+	ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata, 
+			      &info);
+	return ret;
+}
+
+/*
+ * Function disconnect_indication (self, skb)
+ *
+ *    Tell user that the link has been disconnected
+ *
+ */
+void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
+				  struct ircomm_info *info)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+       
+	ASSERT(info != NULL, return;);
+
+	if (self->notify.disconnect_indication) {
+		self->notify.disconnect_indication(self->notify.instance, self,
+						   info->reason, skb);
+	} else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+		dev_kfree_skb(skb);
+	}
+}
+
+/*
+ * Function ircomm_flow_request (self, flow)
+ *
+ *    
+ *
+ */
+void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+
+	if (self->service_type == IRCOMM_3_WIRE_RAW)
+		return;
+
+	irttp_flow_request(self->tsap, flow);
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * Function ircomm_proc_read (buf, start, offset, len, unused)
+ *
+ *    
+ *
+ */
+int ircomm_proc_read(char *buf, char **start, off_t offset, int len, 
+		     int unused)
+{ 	
+	struct ircomm_cb *self;
+	unsigned long flags;
+	int i=0;
+	
+	save_flags(flags);
+	cli();
+
+	len = 0;
+
+	len += sprintf(buf+len, "Instance %d:\n", i++);
+
+	self = (struct ircomm_cb *) hashbin_get_first(ircomm);
+	while (self != NULL) {
+		ASSERT(self->magic == IRCOMM_MAGIC, return len;);
+
+		self = (struct ircomm_cb *) hashbin_get_next(ircomm);
+ 	} 
+	restore_flags(flags);
+
+	return len;
+}
+#endif /* CONFIG_PROC_FS */
+
+#ifdef MODULE
+int init_module(void) 
+{
+	return ircomm_init();
+}
+	
+void cleanup_module(void)
+{
+	ircomm_cleanup();
+}
+#endif /* MODULE */
+
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_event.c linux/net/irda/ircomm/ircomm_event.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_event.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/ircomm_event.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,257 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_event.c
+ * Version:       1.0
+ * Description:   IrCOMM layer state machine
+ * Status:        Stable
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sun Jun  6 20:33:11 1999
+ * Modified at:   Sun Dec 12 13:44:32 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/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irlmp.h>
+#include <net/irda/iriap.h>
+#include <net/irda/irttp.h>
+#include <net/irda/irias_object.h>
+
+#include <net/irda/ircomm_core.h>
+#include <net/irda/ircomm_event.h>
+
+static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			     struct sk_buff *skb, struct ircomm_info *info);
+static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			      struct sk_buff *skb, struct ircomm_info *info);
+static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			      struct sk_buff *skb, struct ircomm_info *info);
+static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			     struct sk_buff *skb, struct ircomm_info *info);
+
+char *ircomm_state[] = {
+	"IRCOMM_IDLE",
+	"IRCOMM_WAITI",
+	"IRCOMM_WAITR",
+	"IRCOMM_CONN",
+};
+
+char *ircomm_event[] = {
+	"IRCOMM_CONNECT_REQUEST",
+        "IRCOMM_CONNECT_RESPONSE",
+        "IRCOMM_TTP_CONNECT_INDICATION",
+	"IRCOMM_LMP_CONNECT_INDICATION",
+        "IRCOMM_TTP_CONNECT_CONFIRM",
+	"IRCOMM_LMP_CONNECT_CONFIRM",
+
+        "IRCOMM_LMP_DISCONNECT_INDICATION",
+	"IRCOMM_TTP_DISCONNECT_INDICATION",
+        "IRCOMM_DISCONNECT_REQUEST",
+
+        "IRCOMM_TTP_DATA_INDICATION",
+	"IRCOMM_LMP_DATA_INDICATION",
+        "IRCOMM_DATA_REQUEST",
+        "IRCOMM_CONTROL_REQUEST",
+        "IRCOMM_CONTROL_INDICATION",
+};
+
+static int (*state[])(struct ircomm_cb *self, IRCOMM_EVENT event,
+		      struct sk_buff *skb, struct ircomm_info *info) = 
+{
+	ircomm_state_idle,
+	ircomm_state_waiti,
+	ircomm_state_waitr,
+	ircomm_state_conn,
+};
+
+/*
+ * Function ircomm_state_idle (self, event, skb)
+ *
+ *    IrCOMM is currently idle
+ *
+ */
+static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			     struct sk_buff *skb, struct ircomm_info *info)
+{
+	int ret = 0;
+
+	switch (event) {
+	case IRCOMM_CONNECT_REQUEST:
+		ircomm_next_state(self, IRCOMM_WAITI);		
+		ret = self->issue.connect_request(self, skb, info);
+		break;
+	case IRCOMM_TTP_CONNECT_INDICATION:
+	case IRCOMM_LMP_CONNECT_INDICATION:
+		ircomm_next_state(self, IRCOMM_WAITR);
+		ircomm_connect_indication(self, skb, info);
+		break;
+	default:
+		IRDA_DEBUG(4, __FUNCTION__"(), unknown event: %s\n",
+			   ircomm_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_state_waiti (self, event, skb)
+ *
+ *    The IrCOMM user has requested an IrCOMM connection to the remote 
+ *    device and is awaiting confirmation
+ */
+static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			      struct sk_buff *skb, struct ircomm_info *info)
+{
+	int ret = 0;
+
+	switch (event) {
+	case IRCOMM_TTP_CONNECT_CONFIRM:
+	case IRCOMM_LMP_CONNECT_CONFIRM:
+		ircomm_next_state(self, IRCOMM_CONN);
+		ircomm_connect_confirm(self, skb, info);
+		break;
+	case IRCOMM_TTP_DISCONNECT_INDICATION:
+	case IRCOMM_LMP_DISCONNECT_INDICATION:
+		ircomm_next_state(self, IRCOMM_IDLE);
+		ircomm_disconnect_indication(self, skb, info);
+		break;
+	default:
+		IRDA_DEBUG(0, __FUNCTION__"(), unknown event: %s\n",
+			   ircomm_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_state_waitr (self, event, skb)
+ *
+ *    IrCOMM has received an incomming connection request and is awaiting
+ *    response from the user
+ */
+static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			      struct sk_buff *skb, struct ircomm_info *info) 
+{
+	int ret = 0;
+
+	switch (event) {
+	case IRCOMM_CONNECT_RESPONSE:
+		ircomm_next_state(self, IRCOMM_CONN);
+		ret = self->issue.connect_response(self, skb);
+		break;
+	case IRCOMM_DISCONNECT_REQUEST:
+		ircomm_next_state(self, IRCOMM_IDLE);
+		ret = self->issue.disconnect_request(self, skb, info);
+		break;
+	case IRCOMM_TTP_DISCONNECT_INDICATION:
+	case IRCOMM_LMP_DISCONNECT_INDICATION:
+		ircomm_next_state(self, IRCOMM_IDLE);
+		ircomm_disconnect_indication(self, skb, info);
+		break;
+	default:
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event = %s\n",
+			   ircomm_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_state_conn (self, event, skb)
+ *
+ *    IrCOMM is connected to the peer IrCOMM device
+ *
+ */
+static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, 
+			     struct sk_buff *skb, struct ircomm_info *info)
+{
+	int ret = 0;
+
+	switch (event) {
+	case IRCOMM_DATA_REQUEST:
+		ret = self->issue.data_request(self, skb, 0);
+		break;
+	case IRCOMM_TTP_DATA_INDICATION:
+		ircomm_process_data(self, skb);
+		break;
+	case IRCOMM_LMP_DATA_INDICATION:
+		ircomm_data_indication(self, skb);
+		break;
+	case IRCOMM_CONTROL_REQUEST:
+		/* Just send a separate frame for now */
+		ret = self->issue.data_request(self, skb, skb->len);
+		break;
+	case IRCOMM_TTP_DISCONNECT_INDICATION:
+	case IRCOMM_LMP_DISCONNECT_INDICATION:
+		ircomm_next_state(self, IRCOMM_IDLE);
+		ircomm_disconnect_indication(self, skb, info);
+		break;
+	case IRCOMM_DISCONNECT_REQUEST:
+		ircomm_next_state(self, IRCOMM_IDLE);
+		ret = self->issue.disconnect_request(self, skb, info);
+		break;
+	default:
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event = %s\n",
+			   ircomm_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_do_event (self, event, skb)
+ *
+ *    Process event
+ *
+ */
+int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
+		    struct sk_buff *skb, struct ircomm_info *info) 
+{
+	IRDA_DEBUG(4, __FUNCTION__": state=%s, event=%s\n",
+		   ircomm_state[self->state], ircomm_event[event]);
+
+	return (*state[self->state])(self, event, skb, info);
+}
+
+/*
+ * Function ircomm_next_state (self, state)
+ *
+ *    Switch state
+ *
+ */
+void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state)
+{
+	self->state = state;
+	
+	IRDA_DEBUG(4, __FUNCTION__": next state=%s, service type=%d\n", 
+		   ircomm_state[self->state], self->service_type);
+}
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_lmp.c linux/net/irda/ircomm/ircomm_lmp.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_lmp.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/ircomm_lmp.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,322 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_lmp.c
+ * Version:       1.0
+ * Description:   Interface between IrCOMM and IrLMP
+ * Status:        Stable
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sun Jun  6 20:48:27 1999
+ * Modified at:   Sun Dec 12 13:44:17 1999
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * Sources:       Previous IrLPT work by Thomas Davis
+ * 
+ *     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/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irlmp.h>
+#include <net/irda/iriap.h>
+
+#include <net/irda/ircomm_event.h>
+#include <net/irda/ircomm_lmp.h>
+
+/*
+ * Function ircomm_open_lsap (self)
+ *
+ *    Open LSAP. This function will only be used when using "raw" services
+ *
+ */
+int ircomm_open_lsap(struct ircomm_cb *self)
+{
+	notify_t notify;
+	
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	
+        /* Register callbacks */
+        irda_notify_init(&notify);
+	notify.data_indication       = ircomm_lmp_data_indication;
+	notify.connect_confirm       = ircomm_lmp_connect_confirm;
+        notify.connect_indication    = ircomm_lmp_connect_indication;
+	notify.disconnect_indication = ircomm_lmp_disconnect_indication;
+	notify.instance = self;
+	strncpy(notify.name, "IrCOMM", NOTIFY_MAX_NAME);
+
+	self->lsap = irlmp_open_lsap(LSAP_ANY, &notify, 0);
+	if (!self->lsap) {
+		IRDA_DEBUG(0,__FUNCTION__"failed to allocate tsap\n");
+		return -1;
+	}
+	self->slsap_sel = self->lsap->slsap_sel;
+
+	/*
+	 *  Initialize the call-table for issuing commands
+	 */
+	self->issue.data_request       = ircomm_lmp_data_request;
+	self->issue.connect_request    = ircomm_lmp_connect_request;
+	self->issue.connect_response   = ircomm_lmp_connect_response;
+	self->issue.disconnect_request = ircomm_lmp_disconnect_request;
+
+	return 0;
+}
+
+/*
+ * Function ircomm_lmp_connect_request (self, userdata)
+ *
+ *    
+ *
+ */
+int ircomm_lmp_connect_request(struct ircomm_cb *self, 
+			       struct sk_buff *userdata, 
+			       struct ircomm_info *info)
+{
+	int ret = 0;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ret = irlmp_connect_request(self->lsap, info->dlsap_sel,
+				    info->saddr, info->daddr, NULL, userdata); 
+	return ret;
+}	
+
+/*
+ * Function ircomm_lmp_connect_response (self, skb)
+ *
+ *    
+ *
+ */
+int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *skb)
+{
+	int ret;
+
+	IRDA_DEBUG(0, __FUNCTION__"()\n");
+	
+	ret = irlmp_connect_response(self->lsap, skb);
+
+	return 0;
+}
+
+int ircomm_lmp_disconnect_request(struct ircomm_cb *self, 
+				  struct sk_buff *userdata, 
+				  struct ircomm_info *info)
+{
+        struct sk_buff *skb;
+	int ret;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+        if (!userdata) {
+                skb = dev_alloc_skb(64);
+		if (!skb)
+			return -ENOMEM;
+		
+		/*  Reserve space for MUX and LAP header */
+		skb_reserve(skb, LMP_MAX_HEADER);		
+		userdata = skb;
+	}
+	ret = irlmp_disconnect_request(self->lsap, userdata);
+
+	return ret;
+}
+
+/*
+ * Function ircomm_lmp_flow_control (skb)
+ *
+ *    This function is called when a data frame we have sent to IrLAP has
+ *    been deallocated. We do this to make sure we don't flood IrLAP with 
+ *    frames, since we are not using the IrTTP flow control mechanism
+ */
+void ircomm_lmp_flow_control(struct sk_buff *skb)
+{
+	struct irda_skb_cb *cb;
+	struct ircomm_cb *self;
+	int line;
+
+	ASSERT(skb != NULL, return;);
+
+	cb = (struct irda_skb_cb *) skb->cb;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ 
+        line = cb->line;
+
+	self = (struct ircomm_cb *) hashbin_find(ircomm, line, NULL);
+        if (!self) {
+		IRDA_DEBUG(2, __FUNCTION__ "(), didn't find myself\n");
+                return;
+	}
+
+        ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+
+	self->pkt_count--;
+
+        if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) {
+                IRDA_DEBUG(2, __FUNCTION__ "(), asking TTY to start again!\n");
+                self->flow_status = FLOW_START;
+                if (self->notify.flow_indication)
+                        self->notify.flow_indication(self->notify.instance, 
+						     self, FLOW_START);
+        }
+}
+    
+/*
+ * Function ircomm_lmp_data_request (self, userdata)
+ *
+ *    Send data frame to peer device
+ *
+ */
+int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb, 
+			    int not_used)
+{
+	struct irda_skb_cb *cb;
+	int ret;
+
+	ASSERT(skb != NULL, return -1;);
+
+	cb = (struct irda_skb_cb *) skb->cb;
+	
+        cb->line = self->line;
+
+	IRDA_DEBUG(4, __FUNCTION__"(), sending frame\n");
+
+	skb->destructor = ircomm_lmp_flow_control;
+	
+        if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
+		IRDA_DEBUG(2, __FUNCTION__ "(), asking TTY to slow down!\n");
+	        self->flow_status = FLOW_STOP;
+                if (self->notify.flow_indication)
+             	        self->notify.flow_indication(self->notify.instance, 
+				                     self, FLOW_STOP);
+        }
+	ret = irlmp_data_request(self->lsap, skb);
+	if (ret) {
+		ERROR(__FUNCTION__ "(), failed\n");
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+/*
+ * Function ircomm_lmp_data_indication (instance, sap, skb)
+ *
+ *    Incomming data which we must deliver to the state machine, to check
+ *    we are still connected.
+ */
+int ircomm_lmp_data_indication(void *instance, void *sap,
+			       struct sk_buff *skb)
+{
+	struct ircomm_cb *self = (struct ircomm_cb *) instance;
+
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+	ASSERT(skb != NULL, return -1;);
+	
+	ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_lmp_connect_confirm (instance, sap, qos, max_sdu_size, 
+ *                                       max_header_size, skb)
+ *
+ *    Connection has been confirmed by peer device
+ *
+ */
+void ircomm_lmp_connect_confirm(void *instance, void *sap,
+				struct qos_info *qos, 
+				__u32 max_seg_size, 
+				__u8 max_header_size,
+				struct sk_buff *skb)
+{
+	struct ircomm_cb *self = (struct ircomm_cb *) instance;
+	struct ircomm_info info;
+
+	IRDA_DEBUG(0, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+	ASSERT(qos != NULL, return;);
+
+	info.max_data_size = max_seg_size;
+	info.max_header_size = max_header_size;
+	info.qos = qos;
+
+	ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info);
+}
+
+/*
+ * Function ircomm_lmp_connect_indication (instance, sap, qos, max_sdu_size,
+ *                                         max_header_size, skb)
+ *
+ *    Peer device wants to make a connection with us
+ *
+ */
+void ircomm_lmp_connect_indication(void *instance, void *sap,
+				   struct qos_info *qos,
+				   __u32 max_seg_size,
+				   __u8 max_header_size,
+				   struct sk_buff *skb)
+{
+	struct ircomm_cb *self = (struct ircomm_cb *)instance;
+	struct ircomm_info info;
+
+	IRDA_DEBUG(0, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+	ASSERT(qos != NULL, return;);
+
+	info.max_data_size = max_seg_size;
+	info.max_header_size = max_header_size;
+	info.qos = qos;
+
+	ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info);
+}
+
+/*
+ * Function ircomm_lmp_disconnect_indication (instance, sap, reason, skb)
+ *
+ *    Peer device has closed the connection, or the link went down for some
+ *    other reason
+ */
+void ircomm_lmp_disconnect_indication(void *instance, void *sap, 
+				      LM_REASON reason,
+				      struct sk_buff *skb)
+{
+	struct ircomm_cb *self = (struct ircomm_cb *) instance;
+	struct ircomm_info info;
+
+	IRDA_DEBUG(0, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+
+	info.reason = reason;
+
+	ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info);
+}
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_param.c linux/net/irda/ircomm/ircomm_param.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_param.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/ircomm_param.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,506 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_param.c
+ * Version:       1.0
+ * Description:   Parameter handling for the IrCOMM protocol
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Mon Jun  7 10:25:11 1999
+ * Modified at:   Tue Dec 14 15:26:30 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/sched.h>
+#include <linux/interrupt.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/parameters.h>
+
+#include <net/irda/ircomm_core.h>
+#include <net/irda/ircomm_tty_attach.h>
+#include <net/irda/ircomm_tty.h>
+
+#include <net/irda/ircomm_param.h>
+
+static int ircomm_param_service_type(void *instance, param_t *param, int get);
+static int ircomm_param_port_type(void *instance, param_t *param, int get);
+static int ircomm_param_port_name(void *instance, param_t *param, int get);
+static int ircomm_param_service_type(void *instance, param_t *param, int get);
+static int ircomm_param_data_rate(void *instance, param_t *param, int get);
+static int ircomm_param_data_format(void *instance, param_t *param, int get);
+static int ircomm_param_flow_control(void *instance, param_t *param, int get);
+static int ircomm_param_xon_xoff(void *instance, param_t *param, int get);
+static int ircomm_param_enq_ack(void *instance, param_t *param, int get);
+static int ircomm_param_line_status(void *instance, param_t *param, int get);
+static int ircomm_param_dte(void *instance, param_t *param, int get);
+static int ircomm_param_dce(void *instance, param_t *param, int get);
+static int ircomm_param_poll(void *instance, param_t *param, int get);
+
+static pi_minor_info_t pi_minor_call_table_common[] = {
+	{ ircomm_param_service_type, PV_INT_8_BITS },
+	{ ircomm_param_port_type,    PV_INT_8_BITS },
+	{ ircomm_param_port_name,    PV_STRING }
+};
+static pi_minor_info_t pi_minor_call_table_non_raw[] = {
+	{ ircomm_param_data_rate,    PV_INT_32_BITS | PV_BIG_ENDIAN },
+	{ ircomm_param_data_format,  PV_INT_8_BITS },
+	{ ircomm_param_flow_control, PV_INT_8_BITS },
+	{ ircomm_param_xon_xoff,     PV_INT_16_BITS },
+	{ ircomm_param_enq_ack,      PV_INT_16_BITS },
+	{ ircomm_param_line_status,  PV_INT_8_BITS }
+};
+static pi_minor_info_t pi_minor_call_table_9_wire[] = {
+	{ ircomm_param_dte,          PV_INT_8_BITS },
+	{ ircomm_param_dce,          PV_INT_8_BITS },
+	{ ircomm_param_poll,         PV_NO_VALUE },
+};
+
+static pi_major_info_t pi_major_call_table[] = {
+	{ pi_minor_call_table_common,  3 },
+	{ pi_minor_call_table_non_raw, 6 },
+ 	{ pi_minor_call_table_9_wire,  3 }
+/* 	{ pi_minor_call_table_centronics }  */
+};
+
+pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
+
+/*
+ * Function ircomm_param_flush (self)
+ *
+ *    Flush (send) out all queued parameters
+ *
+ */
+int ircomm_param_flush(struct ircomm_tty_cb *self)
+{
+	if (self->ctrl_skb) {
+		ircomm_control_request(self->ircomm, self->ctrl_skb);
+		self->ctrl_skb = NULL;	
+	}
+	return 0;
+}
+
+/*
+ * Function ircomm_param_request (self, pi, flush)
+ *
+ *    Queue a parameter for the control channel
+ *
+ */
+int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
+{
+	struct tty_struct *tty;
+	unsigned long flags;
+	struct sk_buff *skb;
+	int count;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	tty = self->tty;
+	if (!tty)
+		return 0;
+
+	/* Make sure we don't send parameters for raw mode */
+	if (self->service_type == IRCOMM_3_WIRE_RAW)
+		return 0;
+
+	save_flags(flags);
+	cli();
+
+	skb = self->ctrl_skb;	
+	if (!skb) {
+		skb = dev_alloc_skb(256);
+		if (!skb) {
+			restore_flags(flags);
+			return -ENOMEM;
+		}
+		
+		skb_reserve(skb, self->max_header_size);
+		self->ctrl_skb = skb;
+	}
+	/* 
+	 * Inserting is a little bit tricky since we don't know how much
+	 * room we will need. But this should hopefully work OK 
+	 */
+	count = irda_param_insert(self, pi, skb->tail, skb_tailroom(skb),
+				  &ircomm_param_info);
+	if (count < 0) {
+		WARNING(__FUNCTION__ "(), no room for parameter!\n");
+		restore_flags(flags);
+		return -1;
+	}
+	skb_put(skb, count);
+
+	restore_flags(flags);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), skb->len=%d\n", skb->len);
+
+	if (flush) {
+		/* ircomm_tty_do_softint will take care of the rest */
+		queue_task(&self->tqueue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+
+	return count;
+}
+
+/*
+ * Function ircomm_param_service_type (self, buf, len)
+ *
+ *    Handle service type, this function will both be called after the LM-IAS
+ *    query and then the remote device sends its initial paramters
+ *
+ */
+static int ircomm_param_service_type(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	__u8 service_type = param->pv.b; /* We know it's a one byte integer */
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	if (get) {
+		param->pv.b = self->settings.service_type;
+		return 0;
+	}
+
+	/* Find all common service types */
+	service_type &= self->service_type;
+	if (!service_type) {
+		IRDA_DEBUG(2, __FUNCTION__
+			   "(), No common service type to use!\n");
+		return -1;
+	}
+	IRDA_DEBUG(0, __FUNCTION__ "(), services in common=%02x\n",
+		   service_type);
+
+	/*
+	 * Now choose a preferred service type of those available
+	 */
+	if (service_type & IRCOMM_CENTRONICS)
+		self->settings.service_type = IRCOMM_CENTRONICS;
+	else if (service_type & IRCOMM_9_WIRE)
+		self->settings.service_type = IRCOMM_9_WIRE;
+	else if (service_type & IRCOMM_3_WIRE)
+		self->settings.service_type = IRCOMM_3_WIRE;
+	else if (service_type & IRCOMM_3_WIRE_RAW)
+		self->settings.service_type = IRCOMM_3_WIRE_RAW;
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), resulting service type=0x%02x\n", 
+		   self->settings.service_type);
+
+	/* 
+	 * Now the line is ready for some communication. Check if we are a
+         * server, and send over some initial parameters 
+	 */
+	if (!self->client && (self->settings.service_type != IRCOMM_3_WIRE_RAW))
+	{
+		/* Init connection */
+		ircomm_tty_send_initial_parameters(self);
+		ircomm_tty_link_established(self);
+	}
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_port_type (self, param)
+ *
+ *    The port type parameter tells if the devices are serial or parallel.
+ *    Since we only advertise serial service, this parameter should only
+ *    be equal to IRCOMM_SERIAL.
+ */
+static int ircomm_param_port_type(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	
+	if (get)
+		param->pv.b = IRCOMM_SERIAL;
+	else {
+		self->settings.port_type = param->pv.b;
+
+		IRDA_DEBUG(0, __FUNCTION__ "(), port type=%d\n", 
+			   self->settings.port_type);
+	}
+	return 0;
+}
+
+/*
+ * Function ircomm_param_port_name (self, param)
+ *
+ *    Exchange port name
+ *
+ */
+static int ircomm_param_port_name(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	if (get) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), not imp!\n");
+	} else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), port-name=%s\n", param->pv.c);
+		strncpy(self->settings.port_name, param->pv.c, 32);
+	}
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_data_rate (self, param)
+ *
+ *    Exchange data rate to be used in this settings
+ *
+ */
+static int ircomm_param_data_rate(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	if (get)
+		param->pv.i = self->settings.data_rate;
+	else
+		self->settings.data_rate = param->pv.i;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), data rate = %d\n", param->pv.i);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_data_format (self, param)
+ *
+ *    Exchange data format to be used in this settings
+ *
+ */
+static int ircomm_param_data_format(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	if (get)
+		param->pv.b = self->settings.data_format;
+	else
+		self->settings.data_format = param->pv.b;
+	
+	return 0;
+}
+
+/*
+ * Function ircomm_param_flow_control (self, param)
+ *
+ *    Exchange flow control settings to be used in this settings
+ *
+ */
+static int ircomm_param_flow_control(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	
+	if (get)
+		param->pv.b = self->settings.flow_control;
+	else
+		self->settings.flow_control = param->pv.b;
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), flow control = 0x%02x\n", param->pv.b);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_xon_xoff (self, param)
+ *
+ *    Exchange XON/XOFF characters
+ *
+ */
+static int ircomm_param_xon_xoff(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	
+	if (get) {
+		param->pv.s = self->settings.xonxoff[0];
+		param->pv.s |= self->settings.xonxoff[1] << 8;
+	} else {
+		self->settings.xonxoff[0] = param->pv.s & 0xff;
+		self->settings.xonxoff[1] = param->pv.s >> 8;
+	}
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), XON/XOFF = 0x%02x,0x%02x\n", 
+		   param->pv.s & 0xff, param->pv.s >> 8);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_enq_ack (self, param)
+ *
+ *    Exchange ENQ/ACK characters
+ *
+ */
+static int ircomm_param_enq_ack(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	
+	if (get) {
+		param->pv.s = self->settings.enqack[0];
+		param->pv.s |= self->settings.enqack[1] << 8;
+	} else {
+		self->settings.enqack[0] = param->pv.s & 0xff;
+		self->settings.enqack[1] = param->pv.s >> 8;
+	}
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), ENQ/ACK = 0x%02x,0x%02x\n",
+		   param->pv.s & 0xff, param->pv.s >> 8);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_line_status (self, param)
+ *
+ *    
+ *
+ */
+static int ircomm_param_line_status(void *instance, param_t *param, int get)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "(), not impl.\n");
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_dte (instance, param)
+ *
+ *    If we get here, there must be some sort of null-modem connection, and
+ *    we are probably working in server mode as well.
+ */
+static int ircomm_param_dte(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	__u8 dte;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	if (get)
+		param->pv.b = self->settings.dte;
+	else {
+		dte = param->pv.b;
+		
+		if (dte & IRCOMM_DELTA_DTR)
+			self->settings.dce |= (IRCOMM_DELTA_DSR|
+					      IRCOMM_DELTA_RI |
+					      IRCOMM_DELTA_CD);
+		if (dte & IRCOMM_DTR)
+			self->settings.dce |= (IRCOMM_DSR|
+					      IRCOMM_RI |
+					      IRCOMM_CD);
+		
+		if (dte & IRCOMM_DELTA_RTS)
+			self->settings.dce |= IRCOMM_DELTA_CTS;
+		if (dte & IRCOMM_RTS)
+			self->settings.dce |= IRCOMM_CTS;
+
+		/* Take appropriate actions */
+		ircomm_tty_check_modem_status(self);
+
+		/* Null modem cable emulator */
+		self->settings.null_modem = TRUE;
+	}
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_dce (instance, param)
+ *
+ *    
+ *
+ */
+static int ircomm_param_dce(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	__u8 dce;
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), dce = 0x%02x\n", param->pv.b);
+
+	dce = param->pv.b;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	self->settings.dce = dce;
+
+	/* Check if any of the settings have changed */
+	if (dce & 0x0f) {
+		if (dce & IRCOMM_DELTA_CTS) {
+			IRDA_DEBUG(2, __FUNCTION__ "(), CTS \n");
+		}
+	}
+
+	ircomm_tty_check_modem_status(self);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_param_poll (instance, param)
+ *
+ *    Called when the peer device is polling for the line settings
+ *
+ */
+static int ircomm_param_poll(void *instance, param_t *param, int get)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	/* Poll parameters are always of lenght 0 (just a signal) */
+	if (!get) {
+		/* Respond with DTE line settings */
+		ircomm_param_request(self, IRCOMM_DTE, TRUE);
+	}
+	return 0;
+}
+
+
+
+
+
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_ttp.c linux/net/irda/ircomm/ircomm_ttp.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_ttp.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/ircomm_ttp.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,304 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_ttp.c
+ * Version:       1.0
+ * Description:   Interface between IrCOMM and IrTTP
+ * Status:        Stable
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sun Jun  6 20:48:27 1999
+ * Modified at:   Mon Dec 13 11:35:13 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/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irlmp.h>
+#include <net/irda/iriap.h>
+#include <net/irda/irttp.h>
+
+#include <net/irda/ircomm_event.h>
+#include <net/irda/ircomm_ttp.h>
+
+/*
+ * Function ircomm_open_tsap (self)
+ *
+ *    
+ *
+ */
+int ircomm_open_tsap(struct ircomm_cb *self)
+{
+	notify_t notify;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Register callbacks */
+	irda_notify_init(&notify);
+	notify.data_indication       = ircomm_ttp_data_indication;
+	notify.connect_confirm       = ircomm_ttp_connect_confirm;
+	notify.connect_indication    = ircomm_ttp_connect_indication;
+	notify.flow_indication       = ircomm_ttp_flow_indication;
+	notify.disconnect_indication = ircomm_ttp_disconnect_indication;
+	notify.instance = self;
+	strncpy(notify.name, "IrCOMM", NOTIFY_MAX_NAME);
+
+	self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
+				     &notify);
+	if (!self->tsap) {
+		IRDA_DEBUG(0, __FUNCTION__"failed to allocate tsap\n");
+		return -1;
+	}
+	self->slsap_sel = self->tsap->stsap_sel;
+
+	/*
+	 *  Initialize the call-table for issuing commands
+	 */
+	self->issue.data_request       = ircomm_ttp_data_request;
+	self->issue.connect_request    = ircomm_ttp_connect_request;
+	self->issue.connect_response   = ircomm_ttp_connect_response;
+	self->issue.disconnect_request = ircomm_ttp_disconnect_request;
+
+	return 0;
+}
+
+/*
+ * Function ircomm_ttp_connect_request (self, userdata)
+ *
+ *    
+ *
+ */
+int ircomm_ttp_connect_request(struct ircomm_cb *self, 
+			       struct sk_buff *userdata, 
+			       struct ircomm_info *info)
+{
+	int ret = 0;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ret = irttp_connect_request(self->tsap, info->dlsap_sel,
+				    info->saddr, info->daddr, NULL, 
+				    TTP_SAR_DISABLE, userdata); 
+	return ret;
+}	
+
+/*
+ * Function ircomm_ttp_connect_response (self, skb)
+ *
+ *    
+ *
+ */
+int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb)
+{
+	int ret;
+
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+	
+	ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, skb);
+
+	return ret;
+}
+
+/*
+ * Function ircomm_ttp_data_request (self, userdata)
+ *
+ *    Send IrCOMM data to IrTTP layer. Currently we do not try to combine 
+ *    control data with pure data, so they will be sent as separate frames. 
+ *    Should not be a big problem though, since control frames are rare. But
+ *    some of them are sent after connection establishment, so this can 
+ *    increase the latency a bit.
+ */
+int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb, 
+			    int clen)
+{
+	int ret;
+
+	ASSERT(skb != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__"(), clen=%d\n", clen);
+
+	/* 
+	 * Insert clen field, currently we either send data only, or control
+	 * only frames, to make things easier and avoid queueing
+	 */
+	ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
+	skb_push(skb, IRCOMM_HEADER_SIZE);
+
+	skb->data[0] = clen;
+
+	ret = irttp_data_request(self->tsap, skb);
+	if (ret) {
+		ERROR(__FUNCTION__ "(), failed\n");
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+/*
+ * Function ircomm_ttp_data_indication (instance, sap, skb)
+ *
+ *    Incomming data
+ *
+ */
+int ircomm_ttp_data_indication(void *instance, void *sap,
+			       struct sk_buff *skb)
+{
+	struct ircomm_cb *self = (struct ircomm_cb *) instance;
+
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+	ASSERT(skb != NULL, return -1;);
+
+	ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
+
+	return 0;
+}
+
+void ircomm_ttp_connect_confirm(void *instance, void *sap,
+				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_info info;
+
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+	ASSERT(qos != NULL, return;);
+
+	if (max_sdu_size != TTP_SAR_DISABLE) {
+		ERROR(__FUNCTION__ "(), SAR not allowed for IrCOMM!\n");
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	info.max_data_size = irttp_get_max_seg_size(self->tsap)
+		- IRCOMM_HEADER_SIZE;
+	info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
+	info.qos = qos;
+
+	ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
+}
+
+/*
+ * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size,
+ *                                         max_header_size, skb)
+ *
+ *    
+ *
+ */
+void ircomm_ttp_connect_indication(void *instance, void *sap,
+				   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_info info;
+
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+	ASSERT(qos != NULL, return;);
+
+	if (max_sdu_size != TTP_SAR_DISABLE) {
+		ERROR(__FUNCTION__ "(), SAR not allowed for IrCOMM!\n");
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	info.max_data_size = irttp_get_max_seg_size(self->tsap)
+		- IRCOMM_HEADER_SIZE;
+	info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
+	info.qos = qos;
+
+	ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
+}
+
+/*
+ * Function ircomm_ttp_disconnect_request (self, userdata, info)
+ *
+ *    
+ *
+ */
+int ircomm_ttp_disconnect_request(struct ircomm_cb *self, 
+				  struct sk_buff *userdata, 
+				  struct ircomm_info *info)
+{
+	int ret;
+
+	ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
+
+	return ret;
+}
+
+/*
+ * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb)
+ *
+ *    
+ *
+ */
+void ircomm_ttp_disconnect_indication(void *instance, void *sap, 
+				      LM_REASON reason,
+				      struct sk_buff *skb)
+{
+	struct ircomm_cb *self = (struct ircomm_cb *) instance;
+	struct ircomm_info info;
+
+	IRDA_DEBUG(2, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+
+	info.reason = reason;
+
+	ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
+}
+
+/*
+ * Function ircomm_ttp_flow_indication (instance, sap, cmd)
+ *
+ *    Layer below is telling us to start or stop the flow of data
+ *
+ */
+void ircomm_ttp_flow_indication(void *instance, void *sap, LOCAL_FLOW cmd)
+{
+	struct ircomm_cb *self = (struct ircomm_cb *) instance;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+	
+	if (self->notify.flow_indication)
+		self->notify.flow_indication(self->notify.instance, self, cmd);
+}
+
+
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_tty.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/ircomm_tty.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,1367 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_tty.c
+ * Version:       1.0
+ * Description:   IrCOMM serial TTY driver
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sun Jun  6 21:00:56 1999
+ * Modified at:   Tue Jan  4 14:12:06 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * Sources:       serial.c and previous IrCOMM work by Takahide Higuchi
+ * 
+ *     Copyright (c) 1999-2000 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/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+
+#include <net/irda/ircomm_core.h>
+#include <net/irda/ircomm_param.h>
+#include <net/irda/ircomm_tty_attach.h>
+#include <net/irda/ircomm_tty.h>
+
+static int  ircomm_tty_open(struct tty_struct *tty, struct file *filp);
+static void ircomm_tty_close(struct tty_struct * tty, struct file *filp);
+static int  ircomm_tty_write(struct tty_struct * tty, int from_user,
+			     const unsigned char *buf, int count);
+static int  ircomm_tty_write_room(struct tty_struct *tty);
+static void ircomm_tty_throttle(struct tty_struct *tty);
+static void ircomm_tty_unthrottle(struct tty_struct *tty);
+static int  ircomm_tty_chars_in_buffer(struct tty_struct *tty);
+static void ircomm_tty_flush_buffer(struct tty_struct *tty);
+static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch);
+static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout);
+static void ircomm_tty_hangup(struct tty_struct *tty);
+static void ircomm_tty_do_softint(void *private_);
+static void ircomm_tty_shutdown(struct ircomm_tty_cb *self);
+
+static int ircomm_tty_data_indication(void *instance, void *sap,
+				      struct sk_buff *skb);
+static int ircomm_tty_control_indication(void *instance, void *sap,
+					 struct sk_buff *skb);
+static void ircomm_tty_flow_indication(void *instance, void *sap, 
+				       LOCAL_FLOW cmd);
+static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
+				int *eof, void *unused);
+
+static struct tty_driver driver;
+static int ircomm_tty_refcount;       /* If we manage several devices */
+
+static struct tty_struct *ircomm_tty_table[NR_PTYS];
+static struct termios *ircomm_tty_termios[NR_PTYS];
+static struct termios *ircomm_tty_termios_locked[NR_PTYS];
+
+hashbin_t *ircomm_tty = NULL;
+
+/*
+ * Function ircomm_tty_init()
+ *
+ *    Init IrCOMM TTY layer/driver
+ *
+ */
+int __init ircomm_tty_init(void)
+{	
+	ircomm_tty = hashbin_new(HB_LOCAL); 
+	if (ircomm_tty == NULL) {
+		ERROR(__FUNCTION__ "(), can't allocate hashbin!\n");
+		return -ENOMEM;
+	}
+
+	memset(&driver, 0, sizeof(struct tty_driver));
+	driver.magic           = TTY_DRIVER_MAGIC;
+	driver.driver_name     = "ircomm";
+	driver.name            = "ircomm";
+	driver.major           = IRCOMM_TTY_MAJOR;
+	driver.minor_start     = IRCOMM_TTY_MINOR;
+	driver.num             = IRCOMM_TTY_PORTS;
+	driver.type            = TTY_DRIVER_TYPE_SERIAL;
+	driver.subtype         = SERIAL_TYPE_NORMAL;
+	driver.init_termios    = tty_std_termios;
+	driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	driver.flags           = TTY_DRIVER_REAL_RAW;
+	driver.refcount        = &ircomm_tty_refcount;
+	driver.table           = ircomm_tty_table;
+	driver.termios         = ircomm_tty_termios;
+	driver.termios_locked  = ircomm_tty_termios_locked;
+	driver.open            = ircomm_tty_open;
+	driver.close           = ircomm_tty_close;
+	driver.write           = ircomm_tty_write;
+	driver.write_room      = ircomm_tty_write_room;
+	driver.chars_in_buffer = ircomm_tty_chars_in_buffer;
+	driver.flush_buffer    = ircomm_tty_flush_buffer;
+	driver.ioctl           = ircomm_tty_ioctl;
+	driver.throttle        = ircomm_tty_throttle;
+	driver.unthrottle      = ircomm_tty_unthrottle;
+	driver.send_xchar      = ircomm_tty_send_xchar;
+	driver.set_termios     = ircomm_tty_set_termios;
+	driver.stop            = ircomm_tty_stop;
+	driver.start           = ircomm_tty_start;
+	driver.hangup          = ircomm_tty_hangup;
+	driver.wait_until_sent = ircomm_tty_wait_until_sent;
+	driver.read_proc       = ircomm_tty_read_proc;
+
+	if (tty_register_driver(&driver)) {
+		ERROR(__FUNCTION__ "Couldn't register serial driver\n");
+		return -1;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+static void __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	ircomm_tty_shutdown(self);
+
+	self->magic = 0;
+	kfree(self);
+}
+
+/*
+ * Function ircomm_tty_cleanup ()
+ *
+ *    Remove IrCOMM TTY layer/driver
+ *
+ */
+void ircomm_tty_cleanup(void)
+{
+	int ret;
+
+	IRDA_DEBUG(4, __FUNCTION__"()\n");	
+
+	ret = tty_unregister_driver(&driver);
+        if (ret) {
+                ERROR(__FUNCTION__ "(), failed to unregister driver\n");
+		return;
+	}
+
+	hashbin_delete(ircomm_tty, (FREE_FUNC) __ircomm_tty_cleanup);
+}
+#endif /* MODULE */
+
+/*
+ * Function ircomm_startup (self)
+ *
+ *    
+ *
+ */
+static int ircomm_tty_startup(struct ircomm_tty_cb *self)
+{
+	notify_t notify;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	/* Already open */
+	if (self->flags & ASYNC_INITIALIZED) {
+		IRDA_DEBUG(2, __FUNCTION__ "(), already open so break out!\n");
+		return 0;
+	}
+
+	/* Register with IrCOMM */
+	irda_notify_init(&notify);
+	/* These callbacks we must handle ourselves */
+	notify.data_indication       = ircomm_tty_data_indication;
+	notify.udata_indication      = ircomm_tty_control_indication;
+ 	notify.flow_indication       = ircomm_tty_flow_indication;
+
+	/* Use the ircomm_tty interface for these ones */
+ 	notify.disconnect_indication = ircomm_tty_disconnect_indication;
+	notify.connect_confirm       = ircomm_tty_connect_confirm;
+ 	notify.connect_indication    = ircomm_tty_connect_indication;
+	strncpy(notify.name, "ircomm_tty", NOTIFY_MAX_NAME);
+	notify.instance = self;
+
+	if (!self->ircomm) {
+		self->ircomm = ircomm_open(&notify, self->service_type, 
+					   self->line);
+	}
+	if (!self->ircomm)
+		return -ENODEV;
+
+	self->slsap_sel = self->ircomm->slsap_sel;
+
+	/* Connect IrCOMM link with remote device */
+	ret = ircomm_tty_attach_cable(self);
+	if (ret < 0) {
+		ERROR(__FUNCTION__ "(), error attaching cable!\n");
+		return ret;
+	}
+
+	self->flags |= ASYNC_INITIALIZED;
+
+	return 0;
+}
+
+/*
+ * Function ircomm_block_til_ready (self, filp)
+ *
+ *    
+ *
+ */
+static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, 
+				      struct file *filp)
+{
+	struct wait_queue wait = { NULL, NULL };
+	int		retval;
+	int		do_clocal = 0, extra_count = 0;
+	unsigned long	flags;
+	struct tty_struct *tty;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	tty = self->tty;
+	wait.task = current;
+
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		/* this is a callout device */
+		/* just verify that normal device is not in use */
+		if (self->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((self->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (self->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (self->session != current->session))
+			return -EBUSY;
+		if ((self->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (self->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (self->pgrp != current->pgrp))
+			return -EBUSY;
+		self->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * 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)){
+		/* nonblock mode is set or port is not enabled */
+		/* just verify that callout device is not active */
+		if (self->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		self->flags |= ASYNC_NORMAL_ACTIVE;
+
+		IRDA_DEBUG(1, __FUNCTION__ "(), O_NONBLOCK requested!\n");
+		return 0;
+	}
+
+	if (self->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (self->normal_termios.c_cflag & CLOCAL) {
+			IRDA_DEBUG(1, __FUNCTION__ "(), doing CLOCAL!\n");
+			do_clocal = 1;
+		}
+	} else {
+		if (tty->termios->c_cflag & CLOCAL) {
+			IRDA_DEBUG(1, __FUNCTION__ "(), doing CLOCAL!\n");
+			do_clocal = 1;
+		}
+	}
+	
+	/* Wait for carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, self->open_count is dropped by one, so that
+	 * mgsl_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	 
+	retval = 0;
+	add_wait_queue(&self->open_wait, &wait);
+	
+	IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
+	      __FILE__,__LINE__, tty->driver.name, self->open_count );
+
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
+		self->open_count--;
+	}
+	restore_flags(flags);
+	self->blocked_open++;
+	
+	while (1) {
+		if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
+ 		    (tty->termios->c_cflag & CBAUD)) {
+			save_flags(flags); cli();
+			self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
+		 	
+			ircomm_param_request(self, IRCOMM_DTE, TRUE);
+			restore_flags(flags);
+		}
+		
+		current->state = TASK_INTERRUPTIBLE;
+		
+		if (tty_hung_up_p(filp) || !(self->flags & ASYNC_INITIALIZED)){
+			retval = (self->flags & ASYNC_HUP_NOTIFY) ?
+					-EAGAIN : -ERESTARTSYS;
+			break;
+		}
+		
+		/*  
+		 * Check if link is ready now. Even if CLOCAL is
+		 * specified, we cannot return before the IrCOMM link is
+		 * ready 
+		 */
+ 		if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
+ 		    !(self->flags & ASYNC_CLOSING) &&
+ 		    (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
+		    self->state == IRCOMM_TTY_READY)
+		{
+ 			break;
+		}
+			
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		
+		IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n",
+		      __FILE__,__LINE__, tty->driver.name, self->open_count );
+		
+		schedule();
+	}
+	
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&self->open_wait, &wait);
+	
+	if (extra_count)
+		self->open_count++;
+	self->blocked_open--;
+	
+	IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n",
+	      __FILE__,__LINE__, tty->driver.name, self->open_count);
+			 
+	if (!retval)
+		self->flags |= ASYNC_NORMAL_ACTIVE;
+		
+	return retval;	
+}
+
+/*
+ * Function ircomm_tty_open (tty, filp)
+ *
+ *    This routine is called when a particular tty device is opened. This
+ *    routine is mandatory; if this routine is not filled in, the attempted
+ *    open will fail with ENODEV.
+ */
+static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	struct ircomm_tty_cb *self;
+	int line;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+
+	/* Check if instance already exists */
+	self = hashbin_find(ircomm_tty, line, NULL);
+	if (!self) {
+		/* No, so make new instance */
+		self = kmalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
+		if (self == NULL) {
+			ERROR(__FUNCTION__"(), kmalloc failed!\n");
+			MOD_DEC_USE_COUNT;
+			return -ENOMEM;
+		}
+		memset(self, 0, sizeof(struct ircomm_tty_cb));
+		
+		self->magic = IRCOMM_TTY_MAGIC;
+		self->flow = FLOW_STOP;
+
+		self->line = line;
+		self->tqueue.routine = ircomm_tty_do_softint;
+		self->tqueue.data = self;
+		self->max_header_size = 5;
+		self->max_data_size = 64-self->max_header_size;
+		self->close_delay = 5*HZ/10;
+		self->closing_wait = 30*HZ;
+
+		/* Init some important stuff */
+		init_timer(&self->watchdog_timer);
+		/* init_waitqueue_head(&self->open_wait); */
+/* 		init_waitqueue_head(&self->close_wait); */
+
+		/* 
+		 * Force TTY into raw mode by default which is usually what
+		 * we want for IrCOMM and IrLPT. This way applications will
+		 * not have to twiddle with printcap etc.  
+		 */
+		tty->termios->c_iflag = 0;
+		tty->termios->c_oflag = 0;
+
+		/* Insert into hash */
+		hashbin_insert(ircomm_tty, (queue_t *) self, line, NULL);
+	}
+	self->open_count++;
+
+	tty->driver_data = self;
+	self->tty = tty;
+
+	IRDA_DEBUG(1, __FUNCTION__"(), %s%d, count = %d\n", tty->driver.name, 
+		   self->line, self->open_count);
+
+	/* Not really used by us, but lets do it anyway */
+	self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	/*
+	 * If the port is the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (self->flags & ASYNC_CLOSING)) {
+		if (self->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&self->close_wait);
+		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
+#ifdef SERIAL_DO_RESTART
+		return ((self->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/* Check if this is a "normal" ircomm device, or an irlpt device */
+	if (line < 0x10) {
+		self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
+		self->settings.service_type = IRCOMM_9_WIRE; /* Default */
+		IRDA_DEBUG(2, __FUNCTION__ "(), IrCOMM device\n");
+	} else {
+		IRDA_DEBUG(2, __FUNCTION__ "(), IrLPT device\n");
+		self->service_type = IRCOMM_3_WIRE_RAW;
+		self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */
+	}
+
+	ret = ircomm_tty_startup(self);
+	if (ret)
+		return ret;
+
+	ret = ircomm_tty_block_til_ready(self, filp);
+	if (ret) {
+		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
+		IRDA_DEBUG(2, __FUNCTION__ 
+		      "(), returning after block_til_ready with %d\n",
+		      ret);
+
+		return ret;
+	}
+
+	self->session = current->session;
+	self->pgrp = current->pgrp;
+
+	return 0;
+}
+
+/*
+ * Function ircomm_tty_close (tty, filp)
+ *
+ *    This routine is called when a particular tty device is closed.
+ *
+ */
+static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	unsigned long flags;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	if (!tty)
+		return;
+
+	save_flags(flags); 
+	cli();
+
+	if (tty_hung_up_p(filp)) {
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+
+		IRDA_DEBUG(0, __FUNCTION__ "(), returning 1\n");
+		return;
+	}
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	if ((tty->count == 1) && (self->open_count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  state->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), bad serial port count; "
+			   "tty->count is 1, state->count is %d\n", 
+			   self->open_count);
+		self->open_count = 1;
+	}
+
+	if (--self->open_count < 0) {
+		ERROR(__FUNCTION__ 
+		      "(), bad serial port count for ttys%d: %d\n",
+		      self->line, self->open_count);
+		self->open_count = 0;
+	}
+	if (self->open_count) {
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+
+		IRDA_DEBUG(0, __FUNCTION__ "(), open count > 0\n");
+		return;
+	}
+	self->flags |= ASYNC_CLOSING;
+
+	/*
+	 * 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 (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, self->closing_wait);
+
+	ircomm_tty_shutdown(self);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+
+	tty->closing = 0;
+	self->tty = 0;
+
+	if (self->blocked_open) {
+		if (self->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(self->close_delay);
+		}
+		wake_up_interruptible(&self->open_wait);
+	}
+
+	self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&self->close_wait);
+
+	MOD_DEC_USE_COUNT;
+	restore_flags(flags);
+}
+
+/*
+ * Function ircomm_tty_flush_buffer (tty)
+ *
+ *    
+ *
+ */
+static void ircomm_tty_flush_buffer(struct tty_struct *tty)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	/* 
+	 * Let do_softint() do this to avoid race condition with 
+	 * do_softint() ;-) 
+	 */
+	queue_task(&self->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * Function ircomm_tty_do_softint (private_)
+ *
+ *    We use this routine to give the write wakeup to the user at at a
+ *    safe time (as fast as possible after write have completed). This 
+ *    can be compared to the Tx interrupt.
+ */
+static void ircomm_tty_do_softint(void *private_)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_;
+	struct tty_struct *tty;
+	unsigned long flags;
+	struct sk_buff *skb, *ctrl_skb;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if (!self || self->magic != IRCOMM_TTY_MAGIC)
+		return;
+
+	tty = self->tty;
+	if (!tty)
+		return;
+
+	/* Unlink control buffer */
+	save_flags(flags);
+	cli();
+
+	ctrl_skb = self->ctrl_skb;
+	self->ctrl_skb = NULL;
+
+	restore_flags(flags);
+
+	/* Flush control buffer if any */
+	if (ctrl_skb && self->flow == FLOW_START)
+		ircomm_control_request(self->ircomm, ctrl_skb);
+
+	if (tty->hw_stopped)
+		return;
+
+	/* Unlink transmit buffer */
+	save_flags(flags);
+	cli();
+	
+	skb = self->tx_skb;
+	self->tx_skb = NULL;
+
+	restore_flags(flags);	
+
+	/* Flush transmit buffer if any */
+	if (skb)
+		ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
+		
+	/* Check if user (still) wants to be waken up */
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
+	    tty->ldisc.write_wakeup)
+	{
+		(tty->ldisc.write_wakeup)(tty);
+	}
+	wake_up_interruptible(&tty->write_wait);
+}
+
+/*
+ * Function ircomm_tty_write (tty, from_user, buf, count)
+ *
+ *    This routine is called by the kernel to write a series of characters
+ *    to the tty device. The characters may come from user space or kernel
+ *    space. This routine will return the number of characters actually
+ *    accepted for writing. This routine is mandatory.
+ */
+static int ircomm_tty_write(struct tty_struct *tty, int from_user,
+			    const unsigned char *buf, int count)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	unsigned long flags;
+	struct sk_buff *skb;
+	int tailroom = 0;
+	int len = 0;
+	int size;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), count=%d, hw_stopped=%d\n", count,
+		   tty->hw_stopped);
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	save_flags(flags);
+	cli();
+
+	/* Fetch current transmit buffer */
+	skb = self->tx_skb;
+
+	/*  
+	 * Send out all the data we get, possibly as multiple fragmented
+	 * frames, but this will only happen if the data is larger than the
+	 * max data size. The normal case however is just the opposite, and
+	 * this function may be called multiple times, and will then actually
+	 * defragment the data and send it out as one packet as soon as 
+	 * possible, but at a safer point in time
+	 */
+	while (count) {
+		size = count;
+
+		/* Adjust data size to the max data size */
+		if (size > self->max_data_size)
+			size = self->max_data_size;
+		
+		/* 
+		 * Do we already have a buffer ready for transmit, or do
+		 * we need to allocate a new frame 
+		 */
+		if (skb) {			
+			/* 
+			 * Any room for more data at the end of the current 
+			 * transmit buffer? Cannot use skb_tailroom, since
+			 * dev_alloc_skb gives us a larger skb than we 
+			 * requested
+			 */
+			if ((tailroom = (self->max_data_size-skb->len)) > 0) {
+				/* Adjust data to tailroom */
+				if (size > tailroom)
+					size = tailroom;
+			} else {
+				/* 
+				 * Current transmit frame is full, so break 
+				 * out, so we can send it as soon as possible
+				 */
+				break;
+			}
+		} else {
+			/* Prepare a full sized frame */
+			skb = dev_alloc_skb(self->max_data_size+
+					    self->max_header_size);
+			if (!skb) {
+				restore_flags(flags);
+				return -ENOBUFS;
+			}
+			skb_reserve(skb, self->max_header_size);
+			self->tx_skb = skb;
+		}
+		
+		/* Copy data */
+		if (from_user)
+			copy_from_user(skb_put(skb,size), buf+len, size);
+		else
+			memcpy(skb_put(skb,size), buf+len, size);
+		
+		count -= size;
+		len += size;
+	}
+
+	restore_flags(flags);
+
+	/*     
+	 * Schedule a new thread which will transmit the frame as soon
+	 * as possible, but at a safe point in time. We do this so the
+	 * "user" can give us data multiple times, as PPP does (because of
+	 * its 256 byte tx buffer). We will then defragment and send out
+	 * all this data as one single packet.  
+	 */
+	queue_task(&self->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	
+	return len;
+}
+
+/*
+ * Function ircomm_tty_write_room (tty)
+ *
+ *    This routine returns the numbers of characters the tty driver will
+ *    accept for queuing to be written. This number is subject to change as
+ *    output buffers get emptied, or if the output flow control is acted.
+ */
+static int ircomm_tty_write_room(struct tty_struct *tty)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	unsigned long flags;
+	int ret;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	/* Check if we are allowed to transmit any data */
+	if (tty->hw_stopped)
+		ret = 0;
+	else {
+		save_flags(flags);
+		cli();
+		if (self->tx_skb)
+			ret = self->max_data_size - self->tx_skb->len;
+		else
+			ret = self->max_data_size;
+		restore_flags(flags);
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), ret=%d\n", ret);
+
+	return ret;
+}
+
+/*
+ * Function ircomm_tty_wait_until_sent (tty, timeout)
+ *
+ *    This routine waits until the device has written out all of the
+ *    characters in its transmitter FIFO.
+ */
+static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	unsigned long orig_jiffies, poll_time;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	orig_jiffies = jiffies;
+
+	/* Set poll time to 200 ms */
+	poll_time = IRDA_MIN(timeout, MSECS_TO_JIFFIES(200));
+
+	while (self->tx_skb && self->tx_skb->len) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(poll_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+			break;
+	}
+	current->state = TASK_RUNNING;
+}
+
+/*
+ * Function ircomm_tty_throttle (tty)
+ *
+ *    This routine notifies the tty driver that input buffers for the line
+ *    discipline are close to full, and it should somehow signal that no
+ *    more characters should be sent to the tty.  
+ */
+static void ircomm_tty_throttle(struct tty_struct *tty)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	/* Software flow control? */
+	if (I_IXOFF(tty))
+		ircomm_tty_send_xchar(tty, STOP_CHAR(tty));
+	
+	/* Hardware flow control? */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		self->settings.dte &= ~IRCOMM_RTS;
+		self->settings.dte |= IRCOMM_DELTA_RTS;
+	
+		ircomm_param_request(self, IRCOMM_DTE, TRUE);
+	}
+
+        ircomm_flow_request(self->ircomm, FLOW_STOP);
+}
+
+/*
+ * Function ircomm_tty_unthrottle (tty)
+ *
+ *    This routine notifies the tty drivers that it should signals that
+ *    characters can now be sent to the tty without fear of overrunning the
+ *    input buffers of the line disciplines.
+ */
+static void ircomm_tty_unthrottle(struct tty_struct *tty)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	/* Using software flow control? */
+	if (I_IXOFF(tty)) {
+		ircomm_tty_send_xchar(tty, START_CHAR(tty));
+	}
+
+	/* Using hardware flow control? */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
+
+		ircomm_param_request(self, IRCOMM_DTE, TRUE);
+		IRDA_DEBUG(1, __FUNCTION__"(), FLOW_START\n");
+	}
+        ircomm_flow_request(self->ircomm, FLOW_START);
+}
+
+/*
+ * Function ircomm_tty_chars_in_buffer (tty)
+ *
+ *    Indicates if there are any data in the buffer
+ *
+ */
+static int ircomm_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	unsigned long flags;
+	int len = 0;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	save_flags(flags);
+	cli();
+
+	if (self->tx_skb)
+		len = self->tx_skb->len;
+
+	restore_flags(flags);
+
+	return len;
+}
+
+static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
+{
+	unsigned long flags;
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	
+	if (!(self->flags & ASYNC_INITIALIZED))
+		return;
+
+	save_flags(flags);
+	cli();
+
+	del_timer(&self->watchdog_timer);
+	
+	/* Free parameter buffer */
+	if (self->ctrl_skb) {
+		dev_kfree_skb(self->ctrl_skb);
+		self->ctrl_skb = NULL;
+	}
+
+	/* Free transmit buffer */
+	if (self->tx_skb) {
+		dev_kfree_skb(self->tx_skb);
+		self->tx_skb = NULL;
+	}
+
+	ircomm_tty_detach_cable(self);
+
+	if (self->ircomm) {
+		ircomm_close(self->ircomm);
+		self->ircomm = NULL;
+	}
+	self->flags &= ~ASYNC_INITIALIZED;
+
+	restore_flags(flags);
+}
+
+/*
+ * Function ircomm_tty_hangup (tty)
+ *
+ *    This routine notifies the tty driver that it should hangup the tty
+ *    device.
+ * 
+ */
+static void ircomm_tty_hangup(struct tty_struct *tty)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+
+	IRDA_DEBUG(0, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	if (!tty)
+		return;
+
+	/* ircomm_tty_flush_buffer(tty); */
+	ircomm_tty_shutdown(self);
+
+	self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	self->tty = 0;
+	self->open_count = 0;
+	wake_up_interruptible(&self->open_wait);
+}
+
+/*
+ * Function ircomm_tty_send_xchar (tty, ch)
+ *
+ *    This routine is used to send a high-priority XON/XOFF character to
+ *    the device.
+ */
+static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch)
+{
+	IRDA_DEBUG(0, __FUNCTION__"(), not impl\n");
+}
+
+/*
+ * Function ircomm_tty_start (tty)
+ *
+ *    This routine notifies the tty driver that it resume sending
+ *    characters to the tty device.  
+ */
+void ircomm_tty_start(struct tty_struct *tty)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+
+	ircomm_flow_request(self->ircomm, FLOW_START);
+}
+
+/*
+ * Function ircomm_tty_stop (tty)
+ *
+ *     This routine notifies the tty driver that it should stop outputting
+ *     characters to the tty device. 
+ */
+void ircomm_tty_stop(struct tty_struct *tty) 
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	ircomm_flow_request(self->ircomm, FLOW_STOP);
+}
+
+/*
+ * Function ircomm_check_modem_status (self)
+ *
+ *    Check for any changes in the DCE's line settings. This function should
+ *    be called whenever the dce parameter settings changes, to update the
+ *    flow control settings and other things
+ */
+void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
+{
+	struct tty_struct *tty;
+	int status;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	tty = self->tty;
+
+	status = self->settings.dce;
+
+	if (status & IRCOMM_DCE_DELTA_ANY) {
+		/*wake_up_interruptible(&self->delta_msr_wait);*/
+	}
+	if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
+		IRDA_DEBUG(2, __FUNCTION__ 
+			   "(), ircomm%d CD now %s...\n", self->line,
+			   (status & IRCOMM_CD) ? "on" : "off");
+
+		if (status & IRCOMM_CD) {
+			wake_up_interruptible(&self->open_wait);
+		} else if (!((self->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (self->flags & ASYNC_CALLOUT_NOHUP))) 
+		{
+			IRDA_DEBUG(2, __FUNCTION__ 
+				   "(), Doing serial hangup..\n");
+			if (tty)
+				tty_hangup(tty);
+
+			/* Hangup will remote the tty, so better break out */
+			return;
+		}
+	}
+	if (self->flags & ASYNC_CTS_FLOW) {
+		if (tty->hw_stopped) {
+			if (status & IRCOMM_CTS) {
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "(), CTS tx start...\n");
+				tty->hw_stopped = 0;
+				
+				queue_task(&self->tqueue, &tq_immediate);
+				mark_bh(IMMEDIATE_BH);
+				return;
+			}
+		} else {
+			if (!(status & IRCOMM_CTS)) {
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "(), CTS tx stop...\n");
+				tty->hw_stopped = 1;
+			}
+		}
+	}
+}
+
+/*
+ * Function ircomm_tty_data_indication (instance, sap, skb)
+ *
+ *    Handle incomming data, and deliver it to the line discipline
+ *
+ */
+static int ircomm_tty_data_indication(void *instance, void *sap,
+				      struct sk_buff *skb)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	IRDA_DEBUG(2, __FUNCTION__"()\n");
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	ASSERT(skb != NULL, return -1;);
+
+	if (!self->tty) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), no tty!\n");
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	/* 
+	 * If we receive data when hardware is stopped then something is wrong.
+	 * We try to poll the peers line settings to check if we are up todate.
+	 * Devices like WinCE can do this, and since they don't send any 
+	 * params, we can just as well declare the hardware for running.
+	 */
+	if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), polling for line settings!\n");
+		ircomm_param_request(self, IRCOMM_POLL, TRUE);
+
+		/* We can just as well declare the hardware for running */
+		ircomm_tty_send_initial_parameters(self);
+		ircomm_tty_link_established(self);
+	}
+
+	/* 
+	 * Just give it over to the line discipline. There is no need to
+	 * involve the flip buffers, since we are not running in an interrupt 
+	 * handler
+	 */
+	self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len);
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_tty_control_indication (instance, sap, skb)
+ *
+ *    Parse all incomming parameters (easy!)
+ *
+ */
+static int ircomm_tty_control_indication(void *instance, void *sap,
+					 struct sk_buff *skb)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	int clen;
+
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+	ASSERT(skb != NULL, return -1;);
+
+	clen = skb->data[0];
+
+	irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen), 
+			       &ircomm_param_info);
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_tty_flow_indication (instance, sap, cmd)
+ *
+ *    This function is called by IrTTP when it wants us to slow down the
+ *    transmission of data. We just mark the hardware as stopped, and wait
+ *    for IrTTP to notify us that things are OK again.
+ */
+static void ircomm_tty_flow_indication(void *instance, void *sap, 
+				       LOCAL_FLOW cmd)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	struct tty_struct *tty;
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	tty = self->tty;
+
+	switch (cmd) {
+	case FLOW_START:
+		IRDA_DEBUG(2, __FUNCTION__ "(), hw start!\n");
+		tty->hw_stopped = 0;
+
+		/* ircomm_tty_do_softint will take care of the rest */
+		queue_task(&self->tqueue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		break;
+	default:  /* If we get here, something is very wrong, better stop */
+	case FLOW_STOP:
+		IRDA_DEBUG(2, __FUNCTION__ "(), hw stopped!\n");
+		tty->hw_stopped = 1;
+		break;
+	}
+	self->flow = cmd;
+}
+
+static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
+{
+        int  ret=0;
+
+	ret += sprintf(buf+ret, "State: %s\n", ircomm_tty_state[self->state]);
+
+	ret += sprintf(buf+ret, "Service type: ");
+	if (self->service_type & IRCOMM_9_WIRE)
+		ret += sprintf(buf+ret, "9_WIRE");
+	else if (self->service_type & IRCOMM_3_WIRE)
+		ret += sprintf(buf+ret, "3_WIRE");
+	else if (self->service_type & IRCOMM_3_WIRE_RAW)
+		ret += sprintf(buf+ret, "3_WIRE_RAW");
+	else
+		ret += sprintf(buf+ret, "No common service type!\n");
+        ret += sprintf(buf+ret, "\n");
+
+	ret += sprintf(buf+ret, "Port name: %s\n", self->settings.port_name);
+
+	ret += sprintf(buf+ret, "DTE status: ");	
+        if (self->settings.dte & IRCOMM_RTS)
+                ret += sprintf(buf+ret, "RTS|");
+        if (self->settings.dte & IRCOMM_DTR)
+                ret += sprintf(buf+ret, "DTR|");
+	if (self->settings.dte)
+		ret--; /* remove the last | */
+        ret += sprintf(buf+ret, "\n");
+
+	ret += sprintf(buf+ret, "DCE status: ");
+        if (self->settings.dce & IRCOMM_CTS)
+                ret += sprintf(buf+ret, "CTS|");
+        if (self->settings.dce & IRCOMM_DSR)
+                ret += sprintf(buf+ret, "DSR|");
+        if (self->settings.dce & IRCOMM_CD)
+                ret += sprintf(buf+ret, "CD|");
+        if (self->settings.dce & IRCOMM_RI) 
+                ret += sprintf(buf+ret, "RI|");
+	if (self->settings.dce)
+		ret--; /* remove the last | */
+        ret += sprintf(buf+ret, "\n");
+
+	ret += sprintf(buf+ret, "Configuration: ");
+	if (!self->settings.null_modem)
+		ret += sprintf(buf+ret, "DTE <-> DCE\n");
+	else
+		ret += sprintf(buf+ret, 
+			       "DTE <-> DTE (null modem emulation)\n");
+
+	ret += sprintf(buf+ret, "Data rate: %d\n", self->settings.data_rate);
+
+	ret += sprintf(buf+ret, "Flow control: ");
+	if (self->settings.flow_control & IRCOMM_XON_XOFF_IN)
+		ret += sprintf(buf+ret, "XON_XOFF_IN|");
+	if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT)
+		ret += sprintf(buf+ret, "XON_XOFF_OUT|");
+	if (self->settings.flow_control & IRCOMM_RTS_CTS_IN)
+		ret += sprintf(buf+ret, "RTS_CTS_IN|");
+	if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT)
+		ret += sprintf(buf+ret, "RTS_CTS_OUT|");
+	if (self->settings.flow_control & IRCOMM_DSR_DTR_IN)
+		ret += sprintf(buf+ret, "DSR_DTR_IN|");
+	if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT)
+		ret += sprintf(buf+ret, "DSR_DTR_OUT|");
+	if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN)
+		ret += sprintf(buf+ret, "ENQ_ACK_IN|");
+	if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT)
+		ret += sprintf(buf+ret, "ENQ_ACK_OUT|");
+	if (self->settings.flow_control)
+		ret--; /* remove the last | */
+        ret += sprintf(buf+ret, "\n");
+
+	ret += sprintf(buf+ret, "Flags: ");
+	if (self->flags & ASYNC_CTS_FLOW)
+		ret += sprintf(buf+ret, "ASYNC_CTS_FLOW|");
+	if (self->flags & ASYNC_CHECK_CD)
+		ret += sprintf(buf+ret, "ASYNC_CHECK_CD|");
+	if (self->flags & ASYNC_INITIALIZED)
+		ret += sprintf(buf+ret, "ASYNC_INITIALIZED|");
+	if (self->flags & ASYNC_LOW_LATENCY)
+		ret += sprintf(buf+ret, "ASYNC_LOW_LATENCY|");
+	if (self->flags & ASYNC_CLOSING)
+		ret += sprintf(buf+ret, "ASYNC_CLOSING|");
+	if (self->flags & ASYNC_NORMAL_ACTIVE)
+		ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|");
+	if (self->flags & ASYNC_CALLOUT_ACTIVE)
+		ret += sprintf(buf+ret, "ASYNC_CALLOUT_ACTIVE|");
+	if (self->flags)
+		ret--; /* remove the last | */
+	ret += sprintf(buf+ret, "\n");
+
+	ret += sprintf(buf+ret, "Role: %s\n", self->client ? 
+		       "client" : "server");
+	ret += sprintf(buf+ret, "Open count: %d\n", self->open_count);
+	ret += sprintf(buf+ret, "Max data size: %d\n", self->max_data_size);
+	ret += sprintf(buf+ret, "Max header size: %d\n", self->max_header_size);
+		
+	if (self->tty)
+		ret += sprintf(buf+ret, "Hardware: %s\n", 
+			       self->tty->hw_stopped ? "Stopped" : "Running");
+
+        ret += sprintf(buf+ret, "\n");
+        return ret;
+}
+
+
+/*
+ * Function ircomm_tty_read_proc (buf, start, offset, len, eof, unused)
+ *
+ *    
+ *
+ */
+static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
+				int *eof, void *unused)
+{
+	struct ircomm_tty_cb *self;
+        int count = 0, l;
+        off_t begin = 0;
+
+	self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
+	while ((self != NULL) && (count < 4000)) {
+		if (self->magic != IRCOMM_TTY_MAGIC)
+			return 0;
+
+                l = ircomm_tty_line_info(self, buf + count);
+                count += l;
+                if (count+begin > offset+len)
+                        goto done;
+                if (count+begin < offset) {
+                        begin += count;
+                        count = 0;
+                }
+				
+		self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
+        }
+        *eof = 1;
+done:
+        if (offset >= count+begin)
+                return 0;
+        *start = buf + (begin-offset);
+        return ((len < begin+count-offset) ? len : begin+count-offset);
+}
+
+
+#ifdef MODULE
+int init_module(void) 
+{
+	return ircomm_tty_init();
+}
+
+void cleanup_module(void)
+{
+	ircomm_tty_cleanup();
+}
+
+#endif /* MODULE */
+
+
+
+
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_tty_attach.c linux/net/irda/ircomm/ircomm_tty_attach.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_tty_attach.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/ircomm_tty_attach.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,925 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_tty_attach.c
+ * Version:       
+ * Description:   Code for attaching the serial driver to IrCOMM
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sat Jun  5 17:42:00 1999
+ * Modified at:   Tue Jan  4 14:20:49 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1999-2000 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/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irlmp.h>
+#include <net/irda/iriap.h>
+#include <net/irda/irttp.h>
+#include <net/irda/irias_object.h>
+#include <net/irda/parameters.h>
+
+#include <net/irda/ircomm_core.h>
+#include <net/irda/ircomm_param.h>
+#include <net/irda/ircomm_event.h>
+
+#include <net/irda/ircomm_tty.h>
+#include <net/irda/ircomm_tty_attach.h>
+
+static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
+static void ircomm_tty_discovery_indication(discovery_t *discovery);
+static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
+					struct ias_value *value, void *priv);
+void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout);
+void ircomm_tty_watchdog_timer_expired(void *data);
+
+static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, 
+				 IRCOMM_TTY_EVENT event, 
+				 struct sk_buff *skb, 
+				 struct ircomm_tty_info *info);
+static int ircomm_tty_state_search(struct ircomm_tty_cb *self, 
+				   IRCOMM_TTY_EVENT event, 
+				   struct sk_buff *skb, 
+				   struct ircomm_tty_info *info);
+static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, 
+					     IRCOMM_TTY_EVENT event, 
+					     struct sk_buff *skb, 
+					     struct ircomm_tty_info *info);
+static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, 
+					   IRCOMM_TTY_EVENT event, 
+					   struct sk_buff *skb, 
+					   struct ircomm_tty_info *info);
+static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, 
+				  IRCOMM_TTY_EVENT event, 
+				  struct sk_buff *skb, 
+				  struct ircomm_tty_info *info);
+static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, 
+				  IRCOMM_TTY_EVENT event, 
+				  struct sk_buff *skb, 
+				  struct ircomm_tty_info *info);
+
+char *ircomm_tty_state[] = {
+	"IRCOMM_TTY_IDLE",
+	"IRCOMM_TTY_SEARCH",
+	"IRCOMM_TTY_QUERY_PARAMETERS",
+	"IRCOMM_TTY_QUERY_LSAP_SEL",
+	"IRCOMM_TTY_SETUP",
+	"IRCOMM_TTY_READY",
+	"*** ERROR *** ",
+};
+
+char *ircomm_tty_event[] = {
+	"IRCOMM_TTY_ATTACH_CABLE",
+	"IRCOMM_TTY_DETACH_CABLE",
+	"IRCOMM_TTY_DATA_REQUEST",
+	"IRCOMM_TTY_DATA_INDICATION",
+	"IRCOMM_TTY_DISCOVERY_REQUEST",
+	"IRCOMM_TTY_DISCOVERY_INDICATION",
+	"IRCOMM_TTY_CONNECT_CONFIRM",
+	"IRCOMM_TTY_CONNECT_INDICATION",
+	"IRCOMM_TTY_DISCONNECT_REQUEST",
+	"IRCOMM_TTY_DISCONNECT_INDICATION",
+	"IRCOMM_TTY_WD_TIMER_EXPIRED",
+	"IRCOMM_TTY_GOT_PARAMETERS",
+	"IRCOMM_TTY_GOT_LSAPSEL",
+	"*** ERROR ****",
+};
+
+static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
+		      struct sk_buff *skb, struct ircomm_tty_info *info) = 
+{
+	ircomm_tty_state_idle,
+	ircomm_tty_state_search,
+	ircomm_tty_state_query_parameters,
+	ircomm_tty_state_query_lsap_sel,
+	ircomm_tty_state_setup,
+	ircomm_tty_state_ready,
+};
+
+/*
+ * Function ircomm_tty_attach_cable (driver)
+ *
+ *    Try to attach cable (IrCOMM link). This function will only return
+ *    when the link has been connected, or if an error condition occurs. 
+ *    If success, the return value is the resulting service type.
+ */
+int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+       	/* Check if somebody has already connected to us */
+	if (ircomm_is_connected(self->ircomm)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), already connected!\n");
+		return 0;
+	}
+
+	/* Make sure nobody tries to write before the link is up */
+	self->tty->hw_stopped = 1;
+
+	ircomm_tty_ias_register(self);
+
+	/* Check if somebody has already connected to us */
+	if (ircomm_is_connected(self->ircomm)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), already connected!\n");
+		return 0;
+	}
+
+	ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
+
+	return 0;
+}
+
+/*
+ * Function ircomm_detach_cable (driver)
+ *
+ *    Detach cable, or cable has been detached by peer
+ *
+ */
+void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	del_timer(&self->watchdog_timer);
+
+	/* Remove IrCOMM hint bits */
+	irlmp_unregister_client(self->ckey);
+	irlmp_unregister_service(self->skey);
+
+	if (self->iriap) { 
+		iriap_close(self->iriap);
+		self->iriap = NULL;
+	}
+
+	/* Remove LM-IAS object */
+	if (self->obj) {
+		irias_delete_object(self->obj);
+		self->obj = NULL;
+	}
+
+	ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL);
+
+	/* Reset some values */
+	self->daddr = self->saddr = 0;
+	self->dlsap_sel = self->slsap_sel = 0;
+
+	memset(&self->settings, 0, sizeof(struct ircomm_params));
+}
+
+/*
+ * Function ircomm_tty_ias_register (self)
+ *
+ *    Register with LM-IAS depending on which service type we are
+ *
+ */
+static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
+{
+	__u8 oct_seq[6];
+	__u16 hints;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+	
+	if (self->service_type & IRCOMM_3_WIRE_RAW) {
+		hints = irlmp_service_to_hint(S_PRINTER);
+		hints |= irlmp_service_to_hint(S_COMM);
+		
+		/* Register IrLPT with LM-IAS */
+		self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
+		irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", 
+					 self->slsap_sel);
+		irias_insert_object(self->obj);
+	} else {
+		hints = irlmp_service_to_hint(S_COMM);
+
+		/* Register IrCOMM with LM-IAS */
+		self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
+		irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", 
+					 self->slsap_sel);
+		
+		/* Code the parameters into the buffer */
+		irda_param_pack(oct_seq, "bbbbbb", 
+				IRCOMM_SERVICE_TYPE, 1, self->service_type,
+				IRCOMM_PORT_TYPE,    1, IRCOMM_SERIAL);
+		
+		/* Register parameters with LM-IAS */
+		irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6);
+		irias_insert_object(self->obj);
+	}
+	self->skey = irlmp_register_service(hints);
+	self->ckey = irlmp_register_client(
+		hints, ircomm_tty_discovery_indication, NULL);
+}
+
+/*
+ * Function ircomm_send_initial_parameters (self)
+ *
+ *    Send initial parameters to the remote IrCOMM device. These parameters
+ *    must be sent before any data.
+ */
+int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
+{
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	if (self->service_type & IRCOMM_3_WIRE_RAW) 
+		return 0;
+
+	/* 
+	 * Set default values, but only if the application for some reason 
+	 * haven't set them already
+	 */
+	IRDA_DEBUG(2, __FUNCTION__ "(), data-rate = %d\n", 
+		   self->settings.data_rate);
+	if (!self->settings.data_rate)
+		self->settings.data_rate = 9600;
+	IRDA_DEBUG(2, __FUNCTION__ "(), data-format = %d\n", 
+		   self->settings.data_format);
+	if (!self->settings.data_format)
+		self->settings.data_format = IRCOMM_WSIZE_8;  /* 8N1 */
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), flow-control = %d\n", 
+		   self->settings.flow_control);
+	/*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
+
+	/* Do not set delta values for the initial parameters */
+	self->settings.dte = IRCOMM_DTR | IRCOMM_RTS;
+
+	/* Only send service type parameter when we are the client */
+	if (self->client)
+		ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);
+	ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
+	ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
+	
+	/* For a 3 wire service, we just flush the last parameter and return */
+	if (self->settings.service_type == IRCOMM_3_WIRE) {
+		ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
+		return 0;
+	}
+
+	/* Only 9-wire service types continue here */
+	ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE);
+#if 0
+	ircomm_param_request(self, IRCOMM_XON_XOFF, FALSE);
+	ircomm_param_request(self, IRCOMM_ENQ_ACK, FALSE);
+#endif	
+	/* Notify peer that we are ready to receive data */
+	ircomm_param_request(self, IRCOMM_DTE, TRUE);
+	
+	return 0;
+}
+
+/*
+ * Function ircomm_tty_discovery_indication (discovery)
+ *
+ *    Remote device is discovered, try query the remote IAS to see which
+ *    device it is, and which services it has.
+ *
+ */
+static void ircomm_tty_discovery_indication(discovery_t *discovery)
+{
+	struct ircomm_tty_cb *self;
+	struct ircomm_tty_info info;
+
+	IRDA_DEBUG(2, __FUNCTION__"()\n");
+
+	info.daddr = discovery->daddr;
+	info.saddr = discovery->saddr;
+
+	self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
+	while (self != NULL) {
+		ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+		
+		ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION, 
+				    NULL, &info);
+
+		self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
+	}
+}
+
+/*
+ * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)
+ *
+ *    Link disconnected
+ *
+ */
+void ircomm_tty_disconnect_indication(void *instance, void *sap, 
+				      LM_REASON reason,
+				      struct sk_buff *skb)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	if (!self->tty)
+		return;
+
+	/* This will stop control data transfers */
+	self->flow = FLOW_STOP;
+
+	/* Stop data transfers */
+	self->tty->hw_stopped = 1;
+
+	ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL, 
+			    NULL);
+}
+
+/*
+ * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv)
+ *
+ *    Got result from the IAS query we make
+ *
+ */
+static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
+					struct ias_value *value, 
+					void *priv)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
+
+	IRDA_DEBUG(2, __FUNCTION__"()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	/* We probably don't need to make any more queries */
+	iriap_close(self->iriap);
+	self->iriap = NULL;
+
+	/* Check if request succeeded */
+	if (result != IAS_SUCCESS) {
+		IRDA_DEBUG(4, __FUNCTION__ "(), got NULL value!\n");
+		return;
+	}
+
+	switch (value->type) {
+ 	case IAS_OCT_SEQ:
+		IRDA_DEBUG(2, __FUNCTION__"(), got octet sequence\n");
+
+		irda_param_extract_all(self, value->t.oct_seq, value->len,
+				       &ircomm_param_info);
+
+		ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL, 
+				    NULL);
+		break;
+	case IAS_INTEGER:
+		/* Got LSAP selector */	
+		IRDA_DEBUG(2, __FUNCTION__"(), got lsapsel = %d\n", 
+			   value->t.integer);
+
+		if (value->t.integer == -1) {
+			IRDA_DEBUG(0, __FUNCTION__"(), invalid value!\n");
+		} else
+			self->dlsap_sel = value->t.integer;
+
+		ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
+		break;
+	case IAS_MISSING:
+		IRDA_DEBUG(0, __FUNCTION__"(), got IAS_MISSING\n");
+		break;
+	default:
+		IRDA_DEBUG(0, __FUNCTION__"(), got unknown type!\n");
+		break;
+	}
+	irias_delete_value(value);
+}
+
+/*
+ * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb)
+ *
+ *    Connection confirmed
+ *
+ */
+void ircomm_tty_connect_confirm(void *instance, void *sap, 
+				struct qos_info *qos, 
+				__u32 max_data_size, 
+				__u8 max_header_size, 
+				struct sk_buff *skb)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	self->client = TRUE;
+	self->max_data_size = max_data_size;
+	self->max_header_size = max_header_size;
+	self->flow = FLOW_START;
+
+	ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
+
+	dev_kfree_skb(skb);
+}
+
+/*
+ * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size, 
+ *                                         skb)
+ *
+ *    we are discovered and being requested to connect by remote device !
+ *
+ */
+void ircomm_tty_connect_indication(void *instance, void *sap, 
+				   struct qos_info *qos, 
+				   __u32 max_data_size,
+				   __u8 max_header_size, 
+				   struct sk_buff *skb)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	int clen;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	self->client = FALSE;
+	self->max_data_size = max_data_size;
+	self->max_header_size = max_header_size;
+	self->flow = FLOW_START;
+
+	clen = skb->data[0];
+	if (clen)
+		irda_param_extract_all(self, skb->data+1, 
+				       IRDA_MIN(skb->len, clen), 
+				       &ircomm_param_info);
+
+	ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
+
+	dev_kfree_skb(skb);
+}
+
+/*
+ * Function ircomm_tty_link_established (self)
+ *
+ *    Called when the IrCOMM link is established
+ *
+ */
+void ircomm_tty_link_established(struct ircomm_tty_cb *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	if (!self->tty)
+		return;
+	
+	del_timer(&self->watchdog_timer);
+
+	/* 
+	 * IrCOMM link is now up, and if we are not using hardware
+	 * flow-control, then declare the hardware as running. Otherwise we
+	 * will have to wait for the peer device (DCE) to raise the CTS
+	 * line.  
+	 */
+	if (self->flags & ASYNC_CTS_FLOW) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), waiting for CTS ...\n");
+		return;
+	} else {
+		IRDA_DEBUG(2, __FUNCTION__ "(), starting hardware!\n");
+
+		self->tty->hw_stopped = 0;
+	
+		/* Wake up processes blocked on open */
+		wake_up_interruptible(&self->open_wait);
+	}
+
+	queue_task(&self->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * Function irlan_start_watchdog_timer (self, timeout)
+ *
+ *    Start the watchdog timer. This timer is used to make sure that any 
+ *    connection attempt is successful, and if not, we will retry after 
+ *    the timeout
+ */
+void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout)
+{
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
+			 ircomm_tty_watchdog_timer_expired);
+}
+
+/*
+ * Function ircomm_tty_watchdog_timer_expired (data)
+ *
+ *    Called when the connect procedure have taken to much time.
+ *
+ */
+void ircomm_tty_watchdog_timer_expired(void *data)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
+}
+
+/*
+ * Function ircomm_tty_state_idle (self, event, skb, info)
+ *
+ *    Just hanging around
+ *
+ */
+static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, 
+				 IRCOMM_TTY_EVENT event, 
+				 struct sk_buff *skb, 
+				 struct ircomm_tty_info *info)
+{
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
+		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
+	switch (event) {
+	case IRCOMM_TTY_ATTACH_CABLE:
+		/* Try to discover any remote devices */		
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+		ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
+		
+		irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
+		break;
+	case IRCOMM_TTY_DISCOVERY_INDICATION:
+		self->daddr = info->daddr;
+		self->saddr = info->saddr;
+
+		if (self->iriap) {
+			WARNING(__FUNCTION__ 
+				"(), busy with a previous query\n");
+			return -EBUSY;
+		}
+
+		self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+					 ircomm_tty_getvalue_confirm);
+
+		iriap_getvaluebyclass_request(self->iriap,
+					      self->saddr, self->daddr,
+					      "IrDA:IrCOMM", "Parameters");
+		
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+		ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
+		break;
+	case IRCOMM_TTY_CONNECT_INDICATION:
+		del_timer(&self->watchdog_timer);
+
+		/* Accept connection */
+		ircomm_connect_response(self->ircomm, NULL);
+		ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+		break;
+	case IRCOMM_TTY_WD_TIMER_EXPIRED:
+		/* Just stay idle */
+		break;
+	case IRCOMM_TTY_DETACH_CABLE:
+		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
+		break;
+	default:
+		IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
+			   ircomm_tty_event[event]);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_tty_state_search (self, event, skb, info)
+ *
+ *    Trying to discover an IrCOMM device
+ *
+ */
+static int ircomm_tty_state_search(struct ircomm_tty_cb *self, 
+				   IRCOMM_TTY_EVENT event, 
+				   struct sk_buff *skb, 
+				   struct ircomm_tty_info *info)
+{
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
+		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
+
+	switch (event) {
+	case IRCOMM_TTY_DISCOVERY_INDICATION:
+		self->daddr = info->daddr;
+		self->saddr = info->saddr;
+
+		if (self->iriap) {
+			WARNING(__FUNCTION__ 
+				"(), busy with a previous query\n");
+			return -EBUSY;
+		}
+		
+		self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+					 ircomm_tty_getvalue_confirm);
+		
+		if (self->service_type == IRCOMM_3_WIRE_RAW) {
+			iriap_getvaluebyclass_request(self->iriap, self->saddr,
+						      self->daddr, "IrLPT", 
+						      "IrDA:IrLMP:LsapSel");
+			ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
+		} else {
+			iriap_getvaluebyclass_request(self->iriap, self->saddr,
+						      self->daddr, 
+						      "IrDA:IrCOMM", 
+						      "Parameters");
+
+			ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
+		}
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+		break;
+	case IRCOMM_TTY_CONNECT_INDICATION:
+		del_timer(&self->watchdog_timer);
+
+		/* Accept connection */
+		ircomm_connect_response(self->ircomm, NULL);
+		ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+		break;
+	case IRCOMM_TTY_WD_TIMER_EXPIRED:
+#if 1
+		/* Give up */
+#else
+		/* Try to discover any remote devices */		
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+		irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
+#endif
+		break;
+	case IRCOMM_TTY_DETACH_CABLE:
+		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
+		break;
+	default:
+		IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
+			   ircomm_tty_event[event]);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_tty_state_query (self, event, skb, info)
+ *
+ *    Querying the remote LM-IAS for IrCOMM parameters
+ *
+ */
+static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, 
+					     IRCOMM_TTY_EVENT event, 
+					     struct sk_buff *skb, 
+					     struct ircomm_tty_info *info)
+{
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
+		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
+
+	switch (event) {
+	case IRCOMM_TTY_GOT_PARAMETERS:
+		if (self->iriap) {
+			WARNING(__FUNCTION__ 
+				"(), busy with a previous query\n");
+			return -EBUSY;
+		}
+		
+		self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+					 ircomm_tty_getvalue_confirm);
+
+		iriap_getvaluebyclass_request(self->iriap, self->saddr, 
+					      self->daddr, "IrDA:IrCOMM", 
+					      "IrDA:TinyTP:LsapSel");
+
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+		ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
+		break;
+	case IRCOMM_TTY_WD_TIMER_EXPIRED:
+		/* Go back to search mode */
+		ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
+		ircomm_tty_start_watchdog_timer(self, 3*HZ); 
+		break;
+	case IRCOMM_TTY_CONNECT_INDICATION:
+		del_timer(&self->watchdog_timer);
+
+		/* Accept connection */
+		ircomm_connect_response(self->ircomm, NULL);
+		ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+		break;
+	case IRCOMM_TTY_DETACH_CABLE:
+		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
+		break;
+	default:
+		IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
+			   ircomm_tty_event[event]);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info)
+ *
+ *    Query remote LM-IAS for the LSAP selector which we can connect to
+ *
+ */
+static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, 
+					   IRCOMM_TTY_EVENT event, 
+					   struct sk_buff *skb, 
+					   struct ircomm_tty_info *info)
+{
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
+		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
+
+	switch (event) {
+	case IRCOMM_TTY_GOT_LSAPSEL:
+		/* Connect to remote device */
+		ret = ircomm_connect_request(self->ircomm, self->dlsap_sel,
+					     self->saddr, self->daddr, 
+					     NULL, self->service_type);
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+		ircomm_tty_next_state(self, IRCOMM_TTY_SETUP);
+		break;
+	case IRCOMM_TTY_WD_TIMER_EXPIRED:
+		/* Go back to search mode */
+		ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+		break;
+	case IRCOMM_TTY_CONNECT_INDICATION:
+		del_timer(&self->watchdog_timer);
+
+		/* Accept connection */
+		ircomm_connect_response(self->ircomm, NULL);
+		ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+		break;
+	case IRCOMM_TTY_DETACH_CABLE:
+		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
+		break;
+	default:
+		IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
+			   ircomm_tty_event[event]);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_tty_state_setup (self, event, skb, info)
+ *
+ *    Trying to connect
+ *
+ */
+static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, 
+				  IRCOMM_TTY_EVENT event, 
+				  struct sk_buff *skb, 
+				  struct ircomm_tty_info *info)
+{
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
+		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
+
+	switch (event) {
+	case IRCOMM_TTY_CONNECT_CONFIRM:
+		del_timer(&self->watchdog_timer);
+		ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+		
+		/* 
+		 * Send initial parameters. This will also send out queued
+		 * parameters waiting for the connection to come up 
+		 */
+		ircomm_tty_send_initial_parameters(self);
+		ircomm_tty_link_established(self);
+		break;
+	case IRCOMM_TTY_CONNECT_INDICATION:
+		del_timer(&self->watchdog_timer);
+		
+		/* Accept connection */
+		ircomm_connect_response(self->ircomm, NULL);
+		ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+		break;
+	case IRCOMM_TTY_WD_TIMER_EXPIRED:
+		/* Go back to search mode */
+		ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+		break;
+	case IRCOMM_TTY_DETACH_CABLE:
+		/* ircomm_disconnect_request(self->ircomm, NULL); */
+		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
+		break;
+	default:
+		IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
+			   ircomm_tty_event[event]);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_tty_state_ready (self, event, skb, info)
+ *
+ *    IrCOMM is now connected
+ *
+ */
+static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, 
+				  IRCOMM_TTY_EVENT event, 
+				  struct sk_buff *skb, 
+				  struct ircomm_tty_info *info)
+{
+	int ret = 0;
+
+	switch (event) {
+	case IRCOMM_TTY_DATA_REQUEST:
+		ret = ircomm_data_request(self->ircomm, skb);
+		break;		
+	case IRCOMM_TTY_DETACH_CABLE:
+		ircomm_disconnect_request(self->ircomm, NULL);
+		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
+		break;
+	case IRCOMM_TTY_DISCONNECT_INDICATION:
+		ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
+		ircomm_tty_start_watchdog_timer(self, 3*HZ);
+
+		if (self->flags & ASYNC_CHECK_CD) {
+			/* Drop carrier */
+			self->settings.dce = IRCOMM_DELTA_CD;
+			ircomm_tty_check_modem_status(self);
+		} else {
+			IRDA_DEBUG(0, __FUNCTION__ "(), hanging up!\n");
+			if (self->tty)
+				tty_hangup(self->tty);
+		}
+		break;
+	default:
+		IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
+			   ircomm_tty_event[event]);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Function ircomm_tty_do_event (self, event, skb)
+ *
+ *    Process event
+ *
+ */
+int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
+			struct sk_buff *skb, struct ircomm_tty_info *info) 
+{
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
+		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
+	
+	return (*state[self->state])(self, event, skb, info);
+}
+
+/*
+ * Function ircomm_tty_next_state (self, state)
+ *
+ *    Switch state
+ *
+ */
+void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
+{
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	self->state = state;
+	
+	IRDA_DEBUG(2, __FUNCTION__": next state=%s, service type=%d\n", 
+		   ircomm_tty_state[self->state], self->service_type);
+}
+
diff -urN linux-2.2.15-pre2/net/irda/ircomm/ircomm_tty_ioctl.c linux/net/irda/ircomm/ircomm_tty_ioctl.c
--- linux-2.2.15-pre2/net/irda/ircomm/ircomm_tty_ioctl.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/ircomm_tty_ioctl.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,465 @@
+/*********************************************************************
+ *                
+ * Filename:      ircomm_tty_ioctl.c
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Thu Jun 10 14:39:09 1999
+ * Modified at:   Wed Jan  5 14:46:17 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1999-2000 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/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+
+#include <net/irda/ircomm_core.h>
+#include <net/irda/ircomm_param.h>
+#include <net/irda/ircomm_tty_attach.h>
+#include <net/irda/ircomm_tty.h>
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+/*
+ * Function ircomm_tty_change_speed (driver)
+ *
+ *    Change speed of the driver. If the remote device is a DCE, then this
+ *    should make it change the speed of its serial port
+ */
+void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
+{
+	unsigned cflag, cval;
+	int baud;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if (!self->tty || !self->tty->termios || !self->ircomm)
+		return;
+
+	cflag = self->tty->termios->c_cflag;
+
+	/*  byte size and parity */
+	switch (cflag & CSIZE) {
+	case CS5: cval = IRCOMM_WSIZE_5; break;
+	case CS6: cval = IRCOMM_WSIZE_6; break;
+	case CS7: cval = IRCOMM_WSIZE_7; break;
+	case CS8: cval = IRCOMM_WSIZE_8; break;
+	default:  cval = IRCOMM_WSIZE_5; break;
+	}
+	if (cflag & CSTOPB)
+		cval |= IRCOMM_2_STOP_BIT;
+	
+	if (cflag & PARENB)
+		cval |= IRCOMM_PARITY_ENABLE;
+	if (!(cflag & PARODD))
+		cval |= IRCOMM_PARITY_EVEN;
+
+	/* Determine divisor based on baud rate */
+	baud = tty_get_baud_rate(self->tty);
+	if (!baud)
+		baud = 9600;	/* B0 transition handled in rs_set_termios */
+
+	self->settings.data_rate = baud;
+	ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
+	
+	/* CTS flow control flag and modem status interrupts */
+	if (cflag & CRTSCTS) {
+		self->flags |= ASYNC_CTS_FLOW;
+		self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
+	} else {
+		self->flags &= ~ASYNC_CTS_FLOW;
+		self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
+	}
+	if (cflag & CLOCAL)
+		self->flags &= ~ASYNC_CHECK_CD;
+	else
+		self->flags |= ASYNC_CHECK_CD;
+#if 0	
+	/*
+	 * Set up parity check flag
+	 */
+
+	if (I_INPCK(self->tty))
+		driver->read_status_mask |= LSR_FE | LSR_PE;
+	if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty))
+		driver->read_status_mask |= LSR_BI;
+	
+	/*
+	 * Characters to ignore
+	 */
+	driver->ignore_status_mask = 0;
+	if (I_IGNPAR(driver->tty))
+		driver->ignore_status_mask |= LSR_PE | LSR_FE;
+
+	if (I_IGNBRK(self->tty)) {
+		self->ignore_status_mask |= LSR_BI;
+		/*
+		 * If we're ignore parity and break indicators, ignore 
+		 * overruns too. (For real raw support).
+		 */
+		if (I_IGNPAR(self->tty)) 
+			self->ignore_status_mask |= LSR_OE;
+	}
+#endif
+	self->settings.data_format = cval;
+
+	ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
+ 	ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
+}
+
+/*
+ * Function ircomm_tty_set_termios (tty, old_termios)
+ *
+ *    This routine allows the tty driver to be notified when device's
+ *    termios settings have changed.  Note that a well-designed tty driver
+ *    should be prepared to accept the case where old == NULL, and try to
+ *    do something rational.
+ */
+void ircomm_tty_set_termios(struct tty_struct *tty, 
+			    struct termios *old_termios)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	unsigned int cflag = tty->termios->c_cflag;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if ((cflag == old_termios->c_cflag) && 
+	    (RELEVANT_IFLAG(tty->termios->c_iflag) == 
+	     RELEVANT_IFLAG(old_termios->c_iflag)))
+	{
+		return;
+	}
+
+	ircomm_tty_change_speed(self);
+
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+	    !(cflag & CBAUD)) {
+		self->settings.dte &= ~(IRCOMM_DTR|IRCOMM_RTS);
+		ircomm_param_request(self, IRCOMM_DTE, TRUE);
+	}
+	
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    (cflag & CBAUD)) {
+		self->settings.dte |= IRCOMM_DTR;
+		if (!(tty->termios->c_cflag & CRTSCTS) || 
+		    !test_bit(TTY_THROTTLED, &tty->flags)) {
+			self->settings.dte |= IRCOMM_RTS;
+		}
+		ircomm_param_request(self, IRCOMM_DTE, TRUE);
+	}
+	
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) 
+	{
+		tty->hw_stopped = 0;
+		ircomm_tty_start(tty);
+	}
+}
+
+/*
+ * Function ircomm_tty_get_modem_info (self, value)
+ *
+ *    
+ *
+ */
+static int ircomm_tty_get_modem_info(struct ircomm_tty_cb *self, 
+				     unsigned int *value)
+{
+	unsigned int result;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	result =  ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0)
+		| ((self->settings.dte & IRCOMM_DTR) ? TIOCM_DTR : 0)
+		| ((self->settings.dce & IRCOMM_CD)  ? TIOCM_CAR : 0)
+		| ((self->settings.dce & IRCOMM_RI)  ? TIOCM_RNG : 0)
+		| ((self->settings.dce & IRCOMM_DSR) ? TIOCM_DSR : 0)
+		| ((self->settings.dce & IRCOMM_CTS) ? TIOCM_CTS : 0);
+
+	return put_user(result, value);
+}
+
+/*
+ * Function set_modem_info (driver, cmd, value)
+ *
+ *    
+ *
+ */
+static int ircomm_tty_set_modem_info(struct ircomm_tty_cb *self, 
+				     unsigned int cmd, unsigned int *value)
+{ 
+	unsigned int arg;
+	__u8 old_rts, old_dtr;
+	int error;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	error = get_user(arg, value);
+	if (error)
+		return error;
+
+	old_rts = self->settings.dte & IRCOMM_RTS;
+	old_dtr = self->settings.dte & IRCOMM_DTR;
+
+	switch (cmd) {
+	case TIOCMBIS: 
+		if (arg & TIOCM_RTS) 
+			self->settings.dte |= IRCOMM_RTS;
+		if (arg & TIOCM_DTR)
+			self->settings.dte |= IRCOMM_DTR;
+		break;
+		
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			self->settings.dte &= ~IRCOMM_RTS;
+		if (arg & TIOCM_DTR)
+ 			self->settings.dte &= ~IRCOMM_DTR;
+ 		break;
+		
+	case TIOCMSET:
+ 		self->settings.dte = 
+			((self->settings.dte & ~(IRCOMM_RTS | IRCOMM_DTR))
+			 | ((arg & TIOCM_RTS) ? IRCOMM_RTS : 0)
+			 | ((arg & TIOCM_DTR) ? IRCOMM_DTR : 0));
+		break;
+		
+	default:
+		return -EINVAL;
+	}
+	
+	if ((self->settings.dte & IRCOMM_RTS) != old_rts)
+		self->settings.dte |= IRCOMM_DELTA_RTS;
+
+	if ((self->settings.dte & IRCOMM_DTR) != old_dtr)
+		self->settings.dte |= IRCOMM_DELTA_DTR;
+
+	ircomm_param_request(self, IRCOMM_DTE, TRUE);
+	
+	return 0;
+}
+
+/*
+ * Function get_serial_info (driver, retinfo)
+ *
+ *    
+ *
+ */
+static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
+				      struct serial_struct *retinfo)
+{
+	struct serial_struct info;
+   
+	if (!retinfo)
+		return -EFAULT;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	memset(&info, 0, sizeof(info));
+	info.line = self->line;
+	info.flags = self->flags;
+	info.baud_base = self->settings.data_rate;
+	info.close_delay = self->close_delay;
+	info.closing_wait = self->closing_wait;
+
+	/* For compatibility  */
+ 	info.type = PORT_16550A;
+ 	info.port = 0;
+ 	info.irq = 0;
+	info.xmit_fifo_size = 0;
+	info.hub6 = 0;   
+	info.custom_divisor = 0;
+
+	if (copy_to_user(retinfo, &info, sizeof(*retinfo)))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * Function set_serial_info (driver, new_info)
+ *
+ *    
+ *
+ */
+static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
+				      struct serial_struct *new_info)
+{
+#if 0
+	struct serial_struct new_serial;
+	struct ircomm_tty_cb old_state, *state;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+		return -EFAULT;
+
+
+	state = self
+	old_state = *self;
+  
+	if (!capable(CAP_SYS_ADMIN)) {
+		if ((new_serial.baud_base != state->settings.data_rate) ||
+		    (new_serial.close_delay != state->close_delay) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (self->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+				 (new_serial.flags & ASYNC_USR_MASK));
+		self->flags = ((self->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		/* self->custom_divisor = new_serial.custom_divisor; */
+		goto check_and_exit;
+	}
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	if (self->settings.data_rate != new_serial.baud_base) {
+		self->settings.data_rate = new_serial.baud_base;
+		ircomm_param_request(self, IRCOMM_DATA_RATE, TRUE);
+	}
+
+	self->close_delay = new_serial.close_delay * HZ/100;
+	self->closing_wait = new_serial.closing_wait * HZ/100;
+	/* self->custom_divisor = new_serial.custom_divisor; */
+
+	self->flags = ((self->flags & ~ASYNC_FLAGS) |
+		       (new_serial.flags & ASYNC_FLAGS));
+	self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ check_and_exit:
+
+	if (self->flags & ASYNC_INITIALIZED) {
+		if (((old_state.flags & ASYNC_SPD_MASK) !=
+		     (self->flags & ASYNC_SPD_MASK)) ||
+		    (old_driver.custom_divisor != driver->custom_divisor)) {
+			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+				driver->tty->alt_speed = 57600;
+			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+				driver->tty->alt_speed = 115200;
+			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+				driver->tty->alt_speed = 230400;
+			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+				driver->tty->alt_speed = 460800;
+			ircomm_tty_change_speed(driver);
+		}
+	}
+#endif
+	return 0;
+}
+
+/*
+ * Function ircomm_tty_ioctl (tty, file, cmd, arg)
+ *
+ *    
+ *
+ */
+int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file, 
+		     unsigned int cmd, unsigned long arg)
+{
+	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+
+	switch (cmd) {
+	case TIOCMGET:
+		ret = ircomm_tty_get_modem_info(self, (unsigned int *) arg);
+		break;
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		ret = ircomm_tty_set_modem_info(self, cmd, (unsigned int *) arg);
+		break;
+	case TIOCGSERIAL:
+		ret = ircomm_tty_get_serial_info(self, (struct serial_struct *) arg);
+		break;
+	case TIOCSSERIAL:
+		ret = ircomm_tty_set_serial_info(self, (struct serial_struct *) arg);
+		break;
+	case TIOCMIWAIT:
+		IRDA_DEBUG(0, "(), TIOCMIWAIT, not impl!\n");
+		break;
+
+	case TIOCGICOUNT:
+		IRDA_DEBUG(0, __FUNCTION__ "(), TIOCGICOUNT not impl!\n");
+#if 0
+		save_flags(flags); cli();
+		cnow = driver->icount;
+		restore_flags(flags);
+		p_cuser = (struct serial_icounter_struct *) arg;
+		error = put_user(cnow.cts, &p_cuser->cts);
+		if (error) return error;
+		error = put_user(cnow.dsr, &p_cuser->dsr);
+		if (error) return error;
+		error = put_user(cnow.rng, &p_cuser->rng);
+		if (error) return error;
+		error = put_user(cnow.dcd, &p_cuser->dcd);
+		if (error) return error;
+		error = put_user(cnow.rx, &p_cuser->rx);
+		if (error) return error;
+		error = put_user(cnow.tx, &p_cuser->tx);
+		if (error) return error;
+		error = put_user(cnow.frame, &p_cuser->frame);
+		if (error) return error;
+		error = put_user(cnow.overrun, &p_cuser->overrun);
+		if (error) return error;
+		error = put_user(cnow.parity, &p_cuser->parity);
+		if (error) return error;
+		error = put_user(cnow.brk, &p_cuser->brk);
+		if (error) return error;
+		error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
+		if (error) return error;			
+#endif		
+		return 0;
+	default:
+		ret = -ENOIOCTLCMD;  /* ioctls which we must ignore */
+	}
+	return ret;
+}
+
+
+
diff -urN linux-2.2.15-pre2/net/irda/ircomm/irvtd_driver.c linux/net/irda/ircomm/irvtd_driver.c
--- linux-2.2.15-pre2/net/irda/ircomm/irvtd_driver.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/ircomm/irvtd_driver.c	Wed Dec 31 16:00:00 1969
@@ -1,2067 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irvtd_driver.c
- * Version:       
- * Description:   Virtual tty driver (the "port emulation entity" of IrCOMM)
- * Status:        Experimental.
- * Author:        Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
- * Source:        serial.c by Linus Torvalds
- *                isdn_tty.c by Fritz Elfert
- *
- *     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
- *     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, Takahide Higuchi, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/termios.h>
-#include <linux/tty.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irias_object.h>
-
-#include <net/irda/irvtd.h>
-
-#ifndef MIN
-#define MIN(a,b)        ((a) < (b) ? (a) : (b))
-#endif
-
-#define DO_RESTART
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-struct tty_driver irvtd_drv;
-struct tty_struct *irvtd_table[COMM_MAX_TTY];
-struct termios *irvtd_termios[COMM_MAX_TTY];
-struct termios *irvtd_termios_locked[COMM_MAX_TTY];
-static int irvtd_refcount;
-struct irvtd_cb **irvtd = NULL;
-
-static char *revision_date = "Wed May 26 00:49:11 1999";
-
-
-/*
- * prototypes
- */
-
-int irvtd_open(struct tty_struct *tty, struct file *filp);
-void irvtd_close(struct tty_struct * tty, struct file * filp);
-int irvtd_write(struct tty_struct * tty, int from_user,
-			const unsigned char *buf, int count);
-void irvtd_put_char(struct tty_struct *tty, unsigned char ch);
-int irvtd_write_room(struct tty_struct *tty);
-int irvtd_chars_in_buffer(struct tty_struct *tty);
-int irvtd_ioctl(struct tty_struct *tty, struct file * file,
-	     unsigned int cmd, unsigned long arg);
-void irvtd_set_termios(struct tty_struct *tty, struct termios * old);
-void irvtd_throttle(struct tty_struct *tty);
-void irvtd_unthrottle(struct tty_struct *tty);
-void irvtd_stop(struct tty_struct *tty);
-void irvtd_start(struct tty_struct *tty);
-void irvtd_hangup(struct tty_struct *tty);
-void irvtd_flush_buffer(struct tty_struct *tty);
-void irvtd_flush_chars(struct tty_struct *tty);
-
-static void change_speed(struct irvtd_cb *driver);
-static void irvtd_write_to_tty( struct irvtd_cb *);
-static void irvtd_send_data_request( struct irvtd_cb *);
-static void irvtd_break(struct tty_struct *tty, int break_state);
-static void irvtd_send_xchar(struct tty_struct *tty, char ch);
-static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static void irvtd_start_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,
-			   int *eof, void *unused);
-
-
-/*
- **********************************************************************
- *
- * ircomm_receive_data() and friends
- *
- * like interrupt handler in the serial.c,we receive data when 
- * ircomm_data_indication comes
- *
- **********************************************************************
- */
-
-
-
-/* 
- * irvtd_write_to_tty
- * send incoming/queued data to tty
- */
-
-static void irvtd_write_to_tty( struct irvtd_cb *driver)
-{	
-	int status, c, flag;
-	struct sk_buff *skb;
-	struct tty_struct *tty = driver->tty;
-	
-	if(driver->rx_disable)
-		return;
-
- 	skb = skb_dequeue(&driver->rxbuff);
-	if(skb == NULL)
-		return; /* there's nothing */
-
-	/* 
-	 * we should parse controlchannel field here. 
-	 * (see process_data() in ircomm.c)
-	 */
-	ircomm_parse_tuples(driver->comm, skb, CONTROL_CHANNEL);
-	
-#ifdef IRVTD_DEBUG_RX
-	printk("received data:");
-	{
-		int i;
-		for ( i=0;i<skb->len;i++)
-			printk("%02x ", skb->data[i]);
-		printk("\n");
-	}
-#endif
-	
-	status = driver->comm->peer_line_status & driver->read_status_mask;
-	
-	/* 
-	 * if there are too many errors which make a character ignored,
-	 * drop characters
-	 */
-
-	if(status & driver->ignore_status_mask){
-		DEBUG(0,__FUNCTION__":some error:ignore characters.\n");
-		dev_kfree_skb(skb);
-		return;
-	}
-	
-	c = MIN(skb->len, (TTY_FLIPBUF_SIZE - tty->flip.count));
-	DEBUG(4, __FUNCTION__"skb_len=%d, tty->flip.count=%d \n"
-	      ,(int)skb->len, tty->flip.count);
-	
-	if (driver->comm->peer_break_signal ) {
-		driver->comm->peer_break_signal = 0;
-		DEBUG(0,"handling break....\n");
-		
-		flag = TTY_BREAK;
-		if (driver->flags & ASYNC_SAK)
-			/*
-			 * do_SAK() seems to be an implementation of the 
-			 * idea called "Secure Attention Key",
-			 * which seems to be discribed in "Orange book".
-			 * (which is published by U.S.military!!?? ,
-			 * see source of do_SAK())
-			 *
-			 * but what kind of security do we need 
-			 * when we use infrared communication??? :p)
-			 */
-			do_SAK(tty);
-	}else if (status & LSR_PE)
-		flag = TTY_PARITY;
-	else if (status & LSR_FE)
-		flag = TTY_FRAME;
-	else if (status & LSR_OE)
-		flag = TTY_OVERRUN;
-	else 
-		flag = TTY_NORMAL;
-	
-	if(c){
-		DEBUG(4,"writing %d chars to tty\n",c);
-		driver->icount.rx += c;
-		memset(tty->flip.flag_buf_ptr, flag, c);
-		memcpy(tty->flip.char_buf_ptr, skb->data, c);
-		tty->flip.flag_buf_ptr += c;
-		tty->flip.char_buf_ptr += c;
-		tty->flip.count += c;
-		skb_pull(skb,c);
-	}
-
-	if(skb->len == 0)
-		dev_kfree_skb(skb);
-	else
-	{
-		/* queue rest of data again */
-		DEBUG(4,__FUNCTION__":retrying frame!\n");
-
-		/* build a dummy control channel */
-		skb_push(skb,1);
-		*skb->data = 0;  /* clen is 0 */
-		skb_queue_head( &driver->rxbuff, skb );
-	}
-	
-	if(c)
-	/* let the process read its buffer! */
-		tty_flip_buffer_push(tty);
-	
-	if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW &&
-	   driver->ttp_stoprx){
-		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){
-		/* disconnect */
-		driver->disconnect_pend = 0;
-		driver->rx_disable = 1;
-		tty_hangup(driver->tty);
-	}
-}
-
-static int irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb)
-{	
-	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
-
-	ASSERT(driver != NULL, return -1;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return -1;);
-	DEBUG(4, __FUNCTION__"(): queue frame\n");
-
-	/* queue incoming data and make bottom half handler ready */
-
-	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;
-}
-
-/*
- ***********************************************************************
- *
- * irvtd_send_data() and friends
- *
- * like interrupt handler in the serial.c,we send data when 
- * a timer is expired
- *
- ***********************************************************************
- */
-
-
-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->rx_timer);
-	
-	driver->rx_timer.data     = (unsigned long) driver;
-	driver->rx_timer.function = &irvtd_rx_timer_expired;
-	driver->rx_timer.expires  = jiffies + timeout;
-	
-	add_timer( &driver->rx_timer);
-}
-
-
-static void irvtd_tx_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");
-
-	irvtd_send_data_request(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");
-
-	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);
-}
-
-
-static void irvtd_send_data_request(struct irvtd_cb *driver)
-{
-	int err;
-	struct sk_buff *skb = driver->txbuff;
-
-	ASSERT(skb != NULL,return;);
-	DEBUG(4, __FUNCTION__"()\n");
-
-	if(driver->tty->hw_stopped || driver->tx_disable)
-		return;
-	if(!skb->len)
-		return;   /* no data to send */
-
-#ifdef IRVTD_DEBUG_TX
-	DEBUG(4, "flush_txbuff:count(%d)\n",(int)skb->len);
-	{
-		int i;
-		for ( i=0;i<skb->len;i++)
-			printk("%02x", skb->data[i]);
-		printk("\n");
-	}
-#endif
-
-	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(1,"%d chars are lost\n",(int)skb->len);
-		skb_trim(skb, 0);
-	}
-
-	/* allocate a new frame */
-	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, driver->max_header_size);
-	}
-
-	wake_up_interruptible(&driver->tty->write_wait);
-}
-
-
-/*
- ***********************************************************************
- *
- * indication/confirmation handlers:
- *
- * these routines are handlers for IrCOMM protocol stack
- *
- ***********************************************************************
- */
-
-/*
- * Function irvtd_connect_confirm (instance, sap, qos, max_sdu_size, skb)
- *
- *    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, __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
-	 */
-	
-	driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS);
-
-	/*
-	 * sending initial control parameters here
-	 */
-	if (driver->comm->servicetype ==	THREE_WIRE_RAW)
-		return;                /* do nothing */
-
-	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
-
-	ircomm_control_request(driver->comm, SERVICETYPE);
-	ircomm_control_request(driver->comm, DATA_RATE);
-	ircomm_control_request(driver->comm, DATA_FORMAT);
-	ircomm_control_request(driver->comm, FLOW_CONTROL);
-	ircomm_control_request(driver->comm, XON_XOFF_CHAR);
-	/* ircomm_control_request(driver->comm, ENQ_ACK_CHAR); */
-
-	switch (driver->comm->servicetype) {
-	case CENTRONICS:
-		break;
-
-	case NINE_WIRE:
-		ircomm_control_request(driver->comm, DTELINE_STATE);
-		break;
-	default:
-	}
-	
-	driver->tx_disable = 0;
-	wake_up_interruptible(&driver->open_wait);
-}
-
-/*
- * Function irvtd_connect_indication (instance, sap, qos, max_sdu_size, skb)
- *
- *    we are discovered and being requested to connect by remote device !
- *
- */
-void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
-			      __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;);
-
-	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 );
-
-	driver->tx_disable = 0;
-
-	/*
-	 * send initial control parameters
-	 */
-	if (driver->comm->servicetype == THREE_WIRE_RAW)
-		return;                /* do nothing */
-
-	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
-
-	switch(driver->comm->servicetype){
-	case NINE_WIRE:
-		ircomm_control_request(driver->comm, DTELINE_STATE);
-		break;
-	default:
-		DEBUG(0, __FUNCTION__ "(), not implemented!\n");
-	}
-
-
-	driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS);
-	wake_up_interruptible(&driver->open_wait);
-}
-
-/*
- * Function irvtd_disconnect_indication (instance, sap, reason, skb)
- *
- *    This is a handler for ircomm_disconnect_indication. since this
- *    function is called in the context of interrupt handler,
- *    interruptible_sleep_on() MUST not be used.
- */
-void irvtd_disconnect_indication(void *instance, void *sap , LM_REASON reason,
-				 struct sk_buff *skb)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->tty != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-
-	DEBUG(4,"irvtd_disconnect_indication:\n");
-
-	driver->tx_disable = 1;
-	if(skb_queue_empty(&driver->rxbuff)){
-		/* disconnect */
-		driver->rx_disable = 1;
-		tty_hangup(driver->tty);
-	} else {
-		driver->disconnect_pend = 1;
-	}
-}
-
-/*
- * Function irvtd_control_indication (instance, sap, cmd)
- *
- *    
- *
- */
-void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-
-	DEBUG(4,__FUNCTION__"()\n");
-
-	if(cmd == TX_READY){
-		driver->ttp_stoptx = 0;
-		driver->tty->hw_stopped = driver->cts_stoptx;
-
-		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.
-		 * now that we can send packets to IrTTP layer,
-		 * we kick it here.
-		 */
-		if ((driver->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
-		    driver->tty->ldisc.write_wakeup)
-			(driver->tty->ldisc.write_wakeup)(driver->tty);
-		return;
-	}
-
-	if(cmd == TX_BUSY){
-		driver->ttp_stoptx = driver->tty->hw_stopped = 1;
-		del_timer( &driver->tx_timer);
-		return;
-	}
-
-
-	ASSERT(cmd == CONTROL_CHANNEL,return;);
-
-	switch(driver->comm->pi){
-
-	case DCELINE_STATE:
-	driver->msr = driver->comm->peer_dce;
-
-	if(driver->msr & (DELTA_CTS|DELTA_DSR|DELTA_RI|DELTA_DCD)){
-		if(driver->msr & DELTA_CTS)
-			driver->icount.cts++;
-		if(driver->msr & DELTA_DSR)
-			driver->icount.dsr++;
-		if(driver->msr & DELTA_RI)
-			driver->icount.rng++;
-		if(driver->msr & DELTA_DCD)
-			driver->icount.dcd++;
-		wake_up_interruptible(&driver->delta_msr_wait);
-	}
-
-	if ((driver->flags & ASYNC_CHECK_CD) && (driver->msr & DELTA_DCD)) {
-
-		DEBUG(0,"CD now %s...\n",
-		      (driver->msr & MSR_DCD) ? "on" : "off");
-
-		if (driver->msr & MSR_DCD)
-		{
-			/* DCD raised! */
-			wake_up_interruptible(&driver->open_wait);
-		}
-		else
-		{
-			/* DCD falled */
-                        DEBUG(0,__FUNCTION__"():hangup..\n");
-			tty_hangup(driver->tty);
-		}
-
-	}
-
-	if (driver->comm->flow_ctrl & USE_CTS) {
-		if (driver->tty->hw_stopped) {
-			if (driver->msr & MSR_CTS) {
-				DEBUG(0,"CTS tx start...\n");
-
-				driver->cts_stoptx = 0;
-				driver->tty->hw_stopped = driver->ttp_stoptx;
-				/*  
-				 * replacement of 
-				 * rs_sched_event(info, RS_EVENT_WRITE_WAKEUP)
-				 * in serial.c
-				 */
-
-				if ((driver->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-				    driver->tty->ldisc.write_wakeup)
-					(driver->tty->ldisc.write_wakeup)(driver->tty);
-
-				wake_up_interruptible(&driver->tty->write_wait);
-				return;
-			}
-		} else {
-			if (!(driver->msr & MSR_CTS)) {
-				DEBUG(0,"CTS tx stop...");
-
-				driver->cts_stoptx = 1;
-				driver->tty->hw_stopped = 1;
-                        }
-                }
-        }
-	break;
-
-	case FLOW_CONTROL:
-	case DATA_RATE:
-	case XON_XOFF_CHAR:
-	case DTELINE_STATE:
-	case ENQ_ACK_CHAR:	/* got this from win95 */
-		/* (maybe) nothing to do  */
-		break;
-	default:
-		DEBUG(0,__FUNCTION__"():PI = 0x%02x is not implemented\n",
-		      (int)driver->comm->pi);
-	}
-}
-
-/*
- ***********************************************************************
- *
- * driver kernel interfaces
- * these functions work as an interface between the kernel and this driver
- *
- ***********************************************************************
- */
-
-
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_open() and friends
- *
- * ----------------------------------------------------------------------
- */
-
-
-static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp,
-				 struct irvtd_cb *driver)
-{
-
- 	struct wait_queue wait = { current, NULL };
-	int		retval = 0;
-	int		do_clocal = 0;
-
-	/*
-	 * 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))) {
-
-		return 0;
-	}
-
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-
-
-	/*
-	 * We wait until ircomm_connect_request() succeed or
-	 *   ircomm_connect_indication comes
-	 */
-
-
-	add_wait_queue(&driver->open_wait, &wait);
-
-	DEBUG(0,__FUNCTION__"():before block( line = %d, count = %d )\n",
-	      driver->line, driver->count);
-
-	driver->blocked_open++;
-
-	/* wait for a connection established */
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		
-		if (tty_hung_up_p(filp) ||
-		    !(driver->flags & ASYNC_INITIALIZED)) {
-#ifdef DO_RESTART
-			if (driver->flags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-
-		if (!(driver->flags & ASYNC_CLOSING) &&
-		    (driver->comm->state == COMM_CONN) && 
-		    ( do_clocal || (driver->msr & MSR_DCD)))
-			break;
-
-		if(signal_pending(current)){
-			retval = -ERESTARTSYS;
-			break;
-		}
-
-
-		DEBUG(4,__FUNCTION__"():blocking( %s%d, count = %d )\n",
-		      tty->driver.name, driver->line, driver->count);
-
-		schedule();
-	}
-
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&driver->open_wait, &wait);
-
-	driver->blocked_open--;
-
-	DEBUG(1, __FUNCTION__"():after blocking\n");
-
-	if (retval)
-		return retval;
-	return 0;
-}	
-
-static void change_speed(struct irvtd_cb *driver)
-{
-	unsigned cflag,cval;
-
-	if (!driver->tty || !driver->tty->termios || !driver->comm)
-		return;
-	cflag = driver->tty->termios->c_cflag;
-
-	/* 
-	 * byte size and parity
-	 */
-	switch (cflag & CSIZE) 
-	{
-	case CS5: cval = IRCOMM_WLEN5; break;
-	case CS6: cval = IRCOMM_WLEN6; break;
-	case CS7: cval = IRCOMM_WLEN7; break;
-	case CS8: cval = IRCOMM_WLEN8; break;
-	default:  cval = IRCOMM_WLEN5; break;	/* too keep GCC shut... */
-	}
-	if (cflag & CSTOPB) {      /* use 2 stop bit mode */
-		cval |= IRCOMM_STOP2;
-	}
-	if (cflag & PARENB)
-		cval |= IRCOMM_PARENB;    /* enable parity check */
-	if (!(cflag & PARODD))
-		cval |= IRCOMM_PAREVEN;         /* even parity */
-	
-	/* CTS flow control flag and modem status interrupts */
-
-	if (cflag & CRTSCTS)
-		driver->comm->flow_ctrl |= USE_CTS;
-	else
-		driver->comm->flow_ctrl |= ~USE_CTS;
-	
-	if (cflag & CLOCAL)
-		driver->flags &= ~ASYNC_CHECK_CD;
-	else
-		driver->flags |= ASYNC_CHECK_CD;
-	
-	/*
-	 * Set up parity check flag
-	 */
-
-	driver->read_status_mask = LSR_OE;
-	if (I_INPCK(driver->tty))
-		driver->read_status_mask |= LSR_FE | LSR_PE;
-	if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty))
-		driver->read_status_mask |= LSR_BI;
-	
-	/*
-	 * Characters to ignore
-	 */
-	driver->ignore_status_mask = 0;
-	if (I_IGNPAR(driver->tty))
-		driver->ignore_status_mask |= LSR_PE | LSR_FE;
-
-	if (I_IGNBRK(driver->tty)) {
-		driver->ignore_status_mask |= LSR_BI;
-		/*
-		 * If we're ignore parity and break indicators, ignore 
-		 * overruns too.  (For real raw support).
-		 */
-		if (I_IGNPAR(driver->tty)) 
-			driver->ignore_status_mask |= LSR_OE;
-	}
-
-	driver->comm->data_format = cval;
-	ircomm_control_request(driver->comm, DATA_FORMAT);
- 	ircomm_control_request(driver->comm, FLOW_CONTROL);
-}
-
-
-
-
-static int irvtd_startup(struct irvtd_cb *driver)
-{
-	struct ias_object* obj;
-	struct notify_t irvtd_notify;
-
-	/* FIXME: it should not be hard coded */
-	__u8 oct_seq[6] = { 0,1,6,1,1,1 }; 
-
-	DEBUG(4,__FUNCTION__"()\n" );
-	if(driver->flags & ASYNC_INITIALIZED)
-		return 0;
-
-	/*
-	 * initialize our tx/rx buffer
-	 */
-
-	skb_queue_head_init(&driver->rxbuff);
-	driver->txbuff = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE); 
-	if (!driver->txbuff){
-		DEBUG(0,__FUNCTION__"(), alloc_skb failed!\n");
-		return -ENOMEM;
-	}
-	skb_reserve(driver->txbuff, COMM_MAX_HEADER_SIZE);
-
-	irda_notify_init(&irvtd_notify);
-	irvtd_notify.data_indication = irvtd_receive_data;
-	irvtd_notify.connect_confirm = irvtd_connect_confirm;
-	irvtd_notify.connect_indication = irvtd_connect_indication;
-	irvtd_notify.disconnect_indication = irvtd_disconnect_indication;
-	irvtd_notify.flow_indication = irvtd_control_indication;
-	strncpy( irvtd_notify.name, "ircomm_tty", NOTIFY_MAX_NAME);
-	irvtd_notify.instance = driver;
-
-	driver->comm = ircomm_open_instance(irvtd_notify);
-	if (!driver->comm)
-		return -ENODEV;
-
-
-	/* 
-         *  Register with LM-IAS as a server
-         */
-
-	obj = irias_new_object( "IrDA:IrCOMM", IAS_IRCOMM_ID);
-	irias_add_integer_attrib( obj, "IrDA:TinyTP:LsapSel", 
-				  driver->comm->tsap->stsap_sel );
-
-	irias_add_octseq_attrib( obj, "Parameters", &oct_seq[0], 6);
-	irias_insert_object( obj);
-
-	driver->flags |= ASYNC_INITIALIZED;
-
-	if (driver->tty)
-		clear_bit(TTY_IO_ERROR, &driver->tty->flags);
-
-	change_speed(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;
-	driver->disconnect_pend = 0;
-	return 0;
-}
-
-
-int irvtd_open(struct tty_struct * tty, struct file * filp)
-{
-	struct irvtd_cb *driver;
-	int retval;
-	int line;
-
-	DEBUG(4, __FUNCTION__"():\n");
-	MOD_INC_USE_COUNT;
-
-	line = MINOR(tty->device) - tty->driver.minor_start;
-	if ((line <0) || (line >= COMM_MAX_TTY)){
-		MOD_DEC_USE_COUNT;
-		return -ENODEV;
-	}
-
-	driver = irvtd[line];
-	ASSERT(driver != NULL, MOD_DEC_USE_COUNT;return -ENOMEM;);
-	ASSERT(driver->magic == IRVTD_MAGIC, MOD_DEC_USE_COUNT;return -EINVAL;);
-
-	driver->count++;
-
-	DEBUG(0, __FUNCTION__"():%s%d count %d\n", tty->driver.name, line, 
-	      driver->count);
-	
-	tty->driver_data = driver;
-	driver->tty = tty;
-
-	driver->tty->low_latency = (driver->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * (sleep) until it's done, then exit.
-	 */
-
-	if (tty_hung_up_p(filp) ||
-	    (driver->flags & ASYNC_CLOSING)) {
-		if (driver->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&driver->close_wait);
-#ifdef DO_RESTART
-		if (driver->flags & ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/* 
-	 * start up discovering process and ircomm_layer 
-	 */
-	
-	retval = irvtd_startup(driver);
-	if (retval){
-		DEBUG(0, __FUNCTION__"():irvtd_startup returns %d\n",retval);
-		return retval;
-	}
-
-	retval = irvtd_block_til_ready(tty, filp, driver);
-	if (retval){
-		DEBUG(0,__FUNCTION__
-		      "():returning after block_til_ready (errno = %d)\n", retval);
-                return retval;
-	}
-
-	driver->session = current->session;
-	driver->pgrp = current->pgrp;
-	return 0;
-}
-
-
-
-
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_close() and friends
- *
- * most of this function is stolen from serial.c
- * ----------------------------------------------------------------------
- */
-
-/*
- * Function irvtd_wait_until_sent (tty, timeout)
- *
- *    wait until Tx queue of IrTTP is empty 
- *
- */
-static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	unsigned long orig_jiffies;
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-	ASSERT(driver->comm != NULL, return;);
-
-	DEBUG(1, __FUNCTION__"():\n");	
-	if(!tty->closing)
-		return;   /* nothing to do */
-	
-	/* 
-	 * at disconnection, we should wait until Tx queue of IrTTP is
-	 * flushed
-	 */
-
- 	ircomm_disconnect_request(driver->comm, NULL, P_NORMAL);
-	orig_jiffies = jiffies;
-
-	while (driver->comm->tsap->disconnect_pend) {
-		DEBUG(1, __FUNCTION__"():wait..\n");
-		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
-		schedule_timeout(HZ);    /* 1sec */
-		if (signal_pending(current))
-			break;
-		if (timeout && time_after(jiffies, orig_jiffies + timeout))
-			break;
-	}
-	current->state = TASK_RUNNING;
-}
-
-
-static void irvtd_shutdown(struct irvtd_cb * driver)
-{
-	unsigned long	flags;
-
-	if (!(driver->flags & ASYNC_INITIALIZED))
-		return;
-
-	DEBUG(1,__FUNCTION__"()\n");
-
-	/*
-	 * This comment is written in serial.c:
-	 *
-	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
-	 * here so the queue might never be waken up
-	 */
- 	wake_up_interruptible(&driver->delta_msr_wait);
-	
-	/* clear DTR and RTS */
-	if (!driver->tty || (driver->tty->termios->c_cflag & HUPCL))
- 		driver->mcr &= ~(MCR_DTR|MCR_RTS);
-
-	driver->comm->dte = driver->mcr;
-	ircomm_control_request(driver->comm, DTELINE_STATE );
-
-
-
-	save_flags(flags); cli(); /* Disable interrupts */
-
-	if (driver->tty)
-		set_bit(TTY_IO_ERROR, &driver->tty->flags);
-	
-	del_timer( &driver->tx_timer);
-	del_timer( &driver->rx_timer);
-
-	irias_delete_object("IrDA:IrCOMM");
-
-	/*
-	 * Free the transmit buffer here 
-	 */
-
-	while(skb_queue_len(&driver->rxbuff)){
-		struct sk_buff *skb;
-		skb = skb_dequeue( &driver->rxbuff);
-		dev_kfree_skb(skb);
-	}
-	if(driver->txbuff){
-		dev_kfree_skb(driver->txbuff);
-		driver->txbuff = NULL;
-	}
-	ircomm_close_instance(driver->comm);
-	driver->comm = NULL;
-	driver->flags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
-}
-
-void irvtd_close(struct tty_struct * tty, struct file * filp)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	int line;
-	unsigned long flags;
-
-	DEBUG(1, __FUNCTION__"():refcount= %d\n",irvtd_refcount);
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-
-	save_flags(flags);cli();
-
-
-	if(tty_hung_up_p(filp)){
-		/*
-		 * upper tty layer caught a HUP signal and called irvtd_hangup()
-		 * before. so we do nothing here.
-		 */
-		DEBUG(1, __FUNCTION__"():tty_hung_up_p.\n");
-		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
-		return;
-	}
-	
-
-	line = MINOR(tty->device) - tty->driver.minor_start;
-	DEBUG(0, __FUNCTION__"():%s%d count %d\n", tty->driver.name, line, 
-	      driver->count);
-
-	if ((tty->count == 1) && (driver->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  Driver->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * ircomm service layer won't be shutdown.
-		 */
-		printk(KERN_ERR"irvtd_close: bad serial port count;" 
-		       "tty->count is 1, but driver->count is %d\n", driver->count);
-		driver->count = 1;
-	}
-	if (--driver->count < 0) {
-		printk(KERN_ERR"irvtd_close: bad count for line%d: %d\n",
-		       line, driver->count);
-		driver->count = 0;
-	}
-
-	if (driver->count) { 	/* do nothing */
-		DEBUG(0, __FUNCTION__"():driver->count is not 0\n");
-		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
-		return; 
-	}
-
-	driver->flags |= ASYNC_CLOSING;
-	
-	/*
-	 * 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 (driver->closing_wait != ASYNC_CLOSING_WAIT_NONE){
-		DEBUG(4, __FUNCTION__"():calling tty_wait_until_sent()\n");
-		tty_wait_until_sent(tty, driver->closing_wait);
-	}
-	/* 
-	 * we can send disconnect_request with P_HIGH since
-	 * tty_wait_until_sent() and irvtd_wait_until_sent() should
-	 * have disconnected the link
-	 */
-	ircomm_disconnect_request(driver->comm, NULL, P_HIGH);
-	
-	/* 
-	 * Now we stop accepting input.
-	 */
-
-	driver->rx_disable = TRUE;
-	/* drop ldisc's buffer */
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
-
- 	if (tty->driver.flush_buffer) 
- 		tty->driver.flush_buffer(driver->tty);  
-
-	tty->closing = 0;
-	driver->tty = NULL;
-
-	if (driver->blocked_open)
-	{
-		if (driver->close_delay) {
-			/* kill time */
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(driver->close_delay);
-		}
-		wake_up_interruptible(&driver->open_wait);
-	}
-	irvtd_shutdown(driver);
-	driver->flags &= ~ASYNC_CLOSING;
-        wake_up_interruptible(&driver->close_wait); 
-
-	MOD_DEC_USE_COUNT;
-        restore_flags(flags);
-	DEBUG(4, __FUNCTION__"():done\n");
-}
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_write() and friends
- * This routine will be called when something data are passed from
- * kernel or user.
- * ----------------------------------------------------------------------
- */
-
-int irvtd_write(struct tty_struct * tty, int from_user,
-		const unsigned char *buf, int count)
-{
-	struct irvtd_cb *driver;
-	int c = 0;
-	int wrote = 0;
- 	unsigned long flags;
-	struct sk_buff *skb;
-	__u8 *frame;
-
-	ASSERT(tty != NULL, return -EFAULT;);
-	driver = (struct irvtd_cb *)tty->driver_data;
-	ASSERT(driver != NULL, return -EFAULT;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return -EFAULT;);
-
-	DEBUG(4, __FUNCTION__"()\n");
-
-	save_flags(flags);
-	while(count > 0){
-		cli();
-		skb = driver->txbuff;
-		ASSERT(skb != NULL, break;);
-		c = MIN(count, (skb_tailroom(skb)));
-		if (c <= 0)
-		{
-			if(!driver->ttp_stoptx)
-			{
-				irvtd_send_data_request(driver);
-				continue;
-			}
-			else
-				break;
-		}
-
-		/* write to the frame */
-
-		frame = skb_put(skb,c);
-		if(from_user){
-			copy_from_user(frame,buf,c);
-		} else
-			memcpy(frame, buf, c);
-
-		restore_flags(flags);
-		wrote += c;
-		count -= c;
-		buf += c;
-	}
-	restore_flags(flags);
-	irvtd_send_data_request(driver);
-	return (wrote);
-}
-
-void irvtd_flush_chars(struct tty_struct *tty)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	ASSERT( driver != NULL, return;);
-	ASSERT( driver->magic == IRVTD_MAGIC, return;);
-
-	DEBUG(4, __FUNCTION__"()\n");
-	irvtd_send_data_request(driver);
-}
-
-
-/*
- * Function irvtd_put_char (tty, ch)
- *
- *    This routine is called by the kernel to pass a single character.
- *    If we exausted our buffer,we can ignore the character!
- *
- */
-void irvtd_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	__u8 *frame ;
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	struct sk_buff *skb;
-	unsigned long flags;
-
-	ASSERT(driver != NULL, return;);
-	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) room(%d):\n",
-	      (int)ch ,(int)skb->len,
-	      skb_tailroom(skb));
-
-	/* append a character  */
-	frame = skb_put(skb,1);
-	frame[0] = ch;
-
-	restore_flags(flags);
-	irvtd_start_tx_timer(driver,20);
-	return;
-}
-
-/*
- * Function irvtd_write_room (tty)
- *
- *    This routine returns the room that our buffer has now.
- *
- */
-int irvtd_write_room(struct tty_struct *tty){
-
-	int ret;
-	struct sk_buff *skb = ((struct irvtd_cb *) tty->driver_data)->txbuff;
-
-	ASSERT(skb !=NULL, return 0;);
-
-	ret = skb_tailroom(skb);
-
-	DEBUG(4, __FUNCTION__"(): room is %d bytes\n",ret);
-
-	return(ret);
-}
-
-/*
- * Function irvtd_chars_in_buffer (tty)
- *
- *    This function returns how many characters which have not been sent yet 
- *    are still in buffer.
- *
- */
-int irvtd_chars_in_buffer(struct tty_struct *tty){
-
-	struct sk_buff *skb;
-	unsigned long flags;
-
-	DEBUG(4, __FUNCTION__"()\n");
-
-	save_flags(flags);cli();
-	skb = ((struct irvtd_cb *) tty->driver_data)->txbuff;
-	if(skb == NULL) goto err;
-
-	restore_flags(flags);
-	return (skb->len );
-err:	
-	ASSERT(skb != NULL, ;);
-	restore_flags(flags);
-	return 0;   /* why not -EFAULT or such? see driver/char/serial.c */
-}
-
-/*
- * Function irvtd_break (tty, break_state)
- *
- *    Routine which turns the break handling on or off
- *
- */
-static void irvtd_break(struct tty_struct *tty, int break_state){
-	
- 	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	unsigned long flags;
-
-	DEBUG(0, __FUNCTION__"()\n");
-	ASSERT(tty->driver_data != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-	
-	save_flags(flags);cli();
-	if (break_state == -1)
-	{
-		driver->comm->break_signal = 0x01;
-		ircomm_control_request(driver->comm, BREAK_SIGNAL);
-
-	}
-	else
-	{
-		driver->comm->break_signal = 0x00;
-		ircomm_control_request(driver->comm, BREAK_SIGNAL);
-
-	}
-
-	restore_flags(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_ioctl() and friends
- * This routine allows us to implement device-specific ioctl's.
- * If passed ioctl number (i.e.cmd) is unknown one, we should return 
- * ENOIOCTLCMD.
- *
- * TODO: we can't use setserial on IrCOMM because some ioctls are not implemented.
- * we should add some ioctls and make some tool which is resemble to setserial.
- * ----------------------------------------------------------------------
- */
-
-static int get_modem_info(struct irvtd_cb * driver, unsigned int *value)
-{
-	unsigned int result;
-	result =  ((driver->mcr & MCR_RTS) ? TIOCM_RTS : 0)
-		| ((driver->mcr & MCR_DTR) ? TIOCM_DTR : 0)
-		| ((driver->msr & DELTA_DCD) ? TIOCM_CAR : 0)
-		| ((driver->msr & DELTA_RI) ? TIOCM_RNG : 0)
-		| ((driver->msr & DELTA_DSR) ? TIOCM_DSR : 0)
-		| ((driver->msr & DELTA_CTS) ? TIOCM_CTS : 0);
-	return put_user(result,value);
-}
-
-static int set_modem_info(struct irvtd_cb * driver, unsigned int cmd,
-			  unsigned int *value)
-{ 
-	int error;
-	unsigned int arg;
-
-	error = get_user(arg, value);
-	if(error)
-		return error;
-
-	switch (cmd) {
-	case TIOCMBIS: 
-		if (arg & TIOCM_RTS) 
-			driver->mcr |= MCR_RTS;
-		if (arg & TIOCM_DTR)
-			driver->mcr |= MCR_DTR;
-		break;
-		
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			driver->mcr &= ~MCR_RTS;
-		if (arg & TIOCM_DTR)
- 			driver->mcr &= ~MCR_DTR;
- 		break;
-		
-	case TIOCMSET:
- 		driver->mcr = ((driver->mcr & ~(MCR_RTS | MCR_DTR))
-			       | ((arg & TIOCM_RTS) ? MCR_RTS : 0)
-			       | ((arg & TIOCM_DTR) ? MCR_DTR : 0));
-		break;
-		
-	default:
-		return -EINVAL;
-	}
-	
-	driver->comm->dte = driver->mcr;
-	ircomm_control_request(driver->comm, DTELINE_STATE );
-
-	return 0;
-}
-
-static int get_serial_info(struct irvtd_cb * driver,
-			   struct serial_struct * retinfo)
-{
-	struct serial_struct tmp;
-   
-	if (!retinfo)
-		return -EFAULT;
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.line = driver->line;
-	tmp.flags = driver->flags;
-	tmp.baud_base = driver->comm->data_rate;
-	tmp.close_delay = driver->close_delay;
-	tmp.closing_wait = driver->closing_wait;
-
-	/* for compatibility  */
-
- 	tmp.type = PORT_16550A;
- 	tmp.port = 0;
- 	tmp.irq = 0;
-	tmp.xmit_fifo_size = 0;
-	tmp.hub6 = 0;   
-	tmp.custom_divisor = driver->custom_divisor;
-
-	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
-		return -EFAULT;
-	return 0;
-}
-
-static int set_serial_info(struct irvtd_cb * driver,
-			   struct serial_struct * new_info)
-{
-	struct serial_struct new_serial;
-	struct irvtd_cb old_driver;
-
-	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-		return -EFAULT;
-
-	old_driver = *driver;
-  
-	if (!capable(CAP_SYS_ADMIN)) {
-		if ((new_serial.baud_base != driver->comm->data_rate) ||
-		    (new_serial.close_delay != driver->close_delay) ||
-		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
-		     (driver->flags & ~ASYNC_USR_MASK)))
-			return -EPERM;
-		driver->flags = ((driver->flags & ~ASYNC_USR_MASK) |
-				 (new_serial.flags & ASYNC_USR_MASK));
-		driver->custom_divisor = new_serial.custom_divisor;
-		goto check_and_exit;
-	}
-
-	/*
-	 * OK, past this point, all the error checking has been done.
-	 * At this point, we start making changes.....
-	 */
-
-	if(driver->comm->data_rate != new_serial.baud_base){
-		driver->comm->data_rate = new_serial.baud_base;
-		if(driver->comm->state == COMM_CONN)
-			ircomm_control_request(driver->comm,DATA_RATE);
-	}
-	driver->close_delay = new_serial.close_delay * HZ/100;
-	driver->closing_wait = new_serial.closing_wait * HZ/100;
-	driver->custom_divisor = new_serial.custom_divisor;
-
-	driver->flags = ((driver->flags & ~ASYNC_FLAGS) |
-			 (new_serial.flags & ASYNC_FLAGS));
-	driver->tty->low_latency = (driver->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
- check_and_exit:
-	if (driver->flags & ASYNC_INITIALIZED) {
-		if (((old_driver.flags & ASYNC_SPD_MASK) !=
-		     (driver->flags & ASYNC_SPD_MASK)) ||
-		    (old_driver.custom_divisor != driver->custom_divisor)) {
-			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-				driver->tty->alt_speed = 57600;
-			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-				driver->tty->alt_speed = 115200;
-			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-				driver->tty->alt_speed = 230400;
-			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-				driver->tty->alt_speed = 460800;
-			change_speed(driver);
-		}
-	}
-	return 0;
-}
-
-
-
-
-int irvtd_ioctl(struct tty_struct *tty, struct file * file,
-		unsigned int cmd, unsigned long arg)
-{
-	int error;
-	unsigned long flags;
- 	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-
-	struct serial_icounter_struct cnow,cprev;
-	struct serial_icounter_struct *p_cuser;	/* user space */
-
-
-	DEBUG(4,"irvtd_ioctl:requested ioctl(0x%08x)\n",cmd);
-
-#ifdef IRVTD_DEBUG_IOCTL
-	{
-		/* kill time so that debug messages will come slowly  */
-		save_flags(flags);cli();
-		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + HZ/4; /*0.25sec*/
-		schedule();
-		restore_flags(flags);
-	}
-#endif
-
-
-
-	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR)){
-			return -EIO;
-		}
-	}
-	
-	switch (cmd) {
-
-	case TIOCMGET:
-		return get_modem_info(driver, (unsigned int *) arg);
-
-	case TIOCMBIS:
-	case TIOCMBIC:
-	case TIOCMSET:
-		return set_modem_info(driver, cmd, (unsigned int *) arg);
-	case TIOCGSERIAL:
-		return get_serial_info(driver, (struct serial_struct *) arg);
-	case TIOCSSERIAL:
-		return set_serial_info(driver, (struct serial_struct *) arg);
-
-
-	case TIOCMIWAIT:
-		save_flags(flags); cli();
-		/* note the counters on entry */
-		cprev = driver->icount;
-		restore_flags(flags);
-		while (1) {
-			interruptible_sleep_on(&driver->delta_msr_wait);
-				/* see if a signal did it */
-			if (signal_pending(current))
-				return -ERESTARTSYS;
-			save_flags(flags); cli();
-			cnow = driver->icount; /* atomic copy */
-			restore_flags(flags);
-			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
-			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-				return -EIO; /* no change => error */
-			if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-			     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-			     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-			     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-				return 0;
-			}
-			cprev = cnow;
-		}
-		/* NOTREACHED */
-
-	case TIOCGICOUNT:
-		save_flags(flags); cli();
-		cnow = driver->icount;
-		restore_flags(flags);
-		p_cuser = (struct serial_icounter_struct *) arg;
-		error = put_user(cnow.cts, &p_cuser->cts);
-		if (error) return error;
-		error = put_user(cnow.dsr, &p_cuser->dsr);
-		if (error) return error;
-		error = put_user(cnow.rng, &p_cuser->rng);
-		if (error) return error;
-		error = put_user(cnow.dcd, &p_cuser->dcd);
-		if (error) return error;
-		error = put_user(cnow.rx, &p_cuser->rx);
-		if (error) return error;
-		error = put_user(cnow.tx, &p_cuser->tx);
-		if (error) return error;
-		error = put_user(cnow.frame, &p_cuser->frame);
-		if (error) return error;
-		error = put_user(cnow.overrun, &p_cuser->overrun);
-		if (error) return error;
-		error = put_user(cnow.parity, &p_cuser->parity);
-		if (error) return error;
-		error = put_user(cnow.brk, &p_cuser->brk);
-		if (error) return error;
-		error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
-		if (error) return error;			
-		return 0;
-		
-		
-		/* ioctls which are imcompatible with serial.c */
-
-	case TIOCSERGSTRUCT:
-		DEBUG(0,__FUNCTION__"():sorry, TIOCSERGSTRUCT is not supported\n");
-		return -ENOIOCTLCMD;  
-	case TIOCSERGETLSR:
-		DEBUG(0,__FUNCTION__"():sorry, TIOCSERGETLSR is not supported\n");
-		return -ENOIOCTLCMD;  
- 	case TIOCSERCONFIG:
-		DEBUG(0,__FUNCTION__"():sorry, TIOCSERCONFIG is not supported\n");
-		return -ENOIOCTLCMD;  
-
-
-	default:
-		return -ENOIOCTLCMD;  /* ioctls which we must ignore */
-	}
-	return 0;
-}
-
-
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_set_termios()
- * This is called when termios is changed.
- * If things that changed is significant for us,(i.e. changing baud rate etc.)
- * send something to peer device.
- * ----------------------------------------------------------------------
- */
-
-void irvtd_set_termios(struct tty_struct *tty, struct termios * old_termios){
-
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-
-	ASSERT(driver != NULL,return;);
-	ASSERT(driver->magic == IRVTD_MAGIC ,return;);
-
-	DEBUG(0, "irvtd_set_termios:\n");
-	return;
-
-	if((tty->termios->c_cflag == old_termios->c_cflag) &&
-	   (RELEVANT_IFLAG(tty->termios->c_iflag) 
-	    == RELEVANT_IFLAG(old_termios->c_iflag)))
-		return;
-
-	change_speed(driver);
-
-	if((old_termios->c_cflag & CRTSCTS) &&
-	   !(tty->termios->c_cflag & CRTSCTS)) {
-		tty->hw_stopped = driver->ttp_stoptx;
-		/* irvtd_start(tty); */       /* we don't need this */
-	}
-}
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_throttle,irvtd_unthrottle
- *   These routines will be called when we have to pause sending up data to tty.
- *   We use RTS virtual signal when servicetype is NINE_WIRE
- * ----------------------------------------------------------------------
- */
-
-static void irvtd_send_xchar(struct tty_struct *tty, char ch){
-
-	DEBUG(1, __FUNCTION__"():\n");
-	irvtd_put_char(tty, ch);
-}
-
-void irvtd_throttle(struct tty_struct *tty){
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-
-	DEBUG(1, "irvtd_throttle:\n");
-
-	if (I_IXOFF(tty))
-		irvtd_put_char(tty, STOP_CHAR(tty));
-
-	driver->mcr &= ~MCR_RTS; 
-	driver->mcr |= DELTA_RTS; 
-	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);
-}
-
-void irvtd_unthrottle(struct tty_struct *tty){
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	DEBUG(1, "irvtd_unthrottle:\n");
-
-	if (I_IXOFF(tty))
-		irvtd_put_char(tty, START_CHAR(tty));
-
-	driver->mcr |= (MCR_RTS|DELTA_RTS);
-	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);
-}
-
-
-/*
- * ------------------------------------------------------------
- * irvtd_stop() and irvtd_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable an interrupt which means "transmitter-is-ready"
- * in serial.c, but  I think these routine are not necessary for us. 
- * ------------------------------------------------------------
- */
-
-#if 0
-irvtd_stop(struct tty_struct *tty){
- 	DEBUG(0, "irvtd_stop()\n");
-
-	struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data; 
-	DEBUG(0, "irvtd_start():not implemented!\n");
-}
-irvtd_start(struct tty_struct *tty){
-
-	struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data;
-	DEBUG(0, "irvtd_start():not_implemented!\n");
-}
-#endif
-
-/*
- * ------------------------------------------------------------
- * irvtd_hangup()
- * This routine notifies that tty layer have got HUP signal
- * ------------------------------------------------------------
- */
-
-void irvtd_hangup(struct tty_struct *tty){
-
-	struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data;
-	DEBUG(0, __FUNCTION__"()\n");
-
-	irvtd_flush_buffer(tty);
-	irvtd_shutdown(info);
-	info->count = 0;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
-}
-
-void irvtd_flush_buffer(struct tty_struct *tty){
-
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	struct sk_buff *skb;
-
-	skb = driver->txbuff;
-	ASSERT(skb != NULL, return;); 
-
-	if(skb->len){
-		DEBUG(0, __FUNCTION__"():%d chars in txbuff are lost..\n",(int)skb->len);
-		skb_trim(skb,0); 
-	}
-	
-	/* write_wait is a wait queue of tty_wait_until_sent().
-	 * see tty_io.c of kernel 
-	 */
-	wake_up_interruptible(&tty->write_wait); 
-
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-}
-
-
-
-/*
- * Function ircomm_register_device(void), init_module() and friends
- *
- *   we register "port emulation entity"(see IrCOMM specification) here
- *   as a tty device.
- */
-
-int irvtd_register_ttydriver(void){
-
-        DEBUG( 4, "-->irvtd_register_ttydriver\n");
-
-	/* setup virtual serial port device */
-
-        /* Initialize the tty_driver structure ,which is defined in 
-	   tty_driver.h */
-        
-        memset(&irvtd_drv, 0, sizeof(struct tty_driver));
-	irvtd_drv.magic = IRVTD_MAGIC;
-	irvtd_drv.driver_name = "IrCOMM_tty";
-	irvtd_drv.name = "irnine";
-	irvtd_drv.major = IRCOMM_MAJOR;
-	irvtd_drv.minor_start = IRVTD_MINOR;
-	irvtd_drv.num = COMM_MAX_TTY;
-	irvtd_drv.type = TTY_DRIVER_TYPE_SERIAL;  /* see tty_driver.h */
-
-
-	/*
-	 * see drivers/char/tty_io.c and termios(3)
-	 */
-
-        irvtd_drv.init_termios = tty_std_termios;
-        irvtd_drv.init_termios.c_cflag =
-		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-        irvtd_drv.flags = TTY_DRIVER_REAL_RAW;   /* see tty_driver.h */
-        irvtd_drv.refcount = &irvtd_refcount;
-
-	/* pointer to the tty data structures */
-
-        irvtd_drv.table = irvtd_table;  
-        irvtd_drv.termios = irvtd_termios;
-        irvtd_drv.termios_locked = irvtd_termios_locked;
-
-        /*
-         * Interface table from the kernel(tty driver) to the ircomm
-         * layer
-         */
-
-        irvtd_drv.open = irvtd_open;
-        irvtd_drv.close = irvtd_close;
-        irvtd_drv.write = irvtd_write;
-        irvtd_drv.put_char = irvtd_put_char;
-	irvtd_drv.flush_chars = irvtd_flush_chars;
-        irvtd_drv.write_room = irvtd_write_room;
-	irvtd_drv.chars_in_buffer = irvtd_chars_in_buffer; 
-        irvtd_drv.flush_buffer = irvtd_flush_buffer;
- 	irvtd_drv.ioctl = irvtd_ioctl; 
-	irvtd_drv.throttle = irvtd_throttle;
-	irvtd_drv.unthrottle = irvtd_unthrottle;
- 	irvtd_drv.set_termios = irvtd_set_termios;
-	irvtd_drv.stop = NULL;          /*  irvtd_stop; */
-	irvtd_drv.start = NULL;         /* irvtd_start; */
-        irvtd_drv.hangup = irvtd_hangup;
-
-        irvtd_drv.send_xchar = irvtd_send_xchar;
-	irvtd_drv.break_ctl = irvtd_break;
-	irvtd_drv.read_proc = irvtd_read_proc;
- 	irvtd_drv.wait_until_sent = irvtd_wait_until_sent;
-
-
-
-	if (tty_register_driver(&irvtd_drv)){
-		DEBUG(0,"IrCOMM:Couldn't register tty driver\n");
-		return(1);
-	}
-
-	DEBUG( 4, "irvtd_register_ttydriver: done.\n");
-	return(0);
-}
-
-
-/*
- * Function irvtd_unregister_device(void) 
- *   it will be called when you rmmod
- */
-
-void irvtd_unregister_ttydriver(void){
-
-	int err;	
-        DEBUG( 4, "--> irvtd_unregister_device\n");
-
-	/* unregister tty device   */
-
-	err = tty_unregister_driver(&irvtd_drv);
-        if (err)
-                printk("IrCOMM: failed to unregister vtd driver(%d)\n",err);
-        DEBUG( 4, "irvtd_unregister_device -->\n");
-	return;
-}
-
-/*
- **********************************************************************
- *    proc stuff
- *
- **********************************************************************
- */
-
-static int line_info(char *buf, struct irvtd_cb *driver)
-{
-	int	ret=0;
-
-	ASSERT(driver != NULL,goto exit;);
-	ASSERT(driver->magic == IRVTD_MAGIC,goto exit;);
-
-	ret += sprintf(buf, "tx: %d rx: %d"
-		      ,driver->icount.tx, driver->icount.rx);
-
-	if (driver->icount.frame)
-                ret += sprintf(buf+ret, " fe:%d", driver->icount.frame);
-        if (driver->icount.parity)
-                ret += sprintf(buf+ret, " pe:%d", driver->icount.parity);
-        if (driver->icount.brk)
-                ret += sprintf(buf+ret, " brk:%d", driver->icount.brk);  
-        if (driver->icount.overrun)
-                ret += sprintf(buf+ret, " oe:%d", driver->icount.overrun);
-
-	if (driver->mcr & MCR_RTS)
-                ret += sprintf(buf+ret, "|RTS");
-        if (driver->msr & MSR_CTS)
-                ret += sprintf(buf+ret, "|CTS");
-        if (driver->mcr & MCR_DTR)
-                ret += sprintf(buf+ret, "|DTR");
-        if (driver->msr & MSR_DSR)
-                ret += sprintf(buf+ret, "|DSR");
-        if (driver->msr & MSR_DCD)
-                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");
-	return ret;
-}
-
-
-
-static int irvtd_read_proc(char *buf, char **start, off_t offset, int len,
-		 int *eof, void *unused)
-{
-	int i, count = 0, l;
-	off_t	begin = 0;
-
-	count += sprintf(buf, "driver revision:%s\n", revision_date);
-	for (i = 0; i < COMM_MAX_TTY && count < 4000; i++) {
-		l = line_info(buf + count, irvtd[i]);
-		count += l;
-		if (count+begin > offset+len)
-			goto done;
-		if (count+begin < offset) {
-			begin += count;
-			count = 0;
-		}
-	}
-	*eof = 1;
-done:
-	if (offset >= count+begin)
-		return 0;
-	*start = buf + (begin-offset);
-	return ((len < begin+count-offset) ? len : begin+count-offset);
-}
-
-
-
-
-/************************************************************
- *    init & cleanup this module 
- ************************************************************/
-
-__initfunc(int irvtd_init(void))
-{
-	int i;
-
-	DEBUG( 4, __FUNCTION__"()\n");
-	printk( KERN_INFO 
-		"ircomm_tty: virtual tty driver for IrCOMM ( revision:%s )\n",
-		revision_date);
-
-
-	/* allocate a master array */
-
-	irvtd = (struct irvtd_cb **) kmalloc( sizeof(void *) *
-						COMM_MAX_TTY,GFP_KERNEL);
-	if ( irvtd == NULL) {
-		printk( KERN_WARNING __FUNCTION__"(): kmalloc failed!\n");
-		return -ENOMEM;
-	}
-
-	memset( irvtd, 0, sizeof(void *) * COMM_MAX_TTY);
-
-	for (i=0; i < COMM_MAX_TTY; i++){
-		irvtd[i] = kmalloc( sizeof(struct irvtd_cb), GFP_KERNEL);	
-		if(irvtd[i] == NULL){
-			printk(KERN_ERR __FUNCTION__"(): kmalloc failed!\n");
-			return -ENOMEM;
-		}
-		memset( irvtd[i], 0, sizeof(struct irvtd_cb));
-		irvtd[i]->magic = IRVTD_MAGIC;
-		irvtd[i]->line = i;
-		irvtd[i]->closing_wait = 10*HZ ;
-		irvtd[i]->close_delay = 5*HZ/10 ; 
-	}
-
-	/* 
-	 * initialize a "port emulation entity"
-	 */
-
-	if(irvtd_register_ttydriver()){
-		printk( KERN_WARNING "IrCOMM: Error in ircomm_register_device\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-void irvtd_cleanup(void)
-{
-	int i;
-	DEBUG( 4, __FUNCTION__"()\n");
-
-	/*
-	 * free some resources
-	 */
-	if (irvtd) {
-		for (i=0; i<COMM_MAX_TTY; i++) {
-			if (irvtd[i]) {
-				if(irvtd[i]->comm)
-					ircomm_close_instance(irvtd[i]->comm);
-				if(irvtd[i]->txbuff)
-					dev_kfree_skb(irvtd[i]->txbuff);
-				DEBUG( 4, "freeing structures\n");
-				kfree(irvtd[i]);
-				irvtd[i] = NULL;
-			}
-		}
-		DEBUG( 4, "freeing master array\n");
-		kfree(irvtd);
-		irvtd = NULL;
-	}
-
- 	irvtd_unregister_ttydriver();
-
-}
-
-#ifdef MODULE
-
-int init_module(void) 
-{
-	irvtd_init();
-	return 0;
-}
-
-/*
- * Function ircomm_cleanup (void)
- *   This is called when you rmmod.
- */
-
-void cleanup_module(void)
-{
-	irvtd_cleanup();
-}
-
-#endif /* MODULE */
diff -urN linux-2.2.15-pre2/net/irda/irda_device.c linux/net/irda/irda_device.c
--- linux-2.2.15-pre2/net/irda/irda_device.c	Tue Jan  4 10:12:27 2000
+++ linux/net/irda/irda_device.c	Mon Dec  3 21:57:53 2001
@@ -1,28 +1,35 @@
 /*********************************************************************
  *                
  * Filename:      irda_device.c
- * Version:       0.5
- * Description:   Abstract device driver layer and helper functions
+ * Version:       0.9
+ * Description:   Utility functions used by the device drivers
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Wed Sep  2 20:22:08 1998
- * Modified at:   Tue Jun  1 09:05:13 1999
+ * Created at:    Sat Oct  9 09:22:27 1999
+ * Modified at:   Sun Dec 12 12:24:32 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
- *      
+ *     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.
- *  
- *     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>
+#include <linux/string.h>
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
 #include <linux/if.h>
@@ -33,17 +40,17 @@
 #include <linux/tty.h>
 #include <linux/kmod.h>
 #include <linux/wireless.h>
+#include <asm/spinlock.h>
 
 #include <asm/ioctls.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
-#include <asm/spinlock.h>
 
 #include <net/pkt_sched.h>
 
 #include <net/irda/irda_device.h>
-#include <net/irda/irlap_frame.h>
+#include <net/irda/irlap.h>
 #include <net/irda/timer.h>
 #include <net/irda/wrapper.h>
 
@@ -55,37 +62,51 @@
 extern int actisys_init(void);
 extern int girbil_init(void);
 
-static hashbin_t *irda_device = NULL;
+static void __irda_task_delete(struct irda_task *task);
+
 static hashbin_t *dongles = NULL;
+static hashbin_t *tasks = NULL;
+
+const char *infrared_mode[] = {
+	"IRDA_IRLAP",
+	"IRDA_RAW",
+	"SHARP_ASK",
+	"TV_REMOTE",
+};
+
+static const char *task_state[] = {
+	"IRDA_TASK_INIT",
+	"IRDA_TASK_DONE", 
+	"IRDA_TASK_WAIT",
+	"IRDA_TASK_WAIT1",
+	"IRDA_TASK_WAIT2",
+	"IRDA_TASK_WAIT3",
+	"IRDA_TASK_CHILD_INIT",
+	"IRDA_TASK_CHILD_WAIT",
+	"IRDA_TASK_CHILD_DONE",
+};
+
+static void irda_task_timer_expired(void *data);
 
-/* Netdevice functions */
-static int irda_device_net_rebuild_header(struct sk_buff *skb);
-static int irda_device_net_hard_header(struct sk_buff *skb, 
-				       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_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);
+int irda_device_proc_read(char *buf, char **start, off_t offset, int len, 
+			  int unused);
 
 #endif /* CONFIG_PROC_FS */
 
-__initfunc(int irda_device_init( void))
+int __init irda_device_init( void)
 {
-	/* Allocate master array */
-	irda_device = hashbin_new( HB_LOCAL);
-	if (irda_device == NULL) {
-		WARNING("IrDA: Can't allocate irda_device hashbin!\n");
+	dongles = hashbin_new(HB_GLOBAL);
+	if (dongles == NULL) {
+		printk(KERN_WARNING 
+		       "IrDA: Can't allocate dongles hashbin!\n");
 		return -ENOMEM;
 	}
 
-	dongles = hashbin_new(HB_LOCAL);
-	if (dongles == NULL) {
+	tasks = hashbin_new(HB_GLOBAL);
+	if (tasks == NULL) {
 		printk(KERN_WARNING 
-		       "IrDA: Can't allocate dongles hashbin!\n");
+		       "IrDA: Can't allocate tasks hashbin!\n");
 		return -ENOMEM;
 	}
 
@@ -123,289 +144,266 @@
 #ifdef CONFIG_LITELINK_DONGLE
 	litelink_init();
 #endif
-
+#ifdef CONFIG_AIRPORT_DONGLE
+ 	airport_init();
+#endif
+#ifdef CONFIG_OLD_BELKIN
+ 	old_belkin_init();
+#endif
 	return 0;
 }
 
 void irda_device_cleanup(void)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(irda_device != NULL, return;);
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
+	hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
 	hashbin_delete(dongles, NULL);
-	hashbin_delete(irda_device, (FREE_FUNC) irda_device_close);
 }
 
 /*
- * Function irda_device_open (self)
- *
- *    Open a new IrDA port device
+ * Function irda_device_set_media_busy (self, status)
  *
+ *    Called when we have detected that another station is transmiting
+ *    in contention mode.
  */
-int irda_device_open(struct irda_device *self, char *name, void *priv)
-{        
-	int result;
-	int i=0;
+void irda_device_set_media_busy(struct device *dev, int status) 
+{
+	struct irlap_cb *self;
 
-	/* Allocate memory if needed */
-	if (self->rx_buff.truesize > 0) {
-		self->rx_buff.head = ( __u8 *) kmalloc(self->rx_buff.truesize,
-						       self->rx_buff.flags);
-		if (self->rx_buff.head == NULL)
-			return -ENOMEM;
+	IRDA_DEBUG(4, __FUNCTION__ "(%s)\n", status ? "TRUE" : "FALSE");
 
-		memset(self->rx_buff.head, 0, self->rx_buff.truesize);
-	}
-	if (self->tx_buff.truesize > 0) {
-		self->tx_buff.head = ( __u8 *) kmalloc(self->tx_buff.truesize, 
-						       self->tx_buff.flags);
-		if (self->tx_buff.head == NULL)
-			return -ENOMEM;
+	self = (struct irlap_cb *) dev->atalk_ptr;
 
-		memset(self->tx_buff.head, 0, self->tx_buff.truesize);
-	}
-	
-      	self->magic = IRDA_DEVICE_MAGIC;
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	self->rx_buff.in_frame = FALSE;
-	self->rx_buff.state = OUTSIDE_FRAME;
-	self->tx_buff.data = self->tx_buff.head;
-	self->rx_buff.data = self->rx_buff.head;
+	if (status) {
+		self->media_busy = TRUE;
+		irlap_start_mbusy_timer(self);
+		IRDA_DEBUG( 4, "Media busy!\n");
+	} else {
+		self->media_busy = FALSE;
+		del_timer(&self->media_busy_timer);
+	}
+}
 
-	/* Initialize timers */
-	init_timer(&self->media_busy_timer);	
+int irda_device_set_dtr_rts(struct device *dev, int dtr, int rts)
+{	
+	struct if_irda_req req;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if (!dev->do_ioctl) {
+		ERROR(__FUNCTION__ "(), do_ioctl not impl. by "
+		      "device driver\n");
+		return -1;
+	}
 
-	self->lock = SPIN_LOCK_UNLOCKED;
+	req.ifr_dtr = dtr;
+	req.ifr_rts = rts;
 
-	/* A pointer to the low level implementation */
-	self->priv = priv;
+	ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCSDTRRTS);
 
-	/* Initialize IrDA net device */
-	do {
-		sprintf(self->name, "%s%d", "irda", i++);
-	} while (dev_get(self->name) != NULL);
-	
-	self->netdev.name = self->name;
-	self->netdev.priv = (void *) self;
-	self->netdev.next = NULL;
+	return ret;
+}
 
-	if ((result = register_netdev(&self->netdev)) != 0) {
-		DEBUG(0, __FUNCTION__ "(), register_netdev() failed!\n");
+int irda_device_change_speed(struct device *dev, __u32 speed)
+{	
+	struct if_irda_req req;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if (!dev->do_ioctl) {
+		ERROR(__FUNCTION__ "(), do_ioctl not impl. by "
+		      "device driver\n");
 		return -1;
 	}
-	
-	/* 
-	 * Make the description for the device. self->netdev.name will get
-	 * a name like "irda0" and the self->descriptin will get a name
-	 * like "irda0 <-> irtty0" 
-	 */
-	strncpy(self->description, self->name, 5);
-	strcat(self->description, " <-> ");
-	strncat(self->description, name, 23);
-	
-	hashbin_insert(irda_device, (QUEUE *) self, (int) self, NULL);
-	
-	/* Open network device */
-	dev_open(&self->netdev);
 
-	MESSAGE("IrDA: Registered device %s\n", self->name);
+	req.ifr_baudrate = speed;
 
-	irda_device_set_media_busy(self, FALSE);
+	ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCSBANDWIDTH);
 
-	/* 
-	 * Open new IrLAP layer instance, now that everything should be
-	 * initialized properly 
-	 */
-	self->irlap = irlap_open(self);
-        
-	/* It's now safe to initilize the saddr */
-	memcpy(self->netdev.dev_addr, &self->irlap->saddr, 4);
-
-	return 0;
+	return ret;
 }
 
 /*
- * Function irda_device_close (self)
+ * Function irda_device_is_receiving (dev)
  *
- *    Close this instance of the irda_device, just deallocate buffers
+ *    Check if the device driver is currently receiving data
  *
  */
-void __irda_device_close(struct irda_device *self)
+int irda_device_is_receiving(struct device *dev)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	struct if_irda_req req;
+	int ret;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	/* We do this test to know if the device has been registered at all */
-	if (self->netdev.type == ARPHRD_IRDA) {
-		dev_close(&self->netdev);
-		
-		/* Remove netdevice */
-		unregister_netdev(&self->netdev);
+	if (!dev->do_ioctl) {
+		ERROR(__FUNCTION__ "(), do_ioctl not impl. by "
+		      "device driver\n");
+		return -1;
 	}
 
-	/* Stop timers */
-	del_timer(&self->media_busy_timer);
+	ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCGRECEIVING);
+	if (ret < 0)
+		return ret;
 
-	if (self->tx_buff.head)
-		kfree(self->tx_buff.head);
-
-	if (self->rx_buff.head)
-		kfree(self->rx_buff.head);
-
-	self->magic = 0;
+	return req.ifr_receiving;
 }
 
-/*
- * Function irda_device_close (self)
- *
- *    Close the device
- *
- */
-void irda_device_close(struct irda_device *self)
+void irda_task_next_state(struct irda_task *task, TASK_STATE state)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "(), state = %s\n", task_state[state]);
 
-	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);
-	self->irlap = NULL;
-
-	hashbin_remove(irda_device, (int) self, NULL);
-
-	__irda_device_close(self);
+	task->state = state;
 }
 
-/*
- * Function irda_device_set_media_busy (self, status)
- *
- *    Called when we have detected that another station is transmiting
- *    in contention mode.
- */
-void irda_device_set_media_busy(struct irda_device *self, int status) 
+static void __irda_task_delete(struct irda_task *task)
 {
-	DEBUG(4, __FUNCTION__ "(%s)\n", status ? "TRUE" : "FALSE");
+	del_timer(&task->timer);
+	
+	kfree(task);
+}
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+void irda_task_delete(struct irda_task *task)
+{
+	/* Unregister task */
+	hashbin_remove(tasks, (int) task, NULL);
 
-	if (status) {
-		self->media_busy = TRUE;
-		irda_device_start_mbusy_timer(self);
-		DEBUG( 4, "Media busy!\n");
-	} else {
-		self->media_busy = FALSE;
-		del_timer(&self->media_busy_timer);
-	}
+	__irda_task_delete(task);
 }
 
 /*
- * Function __irda_device_change_speed (self, speed)
+ * Function irda_task_kick (task)
  *
- *    When this function is called, we will have a process context so its
- *    possible for us to sleep, wait or whatever :-)
+ *    Tries to execute a task possible multiple times until the task is either
+ *    finished, or askes for a timeout. When a task is finished, we do post
+ *    processing, and notify the parent task, that is waiting for this task
+ *    to complete.
  */
-static void __irda_device_change_speed(struct irda_device *self, int speed)
+int irda_task_kick(struct irda_task *task)
 {
-	int n = 0;
+	int finished = TRUE;
+	int count = 0;
+	int timeout;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	/*
-	 *  Is is possible to change speed yet? Wait until the last byte 
-	 *  has been transmitted.
-	 */
-	if (!self->wait_until_sent) {
-		ERROR("IrDA: wait_until_sent() "
-		      "has not implemented by the IrDA device driver!\n");
-		return;
-	}
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	/* Make sure all transmitted data has actually been sent */
-	self->wait_until_sent(self);
+	ASSERT(task != NULL, return -1;);
+	ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
 
-	/* 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;
-		}
-	}
-	
-	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;
+	/* Execute task until it's finished, or askes for a timeout */
+	do {
+		timeout = task->function(task);
+		if (count++ > 100) {
+			ERROR(__FUNCTION__ "(), error in task handler!\n");
+			irda_task_delete(task);
+			return TRUE;
+		}			
+	} while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
+
+	if (timeout < 0) {
+		ERROR(__FUNCTION__ "(), Error executing task!\n");
+		irda_task_delete(task);
+		return TRUE;
+	}
+
+	/* Check if we are finished */
+	if (task->state == IRDA_TASK_DONE) {
+		del_timer(&task->timer);
+
+		/* Do post processing */
+		if (task->finished)
+			task->finished(task);
+
+		/* Notify parent */
+		if (task->parent) {
+			/* Check if parent is waiting for us to complete */
+			if (task->parent->state == IRDA_TASK_CHILD_WAIT) {
+				task->parent->state = IRDA_TASK_CHILD_DONE;
+
+				/* Stop timer now that we are here */
+				del_timer(&task->parent->timer);
+
+				/* Kick parent task */
+				irda_task_kick(task->parent);
+			}
+		}		
+		irda_task_delete(task);
+	} else if (timeout > 0) {
+		irda_start_timer(&task->timer, timeout, (void *) task, 
+				 irda_task_timer_expired);
+		finished = FALSE;
+	} else {
+		IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), not finished, and no timeout!\n");
+		finished = FALSE;
 	}
-	self->netdev.tbusy = FALSE;
+
+	return finished;
 }
 
 /*
- * Function irda_device_change_speed (self, speed)
- *
- *    Change the speed of the currently used irda_device
+ * Function irda_task_execute (instance, function, finished)
  *
+ *    This function registers and tries to execute tasks that may take some
+ *    time to complete. We do it this hairy way since we may have been
+ *    called from interrupt context, so it's not possible to use
+ *    schedule_timeout() 
  */
-inline void irda_device_change_speed(struct irda_device *self, int speed)
+struct irda_task *irda_task_execute(void *instance, TASK_CALLBACK function, 
+				    TASK_CALLBACK finished, 
+				    struct irda_task *parent, void *param)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+	struct irda_task *task;
+	int ret;
 
-	irda_execute_as_process(self, 
-				(TODO_CALLBACK) __irda_device_change_speed, 
-				speed);
-}
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-inline int irda_device_is_media_busy( struct irda_device *self)
-{
-	ASSERT(self != NULL, return FALSE;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
-	
-	return self->media_busy;
-}
+	task = kmalloc(sizeof(struct irda_task), GFP_ATOMIC);
+	if (!task)
+		return NULL;
 
-inline int irda_device_is_receiving( struct irda_device *self)
-{
-	ASSERT(self != NULL, return FALSE;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	task->state    = IRDA_TASK_INIT;
+	task->instance = instance;
+	task->function = function;
+	task->finished = finished;
+	task->parent   = parent;
+	task->param    = param;	
+	task->magic    = IRDA_TASK_MAGIC;
+
+	init_timer(&task->timer);
 
-	if (self->is_receiving)
-		return self->is_receiving(self);
+	/* Register task */
+	hashbin_insert(tasks, (queue_t *) task, (int) task, NULL);
+
+	/* No time to waste, so lets get going! */
+	ret = irda_task_kick(task);
+	if (ret)
+		return NULL;
 	else
-		return FALSE;
+		return task;
 }
 
-inline struct qos_info *irda_device_get_qos(struct irda_device *self)
+/*
+ * Function irda_task_timer_expired (data)
+ *
+ *    Task time has expired. We now try to execute task (again), and restart
+ *    the timer if the task has not finished yet
+ */
+static void irda_task_timer_expired(void *data)
 {
-	ASSERT(self != NULL, return NULL;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return NULL;);
+	struct irda_task *task;
 
-	return &self->qos;
-}
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-static struct enet_statistics *irda_device_get_stats( struct device *dev)
-{
-	struct irda_device *priv = (struct irda_device *) dev->priv;
+	task = (struct irda_task *) data;
 
-	return &priv->stats;
+	irda_task_kick(task);
 }
 
 /*
@@ -416,24 +414,14 @@
  */
 int irda_device_setup(struct device *dev) 
 {
-	struct irda_device *self;
-
 	ASSERT(dev != NULL, return -1;);
 
-	self = (struct irda_device *) dev->priv;
-
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);	
-
-	dev->get_stats	     = irda_device_get_stats;
-	dev->rebuild_header  = irda_device_net_rebuild_header;
-	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;
 
+	/* dev->new_style       = 1; */
+	/* dev->destructor      = irda_device_destructor; */
+
         dev->type            = ARPHRD_IRDA;
         dev->tx_queue_len    = 8; /* Window size + 1 s-frame */
  
@@ -450,254 +438,73 @@
 }
 
 /*
- * Function irda_device_net_rebuild_header (buff, dev, dst, skb)
- *
- *    
- *
- */
-static int irda_device_net_rebuild_header( struct sk_buff *skb)
-{
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	return 0;
-}
-
-static int irda_device_net_hard_header(struct sk_buff *skb, struct device *dev,
-				       unsigned short type, void *daddr, 
-				       void *saddr, unsigned len)
-{
-	DEBUG( 0, __FUNCTION__ "()\n");
-
-	skb->mac.raw = skb->data;
-        /* skb_push(skb,PPP_HARD_HDR_LEN); */
-        /* return PPP_HARD_HDR_LEN; */
-	
-	return 0;
-}
-
-static int irda_device_net_set_config( struct device *dev, struct ifmap *map)
-{
-	DEBUG( 0, __FUNCTION__ "()\n");
-
-	return 0;
-}
-
-static int irda_device_net_change_mtu( struct device *dev, int new_mtu)
-{
-     DEBUG( 0, __FUNCTION__ "()\n");
-     
-     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.disabled) {
-			
-		} break;
-	case SIOCGIWNWID:
-		/* Read domain*/
-/* 		wrq->u.nwid.nwid = domain; */
-/* 		wrq->u.nwid.disabled = 0; */
-		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)
+ * Function irda_device_txqueue_empty (dev)
  *
  *    Check if there is still some frames in the transmit queue for this
  *    device. Maybe we should use: q->q.qlen == 0.
  *
  */
-int irda_device_txqueue_empty(struct irda_device *self)
+int irda_device_txqueue_empty(struct device *dev)
 {
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);	
-
-	if (skb_queue_len(&self->netdev.qdisc->q))
+	if (skb_queue_len(&dev->qdisc->q))
 		return FALSE;
 
 	return TRUE;
 }
 
 /*
- * Function irda_device_init_dongle (self, type)
+ * Function irda_device_init_dongle (self, type, qos)
  *
- *    Initialize attached dongle. Warning, must be called with a process
- *    context!
+ *    Initialize attached dongle.
  */
-void irda_device_init_dongle(struct irda_device *self, int type)
+dongle_t *irda_device_dongle_init(struct device *dev, int type)
 {
-	struct dongle_q *node;
+	struct dongle_reg *reg;
+	char modname[32];
+	dongle_t *dongle;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(dev != NULL, return NULL;);
 
 #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;
-	}
+	sprintf(modname, "irda-dongle-%d", type);
+	request_module(modname);
 #endif /* CONFIG_KMOD */
 
-	node = hashbin_find(dongles, type, NULL);
-	if (!node) {
+	if (!(reg = hashbin_find(dongles, type, NULL))) {
 		ERROR("IrDA: Unable to find requested dongle\n");
-		return;
-	}
-	
-	/* Check if we're already using a dongle */
-	if (self->dongle) {
-		self->dongle->close(self);
+		return NULL;
 	}
 
-	/* Set the dongle to be used by this driver */
-	self->dongle = node->dongle;
+	/* Allocate dongle info for this instance */
+	dongle = kmalloc(sizeof(dongle_t), GFP_KERNEL);
+	if (!dongle)
+		return NULL;
 
-	/* Now initialize the dongle!  */
-	node->dongle->open(self, type);
-	node->dongle->qos_init(self, &self->qos);
-	
-	/* Reset dongle */
-	node->dongle->reset(self);
+	memset(dongle, 0, sizeof(dongle_t));
+
+	/* Bind the registration info to this particular instance */
+	dongle->issue = reg;
+	dongle->dev = dev;
+
+	return dongle;
+}
+
+/*
+ * Function irda_device_dongle_cleanup (dongle)
+ *
+ *    
+ *
+ */
+int irda_device_dongle_cleanup(dongle_t *dongle)
+{
+	ASSERT(dongle != NULL, return -1;);
+
+	dongle->issue->close(dongle);
 
-	/* Set to default baudrate */
-	irda_device_change_speed(self, 9600);
+	kfree(dongle);
+
+	return 0;
 }
 
 /*
@@ -706,26 +513,16 @@
  *    
  *
  */
-int irda_device_register_dongle(struct dongle *dongle)
+int irda_device_register_dongle(struct dongle_reg *new)
 {
-	struct dongle_q *new;
-	
 	/* Check if this dongle has been registred before */
-	if (hashbin_find(dongles, dongle->type, NULL)) {
+	if (hashbin_find(dongles, new->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);
+	hashbin_insert(dongles, (queue_t *) new, new->type, NULL);
 	
         return 0;
 }
@@ -733,25 +530,51 @@
 /*
  * Function irda_device_unregister_dongle (dongle)
  *
- *    
+ *    Unregister dongle, and remove dongle from list of registred dongles
  *
  */
-void irda_device_unregister_dongle(struct dongle *dongle)
+void irda_device_unregister_dongle(struct dongle_reg *dongle)
 {
-	struct dongle_q *node;
+	struct dongle *node;
 
 	node = hashbin_remove(dongles, dongle->type, NULL);
 	if (!node) {
 		ERROR(__FUNCTION__ "(), dongle not found!\n");
 		return;
 	}
-	kfree(node);
+}
+
+/*
+ * Function irda_device_set_mode (self, mode)
+ *
+ *    Set the Infrared device driver into mode where it sends and receives
+ *    data without using IrLAP framing. Check out the particular device
+ *    driver to find out which modes it support.
+ */
+int irda_device_set_mode(struct device* dev, int mode)
+{	
+	struct if_irda_req req;
+	int ret;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	if (!dev->do_ioctl) {
+		ERROR(__FUNCTION__ "(), set_raw_mode not impl. by "
+		      "device driver\n");
+		return -1;
+	}
+	
+	req.ifr_mode = mode;
+
+	ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCSMODE);
+	
+	return ret;
 }
 
 /*
  * Function setup_dma (idev, buffer, count, mode)
  *
- *    Setup the DMA channel
+ *    Setup the DMA channel. Commonly used by ISA FIR drivers
  *
  */
 void setup_dma(int channel, char *buffer, int count, int mode)
@@ -769,88 +592,3 @@
 
 	release_dma_lock(flags);
 }
-
-#ifdef CONFIG_PROC_FS
-
-int irda_device_print_flags(struct irda_device *idev, char *buf)
-{
-	int len=0;
-
-	len += sprintf( buf+len, "\t");
-
-	if (idev->netdev.flags & IFF_UP)
-		len += sprintf( buf+len, "UP ");
-	if (!idev->netdev.tbusy)
-		len += sprintf( buf+len, "RUNNING ");
-
-	if (idev->flags & IFF_SIR)
-		len += sprintf( buf+len, "SIR ");
-	if (idev->flags & IFF_MIR)
-		len += sprintf( buf+len, "MIR ");
-	if (idev->flags & IFF_FIR)
-		len += sprintf( buf+len, "FIR ");
-	if (idev->flags & IFF_PIO)
-		len += sprintf( buf+len, "PIO ");
-	if (idev->flags & IFF_DMA)
-		len += sprintf( buf+len, "DMA ");
-	if (idev->flags & IFF_SHM)
-		len += sprintf( buf+len, "SHM ");
-	if (idev->flags & IFF_DONGLE)
-		len += sprintf( buf+len, "DONGLE ");
-
-	len += sprintf( buf+len, "\n");
-
-	return len;
-}
-
-/*
- * Function irda_device_proc_read (buf, start, offset, len, unused)
- *
- *    Give some info to the /proc file system
- *
- */
-int irda_device_proc_read(char *buf, char **start, off_t offset, int len, 
-			  int unused)
-{
-	struct irda_device *self;
-	unsigned long flags;
-     
-	save_flags(flags);
-	cli();
-
-	len = 0;
-
-	self = (struct irda_device *) hashbin_get_first(irda_device);
-	while ( self != NULL) {
-		len += sprintf(buf+len, "\n%s,", self->name);
-		len += sprintf(buf+len, "\tbinding: %s\n", 
-			       self->description);
-		
-		len += irda_device_print_flags(self, buf+len);
-		len += sprintf(buf+len, "\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\n");
-		
-		len += sprintf(buf+len, "\t%d\t", 
-			       self->qos.baud_rate.value);
-		len += sprintf(buf+len, "%d\t", 
-			       self->qos.max_turn_time.value);
-		len += sprintf(buf+len, "%d\t",
-			       self->qos.data_size.value);
-		len += sprintf(buf+len, "%d\t",
-			       self->qos.window_size.value);
-		len += sprintf(buf+len, "%d\t",
-			       self->qos.additional_bofs.value);
-		len += sprintf(buf+len, "%d\t", 
-			       self->qos.min_turn_time.value);
-		len += sprintf(buf+len, "%d", 
-			       self->qos.link_disc_time.value);
-		len += sprintf(buf+len, "\n");
-		
-		self = (struct irda_device *) hashbin_get_next(irda_device);
-	}
-	restore_flags(flags);
-
-	return len;
-}
-
-#endif /* CONFIG_PROC_FS */
-
diff -urN linux-2.2.15-pre2/net/irda/iriap.c linux/net/irda/iriap.c
--- linux-2.2.15-pre2/net/irda/iriap.c	Sun May 30 10:17:03 1999
+++ linux/net/irda/iriap.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Sun May  9 15:59:05 1999
+ * Modified at:   Sat Dec 25 16:42:42 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -28,7 +28,6 @@
 #include <linux/skbuff.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/irda.h>
 
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
@@ -61,8 +60,8 @@
 
 extern char *lmp_reasons[];
 
-static struct iriap_cb *iriap_open( __u8 slsap, int mode);
 static void __iriap_close(struct iriap_cb *self);
+static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode);
 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, 
@@ -82,22 +81,21 @@
  *    Initializes the IrIAP layer, called by the module initialization code
  *    in irmod.c 
  */
-__initfunc(int iriap_init(void))
+int __init iriap_init(void)
 {
-	__u16 hints;
 	struct ias_object *obj;
+	struct iriap_cb *server;
+	__u8 oct_seq[6];
+	__u16 hints;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
-	
 	/* Allocate master array */
-	iriap = hashbin_new( HB_LOCAL);
-	if ( iriap == NULL)
+	iriap = hashbin_new(HB_LOCAL);
+	if (!iriap)
 		return -ENOMEM;
 
-	objects = hashbin_new( HB_LOCAL);
-	if ( objects == NULL) {
-		printk( KERN_WARNING 
-			"IrIAP: Can't allocate objects hashbin!\n");
+	objects = hashbin_new(HB_LOCAL);
+	if (!objects) {
+		WARNING(__FUNCTION__ "(), Can't allocate objects hashbin!\n");
 		return -ENOMEM;
 	}
 
@@ -105,22 +103,32 @@
 	 *  Register some default services for IrLMP 
 	 */
 	hints  = irlmp_service_to_hint(S_COMPUTER);
-	hints |= irlmp_service_to_hint(S_PNP);
 	service_handle = irlmp_register_service(hints);
 
-	/* 
-	 *  Register the Device object with LM-IAS
-	 */
-	obj = irias_new_object( "Device", IAS_DEVICE_ID);
-	irias_add_string_attrib( obj, "DeviceName", "Linux");
-	irias_insert_object( obj);
+	/* Register the Device object with LM-IAS */
+	obj = irias_new_object("Device", IAS_DEVICE_ID);
+	irias_add_string_attrib(obj, "DeviceName", "Linux");
+
+	oct_seq[0] = 0x01;  /* Version 1 */
+	oct_seq[1] = 0x00;  /* IAS support bits */
+	oct_seq[2] = 0x00;  /* LM-MUX support bits */
+#ifdef CONFIG_IRDA_ULTRA
+	oct_seq[2] |= 0x04; /* Connectionless Data support */
+#endif
+	irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3);
+	irias_insert_object(obj);
 
 	/*  
 	 *  Register server support with IrLMP so we can accept incoming 
 	 *  connections 
 	 */
-	iriap_open( LSAP_IAS, IAS_SERVER);
-	
+	server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
+	if (!server) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to open server\n");
+		return -1;
+	}
+	iriap_register_lsap(server, LSAP_IAS, IAS_SERVER);
+
 	return 0;
 }
 
@@ -130,7 +138,7 @@
  *    Initializes the IrIAP layer, called by the module cleanup code in 
  *    irmod.c
  */
-void iriap_cleanup(void) 
+void iriap_cleanup(void)
 {
 	irlmp_unregister_service(service_handle);
 	
@@ -143,57 +151,41 @@
  *
  *    Opens an instance of the IrIAP layer, and registers with IrLMP
  */
-struct iriap_cb *iriap_open( __u8 slsap_sel, int mode)
+struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, 
+			    CONFIRM_CALLBACK callback)
 {
 	struct iriap_cb *self;
-	struct notify_t notify;
-	struct lsap_cb *lsap;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	self = kmalloc( sizeof(struct iriap_cb), GFP_ATOMIC);
-	if ( self == NULL) {
-		DEBUG( 0, "iriap_open(), Unable to kmalloc!\n");
+	self = kmalloc(sizeof(struct iriap_cb), GFP_ATOMIC);
+	if (!self) {
+		WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
 		return NULL;
 	}
 
 	/*
 	 *  Initialize instance
 	 */
-	memset( self, 0, sizeof(struct iriap_cb));
-
-	irda_notify_init( &notify);
-	notify.connect_confirm = iriap_connect_confirm;
-	notify.connect_indication = iriap_connect_indication;
-	notify.disconnect_indication = iriap_disconnect_indication;
-	notify.data_indication = iriap_data_indication;
-	notify.instance = self;
-	if ( mode == IAS_CLIENT)
-		strcpy( notify.name, "IrIAS cli");
-	else
-		strcpy( notify.name, "IrIAS srv");
-
-	lsap = irlmp_open_lsap( slsap_sel, &notify);
-	if ( lsap == NULL) {
-		DEBUG( 0, "iriap_open: Unable to allocated LSAP!\n");
-		return NULL;
-	}
-	slsap_sel = lsap->slsap_sel;
-	DEBUG( 4, __FUNCTION__ "(), source LSAP sel=%02x\n", slsap_sel);
+	memset(self, 0, sizeof(struct iriap_cb));
 	
 	self->magic = IAS_MAGIC;
-	self->lsap = lsap;
-	self->slsap_sel = slsap_sel;
 	self->mode = mode;
+	if (mode == IAS_CLIENT)
+		iriap_register_lsap(self, slsap_sel, mode);
+
+	self->confirm = callback;
+	self->priv = priv;
 
 	init_timer(&self->watchdog_timer);
 
-	hashbin_insert( iriap, (QUEUE*) self, slsap_sel, NULL);
+	hashbin_insert(iriap, (queue_t *) self, (int) self, NULL);
 	
-	iriap_next_client_state( self, S_DISCONNECT);
-	iriap_next_call_state( self, S_MAKE_CALL);
-	iriap_next_server_state( self, R_DISCONNECT);
-	iriap_next_r_connect_state( self, R_WAITING);
+	/* Initialize state machines */
+	iriap_next_client_state(self, S_DISCONNECT);
+	iriap_next_call_state(self, S_MAKE_CALL);
+	iriap_next_server_state(self, R_DISCONNECT);
+	iriap_next_r_connect_state(self, R_WAITING);
 	
 	return self;
 }
@@ -204,18 +196,21 @@
  *    Removes (deallocates) the IrIAP instance
  *
  */
-static void __iriap_close( struct iriap_cb *self)
+static void __iriap_close(struct iriap_cb *self)
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
 	del_timer(&self->watchdog_timer);
 
+	if (self->skb)
+		dev_kfree_skb(self->skb);
+
 	self->magic = 0;
 
-	kfree( self);
+	kfree(self);
 }
 
 /*
@@ -223,25 +218,51 @@
  *
  *    Closes IrIAP and deregisters with IrLMP
  */
-void iriap_close( struct iriap_cb *self)
+void iriap_close(struct iriap_cb *self)
 {
 	struct iriap_cb *entry;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	if ( self->lsap) {
-		irlmp_close_lsap( self->lsap);
+	if (self->lsap) {
+		irlmp_close_lsap(self->lsap);
 		self->lsap = NULL;
 	}
 
-	entry = (struct iriap_cb *) hashbin_remove( iriap, self->slsap_sel, 
-						    NULL);
-	ASSERT( entry == self, return;);
+	entry = (struct iriap_cb *) hashbin_remove(iriap, (int) self, NULL);
+	ASSERT(entry == self, return;);
+
+	__iriap_close(self);
+}
+
+static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
+{
+	notify_t notify;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	irda_notify_init(&notify);
+	notify.connect_confirm       = iriap_connect_confirm;
+	notify.connect_indication    = iriap_connect_indication;
+	notify.disconnect_indication = iriap_disconnect_indication;
+	notify.data_indication       = iriap_data_indication;
+	notify.instance = self;
+	if (mode == IAS_CLIENT)
+		strcpy(notify.name, "IrIAS cli");
+	else
+		strcpy(notify.name, "IrIAS srv");
+
+	self->lsap = irlmp_open_lsap(slsap_sel, &notify, 0);
+	if (self->lsap == NULL) {
+		ERROR(__FUNCTION__ "(), Unable to allocated LSAP!\n");
+		return -1;
+	}
+	self->slsap_sel = self->lsap->slsap_sel;
 
-	__iriap_close( self);
+	return 0;
 }
 
 /*
@@ -250,47 +271,45 @@
  *    Got disconnect, so clean up everything assosiated with this connection
  *
  */
-static void iriap_disconnect_indication( void *instance, void *sap, 
-					 LM_REASON reason, 
-					 struct sk_buff *userdata)
+static void iriap_disconnect_indication(void *instance, void *sap, 
+					LM_REASON reason, 
+					struct sk_buff *userdata)
 {
 	struct iriap_cb *self;
 
-	DEBUG(4, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);
+	IRDA_DEBUG(4, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);
 
 	self = (struct iriap_cb *) instance;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	ASSERT( iriap != NULL, return;);
+	ASSERT(iriap != NULL, return;);
 
 	del_timer(&self->watchdog_timer);
 
-	if ( self->mode == IAS_CLIENT) {
-		DEBUG( 4, __FUNCTION__ "(), disconnect as client\n");
+	if (self->mode == IAS_CLIENT) {
+		IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as client\n");
 
+
+		iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION, 
+				      NULL);
 		/* 
 		 * Inform service user that the request failed by sending 
-		 * it a NULL value.
+		 * it a NULL value. Warning, the client might close us, so
+		 * remember no to use self anymore after calling confirm
 		 */
 		if (self->confirm)
  			self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
-		
-		
-		iriap_do_client_event( self, IAP_LM_DISCONNECT_INDICATION, 
-				       NULL);
-		/* Close instance only if client */
-		iriap_close( self);
-		
 	} else {
-		DEBUG( 4, __FUNCTION__ "(), disconnect as server\n");
-		iriap_do_server_event( self, IAP_LM_DISCONNECT_INDICATION, 
-				       NULL);
+		IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as server\n");
+		iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, 
+				      NULL);
+		iriap_close(self);
 	}
 
 	if (userdata)
-		dev_kfree_skb( userdata);
+		dev_kfree_skb(userdata);
 }
 
 /*
@@ -303,14 +322,14 @@
 {
 	struct sk_buff *skb;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
 
 	skb = dev_alloc_skb(64);
 	if (skb == NULL) {
-		DEBUG(0, __FUNCTION__
+		IRDA_DEBUG(0, __FUNCTION__
 		      "(), Could not allocate an sk_buff of length %d\n", 64);
 		return;
 	}
@@ -325,27 +344,27 @@
 
 void iriap_getinfobasedetails_request(void) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
 }
 
 void iriap_getinfobasedetails_confirm(void) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
 }
 
 void iriap_getobjects_request(void) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
 }
 
 void iriap_getobjects_confirm(void) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
 }
 
 void iriap_getvalue(void) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
 }
 
 /*
@@ -354,26 +373,21 @@
  *    Retreive all values from attribute in all objects with given class
  *    name
  */
-void iriap_getvaluebyclass_request(char *name, char *attr, 
-				   __u32 saddr, __u32 daddr,
-				   CONFIRM_CALLBACK callback, void *priv)
+int iriap_getvaluebyclass_request(struct iriap_cb *self,
+				  __u32 saddr, __u32 daddr, 
+				  char *name, char *attr)
 {
 	struct sk_buff *skb;
-	struct iriap_cb *self;
-	__u8 *frame;
 	int name_len, attr_len;
-	__u8 slsap = LSAP_ANY;  /* Source LSAP to use */
-
-	DEBUG(4, __FUNCTION__ "()\n");
-	
-	self = iriap_open(slsap, IAS_CLIENT);
-	if (!self)
-		return;
+	__u8 *frame;
 
-	self->mode = IAS_CLIENT;
-	self->confirm = callback;
-	self->priv = priv;
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IAS_MAGIC, return -1;);
 
+	/* Client must supply the destination device address */
+	if (!daddr)
+		return -1;
+	
 	self->daddr = daddr;
 	self->saddr = saddr;
 
@@ -387,7 +401,7 @@
 	
 	skb = dev_alloc_skb(64);
 	if (!skb)
-		return;
+		return -ENOMEM;
 
 	name_len = strlen(name);
 	attr_len = strlen(attr);
@@ -405,6 +419,8 @@
 	memcpy(frame+3+name_len, attr, attr_len);  /* Insert attr */
 
 	iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, skb);
+
+	return 0;
 }
 
 /*
@@ -417,7 +433,6 @@
 void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) 
 {
 	struct ias_value *value;
-	int n;
 	int charset;
 	__u32 value_len;
 	__u32 tmp_cpu32;
@@ -425,6 +440,7 @@
 	__u16 len;
 	__u8  type;
 	__u8 *fp;
+	int n;
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
@@ -437,29 +453,27 @@
 	/* Get length, MSB first */
 	len = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2;
 
-	DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
+	IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
 
 	/* Get object ID, MSB first */
 	obj_id = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2;
-/* 	memcpy(&obj_id, fp+n, 2); n += 2; */
-/* 	be16_to_cpus(&obj_id); */
 
 	type = fp[n++];
-	DEBUG( 4, __FUNCTION__ "(), Value type = %d\n", type);
+	IRDA_DEBUG(4, __FUNCTION__ "(), Value type = %d\n", type);
 
-	switch( type) {
+	switch (type) {
 	case IAS_INTEGER:
 		memcpy(&tmp_cpu32, fp+n, 4); n += 4;
 		be32_to_cpus(&tmp_cpu32);
 		value = irias_new_integer_value(tmp_cpu32);
 
 		/*  Legal values restricted to 0x01-0x6f, page 15 irttp */
-		DEBUG( 4, __FUNCTION__ "(), lsap=%d\n", value->t.integer); 
+		IRDA_DEBUG(4, __FUNCTION__ "(), lsap=%d\n", value->t.integer); 
 		break;
 	case IAS_STRING:
 		charset = fp[n++];
 
-		switch(charset) {
+		switch (charset) {
 		case CS_ASCII:
 			break;
 /* 		case CS_ISO_8859_1: */
@@ -473,41 +487,52 @@
 /* 		case CS_ISO_8859_9: */
 /* 		case CS_UNICODE: */
 		default:
-			DEBUG(0, __FUNCTION__"(), charset %s, not supported\n",
-			      ias_charset_types[charset]);
+			IRDA_DEBUG(0, __FUNCTION__
+				   "(), charset %s, not supported\n",
+				   ias_charset_types[charset]);
+
+			/* Aborting, close connection! */
+			iriap_disconnect_request(self);
+			dev_kfree_skb(skb);
 			return;
 			/* break; */
 		}
 		value_len = fp[n++];
-		DEBUG(4, __FUNCTION__ "(), strlen=%d\n", value_len);
-		ASSERT( value_len < 64, return;);
+		IRDA_DEBUG(4, __FUNCTION__ "(), strlen=%d\n", value_len);
+		ASSERT(value_len < 64, return;);
 		
 		/* Make sure the string is null-terminated */
 		fp[n+value_len] = 0x00;
 		
-		DEBUG(4, "Got string %s\n", fp+n);
+		IRDA_DEBUG(4, "Got string %s\n", fp+n);
 		value = irias_new_string_value(fp+n);
 		break;
 	case IAS_OCT_SEQ:
 		value_len = be16_to_cpu(get_unaligned((__u16 *)(fp+n)));
 		n += 2;
 		
-		/* FIXME:should be 1024, but.... */
-		DEBUG(0, __FUNCTION__ "():octet sequence:len=%d\n", value_len);
 		ASSERT(value_len <= 55, return;);      
 		
 		value = irias_new_octseq_value(fp+n, value_len);
 		break;
 	default:
-		value = &missing;
+		value = irias_new_missing_value();
 		break;
 	}
 	
 	/* Finished, close connection! */
 	iriap_disconnect_request(self);
 
+	/* Warning, the client might close us, so remember no to use self
+	 * anymore after calling confirm 
+	 */
 	if (self->confirm)
 		self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
+	else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), missing handler!\n");
+		irias_delete_value(value);
+	}
+	dev_kfree_skb(skb);
 }
 
 /*
@@ -524,22 +549,22 @@
 	__u32 tmp_be32, tmp_be16;
 	__u8 *fp;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
-	ASSERT( value != NULL, return;);
-	ASSERT( value->len <= 1024, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
+	ASSERT(value != NULL, return;);
+	ASSERT(value->len <= 1024, return;);
 
 	/* Initialize variables */
 	n = 0;
 
 	/* 
 	 *  We must adjust the size of the response after the length of the 
-	 *  value. We add 9 bytes because of the 6 bytes for the frame and
-	 *  max 3 bytes for the value coding.
+	 *  value. We add 32 bytes because of the 6 bytes for the frame and
+	 *  max 5 bytes for the value coding.
 	 */
-	skb = dev_alloc_skb(value->len + self->max_header_size + 9);
+	skb = dev_alloc_skb(value->len + self->max_header_size + 32);
 	if (!skb)
 		return;
 
@@ -561,7 +586,7 @@
 	tmp_be16 = cpu_to_be16(obj_id);
 	memcpy(fp+n, &tmp_be16, 2); n += 2;
 
-	switch(value->type) {
+	switch (value->type) {
 	case IAS_STRING:
 		skb_put(skb, 3 + value->len);
 		fp[n++] = value->type;
@@ -585,13 +610,12 @@
 		memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len;
 		break;
 	case IAS_MISSING:
-		DEBUG( 3, __FUNCTION__ ": sending IAS_MISSING\n");
-		skb_put( skb, 1);
+		IRDA_DEBUG( 3, __FUNCTION__ ": sending IAS_MISSING\n");
+		skb_put(skb, 1);
 		fp[n++] = value->type;
 		break;
-
 	default:
-		DEBUG(0, __FUNCTION__ "(), type not implemented!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), type not implemented!\n");
 		break;
 	}
 	iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb);
@@ -606,64 +630,58 @@
 void iriap_getvaluebyclass_indication(struct iriap_cb *self, 
 				      struct sk_buff *skb)
 {
-	__u8 *fp;
-	int n;
+ 	struct ias_object *obj;
+	struct ias_attrib *attrib;
 	int name_len;
 	int attr_len;
 	char name[64];
 	char attr[64];
- 	struct ias_object *obj;
-	struct ias_attrib *attrib;
+	__u8 *fp;
+	int n;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
 
 	fp = skb->data;
 	n = 1;
 
 	name_len = fp[n++];
-	memcpy( name, fp+n, name_len); n+=name_len;
+	memcpy(name, fp+n, name_len); n+=name_len;
 	name[name_len] = '\0';
 
 	attr_len = fp[n++]; 
-	memcpy( attr, fp+n, attr_len); n+=attr_len;
+	memcpy(attr, fp+n, attr_len); n+=attr_len;
 	attr[attr_len] = '\0';
 
-	dev_kfree_skb( skb);
+	/* We do not need the buffer anymore */
+	dev_kfree_skb(skb);
 
-	/* 
-	 *  Now, do some advanced parsing! :-) 
-	 */
-	DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr);
+	IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr);
 	obj = irias_find_object(name);
 	
-	if ( obj == NULL) {
-		DEBUG( 0, "LM-IAS: Object not found\n");
-		iriap_getvaluebyclass_response( self, 0x1235, 
-						IAS_CLASS_UNKNOWN, &missing);
+	if (obj == NULL) {
+		IRDA_DEBUG(2, "LM-IAS: Object %s not found\n", name);
+		iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN,
+					       &missing);
 		return;
 	}
-	DEBUG(4, "LM-IAS: found %s, id=%d\n", obj->name, obj->id);
+	IRDA_DEBUG(4, "LM-IAS: found %s, id=%d\n", obj->name, obj->id);
 	
-	attrib = irias_find_attrib( obj, attr);
-	if ( attrib == NULL) {
-		DEBUG( 0, "LM-IAS: Attribute %s not found\n", attr);
+	attrib = irias_find_attrib(obj, attr);
+	if (attrib == NULL) {
+		IRDA_DEBUG(2, "LM-IAS: Attribute %s not found\n", attr);
 		iriap_getvaluebyclass_response(self, obj->id,
 					       IAS_ATTRIB_UNKNOWN, &missing);
 		return;
 	}
 	
-	DEBUG(4, "LM-IAS: found %s\n", attrib->name);
+	/* We have a match; send the value.  */
+	iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS, 
+				       attrib->value);
 	
-	/*
-	 * We have a match; send the value.
-	 */
-	iriap_getvaluebyclass_response( self, obj->id, IAS_SUCCESS, 
-					attrib->value);
-
 	return;
 }
 
@@ -673,15 +691,15 @@
  *    Currently not used
  *
  */
-void iriap_send_ack( struct iriap_cb *self) 
+void iriap_send_ack(struct iriap_cb *self) 
 {
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	DEBUG( 6, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __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);
 	if (!skb)
@@ -693,7 +711,25 @@
 	frame = skb->data;
 
 	/* Build frame */
-	frame[0] = IAP_LST | self->operation;
+	frame[0] = IAP_LST | IAP_ACK | self->operation;
+
+	irlmp_data_request(self->lsap, skb);
+}
+
+void iriap_connect_request(struct iriap_cb *self)
+{
+	int ret;
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
+
+	ret = irlmp_connect_request(self->lsap, LSAP_IAS, 
+				    self->saddr, self->daddr, 
+				    NULL, NULL);
+	if (ret < 0) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");
+		self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
+	}
 }
 
 /*
@@ -703,8 +739,8 @@
  *
  */
 static void iriap_connect_confirm(void *instance, void *sap, 
-				  struct qos_info *qos, 
-				  __u32 max_sdu_size, __u8 header_size, 
+				  struct qos_info *qos, __u32 max_seg_size, 
+				  __u8 max_header_size, 
 				  struct sk_buff *userdata)
 {
 	struct iriap_cb *self;
@@ -715,7 +751,8 @@
 	ASSERT(self->magic == IAS_MAGIC, return;);
 	ASSERT(userdata != NULL, return;);
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	self->max_data_size = max_seg_size;
+	self->max_header_size = max_header_size;
 	
 	del_timer(&self->watchdog_timer);
 
@@ -729,18 +766,43 @@
  *
  */
 static void iriap_connect_indication(void *instance, void *sap, 
-				     struct qos_info *qos, __u32 max_sdu_size,
-				     __u8 header_size, 
+				     struct qos_info *qos, __u32 max_seg_size,
+				     __u8 max_header_size, 
 				     struct sk_buff *userdata)
 {
-	struct iriap_cb *self;
+	struct iriap_cb *self, *new;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
 	self = (struct iriap_cb *) instance;
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
+	
+	/* Start new server */
+	new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); 
+	if (!new) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), open failed\n");
+		dev_kfree_skb(userdata);
+		return;
+	}
+	
+	/* Now attach up the new "socket" */
+	new->lsap = irlmp_dup(self->lsap, new);
+	if (!new->lsap) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n");
+		return;
+	}
+		
+	new->max_data_size = max_seg_size;
+	new->max_header_size = max_header_size;
 
-	iriap_do_server_event(self, IAP_LM_CONNECT_INDICATION, userdata);
+	/* Clean up the original one to keep it in listen state */
+	self->lsap->dlsap_sel = LSAP_ANY;
+	self->lsap->lsap_state = LSAP_DISCONNECTED;
+	/* FIXME: refcount in irlmp might get wrong */
+	
+	iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, userdata);
 }
  
 /*
@@ -756,7 +818,7 @@
 	__u8  *frame;
 	__u8  opcode;
 	
-	DEBUG( 4, __FUNCTION__ "()\n"); 
+	IRDA_DEBUG(3, __FUNCTION__ "()\n"); 
 	
 	self = (struct iriap_cb *) instance;
 
@@ -769,65 +831,74 @@
 	
 	if (self->mode == IAS_SERVER) {
 		/* Call server */
-		DEBUG(4, __FUNCTION__ "(), Calling server!\n");
-		iriap_do_r_connect_event( self, IAP_RECV_F_LST, skb);
+		IRDA_DEBUG(4, __FUNCTION__ "(), Calling server!\n");
+		iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
 
 		return 0;
 	}
 	opcode = frame[0];
-	if ( ~opcode & 0x80) {
-		printk( KERN_ERR "IrIAS multiframe commands or results is "
-			"not implemented yet!\n");
+	if (~opcode & IAP_LST) {
+		WARNING(__FUNCTION__ "(), IrIAS multiframe commands or "
+			"results is not implemented yet!\n");
+		dev_kfree_skb(skb);
 		return 0;
 	}
-
-	if (~opcode & IAP_ACK) {
-		DEBUG(2, __FUNCTION__ "() Got ack frame!\n");
-	/* 	return; */
+	
+	/* Check for ack frames since they don't contain any data */
+	if (opcode & IAP_ACK) {
+		IRDA_DEBUG(0, __FUNCTION__ "() Got ack frame!\n");
+		dev_kfree_skb(skb);
+	 	return 0;
 	}
 
 	opcode &= ~IAP_LST; /* Mask away LST bit */
-	
-	switch(opcode) {
+
+	switch (opcode) {
 	case GET_INFO_BASE:
-		DEBUG( 0, "IrLMP GetInfoBaseDetails not implemented!\n");
+		IRDA_DEBUG(0, "IrLMP GetInfoBaseDetails not implemented!\n");
+		dev_kfree_skb(skb);
 		break;
 	case GET_VALUE_BY_CLASS:
-		DEBUG( 4,"IrLMP GetValueByClass\n");
-		
-		switch(frame[1]) {
+		iriap_do_call_event(self, IAP_RECV_F_LST, NULL);
+			
+		switch (frame[1]) {
 		case IAS_SUCCESS:
 			iriap_getvaluebyclass_confirm(self, skb);
 			break;
 		case IAS_CLASS_UNKNOWN:
-			printk(KERN_WARNING "IrIAP No such class!\n");
+			WARNING(__FUNCTION__ "(), No such class!\n");
 			/* Finished, close connection! */
 			iriap_disconnect_request(self);
 
+			/* 
+			 * Warning, the client might close us, so remember
+			 * no to use self anymore after calling confirm 
+			 */
 			if (self->confirm)
-				self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, 
+				self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
 					      self->priv);
+			dev_kfree_skb(skb);
 			break;
 		case IAS_ATTRIB_UNKNOWN:
-			printk(KERN_WARNING "IrIAP No such attribute!\n");
+			WARNING(__FUNCTION__ "(), No such attribute!\n");
 		       	/* Finished, close connection! */
 			iriap_disconnect_request(self);
 
+			/* 
+			 * Warning, the client might close us, so remember
+			 * no to use self anymore after calling confirm 
+			 */
 			if (self->confirm)
 				self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, 
 					      self->priv);
+			dev_kfree_skb(skb);
 			break;
-		}
-		iriap_do_call_event( self, IAP_RECV_F_LST, skb);
-
-		/*  
-		 *  We remove LSAPs used by IrIAS as a client since these
-		 *  are more difficult to reuse!  
-		 */
-		iriap_close( self);
+		}		
 		break;
 	default:
-		DEBUG(0, __FUNCTION__ "(), Unknown op-code: %02x\n", opcode);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown op-code: %02x\n", 
+			   opcode);
+		dev_kfree_skb(skb);
 		break;
 	}
 	return 0;
@@ -839,33 +910,34 @@
  *    Received call to server from peer LM-IAS
  *
  */
-void iriap_call_indication( struct iriap_cb *self, struct sk_buff *skb)
+void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb)
 {
 	__u8 *fp;
-	__u8  opcode;
+	__u8 opcode;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
 
 	fp = skb->data;
 
 	opcode = fp[0];
-	if ( ~opcode & 0x80) {
-		printk( KERN_ERR "IrIAS multiframe commands or results is "
-			"not implemented yet!\n");
+	if (~opcode & 0x80) {
+		WARNING(__FUNCTION__ "(), IrIAS multiframe commands or results"
+			"is not implemented yet!\n");
 		return;
 	}
 	opcode &= 0x7f; /* Mask away LST bit */
 	
 	switch (opcode) {
 	case GET_INFO_BASE:
-		DEBUG( 0, "IrLMP GetInfoBaseDetails not implemented!\n");
+		WARNING(__FUNCTION__ 
+			"(), GetInfoBaseDetails not implemented yet!\n");
 		break;
 	case GET_VALUE_BY_CLASS:
-		iriap_getvaluebyclass_indication( self, skb);
+		iriap_getvaluebyclass_indication(self, skb);
 		break;
 	}
 }
@@ -873,18 +945,17 @@
 /*
  * Function iriap_watchdog_timer_expired (data)
  *
- *    
+ *    Query has taken to long time, so abort
  *
  */
-void iriap_watchdog_timer_expired( unsigned long data)
+void iriap_watchdog_timer_expired(void *data)
 {
-	struct iriap_cb *self = ( struct iriap_cb *) data;
+	struct iriap_cb *self = (struct iriap_cb *) data;
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	DEBUG(0, __FUNCTION__ "() Timeout! closing myself!\n");
-	iriap_close( self);
+	/* iriap_close(self); */
 }
 
 #ifdef CONFIG_PROC_FS
@@ -909,56 +980,56 @@
 
 	len = 0;
 
-	len += sprintf( buf+len, "LM-IAS Objects:\n");
+	len += sprintf(buf+len, "LM-IAS Objects:\n");
 
 	/* List all objects */
-	obj = (struct ias_object *) hashbin_get_first( objects);
+	obj = (struct ias_object *) hashbin_get_first(objects);
 	while ( obj != NULL) {
-		ASSERT( obj->magic == IAS_OBJECT_MAGIC, return 0;);
+		ASSERT(obj->magic == IAS_OBJECT_MAGIC, return 0;);
 
-		len += sprintf( buf+len, "name: %s, ", obj->name);
-		len += sprintf( buf+len, "id=%d", obj->id);
-		len += sprintf( buf+len, "\n");
+		len += sprintf(buf+len, "name: %s, ", obj->name);
+		len += sprintf(buf+len, "id=%d", obj->id);
+		len += sprintf(buf+len, "\n");
 
 		/* List all attributes for this object */
 		attrib = (struct ias_attrib *) 
-			hashbin_get_first( obj->attribs);
-		while ( attrib != NULL) {
-			ASSERT( attrib->magic == IAS_ATTRIB_MAGIC, return 0;);
-
-			len += sprintf( buf+len, " - Attribute name: \"%s\", ",
- 					attrib->name);
-			len += sprintf( buf+len, "value[%s]: ", 
-					ias_value_types[ attrib->value->type]);
+			hashbin_get_first(obj->attribs);
+		while (attrib != NULL) {
+			ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return 0;);
+
+			len += sprintf(buf+len, " - Attribute name: \"%s\", ",
+				       attrib->name);
+			len += sprintf(buf+len, "value[%s]: ", 
+				       ias_value_types[attrib->value->type]);
 			
-			switch( attrib->value->type) {
+			switch (attrib->value->type) {
 			case IAS_INTEGER:
-				len += sprintf( buf+len, "%d\n", 
-						attrib->value->t.integer);
+				len += sprintf(buf+len, "%d\n", 
+					       attrib->value->t.integer);
 				break;
 			case IAS_STRING:
-				len += sprintf( buf+len, "\"%s\"\n", 
-						attrib->value->t.string);
+				len += sprintf(buf+len, "\"%s\"\n", 
+					       attrib->value->t.string);
 				break;
 			case IAS_OCT_SEQ:
-				len += sprintf( buf+len, "octet sequence\n");
+				len += sprintf(buf+len, "octet sequence\n");
 				break;
 			case IAS_MISSING:
-				len += sprintf( buf+len, "missing\n");
+				len += sprintf(buf+len, "missing\n");
 				break;
 			default:
-				DEBUG( 0, __FUNCTION__ 
-				       "(), Unknown value type!\n");
+				IRDA_DEBUG(0, __FUNCTION__ 
+				      "(), Unknown value type!\n");
 				return -1;
 			}
-			len += sprintf( buf+len, "\n");
+			len += sprintf(buf+len, "\n");
 			
 			attrib = (struct ias_attrib *) 
 				hashbin_get_next(obj->attribs);
 		}
-	        obj = ( struct ias_object *) hashbin_get_next( objects);
+	        obj = (struct ias_object *) hashbin_get_next(objects);
  	} 
-	restore_flags( flags);
+	restore_flags(flags);
 
 	return len;
 }
diff -urN linux-2.2.15-pre2/net/irda/iriap_event.c linux/net/irda/iriap_event.c
--- linux-2.2.15-pre2/net/irda/iriap_event.c	Sun May 30 10:17:03 1999
+++ linux/net/irda/iriap_event.c	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Sun May  9 11:01:47 1999
+ * Modified at:   Sat Dec 25 21:09:47 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997, 1999 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 
@@ -27,43 +28,43 @@
 #include <net/irda/iriap.h>
 #include <net/irda/iriap_event.h>
 
-static void state_s_disconnect   ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_s_connecting   ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_s_call         ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-
-static void state_s_make_call    ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_s_calling      ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_s_outstanding  ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_s_replying     ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_s_wait_for_call( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_s_wait_active  ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-
-static void state_r_disconnect   ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_r_call         ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_r_waiting      ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_r_wait_active  ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_r_receiving    ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_r_execute      ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
-static void state_r_returning    ( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb);
+static void state_s_disconnect   (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_s_connecting   (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_s_call         (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+
+static void state_s_make_call    (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_s_calling      (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_s_outstanding  (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_s_replying     (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_s_wait_active  (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+
+static void state_r_disconnect   (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_r_call         (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_r_waiting      (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_r_wait_active  (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_r_receiving    (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_r_execute      (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
+static void state_r_returning    (struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb);
 
-static void (*iriap_state[])( struct iriap_cb *self, IRIAP_EVENT event, 
-			      struct sk_buff *skb) = { 
+static void (*iriap_state[])(struct iriap_cb *self, IRIAP_EVENT event, 
+			     struct sk_buff *skb) = { 
 	/* Client FSM */
 	state_s_disconnect,
 	state_s_connecting,
@@ -89,89 +90,72 @@
 	state_r_returning,
 };
 
-void iriap_next_client_state( struct iriap_cb *self, IRIAP_STATE state) 
+void iriap_next_client_state(struct iriap_cb *self, IRIAP_STATE state) 
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
- 	switch ( state) { 
- /* 	case S_DISCONNECT: DEBUG( 0, "IAP Client = S_DISCONNECT\n"); break;  */
-/*  	case S_CONNECTING: DEBUG( 0, "IAP Client = S_CONNECTING\n"); break;  */
-/*  	case S_CALL:       DEBUG( 0, "IAP Client = S_CALL\n");       break;  */
- 	default: 
- 		break; 
- 	} 
 	self->client_state = state;
 }
 
-void iriap_next_call_state( struct iriap_cb *self, IRIAP_STATE state) 
+void iriap_next_call_state(struct iriap_cb *self, IRIAP_STATE state) 
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-/* 	switch ( state) { */
-/* 	case S_MAKE_CALL:     DEBUG( 0, "IAP Call = S_MAKE_CALL\n"); break; */
-/* 	case S_CALLING:       DEBUG( 0, "IAP Call = S_CALLING\n"); break; */
-/* 	case S_OUTSTANDING:   DEBUG( 0, "IAP Call = S_OUTSTANDING\n");break; */
-/* 	case S_REPLYING:      DEBUG( 0, "IAP Call = S_REPLYING\n"); break; */
-/* 	case S_WAIT_FOR_CALL: DEBUG( 0, "IAP Call = S_WAIT_FOR_CALL\n"); break; */
-/* 	case S_WAIT_ACTIVE:   DEBUG( 0, "IAP Call = S_WAIT_ACTIVE\n"); break; */
-/* 	default: */
-/* 		break; */
-/* 	} */
 	self->call_state = state;
 }
 
-void iriap_next_server_state( struct iriap_cb *self, IRIAP_STATE state)
+void iriap_next_server_state(struct iriap_cb *self, IRIAP_STATE state)
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
 	self->server_state = state;
 }
 
-void iriap_next_r_connect_state( struct iriap_cb *self, IRIAP_STATE state)
+void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state)
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 	
 	self->r_connect_state = state;
 }
 
-void iriap_do_client_event( struct iriap_cb *self, IRIAP_EVENT event, 
-			    struct sk_buff *skb) 
+void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event, 
+			   struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	(*iriap_state[ self->client_state]) ( self, event, skb);
+	(*iriap_state[ self->client_state]) (self, event, skb);
 }
 
-void iriap_do_call_event( struct iriap_cb *self, IRIAP_EVENT event, 
-			  struct sk_buff *skb) 
+void iriap_do_call_event(struct iriap_cb *self, IRIAP_EVENT event, 
+			 struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 	
-	(*iriap_state[ self->call_state]) ( self, event, skb);
+	(*iriap_state[ self->call_state]) (self, event, skb);
 }
 
-void iriap_do_server_event( struct iriap_cb *self, IRIAP_EVENT event, 
-			    struct sk_buff *skb) 
+void iriap_do_server_event(struct iriap_cb *self, IRIAP_EVENT event, 
+			   struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 	
-	(*iriap_state[ self->server_state]) ( self, event, skb);
+	(*iriap_state[ self->server_state]) (self, event, skb);
 }
 
-void iriap_do_r_connect_event( struct iriap_cb *self, IRIAP_EVENT event, 
-			       struct sk_buff *skb) 
+void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event, 
+			      struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 	
-	(*iriap_state[ self->r_connect_state]) ( self, event, skb);
+	(*iriap_state[ self->r_connect_state]) (self, event, skb);
 }
 
 
@@ -181,26 +165,23 @@
  *    S-Disconnect, The device has no LSAP connection to a particular
  *    remote device.
  */
-static void state_s_disconnect( struct iriap_cb *self, IRIAP_EVENT event, 
-				struct sk_buff *skb) 
+static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event, 
+			       struct sk_buff *skb) 
 {
-	int ret;
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
-
-	switch( event) {
+	switch (event) {
 	case IAP_CALL_REQUEST_GVBC:
-		iriap_next_client_state( self, S_CONNECTING);
+		iriap_next_client_state(self, S_CONNECTING);
+		ASSERT(self->skb == NULL, return;);
 		self->skb = skb;
-		ret = irlmp_connect_request( self->lsap, LSAP_IAS, 
-					     self->saddr, self->daddr, 
-					     NULL, NULL);
+		iriap_connect_request(self);
 		break;
 	case IAP_LM_DISCONNECT_INDICATION:
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__"(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__"(), Unknown event %d\n", event);
 		break;
 	}
 }
@@ -211,28 +192,28 @@
  *    S-Connecting
  *
  */
-static void state_s_connecting( struct iriap_cb *self, IRIAP_EVENT event, 
-				struct sk_buff *skb) 
+static void state_s_connecting(struct iriap_cb *self, IRIAP_EVENT event, 
+			       struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	switch( event) {
+	switch (event) {
 	case IAP_LM_CONNECT_CONFIRM:
 		/*
 		 *  Jump to S-Call FSM
 		 */
-		iriap_do_call_event( self, IAP_CALL_REQUEST, skb);
-		/* iriap_call_request( self, 0,0,0); */
-		iriap_next_client_state( self, S_CALL);
+		iriap_do_call_event(self, IAP_CALL_REQUEST, skb);
+		/* iriap_call_request(self, 0,0,0); */
+		iriap_next_client_state(self, S_CALL);
 		break;
 	case IAP_LM_DISCONNECT_INDICATION:
 		/* Abort calls */
-		iriap_next_call_state( self, S_MAKE_CALL);
-		iriap_next_client_state( self, S_DISCONNECT);
+		iriap_next_call_state(self, S_MAKE_CALL);
+		iriap_next_client_state(self, S_DISCONNECT);
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 }
@@ -244,19 +225,19 @@
  *    device. Whenever the LSAP connection is disconnected, this state
  *    catches that event and clears up 
  */
-static void state_s_call( struct iriap_cb *self, IRIAP_EVENT event, 
-			  struct sk_buff *skb) 
+static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event, 
+			 struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
+	ASSERT(self != NULL, return;);
 
-	switch( event) {
+	switch (event) {
 	case IAP_LM_DISCONNECT_INDICATION:
 		/* Abort calls */
-		iriap_next_call_state( self, S_MAKE_CALL);
-		iriap_next_client_state( self, S_DISCONNECT);
+		iriap_next_call_state(self, S_MAKE_CALL);
+		iriap_next_client_state(self, S_DISCONNECT);
 		break;
 	default:
-		DEBUG( 0, "state_s_call: Unknown event %d\n", event);
+		IRDA_DEBUG(0, "state_s_call: Unknown event %d\n", event);
 		break;
 	}
 }
@@ -267,23 +248,25 @@
  *    S-Make-Call
  *
  */
-static void state_s_make_call( struct iriap_cb *self, IRIAP_EVENT event, 
-			       struct sk_buff *skb) 
+static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event, 
+			      struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
+	ASSERT(self != NULL, return;);
 
-	switch( event) {
+	switch (event) {
 	case IAP_CALL_REQUEST:
-		irlmp_data_request( self->lsap, self->skb);
-		iriap_next_call_state( self, S_OUTSTANDING);
+		skb = self->skb;
+		self->skb = NULL;
+		
+		irlmp_data_request(self->lsap, skb);
+		iriap_next_call_state(self, S_OUTSTANDING);
 		break;
 	default:
-		DEBUG( 0, "state_s_make_call: Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
+		if (skb)
+			dev_kfree_skb(skb);
 		break;
 	}
-	if ( skb) {
-		dev_kfree_skb( skb);
-	}
 }
 
 /*
@@ -292,10 +275,10 @@
  *    S-Calling
  *
  */
-static void state_s_calling( struct iriap_cb *self, IRIAP_EVENT event, 
-			     struct sk_buff *skb) 
+static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event, 
+			    struct sk_buff *skb) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
 }
 
 /*
@@ -304,21 +287,20 @@
  *    S-Outstanding, The device is waiting for a response to a command
  *
  */
-static void state_s_outstanding( struct iriap_cb *self, IRIAP_EVENT event, 
-				 struct sk_buff *skb) 
+static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event, 
+				struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
+	ASSERT(self != NULL, return;);
 
-	switch( event) {
+	switch (event) {
 	case IAP_RECV_F_LST:
-		iriap_send_ack( self);
+		iriap_send_ack(self);
 		/*LM_Idle_request(idle); */
 
-		dev_kfree_skb( skb);
-		iriap_next_call_state( self, S_WAIT_FOR_CALL);
+		iriap_next_call_state(self, S_WAIT_FOR_CALL);
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}		
 }
@@ -328,10 +310,10 @@
  *
  *    S-Replying, The device is collecting a multiple part response
  */
-static void state_s_replying( struct iriap_cb *self, IRIAP_EVENT event, 
-			      struct sk_buff *skb) 
+static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event, 
+			     struct sk_buff *skb) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
 }
 
 /*
@@ -340,10 +322,10 @@
  *    S-Wait-for-Call
  *
  */
-static void state_s_wait_for_call( struct iriap_cb *self, IRIAP_EVENT event, 
-				   struct sk_buff *skb) 
+static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, 
+				  struct sk_buff *skb) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
 }
 
 
@@ -353,10 +335,10 @@
  *    S-Wait-Active
  *
  */
-static void state_s_wait_active( struct iriap_cb *self, IRIAP_EVENT event, 
-				 struct sk_buff *skb) 
+static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event, 
+				struct sk_buff *skb) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
 }
 
 /**************************************************************************
@@ -371,18 +353,16 @@
  *    LM-IAS server is disconnected (not processing any requests!)
  *
  */
-static void state_r_disconnect( struct iriap_cb *self, IRIAP_EVENT event, 
-				struct sk_buff *skb) 
+static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, 
+			       struct sk_buff *skb) 
 {
 	struct sk_buff *tx_skb;
 	
-	switch( event) {
+	switch (event) {
 	case IAP_LM_CONNECT_INDICATION:
-		tx_skb = dev_alloc_skb( 64);
-		if ( tx_skb == NULL) {
-			DEBUG( 0,"state_r_disconnect: "
-			       "Could not allocate an sk_buff of length %d\n",
-			       64);
+		tx_skb = dev_alloc_skb(64);
+		if (tx_skb == NULL) {
+			WARNING(__FUNCTION__ "(), unable to malloc!\n");
 			return;
 		}
 
@@ -392,20 +372,20 @@
 		irlmp_connect_response(self->lsap, tx_skb);
 		/*LM_Idle_request(idle); */
 		
-		iriap_next_server_state( self, R_CALL);
+		iriap_next_server_state(self, R_CALL);
 		
 		/*
 		 *  Jump to R-Connect FSM, we skip R-Waiting since we do not
 		 *  care about LM_Idle_request()!
 		 */
-		iriap_next_r_connect_state( self, R_RECEIVING);
+		iriap_next_r_connect_state(self, R_RECEIVING);
 
 		if (skb)
-			dev_kfree_skb( skb);
+			dev_kfree_skb(skb);
 		
 		break;
 	default:
-		DEBUG( 0, "state_r_disconnect: Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event %d\n", event);
 		break;
 	}		
 }
@@ -416,20 +396,19 @@
  *    
  *
  */
-static void state_r_call( struct iriap_cb *self, IRIAP_EVENT event, 
-			  struct sk_buff *skb) 
+static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, 
+			 struct sk_buff *skb) 
 {
-	DEBUG( 4, "state_r_call()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	switch( event) {
+	switch (event) {
 	case IAP_LM_DISCONNECT_INDICATION:
 		/* Abort call */
-		iriap_next_server_state( self, R_DISCONNECT);
-		iriap_next_r_connect_state( self, R_WAITING);
-		
+		iriap_next_server_state(self, R_DISCONNECT);
+		iriap_next_r_connect_state(self, R_WAITING);		
 		break;
 	default:
-		DEBUG( 0, "state_r_call, unknown event!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n");
 		break;
 	}
 }
@@ -444,16 +423,16 @@
  *    
  *
  */
-static void state_r_waiting( struct iriap_cb *self, IRIAP_EVENT event, 
-			     struct sk_buff *skb) 
+static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event, 
+			    struct sk_buff *skb) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
 }
 
-static void state_r_wait_active( struct iriap_cb *self, 
-				 IRIAP_EVENT event, struct sk_buff *skb) 
+static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, 
+				struct sk_buff *skb) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
 }
 
 /*
@@ -462,19 +441,19 @@
  *    We are receiving a command
  *
  */
-static void state_r_receiving( struct iriap_cb *self, IRIAP_EVENT event, 
-			       struct sk_buff *skb) 
+static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, 
+			      struct sk_buff *skb) 
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	switch( event) {
+	switch (event) {
 	case IAP_RECV_F_LST:
-		iriap_next_r_connect_state( self, R_EXECUTE);
+		iriap_next_r_connect_state(self, R_EXECUTE);
 	 		
-		iriap_call_indication( self, skb);
+		iriap_call_indication(self, skb);
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), unknown event!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n");
 		break;
 	}
 
@@ -486,40 +465,40 @@
  *    The server is processing the request
  *
  */
-static void state_r_execute( struct iriap_cb *self, IRIAP_EVENT event, 
-			     struct sk_buff *skb) 
+static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, 
+			    struct sk_buff *skb) 
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( skb != NULL, return;);
+	ASSERT(skb != NULL, return;);
 	
-	if ( !self || self->magic != IAS_MAGIC) {
-		DEBUG( 0, "state_r_execute: bad pointer self\n");
+	if (!self || self->magic != IAS_MAGIC) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), bad pointer self\n");
 		return;
 	}	
 
-	switch( event) {
+	switch (event) {
 	case IAP_CALL_RESPONSE:
 		/*  
 		 *  Since we don't implement the Waiting state, we return
 		 *  to state Receiving instead, DB.
 		 */
-		iriap_next_r_connect_state( self, R_RECEIVING);
+		iriap_next_r_connect_state(self, R_RECEIVING);
 	 		
-		irlmp_data_request( self->lsap, skb);
+		irlmp_data_request(self->lsap, skb);
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), unknown event!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n");
 		break;
 	}
 }
 
-static void state_r_returning( struct iriap_cb *self, IRIAP_EVENT event, 
-			       struct sk_buff *skb) 
+static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event, 
+			      struct sk_buff *skb) 
 {
-	DEBUG( 0, __FUNCTION__ "(), event=%d\n", event);
+	IRDA_DEBUG(0, __FUNCTION__ "(), event=%d\n", event);
 
-	switch( event) {
+	switch (event) {
 	case IAP_RECV_F_LST:
 		
 		break;
diff -urN linux-2.2.15-pre2/net/irda/irias_object.c linux/net/irda/irias_object.c
--- linux-2.2.15-pre2/net/irda/irias_object.c	Thu Apr 15 05:42:42 1999
+++ linux/net/irda/irias_object.c	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct  1 22:50:04 1998
- * Modified at:   Mon Mar 22 13:22:35 1999
+ * Modified at:   Wed Dec 15 11:23:16 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 
@@ -24,7 +24,6 @@
 
 #include <linux/string.h>
 #include <linux/socket.h>
-#include <linux/irda.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
@@ -35,9 +34,7 @@
 /*
  *  Used when a missing value needs to be returned
  */
-struct ias_value missing = {
-        IAS_MISSING,	0,	0,	{ 0 }
-};
+struct ias_value missing = { IAS_MISSING, 0, 0, {0}};
 
 /*
  * Function strdup (str)
@@ -45,20 +42,20 @@
  *    My own kernel version of strdup!
  *
  */
-char *strdup( char *str)
+char *strdup(char *str)
 {
 	char *new_str;
 	
-	if ( str == NULL)
+	if (str == NULL)
 		return NULL;
 
-	ASSERT( strlen( str) < 64, return NULL;);
+	ASSERT(strlen( str) < 64, return NULL;);
 	
-        new_str = kmalloc( strlen( str)+1, GFP_ATOMIC);
-        if ( new_str == NULL)
+        new_str = kmalloc(strlen(str)+1, GFP_ATOMIC);
+        if (new_str == NULL)
 		return NULL;
 	
-	strcpy( new_str, str);
+	strcpy(new_str, str);
 	
 	return new_str;
 }
@@ -73,21 +70,21 @@
 {
         struct ias_object *obj;
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
-	obj = (struct ias_object *) kmalloc( sizeof( struct ias_object), 
-					     GFP_ATOMIC);
-	if ( obj == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Unable to allocate object!\n");
+	obj = (struct ias_object *) kmalloc(sizeof(struct ias_object), 
+					    GFP_ATOMIC);
+	if (obj == NULL) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unable to allocate object!\n");
 		return NULL;
 	}
-	memset( obj, 0, sizeof( struct ias_object));
+	memset(obj, 0, sizeof( struct ias_object));
 
 	obj->magic = IAS_OBJECT_MAGIC;
 	obj->name = strdup( name);
 	obj->id = id;
 
-	obj->attribs = hashbin_new( HB_LOCAL);
+	obj->attribs = hashbin_new(HB_LOCAL);
 	
 	return obj;
 }
@@ -98,59 +95,56 @@
  *    Delete given attribute and deallocate all its memory
  *
  */
-void __irias_delete_attrib( struct ias_attrib *attrib)
+void __irias_delete_attrib(struct ias_attrib *attrib)
 {
-	ASSERT( attrib != NULL, return;);
-	ASSERT( attrib->magic == IAS_ATTRIB_MAGIC, return;);
+	ASSERT(attrib != NULL, return;);
+	ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
 
-	if ( attrib->name)
-		kfree( attrib->name);
+	if (attrib->name)
+		kfree(attrib->name);
 
-	irias_delete_value( attrib->value);
+	irias_delete_value(attrib->value);
 	attrib->magic = ~IAS_ATTRIB_MAGIC;
 	
-	kfree( attrib);
+	kfree(attrib);
 }
 
-/*
- * Function irias_delete_object (obj)
- *
- *    Remove object from hashbin and deallocate all attributes assosiated with
- *    with this object and the object itself
- *
- */
-void __irias_delete_object( struct ias_object *obj) 
+void __irias_delete_object(struct ias_object *obj)
 {
-	ASSERT( obj != NULL, return;);
-	ASSERT( obj->magic == IAS_OBJECT_MAGIC, return;);
-	
-	if ( obj->name)
-		kfree( obj->name);
+	ASSERT(obj != NULL, return;);
+	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
+
+	if (obj->name)
+		kfree(obj->name);
 	
-	hashbin_delete( obj->attribs, (FREE_FUNC) __irias_delete_attrib);
+	hashbin_delete(obj->attribs, (FREE_FUNC) __irias_delete_attrib);
 	
 	obj->magic = ~IAS_OBJECT_MAGIC;
 	
-	kfree( obj);
+	kfree(obj);
 }
 
 /*
- * Function irias_remove_object (obj)
+ * Function irias_delete_object (obj)
  *
- *    Remove object with give name from the LM-IAS object database
+ *    Remove object from hashbin and deallocate all attributes assosiated with
+ *    with this object and the object itself
  *
  */
-void irias_delete_object( char *obj_name)
+int irias_delete_object(struct ias_object *obj) 
 {
-	struct ias_object *obj;
+	struct ias_object *node;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	ASSERT(obj != NULL, return -1;);
+	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
 
-	ASSERT( obj_name != NULL, return;);
+	node = hashbin_remove(objects, 0, obj->name);
+	if (!node)
+		return 0; /* Already removed */
 
-	obj = hashbin_remove( objects, 0, obj_name);
+	__irias_delete_object(node);
 
-	__irias_delete_object( obj);
+	return 0;
 }
 
 /*
@@ -159,14 +153,12 @@
  *    Insert an object into the LM-IAS database
  *
  */
-void irias_insert_object( struct ias_object *obj)
+void irias_insert_object(struct ias_object *obj)
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
-	
-	ASSERT( obj != NULL, return;);
-	ASSERT( obj->magic == IAS_OBJECT_MAGIC, return;);
+	ASSERT(obj != NULL, return;);
+	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 	
-	hashbin_insert( objects, (QUEUE *) obj, 0, obj->name);
+	hashbin_insert(objects, (queue_t *) obj, 0, obj->name);
 }
 
 /*
@@ -175,11 +167,11 @@
  *    Find object with given name
  *
  */
-struct ias_object *irias_find_object( char *name)
+struct ias_object *irias_find_object(char *name)
 {
-	ASSERT( name != NULL, return NULL;);
+	ASSERT(name != NULL, return NULL;);
 
-	return hashbin_find( objects, 0, name);
+	return hashbin_find(objects, 0, name);
 }
 
 /*
@@ -188,18 +180,16 @@
  *    Find named attribute in object
  *
  */
-struct ias_attrib *irias_find_attrib( struct ias_object *obj, char *name)
+struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name)
 {
 	struct ias_attrib *attrib;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	ASSERT(obj != NULL, return NULL;);
+	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;);
+	ASSERT(name != NULL, return NULL;);
 
-	ASSERT( obj != NULL, return NULL;);
-	ASSERT( obj->magic == IAS_OBJECT_MAGIC, return NULL;);
-	ASSERT( name != NULL, return NULL;);
-
-	attrib = hashbin_find( obj->attribs, 0, name);
-	if ( attrib == NULL)
+	attrib = hashbin_find(obj->attribs, 0, name);
+	if (attrib == NULL)
 		return NULL;
 
 	return attrib;
@@ -213,15 +203,13 @@
  */
 void irias_add_attrib( struct ias_object *obj, struct ias_attrib *attrib)
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
-	
-	ASSERT( obj != NULL, return;);
-	ASSERT( obj->magic == IAS_OBJECT_MAGIC, return;);
+	ASSERT(obj != NULL, return;);
+	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 	
-	ASSERT( attrib != NULL, return;);
-	ASSERT( attrib->magic == IAS_ATTRIB_MAGIC, return;);
+	ASSERT(attrib != NULL, return;);
+	ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
 
-	hashbin_insert( obj->attribs, (QUEUE *) attrib, 0, attrib->name);
+	hashbin_insert(obj->attribs, (queue_t *) attrib, 0, attrib->name);
 }
 
 /*
@@ -230,36 +218,36 @@
  *    Change the value of an objects attribute.
  *
  */
-int irias_object_change_attribute( char *obj_name, char *attrib_name, 
-				   struct ias_value *new_value) 
+int irias_object_change_attribute(char *obj_name, char *attrib_name, 
+				  struct ias_value *new_value) 
 {
 	struct ias_object *obj;
 	struct ias_attrib *attrib;
 
 	/* Find object */
-	obj = hashbin_find( objects, 0, obj_name);
-	if ( obj == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Unable to find object: %s\n",
-		       obj_name);
+	obj = hashbin_find(objects, 0, obj_name);
+	if (obj == NULL) {
+		WARNING(__FUNCTION__ "(), Unable to find object: %s\n",
+			obj_name);
 		return -1;
 	}
 
 	/* Find attribute */
-	attrib = hashbin_find( obj->attribs, 0, attrib_name);
-	if ( attrib == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Unable to find attribute: %s\n",
-		       attrib_name);
+	attrib = hashbin_find(obj->attribs, 0, attrib_name);
+	if (attrib == NULL) {
+		WARNING(__FUNCTION__ "(), Unable to find attribute: %s\n",
+			attrib_name);
 		return -1;
 	}
-
+	
 	if ( attrib->value->type != new_value->type) {
-		DEBUG( 0, __FUNCTION__ 
+		IRDA_DEBUG( 0, __FUNCTION__ 
 		       "(), changing value type not allowed!\n");
 		return -1;
 	}
 
 	/* Delete old value */
-	irias_delete_value( attrib->value);
+	irias_delete_value(attrib->value);
 	
 	/* Insert new value */
 	attrib->value = new_value;
@@ -274,33 +262,29 @@
  *    Add an integer attribute to an LM-IAS object
  *
  */
-void irias_add_integer_attrib( struct ias_object *obj, char *name, int value)
+void irias_add_integer_attrib(struct ias_object *obj, char *name, int value)
 {
 	struct ias_attrib *attrib;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	ASSERT( obj != NULL, return;);
-	ASSERT( obj->magic == IAS_OBJECT_MAGIC, return;);
-	ASSERT( name != NULL, return;);
-	
-	attrib = (struct ias_attrib *) kmalloc( sizeof( struct ias_attrib), 
-						GFP_ATOMIC);
-	if ( attrib == NULL) {
-		DEBUG( 0, __FUNCTION__ 
-		       "(), Unable to allocate attribute!\n");
+	ASSERT(obj != NULL, return;);
+	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
+	ASSERT(name != NULL, return;);
+	
+	attrib = (struct ias_attrib *) kmalloc(sizeof(struct ias_attrib), 
+					       GFP_ATOMIC);
+	if (attrib == NULL) {
+		WARNING(__FUNCTION__ "(), Unable to allocate attribute!\n");
 		return;
 	}
-	memset( attrib, 0, sizeof( struct ias_attrib));
+	memset(attrib, 0, sizeof( struct ias_attrib));
 
 	attrib->magic = IAS_ATTRIB_MAGIC;
-	attrib->name = strdup( name);
-/* 	attrib->attr = NULL; */
+	attrib->name = strdup(name);
 
 	/* Insert value */
-	attrib->value = irias_new_integer_value( value);
+	attrib->value = irias_new_integer_value(value);
 	
-	irias_add_attrib( obj, attrib);
+	irias_add_attrib(obj, attrib);
 }
 
  /*
@@ -310,38 +294,32 @@
  *
  */
 
-void irias_add_octseq_attrib( struct ias_object *obj, char *name, 
-			      __u8 *octets, int len)
+void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
+			     int len)
 {
 	struct ias_attrib *attrib;
 	
-	DEBUG( 0, __FUNCTION__ "()\n");
-	
-	DEBUG( 0, __FUNCTION__ ": name=%s\n", name);
-	DEBUG( 0, __FUNCTION__ ": len=%d\n", len);
+	ASSERT(obj != NULL, return;);
+	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 	
-	ASSERT( obj != NULL, return;);
-	ASSERT( obj->magic == IAS_OBJECT_MAGIC, return;);
+	ASSERT(name != NULL, return;);
+	ASSERT(octets != NULL, return;);
 	
-	ASSERT( name != NULL, return;);
-	ASSERT( octets != NULL, return;);
-	ASSERT( len < 55, return;);          /* FIXME: must be 1024, but... */
-	
-	attrib = (struct ias_attrib *) kmalloc( sizeof( struct ias_attrib), 
-						GFP_ATOMIC);
-	if ( attrib == NULL) {
-		DEBUG( 0, __FUNCTION__ 
-		       "(), Unable to allocate attribute!\n");
+	attrib = (struct ias_attrib *) kmalloc(sizeof(struct ias_attrib), 
+					       GFP_ATOMIC);
+	if (attrib == NULL) {
+		WARNING(__FUNCTION__ 
+			"(), Unable to allocate attribute!\n");
 		return;
 	}
-	memset( attrib, 0, sizeof( struct ias_attrib));
+	memset(attrib, 0, sizeof( struct ias_attrib));
 	
 	attrib->magic = IAS_ATTRIB_MAGIC;
 	attrib->name = strdup( name);
 	
 	attrib->value = irias_new_octseq_value( octets, len);
 	
-	irias_add_attrib( obj, attrib);
+	irias_add_attrib(obj, attrib);
 }
 
 /*
@@ -350,36 +328,30 @@
  *    Add a string attribute to an LM-IAS object
  *
  */
-void irias_add_string_attrib( struct ias_object *obj, char *name, char *value)
+void irias_add_string_attrib(struct ias_object *obj, char *name, char *value)
 {
 	struct ias_attrib *attrib;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	ASSERT(obj != NULL, return;);
+	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 
-	DEBUG( 4, __FUNCTION__ ": name=%s\n", name);
-	DEBUG( 4, __FUNCTION__ ": name=%s\n", value);
+	ASSERT(name != NULL, return;);
+	ASSERT(value != NULL, return;);
 	
-	ASSERT( obj != NULL, return;);
-	ASSERT( obj->magic == IAS_OBJECT_MAGIC, return;);
-
-	ASSERT( name != NULL, return;);
-	ASSERT( value != NULL, return;);
-	
-	attrib = (struct ias_attrib *) kmalloc( sizeof( struct ias_attrib), 
-						GFP_ATOMIC);
-	if ( attrib == NULL) {
-		DEBUG( 0, __FUNCTION__ 
-		       "(), Unable to allocate attribute!\n");
+	attrib = (struct ias_attrib *) kmalloc(sizeof( struct ias_attrib), 
+					       GFP_ATOMIC);
+	if (attrib == NULL) {
+		WARNING(__FUNCTION__ "(), Unable to allocate attribute!\n");
 		return;
 	}
-	memset( attrib, 0, sizeof( struct ias_attrib));
+	memset(attrib, 0, sizeof( struct ias_attrib));
 
 	attrib->magic = IAS_ATTRIB_MAGIC;
-	attrib->name = strdup( name);
+	attrib->name = strdup(name);
 
-	attrib->value = irias_new_string_value( value);
+	attrib->value = irias_new_string_value(value);
 
-	irias_add_attrib( obj, attrib);
+	irias_add_attrib(obj, attrib);
 }
 
 /*
@@ -388,16 +360,16 @@
  *    Create new IAS integer value
  *
  */
-struct ias_value *irias_new_integer_value( int integer)
+struct ias_value *irias_new_integer_value(int integer)
 {
 	struct ias_value *value;
 
-	value = kmalloc( sizeof( struct ias_value), GFP_ATOMIC);
-	if ( value == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Unable to kmalloc!\n");
+	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
+	if (value == NULL) {
+		WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
 		return NULL;
 	}
-	memset( value, 0, sizeof( struct ias_value));
+	memset(value, 0, sizeof(struct ias_value));
 
 	value->type = IAS_INTEGER;
 	value->len = 4;
@@ -412,21 +384,21 @@
  *    Create new IAS string value
  *
  */
-struct ias_value *irias_new_string_value( char *string)
+struct ias_value *irias_new_string_value(char *string)
 {
 	struct ias_value *value;
 
-	value = kmalloc( sizeof( struct ias_value), GFP_ATOMIC);
-	if ( value == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Unable to kmalloc!\n");
+	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
+	if (value == NULL) {
+		WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
 		return NULL;
 	}
 	memset( value, 0, sizeof( struct ias_value));
 
 	value->type = IAS_STRING;
 	value->charset = CS_ASCII;
-	value->len = strlen( string);
-	value->t.string = strdup( string);
+	value->len = strlen(string);
+	value->t.string = strdup(string);
 
 	return value;
 }
@@ -438,63 +410,78 @@
  *    Create new IAS octet-sequence value
  *
  */
-struct ias_value *irias_new_octseq_value( __u8 *octseq , int len)
+struct ias_value *irias_new_octseq_value(__u8 *octseq , int len)
 {
 	struct ias_value *value;
 
-	ASSERT(len <= 55, return NULL;); /*FIXME: must be 1024, but.....*/
-
-	value = kmalloc( sizeof( struct ias_value), GFP_ATOMIC);
-	if ( value == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Unable to kmalloc!\n");
+	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
+	if (value == NULL) {
+		WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
 		return NULL;
 	}
-	memset( value, 0, sizeof( struct ias_value));
+	memset(value, 0, sizeof(struct ias_value));
 
 	value->type = IAS_OCT_SEQ;
 	value->len = len;
 
 	value->t.oct_seq = kmalloc(len, GFP_ATOMIC);
-	if( value->t.oct_seq == NULL){
-		DEBUG(0, __FUNCTION__"(), Unable to kmalloc!\n");
+	if (value->t.oct_seq == NULL){
+		WARNING(__FUNCTION__"(), Unable to kmalloc!\n");
 		return NULL;
 	}
 	memcpy(value->t.oct_seq, octseq , len);
 	return value;
 }
 
+struct ias_value *irias_new_missing_value(void)
+{
+	struct ias_value *value;
+
+	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
+	if (value == NULL) {
+		WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
+		return NULL;
+	}
+	memset(value, 0, sizeof(struct ias_value));
+
+	value->type = IAS_MISSING;
+	value->len = 0;
+
+	return value;
+}
+
 /*
  * Function irias_delete_value (value)
  *
  *    Delete IAS value
  *
  */
-void irias_delete_value( struct ias_value *value)
+void irias_delete_value(struct ias_value *value)
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( value != NULL, return;);
+	ASSERT(value != NULL, return;);
 
-	switch( value->type) {
+	switch (value->type) {
 	case IAS_INTEGER: /* Fallthrough */
 	case IAS_MISSING:
 		/* No need to deallocate */
 		break;
 	case IAS_STRING:
 		/* If string, deallocate string */
-		if ( value->t.string != NULL)
-			kfree( value->t.string);
+		if (value->t.string != NULL)
+			kfree(value->t.string);
 		break;
 	case IAS_OCT_SEQ:
 		/* If byte stream, deallocate byte stream */
-		 if ( value->t.oct_seq != NULL)
+		 if (value->t.oct_seq != NULL)
 			 kfree(value->t.oct_seq);
 		 break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), Unknown value type!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown value type!\n");
 		break;
 	}
-	kfree( value);
+	kfree(value);
 }
 
 
diff -urN linux-2.2.15-pre2/net/irda/irlan/Config.in linux/net/irda/irlan/Config.in
--- linux-2.2.15-pre2/net/irda/irlan/Config.in	Sun Mar  7 15:26:44 1999
+++ linux/net/irda/irlan/Config.in	Mon Dec  3 21:57:53 2001
@@ -1 +1 @@
-dep_tristate 'IrLAN protocol' CONFIG_IRLAN $CONFIG_IRDA
+dep_tristate '  IrLAN protocol' CONFIG_IRLAN $CONFIG_IRDA
diff -urN linux-2.2.15-pre2/net/irda/irlan/irlan_client.c linux/net/irda/irlan/irlan_client.c
--- linux-2.2.15-pre2/net/irda/irlan/irlan_client.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlan/irlan_client.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Mon May 31 14:19:34 1999
+ * Modified at:   Tue Dec 14 15:47:02 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>
@@ -67,11 +67,11 @@
 static void irlan_check_response_param(struct irlan_cb *self, char *param, 
 				       char *value, int val_len);
 
-static void irlan_client_kick_timer_expired(unsigned long data)
+static void irlan_client_kick_timer_expired(void *data)
 {
 	struct irlan_cb *self = (struct irlan_cb *) data;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -90,10 +90,9 @@
 
 void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
-	irda_start_timer(&self->client.kick_timer, timeout, 
-			 (unsigned long) self, 
+	irda_start_timer(&self->client.kick_timer, timeout, (void *) self, 
 			 irlan_client_kick_timer_expired);
 }
 
@@ -107,7 +106,7 @@
 {
 	struct irmanager_event mgr_event;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -166,10 +165,10 @@
  */
 void irlan_client_discovery_indication(discovery_t *discovery) 
 {
-	struct irlan_cb *self, *entry;
+	struct irlan_cb *self;
 	__u32 saddr, daddr;
 	
-	DEBUG(1, __FUNCTION__"()\n");
+	IRDA_DEBUG(1, __FUNCTION__"()\n");
 
 	ASSERT(irlan != NULL, return;);
 	ASSERT(discovery != NULL, return;);
@@ -184,7 +183,7 @@
       	if (self) {
 		ASSERT(self->magic == IRLAN_MAGIC, return;);
 
-		DEBUG(1, __FUNCTION__ "(), Found instance (%08x)!\n",
+		IRDA_DEBUG(1, __FUNCTION__ "(), Found instance (%08x)!\n",
 		      daddr);
 		
 		irlan_client_wakeup(self, saddr, daddr);
@@ -195,7 +194,7 @@
 	/* 
 	 * We have no instance for daddr, so start a new one
 	 */
-	DEBUG(1, __FUNCTION__ "(), starting new instance!\n");
+	IRDA_DEBUG(1, __FUNCTION__ "(), starting new instance!\n");
 	self = irlan_open(saddr, daddr, TRUE);
 
 	/* Restart watchdog timer */
@@ -213,7 +212,7 @@
 {
 	struct irlan_cb *self;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
 	self = (struct irlan_cb *) instance;
 	
@@ -223,7 +222,8 @@
 	
 	irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb); 
 
-	/* Ready for a new command */
+	/* Ready for a new command */	
+	IRDA_DEBUG(2, __FUNCTION__ "(), clearing tx_busy\n");
 	self->client.tx_busy = FALSE;
 
 	/* Check if we have some queued commands waiting to be sent */
@@ -238,8 +238,9 @@
 {
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
+	struct sk_buff *skb;
 
-	DEBUG(4, __FUNCTION__ "(), reason=%d\n", reason);
+	IRDA_DEBUG(4, __FUNCTION__ "(), reason=%d\n", reason);
 	
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -251,6 +252,12 @@
 	
 	ASSERT(tsap == self->client.tsap_ctrl, return;);
 
+       	/* Remove frames queued on the control channel */
+	while ((skb = skb_dequeue(&self->client.txq))) {
+		dev_kfree_skb(skb);
+	}
+	self->client.tx_busy = FALSE;
+
 	irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
 }
 
@@ -262,10 +269,10 @@
  */
 void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
 {
-	struct notify_t notify;
 	struct tsap_cb *tsap;
+	notify_t notify;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -285,7 +292,7 @@
 	
 	tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
 	if (!tsap) {
-		DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
 		return;
 	}
 	self->client.tsap_ctrl = tsap;
@@ -305,7 +312,7 @@
 {
 	struct irlan_cb *self;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	self = (struct irlan_cb *) instance;
 
@@ -331,7 +338,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 		
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -374,7 +381,7 @@
 
 	ASSERT(skb != NULL, return;);	
 	
-	DEBUG(4, __FUNCTION__ "() skb->len=%d\n", (int) skb->len);
+	IRDA_DEBUG(4, __FUNCTION__ "() skb->len=%d\n", (int) skb->len);
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -405,7 +412,7 @@
 	/* How many parameters? */
 	count = frame[1];
 
-	DEBUG(4, __FUNCTION__ "(), got %d parameters\n", count);
+	IRDA_DEBUG(4, __FUNCTION__ "(), got %d parameters\n", count);
 	
 	ptr = frame+2;
 
@@ -413,7 +420,7 @@
  	for (i=0; i<count;i++) {
 		ret = irlan_extract_param(ptr, name, value, &val_len);
 		if (ret < 0) {
-			DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
 			break;
 		}
 		ptr += ret;
@@ -437,7 +444,7 @@
 	__u8 *bytes;
 	int i;
 
-	DEBUG(4, __FUNCTION__ "(), parm=%s\n", param);
+	IRDA_DEBUG(4, __FUNCTION__ "(), parm=%s\n", param);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -477,14 +484,14 @@
 		else if (strcmp(value, "HOSTED") == 0)
 			self->client.access_type = ACCESS_HOSTED;
 		else {
-			DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
 		}
 	}
 	/*
 	 *  IRLAN version
 	 */
 	if (strcmp(param, "IRLAN_VER") == 0) {
-		DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0], 
+		IRDA_DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0], 
 		      (__u8) value[1]);
 
 		self->version[0] = value[0];
@@ -496,41 +503,41 @@
 	 */
 	if (strcmp(param, "DATA_CHAN") == 0) {
 		self->dtsap_sel_data = value[0];
-		DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data);
+		IRDA_DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data);
 		return;
 	}
 	if (strcmp(param, "CON_ARB") == 0) {
 		memcpy(&tmp_cpu, value, 2); /* Align value */
 		le16_to_cpus(&tmp_cpu);     /* Convert to host order */
 		self->client.recv_arb_val = tmp_cpu;
-		DEBUG(2, __FUNCTION__ "(), receive arb val=%d\n", 
-		      self->client.recv_arb_val);
+		IRDA_DEBUG(2, __FUNCTION__ "(), receive arb val=%d\n", 
+			   self->client.recv_arb_val);
 	}
 	if (strcmp(param, "MAX_FRAME") == 0) {
 		memcpy(&tmp_cpu, value, 2); /* Align value */
 		le16_to_cpus(&tmp_cpu);     /* Convert to host order */
 		self->client.max_frame = tmp_cpu;
-		DEBUG(4, __FUNCTION__ "(), max frame=%d\n", 
-		      self->client.max_frame);
+		IRDA_DEBUG(4, __FUNCTION__ "(), max frame=%d\n", 
+			   self->client.max_frame);
 	}
 	 
 	/*
 	 *  RECONNECT_KEY, in case the link goes down!
 	 */
 	if (strcmp(param, "RECONNECT_KEY") == 0) {
-		DEBUG(4, "Got reconnect key: ");
+		IRDA_DEBUG(4, "Got reconnect key: ");
 		/* for (i = 0; i < val_len; i++) */
 /* 			printk("%02x", value[i]); */
 		memcpy(self->client.reconnect_key, value, val_len);
 		self->client.key_len = val_len;
-		DEBUG(4, "\n");
+		IRDA_DEBUG(4, "\n");
 	}
 	/*
 	 *  FILTER_ENTRY, have we got an ethernet address?
 	 */
 	if (strcmp(param, "FILTER_ENTRY") == 0) {
 		bytes = value;
-		DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n",
+		IRDA_DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n",
 		      bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], 
 		      bytes[5]);
 		for (i = 0; i < 6; i++) 
@@ -549,16 +556,20 @@
 {
 	struct irlan_cb *self;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(priv != NULL, return;);
 
 	self = (struct irlan_cb *) priv;
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
+	/* We probably don't need to make any more queries */
+	iriap_close(self->client.iriap);
+	self->client.iriap = NULL;
+
 	/* Check if request succeeded */
 	if (result != IAS_SUCCESS) {
-		DEBUG(2, __FUNCTION__ "(), got NULL value!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), got NULL value!\n");
 		irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, 
 				      NULL);
 		return;
@@ -573,18 +584,10 @@
 					      NULL);
 			return;
 		}
-		break;
-	case IAS_STRING:
-		DEBUG(2, __FUNCTION__ "(), got string %s\n", value->t.string);
-		break;
-	case IAS_OCT_SEQ:
-		DEBUG(2, __FUNCTION__ "(), OCT_SEQ not implemented\n");
-		break;
-	case IAS_MISSING:
-		DEBUG(2, __FUNCTION__ "(), MISSING not implemented\n");
+		irias_delete_value(value);
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), unknown type!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), unknown type!\n");
 		break;
 	}
 	irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
diff -urN linux-2.2.15-pre2/net/irda/irlan/irlan_client_event.c linux/net/irda/irlan/irlan_client_event.c
--- linux-2.2.15-pre2/net/irda/irlan/irlan_client_event.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlan/irlan_client_event.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Fri May 14 23:08:15 1999
+ * Modified at:   Sun Dec 26 21:52:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -92,26 +92,33 @@
 static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event, 
 				   struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 	
 	switch (event) {
 	case IRLAN_DISCOVERY_INDICATION:
+		if (self->client.iriap) {
+			WARNING(__FUNCTION__ 
+				"(), busy with a previous query\n");
+			return -EBUSY;
+		}
+		
+		self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+						irlan_client_get_value_confirm);
 		/* Get some values from peer IAS */
-		iriap_getvaluebyclass_request(
-			"IrLAN", "IrDA:TinyTP:LsapSel",
-			self->saddr, self->daddr,
-			irlan_client_get_value_confirm, self);
+		iriap_getvaluebyclass_request(self->client.iriap,
+					      self->saddr, self->daddr,
+					      "IrLAN", "IrDA:TinyTP:LsapSel");
 		
 		irlan_next_client_state(self, IRLAN_QUERY);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
 		break;
 	default:
-		DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb) 
@@ -130,7 +137,7 @@
 static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, 
 				    struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -148,7 +155,7 @@
 		irlan_next_client_state(self, IRLAN_CONN);
 		break;
 	case IRLAN_IAS_PROVIDER_NOT_AVAIL:
-		DEBUG(2, __FUNCTION__ "(), IAS_PROVIDER_NOT_AVAIL\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IAS_PROVIDER_NOT_AVAIL\n");
 		irlan_next_client_state(self, IRLAN_IDLE);
 
 		/* Give the client a kick! */
@@ -161,10 +168,10 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
 		break;
 	default:
-		DEBUG(2, __FUNCTION__"(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__"(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -183,11 +190,11 @@
 static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event, 
 				   struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return -1;);
 	
-	switch(event) {
+	switch (event) {
 	case IRLAN_CONNECT_COMPLETE:
 		/* Send getinfo cmd */
 		irlan_get_provider_info(self);
@@ -198,10 +205,10 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -218,7 +225,7 @@
 static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, 
 				   struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	
@@ -238,10 +245,10 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -260,7 +267,7 @@
 static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, 
 				    struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return -1;);
 
@@ -275,10 +282,10 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -299,7 +306,7 @@
 {
 	struct qos_info qos;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return -1;);
 
@@ -338,7 +345,7 @@
 			irlan_next_client_state(self, IRLAN_DATA);
 			break;
 		default:
-			DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
 			break;
 		}
 		break;
@@ -347,10 +354,10 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	
@@ -370,7 +377,7 @@
 static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event, 
 				   struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return -1;);
 	
@@ -384,10 +391,10 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -401,7 +408,7 @@
 {
 	struct qos_info qos;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	
@@ -423,7 +430,7 @@
 		} else if (self->client.recv_arb_val >
 			   self->provider.send_arb_val) 
 		{
-			DEBUG(2, __FUNCTION__ "(), lost the battle :-(\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), lost the battle :-(\n");
 		}
 		break;
 	case IRLAN_DATA_CONNECT_INDICATION:
@@ -434,10 +441,10 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -456,7 +463,7 @@
 static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, 
 				   struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -470,7 +477,7 @@
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -488,7 +495,7 @@
 static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, 
 				    struct sk_buff *skb) 
 {
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	if (skb)
 		dev_kfree_skb(skb);
@@ -505,7 +512,7 @@
 static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event, 
 				   struct sk_buff *skb) 
 {
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
 	if (skb)
 		dev_kfree_skb(skb);
diff -urN linux-2.2.15-pre2/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- linux-2.2.15-pre2/net/irda/irlan/irlan_common.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlan/irlan_common.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Mon May 31 14:25:19 1999
+ * Modified at:   Sun Dec 26 21:53:10 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -61,7 +61,6 @@
 /* Module parameters */
 static int eth = 0; /* Use "eth" or "irlan" name for devices */
 static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */
-static int timeout = IRLAN_TIMEOUT;
 
 static char *irlan_state[] = {
 	"IRLAN_IDLE",
@@ -106,15 +105,15 @@
 /*
  * Function irlan_watchdog_timer_expired (data)
  *
- *    
+ *    Something has gone wrong during the connection establishment
  *
  */
-void irlan_watchdog_timer_expired(unsigned long data)
+void irlan_watchdog_timer_expired(void *data)
 {
 	struct irmanager_event mgr_event;
 	struct irlan_cb *self;
 	
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
 	self = (struct irlan_cb *) data;
 
@@ -123,7 +122,8 @@
 
 	/* Check if device still configured */
 	if (self->dev.start) {
-		DEBUG(0, __FUNCTION__ "(), notifying irmanager to stop irlan!\n");
+		IRDA_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);
@@ -136,13 +136,8 @@
 		 */
 		self->notify_irmanager = FALSE;
 	} else {
-		DEBUG(0, __FUNCTION__ "(), closing instance!\n");
-		if (self->netdev_registered) {
-			DEBUG(0, __FUNCTION__ "(), removing netdev!\n");
-			unregister_netdev(&self->dev);
-			self->netdev_registered = FALSE;
-		}
-		irlan_close(self);
+		IRDA_DEBUG(0, __FUNCTION__ "(), closing instance!\n");
+		/*irlan_close(self);*/
 	}
 }
 
@@ -154,9 +149,9 @@
  */
 void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
-	irda_start_timer(&self->watchdog_timer, timeout, (unsigned long) self,
+	irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
 			 irlan_watchdog_timer_expired);
 }
 
@@ -166,14 +161,14 @@
  *    Initialize IrLAN layer
  *
  */
-__initfunc(int irlan_init(void))
+int __init irlan_init(void)
 {
 	struct irlan_cb *new;
 	__u16 hints;
 
-	DEBUG(4, __FUNCTION__"()\n");
+	IRDA_DEBUG(4, __FUNCTION__"()\n");
 
-	/* Allocate master array */
+	/* Allocate master structure */
 	irlan = hashbin_new(HB_LOCAL); 
 	if (irlan == NULL) {
 		printk(KERN_WARNING "IrLAN: Can't allocate hashbin!\n");
@@ -183,7 +178,7 @@
 	create_proc_entry("irlan", 0, proc_irda)->get_info = irlan_proc_read;
 #endif /* CONFIG_PROC_FS */
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	hints = irlmp_service_to_hint(S_LAN);
 
@@ -209,7 +204,7 @@
 
 void irlan_cleanup(void) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	irlmp_unregister_client(ckey);
 
@@ -234,19 +229,19 @@
 {
 	int i=0;
 
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
 	/* Check if we should call the device eth<x> or irlan<x> */
 	if (!eth) {
 		/* Get the first free irlan<x> name */
 		do {
 			sprintf(self->ifname, "%s%d", "irlan", i++);
-		} while (dev_get(self->ifname) != NULL);
+		} while (dev_get(self->ifname));
 	}
 	self->dev.name = self->ifname;
 	
 	if (register_netdev(&self->dev) != 0) {
-		DEBUG(2, __FUNCTION__ "(), register_netdev() failed!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), register_netdev() failed!\n");
 		return -1;
 	}
 	self->netdev_registered = TRUE;
@@ -264,7 +259,7 @@
 {
 	struct irlan_cb *self;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	/* 
 	 *  Initialize the irlan structure. 
@@ -300,7 +295,7 @@
 	init_timer(&self->watchdog_timer);
 	init_timer(&self->client.kick_timer);
 
-	hashbin_insert(irlan, (QUEUE *) self, daddr, NULL);
+	hashbin_insert(irlan, (queue_t *) self, daddr, NULL);
 	
 	skb_queue_head_init(&self->client.txq);
 	
@@ -323,7 +318,9 @@
  */
 static void __irlan_close(struct irlan_cb *self)
 {
-	DEBUG(2, __FUNCTION__ "()\n");
+	struct sk_buff *skb;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -333,6 +330,14 @@
 
 	/* Close all open connections and remove TSAPs */
 	irlan_close_tsaps(self);
+	
+	if (self->client.iriap) 
+		iriap_close(self->client.iriap);
+
+	/* Remove frames queued on the control channel */
+	while ((skb = skb_dequeue(&self->client.txq))) {
+		dev_kfree_skb(skb);
+	}
 
 	if (self->netdev_registered) {
 		unregister_netdev(&self->dev);
@@ -352,22 +357,22 @@
 void irlan_close(struct irlan_cb *self)
 {
 	struct irlan_cb *entry;
-	
-	DEBUG(0, __FUNCTION__ "()\n");
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
         ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if device is still configured */
 	if (self->dev.start) {
-		DEBUG(0, __FUNCTION__ 
+		IRDA_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);
+	IRDA_DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
 	entry = hashbin_remove(irlan, self->daddr, NULL);
 
 	ASSERT(entry == self, return;);
@@ -388,7 +393,7 @@
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -400,7 +405,7 @@
 	self->max_sdu_size = max_sdu_size;
 	self->max_header_size = max_header_size;
 
-	DEBUG(0, "IrLAN, We are now connected!\n");
+	IRDA_DEBUG(0, "IrLAN, We are now connected!\n");
 
 	del_timer(&self->watchdog_timer);
 
@@ -435,7 +440,7 @@
 
 	/* TODO: we could set the MTU depending on the max_sdu_size */
 
-	DEBUG(2, "IrLAN, We are now connected!\n");
+	IRDA_DEBUG(2, "IrLAN, We are now connected!\n");
 	del_timer(&self->watchdog_timer);
 
 	/* 
@@ -467,7 +472,7 @@
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
 
-	DEBUG(0, __FUNCTION__ "(), reason=%d\n", reason);
+	IRDA_DEBUG(0, __FUNCTION__ "(), reason=%d\n", reason);
 	
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -479,7 +484,7 @@
 	
 	ASSERT(tsap == self->tsap_data, return;);
 
-	DEBUG(2, "IrLAN, data channel disconnected by peer!\n");
+	IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n");
 
 	switch(reason) {
 	case LM_USER_REQUEST: /* User request */
@@ -489,13 +494,13 @@
 		irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
 		break;
 	case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */
-		DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
 		break;
 	case LM_LAP_RESET:  /* IrLAP reset */
-		DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
 		break;
 	case LM_INIT_DISCONNECT:
-		DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
 		break;
 	default:
 		break;
@@ -507,10 +512,10 @@
 
 void irlan_open_data_tsap(struct irlan_cb *self)
 {
-	struct notify_t notify;
 	struct tsap_cb *tsap;
+	notify_t notify;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -532,7 +537,7 @@
 
 	tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
 	if (!tsap) {
-		DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
 		return;
 	}
 	self->tsap_data = tsap;
@@ -546,7 +551,7 @@
 
 void irlan_close_tsaps(struct irlan_cb *self)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -612,7 +617,7 @@
 		irias_add_string_attrib(obj, "DeviceID", "HWP19F0");
 		irias_add_integer_attrib(obj, "CompCnt", 1);
 		if (self->provider.access_type == ACCESS_PEER)
-			irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+			irias_add_string_attrib(obj, "Comp#01", "PNP8389");
 		else
 			irias_add_string_attrib(obj, "Comp#01", "PNP8294");
 
@@ -631,6 +636,8 @@
 {
 	struct sk_buff *skb;
 
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+
 	if (irda_lock(&self->client.tx_busy) == FALSE)
 		return -EBUSY;
 
@@ -639,11 +646,16 @@
 		self->client.tx_busy = FALSE;
 		return 0;
 	}
-	if (self->client.tsap_ctrl == NULL) {
+	
+	/* Check that it's really possible to send commands */
+	if ((self->client.tsap_ctrl == NULL) || 
+	    (self->client.state == IRLAN_IDLE)) 
+	{
 		self->client.tx_busy = FALSE;
 		dev_kfree_skb(skb);
 		return -1;
 	}
+	IRDA_DEBUG(3, __FUNCTION__ "(), sending ...\n");
 
 	return irttp_data_request(self->client.tsap_ctrl, skb);
 }
@@ -656,6 +668,8 @@
  */
 void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
 {
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
 	/* Queue command */
 	skb_queue_tail(&self->client.txq, skb);
 
@@ -674,7 +688,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -692,7 +706,6 @@
  	frame[0] = CMD_GET_PROVIDER_INFO;
 	frame[1] = 0x00;                 /* Zero parameters */
 	
-	/* irttp_data_request(self->client.tsap_ctrl, skb); */
 	irlan_ctrl_data_request(self, skb);
 }
 
@@ -707,7 +720,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -740,7 +753,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -764,7 +777,6 @@
 
 	irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
 
-	/* irttp_data_request(self->client.tsap_ctrl, skb); */
 	irlan_ctrl_data_request(self, skb);
 }
 
@@ -780,7 +792,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);	
@@ -819,7 +831,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -859,7 +871,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -900,7 +912,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 		
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -936,7 +948,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -1023,7 +1035,7 @@
 	int n=0;
 	
 	if (skb == NULL) {
-		DEBUG(2, __FUNCTION__ "(), Got NULL skb\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), Got NULL skb\n");
 		return 0;
 	}	
 
@@ -1040,7 +1052,7 @@
 		ASSERT(value_len > 0, return 0;);
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown parameter type!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown parameter type!\n");
 		return 0;
 		break;
 	}
@@ -1050,7 +1062,7 @@
 
 	/* Make space for data */
 	if (skb_tailroom(skb) < (param_len+value_len+3)) {
-		DEBUG(2, __FUNCTION__ "(), No more space at end of skb\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), No more space at end of skb\n");
 		return 0;
 	}	
 	skb_put(skb, param_len+value_len+3);
@@ -1097,13 +1109,13 @@
 	__u16 val_len;
 	int n=0;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	/* get length of parameter name (1 byte) */
 	name_len = buf[n++];
 	
 	if (name_len > 254) {
-		DEBUG(2, __FUNCTION__ "(), name_len > 254\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), name_len > 254\n");
 		return -RSP_INVALID_COMMAND_FORMAT;
 	}
 	
@@ -1120,7 +1132,7 @@
 	le16_to_cpus(&val_len); n+=2;
 	
 	if (val_len > 1016) {
-		DEBUG(2, __FUNCTION__ "(), parameter length to long\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), parameter length to long\n");
 		return -RSP_INVALID_COMMAND_FORMAT;
 	}
 	*len = val_len;
@@ -1130,8 +1142,8 @@
 	value[val_len] = '\0';
 	n+=val_len;
 	
-	DEBUG(4, "Parameter: %s ", name); 
-	DEBUG(4, "Value: %s\n", value); 
+	IRDA_DEBUG(4, "Parameter: %s ", name); 
+	IRDA_DEBUG(4, "Value: %s\n", value); 
 
 	return n;
 }
diff -urN linux-2.2.15-pre2/net/irda/irlan/irlan_eth.c linux/net/irda/irlan/irlan_eth.c
--- linux-2.2.15-pre2/net/irda/irlan/irlan_eth.c	Tue Jan  4 10:12:27 2000
+++ linux/net/irda/irlan/irlan_eth.c	Mon Dec  3 21:57:53 2001
@@ -6,13 +6,13 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:37:58 1998
- * Modified at:   Mon May 31 19:57:08 1999
+ * Modified at:   Sun Jan 16 22:43:41 2000
  * 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-1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-2000 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 
@@ -50,7 +50,7 @@
 	struct irmanager_event mgr_event;
 	struct irlan_cb *self;
 
-	DEBUG(2, __FUNCTION__"()\n");
+	IRDA_DEBUG(2, __FUNCTION__"()\n");
 
 	ASSERT(dev != NULL, return -1;);
        
@@ -115,7 +115,7 @@
 {
 	struct irlan_cb *self;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(dev != NULL, return -1;);
 
@@ -150,7 +150,7 @@
 {
 	struct irlan_cb *self = (struct irlan_cb *) dev->priv;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
 	/* Stop device */
 	dev->tbusy = 1;
@@ -253,9 +253,6 @@
 
 	self = (struct irlan_cb *) instance;
 
-	ASSERT(self != NULL, return 0;);
-	ASSERT(self->magic == IRLAN_MAGIC, return 0;);
-
 	if (skb == NULL) {
 		++self->stats.rx_dropped; 
 		return 0;
@@ -282,7 +279,9 @@
  * Function irlan_eth_flow (status)
  *
  *    Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by 
- *    controlling the dev->tbusy variable.
+ *    controlling the dev->tbusy variable. Currently not used, since we
+ *    just drop the frames instead of asking the client layer to buffer 
+ *    them.
  */
 void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
 {
@@ -345,8 +344,8 @@
 	 * is useful if we have changed access points on the same
 	 * subnet.  
 	 */
-#ifdef CONFIG_INET	 
-	DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
+#ifdef CONFIG_INET
+	IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
 	in_dev = dev->ip_ptr;
 	arp_send(ARPOP_REQUEST, ETH_P_ARP, 
 		 in_dev->ifa_list->ifa_address,
@@ -369,14 +368,14 @@
 
  	self = dev->priv; 
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
  	ASSERT(self != NULL, return;); 
  	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if data channel has been connected yet */
 	if (self->client.state != IRLAN_DATA) {
-		DEBUG(1, __FUNCTION__ "(), delaying!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), delaying!\n");
 		return;
 	}
 
@@ -386,20 +385,20 @@
 	} 
 	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");
+		IRDA_DEBUG(4, __FUNCTION__ "(), Setting multicast filter\n");
 		/* hardware_set_filter(NULL); */
 
 		irlan_set_multicast_filter(self, TRUE);
 	}
 	else if (dev->mc_count) {
-		DEBUG(4, __FUNCTION__ "(), Setting multicast filter\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), Setting multicast filter\n");
 		/* Walk the address list, and load the filter */
 		/* hardware_set_filter(dev->mc_list); */
 
 		irlan_set_multicast_filter(self, TRUE);
 	}
 	else {
-		DEBUG(4, __FUNCTION__ "(), Clearing multicast filter\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), Clearing multicast filter\n");
 		irlan_set_multicast_filter(self, FALSE);
 	}
 
diff -urN linux-2.2.15-pre2/net/irda/irlan/irlan_event.c linux/net/irda/irlan/irlan_event.c
--- linux-2.2.15-pre2/net/irda/irlan/irlan_event.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irlan/irlan_event.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Oct 20 09:10:16 1998
- * Modified at:   Sun May  9 21:17:44 1999
+ * Modified at:   Sat Oct 30 12:59:01 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -40,7 +40,7 @@
 
 void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state) 
 {
-	DEBUG(2, __FUNCTION__"(), %s\n", irlan_state[state]);
+	IRDA_DEBUG(2, __FUNCTION__"(), %s\n", irlan_state[state]);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -50,7 +50,7 @@
 
 void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state) 
 {
-	DEBUG(2, __FUNCTION__"(), %s\n", irlan_state[state]);
+	IRDA_DEBUG(2, __FUNCTION__"(), %s\n", irlan_state[state]);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
diff -urN linux-2.2.15-pre2/net/irda/irlan/irlan_filter.c linux/net/irda/irlan/irlan_filter.c
--- linux-2.2.15-pre2/net/irda/irlan/irlan_filter.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlan/irlan_filter.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Jan 29 11:16:38 1999
- * Modified at:   Fri May 14 23:11:01 1999
+ * Modified at:   Sat Oct 30 12:58:45 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -41,7 +41,7 @@
 	if ((self->provider.filter_type == IRLAN_DIRECTED) && 
 	    (self->provider.filter_operation == DYNAMIC))
 	{
-		DEBUG(0, "Giving peer a dynamic Ethernet address\n");
+		IRDA_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;
@@ -71,7 +71,7 @@
 	if ((self->provider.filter_type == IRLAN_DIRECTED) && 
 	    (self->provider.filter_mode == FILTER))
 	{
-		DEBUG(0, "Directed filter on\n");
+		IRDA_DEBUG(0, "Directed filter on\n");
 		skb->data[0] = 0x00; /* Success */
 		skb->data[1] = 0x00;
 		return;
@@ -79,7 +79,7 @@
 	if ((self->provider.filter_type == IRLAN_DIRECTED) && 
 	    (self->provider.filter_mode == NONE))
 	{
-		DEBUG(0, "Directed filter off\n");
+		IRDA_DEBUG(0, "Directed filter off\n");
 		skb->data[0] = 0x00; /* Success */
 		skb->data[1] = 0x00;
 		return;
@@ -88,7 +88,7 @@
 	if ((self->provider.filter_type == IRLAN_BROADCAST) && 
 	    (self->provider.filter_mode == FILTER))
 	{
-		DEBUG(0, "Broadcast filter on\n");
+		IRDA_DEBUG(0, "Broadcast filter on\n");
 		skb->data[0] = 0x00; /* Success */
 		skb->data[1] = 0x00;
 		return;
@@ -96,7 +96,7 @@
 	if ((self->provider.filter_type == IRLAN_BROADCAST) && 
 	    (self->provider.filter_mode == NONE))
 	{
-		DEBUG(0, "Broadcast filter off\n");
+		IRDA_DEBUG(0, "Broadcast filter off\n");
 		skb->data[0] = 0x00; /* Success */
 		skb->data[1] = 0x00;
 		return;
@@ -104,7 +104,7 @@
 	if ((self->provider.filter_type == IRLAN_MULTICAST) && 
 	    (self->provider.filter_mode == FILTER))
 	{
-		DEBUG(0, "Multicast filter on\n");
+		IRDA_DEBUG(0, "Multicast filter on\n");
 		skb->data[0] = 0x00; /* Success */
 		skb->data[1] = 0x00;
 		return;
@@ -112,7 +112,7 @@
 	if ((self->provider.filter_type == IRLAN_MULTICAST) && 
 	    (self->provider.filter_mode == NONE))
 	{
-		DEBUG(0, "Multicast filter off\n");
+		IRDA_DEBUG(0, "Multicast filter off\n");
 		skb->data[0] = 0x00; /* Success */
 		skb->data[1] = 0x00;
 		return;
@@ -120,7 +120,7 @@
 	if ((self->provider.filter_type == IRLAN_MULTICAST) && 
 	    (self->provider.filter_operation == GET))
 	{
-		DEBUG(0, "Multicast filter get\n");
+		IRDA_DEBUG(0, "Multicast filter get\n");
 		skb->data[0] = 0x00; /* Success? */
 		skb->data[1] = 0x02;
 		irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
@@ -130,7 +130,7 @@
 	skb->data[0] = 0x00; /* Command not supported */
 	skb->data[1] = 0x00;
 
-	DEBUG(0, "Not implemented!\n");
+	IRDA_DEBUG(0, "Not implemented!\n");
 }
 
 /*
@@ -143,20 +143,20 @@
 {
 	__u8 *bytes;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	bytes = value;
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
-	DEBUG(4, "%s, %s\n", param, value);
+	IRDA_DEBUG(4, "%s, %s\n", param, value);
 
 	/*
 	 *  This is experimental!! DB.
 	 */
 	 if (strcmp(param, "MODE") == 0) {
-		DEBUG(0, __FUNCTION__ "()\n");
+		IRDA_DEBUG(0, __FUNCTION__ "()\n");
 		self->use_udata = TRUE;
 		return;
 	}
diff -urN linux-2.2.15-pre2/net/irda/irlan/irlan_provider.c linux/net/irda/irlan/irlan_provider.c
--- linux-2.2.15-pre2/net/irda/irlan/irlan_provider.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irlan/irlan_provider.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Sun May  9 12:22:56 1999
+ * Modified at:   Sat Oct 30 12:52:10 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>
@@ -70,7 +70,7 @@
 	struct irlan_cb *self;
 	__u8 code;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	self = (struct irlan_cb *) instance;
 
@@ -82,32 +82,32 @@
 	code = skb->data[0];
 	switch(code) {
 	case CMD_GET_PROVIDER_INFO:
-		DEBUG(4, "Got GET_PROVIDER_INFO command!\n");
+		IRDA_DEBUG(4, "Got GET_PROVIDER_INFO command!\n");
 		irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb); 
 		break;
 
 	case CMD_GET_MEDIA_CHAR:
-		DEBUG(4, "Got GET_MEDIA_CHAR command!\n");
+		IRDA_DEBUG(4, "Got GET_MEDIA_CHAR command!\n");
 		irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb); 
 		break;
 	case CMD_OPEN_DATA_CHANNEL:
-		DEBUG(4, "Got OPEN_DATA_CHANNEL command!\n");
+		IRDA_DEBUG(4, "Got OPEN_DATA_CHANNEL command!\n");
 		irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb); 
 		break;
 	case CMD_FILTER_OPERATION:
-		DEBUG(4, "Got FILTER_OPERATION command!\n");
+		IRDA_DEBUG(4, "Got FILTER_OPERATION command!\n");
 		irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb);
 		break;
 	case CMD_RECONNECT_DATA_CHAN:
-		DEBUG(2, __FUNCTION__"(), Got RECONNECT_DATA_CHAN command\n");
-		DEBUG(2, __FUNCTION__"(), NOT IMPLEMENTED\n");
+		IRDA_DEBUG(2, __FUNCTION__"(), Got RECONNECT_DATA_CHAN command\n");
+		IRDA_DEBUG(2, __FUNCTION__"(), NOT IMPLEMENTED\n");
 		break;
 	case CMD_CLOSE_DATA_CHAN:
-		DEBUG(2, "Got CLOSE_DATA_CHAN command!\n");
-		DEBUG(2, __FUNCTION__"(), NOT IMPLEMENTED\n");
+		IRDA_DEBUG(2, "Got CLOSE_DATA_CHAN command!\n");
+		IRDA_DEBUG(2, __FUNCTION__"(), NOT IMPLEMENTED\n");
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown command!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown command!\n");
 		break;
 	}
 	return 0;
@@ -129,7 +129,7 @@
 	struct tsap_cb *tsap;
 	__u32 saddr, daddr;
 
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 	
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -150,11 +150,11 @@
 	new = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL);
       	if (new) {
 		ASSERT(new->magic == IRLAN_MAGIC, return;);
-		DEBUG(0, __FUNCTION__ "(), found instance!\n");
+		IRDA_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);
+		IRDA_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) {
@@ -165,7 +165,7 @@
 		}
 	} else {
 		/* This must be the master instance, so start a new instance */
-		DEBUG(0, __FUNCTION__ "(), starting new provider!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), starting new provider!\n");
 
 		new = irlan_open(saddr, daddr, TRUE); 
 	}
@@ -182,7 +182,7 @@
 		new->provider.tsap_ctrl = irttp_dup(self->provider.tsap_ctrl, 
 						    new);
 		if (!new->provider.tsap_ctrl) {
-			DEBUG(0, __FUNCTION__ "(), dup failed!\n");
+			IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n");
 			return;
 		}
 		
@@ -245,7 +245,7 @@
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
 
-	DEBUG(4, __FUNCTION__ "(), reason=%d\n", reason);
+	IRDA_DEBUG(4, __FUNCTION__ "(), reason=%d\n", reason);
 	
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -299,7 +299,7 @@
 	
 	ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
 	
-	DEBUG(4, __FUNCTION__ "(), skb->len=%d\n", (int)skb->len);
+	IRDA_DEBUG(4, __FUNCTION__ "(), skb->len=%d\n", (int)skb->len);
 
 	ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
 	ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
@@ -321,7 +321,7 @@
 	/* How many parameters? */
 	count = frame[1];
 
-	DEBUG(4, "Got %d parameters\n", count);
+	IRDA_DEBUG(4, "Got %d parameters\n", count);
 	
 	ptr = frame+2;
 	
@@ -329,7 +329,7 @@
  	for (i=0; i<count;i++) {
 		ret = irlan_extract_param(ptr, name, value, &val_len);
 		if (ret < 0) {
-			DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
 			break;
 		}
 		ptr+=ret;
@@ -354,7 +354,7 @@
 {
 	struct sk_buff *skb;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -379,7 +379,7 @@
 			irlan_insert_string_param(skb, "MEDIA", "802.5");
 			break;
 		default:
-			DEBUG(2, __FUNCTION__ "(), unknown media type!\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), unknown media type!\n");
 			break;
 		}
 		irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
@@ -403,7 +403,7 @@
 			irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED");
 			break;
 		default:
-			DEBUG(2, __FUNCTION__ "(), Unknown access type\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), Unknown access type\n");
 			break;
 		}
 		irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee);
@@ -424,7 +424,7 @@
 		handle_filter_request(self, skb);
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown command!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown command!\n");
 		break;
 	}
 
@@ -439,10 +439,10 @@
  */
 int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
 {
-	struct notify_t notify;
 	struct tsap_cb *tsap;
+	notify_t notify;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -463,7 +463,7 @@
 
 	tsap = irttp_open_tsap(LSAP_ANY, 1, &notify);
 	if (!tsap) {
-		DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
 		return -1;
 	}
 	self->provider.tsap_ctrl = tsap;
diff -urN linux-2.2.15-pre2/net/irda/irlan/irlan_provider_event.c linux/net/irda/irlan/irlan_provider_event.c
--- linux-2.2.15-pre2/net/irda/irlan/irlan_provider_event.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irlan/irlan_provider_event.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Fri May  7 10:53:58 1999
+ * Modified at:   Sat Oct 30 12:52:41 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -72,7 +72,7 @@
 static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
 				     struct sk_buff *skb)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return -1;);
 	
@@ -82,7 +82,7 @@
 	     irlan_next_provider_state( self, IRLAN_INFO);
 	     break;
 	default:
-		DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -101,7 +101,7 @@
 {
 	int ret;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return -1;);
 
@@ -147,7 +147,7 @@
 		irlan_next_provider_state(self, IRLAN_IDLE);
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -166,7 +166,7 @@
 static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, 
 				     struct sk_buff *skb)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 
@@ -186,7 +186,7 @@
 		irlan_next_provider_state(self, IRLAN_IDLE);
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
@@ -205,7 +205,7 @@
 static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, 
 				     struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -221,7 +221,7 @@
 		irlan_next_provider_state(self, IRLAN_IDLE);
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;
 	}
 	if (skb)
diff -urN linux-2.2.15-pre2/net/irda/irlap.c linux/net/irda/irlap.c
--- linux-2.2.15-pre2/net/irda/irlap.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlap.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Mon May 31 21:43:55 1999
+ * Modified at:   Tue Dec 14 09:26:44 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -69,19 +69,20 @@
 
 #endif /* CONFIG_PROC_FS */
 
-__initfunc(int irlap_init(void))
+int __init irlap_init(void)
 {
 	/* Allocate master array */
 	irlap = hashbin_new(HB_LOCAL);
 	if (irlap == NULL) {
-		printk(KERN_WARNING "IrLAP: Can't allocate irlap hashbin!\n");
+	        ERROR(__FUNCTION__ "(), 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");
+		WARNING(__FUNCTION__ 
+			"(), can't allocate compressors hashbin!\n");
 		return -ENOMEM;
 	}
 #endif
@@ -106,15 +107,12 @@
  *    Initialize IrLAP layer
  *
  */
-struct irlap_cb *irlap_open(struct irda_device *irdev)
+struct irlap_cb *irlap_open(struct device *dev, struct qos_info *qos)
 {
 	struct irlap_cb *self;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
-	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)
@@ -124,26 +122,22 @@
 	self->magic = LAP_MAGIC;
 
 	/* Make a binding between the layers */
-	self->irdev = irdev;
-	self->netdev = &irdev->netdev;
+	self->netdev = dev;
+	self->qos_dev = qos;
+
+	/* FIXME: should we get our own field? */
+	dev->atalk_ptr = self;
 
 	irlap_next_state(self, LAP_OFFLINE);
 
-	/* Initialize transmitt queue */
-	skb_queue_head_init(&self->tx_list);
+	/* Initialize transmit queue */
+	skb_queue_head_init(&self->txq);
+	skb_queue_head_init(&self->txq_ultra);
 	skb_queue_head_init(&self->wx_list);
 
 	/* My unique IrLAP device address! */
 	get_random_bytes(&self->saddr, sizeof(self->saddr));
-
-	/* 
-	 * Generate random connection address for this session, which must
-	 * be 7 bits wide and different from 0x00 and 0xfe 
-	 */
-	while ((self->caddr == 0x00) || (self->caddr == 0xfe)) {
-		get_random_bytes(&self->caddr, sizeof(self->caddr));
-		self->caddr &= 0xfe;
-	}
+	memcpy(dev->dev_addr, &self->saddr, 4);
 
 	init_timer(&self->slot_timer);
 	init_timer(&self->query_timer);
@@ -152,12 +146,15 @@
 	init_timer(&self->poll_timer);
 	init_timer(&self->wd_timer);
 	init_timer(&self->backoff_timer);
+	init_timer(&self->media_busy_timer);	
 
 	irlap_apply_default_connection_parameters(self);
+
+	self->N3 = 3; /* # connections attemts to try before giving up */
 	
 	irlap_next_state(self, LAP_NDM);
 
-	hashbin_insert(irlap, (QUEUE *) self, self->saddr, NULL);
+	hashbin_insert(irlap, (queue_t *) self, self->saddr, NULL);
 
 	irlmp_register_link(self, self->saddr, &self->notify);
 	
@@ -183,10 +180,10 @@
 	del_timer(&self->poll_timer);
 	del_timer(&self->wd_timer);
 	del_timer(&self->backoff_timer);
+	del_timer(&self->media_busy_timer);
 
 	irlap_flush_all_queues(self);
        
-	self->irdev = NULL;
 	self->magic = 0;
 	
 	kfree(self);
@@ -202,7 +199,7 @@
 {
 	struct irlap_cb *lap;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -215,7 +212,7 @@
 	/* 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");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Didn't find myself!\n");
 		return;
 	}
 	__irlap_close(lap);
@@ -229,7 +226,7 @@
  */
 void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -248,7 +245,7 @@
  */
 void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	irlap_do_event(self, CONNECT_RESPONSE, skb, NULL);
 }
@@ -263,7 +260,7 @@
 void irlap_connect_request(struct irlap_cb *self, __u32 daddr, 
 			   struct qos_info *qos_user, int sniff) 
 {
-	DEBUG(3, __FUNCTION__ "(), daddr=0x%08x\n", daddr);
+	IRDA_DEBUG(3, __FUNCTION__ "(), daddr=0x%08x\n", daddr);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -276,8 +273,7 @@
 	 */
 	irlap_init_qos_capabilities(self, qos_user);
 	
-	if ((self->state == LAP_NDM) && 
-	    !irda_device_is_media_busy(self->irdev))
+	if ((self->state == LAP_NDM) && !self->media_busy)
 		irlap_do_event(self, CONNECT_REQUEST, NULL, NULL);
 	else
 		self->connect_pending = TRUE;
@@ -291,7 +287,7 @@
  */
 void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -306,7 +302,8 @@
  *    IrLMP for further processing
  *
  */
-inline void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb) 
+void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb,
+			   int unreliable) 
 {
 	/* Hide LAP header from IrLMP layer */
 	skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
@@ -315,43 +312,14 @@
 	if (self->qos_tx.compression.value) {
 		skb = irlap_decompress_frame(self, skb);
 		if (!skb) {
-			DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
+			IRDA_DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
 			return;
 		}
 	}
 #endif
-	irlmp_link_data_indication(self->notify.instance, LAP_RELIABLE, skb);
+	irlmp_link_data_indication(self->notify.instance, skb, unreliable);
 }
 
-/*
- * Function irlap_unit_data_indication (self, skb)
- *
- *    Received some data that was sent unreliable
- *
- */
-void irlap_unit_data_indication(struct irlap_cb *self, struct sk_buff *skb)
-{
-	DEBUG(1, __FUNCTION__ "()\n"); 
-
-	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);
-
-#ifdef CONFIG_IRDA_COMPRESSION
-	if (self->qos_tx.compression.value) {
-		
-		skb = irlap_decompress_frame(self, skb);
-		if (!skb) {
-			DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
-			return;
-		}
-	}
-#endif
-	irlmp_link_data_indication(self->notify.instance, LAP_UNRELIABLE, skb);
-}
 
 /*
  * Function irlap_data_request (self, skb)
@@ -359,23 +327,23 @@
  *    Queue data for transmission, must wait until XMIT state
  *
  */
-inline void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
-				int reliable)
+void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb, 
+			int unreliable)
 {
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
+
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 
 #ifdef CONFIG_IRDA_COMPRESSION
 	if (self->qos_tx.compression.value) {
 		skb = irlap_compress_frame(self, skb);
 		if (!skb) {
-			DEBUG(1, __FUNCTION__ "(), Compress error!\n");
+			IRDA_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);
@@ -384,12 +352,10 @@
 	 *  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)
-		skb->data[1] = I_FRAME;
-	else {
-		DEBUG(4, __FUNCTION__ "(), queueing unreliable frame\n");
+	if (unreliable)
 		skb->data[1] = UI_FRAME;
-	}
+	else
+		skb->data[1] = I_FRAME;
 
 	/* 
 	 *  Send event if this frame only if we are in the right state 
@@ -400,16 +366,65 @@
 		 *  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->txq)) {
+			skb_queue_tail(&self->txq, skb);
+			skb = skb_dequeue(&self->txq);
 			
 			ASSERT(skb != NULL, return;);
 		}
 		irlap_do_event(self, SEND_I_CMD, skb, NULL);
 	} else
-		skb_queue_tail(&self->tx_list, skb);	
+		skb_queue_tail(&self->txq, skb);
+}
+
+/*
+ * Function irlap_unitdata_request (self, skb)
+ *
+ *    Send Ultra data. This is data that must be sent outside any connection
+ *
+ */
+#ifdef CONFIG_IRDA_ULTRA
+void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb)
+{
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+
+	ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), 
+	       return;);
+	skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+
+	skb->data[0] = CBROADCAST;
+	skb->data[1] = UI_FRAME;
+
+	skb_queue_tail(&self->txq_ultra, skb);
+
+	irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
 }
+#endif /*CONFIG_IRDA_ULTRA */
+
+/*
+ * Function irlap_udata_indication (self, skb)
+ *
+ *    Receive Ultra data. This is data that is received outside any connection
+ *
+ */
+#ifdef CONFIG_IRDA_ULTRA
+void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
+{
+	IRDA_DEBUG(1, __FUNCTION__ "()\n"); 
+
+	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);
+
+	irlmp_link_unitdata_indication(self->notify.instance, skb);
+}
+#endif /* CONFIG_IRDA_ULTRA */
 
 /*
  * Function irlap_disconnect_request (void)
@@ -418,11 +433,19 @@
  */
 void irlap_disconnect_request(struct irlap_cb *self) 
 {
-	DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
 	
+	/* Don't disconnect until all data frames are successfully sent */
+	if (skb_queue_len(&self->txq) > 0) {
+		self->disconnect_pending = TRUE;
+		
+		return;
+	}
+
+	/* Check if we are in the right state for disconnecting */
 	switch (self->state) {
 	case LAP_XMIT_P:        /* FALLTROUGH */
 	case LAP_XMIT_S:        /* FALLTROUGH */
@@ -432,7 +455,7 @@
 		irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL);
 		break;
 	default:
-		DEBUG(0, __FUNCTION__ "(), disconnect pending!\n");
+		IRDA_DEBUG(2, __FUNCTION__ "(), disconnect pending!\n");
 		self->disconnect_pending = TRUE;
 		break;
 	}
@@ -446,7 +469,7 @@
  */
 void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) 
 {
-	DEBUG(1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); 
+	IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); 
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -457,21 +480,20 @@
 	/* Flush queues */
 	irlap_flush_all_queues(self);
 	
-	switch(reason) {
+	switch (reason) {
 	case LAP_RESET_INDICATION:
-		DEBUG(1, __FUNCTION__ "(), Sending reset request!\n");
+		IRDA_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, 
-						  self, reason, NULL);
+		irlmp_link_disconnect_indication(self->notify.instance, self, 
+						 reason, NULL);
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Reason %d not implemented!\n", 
-		       reason);
+		ERROR(__FUNCTION__ "(), Unknown reason %d\n", reason);
 	}
 }
 
@@ -489,49 +511,53 @@
 	ASSERT(self->magic == LAP_MAGIC, return;);
 	ASSERT(discovery != NULL, return;);
 	
-	DEBUG(4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
+	IRDA_DEBUG(4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
 
 	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);
-		
-		info.S = discovery->nslots; /* Number of slots */
-		info.s = 0; /* Current slot */
-		
-		self->discovery_cmd = discovery;
-		info.discovery = discovery;
-		
-		/* Check if the slot timeout is within limits */
-		if (sysctl_slot_timeout < 20) {
-			ERROR(__FUNCTION__ 
-			      "(), to low value for slot timeout!\n");
-			sysctl_slot_timeout = 20;
-		}
-		/* 
-		 * Highest value is actually 8, but we allow higher since
-		 * some devices seems to require it.
-		 */
-		if (sysctl_slot_timeout > 160) {
-			ERROR(__FUNCTION__ 
-			      "(), to high value for slot timeout!\n");
-			sysctl_slot_timeout = 160;
-		}
-
-		self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
-		
-		irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
-	} else { 
- 		DEBUG(4, __FUNCTION__ 
-		       "(), discovery only possible in NDM mode\n");
+  	/* Discovery is only possible in NDM mode */
+	if (self->state != LAP_NDM) {
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), discovery only possible in NDM mode\n");
 		irlap_discovery_confirm(self, NULL);
- 	} 
+		return;
+	}
+
+	/* Check if last discovery request finished in time */
+	if (self->discovery_log != NULL) {
+		hashbin_delete(self->discovery_log, (FREE_FUNC) kfree);
+		self->discovery_log = NULL;
+	}
+	
+	self->discovery_log= hashbin_new(HB_LOCAL);
+	
+	info.S = discovery->nslots; /* Number of slots */
+	info.s = 0; /* Current slot */
+	
+	self->discovery_cmd = discovery;
+	info.discovery = discovery;
+	
+	/* Check if the slot timeout is within limits */
+	if (sysctl_slot_timeout < 20) {
+		ERROR(__FUNCTION__ 
+		      "(), to low value for slot timeout!\n");
+		sysctl_slot_timeout = 20;
+	}
+	/* 
+	 * Highest value is actually 8, but we allow higher since
+	 * some devices seems to require it.
+	 */
+	if (sysctl_slot_timeout > 160) {
+		ERROR(__FUNCTION__ 
+		      "(), to high value for slot timeout!\n");
+		sysctl_slot_timeout = 160;
+	}
+	
+	self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
+	
+	irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
 }
 
 /*
@@ -552,16 +578,11 @@
 	 * the media busy condition (irlap p.94). This should allow us to make 
 	 * connection attempts much easier.
 	 */
-	if (discovery_log && hashbin_get_size(discovery_log) > 0)
-		irda_device_set_media_busy(self->irdev, FALSE);
+	if (discovery_log && HASHBIN_GET_SIZE(discovery_log) > 0)
+		irda_device_set_media_busy(self->netdev, FALSE);
 	
 	/* Inform IrLMP */
 	irlmp_link_discovery_confirm(self->notify.instance, discovery_log);
-	
-	/* 
-	 *  IrLMP has now the responsibilities for the discovery_log 
-	 */
-	self->discovery_log = NULL;
 }
 
 /*
@@ -572,7 +593,7 @@
  */
 void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -591,12 +612,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");
+		MESSAGE("IrLAP, no activity on link!\n");
 		break;
 	case STATUS_NOISY:
-		printk(KERN_INFO "IrLAP, noisy link!\n");
+		MESSAGE("IrLAP, noisy link!\n");
 		break;
 	default:
 		break;
@@ -612,7 +633,7 @@
  */
 void irlap_reset_indication(struct irlap_cb *self)
 {
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -631,7 +652,7 @@
  */
 void irlap_reset_confirm(void)
 {
- 	DEBUG(1, __FUNCTION__ "()\n");
+ 	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 }
 
 /*
@@ -666,16 +687,10 @@
 	struct sk_buff *skb = NULL;
 	int count = 0;
 
-	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);
-
 	/* 
 	 *  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
@@ -683,7 +698,7 @@
 	 */
 	if (nr == self->vs) {
 		while ((skb = skb_dequeue(&self->wx_list)) != NULL) {
-		     dev_kfree_skb(skb);
+			dev_kfree_skb(skb);
 		}
 		/* The last acked frame is the next to send minus one */
 		self->va = nr - 1;
@@ -698,10 +713,6 @@
 			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);
 	}
 	
 	/* Advance window */
@@ -715,20 +726,15 @@
  */
 int irlap_validate_ns_received(struct irlap_cb *self, int ns) 
 {
-	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)
 		return NS_EXPECTED;
-	}
 	/*
 	 *  Stations are allowed to treat invalid NS as unexpected NS
 	 *  IrLAP, Recv ... with-invalid-Ns. p. 84
 	 */
 	return NS_UNEXPECTED;
-
+	
 	/* return NR_INVALID; */
 }
 /*
@@ -739,12 +745,9 @@
  */
 int irlap_validate_nr_received(struct irlap_cb *self, int nr) 
 {
-	ASSERT(self != NULL, return -ENODEV;);
-	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
-
 	/*  nr as expected?  */
 	if (nr == self->vs) {
-		DEBUG(4, __FUNCTION__ "(), expected!\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), expected!\n");
 		return NR_EXPECTED;
 	}
 
@@ -772,7 +775,7 @@
  */
 void irlap_initiate_connection_state(struct irlap_cb *self) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -799,17 +802,16 @@
  */
 void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos) 
 {
-	int usecs;
-	int speed;
-	int bytes ;
+	__u32 min_turn_time;
+	__u32 speed;
 	
 	/* Get QoS values.  */
 	speed = qos->baud_rate.value;
-	usecs = qos->min_turn_time.value;
+	min_turn_time = qos->min_turn_time.value;
 
 	/* No need to calculate XBOFs for speeds over 115200 bps */
 	if (speed > 115200) {
-		self->mtt_required = usecs;
+		self->mtt_required = min_turn_time;
 		return;
 	}
 	
@@ -818,9 +820,7 @@
 	 *  min turn time, so now we must calculate how many chars (XBOF's) we 
 	 *  must send for the requested time period (min turn time)
 	 */
-	bytes = speed * usecs / 10000000;
-
-	self->xbofs_delay = bytes;
+	self->xbofs_delay = irlap_min_turn_time_in_bytes(speed, min_turn_time);
 }
 
 /*
@@ -837,9 +837,12 @@
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Free transmission queue */
-	while ((skb = skb_dequeue(&self->tx_list)) != NULL)
+	while ((skb = skb_dequeue(&self->txq)) != NULL)
 		dev_kfree_skb(skb);
 	
+	while ((skb = skb_dequeue(&self->txq_ultra)) != NULL)
+		dev_kfree_skb(skb);
+
 	/* Free sliding window buffered packets */
 	while ((skb = skb_dequeue(&self->wx_list)) != NULL)
 		dev_kfree_skb(skb);
@@ -858,22 +861,18 @@
  *    Change the speed of the IrDA port
  *
  */
-void irlap_change_speed(struct irlap_cb *self, int speed)
+void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now)
 {
-	DEBUG(4, __FUNCTION__ "(), setting speed to %d\n", speed);
+	IRDA_DEBUG(0, __FUNCTION__ "(), setting speed to %d\n", speed);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	if (!self->irdev) {
-		DEBUG(1, __FUNCTION__ "(), driver missing!\n");
-		return;
-	}
-
-	irda_device_change_speed(self->irdev, speed);
+	self->speed = speed;
 
-	self->qos_rx.baud_rate.value = speed;
-	self->qos_tx.baud_rate.value = speed;
+	/* Change speed now, or just piggyback speed on frames */
+	if (now)
+		irda_device_change_speed(self->netdev, speed);
 }
 
 #ifdef CONFIG_IRDA_COMPRESSION
@@ -885,33 +884,33 @@
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
-
+	
 	/* 
 	 *  Find out which compressors we support. We do this be checking that
 	 *  the corresponding compressor for each bit set in the QoS bits has 
 	 *  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", 
-	       self->qos_rx.compression.bits); 
+	IRDA_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);
+		IRDA_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);
+			IRDA_DEBUG(4, __FUNCTION__ 
+				   "(), bit %d is set by defalt\n", 8-i);
 			comp = hashbin_find(irlap_compressors, 
-					     compression[ msb_index(mask)], 
-					     NULL);
+					    compressions[msb_index(mask)], 
+					    NULL);
 			if (!comp) {
 				/* Protocol not supported, so clear the bit */
-				DEBUG(4, __FUNCTION__ "(), Compression "
-				       "protocol %d has not been loaded!\n", 
-				       compression[msb_index(mask)]);
+				IRDA_DEBUG(4, __FUNCTION__ "(), Compression "
+					   "protocol %d has not been loaded!\n", 
+					   compressions[msb_index(mask)]);
 				self->qos_rx.compression.bits &= ~mask;
-				DEBUG(4, __FUNCTION__ 
-				       "(), comp bits 0x%02x\n", 
-				       self->qos_rx.compression.bits); 
+				IRDA_DEBUG(4, __FUNCTION__ 
+					   "(), comp bits 0x%02x\n", 
+					   self->qos_rx.compression.bits); 
 			}
 		}
 		/* Try the next bit */
@@ -933,7 +932,7 @@
 {
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(self->irdev != NULL, return;);
+	ASSERT(self->netdev != NULL, return;);
 
 	/* Start out with the maximum QoS support possible */
 	irda_init_max_qos_capabilies(&self->qos_rx);
@@ -943,8 +942,7 @@
 #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, self->qos_dev);
 
 	/*
 	 *  Check for user supplied QoS parameters. The service user is only 
@@ -952,7 +950,7 @@
 	 *  user may not have set all of them.
 	 */
 	if (qos_user) {
-		DEBUG(1, __FUNCTION__ "(), Found user specified QoS!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Found user specified QoS!\n");
 
 		if (qos_user->baud_rate.bits)
 			self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
@@ -969,17 +967,11 @@
 #endif
 	}
 
-	/* 
-	 *  Make the intersection between IrLAP and drivers QoS
-	 *  capabilities 
-	 */
-
 	/* Use 500ms in IrLAP for now */
-	self->qos_rx.max_turn_time.bits &= 0x03;
 	self->qos_rx.max_turn_time.bits &= 0x01;
 
 	/* Set data size */
-	/* self->qos_rx.data_size.bits &= 0x03; */
+	/*self->qos_rx.data_size.bits &= 0x03;*/
 
 	/* Set disconnect time */
 	self->qos_rx.link_disc_time.bits &= 0x07;
@@ -995,28 +987,54 @@
  */
 void irlap_apply_default_connection_parameters(struct irlap_cb *self)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	irlap_change_speed(self, 9600);
+	irlap_change_speed(self, 9600, TRUE);
+
+	/* Set mbusy when going to NDM state */
+	irda_device_set_media_busy(self->netdev, TRUE);
 
 	/* Default value in NDM */
 	self->bofs_count = 11;
 
-	/* Use these until connection has been made */
+	/* 
+	 * Generate random connection address for this session, which must
+	 * be 7 bits wide and different from 0x00 and 0xfe 
+	 */
+	while ((self->caddr == 0x00) || (self->caddr == 0xfe)) {
+		get_random_bytes(&self->caddr, sizeof(self->caddr));
+		self->caddr &= 0xfe;
+	}
+
+	/* Use default values until connection has been negitiated */
 	self->slot_timeout = sysctl_slot_timeout;
 	self->final_timeout = FINAL_TIMEOUT;
 	self->poll_timeout = POLL_TIMEOUT;
 	self->wd_timeout = WD_TIMEOUT;
 
+	/* Set some default values */
+	self->qos_tx.baud_rate.value = 9600;
+	self->qos_rx.baud_rate.value = 9600;
+	self->qos_tx.max_turn_time.value = 0;
+	self->qos_rx.max_turn_time.value = 0;
+	self->qos_tx.min_turn_time.value = 0;
+	self->qos_rx.min_turn_time.value = 0;
 	self->qos_tx.data_size.value = 64;
+	self->qos_rx.data_size.value = 64;
+	self->qos_tx.window_size.value = 1;
+	self->qos_rx.window_size.value = 1;
 	self->qos_tx.additional_bofs.value = 11;
+	self->qos_rx.additional_bofs.value = 11;
+	self->qos_tx.link_disc_time.value = 0;
+	self->qos_rx.link_disc_time.value = 0;
 
 	irlap_flush_all_queues(self);
 
 	self->disconnect_pending = FALSE;
+	self->connect_pending = FALSE;
 }
 
 /*
@@ -1025,62 +1043,86 @@
  *    Initialize IrLAP with the negotiated QoS values
  *
  */
-void irlap_apply_connection_parameters(struct irlap_cb *self, 
-				       struct qos_info *qos) 
+void irlap_apply_connection_parameters(struct irlap_cb *self) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	irlap_change_speed(self, qos->baud_rate.value);
+	irlap_change_speed(self, self->qos_tx.baud_rate.value, FALSE);
 
-	self->window_size = qos->window_size.value;
-	self->window      = qos->window_size.value;
-	self->bofs_count  = qos->additional_bofs.value;
+	self->window_size = self->qos_tx.window_size.value;
+	self->window      = self->qos_tx.window_size.value;
+	self->bofs_count  = self->qos_tx.additional_bofs.value;
 
 	/*
 	 *  Calculate how many bytes it is possible to transmit before the
-	 *  link must be turned around wb = baud * mtt/1000 * 1/2
+	 *  link must be turned around
 	 */
-	self->window_bytes = qos->baud_rate.value 
-		* qos->max_turn_time.value / 10000;
-	DEBUG(4, "Setting window_bytes = %d\n", self->window_bytes);
-
+	self->line_capacity = 
+		irlap_max_line_capacity(self->qos_tx.baud_rate.value,
+					self->qos_tx.max_turn_time.value);
 	/*
 	 *  Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to 
 	 *  3 seconds otherwise. See page 71 in IrLAP for more details.
 	 *  TODO: these values should be calculated from the final timer
          *  as well
 	 */
-	if (qos->link_disc_time.value == 3)
+	ASSERT(self->qos_tx.max_turn_time.value != 0, return;);
+	if (self->qos_tx.link_disc_time.value == 3)
 		self->N1 = 0;
 	else
-		self->N1 = 3000 / qos->max_turn_time.value;
+		self->N1 = 3000 / self->qos_tx.max_turn_time.value;
+	
+	IRDA_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);
+	self->N2 = self->qos_tx.link_disc_time.value * 1000 / 
+		self->qos_tx.max_turn_time.value;
+	IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
 
 	/* 
 	 *  Initialize timeout values, some of the rules are listed on 
 	 *  page 92 in IrLAP.
 	 */
-	self->poll_timeout = qos->max_turn_time.value * HZ / 1000;
-	self->final_timeout = qos->max_turn_time.value * HZ / 1000;
+	self->poll_timeout = self->qos_tx.max_turn_time.value * HZ / 1000;
 	self->wd_timeout = self->poll_timeout * 2;
 
+	/* 
+	 * Be careful to keep our promises to the peer device about how long
+	 * time it can keep the pf bit. So here we must use the rx_qos value
+	 */
+	self->final_timeout = self->qos_rx.max_turn_time.value * HZ / 1000;
+
 #ifdef CONFIG_IRDA_COMPRESSION
-	if (qos->compression.value) {
-		DEBUG(1, __FUNCTION__ "(), Initializing compression\n");
-		irda_set_compression(self, qos->compression.value);
+	if (self->qos_tx.compression.value) {
+		IRDA_DEBUG(1, __FUNCTION__ "(), Initializing compression\n");
+		irda_set_compression(self, self->qos_tx.compression.value);
 
 		irlap_compressor_init(self, 0);
 	}
 #endif
 }
 
+/*
+ * Function irlap_set_local_busy (self, status)
+ *
+ *    
+ *
+ */
+void irlap_set_local_busy(struct irlap_cb *self, int status)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	self->local_busy = status;
+	
+	if (status)
+		IRDA_DEBUG(0, __FUNCTION__ "(), local busy ON\n");
+	else
+		IRDA_DEBUG(0, __FUNCTION__ "(), local busy OFF\n");
+}
+
 #ifdef CONFIG_PROC_FS
 /*
  * Function irlap_proc_read (buf, start, offset, len, unused)
@@ -1089,7 +1131,7 @@
  *
  */
 int irlap_proc_read(char *buf, char **start, off_t offset, int len, 
-		     int unused)
+		    int unused)
 {
 	struct irlap_cb *self;
 	unsigned long flags;
@@ -1105,27 +1147,30 @@
 		ASSERT(self != NULL, return -ENODEV;);
 		ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
 
-		len += sprintf(buf+len, "irlap%d <-> %s ",
-				i++, self->irdev->name);
+		len += sprintf(buf+len, "irlap%d ", i++);
 		len += sprintf(buf+len, "state: %s\n", 
-				irlap_state[ self->state]);
+			       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, "  win size: %d, ", 
-				self->window_size);
+			       self->window_size);
 		len += sprintf(buf+len, "win: %d, ", self->window);
-		len += sprintf(buf+len, "win bytes: %d, ", self->window_bytes);
+#if CONFIG_IRDA_DYNAMIC_WINDOW
+		len += sprintf(buf+len, "line capacity: %d, ", 
+			       self->line_capacity);
 		len += sprintf(buf+len, "bytes left: %d\n", self->bytes_left);
-
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 		len += sprintf(buf+len, "  tx queue len: %d ", 
-				skb_queue_len(&self->tx_list));
+			       skb_queue_len(&self->txq));
 		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");
+			       skb_queue_len(&self->wx_list));
+		len += sprintf(buf+len, "rbusy: %s", self->remote_busy ?
+			       "TRUE" : "FALSE");
+		len += sprintf(buf+len, " mbusy: %s\n", self->media_busy ?
+			       "TRUE" : "FALSE");
 		
 		len += sprintf(buf+len, "  retrans: %d ", self->retry_count);
 		len += sprintf(buf+len, "vs: %d ", self->vs);
@@ -1135,42 +1180,42 @@
 		len += sprintf(buf+len, "  qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
 		
 		len += sprintf(buf+len, "  tx\t%d\t", 
-				self->qos_tx.baud_rate.value);
+			       self->qos_tx.baud_rate.value);
 		len += sprintf(buf+len, "%d\t", 
-				self->qos_tx.max_turn_time.value);
+			       self->qos_tx.max_turn_time.value);
 		len += sprintf(buf+len, "%d\t",
-				self->qos_tx.data_size.value);
+			       self->qos_tx.data_size.value);
 		len += sprintf(buf+len, "%d\t",
-				self->qos_tx.window_size.value);
+			       self->qos_tx.window_size.value);
 		len += sprintf(buf+len, "%d\t",
-				self->qos_tx.additional_bofs.value);
+			       self->qos_tx.additional_bofs.value);
 		len += sprintf(buf+len, "%d\t", 
-				self->qos_tx.min_turn_time.value);
+			       self->qos_tx.min_turn_time.value);
 		len += sprintf(buf+len, "%d\t", 
-				self->qos_tx.link_disc_time.value);
+			       self->qos_tx.link_disc_time.value);
 #ifdef CONFIG_IRDA_COMPRESSION
 		len += sprintf(buf+len, "%d",
-				self->qos_tx.compression.value);
+			       self->qos_tx.compression.value);
 #endif
 		len += sprintf(buf+len, "\n");
 
 		len += sprintf(buf+len, "  rx\t%d\t", 
-				self->qos_rx.baud_rate.value);
+			       self->qos_rx.baud_rate.value);
 		len += sprintf(buf+len, "%d\t", 
-				self->qos_rx.max_turn_time.value);
+			       self->qos_rx.max_turn_time.value);
 		len += sprintf(buf+len, "%d\t",
-				self->qos_rx.data_size.value);
+			       self->qos_rx.data_size.value);
 		len += sprintf(buf+len, "%d\t",
-				self->qos_rx.window_size.value);
+			       self->qos_rx.window_size.value);
 		len += sprintf(buf+len, "%d\t",
-				self->qos_rx.additional_bofs.value);
+			       self->qos_rx.additional_bofs.value);
 		len += sprintf(buf+len, "%d\t", 
-				self->qos_rx.min_turn_time.value);
+			       self->qos_rx.min_turn_time.value);
 		len += sprintf(buf+len, "%d\t", 
-				self->qos_rx.link_disc_time.value);
+			       self->qos_rx.link_disc_time.value);
 #ifdef CONFIG_IRDA_COMPRESSION
 		len += sprintf(buf+len, "%d",
-				self->qos_rx.compression.value);
+			       self->qos_rx.compression.value);
 #endif
 		len += sprintf(buf+len, "\n");
 		
diff -urN linux-2.2.15-pre2/net/irda/irlap_comp.c linux/net/irda/irlap_comp.c
--- linux-2.2.15-pre2/net/irda/irlap_comp.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irlap_comp.c	Mon Dec  3 21:57:53 2001
@@ -6,8 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Oct  9 09:18:07 1998
- * Modified at:   Sun May  9 11:37:06 1999
+ * Modified at:   Tue Oct  5 11:34:52 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * Modified at:   Fri May 28  3:11 CST 1999
+ * Modified by:   Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
  * Sources:       ppp.c, isdn_ppp.c
  * 
  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -23,6 +25,8 @@
  *     
  ********************************************************************/
 
+#include <linux/string.h>
+
 #include <net/irda/irda.h>
 #include <net/irda/irqueue.h>
 #include <net/irda/irlap.h>
@@ -41,11 +45,11 @@
 {
 	struct irda_compressor *new;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
 	/* Check if this compressor has been registred before */
 	if ( hashbin_find ( irlap_compressors, cp->compress_proto, NULL)) {
-		DEBUG( 0, __FUNCTION__ "(), Compressor already registered\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Compressor already registered\n");
                 return 0;
         }
 	
@@ -59,7 +63,7 @@
         new->cp = cp;
 
 	/* Insert IrDA compressor into hashbin */
-	hashbin_insert( irlap_compressors, (QUEUE *) new, cp->compress_proto,
+	hashbin_insert( irlap_compressors, (queue_t *) new, cp->compress_proto,
 			NULL);
 	
         return 0;
@@ -75,11 +79,11 @@
 {
 	struct irda_compressor *node;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
 	node = hashbin_remove( irlap_compressors, cp->compress_proto, NULL);
 	if ( !node) {
-		DEBUG( 0, __FUNCTION__ "(), compressor not found!\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), compressor not found!\n");
 		return;
 	}	
 	kfree( node);
@@ -98,7 +102,7 @@
 
 	__u8 options[CILEN_DEFLATE];
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
 	ASSERT( self != NULL, return -ENODEV;);
 	ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
@@ -111,7 +115,7 @@
 
 	comp = hashbin_find( irlap_compressors, proto, NULL);
 	if ( !comp) {
-		DEBUG( 0, __FUNCTION__ "(), Unable to find compressor\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Unable to find compressor\n");
 		return -1;
 	}
 
@@ -126,7 +130,7 @@
 	self->compressor.cp = cp;
 	self->compressor.state = cp->comp_alloc( options, sizeof( options));
 	if ( self->compressor.state == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Failed!\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Failed!\n");
 		return -ENOBUFS;
 	}
 
@@ -141,7 +145,7 @@
 	self->decompressor.cp = cp;
 	self->decompressor.state = cp->decomp_alloc( options, sizeof( options));
 	if ( self->decompressor.state == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), Failed!\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Failed!\n");
 		return -ENOBUFS;
 	}
 	return 0;
@@ -155,7 +159,7 @@
  */
 void irda_free_compression( struct irlap_cb *self)
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
 	if ( self->compressor.state) {
 		irda_comp_free( self->compressor.state);
@@ -179,7 +183,7 @@
 	int debug = TRUE;
 	__u8 options[CILEN_DEFLATE];
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT( self != NULL, return;);
 	ASSERT( self->magic == LAP_MAGIC, return;);
@@ -194,7 +198,7 @@
 	 *  We're agreeing to send compressed packets.
 	 */
 	if ( self->compressor.state == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), state == NULL\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), state == NULL\n");
 		return;
 	}
 	
@@ -202,7 +206,7 @@
 					       options, sizeof( options),
 					       0, 0, debug)) 
 	{
-		DEBUG( 0, __FUNCTION__ "(), Compressor running!\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Compressor running!\n");
 		/* ppp->flags |= SC_COMP_RUN; */
 	}
 	
@@ -210,7 +214,7 @@
 	 *  Initialize decompressor
 	 */
 	if ( self->decompressor.state == NULL) {
-		DEBUG( 0, __FUNCTION__ "(), state == NULL\n");
+		IRDA_DEBUG( 0, __FUNCTION__ "(), state == NULL\n");
 		return;
 	}
 	
@@ -218,7 +222,7 @@
 						   options, sizeof( options),
 						   0, 0, 0, debug)) 
 	{
-		DEBUG( 0, __FUNCTION__ "(), Decompressor running!\n");	
+		IRDA_DEBUG( 0, __FUNCTION__ "(), Decompressor running!\n");	
 		
 		/* ppp->flags |= SC_DECOMP_RUN; */
 		/* ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR); */
@@ -239,7 +243,7 @@
 	
 	ASSERT( skb != NULL, return NULL;);
 	
-	DEBUG(4, __FUNCTION__ "() skb->len=%d, jiffies=%ld\n", (int) skb->len,
+	IRDA_DEBUG(4, __FUNCTION__ "() skb->len=%d, jiffies=%ld\n", (int) skb->len,
 	      jiffies);
 
 	ASSERT( self != NULL, return NULL;);
@@ -266,7 +270,7 @@
 						 skb->data, new_skb->data, 
 						 skb->len, new_skb->len);
 	if( count <= 0) {
-		DEBUG(4, __FUNCTION__ "(), Unable to compress frame!\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), Unable to compress frame!\n");
 		dev_kfree_skb( new_skb);
 
 		/* Tell peer that this frame is not compressed */
@@ -283,7 +287,7 @@
 
 	dev_kfree_skb( skb);
 	
-	DEBUG(4, __FUNCTION__ "() new_skb->len=%d\n, jiffies=%ld", 
+	IRDA_DEBUG(4, __FUNCTION__ "() new_skb->len=%d\n, jiffies=%ld", 
 	      (int) new_skb->len, jiffies);
 	
 	return new_skb;
@@ -301,7 +305,7 @@
 	struct sk_buff *new_skb;
 	int count;
 
-	DEBUG( 4, __FUNCTION__ "() skb->len=%d\n", (int) skb->len);
+	IRDA_DEBUG( 4, __FUNCTION__ "() skb->len=%d\n", (int) skb->len);
 
 	ASSERT( self != NULL, return NULL;);
 	ASSERT( self->magic == LAP_MAGIC, return NULL;);
@@ -335,7 +339,7 @@
 	count = irda_decompress( self->decompressor.state, skb->data, 
 				 skb->len, new_skb->data, new_skb->len);
 	if ( count <= 0) {
-		DEBUG( 4, __FUNCTION__ "(), Unable to decompress frame!\n");
+		IRDA_DEBUG( 4, __FUNCTION__ "(), Unable to decompress frame!\n");
 		
 		dev_kfree_skb( new_skb);
 		return skb;
@@ -343,7 +347,7 @@
 
 	skb_trim( new_skb, count);
 	
-	DEBUG( 4, __FUNCTION__ "() new_skb->len=%d\n", (int) new_skb->len);
+	IRDA_DEBUG( 4, __FUNCTION__ "() new_skb->len=%d\n", (int) new_skb->len);
 
 	return new_skb;
 }
diff -urN linux-2.2.15-pre2/net/irda/irlap_event.c linux/net/irda/irlap_event.c
--- linux-2.2.15-pre2/net/irda/irlap_event.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlap_event.c	Mon Dec  3 21:57:53 2001
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      irlap_event.c
- * Version:       0.8
+ * Version:       0.9
  * Description:   IrLAP state machine implementation
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Mon May 31 21:55:42 1999
+ * Modified at:   Mon Jan 17 09:07:36 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
  *                        Thomas Davis <ratbert@radiks.net>
  *     All Rights Reserved.
  *     
@@ -37,11 +37,12 @@
 #include <net/irda/irlap.h>
 #include <net/irda/irlap_frame.h>
 #include <net/irda/qos.h>
+#include <net/irda/parameters.h>
 
 #include <net/irda/irda_device.h>
 
 #if CONFIG_IRDA_FAST_RR
-int sysctl_fast_poll_increase = 50;
+int sysctl_fast_poll_increase = 10;
 #endif
 
 static int irlap_state_ndm    (struct irlap_cb *self, IRLAP_EVENT event, 
@@ -84,6 +85,7 @@
 	"RESET_REQUEST",
 	"RESET_RESPONSE",
 	"SEND_I_CMD",
+	"SEND_UI_FRAME",
 	"RECV_DISCOVERY_XID_CMD",
 	"RECV_DISCOVERY_XID_RSP",
 	"RECV_SNRM_CMD",
@@ -91,14 +93,20 @@
 	"RECV_TEST_RSP",
 	"RECV_UA_RSP",
 	"RECV_DM_RSP",
+	"RECV_RD_RSP",
 	"RECV_I_CMD",
 	"RECV_I_RSP",
 	"RECV_UI_FRAME",
 	"RECV_FRMR_RSP",
 	"RECV_RR_CMD",
 	"RECV_RR_RSP",
-	"RECV_RNR_FRAME",
-	"RECV_DISC_FRAME",
+	"RECV_RNR_CMD",
+	"RECV_RNR_RSP",
+	"RECV_REJ_CMD",
+	"RECV_REJ_RSP",
+	"RECV_SREJ_CMD",
+	"RECV_SREJ_RSP",
+	"RECV_DISC_CMD",
 	"SLOT_TIMER_EXPIRED",
 	"QUERY_TIMER_EXPIRED",
 	"FINAL_TIMER_EXPIRED",
@@ -126,9 +134,9 @@
 	"LAP_RESET_CHECK",
 };
 
-static int (*state[])( struct irlap_cb *self, IRLAP_EVENT event, 
-		       struct sk_buff *skb, struct irlap_info *info) = 
-{ 
+static int (*state[])(struct irlap_cb *self, IRLAP_EVENT event, 
+		      struct sk_buff *skb, struct irlap_info *info) = 
+{
 	irlap_state_ndm,
 	irlap_state_query,
 	irlap_state_reply,
@@ -152,7 +160,7 @@
  *    Poll timer has expired. Normally we must now send a RR frame to the
  *    remote device
  */
-static void irlap_poll_timer_expired(unsigned long data)
+static void irlap_poll_timer_expired(void *data)
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 	
@@ -168,7 +176,11 @@
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
 #ifdef CONFIG_IRDA_FAST_RR
-	if (skb_queue_len(&self->tx_list) == 0) {
+	/* 
+	 * Send out the RR frames faster if our own transmit queue is empty, or
+	 * if the peer is busy. The effect is a much faster conversation
+	 */
+	if ((skb_queue_len(&self->txq) == 0) || (self->remote_busy)) {
 		if (self->fast_RR == TRUE) {
 			/*
 			 *  Assert that the fast poll timer has not reached the
@@ -179,7 +191,7 @@
 				 *  FIXME: this should be a more configurable
 				 *         function
 				 */
-				self->fast_RR_timeout += (sysctl_fast_poll_increase * HZ/1000);
+				self->fast_RR_timeout += MSECS_TO_JIFFIES(sysctl_fast_poll_increase);
 
 				/* Use this fast(er) timeout instead */
 				timeout = self->fast_RR_timeout;
@@ -194,13 +206,14 @@
 	} else
 		self->fast_RR = FALSE;
 
-	DEBUG(4, __FUNCTION__ "(), Timeout=%d\n", timeout);
-#endif
+	IRDA_DEBUG(3, __FUNCTION__ "(), timeout=%d (%ld)\n", timeout, jiffies);
+#endif /* CONFIG_IRDA_FAST_RR */
+
 	if (timeout == 0)
 		irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
 	else
-		irda_start_timer(&self->poll_timer, timeout, 
-				 (unsigned long) self, irlap_poll_timer_expired);
+		irda_start_timer(&self->poll_timer, timeout, self, 
+				 irlap_poll_timer_expired);
 }
 
 /*
@@ -217,11 +230,11 @@
 	if (!self || self->magic != LAP_MAGIC)
 		return;
 	
-  	DEBUG(4, __FUNCTION__ "(), event = %s, state = %s\n", 
-	      irlap_event[event], irlap_state[self->state]); 
-	
-	ret = (*state[ self->state]) (self, event, skb, info);
+  	IRDA_DEBUG(3, __FUNCTION__ "(), event = %s, state = %s\n", 
+		   irlap_event[event], irlap_state[self->state]); 
 	
+	ret = (*state[self->state])(self, event, skb, info);
+
 	/* 
 	 *  Check if there are any pending events that needs to be executed
 	 */
@@ -233,12 +246,12 @@
 		 * try to disconnect link if we send any data frames, since
 		 * that will change the state away form XMIT
 		 */
-		if (skb_queue_len(&self->tx_list)) {
+		if (skb_queue_len(&self->txq)) {
 			/* Try to send away all queued data frames */
-			while ((skb = skb_dequeue(&self->tx_list)) != NULL) {
+			while ((skb = skb_dequeue(&self->txq)) != NULL) {
 				ret = (*state[self->state])(self, SEND_I_CMD,
 							    skb, NULL);
-				if ( ret == -EPROTO)
+				if (ret == -EPROTO)
 					break; /* Try again later! */
 			}
 		} else if (self->disconnect_pending) {
@@ -250,9 +263,7 @@
 		break;
 	case LAP_NDM:
 		/* Check if we should try to connect */
-		if ((self->connect_pending) && 
-		    !irda_device_is_media_busy(self->irdev)) 
-		{
+		if ((self->connect_pending) && !self->media_busy) {
 			self->connect_pending = FALSE;
 			
 			ret = (*state[self->state])(self, CONNECT_REQUEST, 
@@ -278,10 +289,11 @@
 	if (!self || self->magic != LAP_MAGIC)
 		return;
 	
-	DEBUG(4, "next LAP state = %s\n", irlap_state[ state]);
+	IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]);
 
 	self->state = state;
 
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
 	/*
 	 *  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 
@@ -289,7 +301,8 @@
 	 *  we cannot do this when swithing into the XMIT state :-)
 	 */
 	if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S))
-		self->bytes_left = self->window_bytes;
+		self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 }
 
 /*
@@ -298,59 +311,60 @@
  *    NDM (Normal Disconnected Mode) state
  *
  */
-static int irlap_state_ndm( struct irlap_cb *self, IRLAP_EVENT event, 
-			    struct sk_buff *skb,  struct irlap_info *info) 
+static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, 
+			   struct sk_buff *skb, struct irlap_info *info) 
 {
 	discovery_t *discovery_rsp;
 	int ret = 0;
-	
-	DEBUG( 4, __FUNCTION__ "()\n");
-	
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	int i;
 
-	switch(event) {
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
+
+	switch (event) {
 	case CONNECT_REQUEST:
-		ASSERT( self->irdev != NULL, return -1;);
+		ASSERT(self->netdev != NULL, return -1;);
 
-		if (irda_device_is_media_busy(self->irdev)) {
-			DEBUG( 0, __FUNCTION__
-			      "(), CONNECT_REQUEST: media busy!\n");
+		if (self->media_busy) {
+			IRDA_DEBUG(0, __FUNCTION__
+				   "(), CONNECT_REQUEST: media busy!\n");
 			
 			/* Always switch state before calling upper layers */
-			irlap_next_state( self, LAP_NDM);
+			irlap_next_state(self, LAP_NDM);
 			
-			irlap_disconnect_indication( self, LAP_MEDIA_BUSY);
+			irlap_disconnect_indication(self, LAP_MEDIA_BUSY);
 		} else {
-			irlap_send_snrm_frame( self, &self->qos_rx);
+			irlap_send_snrm_frame(self, &self->qos_rx);
 			
 			/* Start Final-bit timer */
 			irlap_start_final_timer(self, self->final_timeout);
 
 			self->retry_count = 0;
-			irlap_next_state( self, LAP_SETUP);
+			irlap_next_state(self, LAP_SETUP);
 		}
 		break;
-
 	case RECV_SNRM_CMD:
-		self->daddr = info->daddr;
-		self->caddr = info->caddr;
-		
-		irlap_next_state( self, LAP_CONN);
-
-		irlap_connect_indication( self, skb);
+		/* Check if the frame contains and I field */
+		if (info) {		       
+			self->daddr = info->daddr;
+			self->caddr = info->caddr;
+			
+			irlap_next_state(self, LAP_CONN);
+			
+			irlap_connect_indication(self, skb);
+		} else {
+			IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame does not "
+				   "contain an I field!\n");
+			dev_kfree_skb(skb);
+		}
 		break;
-
 	case DISCOVERY_REQUEST:		
-		ASSERT( info != NULL, return -1;);
+		ASSERT(info != NULL, return -1;);
 
-	 	if (irda_device_is_media_busy(self->irdev)) {
- 			DEBUG(0, __FUNCTION__ "(), media busy!\n"); 
+	 	if (self->media_busy) {
+ 			IRDA_DEBUG(0, __FUNCTION__ "(), media busy!\n"); 
 			/* irlap->log.condition = MEDIA_BUSY; */
-			
-			/* Always switch state before calling upper layers */
-			irlap_next_state(self, LAP_NDM); 
-			
+						
 			/* This will make IrLMP try again */
  			irlap_discovery_confirm(self, NULL);
 			return 0;
@@ -365,22 +379,21 @@
 		irlap_start_slot_timer(self, self->slot_timeout);
 		irlap_next_state(self, LAP_QUERY);
 		break;
-
 	case RECV_DISCOVERY_XID_CMD:
-		ASSERT( info != NULL, return -1;);
+		ASSERT(info != NULL, return -1;);
 
 		/* Assert that this is not the final slot */
-		if ( info->s <= info->S) {
+		if (info->s <= info->S) {
 			/* self->daddr = info->daddr;  */
 			self->slot = irlap_generate_rand_time_slot(info->S,
 								   info->s);
-			DEBUG( 4, "XID_CMD: S=%d, s=%d, slot %d\n", info->S, 
-			       info->s, self->slot);
+			IRDA_DEBUG(4, "XID_CMD: S=%d, s=%d, slot %d\n", info->S, 
+			      info->s, self->slot);
 
-			if ( self->slot == info->s) {
+			if (self->slot == info->s) {
 				discovery_rsp = irlmp_get_discovery_response();
 				discovery_rsp->daddr = info->daddr;
-
+				
 				irlap_send_discovery_xid_frame(self, info->S, 
 							       self->slot, 
 							       FALSE,
@@ -389,24 +402,63 @@
 			} else
 				self->frame_sent = FALSE;
 			
-			irlap_start_query_timer( self, QUERY_TIMEOUT);
-			irlap_next_state( self, LAP_REPLY);
+			/* 
+			 * Remember to multiply the query timeout value with 
+			 * the number of slots used
+			 */
+			irlap_start_query_timer(self, QUERY_TIMEOUT*info->S);
+			irlap_next_state(self, LAP_REPLY);
 		}
 		dev_kfree_skb(skb);
 		break;
-
+#ifdef CONFIG_IRDA_ULTRA
+	case SEND_UI_FRAME:
+		/* Only allowed to repeat an operation twice */
+		for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) {
+			skb = skb_dequeue(&self->txq_ultra);
+			if (skb)			
+				irlap_send_ui_frame(self, skb, CBROADCAST, 
+						    CMD_FRAME);
+			else
+				break;
+		}
+		if (i == 2) {
+			/* Force us to listen 500 ms again */
+			irda_device_set_media_busy(self->netdev, TRUE);
+		}
+		break;
+	case RECV_UI_FRAME:
+		/* Only accept broadcast frames in NDM mode */
+		if (info->caddr != CBROADCAST) {
+			IRDA_DEBUG(0, __FUNCTION__ 
+				   "(), not a broadcast frame!\n");
+			dev_kfree_skb(skb);
+		} else
+			irlap_unitdata_indication(self, skb);
+		break;
+#endif /* CONFIG_IRDA_ULTRA */
 	case RECV_TEST_CMD:
+		/* Remove test frame header */
 		skb_pull(skb, sizeof(struct test_frame));
-		irlap_send_test_frame(self, info->daddr, skb);
+
+		/* 
+		 * Send response. This skb will not be sent out again, and
+		 * will only be used to send out the same info as the cmd
+		 */
+		irlap_send_test_frame(self, CBROADCAST, info->daddr, skb);
 		dev_kfree_skb(skb);
 		break;
 	case RECV_TEST_RSP:
-		DEBUG(0, __FUNCTION__ "() not implemented!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "() not implemented!\n");
 		dev_kfree_skb(skb);
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %s", 
-		      irlap_event[event]);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlap_event[event]);
+		
+		if (skb)
+			dev_kfree_skb(skb);
+
 		ret = -1;
 		break;
 	}	
@@ -419,30 +471,37 @@
  *    QUERY state
  *
  */
-static int irlap_state_query( struct irlap_cb *self, IRLAP_EVENT event, 
-			      struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event, 
+			     struct sk_buff *skb, struct irlap_info *info) 
 {
 	int ret = 0;
 
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-	switch( event) {
+	switch (event) {
 	case RECV_DISCOVERY_XID_RSP:
-		ASSERT( info != NULL, return -1;);
-		ASSERT( info->discovery != NULL, return -1;);
-
-		DEBUG(4, __FUNCTION__ "(), daddr=%08x\n", 
-		      info->discovery->daddr);
+		ASSERT(info != NULL, return -1;);
+		ASSERT(info->discovery != NULL, return -1;);
 
-		hashbin_insert( self->discovery_log, 
-				(QUEUE *) info->discovery,
-				info->discovery->daddr, NULL);
+		IRDA_DEBUG(4, __FUNCTION__ "(), daddr=%08x\n", 
+			   info->discovery->daddr);
 
-		dev_kfree_skb(skb);
+		if (!self->discovery_log) {
+			WARNING(__FUNCTION__ "(), discovery log is gone! "
+				"maybe the discovery timeout has been set to "
+				"short?\n");
+			dev_kfree_skb(skb);
+			break;
+		}
+		hashbin_insert(self->discovery_log, 
+			       (queue_t *) info->discovery,
+			       info->discovery->daddr, NULL);
 
 		/* Keep state */
-		irlap_next_state( self, LAP_QUERY); 
+		/* irlap_next_state(self, LAP_QUERY);  */
+
+		dev_kfree_skb(skb);
 		break;
 	case SLOT_TIMER_EXPIRED:
 		if (self->s < self->S) {
@@ -468,14 +527,17 @@
 			 *  so now we must return the results
 			 */
 			irlap_discovery_confirm(self, self->discovery_log);
+
+			/* IrLMP should now have taken care of the log */
+			self->discovery_log = NULL;
 		}
 		break;
 	default:
-		DEBUG(2, __FUNCTION__ "(), Unknown event %d, %s\n", event, 
-		      irlap_event[event]);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlap_event[event]);
 
 		if (skb)
-			dev_kfree_skb( skb);
+			dev_kfree_skb(skb);
 
 		ret = -1;
 		break;
@@ -496,14 +558,14 @@
 	discovery_t *discovery_rsp;
 	int ret=0;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-	switch(event) {
+	switch (event) {
 	case QUERY_TIMER_EXPIRED:
-		DEBUG(2, __FUNCTION__ "(), QUERY_TIMER_EXPIRED <%ld>\n",
+		IRDA_DEBUG(2, __FUNCTION__ "(), QUERY_TIMER_EXPIRED <%ld>\n",
 		      jiffies);
 		irlap_next_state(self, LAP_NDM);
 		break;
@@ -535,11 +597,10 @@
 		dev_kfree_skb(skb);
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
-		      irlap_event[event]);
-
-		if ( skb)
-			dev_kfree_skb( skb);
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
+			   irlap_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
 		
 		ret = -1;
 		break;
@@ -559,28 +620,40 @@
 {
 	int ret = 0;
 
-	DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
+	IRDA_DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LAP_MAGIC, return -1;);
 
 	switch (event) {
 	case CONNECT_RESPONSE:
-		/* 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->netdev != NULL, return -1;);
 
-		irlap_initiate_connection_state( self);
+		irlap_qos_negotiate(self, skb);
 
-		/*
-		 * We are allowed to send two frames!
+		irlap_initiate_connection_state(self);
+
+#if 0
+		/* 
+		 * We are allowed to send two frames, but this may increase
+		 * the connect latency, so lets not do it for now.
 		 */
 		irlap_send_ua_response_frame(self, &self->qos_rx);
+#endif
+
+		/* 
+		 * Applying the parameters now will make sure we change speed
+		 * after we have sent the next frame
+		 */
+		irlap_apply_connection_parameters(self);
+
+		/* 
+		 * Sending this frame will force a speed change after it has
+		 * been sent
+		 */
 		irlap_send_ua_response_frame(self, &self->qos_rx);
-		
-		irlap_apply_connection_parameters(self, &self->qos_tx);
 
 		/*
 		 *  The WD-timer could be set to the duration of the P-timer 
@@ -588,29 +661,27 @@
 		 *  value (note 3 IrLAP p. 60). 
 		 */
 		irlap_start_wd_timer(self, self->wd_timeout);
-		irlap_next_state( self, LAP_NRM_S);
-		break;
+		irlap_next_state(self, LAP_NRM_S);
 
-	case RECV_SNRM_CMD:
-		DEBUG( 3, __FUNCTION__ "(), event RECV_SNRM_CMD!\n");
-#if 0
-		irlap_next_state( self, LAP_NDM);
-#endif
+		dev_kfree_skb(skb);
 		break;
-		
 	case RECV_DISCOVERY_XID_CMD:
-		DEBUG( 3, __FUNCTION__ "(), event RECV_DISCOVER_XID_CMD!\n");
-		irlap_next_state( self, LAP_NDM);
-		break;
-		
+		IRDA_DEBUG(3, __FUNCTION__ 
+			   "(), event RECV_DISCOVER_XID_CMD!\n");
+		irlap_next_state(self, LAP_NDM);
+
+		dev_kfree_skb(skb);
+		break;		
 	case DISCONNECT_REQUEST:
-		irlap_send_dm_frame( self);
+		irlap_send_dm_frame(self);
 		irlap_next_state( self, LAP_CONN);
 		break;
-
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event, 
-		      irlap_event[event]);
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
+			   irlap_event[event]);		
+		if (skb)
+			dev_kfree_skb(skb);
+
 		ret = -1;
 		break;
 	}
@@ -625,60 +696,63 @@
  *    a remote peer layer and is awaiting a reply .
  *
  */
-static int irlap_state_setup( struct irlap_cb *self, IRLAP_EVENT event, 
-			      struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event, 
+			     struct sk_buff *skb, struct irlap_info *info) 
 {
 	int ret = 0;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-	switch( event) {
+	switch (event) {
 	case FINAL_TIMER_EXPIRED:
-		if ( self->retry_count < self->N3) {
+		if (self->retry_count < self->N3) {
 /* 
  *  Perform random backoff, Wait a random number of time units, minimum 
  *  duration half the time taken to transmitt a SNRM frame, maximum duration 
  *  1.5 times the time taken to transmit a SNRM frame. So this time should 
  *  between 15 msecs and 45 msecs.
  */
-			irlap_start_backoff_timer( self, 2 + (jiffies % 3));
+			irlap_start_backoff_timer(self, MSECS_TO_JIFFIES(20 + 
+						        (jiffies % 30)));
 		} else {
 			/* Always switch state before calling upper layers */
-			irlap_next_state( self, LAP_NDM);
+			irlap_next_state(self, LAP_NDM);
 
-			irlap_disconnect_indication( self, LAP_FOUND_NONE);
+			irlap_disconnect_indication(self, LAP_FOUND_NONE);
 		}
 		break;
 	case BACKOFF_TIMER_EXPIRED:
-		irlap_send_snrm_frame( self, &self->qos_rx);
-		irlap_start_final_timer( self, self->final_timeout);
+		irlap_send_snrm_frame(self, &self->qos_rx);
+		irlap_start_final_timer(self, self->final_timeout);
 		self->retry_count++;
 		break;
-
 	case RECV_SNRM_CMD:
-		DEBUG( 4, __FUNCTION__ "(), SNRM battle!\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), SNRM battle!\n");
 
-		ASSERT( skb != NULL, return 0;);
-		ASSERT( info != NULL, return 0;);
+		ASSERT(skb != NULL, return 0;);
+		ASSERT(info != NULL, return 0;);
 
 		/*
 		 *  The device with the largest device address wins the battle
 		 *  (both have sent a SNRM command!)
 		 */
-		if (info->daddr > self->saddr) {
+		if (info &&(info->daddr > self->saddr)) {
 			del_timer(&self->final_timer);
 			irlap_initiate_connection_state(self);
 
-			ASSERT(self->irdev != NULL, return -1;);
-			/* skb_pull(skb, 11); */
+			ASSERT(self->netdev != NULL, return -1;);
+
 			skb_pull(skb, sizeof(struct snrm_frame));
-			irda_qos_negotiate(&self->qos_rx, &self->qos_tx, skb);
+
+			irlap_qos_negotiate(self, skb);
 			
 			irlap_send_ua_response_frame(self, &self->qos_rx);
-			irlap_apply_connection_parameters(self, &self->qos_tx);
+			irlap_apply_connection_parameters(self);
+
+			irlap_next_state(self, LAP_NRM_S);
 			irlap_connect_confirm(self, skb);
 			
 			/* 
@@ -687,51 +761,53 @@
 			 *  to use twice the value (note 3 IrLAP p. 60).  
 			 */
 			irlap_start_wd_timer(self, self->wd_timeout);
-			
-			irlap_next_state(self, LAP_NRM_S);
 		} else {
 			/* We just ignore the other device! */
+			dev_kfree_skb(skb);
 			irlap_next_state(self, LAP_SETUP);
 		}
 		break;
 	case RECV_UA_RSP:
 		/* Stop F-timer */
-		del_timer( &self->final_timer);
+		del_timer(&self->final_timer);
 
 		/* Initiate connection state */
-		irlap_initiate_connection_state( self);
+		irlap_initiate_connection_state(self);
 
 		/* Negotiate connection parameters */
-		ASSERT( skb->len > 10, return -1;);
-		/* skb_pull(skb, 10); */
+		ASSERT(skb->len > 10, return -1;);
+
 		skb_pull(skb, sizeof(struct ua_frame));
 
-		ASSERT(self->irdev != NULL, return -1;);
-		irda_qos_negotiate( &self->qos_rx, &self->qos_tx, skb);
+		ASSERT(self->netdev != NULL, return -1;);
+
+		irlap_qos_negotiate(self, skb);
 
-		irlap_apply_connection_parameters( self, &self->qos_tx); 
+		irlap_apply_connection_parameters(self);
 		self->retry_count = 0;
 		
-		/* This frame will just be sent at the old speed */
-		/* irlap_send_rr_frame( self, CMD_FRAME); */
+		/* This frame will actually force the speed change */
+		irlap_send_rr_frame(self, CMD_FRAME);
 
-		irlap_start_final_timer( self, self->final_timeout/2);
-		irlap_next_state( self, LAP_NRM_P);
+		irlap_start_final_timer(self, self->final_timeout/2);
+		irlap_next_state(self, LAP_NRM_P);
 
-		irlap_connect_confirm( self, skb);
+		irlap_connect_confirm(self, skb);
 		break;
+	case RECV_DM_RSP:     /* FALLTHROUGH */
+	case RECV_DISC_CMD: 
+		del_timer(&self->final_timer);
+		irlap_next_state(self, LAP_NDM);
 
-	case RECV_DISC_FRAME:
-		del_timer( &self->final_timer);
-		irlap_next_state( self, LAP_NDM);
-
-		irlap_disconnect_indication( self, LAP_DISC_INDICATION);
+		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+		dev_kfree_skb(skb);
 		break;
-
-       /* DM handled in irlap_frame.c, irlap_input() */
-		
 	default:
-		DEBUG( 4, "irlap_state_setup: Unknown event");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
+			   irlap_event[event]);		
+		if (skb)
+			dev_kfree_skb(skb);
+		
 		ret = -1;
 		break;
 	}	
@@ -744,10 +820,10 @@
  *    OFFLINE state, not used for now!
  *
  */
-static int irlap_state_offline( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Unknown event\n");
+	IRDA_DEBUG( 0, __FUNCTION__ "(), Unknown event\n");
 
 	return -1;
 }
@@ -765,25 +841,23 @@
 {
 	int ret = 0;
 	
-	DEBUG(4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d", 
-	      irlap_event[event], self->vs, self->vr);
-		
 	switch (event) {
 	case SEND_I_CMD:
 		/*
 		 *  Only send frame if send-window > 0.
 		 */ 
 		if ((self->window > 0) && (!self->remote_busy)) {
-
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
 			/*
 			 *  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->bytes_left) {
+				IRDA_DEBUG(4, __FUNCTION__ 
+					   "(), Not allowed to transmit more "
+					   "bytes!\n");
+				skb_queue_head(&self->txq, skb);
 
 				/*
 				 *  We should switch state to LAP_NRM_P, but
@@ -795,20 +869,20 @@
 				 */
 				return -EPROTO;
 			}
-			self->bytes_left -= (skb->len + self->bofs_count);
-
+			self->bytes_left -= skb->len;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 			/*
 			 *  Send data with poll bit cleared only if window > 1
 			 *  and there is more frames after this one to be sent
 			 */
-			if (( self->window > 1) && 
-			    skb_queue_len( &self->tx_list) > 0) 
+			if ((self->window > 1) && 
+			    skb_queue_len( &self->txq) > 0) 
 			{   
-				irlap_send_data_primary( self, skb);
-				irlap_next_state( self, LAP_XMIT_P);
+				irlap_send_data_primary(self, skb);
+				irlap_next_state(self, LAP_XMIT_P);
 			} else {
-				irlap_send_data_primary_poll( self, skb);
-				irlap_next_state( self, LAP_NRM_P);
+				irlap_send_data_primary_poll(self, skb);
+				irlap_next_state(self, LAP_NRM_P);
 				
 				/* 
 				 * Make sure state machine does not try to send
@@ -819,11 +893,11 @@
 #ifdef CONFIG_IRDA_FAST_RR
 			/* Peer may want to reply immediately */
 			self->fast_RR = FALSE;
-#endif
+#endif /* CONFIG_IRDA_FAST_RR */
 		} else {
-			DEBUG( 4, __FUNCTION__ 
-			       "(), Unable to send! remote busy?\n");
-			skb_queue_head(&self->tx_list, skb);
+			IRDA_DEBUG(4, __FUNCTION__ 
+				   "(), Unable to send! remote busy?\n");
+			skb_queue_head(&self->txq, skb);
 
 			/*
 			 *  The next ret is important, because it tells 
@@ -833,6 +907,8 @@
 		}
 		break;
 	case POLL_TIMER_EXPIRED:
+		IRDA_DEBUG(3, __FUNCTION__ "(), POLL_TIMER_EXPIRED (%ld)\n",
+			   jiffies);
 		irlap_send_rr_frame(self, CMD_FRAME);
 		irlap_start_final_timer(self, self->final_timeout);
 		irlap_next_state(self, LAP_NRM_P);
@@ -847,8 +923,11 @@
 		irlap_next_state(self, LAP_PCLOSE);
 		break;
 	default:
-		DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
-		      irlap_event[event]);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlap_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+
 		ret = -EINVAL;
 		break;
 	}
@@ -860,48 +939,51 @@
  *
  *    PCLOSE state
  */
-static int irlap_state_pclose( struct irlap_cb *self, IRLAP_EVENT event, 
-			       struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event, 
+			      struct sk_buff *skb, struct irlap_info *info) 
 {
 	int ret = 0;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 	
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);	
 
-	switch( event) {
-	case RECV_UA_RSP:
-		del_timer( &self->final_timer);
+	switch (event) {
+	case RECV_UA_RSP: /* FALLTHROUGH */
+	case RECV_DM_RSP:
+		del_timer(&self->final_timer);
 		
-		irlap_apply_default_connection_parameters( self);
+		irlap_apply_default_connection_parameters(self);
 
 		/* Always switch state before calling upper layers */
-		irlap_next_state( self, LAP_NDM);
-
-		irlap_disconnect_indication( self, LAP_DISC_INDICATION);
-
+		irlap_next_state(self, LAP_NDM);
+		
+		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+		dev_kfree_skb(skb);
 		break;
 	case FINAL_TIMER_EXPIRED:
-		if ( self->retry_count < self->N3) {
-			irlap_wait_min_turn_around( self, &self->qos_tx);
-			irlap_send_disc_frame( self);
-			irlap_start_final_timer( self, self->final_timeout);
+		if (self->retry_count < self->N3) {
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_disc_frame(self);
+			irlap_start_final_timer(self, self->final_timeout);
 			self->retry_count++;
 			/* Keep state */
 		} else {
-			irlap_apply_default_connection_parameters( self);
+			irlap_apply_default_connection_parameters(self);
 
-			/* 
-			 *  Always switch state before calling upper layers 
-			 */
-			irlap_next_state( self, LAP_NDM);
+			/*  Always switch state before calling upper layers */
+			irlap_next_state(self, LAP_NDM);
 
-			irlap_disconnect_indication( self, LAP_NO_RESPONSE);
+			irlap_disconnect_indication(self, LAP_NO_RESPONSE);
 		}
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d\n", event);
+
+		if (skb)
+			dev_kfree_skb(skb);
+
 		ret = -1;
 		break;	
 	}
@@ -934,7 +1016,7 @@
 		 *  to transmitt
 		 */
 		self->fast_RR = FALSE;
-#endif
+#endif /* CONFIG_IRDA_FAST_RR */
 		ASSERT( info != NULL, return -1;);
 
 		ns_status = irlap_validate_ns_received(self, info->ns);
@@ -944,9 +1026,7 @@
 		 *  Check for expected I(nformation) frame
 		 */
 		if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) {
-			/* 
-			 *  poll bit cleared?
-			 */
+			/*  poll bit cleared?  */
 			if (!info->pf) {
 				self->vr = (self->vr + 1) % 8;
 			
@@ -958,7 +1038,7 @@
 				/* Keep state, do not move this line */
 				irlap_next_state(self, LAP_NRM_P);
 				
-				irlap_data_indication(self, skb);
+				irlap_data_indication(self, skb, FALSE);
 			} else {
 				del_timer(&self->final_timer);
 
@@ -982,21 +1062,18 @@
 				 */
 				irlap_next_state(self, LAP_XMIT_P);
 			
-				irlap_data_indication(self, skb);
+				irlap_data_indication(self, skb, FALSE);
 
 				/* This is the last frame */
 				irlap_start_poll_timer(self, self->poll_timeout);
 			}
-			break;
-			
+			break;			
 		}
-		/*
-		 *  Unexpected next to send (Ns)
-		 */
+		/* Unexpected next to send (Ns) */
 		if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
 		{
-			if ( !info->pf) {
-				irlap_update_nr_received( self, info->nr);
+			if (!info->pf) {
+				irlap_update_nr_received(self, info->nr);
 				
 				/*
 				 *  Wait until the last frame before doing 
@@ -1004,23 +1081,23 @@
 				 */
 
 				/* Keep state */
-				irlap_next_state( self, LAP_NRM_P);
+				irlap_next_state(self, LAP_NRM_P);
 			} else {
-				DEBUG( 4, __FUNCTION__
+				IRDA_DEBUG(4, __FUNCTION__
 				       "(), missing or duplicate frame!\n");
 				
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 				
-				irlap_wait_min_turn_around( self, &self->qos_tx);
-				irlap_send_rr_frame( self, CMD_FRAME);
+				irlap_wait_min_turn_around(self, &self->qos_tx);
+				irlap_send_rr_frame(self, CMD_FRAME);
 				
 				self->ack_required = FALSE;
 			
-				irlap_start_final_timer( self, self->final_timeout);
-				irlap_next_state( self, LAP_NRM_P);
+				irlap_start_final_timer(self, self->final_timeout);
+				irlap_next_state(self, LAP_NRM_P);
 			}
-			dev_kfree_skb( skb);
+			dev_kfree_skb(skb);
 			break;
 		}
 		/* 
@@ -1028,22 +1105,22 @@
 		 */
 		if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
 		{
-			if ( info->pf) {
+			if (info->pf) {
 				self->vr = (self->vr + 1) % 8;
 			
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 			
 				/* Resend rejected frames */
-				irlap_resend_rejected_frames( self, CMD_FRAME);
+				irlap_resend_rejected_frames(self, CMD_FRAME);
 				
 				self->ack_required = FALSE;
-				irlap_start_final_timer( self, self->final_timeout);
+				irlap_start_final_timer(self, self->final_timeout);
 				
 				/* Keep state, do not move this line */
-				irlap_next_state( self, LAP_NRM_P);
+				irlap_next_state(self, LAP_NRM_P);
 				
-				irlap_data_indication( self, skb);
+				irlap_data_indication(self, skb, FALSE);
 			} else {
 				/* 
 				 *  Do not resend frames until the last
@@ -1054,14 +1131,14 @@
 				self->vr = (self->vr + 1) % 8;
 
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 				
 				self->ack_required = FALSE;
 
 				/* Keep state, do not move this line!*/
-				irlap_next_state( self, LAP_NRM_P); 
+				irlap_next_state(self, LAP_NRM_P); 
 				
-				irlap_data_indication( self, skb);
+				irlap_data_indication(self, skb, FALSE);
 			}
 			break;
 		}
@@ -1072,22 +1149,24 @@
 		if ((ns_status == NS_UNEXPECTED) && 
 		    (nr_status == NR_UNEXPECTED)) 
 		{
-			DEBUG( 4, "IrLAP: unexpected nr and ns!\n");
-			if ( info->pf) {
+			IRDA_DEBUG(4, __FUNCTION__ 
+				   "(), unexpected nr and ns!\n");
+			if (info->pf) {
 				/* Resend rejected frames */
-				irlap_resend_rejected_frames( self, CMD_FRAME);
+				irlap_resend_rejected_frames(self, CMD_FRAME);
 				
 				/* Give peer some time to retransmit! */
-				irlap_start_final_timer( self, self->final_timeout);
+				irlap_start_final_timer(self, self->final_timeout);
 
 				/* Keep state, do not move this line */
-				irlap_next_state( self, LAP_NRM_P);
+				irlap_next_state(self, LAP_NRM_P);
 			} else {
 				/* Update Nr received */
 				/* irlap_update_nr_received( info->nr); */
 				
 				self->ack_required = FALSE;
 			}
+			dev_kfree_skb(skb);
 			break;
 		}
 
@@ -1099,7 +1178,7 @@
 				del_timer(&self->final_timer);
 				
 				irlap_next_state(self, LAP_RESET_WAIT);
-
+				
 				irlap_disconnect_indication(self, LAP_RESET_INDICATION);
 				self->xmitflag = TRUE;
 			} else {
@@ -1109,21 +1188,22 @@
 				
 				self->xmitflag = FALSE;
 			}
+			dev_kfree_skb(skb);
 			break;
 		}
-		DEBUG(1, __FUNCTION__ "(), Not implemented!\n");
-		DEBUG(1, __FUNCTION__ 
+		IRDA_DEBUG(1, __FUNCTION__ "(), Not implemented!\n");
+		IRDA_DEBUG(1, __FUNCTION__ 
 		      "(), event=%s, ns_status=%d, nr_status=%d\n", 
 		      irlap_event[ event], ns_status, nr_status);
 		break;
 	case RECV_UI_FRAME:
-		/*  poll bit cleared?  */
+		/* Poll bit cleared? */
 		if (!info->pf) {
-			irlap_unit_data_indication(self, skb);
+			irlap_data_indication(self, skb, TRUE);
 			irlap_next_state(self, LAP_NRM_P);
 		} else {
 			del_timer(&self->final_timer);
-			irlap_unit_data_indication(self, skb);
+			irlap_data_indication(self, skb, TRUE);
 			irlap_start_poll_timer(self, self->poll_timeout);
 		}
 		break;
@@ -1158,63 +1238,56 @@
 			/* Start poll timer */
 			irlap_start_poll_timer(self, self->poll_timeout);
 		} else if (ret == NR_UNEXPECTED) {
-			ASSERT( info != NULL, return -1;);	
+			ASSERT(info != NULL, return -1;);	
 			/* 
 			 *  Unexpected nr! 
 			 */
 			
 			/* Update Nr received */
-			irlap_update_nr_received( self, info->nr);
+			irlap_update_nr_received(self, info->nr);
 
-			DEBUG( 4, "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);
+			IRDA_DEBUG(4, "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);
 			
 			/* Resend rejected frames */
-			irlap_resend_rejected_frames( self, CMD_FRAME);
+			irlap_resend_rejected_frames(self, CMD_FRAME);
 			
-			irlap_next_state( self, LAP_NRM_P);
+			irlap_next_state(self, LAP_NRM_P);
 		} else if (ret == NR_INVALID) {
-			DEBUG(1, "irlap_state_nrm_p: received RR with "
-			      "invalid nr !\n");
-			del_timer( &self->final_timer);
+			IRDA_DEBUG(1, __FUNCTION__ "(), Received RR with "
+				   "invalid nr !\n");
+			del_timer(&self->final_timer);
 
-			irlap_next_state( self, LAP_RESET_WAIT);
+			irlap_next_state(self, LAP_RESET_WAIT);
 
 			irlap_disconnect_indication(self, LAP_RESET_INDICATION);
 			self->xmitflag = TRUE;
 		}
-		if (skb)
-			dev_kfree_skb( skb);
+		dev_kfree_skb(skb);
 		break;
-	case RECV_RNR_FRAME:
-		DEBUG( 4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, "
-		       "nr=%d, va=%d, vs=%d, vr=%d\n",
-		       self->retry_count, info->nr, self->va, self->vs, 
-		       self->vr);
-
-		ASSERT( info != NULL, return -1;);
+	case RECV_RNR_RSP:
+		ASSERT(info != NULL, return -1;);
 
 		/* Stop final timer */
-		del_timer( &self->final_timer);
+		del_timer(&self->final_timer);
 		self->remote_busy = TRUE;
 
 		/* Update Nr received */
-		irlap_update_nr_received( self, info->nr);
-
-		irlap_next_state( self, LAP_XMIT_P);
+		irlap_update_nr_received(self, info->nr);
+		irlap_next_state(self, LAP_XMIT_P);
 			
 		/* Start poll timer */
-		irlap_start_poll_timer( self, self->poll_timeout);
-
-		dev_kfree_skb( skb);
+		irlap_start_poll_timer(self, self->poll_timeout);
+		dev_kfree_skb(skb);
 		break;
 	case RECV_FRMR_RSP:
-		del_timer( &self->final_timer);
+		del_timer(&self->final_timer);
 		self->xmitflag = TRUE;
-		irlap_next_state( self, LAP_RESET_WAIT);
-		irlap_reset_indication( self);
+		irlap_next_state(self, LAP_RESET_WAIT);
+		irlap_reset_indication(self);
+		dev_kfree_skb(skb);
 		break;
 	case FINAL_TIMER_EXPIRED:
 		/* 
@@ -1223,11 +1296,12 @@
 		 *  of receiving a frame (page 45, IrLAP). Check that
 		 *  we only do this once for each frame.
 		 */
-		if ( irda_device_is_receiving( self->irdev) && 
-		     !self->add_wait) {
-			DEBUG( 4, "FINAL_TIMER_EXPIRED when receiving a "
-			       "frame! Waiting a little bit more!\n");
-			irlap_start_final_timer( self, 30);
+		if (irda_device_is_receiving(self->netdev) && 
+		    !self->add_wait) 
+		{
+			IRDA_DEBUG(1, "FINAL_TIMER_EXPIRED when receiving a "
+			      "frame! Waiting a little bit more!\n");
+			irlap_start_final_timer(self, MSECS_TO_JIFFIES(300));
 
 			/*
 			 *  Don't allow this to happen one more time in a row, 
@@ -1239,60 +1313,72 @@
 		}
 		self->add_wait = FALSE;
 
-		if (( self->retry_count < self->N2) && 
-		    ( self->retry_count != self->N1)) {
+		if ((self->retry_count < self->N2) && 
+		    (self->retry_count != self->N1)) {
 			
-			irlap_wait_min_turn_around( self, &self->qos_tx);
-			irlap_send_rr_frame( self, CMD_FRAME);
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_rr_frame(self, CMD_FRAME);
 			
-			irlap_start_final_timer( self, self->final_timeout);
+			irlap_start_final_timer(self, self->final_timeout);
 		 	self->retry_count++;
 
-			DEBUG( 4, "irlap_state_nrm_p: FINAL_TIMER_EXPIRED:"
-			       " retry_count=%d\n", self->retry_count);
+			IRDA_DEBUG(4, "irlap_state_nrm_p: FINAL_TIMER_EXPIRED:"
+				   " retry_count=%d\n", self->retry_count);
 			/* Keep state */
-		} else if ( self->retry_count == self->N1) {
-			irlap_status_indication( STATUS_NO_ACTIVITY);
-			irlap_wait_min_turn_around( self, &self->qos_tx);
-			irlap_send_rr_frame( self, CMD_FRAME);
+		} else if (self->retry_count == self->N1) {
+			irlap_status_indication(STATUS_NO_ACTIVITY);
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_rr_frame(self, CMD_FRAME);
 			
-			irlap_start_final_timer( self, self->final_timeout);
+			irlap_start_final_timer(self, self->final_timeout);
 			self->retry_count++;
 
-			DEBUG( 4, "retry count = N1; retry_count=%d\n", 
-			       self->retry_count);
+			IRDA_DEBUG(4, "retry count = N1; retry_count=%d\n", 
+				   self->retry_count);
 			/* Keep state */
-		} else if ( self->retry_count >= self->N2) {
-			irlap_apply_default_connection_parameters( self);
+		} else if (self->retry_count >= self->N2) {
+			irlap_apply_default_connection_parameters(self);
 
 			/* Always switch state before calling upper layers */
-			irlap_next_state( self, LAP_NDM);
-			irlap_disconnect_indication( self, LAP_NO_RESPONSE);
+			irlap_next_state(self, LAP_NDM);
+			irlap_disconnect_indication(self, LAP_NO_RESPONSE);
 		}
 		break;
-	case RECV_DISC_FRAME: /* FIXME: Check how this is in the standard! */
-		DEBUG(1, __FUNCTION__ "(), RECV_DISC_FRAME()\n");
-
-		/* Always switch state before calling upper layers */
-		irlap_next_state( self, LAP_NDM);
-		
-		irlap_wait_min_turn_around( self, &self->qos_tx);
-		irlap_send_ua_response_frame( self, NULL);
-
- 		del_timer( &self->final_timer);
-		/* del_timer( &self->poll_timer); */
-
-		irlap_flush_all_queues( self);
-		irlap_apply_default_connection_parameters( self);
+	case RECV_REJ_RSP:
+		irlap_update_nr_received(self, info->nr);
+		if (self->remote_busy) {
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_rr_frame(self, CMD_FRAME);
+		} else
+			irlap_resend_rejected_frames(self, CMD_FRAME);
+		irlap_start_final_timer(self, self->final_timeout);
+		dev_kfree_skb(skb);
+		break;
+	case RECV_SREJ_RSP:
+		irlap_update_nr_received(self, info->nr);
+		if (self->remote_busy) {
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_rr_frame(self, CMD_FRAME);
+		} else
+			irlap_resend_rejected_frame(self, CMD_FRAME);
+		irlap_start_final_timer(self, self->final_timeout);
+		dev_kfree_skb(skb);
+		break;
+	case RECV_RD_RSP:
+		IRDA_DEBUG(0, __FUNCTION__ "(), RECV_RD_RSP\n");
 
-		irlap_disconnect_indication( self, LAP_DISC_INDICATION);
-		if (skb)
-			dev_kfree_skb( skb);
-		
+		irlap_next_state(self, LAP_PCLOSE);
+		irlap_send_disc_frame(self);
+		irlap_flush_all_queues(self);
+		irlap_start_final_timer(self, self->final_timeout);
+		self->retry_count = 0;
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", 
-		      irlap_event[event]);
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlap_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+
 		ret = -1;
 		break;
 	}
@@ -1311,21 +1397,21 @@
 {
 	int ret = 0;
 	
-	DEBUG( 3, __FUNCTION__ "(), event = %s\n", irlap_event[event]);
+	IRDA_DEBUG(3, __FUNCTION__ "(), event = %s\n", irlap_event[event]);
 	
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
-	switch( event) {
+	switch (event) {
 	case RESET_REQUEST:
-		if ( self->xmitflag) {
-			irlap_wait_min_turn_around( self, &self->qos_tx);
-			irlap_send_snrm_frame( self, NULL);
-			irlap_start_final_timer( self, self->final_timeout);
-			irlap_next_state( self, LAP_RESET);
+		if (self->xmitflag) {
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_snrm_frame(self, NULL);
+			irlap_start_final_timer(self, self->final_timeout);
+			irlap_next_state(self, LAP_RESET);
 		} else {
-			irlap_start_final_timer( self, self->final_timeout);
-			irlap_next_state( self, LAP_RESET);
+			irlap_start_final_timer(self, self->final_timeout);
+			irlap_next_state(self, LAP_RESET);
 		}
 		break;
 	case DISCONNECT_REQUEST:
@@ -1337,8 +1423,11 @@
 		irlap_next_state( self, LAP_PCLOSE);
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", 
-		      irlap_event[event]);
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlap_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+
 		ret = -1;
 		break;	
 	}
@@ -1352,76 +1441,90 @@
  *    reply.
  *
  */
-static int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event, 
-			      struct sk_buff *skb, struct irlap_info *info)
+static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event, 
+			     struct sk_buff *skb, struct irlap_info *info)
 {
 	int ret = 0;
 	
-	DEBUG(3, __FUNCTION__ "(), event = %s\n", irlap_event[event]);
+	IRDA_DEBUG(3, __FUNCTION__ "(), event = %s\n", irlap_event[event]);
 	
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
-	switch(event) {
-	case RECV_DISC_FRAME:
+	switch (event) {
+	case RECV_DISC_CMD:
 		del_timer(&self->final_timer);
 
-		irlap_apply_default_connection_parameters( self);
+		irlap_apply_default_connection_parameters(self);
 
 		/* Always switch state before calling upper layers */
-		irlap_next_state( self, LAP_NDM);
+		irlap_next_state(self, LAP_NDM);
+
+		irlap_disconnect_indication(self, LAP_NO_RESPONSE);
 
-		irlap_disconnect_indication( self, LAP_NO_RESPONSE);
+		dev_kfree_skb(skb);
 		break;
 	case RECV_UA_RSP:
-		del_timer( &self->final_timer);
+		del_timer(&self->final_timer);
 		
 		/* Initiate connection state */
-		irlap_initiate_connection_state( self);
+		irlap_initiate_connection_state(self);
 		
 		irlap_reset_confirm();
 		
 		self->remote_busy = FALSE;
 
-		irlap_next_state( self, LAP_XMIT_P);
+		irlap_next_state(self, LAP_XMIT_P);
 
-		irlap_start_poll_timer( self, self->poll_timeout);
+		irlap_start_poll_timer(self, self->poll_timeout);
+
+		dev_kfree_skb(skb);
 		break;
 	case FINAL_TIMER_EXPIRED:
-		if ( self->retry_count < 3) {
-			irlap_wait_min_turn_around( self, &self->qos_tx);
+		if (self->retry_count < 3) {
+			irlap_wait_min_turn_around(self, &self->qos_tx);
 
-			ASSERT( self->irdev != NULL, return -1;);
-			irlap_send_snrm_frame(self, 
-					      irda_device_get_qos( self->irdev));
+			ASSERT(self->netdev != NULL, return -1;);
+			irlap_send_snrm_frame(self, self->qos_dev);
 
 			self->retry_count++; /* Experimental!! */
 
-			irlap_start_final_timer( self, self->final_timeout);
-			irlap_next_state( self, LAP_RESET);
-		} else if ( self->retry_count >= self->N3) {
-			irlap_apply_default_connection_parameters( self);
+			irlap_start_final_timer(self, self->final_timeout);
+			irlap_next_state(self, LAP_RESET);
+		} else if (self->retry_count >= self->N3) {
+			irlap_apply_default_connection_parameters(self);
 			
 			/* Always switch state before calling upper layers */
-			irlap_next_state( self, LAP_NDM);
+			irlap_next_state(self, LAP_NDM);
 			
-			irlap_disconnect_indication( self, LAP_NO_RESPONSE);
+			irlap_disconnect_indication(self, LAP_NO_RESPONSE);
 		}
 		break;
-
 	case RECV_SNRM_CMD:
-		DEBUG(3, "lap_reset: RECV_SNRM_CMD\n");
-		irlap_initiate_connection_state( self);
-		irlap_wait_min_turn_around( self, &self->qos_tx);
-		irlap_send_ua_response_frame( self, &self->qos_rx);
-		irlap_reset_confirm();
-		irlap_start_wd_timer( self, self->wd_timeout);
-		irlap_next_state( self, LAP_NDM);
+		/* 
+		 * SNRM frame is not allowed to contain an I-field in this 
+		 * state
+		 */
+		if (!info) {
+			IRDA_DEBUG(3, __FUNCTION__ "(), RECV_SNRM_CMD\n");
+			irlap_initiate_connection_state(self);
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_ua_response_frame(self, &self->qos_rx);
+			irlap_reset_confirm();
+			irlap_start_wd_timer(self, self->wd_timeout);
+			irlap_next_state(self, LAP_NDM);
+		} else {
+			IRDA_DEBUG(0, __FUNCTION__ 
+				   "(), SNRM frame contained an I field!\n");
+		}
+		dev_kfree_skb(skb);
 		break;
-
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", 
-		      irlap_event[ event]);
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlap_event[event]);	
+		if (skb)
+			dev_kfree_skb(skb);
+
 		ret = -1;
 		break;	
 	}
@@ -1435,54 +1538,54 @@
  *   and we therefor do not expect to receive any transmissions from other
  *   stations.  
  */
-static int irlap_state_xmit_s( struct irlap_cb *self, IRLAP_EVENT event, 
-			       struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, 
+			      struct sk_buff *skb, struct irlap_info *info) 
 {
 	int ret = 0;
 	
-	DEBUG( 4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]); 
+	IRDA_DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[event]); 
 
-	ASSERT( self != NULL, return -ENODEV;);
-	ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+	ASSERT(self != NULL, return -ENODEV;);
+	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
 	
-	switch( event) {
+	switch (event) {
 	case SEND_I_CMD:
 		/*
 		 *  Send frame only if send window > 1
 		 */ 
-		if ((self->window > 0) && ( !self->remote_busy)) {
+		if ((self->window > 0) && (!self->remote_busy)) {
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
 			/*
 			 *  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, "IrDA: Not allowed to transmit more bytes!\n");
-				skb_queue_head( &self->tx_list, skb);
+			if (skb->len > self->bytes_left) {
+				skb_queue_head(&self->txq, skb);
 				/*
 				 *  Switch to NRM_S, this is only possible
 				 *  when we are in secondary mode, since we 
 				 *  must be sure that we don't miss any RR
 				 *  frames
 				 */
-				irlap_next_state( self, LAP_NRM_S);
+				irlap_next_state(self, LAP_NRM_S);
 
 				return -EPROTO; /* Try again later */
 			}
-			self->bytes_left -= ( skb->len + self->bofs_count);
-
+			self->bytes_left -= skb->len;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 			/*
 			 *  Send data with final bit cleared only if window > 1
 			 *  and there is more frames to be sent
 			 */
-			if (( self->window > 1) && 
-			    skb_queue_len( &self->tx_list) > 0) 
+			if ((self->window > 1) && 
+			    skb_queue_len(&self->txq) > 0) 
 			{   
-				irlap_send_data_secondary( self, skb);
-				irlap_next_state( self, LAP_XMIT_S);
+				irlap_send_data_secondary(self, skb);
+				irlap_next_state(self, LAP_XMIT_S);
 			} else {
-				irlap_send_data_secondary_final( self, skb);
-				irlap_next_state( self, LAP_NRM_S);
+				irlap_send_data_secondary_final(self, skb);
+				irlap_next_state(self, LAP_NRM_S);
 
 				/* 
 				 * Make sure state machine does not try to send
@@ -1491,14 +1594,23 @@
 				ret = -EPROTO;
 			}
 		} else {
-			DEBUG(1, __FUNCTION__ "(), Unable to send!\n");
-			skb_queue_head( &self->tx_list, skb);
+			IRDA_DEBUG(2, __FUNCTION__ "(), Unable to send!\n");
+			skb_queue_head(&self->txq, skb);
 			ret = -EPROTO;
 		}
 		break;
+	case DISCONNECT_REQUEST:
+		irlap_send_rd_frame(self);
+		irlap_flush_all_queues(self);
+		irlap_start_wd_timer(self, self->wd_timeout);
+		irlap_next_state(self, LAP_SCLOSE);
+		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", 
-		      irlap_event[ event]);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlap_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+
 		ret = -EINVAL;
 		break;
 	}
@@ -1512,29 +1624,29 @@
  *    expecting to receive frames from the primary station
  *
  */
-static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event, 
-			      struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, 
+			     struct sk_buff *skb, struct irlap_info *info) 
 {
-	int ret = 0;
 	int ns_status;
 	int nr_status;
+	int ret = 0;
 
-	DEBUG( 4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
+	IRDA_DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
 
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-	switch(event) {
+	switch (event) {
 	case RECV_I_CMD: /* Optimize for the common case */
 		/* FIXME: must check for remote_busy below */
-		DEBUG( 4, __FUNCTION__ "(), event=%s nr=%d, vs=%d, ns=%d, "
-		       "vr=%d, pf=%d\n", irlap_event[event], info->nr, 
-		       self->vs, info->ns, self->vr, info->pf);
+		IRDA_DEBUG(4, __FUNCTION__ "(), event=%s nr=%d, vs=%d, ns=%d, "
+			   "vr=%d, pf=%d\n", irlap_event[event], info->nr, 
+			   self->vs, info->ns, self->vr, info->pf);
 
 		self->retry_count = 0;
 
-		ns_status = irlap_validate_ns_received( self, info->ns);
-		nr_status = irlap_validate_nr_received( self, info->nr);
+		ns_status = irlap_validate_ns_received(self, info->ns);
+		nr_status = irlap_validate_nr_received(self, info->nr);
 		/* 
 		 *  Check for expected I(nformation) frame
 		 */
@@ -1546,7 +1658,7 @@
 				self->vr = (self->vr + 1) % 8;
 				
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 				
 				self->ack_required = TRUE;
 				
@@ -1554,18 +1666,19 @@
 				 *  Starting WD-timer here is optional, but
 				 *  not recommended. Note 6 IrLAP p. 83
 				 */
-				/* irda_start_timer( WD_TIMER, self->wd_timeout); */
-
+#if 0
+				irda_start_timer(WD_TIMER, self->wd_timeout);
+#endif
 				/* Keep state, do not move this line */
-				irlap_next_state( self, LAP_NRM_S);
+				irlap_next_state(self, LAP_NRM_S);
 				
-				irlap_data_indication( self, skb);
+				irlap_data_indication(self, skb, FALSE);
 				break;
 			} else {
 				self->vr = (self->vr + 1) % 8;
 				
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 				
 				/* 
 				 *  We should wait before sending RR, and
@@ -1580,10 +1693,10 @@
 				 * we decide if we should send a RR frame
 				 * or not
 				 */
-				irlap_data_indication(self, skb);
+				irlap_data_indication(self, skb, FALSE);
 
 				/* Any pending data requests?  */
-				if ((skb_queue_len(&self->tx_list) > 0) && 
+				if ((skb_queue_len(&self->txq) > 0) && 
 				    (self->window > 0)) 
 				{
 					self->ack_required = TRUE;
@@ -1593,7 +1706,8 @@
 					irlap_next_state(self, LAP_XMIT_S);
 				} else {
 					irlap_send_rr_frame(self, RSP_FRAME);
-					irlap_start_wd_timer(self, self->wd_timeout);
+					irlap_start_wd_timer(self, 
+							     self->wd_timeout);
 
 					/* Keep the state */
 					irlap_next_state(self, LAP_NRM_S);
@@ -1607,20 +1721,20 @@
 		if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
 		{
 			/* Unexpected next to send, with final bit cleared */
-			if ( !info->pf) {
-				irlap_update_nr_received( self, info->nr);
+			if (!info->pf) {
+				irlap_update_nr_received(self, info->nr);
 				
-				irlap_start_wd_timer( self, self->wd_timeout);
+				irlap_start_wd_timer(self, self->wd_timeout);
 			} else {
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 			
-				irlap_wait_min_turn_around( self, &self->qos_tx);
-				irlap_send_rr_frame( self, CMD_FRAME);
+				irlap_wait_min_turn_around(self, &self->qos_tx);
+				irlap_send_rr_frame(self, CMD_FRAME);
 			
-				irlap_start_wd_timer( self, self->wd_timeout);
+				irlap_start_wd_timer(self, self->wd_timeout);
 			}
-			dev_kfree_skb( skb);
+			dev_kfree_skb(skb);
 			break;
 		}
 
@@ -1629,81 +1743,83 @@
 		 */
 		if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
 		{
-			if ( info->pf) {
-				DEBUG( 4, "RECV_I_RSP: frame(s) lost\n");
+			if (info->pf) {
+				IRDA_DEBUG(4, "RECV_I_RSP: frame(s) lost\n");
 				
 				self->vr = (self->vr + 1) % 8;
 				
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 				
 				/* Resend rejected frames */
-				irlap_resend_rejected_frames( self, RSP_FRAME);
+				irlap_resend_rejected_frames(self, RSP_FRAME);
 
 				/* Keep state, do not move this line */
-				irlap_next_state( self, LAP_NRM_S);
-
-				irlap_data_indication( self, skb);
-				irlap_start_wd_timer( self, self->wd_timeout);
+				irlap_next_state(self, LAP_NRM_S);
 
+				irlap_data_indication(self, skb, FALSE);
+				irlap_start_wd_timer(self, self->wd_timeout);
 				break;
 			}
 			/*
 			 *  This is not documented in IrLAP!! Unexpected NR
 			 *  with poll bit cleared
 			 */
-			if ( !info->pf) {
+			if (!info->pf) {
 				self->vr = (self->vr + 1) % 8;
 				
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 				
 				/* Keep state, do not move this line */
-				irlap_next_state( self, LAP_NRM_S);
+				irlap_next_state(self, LAP_NRM_S);
 				
-				irlap_data_indication( self, skb);
-				irlap_start_wd_timer( self, self->wd_timeout);
+				irlap_data_indication(self, skb, FALSE);
+				irlap_start_wd_timer(self, self->wd_timeout);
 			}
+			break;
 		}
 		
-		if ( ret == NR_INVALID) {
-			DEBUG( 0, "NRM_S, NR_INVALID not implemented!\n");
+		if (ret == NR_INVALID) {
+			IRDA_DEBUG(0, "NRM_S, NR_INVALID not implemented!\n");
+			dev_kfree_skb(skb);
 		}
-		if ( ret == NS_INVALID) {
-			DEBUG( 0, "NRM_S, NS_INVALID not implemented!\n");
+		if (ret == NS_INVALID) {
+			IRDA_DEBUG(0, "NRM_S, NS_INVALID not implemented!\n");
+			dev_kfree_skb(skb);
 		}
 		break;
 	case RECV_UI_FRAME:
 		/* 
 		 *  poll bit cleared?
 		 */
-		if ( !info->pf) {
-			irlap_unit_data_indication( self, skb);
-			irlap_next_state( self, LAP_NRM_S); /* Keep state */
+		if (!info->pf) {
+			irlap_data_indication(self, skb, TRUE);
+			irlap_next_state(self, LAP_NRM_S); /* Keep state */
 		} else {
 			/*
 			 *  Any pending data requests?
 			 */
-			if (( skb_queue_len( &self->tx_list) > 0) && 
-			    ( self->window > 0) && !self->remote_busy) 
+			if ((skb_queue_len(&self->txq) > 0) && 
+			    (self->window > 0) && !self->remote_busy) 
 			{
-				irlap_unit_data_indication( self, skb);
+				irlap_data_indication(self, skb, 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_unit_data_indication( self, skb);
+				irlap_data_indication(self, skb, TRUE);
 
-				irlap_wait_min_turn_around( self, &self->qos_tx);
+				irlap_wait_min_turn_around(self, &self->qos_tx);
 
-				irlap_send_rr_frame( self, RSP_FRAME);
+				irlap_send_rr_frame(self, RSP_FRAME);
 				self->ack_required = FALSE;
 				
-				irlap_start_wd_timer( self, self->wd_timeout);
+				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);
 			}
 		}
 		break;
@@ -1713,18 +1829,18 @@
 		/* 
 		 *  Nr as expected? 
 		 */
-		nr_status = irlap_validate_nr_received( self, info->nr);
-		if ( nr_status == NR_EXPECTED) {
-			if (( skb_queue_len( &self->tx_list) > 0) && 
-			    ( self->window > 0)) {
+		nr_status = irlap_validate_nr_received(self, info->nr);
+		if (nr_status == NR_EXPECTED) {
+			if ((skb_queue_len( &self->txq) > 0) && 
+			    (self->window > 0)) {
 				self->remote_busy = FALSE;
 				
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
-				del_timer( &self->wd_timer);
+				irlap_update_nr_received(self, info->nr);
+				del_timer(&self->wd_timer);
 				
 				irlap_wait_min_turn_around(self, &self->qos_tx);
-				irlap_next_state( self, LAP_XMIT_S);
+				irlap_next_state(self, LAP_XMIT_S);
 			} else {			
 				self->remote_busy = FALSE;
 				/* Update Nr received */
@@ -1738,99 +1854,120 @@
 			}
 		} else if (nr_status == NR_UNEXPECTED) {
 			self->remote_busy = FALSE;
-			irlap_update_nr_received( self, info->nr);
-			irlap_resend_rejected_frames( self, RSP_FRAME);
+			irlap_update_nr_received(self, info->nr);
+			irlap_resend_rejected_frames(self, RSP_FRAME);
 
-			irlap_start_wd_timer( self, self->wd_timeout);
+			irlap_start_wd_timer(self, self->wd_timeout);
 
 			/* Keep state */
-			irlap_next_state( self, LAP_NRM_S); 
+			irlap_next_state(self, LAP_NRM_S); 
 		} else {
-			DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
+			IRDA_DEBUG(1, __FUNCTION__ 
+				   "(), invalid nr not implemented!\n");
 		} 
-		if (skb)
-			dev_kfree_skb(skb);
-
+		dev_kfree_skb(skb);
 		break;
 	case RECV_SNRM_CMD:
-		del_timer( &self->wd_timer);
-		DEBUG(1, __FUNCTION__ "(), received SNRM cmd\n");
-		irlap_next_state( self, LAP_RESET_CHECK);
-
-		irlap_reset_indication( self);
+		/* SNRM frame is not allowed to contain an I-field */
+		if (!info) {
+			del_timer(&self->wd_timer);
+			IRDA_DEBUG(1, __FUNCTION__ "(), received SNRM cmd\n");
+			irlap_next_state(self, LAP_RESET_CHECK);
+			
+			irlap_reset_indication(self);
+		} else {
+			IRDA_DEBUG(0, __FUNCTION__ 
+				   "(), SNRM frame contained an I-field!\n");
+			
+		}
+		dev_kfree_skb(skb);
+		break;
+	case RECV_REJ_CMD:
+		irlap_update_nr_received(self, info->nr);
+		if (self->remote_busy) {
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_rr_frame(self, CMD_FRAME);
+		} else
+			irlap_resend_rejected_frames(self, CMD_FRAME);
+		irlap_start_wd_timer(self, self->wd_timeout);
+		dev_kfree_skb(skb);
+		break;
+	case RECV_SREJ_CMD:
+		irlap_update_nr_received(self, info->nr);
+		if (self->remote_busy) {
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+			irlap_send_rr_frame(self, CMD_FRAME);
+		} else
+			irlap_resend_rejected_frame(self, CMD_FRAME);
+		irlap_start_wd_timer(self, self->wd_timeout);
+		dev_kfree_skb(skb);
 		break;
 	case WD_TIMER_EXPIRED:
-		DEBUG( 4, "WD_TIMER_EXPIRED: %ld\n", jiffies);
-	
 		/*
 		 *  Wait until retry_count * n matches negotiated threshold/
 		 *  disconnect time (note 2 in IrLAP p. 82)
 		 */
-		DEBUG(1, __FUNCTION__ "(), retry_count = %d\n", 
-		      self->retry_count);
+		IRDA_DEBUG(1, __FUNCTION__ "(), retry_count = %d\n", 
+			   self->retry_count);
 
-		if (( self->retry_count < (self->N2/2))  && 
-		    ( self->retry_count != self->N1/2)) {
+		if ((self->retry_count < (self->N2/2))  && 
+		    (self->retry_count != self->N1/2)) {
 			
-			irlap_start_wd_timer( self, self->wd_timeout);
+			irlap_start_wd_timer(self, self->wd_timeout);
 			self->retry_count++;		
-		} else if ( self->retry_count == (self->N1/2)) {
-			irlap_status_indication( STATUS_NO_ACTIVITY);
-			irlap_start_wd_timer( self, self->wd_timeout);
+		} else if (self->retry_count == (self->N1/2)) {
+			irlap_status_indication(STATUS_NO_ACTIVITY);
+			irlap_start_wd_timer(self, self->wd_timeout);
 			self->retry_count++;
-		} else if ( self->retry_count >= self->N2/2) {
-			irlap_apply_default_connection_parameters( self);
+		} else if (self->retry_count >= self->N2/2) {
+			irlap_apply_default_connection_parameters(self);
 			
 			/* Always switch state before calling upper layers */
-			irlap_next_state( self, LAP_NDM);
+			irlap_next_state(self, LAP_NDM);
 
-			irlap_disconnect_indication( self, LAP_NO_RESPONSE);
+			irlap_disconnect_indication(self, LAP_NO_RESPONSE);
 		}
 		break;
-
-	case RECV_DISC_FRAME:
+	case RECV_DISC_CMD:
 		/* Always switch state before calling upper layers */
-		irlap_next_state( self, LAP_NDM);
+		irlap_next_state(self, LAP_NDM);
 
-		irlap_wait_min_turn_around( self, &self->qos_tx);
-		irlap_send_ua_response_frame( self, NULL);
-		del_timer( &self->wd_timer);
-		irlap_flush_all_queues( self);
-		irlap_apply_default_connection_parameters( self);
+		irlap_wait_min_turn_around(self, &self->qos_tx);
+		irlap_send_ua_response_frame(self, NULL);
+		del_timer(&self->wd_timer);
+		irlap_flush_all_queues(self);
+		irlap_apply_default_connection_parameters(self);
 
-		irlap_disconnect_indication( self, LAP_DISC_INDICATION);
-		if (skb)
-			dev_kfree_skb( skb);
-		
+		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+		dev_kfree_skb(skb);		
 		break;
-
 	case RECV_DISCOVERY_XID_CMD:
-		DEBUG( 3, "irlap_state_nrm_s: got event RECV_DISCOVER_XID_CMD!\n");
-		del_timer( &self->final_timer);
-		
-		irlap_apply_default_connection_parameters( self);
-
-		/* Always switch state before calling upper layers */
-		irlap_next_state( self, LAP_NDM);
+		irlap_wait_min_turn_around(self, &self->qos_tx);
+		irlap_send_rr_frame(self, RSP_FRAME);
+		self->ack_required = TRUE;
+		irlap_start_wd_timer(self, self->wd_timeout);
+		irlap_next_state(self, LAP_NRM_S);
 
-		irlap_disconnect_indication( self, LAP_DISC_INDICATION);
-		
-#if 0
-		irlap_wait_min_turn_around( self, &self->qos_session);
-		irlap_send_rr_frame( RSP_FRAME);
-		irda_start_timer( WD_TIMER, self->wd_timeout);
-		irlap_next_state( self, LAP_NRM_S);
-#endif
+		dev_kfree_skb(skb);
 		break;
 	case RECV_TEST_CMD:
+		/* Remove test frame header */
 		skb_pull(skb, sizeof(struct test_frame));
-		irlap_send_test_frame(self, info->daddr, skb);
+
+		irlap_wait_min_turn_around(self, &self->qos_tx);
+		irlap_start_wd_timer(self, self->wd_timeout);
+
+		/* Send response (info will be copied) */
+		irlap_send_test_frame(self, self->caddr, info->daddr, skb);
 		dev_kfree_skb(skb);
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n", 
-		      event, irlap_event[event]);
-		ret = -1;
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n", 
+			   event, irlap_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+
+		ret = -EINVAL;
 		break;
 	}
 	return ret;
@@ -1842,10 +1979,53 @@
  *    
  *
  */
-static int irlap_state_sclose( struct irlap_cb *self, IRLAP_EVENT event, 
-			       struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, 
+			      struct sk_buff *skb, struct irlap_info *info) 
 {
-	DEBUG( 0, __FUNCTION__ "(), Not implemented!\n");
+	int ret = 0;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -ENODEV;);
+	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+	
+	switch (event) {
+	case RECV_DISC_CMD:
+		/* Always switch state before calling upper layers */
+		irlap_next_state(self, LAP_NDM);
+		
+		irlap_wait_min_turn_around(self, &self->qos_tx);
+		irlap_send_ua_response_frame(self, NULL);
+		del_timer(&self->wd_timer);
+		irlap_apply_default_connection_parameters(self);
+
+		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+		dev_kfree_skb(skb);
+		break;
+	case RECV_DM_RSP:
+		/* Always switch state before calling upper layers */
+		irlap_next_state(self, LAP_NDM);
+
+		del_timer(&self->wd_timer);
+		irlap_apply_default_connection_parameters(self);
+		
+		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+		dev_kfree_skb(skb);
+		break;
+	case WD_TIMER_EXPIRED:
+		irlap_apply_default_connection_parameters(self);
+		
+		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+		break;
+	default:
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n", 
+			   event, irlap_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+		
+		ret = -EINVAL;
+		break;
+	}
 
 	return -1;
 }
@@ -1856,31 +2036,34 @@
 {
 	int ret = 0;
 
-	DEBUG(1, __FUNCTION__ "(), event=%s\n", irlap_event[ event]); 
+	IRDA_DEBUG(1, __FUNCTION__ "(), event=%s\n", irlap_event[event]); 
 
-	ASSERT( self != NULL, return -ENODEV;);
-	ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+	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);
-		irlap_start_wd_timer( self, WD_TIMEOUT);
-		irlap_flush_all_queues( self);
+		irlap_send_ua_response_frame(self, &self->qos_rx);
+		irlap_initiate_connection_state(self);
+		irlap_start_wd_timer(self, WD_TIMEOUT);
+		irlap_flush_all_queues(self);
 		
-		irlap_next_state( self, LAP_NRM_S);
+		irlap_next_state(self, LAP_NRM_S);
 		break;
 	case DISCONNECT_REQUEST:
-		irlap_wait_min_turn_around( self, &self->qos_tx);
-		/* irlap_send_rd_frame(self); */
-		irlap_start_wd_timer( self, WD_TIMEOUT);
+		irlap_wait_min_turn_around(self, &self->qos_tx);
+		irlap_send_rd_frame(self);
+		irlap_start_wd_timer(self, WD_TIMEOUT);
+		irlap_next_state(self, LAP_SCLOSE);
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n", 
-		      event, irlap_event[event]);
-		ret = -1;
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n", 
+			   event, irlap_event[event]);
+		if (skb)
+			dev_kfree_skb(skb);
+
+		ret = -EINVAL;
 		break;
 	}
-
 	return ret;
 }
diff -urN linux-2.2.15-pre2/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c
--- linux-2.2.15-pre2/net/irda/irlap_frame.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlap_frame.c	Mon Dec  3 21:57:53 2001
@@ -1,15 +1,16 @@
 /*********************************************************************
  *                
  * Filename:      irlap_frame.c
- * Version:       0.9
+ * Version:       1.0
  * Description:   Build and transmit IrLAP frames
- * Status:        Experimental.
+ * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Mon May 31 09:29:13 1999
+ * Modified at:   Wed Jan  5 08:59:04 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
+ *     Copyright (c) 1998-2000 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,26 +43,30 @@
 #include <net/irda/qos.h>
 
 /*
- * Function irlap_insert_mtt (self, skb)
- *
- *    Insert minimum turnaround time relevant information into the skb. We 
- *    need to do this since it's per packet relevant information.
+ * Function irlap_insert_info (self, skb)
  *
+ *    Insert minimum turnaround time and speed information into the skb. We 
+ *    need to do this since it's per packet relevant information. Safe to
+ *    have this function inlined since it's only called from one place
  */
-static inline void irlap_insert_mtt(struct irlap_cb *self, struct sk_buff *skb)
+static inline void irlap_insert_info(struct irlap_cb *self, 
+				     struct sk_buff *skb)
 {
-	struct irlap_skb_cb *cb;
+	struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
 
-	cb = (struct irlap_skb_cb *) skb->cb;
-	
+	/*  
+	 * Insert MTT (min. turn time) and speed into skb, so that the
+	 * device driver knows which settings to use 
+	 */
 	cb->magic = LAP_MAGIC;
 	cb->mtt = self->mtt_required;
-	
+	cb->speed = self->speed;
+
 	/* Reset */
 	self->mtt_required = 0;
 	
 	/* 
-	 * Delay equals negotiated BOFs count plus the number of BOFs to 
+	 * Delay equals negotiated BOFs count, plus the number of BOFs to 
 	 * force the negotiated minimum turnaround time 
 	 */
 	cb->xbofs = self->bofs_count+self->xbofs_delay;
@@ -84,14 +89,9 @@
  	skb->protocol = htons(ETH_P_IRDA);
 	skb->priority = TC_PRIO_BESTEFFORT;
 
-	/* 
-	 * Insert MTT (min. turn time) into skb, so that the device driver 
-	 * knows which MTT to use 
-	 */
-	irlap_insert_mtt(self, skb);
-	
+	irlap_insert_info(self, skb);
+
 	dev_queue_xmit(skb);
-	self->stats.tx_packets++;
 }
 
 /*
@@ -103,7 +103,7 @@
 {
 	struct sk_buff *skb;
 	struct snrm_frame *frame;
-	int len;
+	int ret;
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -113,8 +113,7 @@
 	if (!skb)
 		return;
 
-	skb_put(skb, 2); 
-	frame = (struct snrm_frame *) skb->data;
+	frame = (struct snrm_frame *) skb_put(skb, 2); 
 
 	/* Insert connection address field */
 	if (qos)
@@ -135,9 +134,11 @@
 
 		frame->ncaddr = self->caddr;
 				
-		len = irda_insert_qos_negotiation_params(qos, frame->params);
-		/* Should not be dangerous to do this afterwards */
-		skb_put(skb, len);
+		ret = irlap_insert_qos_negotiation_params(self, skb);
+		if (ret < 0) {
+			dev_kfree_skb(skb);
+			return;
+		}
 	}
 	irlap_queue_xmit(self, skb);
 }
@@ -153,27 +154,34 @@
 {
 	struct snrm_frame *frame;
 
-	DEBUG(3, __FUNCTION__ "()\n");
-
-	ASSERT(skb != NULL, return;);
-	ASSERT(info != NULL, return;);
-
 	frame = (struct snrm_frame *) skb->data;
-
-	/* Copy peer device address */
-	info->daddr = le32_to_cpu(frame->saddr);
-
-	/* Copy connection address */
-	info->caddr = frame->ncaddr;
-
-	/* Check if connection address has got a valid value */
-	if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
-		DEBUG(3, __FUNCTION__ "(), invalid connection address!\n");
-		dev_kfree_skb(skb);
-		return;
-	}
-
-	irlap_do_event(self, RECV_SNRM_CMD, skb, info);
+	
+	if (skb->len >= sizeof(struct snrm_frame)) {
+		/* Copy the new connection address */
+		info->caddr = frame->ncaddr;
+
+		/* Check if the new connection address is valid */
+		if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
+			IRDA_DEBUG(3, __FUNCTION__ 
+			      "(), invalid connection address!\n");
+			dev_kfree_skb(skb);
+			return;
+		}
+		
+		/* Copy peer device address */
+		info->daddr = le32_to_cpu(frame->saddr);
+		info->saddr = le32_to_cpu(frame->daddr);
+		
+		/* Only accept if addressed directly to us */
+		if (info->saddr != self->saddr) {
+			IRDA_DEBUG(2, __FUNCTION__ "(), not addressed to us!\n");
+			dev_kfree_skb(skb);
+			return;
+		}
+		irlap_do_event(self, RECV_SNRM_CMD, skb, info);
+	} else
+		/* Signal that this SNRM frame does not contain and I-field */
+		irlap_do_event(self, RECV_SNRM_CMD, skb, NULL);
 }
 
 /*
@@ -186,9 +194,9 @@
 {
 	struct sk_buff *skb;
 	struct ua_frame *frame;
-	int len;
+	int ret;
 	
-	DEBUG(2, __FUNCTION__ "() <%ld>\n", jiffies);
+	IRDA_DEBUG(2, __FUNCTION__ "() <%ld>\n", jiffies);
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -200,8 +208,7 @@
 	if (!skb)
 		return;
 
-	skb_put( skb, 10);
-	frame = (struct ua_frame *) skb->data;
+	frame = (struct ua_frame *) skb_put(skb, 10);
 	
 	/* Build UA response */
 	frame->caddr = self->caddr;
@@ -212,8 +219,11 @@
 
 	/* Should we send QoS negotiation parameters? */
 	if (qos) {
-		len = irda_insert_qos_negotiation_params(qos, frame->params);
-		skb_put(skb, len);
+		ret = irlap_insert_qos_negotiation_params(self, skb);
+		if (ret < 0) {
+			dev_kfree_skb(skb);
+			return;
+		}
 	}
 
 	irlap_queue_xmit(self, skb);
@@ -238,8 +248,7 @@
 	if (!skb)
 		return;
 
-	skb_put( skb, 2);
-	frame = skb->data;
+	frame = skb_put( skb, 2);
 	
 	if (self->state == LAP_NDM)
 		frame[0] = CBROADCAST;
@@ -262,17 +271,16 @@
 	struct sk_buff *skb = NULL;
 	__u8 *frame;
 	
-	DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	skb = dev_alloc_skb(32);
+	skb = dev_alloc_skb(16);
 	if (!skb)
 		return;
 
-	skb_put(skb, 2);
-	frame = skb->data;
+	frame = skb_put(skb, 2);
 	
 	frame[0] = self->caddr | CMD_FRAME;
 	frame[1] = DISC_CMD | PF_BIT;
@@ -292,12 +300,14 @@
 	struct sk_buff *skb = NULL;
 	struct xid_frame *frame;
 	__u32 bcast = BROADCAST;
+	__u8 *info;
 
- 	DEBUG( 4, __FUNCTION__ "(), s=%d, S=%d, command=%d\n", s, S, command);
+ 	IRDA_DEBUG(4, __FUNCTION__ "(), s=%d, S=%d, command=%d\n", s, S, 
+		   command);
 
-	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;);
 
 	skb = dev_alloc_skb(64);
 	if (!skb)
@@ -306,7 +316,7 @@
 	skb_put(skb, 14);
 	frame = (struct xid_frame *) skb->data;
 
-	if ( command) {
+	if (command) {
 		frame->caddr = CBROADCAST | CMD_FRAME;
 		frame->control =  XID_CMD | PF_BIT;
 	} else {
@@ -322,7 +332,7 @@
 	else
 		frame->daddr = cpu_to_le32(discovery->daddr);
 	
-	switch(S) {
+	switch (S) {
 	case 1:
 		frame->flags = 0x00;
 		break;
@@ -348,29 +358,24 @@
 	 *  responses. Send the second byte of the hint only if the
 	 *  EXTENSION bit is set in the first byte.
 	 */
-	if ( !command || ( frame->slotnr == 0xff)) {
-		int i;
-
-		if (discovery->hints.byte[0] & HINT_EXTENSION)
-			skb_put( skb, 3+discovery->info_len);
-		else
-			skb_put( skb, 2+discovery->info_len);
-		
-		i = 0;
-		frame->discovery_info[i++] = discovery->hints.byte[0];
-		if(discovery->hints.byte[0] & HINT_EXTENSION)
-			frame->discovery_info[i++] = discovery->hints.byte[1];
-		
-		frame->discovery_info[i++] = discovery->charset;
-
-		ASSERT( discovery->info_len < 30, return;);
+	if (!command || (frame->slotnr == 0xff)) {
+		int len;
 
-		memcpy( &frame->discovery_info[i++], discovery->info, 
-			discovery->info_len);
+		if (discovery->hints.byte[0] & HINT_EXTENSION) {
+			info = skb_put(skb, 2);		
+			info[0] = discovery->hints.byte[0];
+			info[1] = discovery->hints.byte[1];
+		} else {
+			info = skb_put(skb, 1);
+			info[0] = discovery->hints.byte[0];
+		}
+		info = skb_put(skb, 1);
+		info[0] = discovery->charset;
 
+		len = IRDA_MIN(discovery->name_len, skb_tailroom(skb));
+		info = skb_put(skb, len);
+		memcpy(info, discovery->nickname, len);
 	} 
-	ASSERT( self->netdev != NULL, return;);
-
 	irlap_queue_xmit(self, skb);
 }
 
@@ -386,51 +391,61 @@
 {
 	struct xid_frame *xid;
 	discovery_t *discovery = NULL;
+	__u8 *discovery_info;
 	char *text;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-	ASSERT(info != NULL, return;);
+
+	xid = (struct xid_frame *) skb->data;
+
+	info->daddr = le32_to_cpu(xid->saddr);
+	info->saddr = le32_to_cpu(xid->daddr);
+
+	/* Make sure frame is addressed to us */
+	if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
+		IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), frame is not addressed to us!\n");
+		dev_kfree_skb(skb);
+		return;
+	}
 
 	if ((discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
-		DEBUG(0, __FUNCTION__ "(), kmalloc failed!\n");
+		WARNING(__FUNCTION__ "(), kmalloc failed!\n");
+		dev_kfree_skb(skb);
 		return;
 	}
 	memset(discovery, 0, sizeof(discovery_t));
 
-	xid = (struct xid_frame *) skb->data;
-
-	/* 
-	 *  Copy peer device address and set the source address
-	 */
-	info->daddr = le32_to_cpu(xid->saddr);
 	discovery->daddr = info->daddr;
 	discovery->saddr = self->saddr;
 	discovery->timestamp = jiffies;
 
-	DEBUG(4, __FUNCTION__ "(), daddr=%08x\n", discovery->daddr);
+	IRDA_DEBUG(4, __FUNCTION__ "(), daddr=%08x\n", discovery->daddr);
+
+	discovery_info = skb_pull(skb, sizeof(struct xid_frame));
 
 	/* Get info returned from peer */
-	discovery->hints.byte[0] = xid->discovery_info[0];
-	if (xid->discovery_info[0] & HINT_EXTENSION) {
-		DEBUG(4, "EXTENSION\n");
-		discovery->hints.byte[1] = xid->discovery_info[1];
-		discovery->charset = xid->discovery_info[2];
-		text = (char *) &xid->discovery_info[3];
+	discovery->hints.byte[0] = discovery_info[0];
+	if (discovery_info[0] & HINT_EXTENSION) {
+		IRDA_DEBUG(4, "EXTENSION\n");
+		discovery->hints.byte[1] = discovery_info[1];
+		discovery->charset = discovery_info[2];
+		text = (char *) &discovery_info[3];
 	} else {
 		discovery->hints.byte[1] = 0;
-		discovery->charset = xid->discovery_info[1];
-		text = (char *) &xid->discovery_info[2];
+		discovery->charset = discovery_info[1];
+		text = (char *) &discovery_info[2];
 	}
 	/* 
-	 *  Terminate string, should be safe since this is where the 
+	 *  Terminate info string, should be safe since this is where the 
 	 *  FCS bytes resides.
 	 */
 	skb->data[skb->len] = '\0'; 
-	strcpy(discovery->info, text);
+	strncpy(discovery->nickname, text, NICKNAME_MAX_LEN);
+	discovery->name_len = strlen(discovery->nickname);
 
 	info->discovery = discovery;
 
@@ -443,27 +458,29 @@
  *    Received a XID discovery command
  *
  */
-static void irlap_recv_discovery_xid_cmd( struct irlap_cb *self, 
-					  struct sk_buff *skb, 
-					  struct irlap_info *info) 
+static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, 
+					 struct sk_buff *skb, 
+					 struct irlap_info *info) 
 {
 	struct xid_frame *xid;
 	discovery_t *discovery = NULL;
+	__u8 *discovery_info;
 	char *text;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-	ASSERT( info != NULL, return;);
-
 	xid = (struct xid_frame *) skb->data;
-	
-	/* Copy peer device address */
+
 	info->daddr = le32_to_cpu(xid->saddr);
+	info->saddr = le32_to_cpu(xid->daddr);
 
-	switch ( xid->flags & 0x03) {
+	/* Make sure frame is addressed to us */
+	if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
+		IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), frame is not addressed to us!\n");
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	switch (xid->flags & 0x03) {
 	case 0x00:
 		info->S = 1;
 		break;
@@ -478,50 +495,54 @@
 		break;
 	default:
 		/* Error!! */
+		dev_kfree_skb(skb);
 		return;
 	}
 	info->s = xid->slotnr;
 	
+	discovery_info = skb_pull(skb, sizeof(struct xid_frame));
+
 	/* 
 	 *  Check if last frame 
 	 */
-	if ( info->s == 0xff) {
+	if (info->s == 0xff) {
 		/*
 		 *  We now have some discovery info to deliver!
 		 */
-		discovery = kmalloc( sizeof(discovery_t), GFP_ATOMIC);
-		if (!discovery)
+		discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC);
+		if (!discovery) {
+			WARNING(__FUNCTION__ "(), unable to malloc!\n");
+			dev_kfree_skb(skb);
 			return;
+		}
 	      
 		discovery->daddr = info->daddr;
 		discovery->saddr = self->saddr;
 		discovery->timestamp = jiffies;
 
-		DEBUG( 4, __FUNCTION__ "(), daddr=%08x\n", 
-		       discovery->daddr);
-
-		discovery->hints.byte[0] = xid->discovery_info[0];
-		if ( xid->discovery_info[0] & HINT_EXTENSION) {
-			discovery->hints.byte[1] = xid->discovery_info[1];
-			discovery->charset = xid->discovery_info[2];
-			text = (char *) &xid->discovery_info[3];
+		discovery->hints.byte[0] = discovery_info[0];
+		if (discovery_info[0] & HINT_EXTENSION) {
+			discovery->hints.byte[1] = discovery_info[1];
+			discovery->charset = discovery_info[2];
+			text = (char *) &discovery_info[3];
 		} else {
 			discovery->hints.byte[1] = 0;
-			discovery->charset = xid->discovery_info[1];
-			text = (char *) &xid->discovery_info[2];
+			discovery->charset = discovery_info[1];
+			text = (char *) &discovery_info[2];
 		}
 		/* 
 		 *  Terminate string, should be safe since this is where the 
 		 *  FCS bytes resides.
 		 */
 		skb->data[skb->len] = '\0'; 
-		strcpy( discovery->info, text);
+		strncpy(discovery->nickname, text, NICKNAME_MAX_LEN);
+		discovery->name_len = strlen(discovery->nickname);
 
 		info->discovery = discovery;
 	} else
 		info->discovery = NULL;
 	
-	irlap_do_event( self, RECV_DISCOVERY_XID_CMD, skb, info);
+	irlap_do_event(self, RECV_DISCOVERY_XID_CMD, skb, info);
 }
 
 /*
@@ -535,7 +556,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	skb = dev_alloc_skb(32);
+	skb = dev_alloc_skb(16);
 	if (!skb)
 		return;
 	
@@ -550,11 +571,34 @@
 }
 
 /*
+ * Function irlap_send_rd_frame (self)
+ *
+ *    Request disconnect. Used by a secondary station to request the 
+ *    disconnection of the link.
+ */
+void irlap_send_rd_frame(struct irlap_cb *self)
+{
+	struct sk_buff *skb;
+	__u8 *frame;
+
+	skb = dev_alloc_skb(16);
+	if (!skb)
+		return;
+	
+	frame = skb_put(skb, 2);
+	
+	frame[0] = self->caddr;
+	frame[1] = RD_RSP | PF_BIT;
+
+	irlap_queue_xmit(self, skb);
+}
+
+/*
  * Function irlap_recv_rr_frame (skb, info)
  *
  *    Received RR (Receive Ready) frame from peer station, no harm in
  *    making it inline since its called only from one single place
- *    (irlap_input).
+ *    (irlap_driver_rcv).
  */
 static inline void irlap_recv_rr_frame(struct irlap_cb *self, 
 				       struct sk_buff *skb, 
@@ -581,8 +625,7 @@
 	if (!skb)
 		return;
 
-	skb_put( skb, 2);
-	frame = skb->data;
+	frame = skb_put( skb, 2);
 	
 	frame[0] = self->caddr;
 	frame[0] |= (command) ? CMD_FRAME : 0;
@@ -593,7 +636,7 @@
 
 	frame[2] = 0;
 
-   	DEBUG( 4, __FUNCTION__ "(), vr=%d, %ld\n",self->vr, jiffies); 
+   	IRDA_DEBUG(4, __FUNCTION__ "(), vr=%d, %ld\n",self->vr, jiffies); 
 
 	irlap_queue_xmit(self, skb);
 }
@@ -604,20 +647,57 @@
  *    Received RNR (Receive Not Ready) frame from peer station
  *
  */
-static void irlap_recv_rnr_frame( struct irlap_cb *self, struct sk_buff *skb, 
-				  struct irlap_info *info) 
+static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, 
+				 struct irlap_info *info, int command) 
 {
-	__u8 *frame;
+	info->nr = skb->data[1] >> 5;
 
-	ASSERT( skb != NULL, return;);
-	ASSERT( info != NULL, return;);
+	IRDA_DEBUG(4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
 
-	frame = skb->data;
-	info->nr = frame[1] >> 5;
+	if (command)
+		irlap_do_event(self, RECV_RNR_CMD, skb, info);
+	else
+		irlap_do_event(self, RECV_RNR_RSP, skb, info);
+}
+
+static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, 
+				 struct irlap_info *info, int command)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	info->nr = skb->data[1] >> 5;
+	
+	/* Check if this is a command or a response frame */
+	if (command)
+		irlap_do_event(self, RECV_REJ_CMD, skb, info);
+	else
+		irlap_do_event(self, RECV_REJ_RSP, skb, info);
+}
 
-	DEBUG( 4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
+static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, 
+				  struct irlap_info *info, int command)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
-	irlap_do_event( self, RECV_RNR_FRAME, skb, info);
+	info->nr = skb->data[1] >> 5;
+	
+	/* Check if this is a command or a response frame */
+	if (command)
+		irlap_do_event(self, RECV_SREJ_CMD, skb, info);
+	else
+		irlap_do_event(self, RECV_SREJ_RSP, skb, info);
+}
+
+static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, 
+				  struct irlap_info *info, int command)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	/* Check if this is a command or a response frame */
+	if (command)
+		irlap_do_event(self, RECV_DISC_CMD, skb, info);
+	else
+		irlap_do_event(self, RECV_RD_RSP, skb, info);
 }
 
 /*
@@ -626,24 +706,20 @@
  *    Received UA (Unnumbered Acknowledgement) frame
  *
  */
-static void irlap_recv_ua_frame(struct irlap_cb *self, struct sk_buff *skb, 
-				struct irlap_info *info) 
+static inline void irlap_recv_ua_frame(struct irlap_cb *self, 
+				       struct sk_buff *skb, 
+				       struct irlap_info *info) 
 {
- 	DEBUG(4, __FUNCTION__ "(), <%ld>\n", jiffies); 
-
-	ASSERT(skb != NULL, return;);
-	ASSERT(info != NULL, return;);
-
 	irlap_do_event(self, RECV_UA_RSP, skb, info);
 }
 
 /*
  * Function irlap_send_data_primary(self, skb)
  *
- *    
+ *    Send I-frames as the primary station but without the poll bit set
  *
  */
-void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb)
+void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
 {
 	struct sk_buff *tx_skb;
 
@@ -679,17 +755,17 @@
 
 		irlap_send_i_frame( self, tx_skb, CMD_FRAME);
 	} else {
-		DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n");
-		irlap_send_ui_frame(self, skb, CMD_FRAME);
+		IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
+		irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
 		self->window -= 1;
 	}
 }
 /*
- * Function irlap_send_data_primary_poll ( self, skb)
+ * Function irlap_send_data_primary_poll (self, skb)
  *
  *    Send I(nformation) frame as primary with poll bit set
  */
-void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb) 
+void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) 
 {
 	struct sk_buff *tx_skb;
 
@@ -738,17 +814,17 @@
 
 		irlap_send_i_frame(self, tx_skb, CMD_FRAME);
 	} else {
-		DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
 
 		del_timer(&self->poll_timer);
 
 		if (self->ack_required) {
-			irlap_send_ui_frame(self, skb, CMD_FRAME);
+			irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
 			irlap_send_rr_frame(self, CMD_FRAME);
 			self->ack_required = FALSE;
 		} else {
 			skb->data[1] |= PF_BIT;
-			irlap_send_ui_frame(self, skb, CMD_FRAME);
+			irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
 		}
 		self->window = self->window_size;
 		irlap_start_final_timer(self, self->final_timeout);
@@ -766,12 +842,12 @@
 {
 	struct sk_buff *tx_skb = NULL;
 
-	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;);
 
 	/* Is this reliable or unreliable data? */
-	if ( skb->data[1] == I_FRAME) {
+	if (skb->data[1] == I_FRAME) {
 
 		/*  
 		 *  Insert frame sequence number (Vs) in control field before
@@ -779,17 +855,17 @@
 		 */
 		skb->data[1] = I_FRAME | (self->vs << 1);
 		
-		tx_skb = skb_clone( skb, GFP_ATOMIC);
-		if ( tx_skb == NULL) {
-			dev_kfree_skb( skb);
+		tx_skb = skb_clone(skb, GFP_ATOMIC);
+		if (tx_skb == NULL) {
+			dev_kfree_skb(skb);
 			return;
 		}		
 
 		if (skb->sk != NULL)
-			skb_set_owner_w( tx_skb, skb->sk);
+			skb_set_owner_w(tx_skb, skb->sk);
 		
 		/* Insert frame in store */
-		skb_queue_tail( &self->wx_list, skb);
+		skb_queue_tail(&self->wx_list, skb);
 		
 		tx_skb->data[1] |= PF_BIT;
 		
@@ -797,21 +873,21 @@
 		self->window = self->window_size;
 		self->ack_required = FALSE;
 		
-		irlap_start_wd_timer( self, self->wd_timeout);
+		irlap_start_wd_timer(self, self->wd_timeout);
 
-		irlap_send_i_frame( self, tx_skb, RSP_FRAME); 
+		irlap_send_i_frame(self, tx_skb, RSP_FRAME); 
 	} else {
-		if ( self->ack_required) {
-			irlap_send_ui_frame( self, skb, RSP_FRAME);
-			irlap_send_rr_frame( self, RSP_FRAME);
+		if (self->ack_required) {
+			irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
+			irlap_send_rr_frame(self, RSP_FRAME);
 			self->ack_required = FALSE;
 		} else {
 			skb->data[1] |= PF_BIT;
-			irlap_send_ui_frame( self, skb, RSP_FRAME);
+			irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
 		}
 		self->window = self->window_size;
 
-		irlap_start_wd_timer( self, self->wd_timeout);
+		irlap_start_wd_timer(self, self->wd_timeout);
 	}
 }
 
@@ -821,16 +897,12 @@
  *    Send I(nformation) frame as secondary without final bit set
  *
  */
-void irlap_send_data_secondary( struct irlap_cb *self, struct sk_buff *skb) 
+void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) 
 {
 	struct sk_buff *tx_skb = NULL;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-
 	/* Is this reliable or unreliable data? */
-	if ( skb->data[1] == I_FRAME) {
+	if (skb->data[1] == I_FRAME) {
 		
 		/*  
 		 *  Insert frame sequence number (Vs) in control field before
@@ -838,25 +910,25 @@
 		 */
 		skb->data[1] = I_FRAME | (self->vs << 1);
 		
-		tx_skb = skb_clone( skb, GFP_ATOMIC);
-		if ( tx_skb == NULL) {
-			dev_kfree_skb( skb);
+		tx_skb = skb_clone(skb, GFP_ATOMIC);
+		if (tx_skb == NULL) {
+			dev_kfree_skb(skb);
 			return;
 		}		
 		
 		if (skb->sk != NULL)
-			skb_set_owner_w( tx_skb, skb->sk);
+			skb_set_owner_w(tx_skb, skb->sk);
 		
 		/* Insert frame in store */
-		skb_queue_tail( &self->wx_list, skb);
+		skb_queue_tail(&self->wx_list, skb);
 		
 		self->vs = (self->vs + 1) % 8;
 		self->ack_required = FALSE;		
 		self->window -= 1;
 
-		irlap_send_i_frame( self, tx_skb, RSP_FRAME); 
+		irlap_send_i_frame(self, tx_skb, RSP_FRAME); 
 	} else {
-		irlap_send_ui_frame( self, skb, RSP_FRAME);
+		irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
 		self->window -= 1;
 	}
 }
@@ -864,46 +936,37 @@
 /*
  * Function irlap_resend_rejected_frames (nr)
  *
- *    Resend frames which has not been acknowledged. TODO: check that the 
- *    traversal of the list is atomic, i.e that no-one tries to insert or
- *    remove frames from the list while we travers it!
- * 
- *    FIXME: It is not safe to traverse a this list without locking it!
+ *    Resend frames which has not been acknowledged. Should be safe to 
+ *    traverse the list without locking it since this function will only be 
+ *    called from interrupt context (BH)
  */
-void irlap_resend_rejected_frames( struct irlap_cb *self, int command) 
+void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
 {
 	struct sk_buff *tx_skb;
 	struct sk_buff *skb;
 	int count;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-
-	DEBUG(2, __FUNCTION__ "(), retry_count=%d\n", self->retry_count);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Initialize variables */
 	skb = tx_skb = NULL;
 
-	/* 
-	 *  Resend all unacknowledged frames 
-	 */
-	count = skb_queue_len( &self->wx_list);
-	skb = skb_peek( &self->wx_list);
-	while ( skb != NULL) {
-		irlap_wait_min_turn_around( self, &self->qos_tx);
+	count = skb_queue_len(&self->wx_list);
+
+	/*  Resend unacknowledged frame(s) */
+	skb = skb_peek(&self->wx_list);
+	while (skb != NULL) {
+		irlap_wait_min_turn_around(self, &self->qos_tx);
 
 		/* We copy the skb to be retransmitted since we will have to 
 		 * modify it. Cloning will confuse packet sniffers 
 		 */
 		/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
 		tx_skb = skb_copy(skb, GFP_ATOMIC);
-		if ( tx_skb == NULL) {
-			/* Unlink tx_skb from list */
-			tx_skb->next = tx_skb->prev = NULL;
-			tx_skb->list = NULL;
-		
-			dev_kfree_skb( skb);
-			return;	
+		if (!tx_skb) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
+			return;
 		}
 		/* Unlink tx_skb from list */
 		tx_skb->next = tx_skb->prev = NULL;
@@ -912,8 +975,8 @@
 		/*
 		 *  make sure the skb->sk accounting of memory usage is sane
 		 */
-		if ( skb->sk != NULL)
-			skb_set_owner_w( tx_skb, skb->sk);
+		if (skb->sk != NULL)
+			skb_set_owner_w(tx_skb, skb->sk);
 
 		/* Clear old Nr field + poll bit */
 		tx_skb->data[1] &= 0x0f;
@@ -921,41 +984,40 @@
 		/* 
 		 *  Set poll bit on the last frame retransmitted
 		 */
-	 	if ( count-- == 1) 
+	 	if (count-- == 1)
 	 		tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
 		else
 			tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */
 	      	
-		irlap_send_i_frame( self, tx_skb, command);
+		irlap_send_i_frame(self, tx_skb, command);
 
 		/* 
 		 *  If our skb is the last buffer in the list, then
 		 *  we are finished, if not, move to the next sk-buffer
 		 */
-		if ( skb == skb_peek_tail( &self->wx_list))
+		if (skb == skb_peek_tail(&self->wx_list))
 			skb = NULL;
 		else
 			skb = skb->next;
 	}
+#if 0 /* Not yet */
 	/* 
 	 *  We can now fill the window with additinal data frames
 	 */
-	return; /* Skip this for now, DB */
-
-	while ( skb_queue_len( &self->tx_list) > 0) {
+	while (skb_queue_len( &self->txq) > 0) {
 		
-		DEBUG( 0, __FUNCTION__ "(), sending additional frames!\n");
-		if (( skb_queue_len( &self->tx_list) > 0) && 
-		    ( self->window > 0)) {
-			skb = skb_dequeue( &self->tx_list); 
-			ASSERT( skb != NULL, return;);
+		IRDA_DEBUG(0, __FUNCTION__ "(), sending additional frames!\n");
+		if ((skb_queue_len( &self->txq) > 0) && 
+		    (self->window > 0)) {
+			skb = skb_dequeue( &self->txq); 
+			ASSERT(skb != NULL, return;);
 
 			/*
 			 *  If send window > 1 then send frame with pf 
 			 *  bit cleared
 			 */ 
 			if ((self->window > 1) && 
-			    skb_queue_len(&self->tx_list) > 0) 
+			    skb_queue_len(&self->txq) > 0) 
 			{
 				irlap_send_data_primary(self, skb);
 			} else {
@@ -963,6 +1025,52 @@
 			}
 		}
 	}
+#endif
+}
+
+void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
+{
+	struct sk_buff *tx_skb;
+	struct sk_buff *skb;
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+
+	/* Initialize variables */
+	skb = tx_skb = NULL;
+
+	/*  Resend unacknowledged frame(s) */
+	skb = skb_peek(&self->wx_list);
+	if (skb != NULL) {
+		irlap_wait_min_turn_around(self, &self->qos_tx);
+
+		/* We copy the skb to be retransmitted since we will have to 
+		 * modify it. Cloning will confuse packet sniffers 
+		 */
+		/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
+		tx_skb = skb_copy(skb, GFP_ATOMIC);
+		if (!tx_skb) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
+			return;	
+		}
+		/* Unlink tx_skb from list */
+		tx_skb->next = tx_skb->prev = NULL;
+		tx_skb->list = NULL;
+
+		/*
+		 *  make sure the skb->sk accounting of memory usage is sane
+		 */
+		if (skb->sk != NULL)
+			skb_set_owner_w(tx_skb, skb->sk);
+
+		/* Clear old Nr field + poll bit */
+		tx_skb->data[1] &= 0x0f;
+
+		/*  Set poll/final bit */
+		tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
+	      	
+		irlap_send_i_frame(self, tx_skb, command);
+	}
 }
 
 /*
@@ -972,21 +1080,16 @@
  *
  */
 void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, 
-			 int command) 
+			 __u8 caddr, int command)
 {
-	__u8  *frame;
-
-	DEBUG( 4, __FUNCTION__ "()\n");
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
-	frame = skb->data;
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
 	
 	/* Insert connection address */
-	frame[0] = self->caddr;
-	frame[0] |= (command) ? CMD_FRAME : 0;
+	skb->data[0] = caddr | ((command) ? CMD_FRAME : 0);
 
 	irlap_queue_xmit(self, skb);
 }
@@ -999,16 +1102,12 @@
 void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, 
 			int command) 
 {
-	__u8  *frame;
-	
-	frame = skb->data;
-	
 	/* Insert connection address */
-	frame[0] = self->caddr;
-	frame[0] |= (command) ? CMD_FRAME : 0;
+	skb->data[0] = self->caddr;
+	skb->data[0] |= (command) ? CMD_FRAME : 0;
 	
 	/* Insert next to receive (Vr) */
-	frame[1] |= (self->vr << 5);  /* insert nr */
+	skb->data[1] |= (self->vr << 5);  /* insert nr */
 
 	irlap_queue_xmit(self, skb);
 }
@@ -1017,7 +1116,7 @@
  * Function irlap_recv_i_frame (skb, frame)
  *
  *    Receive and parse an I (Information) frame, no harm in making it inline
- *    since it's called only from one single place (irlap_input).
+ *    since it's called only from one single place (irlap_driver_rcv).
  */
 static inline void irlap_recv_i_frame(struct irlap_cb *self, 
 				      struct sk_buff *skb, 
@@ -1027,9 +1126,6 @@
 	info->pf = skb->data[1] & PF_BIT;      /* Final bit */
 	info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */
 
- 	DEBUG(4, __FUNCTION__"(), ns=%d, nr=%d, pf=%d, %ld\n", 
-	      info->ns, info->nr, info->pf>>4, jiffies); 
-
 	/* Check if this is a command or a response frame */
 	if (command)
 		irlap_do_event(self, RECV_I_CMD, skb, info);
@@ -1046,15 +1142,11 @@
 static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, 
 				struct irlap_info *info)
 {
-	__u8 *frame;
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	frame = skb->data;
-
-	info->pf = frame[1] & PF_BIT;      /* Final bit */
+	info->pf = skb->data[1] & PF_BIT;      /* Final bit */
 
-	irlap_do_event( self, RECV_UI_FRAME, skb, info);
+	irlap_do_event(self, RECV_UI_FRAME, skb, info);
 }
 
 /*
@@ -1063,23 +1155,23 @@
  *    Received Frame Reject response.
  *
  */
-static void irlap_recv_frmr_frame( struct irlap_cb *self, struct sk_buff *skb, 
-				   struct irlap_info *info) 
+static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, 
+				  struct irlap_info *info) 
 {
 	__u8 *frame;
 	int w, x, y, z;
 
-	DEBUG( 0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-	ASSERT( info != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+	ASSERT(info != NULL, return;);
 	
 	frame = skb->data;
 
 	info->nr = frame[2] >> 5;          /* Next to receive */
-	info->pf = frame[2] & PF_BIT;        /* Final bit */
+	info->pf = frame[2] & PF_BIT;      /* Final bit */
 	info->ns = (frame[2] >> 1) & 0x07; /* Next to send */
 
 	w = frame[3] & 0x01;
@@ -1087,24 +1179,24 @@
 	y = frame[3] & 0x04;
 	z = frame[3] & 0x08;
 	
-	if ( w) {
-		DEBUG( 0, "Rejected control field is undefined or not "
-		       "implemented.\n");
+	if (w) {
+		IRDA_DEBUG(0, "Rejected control field is undefined or not "
+		      "implemented.\n");
 	} 
-	if ( x) {
-		DEBUG( 0, "Rejected control field was invalid because it "
-		       "contained a non permitted I field.\n");
-	}
-	if ( y) {
-		DEBUG( 0, "Received I field exceeded the maximum negotiated "
-		       "for the existing connection or exceeded the maximum "
-		       "this station supports if no connection exists.\n");
-	}
-	if ( z) {
-		DEBUG( 0, "Rejected control field control field contained an "
-		       "invalid Nr count.\n");
+	if (x) {
+		IRDA_DEBUG(0, "Rejected control field was invalid because it "
+		      "contained a non permitted I field.\n");
+	}
+	if (y) {
+		IRDA_DEBUG(0, "Received I field exceeded the maximum negotiated "
+		      "for the existing connection or exceeded the maximum "
+		      "this station supports if no connection exists.\n");
+	}
+	if (z) {
+		IRDA_DEBUG(0, "Rejected control field control field contained an "
+		      "invalid Nr count.\n");
 	}
-	irlap_do_event( self, RECV_FRMR_RSP, skb, info);
+	irlap_do_event(self, RECV_FRMR_RSP, skb, info);
 }
 
 /*
@@ -1113,35 +1205,34 @@
  *    Send a test frame response
  *
  */
-void irlap_send_test_frame(struct irlap_cb *self, __u32 daddr, 
+void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, 
 			   struct sk_buff *cmd)
 {
 	struct sk_buff *skb;
 	struct test_frame *frame;
-	
+	__u8 *info;
+
 	skb = dev_alloc_skb(32);
 	if (!skb)
 		return;
 
-	skb_put(skb, sizeof(struct test_frame));
-
-	frame = (struct test_frame *) skb->data;
+	/* Broadcast frames must include saddr and daddr fields */
+	if (caddr == CBROADCAST) {
+		frame = (struct test_frame *) 
+			skb_put(skb, sizeof(struct test_frame));
 
-	/* Build header */
-	if (self->state == LAP_NDM)
-		frame->caddr = CBROADCAST; /* Send response */
-	else
-		frame->caddr = self->caddr;
+		/* Insert the swapped addresses */
+		frame->saddr = cpu_to_le32(self->saddr);
+		frame->daddr = cpu_to_le32(daddr);
+	} else
+		frame = (struct test_frame *) skb_put(skb, LAP_MAX_HEADER);
 
+	frame->caddr = caddr;
 	frame->control = TEST_RSP;
 
-	/* Insert the swapped addresses */
-	frame->saddr = cpu_to_le32(self->saddr);
-	frame->daddr = cpu_to_le32(daddr);
-
 	/* Copy info */
-	skb_put(skb, cmd->len);
-	memcpy(frame->info, cmd->data, cmd->len);
+	info = skb_put(skb, cmd->len);
+	memcpy(info, cmd->data, cmd->len);
 
 	/* Return to sender */
 	irlap_wait_min_turn_around(self, &self->qos_tx);
@@ -1154,23 +1245,35 @@
  *    Receive a test frame
  *
  */
-void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, 
-			   struct irlap_info *info, int command)
+static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, 
+				  struct irlap_info *info, int command)
 {
 	struct test_frame *frame;
 
-	DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
-	if (skb->len < sizeof(struct test_frame)) {
-		DEBUG(0, __FUNCTION__ "() test frame to short!\n");
-		return;
-	}
-
 	frame = (struct test_frame *) skb->data;
-
-	/* Read and swap addresses */
-	info->daddr = le32_to_cpu(frame->saddr);
-	info->saddr = le32_to_cpu(frame->daddr);
+		
+	/* Broadcast frames must carry saddr and daddr fields */
+	if (info->caddr == CBROADCAST) {
+		if (skb->len < sizeof(struct test_frame)) {
+			IRDA_DEBUG(0, __FUNCTION__ 
+				   "() test frame to short!\n");
+			dev_kfree_skb(skb);
+			return;
+		}
+		
+		/* Read and swap addresses */
+		info->daddr = le32_to_cpu(frame->saddr);
+		info->saddr = le32_to_cpu(frame->daddr);
+
+		/* Make sure frame is addressed to us */
+		if ((info->saddr != self->saddr) && 
+		    (info->saddr != BROADCAST)) {
+			dev_kfree_skb(skb);
+			return;
+		}
+	}
 
 	if (command)
 		irlap_do_event(self, RECV_TEST_CMD, skb, info);
@@ -1190,36 +1293,36 @@
 {
 	struct irlap_info info;
 	struct irlap_cb *self;
-	struct irda_device *idev;
-	__u8 *frame;
 	int command;
 	__u8 control;
 	
-	idev = (struct irda_device *) dev->priv;
+	/* FIXME: should we get our own field? */
+	self = (struct irlap_cb *) dev->atalk_ptr;
 
-	ASSERT( idev != NULL, return -1;);
-	self = idev->irlap;
+	/* If the net device is down, then IrLAP is gone! */
+	if (!self || self->magic != LAP_MAGIC) {
+		dev_kfree_skb(skb);
+		return -1;
+	}
 
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
-	ASSERT( skb->len > 1, return -1;);
+	/* Check if frame is large enough for parsing */
+	if (skb->len < 2) {
+		ERROR(__FUNCTION__ "(), frame to short!\n");
+		dev_kfree_skb(skb);
+		return -1;
+	}
 	
-	frame = skb->data;
-
-	command    = frame[0] & CMD_FRAME;
-	info.caddr = frame[0] & CBROADCAST;
+	command    = skb->data[0] & CMD_FRAME;
+	info.caddr = skb->data[0] & CBROADCAST;
 	
-	info.pf      = frame[1] &  PF_BIT;
-	info.control = frame[1] & ~PF_BIT; /* Mask away poll/final bit */
+	info.pf      = skb->data[1] &  PF_BIT;
+	info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */
 
 	control = info.control;
 
-	/* 
-	 *  First check if this frame addressed to us 
-	 */
+	/*  First we check if this frame has a valid connection address */
 	if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) {
-		DEBUG(2, __FUNCTION__ "(), Received frame is not for us!\n");
-
+		IRDA_DEBUG(0, __FUNCTION__ "(), wrong connection address!\n");
 		dev_kfree_skb(skb);
 		return 0;
 	}
@@ -1229,7 +1332,6 @@
 	 */
 	if (~control & 0x01) {
 		irlap_recv_i_frame(self, skb, &info, command);
-		self->stats.rx_packets++;
 		return 0;
 	}
 	/*
@@ -1243,22 +1345,22 @@
 		 */
 		switch (control & 0x0f) {
 		case RR:
-			irlap_recv_rr_frame( self, skb, &info, command);
-			self->stats.rx_packets++;
+			irlap_recv_rr_frame(self, skb, &info, command);
 			break;
 		case RNR:
-			irlap_recv_rnr_frame( self, skb, &info);
-			self->stats.rx_packets++;
+			irlap_recv_rnr_frame(self, skb, &info, command);
 			break;
 		case REJ:
-			DEBUG( 0, "*** REJ frame received! ***\n");
+			irlap_recv_rej_frame(self, skb, &info, command);
 			break;
 		case SREJ:
-			DEBUG( 0, "*** SREJ frame received! ***\n");
+			irlap_recv_srej_frame(self, skb, &info, command);
 			break;
 		default:
-			DEBUG( 0, "Unknown S frame %02x received!\n", 
-			       info.control);
+			WARNING(__FUNCTION__ 
+				"() Unknown S-frame %02x received!\n",
+				info.control);
+			dev_kfree_skb(skb);
 			break;
 		}
 		return 0;
@@ -1277,33 +1379,28 @@
 		irlap_recv_snrm_cmd(self, skb, &info);
 		break;
 	case DM_RSP:
-		DEBUG( 0, "DM rsp frame received!\n");
-		irlap_next_state(self, LAP_NDM);
+		irlap_do_event(self, RECV_DM_RSP, skb, &info);
 		break;
-	case DISC_CMD:
-		irlap_do_event(self, RECV_DISC_FRAME, skb, &info);
+	case DISC_CMD: /* And RD_RSP since they have the same value */
+		irlap_recv_disc_frame(self, skb, &info, command);
 		break;
 	case TEST_CMD:
-		DEBUG(0,__FUNCTION__ "(), TEST_FRAME\n");
 		irlap_recv_test_frame(self, skb, &info, command);
 		break;
 	case UA_RSP:
-		DEBUG( 4, "UA rsp frame received!\n");
-		irlap_recv_ua_frame( self, skb, &info);
+		irlap_recv_ua_frame(self, skb, &info);
 		break;
 	case FRMR_RSP:
-		irlap_recv_frmr_frame( self, skb, &info);
+		irlap_recv_frmr_frame(self, skb, &info);
 		break;
 	case UI_FRAME:
-		DEBUG( 4, "UI-frame received!\n");
-		irlap_recv_ui_frame( self, skb, &info);
+		irlap_recv_ui_frame(self, skb, &info);
 		break;
 	default:
-		DEBUG( 0, "Unknown frame %02x received!\n", info.control);
-		dev_kfree_skb( skb); 
+		WARNING(__FUNCTION__ "(), Unknown frame %02x received!\n", 
+			info.control);
+		dev_kfree_skb(skb); 
 		break;
 	}
-	self->stats.rx_packets++;
-
 	return 0;
 }
diff -urN linux-2.2.15-pre2/net/irda/irlmp.c linux/net/irda/irlmp.c
--- linux-2.2.15-pre2/net/irda/irlmp.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlmp.c	Mon Dec  3 21:57:53 2001
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      irlmp.c
- * Version:       0.9
+ * Version:       1.0
  * Description:   IrDA Link Management Protocol (LMP) layer                 
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Mon May 31 21:49:41 1999
+ * Modified at:   Sun Jan  9 07:43:35 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -32,7 +32,6 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/random.h>
-#include <linux/irda.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
@@ -47,8 +46,9 @@
 struct irlmp_cb *irlmp = NULL;
 
 /* These can be altered by the sysctl interface */
-int  sysctl_discovery = 0;
-int  sysctl_discovery_slots = 6;
+int  sysctl_discovery         = 0;
+int  sysctl_discovery_timeout = 3; /* 3 seconds by default */
+int  sysctl_discovery_slots   = 6; /* 6 slots by default */
 char sysctl_devname[65];
 
 char *lmp_reasons[] = {
@@ -61,7 +61,7 @@
 	"ERROR, NOT USED",
 };
 
-__u8 *irlmp_hint_to_service( __u8 *hint);
+__u8 *irlmp_hint_to_service(__u8 *hint);
 #ifdef CONFIG_PROC_FS
 int irlmp_proc_read(char *buf, char **start, off_t offst, int len, int unused);
 #endif
@@ -69,20 +69,19 @@
 /*
  * Function irlmp_init (void)
  *
- *    Create (allocate) the main IrLMP structure and the pointer array
- *    which will contain pointers to each instance of a LSAP.
+ *    Create (allocate) the main IrLMP structure
+ *
  */
-__initfunc(int irlmp_init(void))
+int __init irlmp_init(void)
 {
 	/* Initialize the irlmp structure. */
-	if ( irlmp == NULL) {
-		irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
-		if ( irlmp == NULL)
-			return -ENOMEM;
-	}
-	memset( irlmp, 0, sizeof(struct irlmp_cb));
+	irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
+	if (irlmp == NULL)
+		return -ENOMEM;
+	memset(irlmp, 0, sizeof(struct irlmp_cb));
 	
 	irlmp->magic = LMP_MAGIC;
+	spin_lock_init(&irlmp->lock);
 
 	irlmp->clients = hashbin_new(HB_GLOBAL);
 	irlmp->services = hashbin_new(HB_GLOBAL);
@@ -90,7 +89,7 @@
 	irlmp->unconnected_lsaps = hashbin_new(HB_GLOBAL);
 	irlmp->cachelog = hashbin_new(HB_GLOBAL);
 	
-	irlmp->free_lsap_sel = 0x10; /* Servers use 0x00-0x0f */
+	irlmp->free_lsap_sel = 0x10; /* Reserved 0x00-0x0f */
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 	irlmp->cache.valid = FALSE;
 #endif
@@ -98,7 +97,7 @@
 	
 	/* Do discovery every 3 seconds */
 	init_timer(&irlmp->discovery_timer);
-   	irlmp_start_discovery_timer(irlmp, 600); 
+   	irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout*HZ);
 
 	return 0;
 }
@@ -134,7 +133,7 @@
  *   Register with IrLMP and create a local LSAP,
  *   returns handle to LSAP.
  */
-struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, struct notify_t *notify)
+struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid)
 {
 	struct lsap_cb *self;
 
@@ -142,42 +141,33 @@
 	ASSERT(irlmp != NULL, return NULL;);
 	ASSERT(irlmp->magic == LMP_MAGIC, return NULL;);
 
-	DEBUG(4, __FUNCTION__ "(), slsap_sel=%02x\n", slsap_sel);
-
-	/* 
-	 *  Does the client care which Source LSAP selector it gets? 
-	 */
+	/*  Does the client care which Source LSAP selector it gets?  */
 	if (slsap_sel == LSAP_ANY) {
-		/*
-		 *  Find unused LSAP
-		 */
 		slsap_sel = irlmp_find_free_slsap();
-		if ( slsap_sel == 0)
+		if (!slsap_sel)
 			return NULL;
-	} else {
-		/*
-		 *  Client wants specific LSAP, so check if it's already
-		 *  in use
-		 */
-		if (irlmp_slsap_inuse(slsap_sel)) {
-			return NULL;
-		}
-	}
+	} else if (irlmp_slsap_inuse(slsap_sel))
+		return NULL;
 
-	/*
-	 *  Allocate new instance of a LSAP connection
-	 */
+	/* Allocate new instance of a LSAP connection */
 	self = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
 	if (self == NULL) {
-		printk( KERN_ERR "IrLMP: Can't allocate memory for "
-			"LSAP control block!\n");
+		ERROR(__FUNCTION__ "(), can't allocate memory");
 		return NULL;
 	}
 	memset(self, 0, sizeof(struct lsap_cb));
 	
 	self->magic = LMP_LSAP_MAGIC;
 	self->slsap_sel = slsap_sel;
-	self->dlsap_sel = LSAP_ANY;
+
+	/* Fix connectionless LSAP's */
+	if (slsap_sel == LSAP_CONNLESS) {
+#ifdef CONFIG_IRDA_ULTRA
+		self->dlsap_sel = LSAP_CONNLESS;
+		self->pid = pid;
+#endif /* CONFIG_IRDA_ULTRA */
+	} else
+		self->dlsap_sel = LSAP_ANY;
 	self->connected = FALSE;
 
 	init_timer(&self->watchdog_timer);
@@ -187,10 +177,8 @@
 
 	irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 	
-	/*
-	 *  Insert into queue of unconnected LSAPs
-	 */
-	hashbin_insert(irlmp->unconnected_lsaps, (QUEUE *) self, (int) self, 
+	/* Insert into queue of unconnected LSAPs */
+	hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) self, (int) self, 
 		       NULL);
 	
 	return self;
@@ -203,7 +191,7 @@
  */
 static void __irlmp_close_lsap(struct lsap_cb *self)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -211,9 +199,12 @@
 	/*
 	 *  Set some of the variables to preset values
 	 */
-	self->magic = ~LMP_LSAP_MAGIC;
+	self->magic = 0;
 	del_timer(&self->watchdog_timer); /* Important! */
 
+	if (self->conn_skb)
+		dev_kfree_skb(self->conn_skb);
+
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 	ASSERT(irlmp != NULL, return;);
 	irlmp->cache.valid = FALSE;
@@ -250,8 +241,8 @@
 				      NULL);
 	}
 	if (!lsap) {
-		DEBUG(0, __FUNCTION__ 
-		       "(), Looks like somebody has removed me already!\n");
+		IRDA_DEBUG(0, __FUNCTION__ 
+		     "(), Looks like somebody has removed me already!\n");
 		return;
 	}
 	__irlmp_close_lsap(self);
@@ -264,13 +255,10 @@
  *    instances of the IrLAP layer, each connected to different IrDA ports
  *
  */
-void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, 
-			 struct notify_t *notify)
+void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify)
 {
 	struct lap_cb *lap;
 
-	DEBUG(4, __FUNCTION__ "(), Registered IrLAP, saddr = %08x\n", saddr);
-	
 	ASSERT(irlmp != NULL, return;);
 	ASSERT(irlmp->magic == LMP_MAGIC, return;);
 	ASSERT(notify != NULL, return;);
@@ -280,7 +268,7 @@
 	 */
 	lap = kmalloc(sizeof(struct lap_cb), GFP_KERNEL);
 	if (lap == NULL) {
-		DEBUG(3, __FUNCTION__ "(), unable to kmalloc\n");
+		ERROR(__FUNCTION__ "(), unable to kmalloc\n");
 		return;
 	}
 	memset(lap, 0, sizeof(struct lap_cb));
@@ -298,7 +286,7 @@
 	/*
 	 *  Insert into queue of unconnected LSAPs
 	 */
-	hashbin_insert(irlmp->links, (QUEUE *) lap, lap->saddr, NULL);
+	hashbin_insert(irlmp->links, (queue_t *) lap, lap->saddr, NULL);
 
 	/* 
 	 *  We set only this variable so IrLAP can tell us on which link the
@@ -318,7 +306,7 @@
 {
 	struct lap_cb *link;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	link = hashbin_remove(irlmp->links, saddr, NULL);
 	if (link) {
@@ -349,20 +337,20 @@
 	struct lsap_cb *lsap;
 	discovery_t *discovery;
 
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -EBADR;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
 	
-	DEBUG(2, __FUNCTION__ 
+	IRDA_DEBUG(2, __FUNCTION__ 
 	      "(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", 
 	      self->slsap_sel, dlsap_sel, saddr, daddr);
 	
-	if ( self->connected) 
+	if (self->connected) 
 		return -EISCONN;
-
+	
 	/* Client must supply destination device address */
 	if (!daddr)
 		return -EINVAL;
-
+	
 	/* Any userdata? */
 	if (userdata == NULL) {
 		skb = dev_alloc_skb(64);
@@ -378,7 +366,6 @@
 	skb_push(skb, LMP_CONTROL_HEADER);
 
 	self->dlsap_sel = dlsap_sel;
-	self->tmp_skb = skb;
 	
 	/*  
 	 * Find the link to where we should try to connect since there may
@@ -389,20 +376,29 @@
 	 * device with the given daddr 
 	 */
 	if (!saddr) {
-		discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
-		if (discovery)
+		if (daddr != DEV_ADDR_ANY)
+			discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
+		else {
+			IRDA_DEBUG(2, __FUNCTION__ "(), no daddr\n");
+			discovery = (discovery_t *) 
+				hashbin_get_first(irlmp->cachelog);
+		}
+
+		if (discovery) {
 			saddr = discovery->saddr;
+			daddr = discovery->daddr;
+		}
 	}
 	lap = hashbin_find(irlmp->links, saddr, NULL);	
 	if (lap == NULL) {
-		DEBUG(1, __FUNCTION__ "(), Unable to find a usable link!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unable to find a usable link!\n");
 		return -EHOSTUNREACH;
 	}
 
 	if (lap->daddr == DEV_ADDR_ANY)
 		lap->daddr = daddr;
 	else if (lap->daddr != daddr) {
-		DEBUG(0, __FUNCTION__ "(), sorry, but link is busy!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but link is busy!\n");
 		return -EBUSY;
 	}
 
@@ -419,7 +415,7 @@
 	ASSERT(lsap->lap != NULL, return -1;);
 	ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
 
-	hashbin_insert(self->lap->lsaps, (QUEUE *) self, (int) self, NULL);
+	hashbin_insert(self->lap->lsaps, (queue_t *) self, (int) self, NULL);
 
 	self->connected = TRUE;
 	
@@ -451,23 +447,18 @@
 	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);
-
+	IRDA_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-LMP_HEADER;
-	DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
-	
-	lap_header_size = irlap_get_header_size(self->lap->irlap);
-
+	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, 
@@ -480,22 +471,40 @@
  *    Service user is accepting connection
  *
  */
-void irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) 
+int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) 
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT(userdata != NULL, return;);
-
-	self->connected = TRUE;
+	struct sk_buff *skb;
 
-	DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
-	      self->slsap_sel, self->dlsap_sel);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
-	/* Make room for MUX control header ( 3 bytes) */
-	ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return;);
-	skb_push(userdata, LMP_CONTROL_HEADER);
+	/* Any userdata supplied? */
+	if (!userdata) {
+		skb = dev_alloc_skb(64);
+		if (!skb)
+			return -ENOMEM;
+		
+		/* Reserve space for MUX_CONTROL and LAP header */
+		skb_reserve(skb, LMP_MAX_HEADER);
+	} else {
+		skb = userdata;
+		/*  
+		 *  Check that the client has reserved enough space for 
+		 *  headers
+		 */
+		ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;);
+	}
+	
+	self->connected = TRUE;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+		   self->slsap_sel, self->dlsap_sel);
 	
-	irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
+	/* Make room for MUX control header (3 bytes) */
+	skb_push(skb, LMP_CONTROL_HEADER);	
+	irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, skb);
+	
+	return 0;
 }
 
 /*
@@ -505,34 +514,32 @@
  */
 void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) 
 {
-	int max_seg_size;
 	int max_header_size;
 	int lap_header_size;
+	int max_seg_size;
 
-	DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 	
 	ASSERT(skb != NULL, return;);
 	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-	
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);	
 	ASSERT(self->lap != NULL, return;);
-	self->qos = *self->lap->qos;
 
-	max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
-	DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
+	self->qos = *self->lap->qos;
 
-	lap_header_size = irlap_get_header_size(self->lap->irlap);
-	
+	max_seg_size    = self->lap->qos->data_size.value-LMP_HEADER;
+	lap_header_size = 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);
+	IRDA_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_confirm) {
 		self->notify.connect_confirm(self->notify.instance, self,
-					     &self->qos, max_seg_size, 
+					     &self->qos, max_seg_size,
 					     max_header_size, skb);
 	}
 }
@@ -548,16 +555,16 @@
 {
 	struct lsap_cb *new;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	/* Only allowed to duplicate unconnected LSAP's */
 	if (!hashbin_find(irlmp->unconnected_lsaps, (int) orig, NULL)) {
-		DEBUG(0, __FUNCTION__ "(), unable to find LSAP\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to find LSAP\n");
 		return NULL;
 	}
 	new = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
 	if (!new)  {
-		DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
 		return NULL;
 	}
 	/* Dup */
@@ -566,7 +573,7 @@
 	
 	init_timer(&new->watchdog_timer);
 	
-	hashbin_insert(irlmp->unconnected_lsaps, (QUEUE *) new, (int) new, 
+	hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) new, (int) new, 
 		       NULL);
 
 	/* Make sure that we invalidate the cache */
@@ -583,53 +590,53 @@
  *    The service user is requesting disconnection, this will not remove the 
  *    LSAP, but only mark it as disconnected
  */
-void irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) 
+int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) 
 {
 	struct lsap_cb *lsap;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
 	/* Already disconnected? */
-	if ( !self->connected) {
-		DEBUG( 1, __FUNCTION__ "(), already disconnected!\n");
-		return;
+	if (!self->connected) {
+		WARNING(__FUNCTION__ "(), already disconnected!\n");
+		return -1;
 	}
 
-	ASSERT( userdata != NULL, return;);
-	ASSERT( self->connected == TRUE, return;);
+	ASSERT(userdata != NULL, return -1;);
+	ASSERT(self->connected == TRUE, return -1;);
 	
-	skb_push( userdata, LMP_CONTROL_HEADER);
+	skb_push(userdata, LMP_CONTROL_HEADER);
 
 	/* 
 	 *  Do the event before the other stuff since we must know
 	 *  which lap layer that the frame should be transmitted on
 	 */
-	irlmp_do_lsap_event( self, LM_DISCONNECT_REQUEST, userdata);
+	irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata);
 
 	/* 
 	 *  Remove LSAP from list of connected LSAPs for the particular link
 	 *  and insert it into the list of unconnected LSAPs
 	 */
-	ASSERT( self->lap != NULL, return;);
-	ASSERT( self->lap->magic == LMP_LAP_MAGIC, return;);
-	ASSERT( self->lap->lsaps != NULL, return;);
+	ASSERT(self->lap != NULL, return -1;);
+	ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
+	ASSERT(self->lap->lsaps != NULL, return -1;);
 
 	lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
 
-	ASSERT( lsap != NULL, return;);
-	ASSERT( lsap->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT( lsap == self, return;);
+	ASSERT(lsap != NULL, return -1;);
+	ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
+	ASSERT(lsap == self, return -1;);
 
-	hashbin_insert(irlmp->unconnected_lsaps, (QUEUE *) self, (int) self, 
+	hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) self, (int) self, 
 		       NULL);
 	
 	/* Reset some values */
 	self->connected = FALSE;
 	self->dlsap_sel = LSAP_ANY;
 	self->lap = NULL;
+	
+	return 0;
 }
 
 /*
@@ -642,14 +649,13 @@
 {
 	struct lsap_cb *lsap;
 
-	DEBUG( 1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);	
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
- 	ASSERT( self->connected == TRUE, return;); 
+	IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);	
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+ 	ASSERT(self->connected == TRUE, return;); 
 
-	DEBUG( 3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
-	       self->slsap_sel, self->dlsap_sel);
+	IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+		   self->slsap_sel, self->dlsap_sel);
 
 	self->connected = FALSE;
 	self->dlsap_sel = LSAP_ANY;
@@ -661,14 +667,14 @@
 	/* 
 	 *  Remove association between this LSAP and the link it used 
 	 */
-	ASSERT( self->lap != NULL, return;);
-	ASSERT( self->lap->lsaps != NULL, return;);
+	ASSERT(self->lap != NULL, return;);
+	ASSERT(self->lap->lsaps != NULL, return;);
 
-	lsap = hashbin_remove( self->lap->lsaps, (int) self, NULL);
+	lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
 
-	ASSERT( lsap != NULL, return;);
-	ASSERT( lsap == self, return;);
-	hashbin_insert(irlmp->unconnected_lsaps, (QUEUE *) lsap, (int) lsap, 
+	ASSERT(lsap != NULL, return;);
+	ASSERT(lsap == self, return;);
+	hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) lsap, (int) lsap, 
 		       NULL);
 
 	self->lap = NULL;
@@ -676,9 +682,12 @@
 	/*
 	 *  Inform service user
 	 */
-	if ( self->notify.disconnect_indication) {
-		self->notify.disconnect_indication( self->notify.instance, 
-						    self, reason, userdata);
+	if (self->notify.disconnect_indication)
+		self->notify.disconnect_indication(self->notify.instance, 
+						   self, reason, userdata);
+	else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n");
+		dev_kfree_skb(userdata);
 	}
 }
 
@@ -692,9 +701,9 @@
 {
 	struct lap_cb *lap;
 
-	/* Make sure value is sane */
-	if ((nslots != 1) && (nslots != 6) && (nslots != 8)&&(nslots != 16)) {
-		printk(KERN_WARNING __FUNCTION__ 
+	/* Make sure the value is sane */
+	if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
+		WARNING(__FUNCTION__ 
 		       "(), invalid value for number of slots!\n");
 		nslots = sysctl_discovery_slots = 8;
 	}
@@ -708,8 +717,9 @@
 	 *  end
 	 */
 	irlmp->discovery_cmd.charset = CS_ASCII;
-	strncpy(irlmp->discovery_cmd.info, sysctl_devname, 31);
-	irlmp->discovery_cmd.info_len = strlen(irlmp->discovery_cmd.info);
+	strncpy(irlmp->discovery_cmd.nickname, sysctl_devname, 
+		NICKNAME_MAX_LEN);
+	irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.nickname);
 	irlmp->discovery_cmd.nslots = nslots;
 	
 	/*
@@ -740,21 +750,18 @@
  */
 void irlmp_discovery_request(int nslots)
 {
-	DEBUG(4, __FUNCTION__ "(), nslots=%d\n", nslots);
-
 	/* Check if user wants to override the default */
 	if (nslots == DISCOVERY_DEFAULT_SLOTS)
 		nslots = sysctl_discovery_slots;
 
+	/* Return current cached discovery log */
+	irlmp_discovery_confirm(irlmp->cachelog);
+
 	/* 
-	 * If discovery is already running, then just return the current 
-	 * discovery log
+	 * Start a single discovery operation if discovery is not already
+         * running 
 	 */
-	if (sysctl_discovery) {
-		DEBUG(2, __FUNCTION__ "() discovery already running, so we"
-		      " just return the old discovery log!\n");
-		irlmp_discovery_confirm(irlmp->cachelog);
-	} else
+	if (!sysctl_discovery)
 		irlmp_do_discovery(nslots);
 }
 
@@ -773,8 +780,8 @@
 	__u8 service;
 	int i = 0;
 
-	DEBUG(1, "IrDA Discovered: %s\n", discovery->info);
-	DEBUG(1, "    Services: ");
+	IRDA_DEBUG(1, "IrDA Discovered: %s\n", discovery->info);
+	IRDA_DEBUG(1, "    Services: ");
 
 	service_log = irlmp_hint_to_service(discovery->hints.byte);
 	if (!service_log)
@@ -784,10 +791,10 @@
 	 *  Check all services on the device
 	 */
 	while ((service = service_log[i++]) != S_END) {
-		DEBUG( 4, "service=%02x\n", service);
+		IRDA_DEBUG( 4, "service=%02x\n", service);
 		client = hashbin_find(irlmp->registry, service, NULL);
 		if (entry && entry->discovery_callback) {
-			DEBUG( 4, "discovery_callback!\n");
+			IRDA_DEBUG( 4, "discovery_callback!\n");
 
 			entry->discovery_callback(discovery);
 		} else {
@@ -819,7 +826,7 @@
 {
 	discovery_t *discovery;
 
-	DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 	
 	/* Check if client wants the whole log */
 	if (client->callback2)
@@ -831,9 +838,13 @@
 	 */
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
-		DEBUG(3, "discovery->daddr = 0x%08x\n", discovery->daddr); 
+		IRDA_DEBUG(3, "discovery->daddr = 0x%08x\n", discovery->daddr); 
 		
-		if (client->hint_mask & discovery->hints.word) {
+		/* 
+		 * Any common hint bits? Remember to mask away the extension
+		 * bits ;-)
+		 */
+		if (client->hint_mask & discovery->hints.word & 0x7f7f) {
 			if (client->callback1)
 				client->callback1(discovery);
 		}
@@ -852,11 +863,11 @@
 {
 	irlmp_client_t *client;
 	
-	DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 	
 	ASSERT(log != NULL, return;);
 	
-	if (!hashbin_get_size(log))
+	if (!(HASHBIN_GET_SIZE(log)))
 		return;
 	
 	client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
@@ -876,7 +887,7 @@
  */
 discovery_t *irlmp_get_discovery_response()
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(irlmp != NULL, return NULL;);
 
@@ -889,8 +900,9 @@
 	 */
 	irlmp->discovery_rsp.charset = CS_ASCII;
 
-	strncpy(irlmp->discovery_rsp.info, sysctl_devname, 31);
-	irlmp->discovery_rsp.info_len = strlen(irlmp->discovery_rsp.info) + 2;
+	strncpy(irlmp->discovery_rsp.nickname, sysctl_devname, 
+		NICKNAME_MAX_LEN);
+	irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.nickname);
 
 	return &irlmp->discovery_rsp;
 }
@@ -901,17 +913,16 @@
  *    Send some data to peer device
  *
  */
-void irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb) 
+int irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb) 
 {
-	ASSERT(skb != NULL, return;);
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 	
 	/* Make room for MUX header */
-	ASSERT(skb_headroom( skb) >= LMP_HEADER, return;);
+	ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
 	skb_push(skb, LMP_HEADER);
-
-	irlmp_do_lsap_event(self, LM_DATA_REQUEST, skb);
+	
+	return irlmp_do_lsap_event(self, LM_DATA_REQUEST, skb);
 }
 
 /*
@@ -920,13 +931,15 @@
  *    Got data from LAP layer so pass it up to upper layer
  *
  */
-inline void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) 
+void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
 	/* Hide LMP header from layer above */
 	skb_pull(skb, LMP_HEADER);
 
 	if (self->notify.data_indication)
 		self->notify.data_indication(self->notify.instance, self, skb);
+	else
+		dev_kfree_skb(skb);
 }
 
 /*
@@ -935,17 +948,17 @@
  *    
  *
  */
-inline void irlmp_udata_request( struct lsap_cb *self, struct sk_buff *skb) 
+int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb) 
 {
- 	DEBUG( 4, __FUNCTION__ "()\n"); 
+ 	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
 
-	ASSERT( skb != NULL, return;);
+	ASSERT(skb != NULL, return -1;);
 	
 	/* Make room for MUX header */
-	ASSERT( skb_headroom( skb) >= LMP_HEADER, return;);
-	skb_push( skb, LMP_HEADER);
+	ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
+	skb_push(skb, LMP_HEADER);
 
-	irlmp_do_lsap_event( self, LM_UDATA_REQUEST, skb);
+	return irlmp_do_lsap_event(self, LM_UDATA_REQUEST, skb);
 }
 
 /*
@@ -954,51 +967,104 @@
  *    Send unreliable data (but still within the connection)
  *
  */
-void irlmp_udata_indication( struct lsap_cb *self, struct sk_buff *skb) 
+void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
- 	DEBUG( 4, __FUNCTION__ "()\n"); 
+ 	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
 
-	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(skb != NULL, return;);
 
 	/* Hide LMP header from layer above */
-	skb_pull( skb, LMP_HEADER);
+	skb_pull(skb, LMP_HEADER);
 
 	if (self->notify.udata_indication)
-		self->notify.udata_indication(self->notify.instance, self, skb);
+		self->notify.udata_indication(self->notify.instance, self, 
+					      skb);
+	else
+		dev_kfree_skb(skb);
 }
 
 /*
- * Function irlmp_connection_less_data_request (skb)
+ * Function irlmp_connless_data_request (self, skb)
  *
- *    Send out of connection UI frames
+ *    
  *
  */
-void irlmp_connectionless_data_request( struct sk_buff *skb)
+#ifdef CONFIG_IRDA_ULTRA
+int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *skb) 
 {
-	DEBUG( 1, __FUNCTION__ "(), Sorry not implemented\n"); 
+	struct sk_buff *clone_skb;
+	struct lap_cb *lap;
+
+ 	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+
+	ASSERT(skb != NULL, return -1;);
+	
+	/* Make room for MUX and PID header */
+	ASSERT(skb_headroom(skb) >= LMP_HEADER+LMP_PID_HEADER, return -1;);
+	
+	/* Insert protocol identifier */
+	skb_push(skb, LMP_PID_HEADER);
+	skb->data[0] = self->pid;
+
+	/* Connectionless sockets must use 0x70 */
+	skb_push(skb, LMP_HEADER);
+	skb->data[0] = skb->data[1] = LSAP_CONNLESS;
+
+	/* Try to send Connectionless  packets out on all links */
+	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
+	while (lap != NULL) {
+		ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
+
+		clone_skb = skb_clone(skb, GFP_ATOMIC);
+		if (!clone_skb)
+			return -ENOMEM;
+
+		irlap_unitdata_request(lap->irlap, clone_skb);
+		
+		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
+	}
+	dev_kfree_skb(skb);
+
+	return 0;
 }
+#endif /* CONFIG_IRDA_ULTRA */
 
 /*
- * Function irlmp_connection_less_data_indication (skb)
+ * Function irlmp_connless_data_indication (self, skb)
  *
- *    
+ *    Receive unreliable data outside any connection. Mostly used by Ultra
  *
  */
-void irlmp_connectionless_data_indication( struct sk_buff *skb)
+#ifdef CONFIG_IRDA_ULTRA
+void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
-	DEBUG( 1, __FUNCTION__ "()\n"); 
+ 	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+
+	/* Hide LMP and PID header from layer above */
+	skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
+
+	if (self->notify.udata_indication)
+		self->notify.udata_indication(self->notify.instance, self,
+					      skb);
+	else
+		dev_kfree_skb(skb);
 }
+#endif /* CONFIG_IRDA_ULTRA */
 
 void irlmp_status_request(void) 
 {
-	DEBUG( 1, "irlmp_status_request(), Not implemented\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
 }
 
 void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock) 
 {
-	DEBUG( 4, "irlmp_status_indication(), Not implemented\n");
+	IRDA_DEBUG(1, __FUNCTION__ "(), Not implemented\n");
 }
 
 /*
@@ -1016,32 +1082,33 @@
 	 * Allocate array to store services in. 16 entries should be safe 
 	 * since we currently only support 2 hint bytes
 	 */
-	service = kmalloc( 16, GFP_ATOMIC);
-	if ( !service) {
-		DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
+	service = kmalloc(16, GFP_ATOMIC);
+	if (!service) {
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
 		return NULL;
 	}
 
-	if ( !hint[0]) {
-		DEBUG(1, "<None>\n");
+	if (!hint[0]) {
+		IRDA_DEBUG(1, "<None>\n");
+		kfree(service);
 		return NULL;
 	}
-	if ( hint[0] & HINT_PNP)
-		DEBUG(1, "PnP Compatible ");
-	if ( hint[0] & HINT_PDA)
-		DEBUG(1, "PDA/Palmtop ");
-	if ( hint[0] & HINT_COMPUTER)
-		DEBUG(1, "Computer ");
-	if ( hint[0] & HINT_PRINTER) {
-		DEBUG(1, "Printer ");
+	if (hint[0] & HINT_PNP)
+		IRDA_DEBUG(1, "PnP Compatible ");
+	if (hint[0] & HINT_PDA)
+		IRDA_DEBUG(1, "PDA/Palmtop ");
+	if (hint[0] & HINT_COMPUTER)
+		IRDA_DEBUG(1, "Computer ");
+	if (hint[0] & HINT_PRINTER) {
+		IRDA_DEBUG(1, "Printer ");
 		service[i++] = S_PRINTER;
 	}
-	if ( hint[0] & HINT_MODEM)
-		DEBUG(1, "Modem ");
-	if ( hint[0] & HINT_FAX)
-		DEBUG(1, "Fax ");
-	if ( hint[0] & HINT_LAN) {
-		DEBUG(1, "LAN Access ");		
+	if (hint[0] & HINT_MODEM)
+		IRDA_DEBUG(1, "Modem ");
+	if (hint[0] & HINT_FAX)
+		IRDA_DEBUG(1, "Fax ");
+	if (hint[0] & HINT_LAN) {
+		IRDA_DEBUG(1, "LAN Access ");		
 		service[i++] = S_LAN;
 	}
 	/* 
@@ -1049,23 +1116,23 @@
 	 *  there, but this is not really required by the standard.
 	 *  (IrLMP p. 29)
 	 */
-	if ( hint[0] & HINT_EXTENSION) {
-		if ( hint[1] & HINT_TELEPHONY) {
-			DEBUG(1, "Telephony ");
+	if (hint[0] & HINT_EXTENSION) {
+		if (hint[1] & HINT_TELEPHONY) {
+			IRDA_DEBUG(1, "Telephony ");
 			service[i++] = S_TELEPHONY;
-		} if ( hint[1] & HINT_FILE_SERVER)
-			DEBUG(1, "File Server ");
+		} if (hint[1] & HINT_FILE_SERVER)
+			IRDA_DEBUG(1, "File Server ");
 		
-		if ( hint[1] & HINT_COMM) {
-			DEBUG(1, "IrCOMM ");
+		if (hint[1] & HINT_COMM) {
+			IRDA_DEBUG(1, "IrCOMM ");
 			service[i++] = S_COMM;
 		}
-		if ( hint[1] & HINT_OBEX) {
-			DEBUG(1, "IrOBEX ");
+		if (hint[1] & HINT_OBEX) {
+			IRDA_DEBUG(1, "IrOBEX ");
 			service[i++] = S_OBEX;
 		}
 	}
-	DEBUG(1, "\n");
+	IRDA_DEBUG(1, "\n");
 
 	/* So that client can be notified about any discovery */
 	service[i++] = S_ANY;
@@ -1115,11 +1182,15 @@
 		hint.byte[0] |= HINT_EXTENSION;
 		hint.byte[1] |= HINT_OBEX;
 		break;
+	case S_TELEPHONY:
+		hint.byte[0] |= HINT_EXTENSION;
+		hint.byte[1] |= HINT_TELEPHONY;
+		break;
 	case S_ANY:
 		hint.word = 0xffff;
 		break;
 	default:
-		DEBUG( 1, __FUNCTION__ "(), Unknown service!\n");
+		IRDA_DEBUG( 1, __FUNCTION__ "(), Unknown service!\n");
 		break;
 	}
 	return hint.word;
@@ -1136,7 +1207,7 @@
 	irlmp_service_t *service;
 	__u32 handle;
 
-	DEBUG(4, __FUNCTION__ "(), hints = %04x\n", hints);
+	IRDA_DEBUG(4, __FUNCTION__ "(), hints = %04x\n", hints);
 
 	/* Get a unique handle for this service */
 	get_random_bytes(&handle, sizeof(handle));
@@ -1148,11 +1219,11 @@
 	/* Make a new registration */
  	service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
 	if (!service) {
-		DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
 		return 0;
 	}
 	service->hints = hints;
-	hashbin_insert(irlmp->services, (QUEUE*) service, handle, NULL);
+	hashbin_insert(irlmp->services, (queue_t *) service, handle, NULL);
 
 	return handle;
 }
@@ -1168,14 +1239,14 @@
 {
 	irlmp_service_t *service;
 		
- 	DEBUG(4, __FUNCTION__ "()\n");
+ 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	if (!handle)
 		return -1;
  
 	service = hashbin_find(irlmp->services, handle, NULL);
 	if (!service) {
-		DEBUG(1, __FUNCTION__ "(), Unknown service!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown service!\n");
 		return -1;
 	}
 
@@ -1217,7 +1288,7 @@
 	/* Make a new registration */
  	client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
 	if (!client) {
-		DEBUG( 1, __FUNCTION__ "(), Unable to kmalloc!\n");
+		IRDA_DEBUG( 1, __FUNCTION__ "(), Unable to kmalloc!\n");
 
 		return 0;
 	}
@@ -1227,7 +1298,7 @@
 	client->callback1 = callback1;
 	client->callback2 = callback2;
 
- 	hashbin_insert(irlmp->clients, (QUEUE *) client, handle, NULL);
+ 	hashbin_insert(irlmp->clients, (queue_t *) client, handle, NULL);
 
 	return handle;
 }
@@ -1251,7 +1322,7 @@
 
 	client = hashbin_find(irlmp->clients, handle, NULL);
 	if (!client) {
-		DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
 		return -1;
 	}
 
@@ -1272,18 +1343,18 @@
 {
  	struct irlmp_client *client;
  
- 	DEBUG(4, __FUNCTION__ "()\n");
+ 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	if (!handle)
 		return -1;
  
 	client = hashbin_find(irlmp->clients, handle, NULL);
 	if (!client) {
-		DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
 		return -1;
 	}
 
-	DEBUG( 4, __FUNCTION__ "(), removing client!\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "(), removing client!\n");
 	client = hashbin_remove( irlmp->clients, handle, NULL);
 	if (client)
 		kfree(client);
@@ -1296,19 +1367,25 @@
  *
  *    Check if the given source LSAP selector is in use
  */
-int irlmp_slsap_inuse( __u8 slsap_sel)
+int irlmp_slsap_inuse(__u8 slsap_sel)
 {
 	struct lsap_cb *self;
 	struct lap_cb *lap;
 
-	ASSERT( irlmp != NULL, return TRUE;);
-	ASSERT( irlmp->magic == LMP_MAGIC, return TRUE;);
-	ASSERT( slsap_sel != LSAP_ANY, return TRUE;);
-
-	DEBUG( 4, __FUNCTION__ "()\n");
+	ASSERT(irlmp != NULL, return TRUE;);
+	ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
+	ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+#ifdef CONFIG_IRDA_ULTRA
+	/* Accept all bindings to the connectionless LSAP */
+	if (slsap_sel == LSAP_CONNLESS)
+		return FALSE;
+#endif /* CONFIG_IRDA_ULTRA */
 
 	/* Valid values are between 0 and 127 */
-	if (slsap_sel > 127)
+	if (slsap_sel > LSAP_MAX)
 		return TRUE;
 
 	/*
@@ -1324,16 +1401,14 @@
 		while (self != NULL) {
 			ASSERT(self->magic == LMP_LSAP_MAGIC, return TRUE;);
 
-			if ((self->slsap_sel == slsap_sel))/*  &&  */
-/* 			    ( self->dlsap_sel == LSAP_ANY)) */
-			{
-				DEBUG( 4, "Source LSAP selector=%02x in use\n",
-				       self->slsap_sel); 
+			if ((self->slsap_sel == slsap_sel)) {
+				IRDA_DEBUG(4, "Source LSAP selector=%02x in use\n",
+				      self->slsap_sel); 
 				return TRUE;
 			}
-			self = (struct lsap_cb*) hashbin_get_next( lap->lsaps);
+			self = (struct lsap_cb*) hashbin_get_next(lap->lsaps);
 		}
-		lap = (struct lap_cb *) hashbin_get_next( irlmp->links);
+		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
 	}     
 	return FALSE;
 }
@@ -1358,8 +1433,8 @@
 	while (irlmp_slsap_inuse(irlmp->free_lsap_sel)) {
 		irlmp->free_lsap_sel++;
 
-		/* Check if we need to wraparound */
-		if (irlmp->free_lsap_sel > 127) {
+		/* Check if we need to wraparound (0x70-0x7f are reserved) */
+		if (irlmp->free_lsap_sel > LSAP_MAX) {
 			irlmp->free_lsap_sel = 10;
 
 			/* Make sure we terminate the loop */
@@ -1367,7 +1442,7 @@
 				return 0;
 		}
 	}
-	DEBUG(4, __FUNCTION__ "(), next free lsap_sel=%02x\n", lsap_sel);
+	IRDA_DEBUG(4, __FUNCTION__ "(), next free lsap_sel=%02x\n", lsap_sel);
 	
 	return lsap_sel;
 }
@@ -1385,26 +1460,26 @@
 
 	switch (lap_reason) {		
 	case LAP_DISC_INDICATION: /* Received a disconnect request from peer */
-		DEBUG( 1, __FUNCTION__ "(), LAP_DISC_INDICATION\n");
+		IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_DISC_INDICATION\n");
 		reason = LM_USER_REQUEST;
 		break;
 	case LAP_NO_RESPONSE:    /* To many retransmits without response */
-		DEBUG( 1, __FUNCTION__ "(), LAP_NO_RESPONSE\n");
+		IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_NO_RESPONSE\n");
 		reason = LM_LAP_DISCONNECT;
 		break;
 	case LAP_RESET_INDICATION:
-		DEBUG( 1, __FUNCTION__ "(), LAP_RESET_INDICATION\n");
+		IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_RESET_INDICATION\n");
 		reason = LM_LAP_RESET;
 		break;
 	case LAP_FOUND_NONE:
 	case LAP_MEDIA_BUSY:
 	case LAP_PRIMARY_CONFLICT:
-		DEBUG( 1, __FUNCTION__ "(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n");
 		reason = LM_CONNECT_FAILURE;
 		break;
 	default:
-		DEBUG( 1, __FUNCTION__ 
-		       "(), Unknow IrLAP disconnect reason %d!\n", lap_reason);
+		IRDA_DEBUG(1, __FUNCTION__ 
+		      "(), Unknow IrLAP disconnect reason %d!\n", lap_reason);
 		reason = LM_LAP_DISCONNECT;
 		break;
 	}
@@ -1414,8 +1489,6 @@
 
 __u32 irlmp_get_saddr(struct lsap_cb *self)
 {
-	DEBUG(3, __FUNCTION__ "()\n");
-
 	ASSERT(self != NULL, return 0;);
 	ASSERT(self->lap != NULL, return 0;);
 
@@ -1424,8 +1497,6 @@
 
 __u32 irlmp_get_daddr(struct lsap_cb *self)
 {
-	DEBUG(3, __FUNCTION__ "()\n");
-
 	ASSERT(self != NULL, return 0;);
 	ASSERT(self->lap != NULL, return 0;);
 	
@@ -1455,21 +1526,21 @@
 	
 	len += sprintf( buf+len, "Unconnected LSAPs:\n");
 	self = (struct lsap_cb *) hashbin_get_first( irlmp->unconnected_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(
 			irlmp->unconnected_lsaps);
  	} 
 
-	len += sprintf( buf+len, "\nRegistred Link Layers:\n");
+	len += sprintf(buf+len, "\nRegistred Link Layers:\n");
 
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
@@ -1478,10 +1549,11 @@
 
 		len += sprintf(buf+len, "saddr: %#08x, daddr: %#08x, ",
 			       lap->saddr, lap->daddr); 
+		len += sprintf(buf+len, "refcount: %d", lap->refcount);
 		len += sprintf(buf+len, "\n");
 
-		len += sprintf( buf+len, "\nConnected LSAPs:\n");
-		self = (struct lsap_cb *) hashbin_get_first( lap->lsaps);
+		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, ", 
@@ -1499,9 +1571,8 @@
 
 		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
  	} 
-
-	restore_flags( flags);
-
+	restore_flags(flags);
+	
 	return len;
 }
 
diff -urN linux-2.2.15-pre2/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c
--- linux-2.2.15-pre2/net/irda/irlmp_event.c	Sat Apr 24 17:50:06 1999
+++ linux/net/irda/irlmp_event.c	Mon Dec  3 21:57:53 2001
@@ -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 08:57:23 1999
+ * Modified at:   Sun Jan  9 07:45:06 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -75,35 +75,35 @@
 };
 
 /* LAP Connection control proto declarations */
-static void irlmp_state_standby  ( struct lap_cb *, IRLMP_EVENT, 
-				   struct sk_buff *);
-static void irlmp_state_u_connect( struct lap_cb *, IRLMP_EVENT, 
-				   struct sk_buff *);
-static void irlmp_state_active   ( struct lap_cb *, IRLMP_EVENT, 
-				   struct sk_buff *);
+static void irlmp_state_standby  (struct lap_cb *, IRLMP_EVENT, 
+				  struct sk_buff *);
+static void irlmp_state_u_connect(struct lap_cb *, IRLMP_EVENT, 
+				  struct sk_buff *);
+static void irlmp_state_active   (struct lap_cb *, IRLMP_EVENT, 
+				  struct sk_buff *);
 
 /* LSAP Connection control proto declarations */
-static void irlmp_state_disconnected( struct lsap_cb *, IRLMP_EVENT, 
-				      struct sk_buff *);
-static void irlmp_state_connect     ( struct lsap_cb *, IRLMP_EVENT, 
-				      struct sk_buff *);
-static void irlmp_state_connect_pend( struct lsap_cb *, IRLMP_EVENT,
-				      struct sk_buff *);
-static void irlmp_state_dtr         ( struct lsap_cb *, IRLMP_EVENT, 
-				      struct sk_buff *);
-static void irlmp_state_setup       ( struct lsap_cb *, IRLMP_EVENT, 
-				      struct sk_buff *);
-static void irlmp_state_setup_pend  ( struct lsap_cb *, IRLMP_EVENT, 
-				      struct sk_buff *);
+static int irlmp_state_disconnected(struct lsap_cb *, IRLMP_EVENT, 
+				    struct sk_buff *);
+static int irlmp_state_connect     (struct lsap_cb *, IRLMP_EVENT, 
+				    struct sk_buff *);
+static int irlmp_state_connect_pend(struct lsap_cb *, IRLMP_EVENT,
+				    struct sk_buff *);
+static int irlmp_state_dtr         (struct lsap_cb *, IRLMP_EVENT, 
+				    struct sk_buff *);
+static int irlmp_state_setup       (struct lsap_cb *, IRLMP_EVENT, 
+				    struct sk_buff *);
+static int irlmp_state_setup_pend  (struct lsap_cb *, IRLMP_EVENT, 
+				    struct sk_buff *);
 
-static void (*lap_state[]) ( struct lap_cb *, IRLMP_EVENT, struct sk_buff *) =
+static void (*lap_state[]) (struct lap_cb *, IRLMP_EVENT, struct sk_buff *) =
 {
 	irlmp_state_standby,
 	irlmp_state_u_connect,
 	irlmp_state_active,
 };
 
-static void (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) =
+static int (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) =
 {
 	irlmp_state_disconnected,
 	irlmp_state_connect,
@@ -114,16 +114,16 @@
 };
 
 /* Do connection control events */
-void irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, 
-			 struct sk_buff *skb)
+int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, 
+			struct sk_buff *skb)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
-	DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
-	      irlmp_event[ event], irlmp_state[ self->lsap_state]);
+	IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
+		   irlmp_event[event], irlmp_state[ self->lsap_state]);
 
-	(*lsap_state[self->lsap_state]) (self, event, skb);
+	return (*lsap_state[self->lsap_state]) (self, event, skb);
 }
 
 /*
@@ -138,29 +138,29 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 	
-	DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
-	      irlmp_event[event], 
-	      irlmp_state[self->lap_state]);
+	IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
+		   irlmp_event[event], 
+		   irlmp_state[self->lap_state]);
 
 	(*lap_state[self->lap_state]) (self, event, skb);
 }
 
-void irlmp_discovery_timer_expired( unsigned long data)
+void irlmp_discovery_timer_expired(void *data)
 {
-	DEBUG(4, "IrLMP, discovery timer expired!\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	if (sysctl_discovery)
 		irlmp_do_discovery(sysctl_discovery_slots);
 
 	/* Restart timer */
-	irlmp_start_discovery_timer(irlmp, 300);
+	irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout * HZ);
 }
 
-void irlmp_watchdog_timer_expired( unsigned long data)
+void irlmp_watchdog_timer_expired(void *data)
 {
-	struct lsap_cb *self = ( struct lsap_cb *) data;
+	struct lsap_cb *self = (struct lsap_cb *) data;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -168,11 +168,11 @@
 	irlmp_do_lsap_event(self, LM_WATCHDOG_TIMEOUT, NULL);
 }
 
-void irlmp_idle_timer_expired(unsigned long data)
+void irlmp_idle_timer_expired(void *data)
 {
 	struct lap_cb *self = (struct lap_cb *) data;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
@@ -195,10 +195,10 @@
 static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, 
 				struct sk_buff *skb)
 {	
-	DEBUG( 4, __FUNCTION__ "()\n"); 
-	ASSERT( self->irlap != NULL, return;);
+	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+	ASSERT(self->irlap != NULL, return;);
 	
-	switch( event) {
+	switch (event) {
 	case LM_LAP_DISCOVERY_REQUEST:
 		/* irlmp_next_station_state( LMP_DISCOVER); */
 		
@@ -213,27 +213,31 @@
 		 *  think that the link is free since IrLMP may then start
 		 *  discovery before the connection is properly set up. DB.
 		 */
-		irlmp_next_lap_state( self, LAP_ACTIVE);
+		irlmp_next_lap_state(self, LAP_ACTIVE);
 
 		/* Just accept connection TODO, this should be fixed */
-		irlap_connect_response( self->irlap, skb);
+		irlap_connect_response(self->irlap, skb);
 		break;
 	case LM_LAP_CONNECT_REQUEST:
-		DEBUG(4, __FUNCTION__ "() LS_CONNECT_REQUEST\n");
+		IRDA_DEBUG(4, __FUNCTION__ "() LS_CONNECT_REQUEST\n");
+
+		irlmp_next_lap_state(self, LAP_U_CONNECT);
+		self->refcount++;
 
 		/* FIXME: need to set users requested QoS */
 		irlap_connect_request(self->irlap, self->daddr, NULL, 0);
-
-		irlmp_next_lap_state( self, LAP_U_CONNECT);
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
-		DEBUG( 4, __FUNCTION__ 
-		       "(), Error LM_LAP_DISCONNECT_INDICATION\n");
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), Error LM_LAP_DISCONNECT_INDICATION\n");
 		
-		irlmp_next_lap_state( self, LAP_STANDBY);
+		irlmp_next_lap_state(self, LAP_STANDBY);
 		break;
 	default:
-		DEBUG(4, __FUNCTION__ "(), Unknown event\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+			   irlmp_event[event]);
+		if (skb)
+ 			dev_kfree_skb(skb);
 		break;
 	}
 }
@@ -245,55 +249,75 @@
  *    since the IrLAP connection does not exist, we must first start an
  *    IrLAP connection. We are now waiting response from IrLAP.
  * */
-static void irlmp_state_u_connect( struct lap_cb *self, IRLMP_EVENT event, 
-				   struct sk_buff *skb)
+static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, 
+				  struct sk_buff *skb)
 {
 	struct lsap_cb *lsap;
 	struct lsap_cb *lsap_current;
 	
-	DEBUG(2, __FUNCTION__ "(), event=%s\n", irlmp_event[ event]);
+	IRDA_DEBUG(2, __FUNCTION__ "(), event=%s\n", irlmp_event[event]);
 
-	switch( event) {
+	switch (event) {
+	case LM_LAP_CONNECT_INDICATION:
+		/*  It's important to switch state first, to avoid IrLMP to 
+		 *  think that the link is free since IrLMP may then start
+		 *  discovery before the connection is properly set up. DB.
+		 */
+		irlmp_next_lap_state(self, LAP_ACTIVE);
+
+		/* Just accept connection TODO, this should be fixed */
+		irlap_connect_response(self->irlap, skb);
+
+		lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+		while (lsap != NULL) {
+			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
+			lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
+		}
+		break;
+	case LM_LAP_CONNECT_REQUEST:
+		/* Already trying to connect */
+		self->refcount++;
+		break;
 	case LM_LAP_CONNECT_CONFIRM:
 		/* For all lsap_ce E Associated do LS_Connect_confirm */
-		irlmp_next_lap_state( self, LAP_ACTIVE);
+		irlmp_next_lap_state(self, LAP_ACTIVE);
 
-		lsap = ( struct lsap_cb *) hashbin_get_first( self->lsaps);
-		while ( lsap != NULL) {
-			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, skb);
+		lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+		while (lsap != NULL) {
+			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
 			lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
-		}		
+		}
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
-		DEBUG(2, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n");
-	
-		irlmp_next_lap_state( self, LAP_STANDBY);
+		irlmp_next_lap_state(self, LAP_STANDBY);
+		self->refcount = 0;
 
 		/* Send disconnect event to all LSAPs using this link */
-		
-		lsap = ( struct lsap_cb *) hashbin_get_first( self->lsaps);
-		while ( lsap != NULL ) {
-			ASSERT( lsap->magic == LMP_LSAP_MAGIC, return;);
+		lsap = (struct lsap_cb *) hashbin_get_first( self->lsaps);
+		while (lsap != NULL ) {
+			ASSERT(lsap->magic == LMP_LSAP_MAGIC, return;);
 			
 			lsap_current = lsap;
 
 			/* Be sure to stay one item ahead */
-			lsap = ( struct lsap_cb *) hashbin_get_next( self->lsaps);
-			irlmp_do_lsap_event( lsap_current, 
-					     LM_LAP_DISCONNECT_INDICATION,
-					     NULL);
+			lsap = (struct lsap_cb *) hashbin_get_next(self->lsaps);
+			irlmp_do_lsap_event(lsap_current, 
+					    LM_LAP_DISCONNECT_INDICATION,
+					    NULL);
 		}
 		break;
 	case LM_LAP_DISCONNECT_REQUEST:
-		DEBUG( 4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
 
-		irlmp_next_lap_state( self, LAP_STANDBY);
-
-		/* FIXME */
-/* 		irlap_disconnect_request( self->irlap); */
+		self->refcount--;
+		if (self->refcount == 0)
+			irlmp_next_lap_state(self, LAP_STANDBY);
 		break;
 	default:
-		DEBUG( 4, __FUNCTION__ "(), Unknown event\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+			   irlmp_event[event]);
+		if (skb)
+ 			dev_kfree_skb(skb);
 		break;
 	}	
 }
@@ -310,11 +334,12 @@
 	struct lsap_cb *lsap;
 	struct lsap_cb *lsap_current;
 
-	DEBUG( 4, __FUNCTION__ "()\n"); 
+	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
 
- 	switch( event) {
+ 	switch (event) {
 	case LM_LAP_CONNECT_REQUEST:
-		DEBUG( 4, __FUNCTION__ "(), LS_CONNECT_REQUEST\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_REQUEST\n");
+		self->refcount++;
 
 		/*
 		 *  LAP connection allready active, just bounce back! Since we 
@@ -324,7 +349,7 @@
 		 */
 		lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
 		while (lsap != NULL) {
-			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, skb);
+			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
  			lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
 		}
 		
@@ -336,12 +361,12 @@
 			/* Be sure to stay one item ahead */
  			lsap = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps);
 			irlmp_do_lsap_event(lsap_current, 
-					    LM_LAP_CONNECT_CONFIRM, skb);
+					    LM_LAP_CONNECT_CONFIRM, NULL);
 		}
 		/* Keep state */
 		break;
 	case LM_LAP_DISCONNECT_REQUEST:
-		DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
+		self->refcount--;
 
 		/*
 		 *  Need to find out if we should close IrLAP or not. If there
@@ -349,42 +374,44 @@
 		 *  must be the one that tries to close IrLAP. It will be 
 		 *  removed later and moved to the list of unconnected LSAPs
 		 */
-		if (hashbin_get_size(self->lsaps) == 1)
+		if (HASHBIN_GET_SIZE(self->lsaps) > 0)
 			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
-
+		else {
+			/* No more connections, so close IrLAP */
+			irlmp_next_lap_state(self, LAP_STANDBY);
+			irlap_disconnect_request(self->irlap);
+		}
 		break;
 	case LM_LAP_IDLE_TIMEOUT:
-		if (hashbin_get_size(self->lsaps) == 0) {
-			DEBUG(2, __FUNCTION__ 
-			      "(), no more LSAPs so time to close IrLAP\n");
+		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
 			irlmp_next_lap_state(self, LAP_STANDBY);
-			
 			irlap_disconnect_request(self->irlap);
 		}
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
-		DEBUG(4, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n");
-	
-		irlmp_next_lap_state( self, LAP_STANDBY);		
+		irlmp_next_lap_state(self, LAP_STANDBY);		
+		self->refcount = 0;
 		
 		/* 
 		 *  Inform all connected LSAP's using this link
 		 */
-		lsap = ( struct lsap_cb *) hashbin_get_first( self->lsaps);
-		while ( lsap != NULL ) {
-			ASSERT( lsap->magic == LMP_LSAP_MAGIC, return;);
+		lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+		while (lsap != NULL ) {
+			ASSERT(lsap->magic == LMP_LSAP_MAGIC, return;);
 			
 			lsap_current = lsap;
 
 			/* Be sure to stay one item ahead */
-			lsap = ( struct lsap_cb *) hashbin_get_next( self->lsaps);
-			irlmp_do_lsap_event( lsap_current, 
-					     LM_LAP_DISCONNECT_INDICATION,
-					     NULL);
+			lsap = (struct lsap_cb *) hashbin_get_next(self->lsaps);
+			irlmp_do_lsap_event(lsap_current, 
+					    LM_LAP_DISCONNECT_INDICATION,
+					    NULL);
 		}
 		break;
 	default:
-		DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
+		if (skb)
+ 			dev_kfree_skb(skb);
 		break;
 	}	
 }
@@ -401,33 +428,59 @@
  *    DISCONNECTED
  *
  */
-static void irlmp_state_disconnected( struct lsap_cb *self, IRLMP_EVENT event,
-				      struct sk_buff *skb) 
+static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
+				    struct sk_buff *skb) 
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	int ret = 0;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	switch( event) {
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+
+	switch (event) {
+#ifdef CONFIG_IRDA_ULTRA
+	case LM_UDATA_INDICATION:
+		irlmp_connless_data_indication(self, skb); 
+		break;
+#endif /* CONFIG_IRDA_ULTRA */
 	case LM_CONNECT_REQUEST:
-		DEBUG( 4, __FUNCTION__ "(), LM_CONNECT_REQUEST\n");
-		irlmp_next_lsap_state( self, LSAP_SETUP_PEND);
+		IRDA_DEBUG(4, __FUNCTION__ "(), LM_CONNECT_REQUEST\n");
+
+		if (self->conn_skb) {
+			WARNING(__FUNCTION__ 
+				"(), busy with another request!\n");
+			return -EBUSY;
+		}
+		self->conn_skb = skb;
+
+		irlmp_next_lsap_state(self, LSAP_SETUP_PEND);
 
 		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 
-		/* Start watchdog timer ( 5 secs for now) */
-		irlmp_start_watchdog_timer(self, 500);
+		/* Start watchdog timer (5 secs for now) */
+		irlmp_start_watchdog_timer(self, 5*HZ);
 		break;
 	case LM_CONNECT_INDICATION:
 		irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
 
-		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, skb);
+		if (self->conn_skb) {
+			WARNING(__FUNCTION__ 
+				"(), busy with another request!\n");
+			return -EBUSY;
+		}
+		self->conn_skb = skb;
+
+		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 		break;
 	default:
-		DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlmp_event[event]);
+		if (skb)
+  			dev_kfree_skb(skb);
 		break;
 	}
+	return ret;
 }
 
 /*
@@ -436,19 +489,20 @@
  *    CONNECT
  *
  */
-static void irlmp_state_connect( struct lsap_cb *self, IRLMP_EVENT event, 
-				 struct sk_buff *skb) 
+static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, 
+				struct sk_buff *skb) 
 {
 	struct lsap_cb *lsap;
+	int ret = 0;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
-	switch( event) {
+	switch (event) {
 	case LM_CONNECT_RESPONSE:
-		ASSERT( skb != NULL, return;);
+		del_timer(&self->watchdog_timer);
 
 		/* 
 		 *  Bind this LSAP to the IrLAP link where the connect was
@@ -457,25 +511,27 @@
 		lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, 
 				      NULL);
 
-		ASSERT(lsap == self, return;);
+		ASSERT(lsap == self, return -1;);		
+		ASSERT(self->lap != NULL, return -1;);
+		ASSERT(self->lap->lsaps != NULL, return -1;);
 		
-		ASSERT(self->lap != NULL, return;);
-		ASSERT(self->lap->lsaps != NULL, return;);
-		
-		hashbin_insert(self->lap->lsaps, (QUEUE *) self, (int) self, 
+		hashbin_insert(self->lap->lsaps, (queue_t *) self, (int) self, 
 			       NULL);
 
+		self->connected = TRUE;	
+		irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
+
 		irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, 
 				   self->slsap_sel, CONNECT_CNF, skb);
-
-		del_timer(&self->watchdog_timer);
-
-		irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
 		break;
 	default:
-		DEBUG( 4, __FUNCTION__ "(), Unknown event\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+			   irlmp_event[event]);
+		if (skb)
+ 			dev_kfree_skb(skb);
 		break;
 	}
+	return ret;
 }
 
 /*
@@ -484,37 +540,47 @@
  *    CONNECT_PEND
  *
  */
-static void irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
-				     struct sk_buff *skb) 
+static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
+				    struct sk_buff *skb) 
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	int ret = 0;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
-	switch( event) {
+	switch (event) {
 	case LM_CONNECT_REQUEST:
 		/* Keep state */
 		break;
 	case LM_CONNECT_RESPONSE:
-		DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, "
-		      "no indication issued yet\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, "
+			   "no indication issued yet\n");
 		/* Keep state */
 		break;
 	case LM_DISCONNECT_REQUEST:
-		DEBUG(0, __FUNCTION__ "(), LM_DISCONNECT_REQUEST, "
-		      "not yet bound to IrLAP connection\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), LM_DISCONNECT_REQUEST, "
+			   "not yet bound to IrLAP connection\n");
 		/* Keep state */
 		break;
 	case LM_LAP_CONNECT_CONFIRM:
-		DEBUG(4, __FUNCTION__ "(), LS_CONNECT_CONFIRM\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_CONFIRM\n");
 		irlmp_next_lsap_state(self, LSAP_CONNECT);
+
+		skb = self->conn_skb;
+		self->conn_skb = NULL;
+
 		irlmp_connect_indication(self, skb);
 		break;
 	default:
-		DEBUG( 4, __FUNCTION__ "Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "Unknown event %s\n", 
+			   irlmp_event[event]);
+		if (skb)
+ 			dev_kfree_skb(skb);
 		break;	
-	}	
+	}
+	return ret;
 }
 
 /*
@@ -523,56 +589,52 @@
  *    DATA_TRANSFER_READY
  *
  */
-static void irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, 
-			    struct sk_buff *skb) 
+static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, 
+			   struct sk_buff *skb) 
 {
 	LM_REASON reason;
+	int ret = 0;
 
- 	DEBUG(4, __FUNCTION__ "()\n");
+ 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT(self->lap != NULL, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	ASSERT(self->lap != NULL, return -1;);
 
 	switch (event) {
 	case LM_DATA_REQUEST: /* Optimize for the common case */
 		irlmp_send_data_pdu(self->lap, self->dlsap_sel, 
 				    self->slsap_sel, FALSE, skb);
-		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
 		break;
 	case LM_DATA_INDICATION: /* Optimize for the common case */
 		irlmp_data_indication(self, skb); 
-		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
 		break;
 	case LM_UDATA_REQUEST:
-		ASSERT(skb != NULL, return;);
+		ASSERT(skb != NULL, return -1;);
 		irlmp_send_data_pdu(self->lap, self->dlsap_sel, 
 				    self->slsap_sel, TRUE, skb);
 		break;
 	case LM_UDATA_INDICATION:
 		irlmp_udata_indication(self, skb); 
-		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
 		break;
 	case LM_CONNECT_REQUEST:
-		DEBUG(0, __FUNCTION__ "(), LM_CONNECT_REQUEST, "
-		      "error, LSAP already connected\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_REQUEST, "
+			   "error, LSAP already connected\n");
 		/* Keep state */
 		break;
 	case LM_CONNECT_RESPONSE:
-		DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " 
-		      "error, LSAP allready connected\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " 
+			   "error, LSAP allready connected\n");
 		/* Keep state */
 		break;
 	case LM_DISCONNECT_REQUEST:
-		ASSERT(skb != NULL, return;);
-
-		irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, 
-				   self->slsap_sel, DISCONNECT, skb);
+		irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, self->slsap_sel,
+				   DISCONNECT, skb);
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		
 		/* Try to close the LAP connection if its still there */
 		if (self->lap) {
-			DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
+			IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
 			irlmp_do_lap_event(self->lap, 
 					   LM_LAP_DISCONNECT_REQUEST, 
 					   NULL);
@@ -588,23 +650,27 @@
 	case LM_DISCONNECT_INDICATION:
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 			
-		ASSERT(self->lap != NULL, return;);
-		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return;);
+		ASSERT(self->lap != NULL, return -1;);
+		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 	
-		ASSERT(skb != NULL, return;);
-		ASSERT(skb->len > 3, return;);
+		ASSERT(skb != NULL, return -1;);
+		ASSERT(skb->len > 3, return -1;);
 		reason = skb->data[3];
 
 		 /* Try to close the LAP connection */
-		DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
+		IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 
 		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	default:
-		DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlmp_event[event]);
+		if (skb)
+ 			dev_kfree_skb(skb);
 		break;	
-	}	
+	}
+	return ret;
 }
 
 /*
@@ -614,54 +680,70 @@
  *    An LSAP connection request has been transmitted to the peer
  *    LSAP-Connection Control FSM and we are awaiting reply.
  */
-static void irlmp_state_setup( struct lsap_cb *self, IRLMP_EVENT event, 
-			       struct sk_buff *skb) 
+static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, 
+			     struct sk_buff *skb) 
 {
 	LM_REASON reason;
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+	int ret = 0;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
-	switch( event) {
-	case LM_CONNECT_CONFIRM:
-		ASSERT( skb != NULL, return;);
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-		irlmp_next_lsap_state( self, LSAP_DATA_TRANSFER_READY);
+	switch (event) {
+	case LM_CONNECT_CONFIRM:
+		irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
 
-		del_timer( &self->watchdog_timer);
+		del_timer(&self->watchdog_timer);
 		
-		irlmp_connect_confirm( self, skb);
+		irlmp_connect_confirm(self, skb);
 		break;
 	case LM_DISCONNECT_INDICATION:
-		DEBUG(0, __FUNCTION__ "(), this should never happen!!\n");
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
+			
+		ASSERT(self->lap != NULL, return -1;);
+		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
+	
+		ASSERT(skb != NULL, return -1;);
+		ASSERT(skb->len > 3, return -1;);
+		reason = skb->data[3];
+
+		 /* Try to close the LAP connection */
+		IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
+		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
+
+		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 
 		del_timer(&self->watchdog_timer);
 
-		ASSERT(self->lap != NULL, return;);
-		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return;);
+		ASSERT(self->lap != NULL, return -1;);
+		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 		
 		reason = irlmp_convert_lap_reason(self->lap->reason);
 
 		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	case LM_WATCHDOG_TIMEOUT:
-		DEBUG( 0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
 		
-		ASSERT( self->lap != NULL, return;);
-		irlmp_do_lap_event( self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
-		irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+		ASSERT(self->lap != NULL, return -1;);
+		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		
-		irlmp_disconnect_indication( self, LM_CONNECT_FAILURE, NULL);
+		irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
 		break;
 	default:
-		DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlmp_event[event]);
+		if (skb)
+ 			dev_kfree_skb(skb);
 		break;	
 	}
+	return ret;
 }
 
 /*
@@ -672,57 +754,67 @@
  *    LAP FSM to set up the underlying IrLAP connection, and we
  *    are awaiting confirm.
  */
-static void irlmp_state_setup_pend( struct lsap_cb *self, IRLMP_EVENT event, 
-				    struct sk_buff *skb) 
+static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, 
+				  struct sk_buff *skb) 
 {
 	LM_REASON reason;
+	int ret = 0;
 
-	DEBUG( 4, __FUNCTION__ "()\n"); 
+	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
 
-	ASSERT( self != NULL, return;);
-	ASSERT( irlmp != NULL, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(irlmp != NULL, return -1;);
 
-	switch( event) {
+	switch (event) {
 	case LM_LAP_CONNECT_CONFIRM:
-		irlmp_send_lcf_pdu( self->lap, self->dlsap_sel, 
-				    self->slsap_sel, CONNECT_CMD, 
-				    self->tmp_skb);
-		irlmp_next_lsap_state( self, LSAP_SETUP);
+		ASSERT(self->conn_skb != NULL, return -1;);
+
+		skb = self->conn_skb;
+		self->conn_skb = NULL;
+
+		irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, 
+				   self->slsap_sel, CONNECT_CMD, skb);
+
+		irlmp_next_lsap_state(self, LSAP_SETUP);
 		break;
 	case LM_WATCHDOG_TIMEOUT:
-		DEBUG( 0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
 
-		ASSERT( self->lap != NULL, return;);
+		ASSERT(self->lap != NULL, return -1;);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
-		irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 
-		irlmp_disconnect_indication( self, LM_CONNECT_FAILURE, NULL);
+		irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
 		break;
 	case LM_LAP_DISCONNECT_INDICATION: /* LS_Disconnect.indication */
 		del_timer( &self->watchdog_timer);
 
-		irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		
-		reason = irlmp_convert_lap_reason( self->lap->reason);
+		reason = irlmp_convert_lap_reason(self->lap->reason);
 		
-		irlmp_disconnect_indication( self, reason, NULL);
+		irlmp_disconnect_indication(self, reason, NULL);
 		break;
 	default:
-		DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
+			   irlmp_event[event]);
+		if (skb)
+ 			dev_kfree_skb(skb);
 		break;	
 	}
+	return ret;
 }
 
-void irlmp_next_lap_state( struct lap_cb *self, IRLMP_STATE state) 
+void irlmp_next_lap_state(struct lap_cb *self, IRLMP_STATE state) 
 {
-	DEBUG( 4, __FUNCTION__ "(), LMP LAP = %s\n", irlmp_state[state]);
+	IRDA_DEBUG(4, __FUNCTION__ "(), LMP LAP = %s\n", irlmp_state[state]);
 	self->lap_state = state;
 }
 
-void irlmp_next_lsap_state( struct lsap_cb *self, LSAP_STATE state) 
+void irlmp_next_lsap_state(struct lsap_cb *self, LSAP_STATE state) 
 {
-	ASSERT( self != NULL, return;);
+	ASSERT(self != NULL, return;);
 
-	DEBUG( 4, __FUNCTION__ "(), LMP LSAP = %s\n", irlsap_state[state]);
+	IRDA_DEBUG(4, __FUNCTION__ "(), LMP LSAP = %s\n", irlsap_state[state]);
 	self->lsap_state = state;
 }
diff -urN linux-2.2.15-pre2/net/irda/irlmp_frame.c linux/net/irda/irlmp_frame.c
--- linux-2.2.15-pre2/net/irda/irlmp_frame.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irlmp_frame.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 02:09:59 1997
- * Modified at:   Mon May 31 09:53:16 1999
+ * Modified at:   Mon Dec 13 13:41:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
@@ -40,18 +40,14 @@
 inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
 				int expedited, struct sk_buff *skb)
 {
-	__u8 *frame;
-
-	frame = skb->data;
-
-	frame[0] = dlsap;
-	frame[1] = slsap;
+	skb->data[0] = dlsap;
+	skb->data[1] = slsap;
 
 	if (expedited) {
-		DEBUG( 4, __FUNCTION__ "(), sending expedited data\n");
-		irlap_data_request( self->irlap, skb, FALSE);
+		IRDA_DEBUG(4, __FUNCTION__ "(), sending expedited data\n");
+		irlap_data_request(self->irlap, skb, TRUE);
 	} else
-		irlap_data_request( self->irlap, skb, TRUE);
+		irlap_data_request(self->irlap, skb, FALSE);
 }
 
 /*
@@ -64,8 +60,8 @@
 {
 	__u8 *frame;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
-	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 	ASSERT(skb != NULL, return;);
@@ -82,8 +78,7 @@
 	else
 		frame[3] = 0x00; /* rsvd */
 
-	ASSERT(self->irlap != NULL, return;);
-	irlap_data_request(self->irlap, skb, TRUE);
+	irlap_data_request(self->irlap, skb, FALSE);
 }
 
 /*
@@ -92,14 +87,16 @@
  *    Used by IrLAP to pass received data frames to IrLMP layer
  *
  */
-void irlmp_link_data_indication(struct lap_cb *self, int reliable, 
-			        struct sk_buff *skb)
+void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, 
+				int unreliable)
 {
 	struct lsap_cb *lsap;
 	__u8   slsap_sel;   /* Source (this) LSAP address */
 	__u8   dlsap_sel;   /* Destination LSAP address */
 	__u8   *fp;
 	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 	ASSERT(skb->len > 2, return;);
@@ -111,15 +108,16 @@
 	 *  destination LSAP of received frame is source LSAP in our view
 	 */
 	slsap_sel = fp[0] & LSAP_MASK; 
-	dlsap_sel = fp[1];
+	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.
 	 */
 	if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
-		DEBUG(3,"Incoming connection, source LSAP=%d, dest LSAP=%d\n",
-		      slsap_sel, dlsap_sel);
+		IRDA_DEBUG(3, __FUNCTION__ "(), incoming connection, "
+			   "source LSAP=%d, dest LSAP=%d\n",
+			   slsap_sel, dlsap_sel);
 		
 		/* Try to find LSAP among the unconnected LSAPs */
 		lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD,
@@ -134,15 +132,15 @@
 				       self->lsaps);
 	
 	if (lsap == NULL) {
-		DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
-		DEBUG(2, __FUNCTION__ 
+		IRDA_DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
+		IRDA_DEBUG(2, __FUNCTION__ 
 		      "(), slsap_sel = %02x, dlsap_sel = %02x\n", slsap_sel, 
 		      dlsap_sel);
 		if (fp[0] & CONTROL_BIT) {
-			DEBUG(2, __FUNCTION__ 
+			IRDA_DEBUG(2, __FUNCTION__ 
 			      "(), received control frame %02x\n", fp[2]);
 		} else {
-			DEBUG(2, __FUNCTION__ "(), received data frame\n");
+			IRDA_DEBUG(2, __FUNCTION__ "(), received data frame\n");
 		}
 		dev_kfree_skb(skb);
 		return;
@@ -152,7 +150,7 @@
 	 *  Check if we received a control frame? 
 	 */
 	if (fp[0] & CONTROL_BIT) {
-		switch(fp[2]) {
+		switch (fp[2]) {
 		case CONNECT_CMD:
 			lsap->lap = self;
 			irlmp_do_lsap_event(lsap, LM_CONNECT_INDICATION, skb);
@@ -161,37 +159,109 @@
 			irlmp_do_lsap_event(lsap, LM_CONNECT_CONFIRM, skb);
 			break;
 		case DISCONNECT:
-			DEBUG( 4, __FUNCTION__ "(), Disconnect indication!\n");
+			IRDA_DEBUG(4, __FUNCTION__ 
+				   "(), Disconnect indication!\n");
 			irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION, 
 					    skb);
 			break;
 		case ACCESSMODE_CMD:
-			DEBUG( 0, "Access mode cmd not implemented!\n");
+			IRDA_DEBUG(0, "Access mode cmd not implemented!\n");
+			dev_kfree_skb(skb);
 			break;
 		case ACCESSMODE_CNF:
-			DEBUG( 0, "Access mode cnf not implemented!\n");
+			IRDA_DEBUG(0, "Access mode cnf not implemented!\n");
+			dev_kfree_skb(skb);
 			break;
 		default:
-			DEBUG( 0, __FUNCTION__ 
-			       "(), Unknown control frame %02x\n", fp[2]);
+			IRDA_DEBUG(0, __FUNCTION__ 
+				   "(), Unknown control frame %02x\n", fp[2]);
+			dev_kfree_skb(skb);
 			break;
 		}
-	} else if (reliable == LAP_RELIABLE) {
+	} else if (unreliable) {
 		/* Optimize and bypass the state machine if possible */
 		if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
-			irlmp_data_indication(lsap, skb);
+			irlmp_udata_indication(lsap, skb);
 		else
-			irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
-	} else if (reliable == LAP_UNRELIABLE) {
+			irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
+	} else {	
 		/* Optimize and bypass the state machine if possible */
 		if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
 			irlmp_data_indication(lsap, skb);
 		else
-			irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
+			irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
 	}
 }
 
 /*
+ * Function irlmp_link_unitdata_indication (self, skb)
+ *
+ *    
+ *
+ */
+#ifdef CONFIG_IRDA_ULTRA
+void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
+{
+	struct lsap_cb *lsap;
+	__u8   slsap_sel;   /* Source (this) LSAP address */
+	__u8   dlsap_sel;   /* Destination LSAP address */
+	__u8   pid;         /* Protocol identifier */
+	__u8   *fp;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT(skb->len > 2, return;);
+
+	fp = skb->data;
+
+	/*
+	 *  The next statements may be confusing, but we do this so that 
+	 *  destination LSAP of received frame is source LSAP in our view
+	 */
+	slsap_sel = fp[0] & LSAP_MASK; 
+	dlsap_sel = fp[1];
+	pid       = fp[2];
+	
+	if (pid & 0x80) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), extension in PID not supp!\n");
+		dev_kfree_skb(skb);
+
+		return;
+	}
+
+	/* Check if frame is addressed to the connectionless LSAP */
+	if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), dropping frame!\n");
+		dev_kfree_skb(skb);
+		
+		return;
+	}
+	
+	lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
+	while (lsap != NULL) {
+		/*
+		 *  Check if source LSAP and dest LSAP selectors and PID match.
+		 */
+		if ((lsap->slsap_sel == slsap_sel) && 
+		    (lsap->dlsap_sel == dlsap_sel) && 
+		    (lsap->pid == pid)) 
+		{			
+			break;
+		}
+		lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps);
+	}
+	if (lsap)
+		irlmp_connless_data_indication(lsap, skb);
+	else {
+		IRDA_DEBUG(0, __FUNCTION__ "(), found no matching LSAP!\n");
+		dev_kfree_skb(skb);
+	}
+}
+#endif /* CONFIG_IRDA_ULTRA */
+
+/*
  * Function irlmp_link_disconnect_indication (reason, userdata)
  *
  *    IrLAP has disconnected 
@@ -202,7 +272,7 @@
 				      LAP_REASON reason, 
 				      struct sk_buff *userdata)
 {
-	DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(lap != NULL, return;);
 	ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
@@ -211,7 +281,9 @@
 	lap->daddr = DEV_ADDR_ANY;
 
         /* FIXME: must do something with the userdata if any */
-
+	if (userdata)
+		dev_kfree_skb(userdata);
+	
 	/*
 	 *  Inform station state machine
 	 */
@@ -228,7 +300,7 @@
 				   __u32 daddr, struct qos_info *qos,
 				   struct sk_buff *skb) 
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	/* Copy QoS settings for this session */
 	self->qos = qos;
@@ -249,12 +321,16 @@
 void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, 
 				struct sk_buff *userdata)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 	ASSERT(qos != NULL, return;);
 
+	/* Don't need use the userdata for now */
+	if (userdata)
+		dev_kfree_skb(userdata);
+
 	/* Copy QoS settings for this session */
 	self->qos = qos;
 
@@ -274,9 +350,10 @@
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 
 	irlmp_add_discovery(irlmp->cachelog, discovery);
+	
+#if 0   /* This will just cause a lot of connection collisions */
 
 	/* Just handle it the same way as a discovery confirm */
-#if 0
 	irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
 #endif
 }
@@ -291,7 +368,7 @@
  */
 void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
@@ -373,5 +450,3 @@
 	/* Sorry not found! */
 	return NULL;
 }
-
-
diff -urN linux-2.2.15-pre2/net/irda/irlpt/Config.in linux/net/irda/irlpt/Config.in
--- linux-2.2.15-pre2/net/irda/irlpt/Config.in	Wed Jan 20 11:05:33 1999
+++ linux/net/irda/irlpt/Config.in	Wed Dec 31 16:00:00 1969
@@ -1,7 +0,0 @@
-
-dep_tristate 'IrLPT protocol' CONFIG_IRLPT $CONFIG_IRDA
-
-if [ "$CONFIG_IRLPT" != "n" ]; then
-  dep_tristate '   IrLPT client support' CONFIG_IRLPT_CLIENT $CONFIG_IRLPT
-  dep_tristate '   IrLPT server support' CONFIG_IRLPT_SERVER $CONFIG_IRLPT
-fi
diff -urN linux-2.2.15-pre2/net/irda/irlpt/Makefile linux/net/irda/irlpt/Makefile
--- linux-2.2.15-pre2/net/irda/irlpt/Makefile	Wed Jan 20 11:05:33 1999
+++ linux/net/irda/irlpt/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-#
-# Makefile for the Linux IrDA IrLPT protocol layer.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
-
-MOD_LIST_NAME := IRDA_MODULES
-O_TARGET := irlpt.o
-O_OBJS	 := irlpt_common.o
-M_OBJS   := $(O_TARGET)
-MI_OBJS  :=
-
-OX_OBJS  += 
-
-ifeq ($(CONFIG_IRLPT_CLIENT),y)
-O_OBJS += irlpt_cli.o irlpt_cli_fsm.o
-else
-  ifeq ($(CONFIG_IRLPT_CLIENT),m)
-  M_OBJS += irlpt_client.o
-  endif
-endif
-
-ifeq ($(CONFIG_IRLPT_SERVER),y)
-O_OBJS += irlpt_srvr.o irlpt_srvr_fsm.o
-else
-  ifeq ($(CONFIG_IRLPT_SERVER),m)
-  M_OBJS += irlpt_server.o
-  endif
-endif
-
-# Special rule to build the composite modules
-ifeq ($(CONFIG_IRLPT_CLIENT),m)
-irlpt_client.o: irlpt_cli.o irlpt_cli_fsm.o
-	$(LD) $(LD_RFLAG) -r -o $@ irlpt_cli.o irlpt_cli_fsm.o
-endif
-ifeq ($(CONFIG_IRLPT_SERVER),m)
-irlpt_server.o: irlpt_srvr.o irlpt_srvr_fsm.o
-	$(LD) $(LD_RFLAG) -r -o $@ irlpt_srvr.o irlpt_srvr_fsm.o
-endif
-
-include $(TOPDIR)/Rules.make
-
-tar:
-	tar -cvf /dev/f1 .
-
diff -urN linux-2.2.15-pre2/net/irda/irlpt/irlpt_cli.c linux/net/irda/irlpt/irlpt_cli.c
--- linux-2.2.15-pre2/net/irda/irlpt/irlpt_cli.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irlpt/irlpt_cli.c	Wed Dec 31 16:00:00 1969
@@ -1,660 +0,0 @@
-/*********************************************************************
- *
- * Filename:      irlpt_cli.c
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Thomas Davis, <ratbert@radiks.net>
- * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Sun Mar  8 23:44:19 1998
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * Sources:	  irlan.c
- *
- *     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
- *     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, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <net/irda/irlap.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irias_object.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irlpt_common.h>
-#include <net/irda/irlpt_cli.h>
-#include <net/irda/irlpt_cli_fsm.h>
-#include <net/irda/timer.h>
-#include <net/irda/irda.h>
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/proc_fs.h>
-
-int irlpt_client_init(void);
-static void irlpt_client_close(struct irlpt_cb *self);
-
-static void irlpt_client_discovery_indication(discovery_t *);
-
-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_expired(unsigned long data);
-
-#if 0
-static char *rcsid = "$Id: irlpt_client.c,v 1.10 1998/11/10 22:50:57 dagb Exp $";
-#endif
-static char *version = "IrLPT client, v2 (Thomas Davis)";
-
-static __u32 ckey; /* IrLMP client handle */
-
-struct file_operations client_fops = {
-	irlpt_seek,    /* seek */
-	NULL,          /* read_irlpt (server) */
-	irlpt_write,   /* write */
-	NULL,	       /* readdir */
-	NULL,          /* poll */
-	NULL,	       /* ioctl */
-	NULL,	       /* mmap */
-	irlpt_open,    /* open */
-	NULL,          /* flush */
-	irlpt_close,   /* release */
-	NULL,          /* fsync */
-	NULL,          /* fasync */
-	NULL,          /* check_media_change */
-	NULL,          /* revalidate */
-	NULL,          /* lock */
-};
-
-int irlpt_client_debug = 4;
-
-extern char *irlptstate[];
-
-#ifdef CONFIG_PROC_FS
-
-/*
- * Function client_proc_read (buf, start, offset, len, unused)
- *
- */
-static int irlpt_client_proc_read( char *buf, char **start, off_t offset, 
-				   int len, int unused)
-{
-	struct irlpt_cb *self;
-	int index;
-
-	len = sprintf(buf, "%s\n\n", version);
-
-	self = (struct irlpt_cb *) hashbin_get_first( irlpt_clients);
-	while( self) {
-	        ASSERT( self != NULL, return len;);
-          	ASSERT( self->magic == IRLPT_MAGIC, return len;);
-		if (self->in_use == FALSE) {
-		        break;
-		}
-
-		len += sprintf(buf+len, "ifname: %s\n", self->ifname);
-		len += sprintf(buf+len, "minor: %d\n", self->ir_dev.minor);
-
-		switch ( self->servicetype) {
-		case IRLPT_UNKNOWN:
-			index = 0;
-			break;
-		case IRLPT_THREE_WIRE_RAW:
-			index = 1;
-			break;
-		case IRLPT_THREE_WIRE:
-			index = 2;
-			break;
-		case IRLPT_NINE_WIRE:
-			index = 3;
-			break;
-		case IRLPT_CENTRONICS:
-			index = 4;
-			break;
-		case IRLPT_SERVER_MODE:
-			index = 5;
-			break;
-		default:
-			index = 0;
-			break;
-		}
-		
-		len += sprintf(buf+len, "service_type: %s, port type: %s\n", 
-			       irlpt_service_type[index],
-			       irlpt_port_type[ self->porttype]);
-
-		len += sprintf(buf+len, "saddr: 0x%08x, daddr: 0x%08x\n", 
-			       self->saddr, self->daddr);
-		len += sprintf(buf+len, 
-			       "retries: %d, count: %d, queued packets: %d\n", 
-			       self->open_retries,
-			       self->count, self->pkt_count);
-		len += sprintf(buf+len, "slsap: %d, dlsap: %d\n", 
-			       self->slsap_sel, self->dlsap_sel);
-		len += sprintf(buf+len, "fsm state: %s\n", 
-			       irlpt_client_fsm_state[self->state]);
-		len += sprintf(buf+len, "\n\n");
-		
-		self = (struct irlpt_cb *) hashbin_get_next( irlpt_clients);
-	}
-	
-	return len;
-}
-
-extern struct proc_dir_entry *proc_irda;
-
-#endif /* CONFIG_PROC_FS */
-
-/*
- * Function irlpt_client_init (dev)
- *
- *   Initializes the irlpt control structure
- *
- */
-__initfunc(int irlpt_client_init(void))
-{
-	__u16 hints;
-	
-	DEBUG( irlpt_client_debug, "--> "__FUNCTION__ "\n");
-
-	printk( KERN_INFO "%s\n", version);
-
-	irlpt_clients = hashbin_new( HB_LOCAL); 
-	if ( irlpt_clients == NULL) {
-		printk( KERN_WARNING 
-			"IrLPT client: Can't allocate hashbin!\n");
-		return -ENOMEM;
-	}
-	hints = irlmp_service_to_hint(S_PRINTER);
-	ckey = irlmp_register_client(hints, irlpt_client_discovery_indication,
-				     NULL);
-
-#ifdef CONFIG_PROC_FS
-	create_proc_entry("irlpt_client", 0, proc_irda)->get_info
-		= irlpt_client_proc_read;
-#endif /* CONFIG_PROC_FS */
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-
-#ifdef MODULE
-/*
- * Function irlpt_client_cleanup (void)
- *
- */
-static void irlpt_client_cleanup(void)
-{
-	DEBUG( irlpt_client_debug, "--> "__FUNCTION__ "\n");
-
-	irlmp_unregister_client(ckey);
-
-	/*
-	 *  Delete hashbin and close all irlpt client instances in it
-	 */
-	hashbin_delete( irlpt_clients, (FREE_FUNC) irlpt_client_close);
-
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("irlpt_client", proc_irda);
-#endif
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-}
-#endif /* MODULE */
-
-
-/*
- * Function irlpt_client_open (void)
- *
- */
-static struct irlpt_cb *irlpt_client_open( __u32 daddr)
-{
-	struct irmanager_event mgr_event;
-	struct irlpt_cb *self;
-
-	DEBUG( irlpt_client_debug, "--> "__FUNCTION__ "\n");
-
-	self = (struct irlpt_cb *) hashbin_find(irlpt_clients, daddr, NULL);
-
-	if (self == NULL) {
-	        self = kmalloc(sizeof(struct irlpt_cb), GFP_ATOMIC);
-		if (self == NULL)
-		        return NULL;
-
-		memset(self, 0, sizeof(struct irlpt_cb));
-
-		ASSERT( self != NULL, return NULL;);
-
-		sprintf(self->ifname, "irlpt%d", 
-			hashbin_get_size(irlpt_clients));
-
-		hashbin_insert( irlpt_clients, (QUEUE *) self, daddr, NULL);
-	}
-
-	self->ir_dev.minor = MISC_DYNAMIC_MINOR;
-	self->ir_dev.name = self->ifname;
-	self->ir_dev.fops = &client_fops;
-
-	misc_register(&self->ir_dev);
-
-	self->magic = IRLPT_MAGIC;
-	self->in_use = TRUE;
-	self->servicetype = IRLPT_THREE_WIRE_RAW;
-	self->porttype = IRLPT_SERIAL;
-	self->do_event = irlpt_client_do_event;
-
-	skb_queue_head_init(&self->rx_queue);
-
-	irlpt_client_next_state( self, IRLPT_CLIENT_IDLE);
-
-	/* Tell irmanager to create /dev/irlpt<X> */
-	mgr_event.event = EVENT_IRLPT_START;
-	sprintf(mgr_event.devname, "%s", self->ifname);
-	irmanager_notify(&mgr_event);
-
-	MOD_INC_USE_COUNT;
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-
-	return self;
-}
-
-/*
- * Function irlpt_client_close (self)
- *
- *    This function closes and marks the IrLPT instance as not in use.
- */
-static void irlpt_client_close( struct irlpt_cb *self)
-{
-	struct irmanager_event mgr_event;
-	struct sk_buff *skb;
-
-	DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	/* Tell irmanager to remove /dev/irlpt<X> */
-	mgr_event.event = EVENT_IRLPT_STOP;
- 	sprintf(mgr_event.devname, "%s", self->ifname);
- 	irmanager_notify(&mgr_event);
-
-	while (( skb = skb_dequeue(&self->rx_queue)) != NULL) {
-		DEBUG(irlpt_client_debug, 
-		      __FUNCTION__ ": freeing SKB\n");
-                dev_kfree_skb( skb);
-	}
-
-	misc_deregister(&self->ir_dev);
-	self->in_use = FALSE;
-
-	MOD_DEC_USE_COUNT;
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function irlpt_discovery_indication (daddr)
- *
- *    Remote device discovered, try query the remote IAS to see which
- *    device it is, and which services it has.
- *
- */
-static void irlpt_client_discovery_indication(discovery_t *discovery)
-{
-	struct irlpt_info info;
-	struct irlpt_cb *self;
-	__u32 daddr; /* address of remote printer */
-	__u32 saddr; /* address of local link where it was discovered */
-
-	DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
-
-	ASSERT( irlpt_clients != NULL, return;);
-	ASSERT( discovery != NULL, return;);
-
-	daddr = info.daddr = discovery->daddr;
-	saddr = info.saddr = discovery->saddr;
-
-	/*
-	 *  Check if an instance is already dealing with this device
-	 *  (daddr)
-	 */
-	self = (struct irlpt_cb *) hashbin_find( irlpt_clients, daddr, NULL);
-      	if (self == NULL || self->in_use == FALSE) {
-	        DEBUG( irlpt_client_debug, __FUNCTION__ 
-		       ": daddr 0x%08x not found or was closed\n", daddr);
-	        /*
-		 * We have no instance for daddr, so time to start a new 
-		 * instance. First we must find a free entry in master array
-		 */
-		if (( self = irlpt_client_open( daddr)) == NULL) {
-			DEBUG(irlpt_client_debug, __FUNCTION__ 
-			      ": failed!\n");
-			return;
-		}
-	}
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLPT_MAGIC, return;);
-
-	self->daddr = daddr;
-	self->saddr = saddr;
-	self->timeout = irlpt_client_expired;
-
-	irda_start_timer( &self->lpt_timer, 5000, (unsigned long) self, 
-			  self->timeout);
-	
-#if 0
-	/* changed to wake up when we get connected; that way,
-	   if the connection drops, we can easily kill the link. */
-	wake_up_interruptible( &self->write_wait);
-#endif
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function irlpt_disconnect_indication (handle)
- *
- */
-static void irlpt_client_disconnect_indication( void *instance,
-						void *sap, 
-						LM_REASON reason,
-						struct sk_buff *skb)
-{
-	struct irlpt_info info;
-	struct irlpt_cb *self;
-
-	DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
-
-	self = ( struct irlpt_cb *) instance;
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	info.daddr = self->daddr;
-
-        DEBUG( irlpt_client_debug, 
-	       __FUNCTION__ ": reason=%d (%s), peersap=%d\n",
-	       reason, irlpt_reasons[reason], self->dlsap_sel);
-
-	self->connected = IRLPT_DISCONNECTED;
-	self->eof = reason;
-
-	wake_up_interruptible( &self->write_wait);
-
-	irlpt_client_do_event( self, LMP_DISCONNECT, NULL, NULL);
-
-	if (skb)
-		dev_kfree_skb( skb);
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function irlpt_connect_confirm (handle, qos, skb)
- *
- *    LSAP connection confirmed!
- */
-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)
-{
-	struct irlpt_info info;
-	struct irlpt_cb *self;
-
-	DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
-
-	self = ( struct irlpt_cb *) instance;
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	info.daddr = self->daddr;
-
-#if 0
-	/*
-	 *  Check if we have got some QoS parameters back! This should be the
-	 *  negotiated QoS for the link.
-	 */
-	if ( qos) {
-		DEBUG( irlpt_client_debug, __FUNCTION__ ": Frame Size: %d\n",
-		       qos->data_size.value);
-	}
-#endif
-
-	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)
-		dev_kfree_skb( skb);
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function client_data_indication (handle, skb)
- *
- *    This function gets the data that is received on the data channel
- *
- */
-static int irlpt_client_data_indication(void *instance, void *sap, 
-					struct sk_buff *skb) 
-{
-	struct irlpt_cb *self;
-
-	DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
-
-	ASSERT( skb != NULL, return -1;);
-	DEBUG( irlpt_client_debug, __FUNCTION__ ": len=%d\n", (int) skb->len);
-
-	self = ( struct irlpt_cb *) instance;
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-#if 1
-	{
-		int i;
-
-		for(i=0;i<skb->len;i++)
-			if (skb->data[i] > 31 && skb->data[i] < 128) {
-				printk("%c", skb->data[i]);
-			} else {
-				if (skb->data[i] == 0x0d) {
-					printk("\n");
-				} else {
-					printk(".");
-				}
-			}
-
-		printk("\n");
-	}
-#endif
-	
-	skb_queue_tail(&self->rx_queue, skb);
-        wake_up_interruptible(&self->read_wait);
-
-/* 	if (skb) { */
-/* 		dev_kfree_skb( skb); */
-/* 	} */
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-/*
- * Function irlpt_get_value_confirm (obj_id, type, value_int, value_char, priv)
- *
- *    Fixed to match changes in iriap.h, DB.
- *
- */
-void irlpt_client_get_value_confirm(int result, __u16 obj_id, 
-				    struct ias_value *value, void *priv)
-{
-	struct irlpt_info info;
-	struct irlpt_cb *self;
-
-	DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
-
-	ASSERT( priv != NULL, return;);
-
-	self = (struct irlpt_cb *) priv;
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	/* Check if request succeeded */
-	if (result != IAS_SUCCESS) {
-		DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
-		irlpt_client_do_event( self, IAS_PROVIDER_NOT_AVAIL, NULL, 
-				       &info);
-		return;
-	}
-
-	if ( value->type == IAS_INTEGER && value->t.integer != -1) {
-	        info.dlsap_sel = value->t.integer;
-		self->dlsap_sel = value->t.integer;
-
-		DEBUG( irlpt_client_debug, __FUNCTION__ 
-		       ": obj_id = %d, value = %d\n", 
-		       obj_id, value->t.integer);
-
-		irlpt_client_do_event( self, IAS_PROVIDER_AVAIL, NULL, &info);
-	} else
-		irlpt_client_do_event( self, IAS_PROVIDER_NOT_AVAIL, NULL, 
-				       &info);
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-}
-
-void irlpt_client_connect_request( struct irlpt_cb *self) 
-{
-	struct notify_t lpt_notify;
-
-	DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	irda_notify_init( &lpt_notify);
-
-	lpt_notify.connect_confirm = irlpt_client_connect_confirm;
-	lpt_notify.disconnect_indication = irlpt_client_disconnect_indication;
-	lpt_notify.data_indication = irlpt_client_data_indication;
-	strcpy( lpt_notify.name, "IrLPT client");
-	lpt_notify.instance = self;
-
-	self->lsap = irlmp_open_lsap( LSAP_ANY, &lpt_notify);
-	DEBUG( irlpt_client_debug, __FUNCTION__ ": Dest LSAP sel= %d\n", 
-	       self->dlsap_sel);
-	
-	if (self->servicetype == IRLPT_THREE_WIRE_RAW) {
-	        DEBUG( irlpt_client_debug, __FUNCTION__ 
-		       ": issue THREE_WIRE_RAW connect\n");
-		irlmp_connect_request( self->lsap, self->dlsap_sel, 
-				       self->saddr, self->daddr, NULL, NULL);
-	}
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-}
-
-static void irlpt_client_expired(unsigned long data)
-{
-	struct irlpt_cb *self = (struct irlpt_cb *) data;
-	struct sk_buff *skb;
-
-	DEBUG( irlpt_client_debug, "--> " __FUNCTION__ "\n");
-
-	DEBUG( irlpt_client_debug, __FUNCTION__
-	       ": removing irlpt_cb!\n");
-
-	ASSERT(self != NULL, return; );
-	ASSERT(self->magic == IRLPT_MAGIC, return;);
-
-	if (self->state == IRLPT_CLIENT_CONN) {
-		skb = dev_alloc_skb(64);
-		if (skb == NULL) {
-			DEBUG( 0, __FUNCTION__ "(: Could not allocate an "
-			       "sk_buff of length %d\n", 64);
-			return;
-		}
-
-		skb_reserve(skb, LMP_MAX_HEADER);
-		irlmp_disconnect_request(self->lsap, skb);
-		DEBUG(irlpt_client_debug, __FUNCTION__
-		      ": irlmp_close_slap(self->lsap)\n");
-		irlmp_close_lsap(self->lsap);
-	}
-
-	irlpt_client_close(self);
-
-	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Thomas Davis <ratbert@radiks.net>");
-MODULE_DESCRIPTION("The Linux IrDA/IrLPT client protocol");
-MODULE_PARM(irlpt_client_debug,"1i");
-MODULE_PARM(irlpt_client_fsm_debug,"1i");
-
-/*
- * Function init_module (void)
- *
- *    Initialize the IrLPT client module, this function is called by the
- *    modprobe(1) program.
- */
-int init_module(void)
-{
-
-        DEBUG( irlpt_client_debug, "--> IrLPT client: init_module\n");
-
-        irlpt_client_init();
-
-        DEBUG( irlpt_client_debug, "IrLPT client: init_module -->\n");
-
-        return 0;
-}
-
-/*
- * Function cleanup_module (void)
- *
- *    Remove the IrLPT server module, this function is called by the rmmod(1)
- *    program
- */
-void cleanup_module(void)
-{
-        DEBUG( irlpt_client_debug, "--> IrLPT client: cleanup_module\n");
-        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-
-        /* Free some memory */
-        irlpt_client_cleanup();
-
-        DEBUG( irlpt_client_debug, "IrLPT client: cleanup_module -->\n");
-}
-
-#endif /* MODULE */
diff -urN linux-2.2.15-pre2/net/irda/irlpt/irlpt_cli_fsm.c linux/net/irda/irlpt/irlpt_cli_fsm.c
--- linux-2.2.15-pre2/net/irda/irlpt/irlpt_cli_fsm.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irlpt/irlpt_cli_fsm.c	Wed Dec 31 16:00:00 1969
@@ -1,369 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irlpt_cli_fsm.c
- * Version:       0.1
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Tue Jan 12 11:06:00 1999
- * Modified at:   Sun May  9 13:36:13 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-1999, 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 
- *     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, provide no warranty for any of this software. This 
- *     material is provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#include <net/irda/iriap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irlpt_common.h>
-#include <net/irda/irlpt_cli.h>
-#include <net/irda/irlpt_cli_fsm.h>
-#include <net/irda/irda.h>
-
-#if 0
-static char *rcsid = "$Id: irlpt_client_fsm.c,v 1.3 1998/10/05 05:46:44 ratbert Exp $";
-#endif
-
-static int irlpt_client_state_idle  ( struct irlpt_cb *self, 
-				      IRLPT_EVENT event,
-				      struct sk_buff *skb, 
-				      struct irlpt_info *info);
-static int irlpt_client_state_query ( 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, 
-				      struct irlpt_info *info);
-static int irlpt_client_state_conn  ( struct irlpt_cb *self, 
-				      IRLPT_EVENT event,
-				      struct sk_buff *skb, 
-				      struct irlpt_info *info);
-
-int irlpt_client_fsm_debug = 4;
-
-int (*irlpt_client_state[])( struct irlpt_cb *self, 
-			     IRLPT_EVENT event, 
-			     struct sk_buff *skb, 
-			     struct irlpt_info *info) = 
-{ 
-	irlpt_client_state_idle,
-	irlpt_client_state_query,
-	irlpt_client_state_ready,
-	irlpt_client_state_waiti,
-	irlpt_client_state_conn,
-};
-
-void irlpt_client_do_event( struct irlpt_cb *self, 
-			    IRLPT_EVENT event, 
-			    struct sk_buff *skb, 
-			    struct irlpt_info *info) 
-{
-	DEBUG( irlpt_client_fsm_debug, "--> "  __FUNCTION__ "\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	DEBUG( irlpt_client_fsm_debug, 
-	       __FUNCTION__ ": STATE = %s, EVENT = %s\n", 
-	       irlpt_server_fsm_state[self->state], irlpt_fsm_event[event]);
-
-	(*irlpt_client_state[ self->state]) ( self, event, skb, info);
-
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ " -->\n");
-}
-
-void irlpt_client_next_state( struct irlpt_cb *self, 
-			      IRLPT_CLIENT_STATE state) 
-{
-	DEBUG( irlpt_client_fsm_debug, "--> "  __FUNCTION__ ":\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ ": NEXT STATE = %s\n", 
-	       irlpt_client_fsm_state[state]);
-
-	self->state = state;
-
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function irlpt_client_state_idle (self, event, skb, info)
- *
- *    IDLE, We are waiting for an indication that there is a provider
- *    available.
- */
-static int irlpt_client_state_idle( struct irlpt_cb *self, 
-				    IRLPT_EVENT event, 
-				    struct sk_buff *skb, 
-				    struct irlpt_info *info) 
-{
-	DEBUG( irlpt_client_fsm_debug, "--> "  __FUNCTION__ ":\n");
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	switch( event) {
-	case IRLPT_DISCOVERY_INDICATION:
-		/* Get some values from peer IAS */
-		DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": IRLPT_DISCOVERY_INDICATION, "
-		       "sending getvaluebyclass command..\n");
-		iriap_getvaluebyclass_request( 
-			"IrLPT", "IrDA:IrLMP:LsapSel",
-			info->saddr, info->daddr,
-			irlpt_client_get_value_confirm,
-			(void *) self);
-		irlpt_client_next_state( self, IRLPT_CLIENT_QUERY);
-		break;
-
-	default:
-		DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": Unknown event %d (%s)\n",
-		       event, irlpt_fsm_event[event]);
-		break;
-	}
-
-	if (skb) {
-		dev_kfree_skb( skb);
-	}
-
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-/*
- * Function irlpt_client_state_query
- *
- *    QUERY, We have queryed the remote IAS and is ready to connect
- *    to provider, just waiting for the confirm.
- *
- */
-static int irlpt_client_state_query( struct irlpt_cb *self, 
-				     IRLPT_EVENT event, 
-				     struct sk_buff *skb, 
-				     struct irlpt_info *info) 
-{
-	DEBUG( irlpt_client_fsm_debug, "--> "  __FUNCTION__ ":\n");
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	switch( event) {
-	case IAS_PROVIDER_AVAIL:
-		DEBUG( irlpt_client_fsm_debug, 
-		       __FUNCTION__ ": IAS_PROVIDER_AVAIL\n");
-		self->open_retries = 0;
-		irlpt_client_next_state( self, IRLPT_CLIENT_READY);
-		irlpt_client_do_event( self, IRLPT_CONNECT_REQUEST, 
-				       NULL, NULL);
-		break;
-
-	case IAS_PROVIDER_NOT_AVAIL:
-		DEBUG( irlpt_client_fsm_debug, 
-		       __FUNCTION__ ": IAS_PROVIDER_NOT_AVAIL\n");
-		irlpt_client_next_state( self, IRLPT_CLIENT_IDLE);
-		DEBUG(irlpt_client_fsm_debug, __FUNCTION__
-		      ": waking any sleepers..\n");
-		wake_up_interruptible(&self->read_wait);
-		break;
-
-	case LMP_DISCONNECT:
-	case LAP_DISCONNECT:
-	        DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": LMP_DISCONNECT or LAP_DISCONNECT\n");
-		irlpt_client_next_state( self, IRLPT_CLIENT_IDLE);
-		DEBUG(irlpt_client_fsm_debug, __FUNCTION__
-		      ": waking any sleepers..\n");
-		wake_up_interruptible(&self->read_wait);
-		break;
-	default:
-		DEBUG( irlpt_client_fsm_debug, 
-		       __FUNCTION__ ": Unknown event %d (%s)\n",
-		       event, irlpt_fsm_event[event]);
-		break;
-	}
-
-	if (skb) {
-		dev_kfree_skb( skb);
-	}
-
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-/*
- * Function irlpt_client_state_info 
- *
- *    INFO, We have issued a GetInfo command and is awaiting a reply.
- */
-static int irlpt_client_state_ready( struct irlpt_cb *self, 
-				     IRLPT_EVENT event,
-				     struct sk_buff *skb, 
-				     struct irlpt_info *info) 
-{
-	DEBUG( irlpt_client_fsm_debug,"--> "  __FUNCTION__ ":\n");
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	switch( event) {
-	case IRLPT_CONNECT_REQUEST:
-	        DEBUG( irlpt_client_fsm_debug, 
-		       __FUNCTION__ ": IRLPT_CONNECT_REQUEST\n");
-		irlpt_client_connect_request(self);
-		irlpt_client_next_state( self, IRLPT_CLIENT_WAITI);
-		break;
-	case LMP_DISCONNECT:
-	case LAP_DISCONNECT:
-	        DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": LMP_DISCONNECT or LAP_DISCONNECT\n");
-		DEBUG(irlpt_client_fsm_debug, __FUNCTION__
-		      ": waking any sleepers..\n");
-		wake_up_interruptible(&self->read_wait);
-		irlpt_client_next_state( self, IRLPT_CLIENT_IDLE);
-		break;
-	default:
-		DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": Unknown event %d (%s)\n", 
-		       event, irlpt_fsm_event[event]);
-		break;
-	}
-
-	if ( skb) {
-		dev_kfree_skb( skb);
-	}
-
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-
-/*
- * Function irlpt_client_state_waiti 
- *
- *
- */
-static int irlpt_client_state_waiti( struct irlpt_cb *self, 
-				     IRLPT_EVENT event, 
-				     struct sk_buff *skb, 
-				     struct irlpt_info *info) 
-{
-	DEBUG( irlpt_client_fsm_debug,"--> "  __FUNCTION__ ":\n");
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	switch( event) {
-	case LMP_CONNECT:
-	        DEBUG( irlpt_client_fsm_debug, __FUNCTION__ ": LMP_CONNECT\n");
-	        irlpt_client_next_state(self, IRLPT_CLIENT_CONN);
-		DEBUG(irlpt_client_fsm_debug, __FUNCTION__
-		      ": waking any sleepers..\n");
-		wake_up_interruptible(&self->read_wait);
-	        break;
-	case LAP_DISCONNECT:
-	case LMP_DISCONNECT:
-	        DEBUG( irlpt_client_fsm_debug, 
-		       __FUNCTION__ ": LMP_DISCONNECT\n");
-		DEBUG(irlpt_client_fsm_debug, __FUNCTION__
-		      ": waking any sleepers..\n");
-		wake_up_interruptible(&self->read_wait);
-	        irlpt_client_next_state( self, IRLPT_CLIENT_IDLE);
-	        break;
-
-	default:
-		DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": Unknown event %d (%s)\n", 
-		       event, irlpt_fsm_event[event]);
-		break;
-	}
-
-	if ( skb) {
-		dev_kfree_skb( skb);
-	}
-
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-/*
- * Function irlpt_client_state_conn (self, event, skb, info)
- *
- *    CONN, We have connected to a provider but has not issued any
- *    commands yet.
- *
- */
-static int irlpt_client_state_conn( struct irlpt_cb *self, 
-				    IRLPT_EVENT event, 
-				    struct sk_buff *skb, 
-				    struct irlpt_info *info) 
-{
-	DEBUG( irlpt_client_fsm_debug, "--> " __FUNCTION__ ":\n");
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	switch( event) {
-	case CLIENT_DATA_INDICATION:
-		DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": CLIENT_DATA_INDICATION\n");
-		irlpt_client_next_state( self, IRLPT_CLIENT_CONN);
-		break;
-
-	case LMP_DISCONNECT:
-	case LAP_DISCONNECT:
-		DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": LMP_DISCONNECT/LAP_DISCONNECT\n");
-		DEBUG(irlpt_client_fsm_debug, __FUNCTION__
-		      ": waking any sleepers..\n");
-		wake_up_interruptible(&self->read_wait);
-	        irlpt_client_next_state( self, IRLPT_CLIENT_IDLE);
-		irlpt_client_next_state( self, IRLPT_CLIENT_IDLE);
-		break;
-
-	default:
-		DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-		       ": Unknown event %d (%s)\n",
-		       event, irlpt_fsm_event[event]);
-		break;
-	}
-
-	if ( skb) {
-		dev_kfree_skb( skb);
-	}
-
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-void irlpt_client_print_event( IRLPT_EVENT event) 
-{
-	DEBUG( irlpt_client_fsm_debug, __FUNCTION__ 
-	       ": IRLPT_EVENT = %s\n", irlpt_fsm_event[event]);
-}
-
-
diff -urN linux-2.2.15-pre2/net/irda/irlpt/irlpt_common.c linux/net/irda/irlpt/irlpt_common.c
--- linux-2.2.15-pre2/net/irda/irlpt/irlpt_common.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irlpt/irlpt_common.c	Wed Dec 31 16:00:00 1969
@@ -1,509 +0,0 @@
-/*********************************************************************
- *
- * Filename:      irlpt_common.c
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Thomas Davis, <ratbert@radiks.net>
- * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Sun Mar  8 23:44:19 1998
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * Sources:	  irlpt.c
- *
- *     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
- *     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, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h> 
-
-#include <asm/segment.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irttp.h>
-#include <net/irda/timer.h>
-
-#include <net/irda/irlpt_common.h>
-/* #include "irlpt_client.h" */
-/* #include "irlpt_server.h" */
-
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/fs.h>
-
-char *irlpt_service_type[] = {
-	"IRLPT_UNKNOWN",
-	"IRLPT_THREE_WIRE_RAW",
-	"IRLPT_THREE_WIRE",
-	"IRLPT_NINE_WIRE",
-	"IRLPT_CENTRONICS",
-	"IRLPT_SERVER_MODE",
-};
-
-char *irlpt_port_type[] = {
-	"IRLPT_UNKNOWN",
-	"IRLPT_SERIAL",
-	"IRLPT_PARALLEL",
-};
-
-char *irlpt_connected[] = {
-	"IRLPT_DISCONNECTED",
-	"IRLPT_WAITING",
-	"IRLPT_CONNECTED",
-	"IRLPT_FLUSHED",
-};
-
-char *irlpt_reasons[] = {
-	"SERVICE_CLOSE",     /* Service has closed the connection */
-	"DISC_INDICATION",   /* Received disconnect request from peer entity*/
-	"NO_RESPONSE",       /* To many retransmits without response */
-	"DEADLOCK_DETECTED", /* To many retransmits _with_ response */
-	"FOUND_NONE",        /* No devices were discovered */
-	"MEDIA_BUSY",
-
-};
-
-char *irlpt_client_fsm_state[] = {
-	"IRLPT_CLIENT_IDLE",
-	"IRLPT_CLIENT_QUERY",
-	"IRLPT_CLIENT_READY",
-	"IRLPT_CLIENT_WAITI",
-	"IRLPT_CLIENT_CONN"
-};
-
-char *irlpt_server_fsm_state[] = {
-	"IRLPT_SERVER_IDLE",
-	"IRLPT_SERVER_CONN"
-};
-
-char *irlpt_fsm_event[] = {
-	"QUERY_REMOTE_IAS",
-	"IAS_PROVIDER_AVAIL",
-	"IAS_PROVIDER_NOT_AVAIL",
-	"LAP_DISCONNECT",
-	"LMP_CONNECT",
-	"LMP_DISCONNECT",
-	"LMP_CONNECT_INDICATION",
-	"LMP_DISCONNECT_INDICATION",
-        "IRLPT_DISCOVERY_INDICATION",
-	"IRLPT_CONNECT_REQUEST",
-	"IRLPT_DISCONNECT_REQUEST",
-	"CLIENT_DATA_INDICATION",
-};
-
-hashbin_t *irlpt_clients = NULL;
-struct irlpt_cb *irlpt_server = NULL;
-int irlpt_common_debug = 4;  /* want to change this? please don't! 
-				use irlpt_common_debug=3 on the 
-				command line! */
-
-#if 0
-static char *rcsid = "$Id: irlpt_common.c,v 1.6 1998/11/10 22:50:58 dagb Exp $";
-#endif
-
-struct irlpt_cb *irlpt_find_handle(unsigned int minor)
-{
-	struct irlpt_cb *self;
-
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-	
-	/* Check for server */
-	if (irlpt_server != NULL && irlpt_server->ir_dev.minor == minor) {
-		DEBUG(irlpt_common_debug, __FUNCTION__ 
-		      ": irlpt_server file handle!\n");
-		return irlpt_server;
-	}
-
-	/* Check the clients */
-	self = (struct irlpt_cb *) hashbin_get_first( irlpt_clients);
-	while ( self) {
-		ASSERT( self->magic == IRLPT_MAGIC, return NULL;);
-		
-		if ( minor == self->ir_dev.minor)
-			return self;
-
-		self = (struct irlpt_cb *) hashbin_get_next( irlpt_clients);
-	}
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-
-	return NULL;
-}
-
-ssize_t irlpt_read( struct file *file, char *buffer, size_t count, loff_t
-		    *noidea)
-{
-	int len=0;
-	char *ptr = buffer;
-	struct irlpt_cb *self;
-	struct sk_buff *skb = NULL;
-
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-
-	self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
-
-	ASSERT( self != NULL, return 0;);
-	ASSERT( self->magic == IRLPT_MAGIC, return 0;);
-
-	DEBUG( irlpt_common_debug, __FUNCTION__ 
-	       ": count=%d, skb_len=%d, connected=%d (%s) eof=%d\n", 
-	       count, skb_queue_len(&self->rx_queue), self->connected, 
-	       irlpt_connected[self->connected], self->eof);
-
-	if (self->eof && !skb_queue_len(&self->rx_queue)) {
-		switch (self->eof) {
-		case LM_USER_REQUEST:
-			self->eof = FALSE;
-			DEBUG(irlpt_common_debug, 
-			      __FUNCTION__ ": returning 0\n");
-			return 0;
-		case LM_LAP_DISCONNECT:
-			self->eof = FALSE;
-			return 0;
-		case LM_LAP_RESET:
-			self->eof = FALSE;
-			return -ECONNRESET;
-		default:
-			self->eof = FALSE;
-			return -EIO;
-		}
-	}
-
-	while (len <= count) {
-		skb = skb_dequeue(&self->rx_queue);
-
-		if (skb != NULL) {
-			DEBUG(irlpt_common_debug, __FUNCTION__ 
-			      ": len=%d, skb->len=%d, count=%d\n", 
-			       len, (int) skb->len, count);
-
-			if ((skb->len + len) < count) {
-				copy_to_user(ptr, skb->data, skb->len);
-				len += skb->len;
-				ptr += skb->len;
-		
-				dev_kfree_skb( skb);
-			} else {
-				skb_queue_head(&self->rx_queue, skb);
-				break;
-			}
-		} else {
-			DEBUG( irlpt_common_debug, __FUNCTION__ 
-			       ": skb=NULL, len=%d, count=%d, eof=%d\n", 
-			       len, count, self->eof);
-
-			if (!signal_pending(current) && !self->eof) {
-				interruptible_sleep_on(&self->read_wait);
-			} else
-				break;
-		}
-	}
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ ": len=%d\n", len);
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-	return len;
-}
-
-ssize_t irlpt_write(struct file *file, const char *buffer,
-		    size_t count, loff_t *noidea)
-{
-	struct irlpt_cb *self;
-	struct sk_buff *skb;
-
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-
-	self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
-
-	ASSERT( self != NULL, return 0;);
-	ASSERT( self->magic == IRLPT_MAGIC, return 0;);
-	
-	DEBUG( irlpt_common_debug, __FUNCTION__ 
-	       ": count = %d\n", count);
-
-	DEBUG( irlpt_common_debug, __FUNCTION__ 
-	       ": pkt_count = %d\n", self->pkt_count);
-	if (self->pkt_count > 8) {
-		DEBUG( irlpt_common_debug, __FUNCTION__ 
-		       ": too many outstanding buffers, going to sleep\n");
-		interruptible_sleep_on(&self->write_wait);
-	}
-
-	DEBUG( irlpt_common_debug, __FUNCTION__ 
-	       ": pkt_count = %d\n", self->pkt_count);
-
-	if (self->state != IRLPT_CLIENT_CONN) {
-		DEBUG( irlpt_common_debug, __FUNCTION__ 
-		       ": state != IRLPT_CONN (possible link problems?)\n");
-		return -ENOLINK;
-	}
-
-	DEBUG( irlpt_common_debug, __FUNCTION__ 
-	       ": count = %d, max_data_size = %d, IRLPT_MAX_HEADER = %d\n",
-		count, self->max_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 + self->max_header_size);
-	if ( skb == NULL) {
-		printk( KERN_INFO 
-			__FUNCTION__ ": couldn't allocate skbuff!\n");
-		return 0;
-	}
-
-	/*
-	 * we use the unused stamp field to hold the device minor
-	 * number, so we can look it up when the skb is destroyed.
-	 */
-	*((__u32 *) &skb->stamp) = MINOR( file->f_dentry->d_inode->i_rdev);
-
-	skb_reserve( skb, IRLPT_MAX_HEADER);
-	skb_put( skb, count);
-
-	skb->destructor = irlpt_flow_control;
-	self->pkt_count++;
-
-	copy_from_user( skb->data, buffer, count);
-
-	irlmp_data_request(self->lsap, skb);
-
-	irda_start_timer( &self->lpt_timer, 5000, (unsigned long) self, 
-			  self->timeout);
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-
-	return(count);
-}
-
-loff_t irlpt_seek( struct file *file, loff_t offset, int count)
-{
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-	return -ESPIPE;
-}
-
-/*
- * Function irlpt_poll (file, wait)
- *
- *    
- *
- */
-u_int irlpt_poll(struct file *file, poll_table *wait)
-{
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-
-	/* check out /usr/src/pcmcia/modules/ds.c for an example */
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-	return 0;
-}
-
-/*
- * Function open_irlpt (inode, file)
- *
- *
- *
- */
-int irlpt_open(struct inode *inode, struct file *file)
-{
-	struct irlpt_cb *self;
-	struct irlpt_info info;
-
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-
-	self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	if (self->count++) {
-		DEBUG( irlpt_common_debug, __FUNCTION__ 
-		       ": count not zero; actual = %d\n", self->count);
-		self->count--;
-		return -EBUSY;
-	}
-
-	self->eof = FALSE;
-
-	/* ok, now, if it's idle, try to get some information
-	   about the remote end, and sleep till we get totally connected.. */
-
-	if ((self->servicetype != IRLPT_SERVER_MODE) && 
-	    self->state != IRLPT_CLIENT_CONN) {
-		DEBUG(irlpt_common_debug, __FUNCTION__
-		      ": self->state != IRLPT_CLIENT_CONN\n");
-
-		info.daddr = self->daddr;
-		info.saddr = self->saddr;
-
-		if (self->do_event != NULL) {
-			DEBUG(irlpt_common_debug, __FUNCTION__ 
-			      ": doing a discovery..\n");
-			self->do_event( self, 
-					IRLPT_DISCOVERY_INDICATION, 
-					NULL, &info);
-			DEBUG(irlpt_common_debug, __FUNCTION__ 
-			      ": sleeping until connected.\n");
-			interruptible_sleep_on(&self->read_wait);
-		}
-	}
-
-	/* at this point, if it's a client, we have a connection.
-	 * if it's the server, it's waiting for a connection.
-	 */
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-/*
- * Function close_irlpt (inode, file)
- *
- *
- *
- */
-int irlpt_close(struct inode *inode, 
-		struct file *file)
-{
-	struct irlpt_cb *self;
-	struct sk_buff *skb;
-	struct irlpt_info info;
-
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-
-	self = irlpt_find_handle(MINOR( file->f_dentry->d_inode->i_rdev));
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ ": have handle!\n");
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	DEBUG(irlpt_common_debug, 
-	      __FUNCTION__ ": self->count=%d\n", self->count);
-
-	if (self->count > 0)
-		self->count--;
-
-	while (self->pkt_count > 0) {
-		interruptible_sleep_on(&self->write_wait);
-	}
-
-	/* all done, tear down the connection and wait for the next open */
-	if ((self->servicetype != IRLPT_SERVER_MODE) &&
-	    self->state == IRLPT_CLIENT_CONN) {
-		skb = dev_alloc_skb(64);
-		if (skb == NULL) {
-			DEBUG( 0, __FUNCTION__ "(: Could not allocate an "
-			       "sk_buff of length %d\n", 64);
-			return 0;
-		}
-
-		skb_reserve( skb, LMP_MAX_HEADER);
-		irlmp_disconnect_request(self->lsap, skb);
-		DEBUG(irlpt_common_debug, __FUNCTION__
-		      ": irlmp_close_slap(self->lsap)\n");
-		irlmp_close_lsap(self->lsap);
-	}
-
-	info.daddr = self->daddr;
-
-	if (self->do_event != NULL) {
-	        DEBUG(irlpt_common_debug, __FUNCTION__ 
-		      ": closing connection..\n");
-		self->do_event( self, LMP_DISCONNECT, NULL, &info);
-	}
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-	return 0;
-}
-
-void irlpt_dump_buffer( struct sk_buff *skb) 
-{
-	int i;
-
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-
-	for(i=0;i<skb->len;i++)
-		if (skb->data[i] > 31 && skb->data[i] < 128) {
-			printk("%c", skb->data[i]);
-		} else {
-			if (skb->data[i] == 0x0d) {
-				printk("\n");
-			} else {
-				printk(".");
-			}
-		}
-	
-	printk("\n");
-	
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-}
-
-void irlpt_flow_control(struct sk_buff *skb)
-{
-	struct irlpt_cb *self;
-
-	DEBUG(irlpt_common_debug, "--> " __FUNCTION__ "\n");
-
-	self = irlpt_find_handle( *((__u32 *) &skb->stamp));
-
-	self->pkt_count--;
-
-	ASSERT(self->pkt_count >= 0, return;);
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ 
-	      ": packet destroyed, count = %d\n", self->pkt_count);
-
-	wake_up_interruptible( &self->write_wait);
-
-	DEBUG(irlpt_common_debug, __FUNCTION__ " -->\n");
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Thomas Davis <ratbert@radiks.net>");
-MODULE_DESCRIPTION("The Linux IrDA/IrLPT common");
-MODULE_PARM(irlpt_common_debug,"1i");
-
-/*
- * Function init_module (void)
- *
- *    Initialize the module, this function is called by the
- *    modprobe(1) program.
- */
-int init_module(void) 
-{
-	return 0;
-}
-
-/*
- * Function cleanup_module (void)
- *
- *    Remove the module, this function is called by the rmmod(1)
- *    program
- */
-void cleanup_module(void) 
-{
-
-}
-
-#endif /* MODULE */
diff -urN linux-2.2.15-pre2/net/irda/irlpt/irlpt_srvr.c linux/net/irda/irlpt/irlpt_srvr.c
--- linux-2.2.15-pre2/net/irda/irlpt/irlpt_srvr.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irlpt/irlpt_srvr.c	Wed Dec 31 16:00:00 1969
@@ -1,530 +0,0 @@
-/*********************************************************************
- *
- * Filename:      irlpt.c
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Thomas Davis, <ratbert@radiks.net>
- * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Sun Mar  8 23:44:19 1998
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * Sources:	  irlan.c
- *
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>,
- *			   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
- *     published by the Free Software Foundation; either version 2 of
- *     the License, or (at your option) any later version.
- *
- *     I, Thomas Davis, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/proc_fs.h>
-
-#include <net/irda/irlap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irias_object.h>
-#include <net/irda/timer.h>
-#include <net/irda/irda.h>
-#include <net/irda/irlpt_common.h>
-#include <net/irda/irlpt_server.h>
-#include <net/irda/irlpt_server_fsm.h>
-
-#ifdef CONFIG_PROC_FS
-static int irlpt_server_proc_read(char *buf, char **start, off_t offset, 
-				  int len, int unused);
-#endif /* CONFIG_PROC_FS */
-
-int irlpt_server_init(void);
-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);
-static void deregister_irlpt_server(void);
-
-static __u32 skey; /* IrLMP service handle */
-
-int irlpt_server_lsap = LSAP_IRLPT;
-int irlpt_server_debug = 4;
-
-#if 0
-static char *rcsid = "$Id: irlpt_server.c,v 1.9 1998/10/22 12:02:22 dagb Exp $";
-#endif
-
-static char *version = "IrLPT server, v2 (Thomas Davis)";
-
-struct file_operations irlpt_fops = {
-	irlpt_seek,	/* seek */
-	irlpt_read,     /* read */   
-	irlpt_write,
-	NULL,		/* readdir */
-	NULL,           /* poll */
-	NULL,		/* ioctl */
-	NULL,		/* mmap */
-	irlpt_open,     /* open */
-	NULL,           /* flush */
-	irlpt_close,    /* release */
-	NULL,           /* fsync */
-	NULL,           /* fasync */
-	NULL,           /* check_media_change */
-	NULL,           /* revalidate */
-        NULL,           /* lock */
-};
-
-#ifdef CONFIG_PROC_FS
-
-/*
- * Function irlpt_server_proc_read (buf, start, offset, len, unused)
- *
- *
- *
- */
-static int irlpt_server_proc_read(char *buf, char **start, off_t offset, 
-				  int len, int unused)
-{
-	int index;
-
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-
-	if (irlpt_server != NULL) {
-	        len = sprintf(buf, "%s\n\n", version);
-		len += sprintf(buf+len, "ifname: %s\n", irlpt_server->ifname);
-		len += sprintf(buf+len, "minor: %d\n", irlpt_server->ir_dev.minor);
-
-		switch (irlpt_server->servicetype) {
-		case IRLPT_UNKNOWN:
-			index = 0;
-			break;
-		case IRLPT_THREE_WIRE_RAW:
-			index = 1;
-			break;
-		case IRLPT_THREE_WIRE:
-			index = 2;
-			break;
-		case IRLPT_NINE_WIRE:
-			index = 3;
-			break;
-		case IRLPT_CENTRONICS:
-			index = 4;
-			break;
-		case IRLPT_SERVER_MODE:
-			index = 5;
-			break;
-		default:
-			index = 0;
-			break;
-		}
-
-		len += sprintf(buf+len, "servicetype: %s, porttype: %s\n",
-			       irlpt_service_type[index],
-			       irlpt_port_type[irlpt_server->porttype]);
-		len += sprintf(buf+len, "saddr: 0x%08x, daddr: 0x%08x\n", 
-			       irlpt_server->saddr, irlpt_server->daddr);
-		len += sprintf(buf+len, "slsap: 0x%08x, dlsap: 0x%08x\n", 
-			       irlpt_server->slsap_sel, 
-			       irlpt_server->dlsap_sel);
-		len += sprintf(buf+len, "retries: %d, count: %d\n", 
-			       irlpt_server->open_retries,
-			       irlpt_server->count);
-		len += sprintf(buf+len, "fsm state: %s, rx queue depth: %d\n", 
-			       irlpt_server_fsm_state[irlpt_server->state],
-			       skb_queue_len(&irlpt_server->rx_queue));
-		len += sprintf(buf+len, "\n");
-	}
-
-	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
-
-	return len;
-}
-
-extern struct proc_dir_entry *proc_irda;
-#endif /* CONFIG_PROC_FS */
-
-/*
- * Function irlpt_init (dev)
- *
- *   Initializes the irlpt control structure
- *
- */
-
-__initfunc(int irlpt_server_init(void))
-{
-	struct irmanager_event mgr_event;
-	__u16 hints;
-
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-
-	printk( KERN_INFO "%s\n", version);
-
-	irlpt_server = (struct irlpt_cb *) kmalloc (sizeof(struct irlpt_cb), 
-						    GFP_KERNEL);
-
-	if ( irlpt_server == NULL) {
-		printk( KERN_WARNING "IrLPT server: Can't allocate" 
-			" irlpt_server control block!\n");
-		return -ENOMEM;
-	}
-	memset( irlpt_server, 0, sizeof(struct irlpt_cb));
-
-	sprintf(irlpt_server->ifname, "irlpt_server");
-	irlpt_server->ir_dev.minor = MISC_DYNAMIC_MINOR;
-	irlpt_server->ir_dev.name = irlpt_server->ifname;
-	irlpt_server->ir_dev.fops = &irlpt_fops;
-	misc_register(&irlpt_server->ir_dev);
-	irlpt_server->magic = IRLPT_MAGIC;
-	irlpt_server->in_use = TRUE;
-	irlpt_server->servicetype = IRLPT_THREE_WIRE_RAW;
-	irlpt_server->porttype = IRLPT_SERIAL;
-
-	skb_queue_head_init(&irlpt_server->rx_queue);
-
-	hints = irlmp_service_to_hint(S_PRINTER);
-	skey = irlmp_register_service(hints);
-	
-	register_irlpt_server();
-
-#ifdef CONFIG_PROC_FS
-	create_proc_entry("irlpt_server", 0, proc_irda)->get_info
-		= 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;
-}
-
-/*
- * Function irlpt_cleanup (void)
- *
- *
- *
- */
-static void irlpt_server_cleanup(void)
-{
-	struct irmanager_event mgr_event;
-	struct sk_buff *skb;
-
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-
-	irlmp_unregister_service(skey);
-	deregister_irlpt_server();
-
-	while (( skb = skb_dequeue(&irlpt_server->rx_queue)) != NULL) {
-		DEBUG(irlpt_server_debug, __FUNCTION__ ": freeing SKB\n");
-                dev_kfree_skb( skb);
-	}
-
-	misc_deregister(&irlpt_server->ir_dev);
-
-	kfree(irlpt_server);
-
-#ifdef CONFIG_PROC_FS
-	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");
-}
-
-/*
- * Function irlpt_disconnect_indication (handle)
- *
- */
-static void irlpt_server_disconnect_indication( void *instance, 
-						void *sap, 
-						LM_REASON reason,
-						struct sk_buff *userdata)
-{
-#if 0
-	struct irlpt_info info;
-#endif
-	struct irlpt_cb *self;
-
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-
-	self = ( struct irlpt_cb *) instance;
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-#if 0
-	info.daddr = self->daddr;
-#endif
-
-	DEBUG( irlpt_server_debug, 
-	       __FUNCTION__ ": reason=%d (%s), dlsap_sel=%d\n",
-	       reason, irlpt_reasons[reason], self->dlsap_sel);
-
-	self->connected = IRLPT_DISCONNECTED;
-	self->eof = reason;
-
-        wake_up_interruptible(&self->read_wait);
-	wake_up_interruptible(&self->write_wait);
-	wake_up_interruptible(&self->ex_wait);
-
-	DEBUG( irlpt_server_debug, __FUNCTION__ ": rx queue length: %d\n",
-	       skb_queue_len(&irlpt_server->rx_queue));
-
-	irlpt_server_do_event( self, LMP_DISCONNECT, NULL, NULL);
-
-	deregister_irlpt_server();
-	register_irlpt_server();
-
-	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function irlpt_connect_confirm (handle, qos, skb)
- *
- *    LSAP connection confirmed!
- */
-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)
-{
-	struct irlpt_cb *self;
-
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-	self = ( struct irlpt_cb *) instance;
-
-	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);
-
-	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function irlpt_connect_indication (handle)
- *
- */
-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)
-{
-	struct irlpt_cb *self;
-	struct irlpt_info info;
-
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-
-	self = ( struct irlpt_cb *) instance;
-
-	info.lsap  = (struct lsap_cb *) sap;
-	
-	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)
-		dev_kfree_skb( skb);
-
-	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function irlpt_server_data_indication (handle, skb)
- *
- *    This function gets the data that is received on the data channel
- *
- */
-static int irlpt_server_data_indication(void *instance, void *sap, 
-					struct sk_buff *skb) 
-{
-	struct irlpt_cb *self;
-
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-
-	self = ( struct irlpt_cb *) instance;
-	     
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	ASSERT( skb != NULL, return -1;);
-
-	DEBUG( irlpt_server_debug, __FUNCTION__ ": len=%d\n", (int) skb->len);
-
-#if 0
-	dump_buffer(skb);
-#endif
-	
-	skb_queue_tail(&self->rx_queue, skb);
-        wake_up_interruptible(&self->read_wait);
-
-	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
-	
-	return 0;
-}
-
-/*
- * Function register_irlpt_server(void)
- *
- *    Register server support so we can accept incoming connections. We
- *    must register both a TSAP for control and data
- * 
- */
-static void register_irlpt_server(void)
-{
-	struct notify_t notify;
-	struct ias_object *obj;
-	
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-
-	/*
-	 *  First register control TSAP
-	 */
-	if ( !irlpt_server || irlpt_server->magic != IRLPT_MAGIC) {
-		DEBUG( 0, __FUNCTION__ ": unable to obtain handle!\n");
-		return;
-	}
-
-	irda_notify_init(&notify);
-
-	notify.connect_confirm = irlpt_server_connect_confirm;
-	notify.connect_indication = irlpt_server_connect_indication;
-	notify.disconnect_indication = irlpt_server_disconnect_indication;
-	notify.data_indication = irlpt_server_data_indication;
-	notify.instance = irlpt_server;
-	strcpy(notify.name, "IrLPT server");
-
-	irlpt_server->lsap = irlmp_open_lsap( irlpt_server_lsap, &notify);
-
-	irlpt_server->connected = IRLPT_WAITING;
-	irlpt_server->service_LSAP = irlpt_server_lsap;
-	irlpt_server->slsap_sel = irlpt_server_lsap;
-
-	/* 
-	 *  Register with LM-IAS
-	 */
-
-	obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
-	irias_add_integer_attrib(obj, "IrDA:IrLMP:LsapSel", irlpt_server_lsap);
-	irias_insert_object(obj);
-
-	DEBUG( irlpt_server_debug, __FUNCTION__ 
-	       ": Source LSAP sel=%d\n", irlpt_server->slsap_sel);
-	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function register_irlpt_server(void)
- *
- *    Register server support so we can accept incoming connections. We
- *    must register both a TSAP for control and data
- * 
- */
-static void deregister_irlpt_server(void)
-{
-	DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
-
-	irlpt_server->connected = IRLPT_DISCONNECTED;
-
-	/* 
-	 *  de-Register with LM-IAS
-	 */
-	irias_delete_object( "IrLPT");
-
-	DEBUG( irlpt_server_debug, 
-	       __FUNCTION__ ": Source LSAP sel=%d\n", irlpt_server->slsap_sel);
-	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Thomas Davis <ratbert@radiks.net>");
-MODULE_DESCRIPTION("The Linux IrDA/IrLPT server protocol");
-MODULE_PARM(irlpt_server_debug,"1i");
-MODULE_PARM(irlpt_server_fsm_debug, "1i");
-
-/*
- * Function init_module (void)
- *
- *    Initialize the IrLPT server module, this function is called by the
- *    modprobe(1) program.
- */
-int init_module(void)
-{
-	int ret;
-
-        DEBUG( irlpt_server_debug, "--> IrLPT server: init_module\n");
-
-        ret = irlpt_server_init();
-
-        DEBUG( irlpt_server_debug, "IrLPT server: init_module -->\n");
-
-        return ret;
-}
-
-/*
- * Function cleanup_module (void)
- *
- *    Remove the IrLPT server module, this function is called by the rmmod(1)
- *    program
- */
-void cleanup_module(void)
-{
-        DEBUG( irlpt_server_debug, "--> IrLPT server: cleanup_module\n");
-
-        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-
-        /* Free some memory */
-        irlpt_server_cleanup();
-
-        DEBUG( irlpt_server_debug, "IrLPT server: cleanup_module -->\n");
-}
-
-#endif /* MODULE */
diff -urN linux-2.2.15-pre2/net/irda/irlpt/irlpt_srvr_fsm.c linux/net/irda/irlpt/irlpt_srvr_fsm.c
--- linux-2.2.15-pre2/net/irda/irlpt/irlpt_srvr_fsm.c	Sun Mar  7 15:26:44 1999
+++ linux/net/irda/irlpt/irlpt_srvr_fsm.c	Wed Dec 31 16:00:00 1969
@@ -1,187 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irlpt_srvr_fsm.c
- * Version:       0.1
- * Sources:       irlan_event.c
- * 
- *     Copyright (c) 1997, Dag Brattli <dagb@cs.uit.no>, 
- *		All Rights Reserved.
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.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, provide no warranty for any of this software. This 
- *     material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <net/irda/iriap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irlpt_common.h>
-#include <net/irda/irlpt_server.h>
-#include <net/irda/irlpt_server_fsm.h>
-#include <net/irda/irda.h>
-
-static int irlpt_server_state_idle  ( struct irlpt_cb *self, 
-				      IRLPT_EVENT event,
-				      struct sk_buff *skb, 
-				      struct irlpt_info *info);
-static int irlpt_server_state_conn  ( struct irlpt_cb *self, 
-				      IRLPT_EVENT event, 
-				      struct sk_buff *skb, 
-				      struct irlpt_info *info);
-
-#if 0
-static char *rcsid = "$Id: irlpt_server_fsm.c,v 1.4 1998/10/05 05:46:45 ratbert Exp $";
-#endif
-
-int irlpt_server_fsm_debug = 4; /* don't change this! */
-
-static int (*irlpt_server_state[])( struct irlpt_cb *self, 
-				    IRLPT_EVENT event, 
-				    struct sk_buff *skb,
-				    struct irlpt_info *info) = 
-{ 
-	irlpt_server_state_idle,
-	irlpt_server_state_conn,
-};
-
-void irlpt_server_do_event( struct irlpt_cb *self, 
-			    IRLPT_EVENT event, 
-			    struct sk_buff *skb, 
-			    struct irlpt_info *info) 
-{
-	DEBUG( irlpt_server_fsm_debug, 
-	       __FUNCTION__ ": STATE = %s, EVENT = %s\n", 
-	       irlpt_server_fsm_state[self->state], irlpt_fsm_event[event]);
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	(*irlpt_server_state[ self->state]) ( self, event, skb, info);
-
-	DEBUG( irlpt_server_fsm_debug, __FUNCTION__ " -->\n");
-}
-
-void irlpt_server_next_state( struct irlpt_cb *self, 
-			      IRLPT_CLIENT_STATE state) 
-{
-
-	DEBUG( irlpt_server_fsm_debug, __FUNCTION__ ": NEXT STATE = %s\n", 
-	       irlpt_server_fsm_state[state]);
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRLPT_MAGIC, return;);
-
-	self->state = state;
-
-	DEBUG( irlpt_server_fsm_debug, __FUNCTION__ " -->\n");
-}
-
-/*
- * Function server_state_idle (event, skb, info)
- *
- *    IDLE, We are waiting for an indication that there is a provider
- *    available.
- */
-static int irlpt_server_state_idle( struct irlpt_cb *self, 
-				    IRLPT_EVENT event, 
-				    struct sk_buff *skb, 
-				    struct irlpt_info *info) 
-{
-	struct sk_buff *r_skb;
-
-	DEBUG( irlpt_server_fsm_debug, "--> " __FUNCTION__ ":\n");
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	switch( event) {
-	case LMP_CONNECT:
-		DEBUG( irlpt_server_fsm_debug, __FUNCTION__ 
-		       ": LM_CONNECT, remote lsap: 0x%08x\n",
-		       info->lsap->dlsap_sel);
-
-		self->dlsap_sel = info->lsap->dlsap_sel;
-		self->daddr = info->daddr;
-		self->saddr = info->saddr;
-
-		r_skb = dev_alloc_skb(64);
-		if (r_skb == NULL) { 
-			printk( KERN_INFO __FUNCTION__ 
-				": can't allocate sk_buff of length 64\n");
-			return 0;
-		}
-		skb_reserve( r_skb, LMP_MAX_HEADER);
-		irlmp_connect_response( self->lsap, r_skb);
-		irlpt_server_next_state( self, IRLPT_SERVER_CONN);
-		break;
-
-	default:
-		DEBUG( irlpt_server_fsm_debug, __FUNCTION__ 
-		       ": Unknown event %d (%s)\n", 
-		       event, irlpt_fsm_event[event]);
-		break;
-	}
-
-	if (skb) {
-		dev_kfree_skb( skb);
-	}
-
-	DEBUG( irlpt_server_fsm_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-/*
- * Function server_state_conn (event, skb, info)
- *
- *    CONN, We have connected to a provider but has not issued any
- *    commands yet.
- *
- */
-static int irlpt_server_state_conn( struct irlpt_cb *self, 
-				    IRLPT_EVENT event, 
-				    struct sk_buff *skb, 
-				    struct irlpt_info *info) 
-{
-	DEBUG( irlpt_server_fsm_debug, "--> " __FUNCTION__ ":\n");
-
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == IRLPT_MAGIC, return -1;);
-
-	switch( event) {
-	case LMP_DISCONNECT:
-	case LAP_DISCONNECT:
-		DEBUG( irlpt_server_fsm_debug, __FUNCTION__ 
-		       ": LMP_DISCONNECT/LAP_DISCONNECT\n");
-		irlpt_server_next_state( self, IRLPT_SERVER_IDLE);
-		break;
-
-	default:
-		DEBUG( irlpt_server_fsm_debug, __FUNCTION__ 
-		       ": Unknown event %d (%s)\n", 
-		       event, irlpt_fsm_event[event]);
-		break;
-	}
-
-	if ( skb) {
-		dev_kfree_skb( skb);
-	}
-
-	DEBUG( irlpt_server_fsm_debug, __FUNCTION__ " -->\n");
-
-	return 0;
-}
-
-#if 0
-static void irlpt_server_print_event( IRLPT_EVENT event) 
-{
-	DEBUG( 0, "IRLPT_EVENT = %s\n", irlpt_fsm_event[event]);
-}
-#endif
diff -urN linux-2.2.15-pre2/net/irda/irmod.c linux/net/irda/irmod.c
--- linux-2.2.15-pre2/net/irda/irmod.c	Tue Jan  4 10:12:27 2000
+++ linux/net/irda/irmod.c	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:55:39 1997
- * Modified at:   Fri May 14 13:46:02 1999
+ * Modified at:   Mon Jan 17 11:21:56 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 1999-2000 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 
@@ -27,10 +27,10 @@
 
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <asm/segment.h>
-
 #include <linux/proc_fs.h>
 
+#include <asm/segment.h>
+
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irlap.h>
@@ -44,6 +44,7 @@
 #include <net/irda/irda_device.h>
 #include <net/irda/wrapper.h>
 #include <net/irda/timer.h>
+#include <net/irda/parameters.h>
 
 extern struct proc_dir_entry *proc_irda;
 
@@ -66,7 +67,7 @@
 extern int irlan_client_init(void);
 extern int irlan_server_init(void);
 extern int ircomm_init(void);
-extern int irvtd_init(void);
+extern int ircomm_tty_init(void);
 extern int irlpt_client_init(void);
 extern int irlpt_server_init(void);
 
@@ -122,8 +123,15 @@
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(proc_irda);
 #endif
+EXPORT_SYMBOL(irda_param_insert);
+EXPORT_SYMBOL(irda_param_extract);
+EXPORT_SYMBOL(irda_param_extract_all);
+EXPORT_SYMBOL(irda_param_pack);
+EXPORT_SYMBOL(irda_param_unpack);
 
 /* IrIAP/IrIAS */
+EXPORT_SYMBOL(iriap_open);
+EXPORT_SYMBOL(iriap_close);
 EXPORT_SYMBOL(iriap_getvaluebyclass_request);
 EXPORT_SYMBOL(irias_object_change_attribute);
 EXPORT_SYMBOL(irias_add_integer_attrib);
@@ -132,6 +140,7 @@
 EXPORT_SYMBOL(irias_insert_object);
 EXPORT_SYMBOL(irias_new_object);
 EXPORT_SYMBOL(irias_delete_object);
+EXPORT_SYMBOL(irias_delete_value);
 EXPORT_SYMBOL(irias_find_object);
 EXPORT_SYMBOL(irias_find_attrib);
 EXPORT_SYMBOL(irias_new_integer_value);
@@ -167,42 +176,50 @@
 EXPORT_SYMBOL(hashbin_get_first);
 
 /* IrLAP */
+EXPORT_SYMBOL(irlap_open);
+EXPORT_SYMBOL(irlap_close);
 #ifdef CONFIG_IRDA_COMPRESSION
 EXPORT_SYMBOL(irda_unregister_compressor);
 EXPORT_SYMBOL(irda_register_compressor);
 #endif /* CONFIG_IRDA_COMPRESSION */
 EXPORT_SYMBOL(irda_init_max_qos_capabilies);
 EXPORT_SYMBOL(irda_qos_bits_to_value);
-EXPORT_SYMBOL(irda_device_open);
-EXPORT_SYMBOL(irda_device_close);
 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_dongle_init);
+EXPORT_SYMBOL(irda_device_dongle_cleanup);
 EXPORT_SYMBOL(irda_device_register_dongle);
 EXPORT_SYMBOL(irda_device_unregister_dongle);
+EXPORT_SYMBOL(irda_task_execute);
+EXPORT_SYMBOL(irda_task_kick);
+EXPORT_SYMBOL(irda_task_next_state);
+EXPORT_SYMBOL(irda_task_delete);
 
 EXPORT_SYMBOL(async_wrap_skb);
 EXPORT_SYMBOL(async_unwrap_char);
 EXPORT_SYMBOL(irda_start_timer);
-/* EXPORT_SYMBOL(irda_get_mtt); */
 EXPORT_SYMBOL(setup_dma);
+EXPORT_SYMBOL(infrared_mode);
 
 #ifdef CONFIG_IRTTY
 EXPORT_SYMBOL(irtty_set_dtr_rts);
 EXPORT_SYMBOL(irtty_register_dongle);
 EXPORT_SYMBOL(irtty_unregister_dongle);
+EXPORT_SYMBOL(irtty_set_packet_mode);
 #endif
 
-__initfunc(int irda_init(void))
+int __init irda_init(void)
 {
-        printk(KERN_INFO "IrDA (tm) Protocols for Linux-2.2 (Dag Brattli)\n");
-
+	MESSAGE("IrDA (tm) Protocols for Linux-2.2 (Dag Brattli)\n");
+	
  	irlmp_init();
 	irlap_init();
-	irda_device_init();
-
+	
+#ifdef MODULE
+	irda_device_init();	/* Called by init/main.c when non-modular */
+#endif
 	iriap_init();
  	irttp_init();
 	
@@ -212,12 +229,11 @@
 #ifdef CONFIG_SYSCTL
 	irda_sysctl_register();
 #endif
-
 	irda.dev.minor = MISC_DYNAMIC_MINOR;
 	irda.dev.name = "irda";
 	irda.dev.fops = &irda_fops;
 	
-	misc_register( &irda.dev);
+	misc_register(&irda.dev);
 
 	irda.in_use = FALSE;
 
@@ -229,15 +245,7 @@
 #endif
 #ifdef CONFIG_IRCOMM
 	ircomm_init();
-	irvtd_init();
-#endif
-
-#ifdef CONFIG_IRLPT_CLIENT
-	irlpt_client_init();
-#endif
-
-#ifdef CONFIG_IRLPT_SERVER
-	irlpt_server_init();
+	ircomm_tty_init();
 #endif
 
 #ifdef CONFIG_IRDA_COMPRESSION
@@ -252,7 +260,7 @@
 #ifdef MODULE
 void irda_cleanup(void)
 {
-	misc_deregister( &irda.dev);
+	misc_deregister(&irda.dev);
 
 #ifdef CONFIG_SYSCTL
 	irda_sysctl_unregister();
@@ -261,7 +269,6 @@
 #ifdef CONFIG_PROC_FS
 	irda_proc_unregister();
 #endif
-
 	/* Remove higher layers */
 	irttp_cleanup();
 	iriap_cleanup();
@@ -296,7 +303,7 @@
  *    Used for initializing the notify structure
  *
  */
-void irda_notify_init( struct notify_t *notify)
+void irda_notify_init(notify_t *notify)
 {
 	notify->data_indication = NULL;
 	notify->udata_indication = NULL;
@@ -305,7 +312,7 @@
 	notify->disconnect_indication = NULL;
 	notify->flow_indication = NULL;
 	notify->instance = NULL;
-	strncpy( notify->name, "Unknown", NOTIFY_MAX_NAME);
+	strncpy(notify->name, "Unknown", NOTIFY_MAX_NAME);
 }
 
 /*
@@ -322,10 +329,8 @@
 	struct irmanager_event event;
 
 	/* Make sure irmanager is running */
-	if ( !irda.in_use) {
-		printk( KERN_ERR "irmanager is not running!\n");
+	if (!irda.in_use)
 		return;
-	}
 
 	/* Make new todo event */
 	new = (struct irda_todo *) kmalloc( sizeof(struct irda_todo),
@@ -340,12 +345,12 @@
 	new->param = param;
 	
 	/* Queue todo */
-	enqueue_last( &irda.todo_queue, (QUEUE *) new);
+	enqueue_last(&irda.todo_queue, (queue_t *) new);
 
 	event.event = EVENT_NEED_PROCESS_CONTEXT;
 
 	/* Notify the user space manager */
-	irmanager_notify( &event);
+	irmanager_notify(&event);
 }
 
 /*
@@ -358,13 +363,11 @@
 {
 	struct irda_event *new;
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
-
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	
 	/* Make sure irmanager is running */
-	if ( !irda.in_use) {
-		printk( KERN_ERR "irmanager is not running!\n");
+	if (!irda.in_use)
 		return;
-	}
 
 	/* Make new IrDA Event */
 	new = (struct irda_event *) kmalloc( sizeof(struct irda_event),
@@ -372,28 +375,29 @@
 	if ( new == NULL) {
 		return;	
 	}
-	memset( new, 0, sizeof( struct irda_event));
+	memset(new, 0, sizeof( struct irda_event));
 	new->event = *event;
 	
 	/* Queue event */
-	enqueue_last( &irda.event_queue, (QUEUE *) new);
+	enqueue_last(&irda.event_queue, (queue_t *) new);
 	
 	/* Wake up irmanager sleeping on read */
-	wake_up_interruptible( &irda.wait_queue);
+	wake_up_interruptible(&irda.wait_queue);
 }
 
 static int irda_open( struct inode * inode, struct file *file)
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
-	if ( irda.in_use) {
-		DEBUG( 0, __FUNCTION__ "(), irmanager is already running!\n");
+	if (irda.in_use) {
+		IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), irmanager is already running!\n");
 		return -1;
 	}
 	irda.in_use = TRUE;
 		
 	MOD_INC_USE_COUNT;
-
+	
 	return 0;
 }
 
@@ -403,62 +407,62 @@
  *    Ioctl, used by irmanager to ...
  *
  */
-static int irda_ioctl( struct inode *inode, struct file *filp, 
-		       unsigned int cmd, unsigned long arg)
+static int irda_ioctl(struct inode *inode, struct file *filp, 
+		      unsigned int cmd, unsigned long arg)
 {
 	struct irda_todo *todo;
 	int err = 0;
 	int size = _IOC_SIZE(cmd);
-
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	if ( _IOC_DIR(cmd) & _IOC_READ)
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	
+	if (_IOC_DIR(cmd) & _IOC_READ)
 		err = verify_area( VERIFY_WRITE, (void *) arg, size);
-	else if ( _IOC_DIR(cmd) & _IOC_WRITE)
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
 		err = verify_area( VERIFY_READ, (void *) arg, size);
-	if ( err)
+	if (err)
 		return err;
 	
-	switch( cmd) {
+	switch (cmd) {
 	case IRMGR_IOCTNPC:
 		/* Got process context! */
-		DEBUG( 4, __FUNCTION__ "(), got process context!\n");
-
-		while (( todo = (struct irda_todo *) dequeue_first( 
+		IRDA_DEBUG(4, __FUNCTION__ "(), got process context!\n");
+		
+		while ((todo = (struct irda_todo *) dequeue_first( 
 			&irda.todo_queue)) != NULL)
 		{
-			todo->callback( todo->self, todo->param);
+			todo->callback(todo->self, todo->param);
 
-			kfree( todo);
+			kfree(todo);
 		}
 		break;
 
 	default:
 		return -ENOIOCTLCMD;
 	}
-
+	
 	return 0;
 }
 
-static int irda_close( struct inode *inode, struct file *file)
+static int irda_close(struct inode *inode, struct file *file)
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	MOD_DEC_USE_COUNT;
-
+	
 	irda.in_use = FALSE;
 
 	return 0;
 }
 
-static ssize_t irda_read( struct file *file, char *buffer, size_t count, 
-			  loff_t *noidea)
+static ssize_t irda_read(struct file *file, char *buffer, size_t count, 
+			 loff_t *noidea)
 {
 	struct irda_event *event;
 	unsigned long flags;
 	int len;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	/* * Go to sleep and wait for event if there is no event to be read! */
 	save_flags( flags);
@@ -471,31 +475,33 @@
 	 *  Ensure proper reaction to signals, and screen out 
 	 *  blocked signals (page 112. linux device drivers)
 	 */
-	if ( signal_pending( current))
+	if (signal_pending( current))
 		return -ERESTARTSYS;
 
 	event = (struct irda_event *) dequeue_first( &irda.event_queue);
+	if (!event)
+		return 0;
 
 	len = sizeof(struct irmanager_event);
-	copy_to_user( buffer, &event->event, len);
+	copy_to_user(buffer, &event->event, len);
 
 	/* Finished with event */
-	kfree( event);
+	kfree(event);
 
 	return len;
 }
 
-static ssize_t irda_write( struct file *file, const char *buffer,
-			   size_t count, loff_t *noidea)
+static ssize_t irda_write(struct file *file, const char *buffer,
+			  size_t count, loff_t *noidea)
 {
-	DEBUG( 0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 	
 	return 0;
 }
 
-static u_int irda_poll( struct file *file, poll_table *wait)
+static u_int irda_poll(struct file *file, poll_table *wait)
 {
-	DEBUG( 0, __FUNCTION__ "(), Sorry not implemented yet!\n");
+	IRDA_DEBUG(0, __FUNCTION__ "(), Sorry not implemented yet!\n");
 
 	return 0;
 }
diff -urN linux-2.2.15-pre2/net/irda/irproc.c linux/net/irda/irproc.c
--- linux-2.2.15-pre2/net/irda/irproc.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irproc.c	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Thomas Davis, <ratbert@radiks.net>
  * Created at:    Sat Feb 21 21:33:24 1998
- * Modified at:   Fri May  7 08:06:49 1999
+ * Modified at:   Wed Jan  5 22:45:14 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-1999, Thomas Davis, <ratbert@radiks.net>, 
+ *
+ *     Copyright (c) 1998-2000, Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>, 
  *     All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
@@ -22,6 +23,9 @@
  *     
  ********************************************************************/
 
+#define __NO_VERSION__    /* irmod.c defines module_kernel_version */
+#include <linux/module.h>
+
 #include <linux/miscdevice.h>
 #include <linux/proc_fs.h>
 
@@ -30,8 +34,6 @@
 #include <net/irda/irlap.h>
 #include <net/irda/irlmp.h>
 
-extern int irda_device_proc_read(char *buf, char **start, off_t offset, 
-				 int len, int unused);
 extern int irlap_proc_read(char *buf, char **start, off_t offset, int len, 
 			   int unused);
 extern int irlmp_proc_read(char *buf, char **start, off_t offset, int len, 
@@ -42,18 +44,6 @@
 			   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 */
-/* }; */
 
 struct irda_entry {
 	char *name;
@@ -64,7 +54,6 @@
  
 static struct irda_entry dir[] = {
 	{"discovery",	discovery_proc_read},
-	{"irda_device",	irda_device_proc_read},
 	{"irttp",	irttp_proc_read},
 	{"irlmp",	irlmp_proc_read},
 	{"irlap",	irlap_proc_read},
diff -urN linux-2.2.15-pre2/net/irda/irqueue.c linux/net/irda/irqueue.c
--- linux-2.2.15-pre2/net/irda/irqueue.c	Thu Apr 15 05:42:42 1999
+++ linux/net/irda/irqueue.c	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Jun  9 13:29:31 1998
- * Modified at:   Thu Mar 11 13:27:04 1999
+ * Modified at:   Sun Dec 12 13:48:22 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (C) 1998, Aage Kvalnes <aage@cs.uit.no>
+ *     Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no>
  *     Copyright (C) 1998, Dag Brattli, 
  *     All Rights Reserved.
  *
@@ -36,7 +36,7 @@
 #include <net/irda/irqueue.h>
 #include <net/irda/irmod.h>
 
-static QUEUE *dequeue_general( QUEUE **queue, QUEUE* element);
+static queue_t *dequeue_general( queue_t **queue, queue_t* element);
 static __u32 hash( char* name);
 
 /*
@@ -50,8 +50,6 @@
 	hashbin_t* hashbin;
 	int i;
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
-	
 	/*
 	 * Allocate new hashbin
 	 */
@@ -81,22 +79,22 @@
  */
 int hashbin_clear( hashbin_t* hashbin, FREE_FUNC free_func)
 {
-	QUEUE* queue;
+	queue_t* queue;
 	int i;
 	
-	ASSERT( hashbin != NULL, return -1;);
-	ASSERT( hashbin->magic == HB_MAGIC, return -1;);
+	ASSERT(hashbin != NULL, return -1;);
+	ASSERT(hashbin->magic == HB_MAGIC, return -1;);
 
 	/*
 	 * Free the entries in the hashbin
 	 */
-	for ( i = 0; i < HASHBIN_SIZE; i ++ ) {
-		queue = dequeue_first( (QUEUE**) &hashbin->hb_queue[ i]);
-		while( queue ) {
-			if ( free_func)
-				(*free_func)( queue );
+	for (i = 0; i < HASHBIN_SIZE; i ++ ) {
+		queue = dequeue_first( (queue_t**) &hashbin->hb_queue[i]);
+		while (queue) {
+			if (free_func)
+				(*free_func)(queue);
 			queue = dequeue_first( 
-				(QUEUE**) &hashbin->hb_queue[ i]);
+				(queue_t**) &hashbin->hb_queue[i]);
 		}
 	}
 	hashbin->hb_size = 0;
@@ -114,22 +112,23 @@
  */
 int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
 {
+	queue_t* queue;
 	int i;
-	QUEUE* queue;
 
-	DEBUG( 4, "hashbin_destroy()\n");
+	ASSERT(hashbin != NULL, return -1;);
+	ASSERT(hashbin->magic == HB_MAGIC, return -1;);
 	
 	/*
 	 *  Free the entries in the hashbin, TODO: use hashbin_clear when
 	 *  it has been shown to work
 	 */
-	for ( i = 0; i < HASHBIN_SIZE; i ++ ) {
-		queue = dequeue_first( (QUEUE**) &hashbin->hb_queue[ i ] );
-		while( queue ) {
-			if ( free_func)
-				(*free_func)( queue );
+	for (i = 0; i < HASHBIN_SIZE; i ++ ) {
+		queue = dequeue_first((queue_t**) &hashbin->hb_queue[i]);
+		while (queue ) {
+			if (free_func)
+				(*free_func)(queue);
 			queue = dequeue_first( 
-				(QUEUE**) &hashbin->hb_queue[ i ]);
+				(queue_t**) &hashbin->hb_queue[i]);
 		}
 	}
 	
@@ -137,7 +136,7 @@
 	 *  Free the hashbin structure
 	 */
 	hashbin->magic = ~HB_MAGIC;
-	kfree( hashbin );
+	kfree(hashbin);
 
 	return 0;
 }
@@ -148,28 +147,28 @@
  *    Lock the hashbin
  *
  */
-void hashbin_lock( hashbin_t* hashbin, __u32 hashv, char* name, 
-		   unsigned long flags)
+void hashbin_lock(hashbin_t* hashbin, __u32 hashv, char* name, 
+		  unsigned long flags)
 {
 	int bin;
 	
-	DEBUG( 0, "hashbin_lock\n");
+	IRDA_DEBUG(0, "hashbin_lock\n");
 
-	ASSERT( hashbin != NULL, return;);
-	ASSERT( hashbin->magic == HB_MAGIC, return;);
+	ASSERT(hashbin != NULL, return;);
+	ASSERT(hashbin->magic == HB_MAGIC, return;);
 
 	/*
 	 * Locate hashbin
 	 */
-	if ( name )
-		hashv = hash( name );
-	bin = GET_HASHBIN( hashv);
+	if (name)
+		hashv = hash(name);
+	bin = GET_HASHBIN(hashv);
 	
 	/* Synchronize */
 	if ( hashbin->hb_type & HB_GLOBAL )
-		spin_lock_irqsave( &hashbin->hb_mutex[ bin], flags);
+		spin_lock_irqsave(&hashbin->hb_mutex[ bin], flags);
 	else {
-		save_flags( flags);
+		save_flags(flags);
 		cli();
 	}
 }
@@ -185,7 +184,7 @@
 {
 	int bin;
 
-	DEBUG(0, "hashbin_unlock()\n");
+	IRDA_DEBUG(0, "hashbin_unlock()\n");
 
 	ASSERT(hashbin != NULL, return;);
 	ASSERT(hashbin->magic == HB_MAGIC, return;);
@@ -211,12 +210,12 @@
  *    Insert an entry into the hashbin
  *
  */
-void hashbin_insert( hashbin_t* hashbin, QUEUE* entry, __u32 hashv, char* name)
+void hashbin_insert(hashbin_t* hashbin, queue_t* entry, __u32 hashv, char* name)
 {
 	unsigned long flags = 0;
 	int bin;
 
-	DEBUG( 4, __FUNCTION__"()\n");
+	IRDA_DEBUG( 4, __FUNCTION__"()\n");
 
 	ASSERT( hashbin != NULL, return;);
 	ASSERT( hashbin->magic == HB_MAGIC, return;);
@@ -251,7 +250,7 @@
 	 */
 	if ( hashbin->hb_type & HB_SORTED) {
 	} else {
-		enqueue_first( (QUEUE**) &hashbin->hb_queue[ bin ],
+		enqueue_first( (queue_t**) &hashbin->hb_queue[ bin ],
 			       entry);
 	}
 	hashbin->hb_size++;
@@ -276,9 +275,9 @@
 {
 	int bin, found = FALSE;
 	unsigned long flags = 0;
-	QUEUE* entry;
+	queue_t* entry;
 
-	DEBUG( 4, "hashbin_find()\n");
+	IRDA_DEBUG( 4, "hashbin_find()\n");
 
 	ASSERT( hashbin != NULL, return NULL;);
 	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
@@ -343,7 +342,7 @@
 void *hashbin_remove_first( hashbin_t *hashbin)
 {
 	unsigned long flags;
-	QUEUE *entry = NULL;
+	queue_t *entry = NULL;
 
 	save_flags(flags);
 	cli();
@@ -368,9 +367,9 @@
 {
 	int bin, found = FALSE;
 	unsigned long flags = 0;
-	QUEUE* entry;
+	queue_t* entry;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
 	ASSERT( hashbin != NULL, return NULL;);
 	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
@@ -422,8 +421,8 @@
 	 * If entry was found, dequeue it
 	 */
 	if ( found ) {
-		dequeue_general( (QUEUE**) &hashbin->hb_queue[ bin ],
-				 (QUEUE*) entry );
+		dequeue_general( (queue_t**) &hashbin->hb_queue[ bin ],
+				 (queue_t*) entry );
 		hashbin->hb_size--;
 
 		/*
@@ -458,9 +457,9 @@
  *    called before any calls to hashbin_get_next()!
  *
  */
-QUEUE *hashbin_get_first( hashbin_t* hashbin) 
+queue_t *hashbin_get_first( hashbin_t* hashbin) 
 {
-	QUEUE *entry;
+	queue_t *entry;
 	int i;
 
 	ASSERT( hashbin != NULL, return NULL;);
@@ -490,9 +489,9 @@
  *    NULL when all items have been traversed
  * 
  */
-QUEUE *hashbin_get_next( hashbin_t *hashbin)
+queue_t *hashbin_get_next( hashbin_t *hashbin)
 {
-	QUEUE* entry;
+	queue_t* entry;
 	int bin;
 	int i;
 
@@ -543,9 +542,9 @@
  *    Insert item into end of queue.
  *
  */
-static void __enqueue_last( QUEUE **queue, QUEUE* element)
+static void __enqueue_last( queue_t **queue, queue_t* element)
 {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
 	/*
 	 * Check if queue is empty.
@@ -567,7 +566,7 @@
 	}	
 }
 
-inline void enqueue_last( QUEUE **queue, QUEUE* element)
+inline void enqueue_last( queue_t **queue, queue_t* element)
 {
 	unsigned long flags;
 	
@@ -585,10 +584,10 @@
  *    Insert item first in queue.
  *
  */
-void enqueue_first(QUEUE **queue, QUEUE* element)
+void enqueue_first(queue_t **queue, queue_t* element)
 {
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
 	/*
 	 * Check if queue is empty.
@@ -617,9 +616,9 @@
  *    Insert a queue (list) into the start of the first queue
  *
  */
-void enqueue_queue( QUEUE** queue, QUEUE** list )
+void enqueue_queue( queue_t** queue, queue_t** list )
 {
-	QUEUE* tmp;
+	queue_t* tmp;
 	
 	/*
 	 * Check if queue is empty
@@ -644,9 +643,9 @@
  *
  */
 #if 0
-static void enqueue_second(QUEUE **queue, QUEUE* element)
+static void enqueue_second(queue_t **queue, queue_t* element)
 {
-	DEBUG( 0, "enqueue_second()\n");
+	IRDA_DEBUG( 0, "enqueue_second()\n");
 
 	/*
 	 * Check if queue is empty.
@@ -675,11 +674,11 @@
  *    Remove first entry in queue
  *
  */
-QUEUE *dequeue_first(QUEUE **queue)
+queue_t *dequeue_first(queue_t **queue)
 {
-	QUEUE *ret;
+	queue_t *ret;
 
-	DEBUG( 4, "dequeue_first()\n");
+	IRDA_DEBUG( 4, "dequeue_first()\n");
 	
 	/*
 	 * Set return value
@@ -716,11 +715,11 @@
  *
  *
  */
-static QUEUE *dequeue_general(QUEUE **queue, QUEUE* element)
+static queue_t *dequeue_general(queue_t **queue, queue_t* element)
 {
-	QUEUE *ret;
+	queue_t *ret;
 	
-	DEBUG( 4, "dequeue_general()\n");
+	IRDA_DEBUG( 4, "dequeue_general()\n");
 	
 	/*
 	 * Set return value
diff -urN linux-2.2.15-pre2/net/irda/irsysctl.c linux/net/irda/irsysctl.c
--- linux-2.2.15-pre2/net/irda/irsysctl.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/irsysctl.c	Mon Dec  3 21:57:53 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 24 22:12:06 1998
- * Modified at:   Thu May  6 21:32:46 1999
+ * Modified at:   Fri Jun  4 02:50:15 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
@@ -31,13 +31,15 @@
 #include <net/irda/irda.h>
 
 #define NET_IRDA 412 /* Random number */
-enum { DISCOVERY=1, DEVNAME, COMPRESSION, DEBUG, SLOTS, SLOT_TIMEOUT };
+enum { DISCOVERY=1, DEVNAME, COMPRESSION, DEBUG, SLOTS, DISCOVERY_TIMEOUT, 
+       SLOT_TIMEOUT };
 
-extern int sysctl_discovery;
-extern int sysctl_discovery_slots;
-extern int sysctl_slot_timeout;
-extern int sysctl_fast_poll_increase;
-int sysctl_compression = 0;
+extern int  sysctl_discovery;
+extern int  sysctl_discovery_slots;
+extern int  sysctl_discovery_timeout;
+extern int  sysctl_slot_timeout;
+extern int  sysctl_fast_poll_increase;
+int         sysctl_compression = 0;
 extern char sysctl_devname[];
 
 #ifdef CONFIG_IRDA_DEBUG
@@ -62,6 +64,8 @@
 #endif
 	{ SLOTS, "discovery_slots", &sysctl_discovery_slots,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
+	{ DISCOVERY_TIMEOUT, "discovery_timeout", &sysctl_discovery_timeout,
+	  sizeof(int), 0644, NULL, &proc_dointvec },
 	{ SLOT_TIMEOUT, "slot_timeout", &sysctl_slot_timeout,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 	{ 0 }
@@ -89,9 +93,10 @@
  */
 int irda_sysctl_register(void)
 {
-	irda_table_header = register_sysctl_table( irda_root_table, 0);
-	if ( !irda_table_header)
+	irda_table_header = register_sysctl_table(irda_root_table, 0);
+	if (!irda_table_header)
 		return -ENOMEM;
+
 	return 0;
 }
 
@@ -103,7 +108,7 @@
  */
 void irda_sysctl_unregister(void) 
 {
-	unregister_sysctl_table( irda_table_header);
+	unregister_sysctl_table(irda_table_header);
 }
 
 
diff -urN linux-2.2.15-pre2/net/irda/irttp.c linux/net/irda/irttp.c
--- linux-2.2.15-pre2/net/irda/irttp.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/irttp.c	Mon Dec  3 21:57:53 2001
@@ -3,13 +3,13 @@
  * Filename:      irttp.c
  * Version:       1.2
  * Description:   Tiny Transport Protocol (TTP) implementation
- * Status:        Experimental.
+ * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Mon May 31 10:29:56 1999
+ * Modified at:   Sun Jan 16 22:46:33 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -32,7 +32,9 @@
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
+#include <net/irda/irlap.h>
 #include <net/irda/irlmp.h>
+#include <net/irda/parameters.h>
 #include <net/irda/irttp.h>
 
 static struct irttp_cb *irttp = NULL;
@@ -58,6 +60,15 @@
 static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
 static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
 static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
+static int irttp_param_max_sdu_size(void *instance, param_t *param, int get);
+
+/* Information for parsing parameters in IrTTP */
+static pi_minor_info_t pi_minor_call_table[] = {
+	{ NULL, 0 },                                             /* 0x00 */
+	{ irttp_param_max_sdu_size, PV_INTEGER | PV_BIG_ENDIAN } /* 0x01 */
+};
+static pi_major_info_t pi_major_call_table[] = {{ pi_minor_call_table, 2 }};
+static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 };
 
 /*
  * Function irttp_init (void)
@@ -65,7 +76,7 @@
  *    Initialize the IrTTP layer. Called by module initialization code
  *
  */
-__initfunc(int irttp_init(void))
+int __init irttp_init(void)
 {
 	/* Initialize the irttp structure. */
 	if (irttp == NULL) {
@@ -79,7 +90,7 @@
 
 	irttp->tsaps = hashbin_new(HB_LOCAL);
 	if (!irttp->tsaps) {
-		printk(KERN_WARNING "IrDA: Can't allocate IrTTP hashbin!\n");
+		ERROR(__FUNCTION__ "(), can't allocate IrTTP hashbin!\n");
 		return -ENOMEM;
 	}
 	
@@ -118,22 +129,22 @@
  *
  *    Create TSAP connection endpoint,
  */
-struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, 
-				struct notify_t *notify) 
+struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) 
 {
-	struct notify_t ttp_notify;
 	struct tsap_cb *self;
 	struct lsap_cb *lsap;
+	notify_t ttp_notify;
 
 	ASSERT(irttp != NULL, return NULL;);
 	ASSERT(irttp->magic == TTP_MAGIC, return NULL;);
 
 	self = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
 	if (self == NULL) {
-		DEBUG(0, __FUNCTION__ "(), unable to kmalloc!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc!\n");
 		return NULL;
 	}
 	memset(self, 0, sizeof(struct tsap_cb));
+	spin_lock_init(&self->lock);
 
 	init_timer(&self->todo_timer);
 
@@ -156,9 +167,9 @@
 	/*
 	 *  Create LSAP at IrLMP layer
 	 */
-	lsap = irlmp_open_lsap(stsap_sel, &ttp_notify);
+	lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
 	if (lsap == NULL) {
-		printk(KERN_ERR "IrTTP, Unable to get LSAP!!\n");
+		WARNING(__FUNCTION__ "(), unable to allocate LSAP!!\n");
 		return NULL;
 	}
 	
@@ -168,12 +179,12 @@
 	 *  the stsap_sel we have might not be valid anymore
 	 */
 	self->stsap_sel = lsap->slsap_sel;
-	DEBUG(4, __FUNCTION__ "(), stsap_sel=%02x\n", self->stsap_sel);
+	IRDA_DEBUG(4, __FUNCTION__ "(), stsap_sel=%02x\n", self->stsap_sel);
 
 	self->notify = *notify;
 	self->lsap = lsap;
 
-	hashbin_insert(irttp->tsaps, (QUEUE *) self, (int) self, NULL);
+	hashbin_insert(irttp->tsaps, (queue_t *) self, (int) self, NULL);
 
 	if (credit > TTP_MAX_QUEUE)
 		self->initial_credit = TTP_MAX_QUEUE;
@@ -217,7 +228,7 @@
 {
 	struct tsap_cb *tsap;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
@@ -226,11 +237,11 @@
 	if (self->connected) {
 		/* Check if disconnect is not pending */
 		if (!self->disconnect_pend) {
-			DEBUG(0, __FUNCTION__ "(), TSAP still connected!\n");
+			IRDA_DEBUG(0, __FUNCTION__ "(), TSAP still connected!\n");
 			irttp_disconnect_request(self, NULL, P_NORMAL);
 		}
 		self->close_pend = TRUE;
-		irttp_start_todo_timer(self, 100);
+		irttp_start_todo_timer(self, 1*HZ);
 
 		return 0; /* Will be back! */
 	}
@@ -262,16 +273,16 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 	ASSERT(skb != NULL, return -1;);
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
-		DEBUG(1, __FUNCTION__ "(), No data, or not connected\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), No data, or not connected\n");
 		return -1;
 	}
 	
 	if (skb->len > self->max_seg_size) {
-		DEBUG(1, __FUNCTION__ "(), UData is to large for IrLAP!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), UData is to large for IrLAP!\n");
 		return -1;
 	}
 		    
@@ -291,13 +302,9 @@
 {
 	__u8 *frame;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
-
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
-		ERROR(__FUNCTION__ "(), No data, or not connected\n");
+		WARNING(__FUNCTION__ "(), No data, or not connected\n");
 		return -ENOTCONN;
 	}
 
@@ -316,7 +323,7 @@
 	 *  TxMaxSduSize 
 	 */
 	if ((self->tx_max_sdu_size != 0) && 
-	    (self->tx_max_sdu_size != SAR_UNBOUND) && 
+	    (self->tx_max_sdu_size != TTP_SAR_UNBOUND) && 
 	    (skb->len > self->tx_max_sdu_size))
 	{
 		ERROR(__FUNCTION__ "(), SAR enabled, "
@@ -355,7 +362,7 @@
 
 	/* Check if we can accept more data from client */
 	if ((!self->tx_sdu_busy) && 
-	    (skb_queue_len(&self->tx_queue) > HIGH_THRESHOLD)) {
+	    (skb_queue_len(&self->tx_queue) > TTP_HIGH_THRESHOLD)) {
 		
 		/* Tx queue filling up, so stop client */
 		self->tx_sdu_busy = TRUE;
@@ -375,25 +382,36 @@
 /*
  * Function irttp_run_tx_queue (self)
  *
- *    If possible, transmit a frame queued for transmission.
+ *    Transmit packets queued for transmission (if possible)
  *
  */
 static void irttp_run_tx_queue(struct tsap_cb *self) 
 {
-	struct sk_buff *skb = NULL;
+	struct sk_buff *skb;
 	unsigned long flags;
 	int n;
 
 	if (irda_lock(&self->tx_queue_lock) == FALSE)
 		return;
 
-	while ((self->send_credit > 0) && !skb_queue_empty(&self->tx_queue)) {
-		skb = skb_dequeue(&self->tx_queue);
-		ASSERT(skb != NULL, return;);
-		
-		/* Make room for TTP header */
-		ASSERT(skb_headroom(skb) >= TTP_HEADER, return;);
-				
+	/* Try to send out frames as long as we have credits */
+	while ((self->send_credit > 0) &&
+	       (skb = skb_dequeue(&self->tx_queue)))
+	{
+		/* 
+		 * Make sure we don't flood IrLAP with frames just because
+		 * the remote device has given us a lot of credits
+		 */
+		if (irlmp_get_lap_tx_queue_len(self->lsap) > LAP_MAX_QUEUE) {
+			/* Re-queue packet */
+			skb_queue_head(&self->tx_queue, skb);
+
+			/* Try later. Maybe IrLAP could notify us? */
+			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(10));
+			
+			break;
+		}
+
 		/*
 		 *  Since we can transmit and receive frames concurrently, 
 		 *  the code below is a critical region and we must assure that
@@ -425,7 +443,7 @@
 
 		/* Check if we can accept more frames from client */
 		if ((self->tx_sdu_busy) && 
-		    (skb_queue_len(&self->tx_queue) < LOW_THRESHOLD)) 
+		    (skb_queue_len(&self->tx_queue) < TTP_LOW_THRESHOLD)) 
 		{
 			self->tx_sdu_busy = FALSE;
 			
@@ -435,9 +453,7 @@
 					FLOW_START);
 		}
 	}
-	
-	/* Reset lock */
-	self->tx_queue_lock = 0;
+	self->tx_queue_lock = 0; /* Reset lock */
 }
 
 /*
@@ -455,8 +471,8 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);	
 
-	DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
-	       self->send_credit, self->avail_credit, self->remote_credit);
+	IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
+		   self->send_credit, self->avail_credit, self->remote_credit);
 	
 	/* Give credit to peer */
 	tx_skb = dev_alloc_skb(64);
@@ -503,7 +519,7 @@
 {
 	struct tsap_cb *self;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	self = (struct tsap_cb *) instance;
 
@@ -512,16 +528,18 @@
 	ASSERT(skb != NULL, return -1;);
 
 	/* Just pass data to layer above */
-	if (self->notify.udata_indication) {
-		self->notify.udata_indication(self->notify.instance, self, skb);
-	}
+	if (self->notify.udata_indication)
+		self->notify.udata_indication(self->notify.instance, self,skb);
+	else
+		dev_kfree_skb(skb);
+
 	self->stats.rx_packets++;
 
 	return 0;
 }
 
 /*
- * Function irttp_data_indication (handle, skb)
+ * Function irttp_data_indication (instance, sap, skb)
  *
  *    Receive segment from IrLMP. 
  *
@@ -534,20 +552,15 @@
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
 	n = skb->data[0] & 0x7f;     /* Extract the credits */
 
 	self->stats.rx_packets++;
 
 	/* 
-	 *  Data or dataless frame? Dataless frames only contain the 
-	 *  TTP_HEADER
+	 *  Data or dataless packet? Dataless frames contains only the 
+	 *  TTP_HEADER. 
 	 */
-	if (skb->len == 1)
-		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
-	else {
+	if (skb->len > 1) {
 		/* Deal with inbound credit */
 		self->send_credit += n;
 		self->remote_credit--;
@@ -557,7 +570,10 @@
 		 *  more bit, so the defragment routing knows what to do
 		 */
 		skb_queue_tail(&self->rx_queue, skb);
-	} 
+	} else {
+		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
+		dev_kfree_skb(skb);
+	}
 
 	irttp_run_rx_queue(self);
 
@@ -565,18 +581,22 @@
 	 *  Give avay some credits to peer? 
 	 */
 	if ((skb_queue_empty(&self->tx_queue)) && 
-	    (self->remote_credit < LOW_THRESHOLD) && 
+	    (self->remote_credit < TTP_LOW_THRESHOLD) && 
 	    (self->avail_credit > 0)) 
 	{
 		/* Schedule to start immediately after this thread */
 		irttp_start_todo_timer(self, 0);
+		/*irttp_give_credit(self);*/
 	}
-
-	/* If peer has given us some credites and we didn't have anyone
-         * from before, the we need to shedule the tx queue? 
+	
+	/* 
+	 * If the peer device has given us some credits and we didn't have
+         * anyone from before, the we need to shedule the tx queue?  
 	 */
-	if (self->send_credit == n)
+	if (self->send_credit == n) {
+		/*irttp_run_tx_queue(self);*/
 		irttp_start_todo_timer(self, 0);
+	}
 	return 0;
 }
 
@@ -589,24 +609,24 @@
  */
 void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow)
 {
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	switch (flow) {
 	case FLOW_STOP:
-		DEBUG(1, __FUNCTION__ "(), flow stop\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), flow stop\n");
 		self->rx_sdu_busy = TRUE;
 		break;
 	case FLOW_START:
-		DEBUG(1, __FUNCTION__ "(), flow start\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), flow start\n");
 		self->rx_sdu_busy = FALSE;
 		
 		irttp_run_rx_queue(self);
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n");
 	}
 }
 	
@@ -625,11 +645,14 @@
 	__u8 *frame;
 	__u8 n;
 	
-	DEBUG(4, __FUNCTION__ "(), max_sdu_size=%d\n", max_sdu_size); 
+	IRDA_DEBUG(4, __FUNCTION__ "(), max_sdu_size=%d\n", max_sdu_size); 
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -EBADR;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
 
+	if (self->connected)
+		return -EISCONN;
+	
 	/* Any userdata supplied? */
 	if (userdata == NULL) {
 		skb = dev_alloc_skb(64);
@@ -705,17 +728,16 @@
  *
  */
 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 qos_info *qos, __u32 max_seg_size,
+				  __u8 max_header_size, struct sk_buff *skb) 
 {
 	struct tsap_cb *self;
 	int parameters;
-	__u8 *frame;
-	__u8 plen, pi, pl;
+	int ret;
+	__u8 plen;
 	__u8 n;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	self = (struct tsap_cb *) instance;
 
@@ -723,7 +745,7 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 	ASSERT(skb != NULL, return;);
 
-	self->max_seg_size = max_seg_size;
+	self->max_seg_size = max_seg_size - TTP_HEADER;
 	self->max_header_size = max_header_size + TTP_HEADER;
 
 	/*
@@ -731,63 +753,53 @@
 	 *  negotiated QoS for the link.
 	 */
 	if (qos) {
-		DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %02x\n", 
+		IRDA_DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %02x\n", 
 		       qos->baud_rate.bits);			
-		DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %d bps.\n", 
+		IRDA_DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %d bps.\n", 
 		       qos->baud_rate.value);
 	}
 
-	frame = skb->data;
-	n = frame[0] & 0x7f;
+	n = skb->data[0] & 0x7f;
 	
-	DEBUG(4, __FUNCTION__ "(), Initial send_credit=%d\n", n);
+	IRDA_DEBUG(4, __FUNCTION__ "(), Initial send_credit=%d\n", n);
 	
 	self->send_credit = n;
 	self->tx_max_sdu_size = 0;
 	self->connected = TRUE;
 
-	parameters = frame[0] & 0x80;	
+	parameters = skb->data[0] & 0x80;	
 
 	ASSERT(skb->len >= TTP_HEADER, return;);
 	skb_pull(skb, TTP_HEADER);
-		
+
 	if (parameters) {
-		plen = frame[1];
-		pi   = frame[2];
-		pl   = frame[3];
-
-		switch (pl) {
-		case 1:
-			self->tx_max_sdu_size = *(frame+4);
-			break;
-		case 2:
-			self->tx_max_sdu_size = 
-				be16_to_cpu(get_unaligned((__u16 *)(frame+4)));
-			break;
-		case 4:
-			self->tx_max_sdu_size = 
-				be32_to_cpu(get_unaligned((__u32 *)(frame+4)));
-			break;
-		default:
-			printk(KERN_ERR __FUNCTION__ 
-			       "() illegal value length for max_sdu_size!\n");
-			self->tx_max_sdu_size = 0;
-		};
+		plen = skb->data[0];
 
-		DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n", 
-		      self->tx_max_sdu_size);
-		
+		ret = irda_param_extract_all(self, skb->data+1,
+					     IRDA_MIN(skb->len-1, plen), 
+					     &param_info);
+
+		/* Any errors in the parameter list? */
+		if (ret < 0) {
+			WARNING(__FUNCTION__ 
+				"(), error extracting parameters\n");
+			dev_kfree_skb(skb);
+
+			/* Do not accept this connection attempt */
+			return;
+		}
 		/* Remove parameters */
-		ASSERT(skb->len >= (plen+1), return;);
-		skb_pull(skb, plen+1);
+		skb_pull(skb, IRDA_MIN(skb->len, plen+1));
 	}
 	
-	DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
+	IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
 	      self->send_credit, self->avail_credit, self->remote_credit);
 
+	IRDA_DEBUG(2, __FUNCTION__ "(), MaxSduSize=%d\n", self->tx_max_sdu_size);
+
 	if (self->notify.connect_confirm) {
 		self->notify.connect_confirm(self->notify.instance, self, qos,
-					     self->tx_max_sdu_size, 
+					     self->tx_max_sdu_size,
 					     self->max_header_size, skb);
 	}
 }
@@ -805,8 +817,8 @@
 	struct tsap_cb *self;
 	struct lsap_cb *lsap;
 	int parameters;
-	__u8 *frame;
-	__u8 plen, pi, pl;
+	int ret;
+	__u8 plen;
 	__u8 n;
 
 	self = (struct tsap_cb *) instance;
@@ -817,65 +829,51 @@
 
 	lsap = (struct lsap_cb *) sap;
 
-	self->max_seg_size = max_seg_size;
-
+	self->max_seg_size = max_seg_size - TTP_HEADER;;
 	self->max_header_size = max_header_size+TTP_HEADER;
 
-	DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
+	IRDA_DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
 
 	/* Need to update dtsap_sel if its equal to LSAP_ANY */
 	self->dtsap_sel = lsap->dlsap_sel;
 
-	frame = skb->data;
-	n = frame[0] & 0x7f;
+	n = skb->data[0] & 0x7f;
 
 	self->send_credit = n;
 	self->tx_max_sdu_size = 0;
 	
-	parameters = frame[0] & 0x80;
+	parameters = skb->data[0] & 0x80;
 
 	ASSERT(skb->len >= TTP_HEADER, return;);
 	skb_pull(skb, TTP_HEADER);
-		
+
 	if (parameters) {
-		DEBUG(3, __FUNCTION__ "(), Contains parameters!\n");
-		plen = frame[1];
-		pi   = frame[2];
-		pl   = frame[3];
-
-		switch (pl) {
-		case 1:
-			self->tx_max_sdu_size = frame[4];
-			break;
-		case 2:
-			self->tx_max_sdu_size = 
-				be16_to_cpu(get_unaligned((__u16 *)(frame+4)));
-			break;
-		case 4:
-			self->tx_max_sdu_size = 
-				be32_to_cpu(get_unaligned((__u32 *)(frame+4)));
-			break;
-		default:
-			printk(KERN_ERR __FUNCTION__ 
-			       "() illegal value length for max_sdu_size!\n");
-			self->tx_max_sdu_size = 0;
-		};
+		plen = skb->data[0];
 		
-		/* Remove parameters */
-		ASSERT(skb->len >= (plen+1), return;);
-		skb_pull(skb, plen+1);
+		ret = irda_param_extract_all(self, skb->data+1,
+					     IRDA_MIN(skb->len-1, plen), 
+					     &param_info);
+
+		/* Any errors in the parameter list? */
+		if (ret < 0) {
+			WARNING(__FUNCTION__ 
+				"(), error extracting parameters\n");
+			dev_kfree_skb(skb);
+			
+			/* Do not accept this connection attempt */
+			return;
+		}
 
-		DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n", 
-		      self->tx_max_sdu_size);
+		/* Remove parameters */
+		skb_pull(skb, IRDA_MIN(skb->len, plen+1));
 	}
 
-	DEBUG(4, __FUNCTION__ "(), initial send_credit=%d\n", n);
-
 	if (self->notify.connect_indication) {
 		self->notify.connect_indication(self->notify.instance, self, 
-						qos, self->rx_max_sdu_size, 
+						qos, self->tx_max_sdu_size, 
 						self->max_header_size, skb);
-	}
+	} else
+		dev_kfree_skb(skb);
 }
 
 /*
@@ -885,24 +883,25 @@
  *    IrLMP!
  * 
  */
-void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, 
-			    struct sk_buff *userdata)
+int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, 
+			   struct sk_buff *userdata)
 {
 	struct sk_buff *skb;
 	__u8 *frame;
+	int ret;
 	__u8 n;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
-	DEBUG(4, __FUNCTION__ "(), Source TSAP selector=%02x\n", 
-	      self->stsap_sel);
+	IRDA_DEBUG(4, __FUNCTION__ "(), Source TSAP selector=%02x\n", 
+		   self->stsap_sel);
 	
 	/* Any userdata supplied? */
 	if (userdata == NULL) {
 		skb = dev_alloc_skb(64);
 		if (!skb)
-			return;
+			return -ENOMEM;
 
 		/* Reserve space for MUX_CONTROL and LAP header */
 		skb_reserve(skb, TTP_MAX_HEADER);
@@ -912,7 +911,7 @@
 		 *  Check that the client has reserved enough space for 
 		 *  headers
 		 */
-		ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return;);
+		ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return -1;);
 	}
 	
 	self->avail_credit = 0;
@@ -935,13 +934,17 @@
 	/* SAR enabled? */
 	if (max_sdu_size > 0) {
 		ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER), 
-		       return;);
+		       return -1;);
 		
 		/* Insert TTP header with SAR parameters */
 		frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER);
 		
 		frame[0] = TTP_PARAMETERS | n;
 		frame[1] = 0x04; /* Length */
+
+		/* irda_param_insert(self, IRTTP_MAX_SDU_SIZE, frame+1,  */
+/* 				  TTP_SAR_HEADER, &param_info) */
+		
 		frame[2] = 0x01; /* MaxSduSize */
 		frame[3] = 0x02; /* Value length */
 
@@ -954,7 +957,9 @@
 		frame[0] = n & 0x7f;
 	}
 	 
-	irlmp_connect_response(self->lsap, skb);
+	ret = irlmp_connect_response(self->lsap, skb);
+
+	return ret;
 }
 
 /*
@@ -967,15 +972,15 @@
 {
 	struct tsap_cb *new;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	if (!hashbin_find(irttp->tsaps, (int) orig, NULL)) {
-		DEBUG(0, __FUNCTION__ "(), unable to find TSAP\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to find TSAP\n");
 		return NULL;
 	}
 	new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
 	if (!new) {
-		DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
 		return NULL;
 	}
 	/* Dup */
@@ -990,7 +995,7 @@
 	skb_queue_head_init(&new->tx_queue);
 	skb_queue_head_init(&new->rx_fragments);
 
-	hashbin_insert(irttp->tsaps, (QUEUE *) new, (int) new, NULL);
+	hashbin_insert(irttp->tsaps, (queue_t *) new, (int) new, NULL);
 
 	return new;
 }
@@ -1002,32 +1007,31 @@
  *    segments, if any, will be deallocated first
  *
  */
-void irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, 
-			      int priority)
+int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, 
+			     int priority)
 {
 	struct sk_buff *skb;
+	int ret;
 
-	DEBUG(2, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
 	/* Already disconnected? */
 	if (!self->connected) {
-		DEBUG(4, __FUNCTION__ "(), already disconnected!\n");
-		return;
+		IRDA_DEBUG(4, __FUNCTION__ "(), already disconnected!\n");
+		return -1;
 	}
 
 	/* Disconnect already pending? */
 	if (self->disconnect_pend) {
-		DEBUG(1, __FUNCTION__ "(), disconnect already pending\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), disconnect already pending\n");
 		if (userdata) {
 			dev_kfree_skb(userdata);
 		}
 
 		/* Try to make some progress */
 		irttp_run_rx_queue(self);
-		return;
+		return -1;
 	}
 
 	/*
@@ -1035,7 +1039,7 @@
 	 */
 	if (skb_queue_len(&self->tx_queue) > 0) {
 		if (priority == P_HIGH) {
-			DEBUG(1, __FUNCTION__  "High priority!!()\n" );
+			IRDA_DEBUG(1, __FUNCTION__  "High priority!!()\n" );
 			
 			/* 
 			 *  No need to send the queued data, if we are 
@@ -1057,18 +1061,18 @@
 
 			irttp_run_tx_queue(self);
 
-			irttp_start_todo_timer(self, 100);
-			return;
+			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(1000));
+			return -1;
 		}
 	}
-	DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
+	IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
 
 	self->connected = FALSE;
 	
 	if (!userdata) {
 		skb = dev_alloc_skb(64);
 		if (!skb)
-			return;
+			return -ENOMEM;
 		
 		/* 
 		 *  Reserve space for MUX and LAP header 
@@ -1077,7 +1081,9 @@
 		
 		userdata = skb;
 	}
-	irlmp_disconnect_request(self->lsap, userdata);
+	ret = irlmp_disconnect_request(self->lsap, userdata);
+
+	return ret;
 }
 
 /*
@@ -1087,11 +1093,11 @@
  *
  */
 void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason, 
-				 struct sk_buff *userdata) 
+				 struct sk_buff *skb) 
 {
 	struct tsap_cb *self;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	self = (struct tsap_cb *) instance;
 	
@@ -1100,11 +1106,22 @@
 	
 	self->connected = FALSE;
 	
-	if (!self->notify.disconnect_indication)
+	/* Check if client has already tried to close the TSAP */
+	if (self->close_pend) {
+		irttp_close_tsap(self);
 		return;
+	}
 
-	self->notify.disconnect_indication(self->notify.instance, self, reason,
-					   userdata);
+	/* No need to notify the client if has already tried to disconnect */
+	if (self->disconnect_pend)
+		return;
+	
+	if (self->notify.disconnect_indication)
+		self->notify.disconnect_indication(self->notify.instance, self,
+						   reason, skb);
+	else
+		if (skb)
+			dev_kfree_skb(skb);
 }
 
 /*
@@ -1118,6 +1135,12 @@
 {
 	int err;
 
+	/* Check if client has already tried to close the TSAP */
+	if (self->close_pend || self->disconnect_pend) {
+		dev_kfree_skb(skb);
+		return;
+	}
+
 	err = self->notify.data_indication(self->notify.instance, self, skb);
 
 	/* Usually the layer above will notify that it's input queue is
@@ -1126,7 +1149,7 @@
 	 * give an error back 
 	 */
 	if (err == -ENOMEM) {
-		DEBUG(0, __FUNCTION__ "() requeueing skb!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "() requeueing skb!\n");
 
 		/* Make sure we take a break */
 		self->rx_sdu_busy = TRUE;
@@ -1151,8 +1174,8 @@
 	struct sk_buff *skb;
 	int more = 0;
 
-	DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
-	       self->send_credit, self->avail_credit, self->remote_credit);
+	IRDA_DEBUG(2, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
+		   self->send_credit, self->avail_credit, self->remote_credit);
 
 	if (irda_lock(&self->rx_queue_lock) == FALSE)
 		return;
@@ -1177,7 +1200,7 @@
 		 * immediately. This can be requested by clients that
 		 * implements byte streams without any message boundaries
 		 */
-		if (self->rx_max_sdu_size == SAR_DISABLE) {
+		if (self->rx_max_sdu_size == TTP_SAR_DISABLE) {
 			irttp_do_data_indication(self, skb);
 			self->rx_sdu_size = 0;
 
@@ -1191,7 +1214,7 @@
 			 *  limits of the maximum size of the rx_sdu
 			 */
 			if (self->rx_sdu_size <= self->rx_max_sdu_size) {
-				DEBUG(4, __FUNCTION__ "(), queueing frag\n");
+				IRDA_DEBUG(4, __FUNCTION__ "(), queueing frag\n");
 				skb_queue_tail(&self->rx_fragments, skb);
 			} else {
 				/* Free the part of the SDU that is too big */
@@ -1203,7 +1226,7 @@
 		 *  This is the last fragment, so time to reassemble!
 		 */
 		if ((self->rx_sdu_size <= self->rx_max_sdu_size) ||
-		    (self->rx_max_sdu_size == SAR_UNBOUND)) 
+		    (self->rx_max_sdu_size == TTP_SAR_UNBOUND)) 
 		{
 			/* 
 			 * A little optimizing. Only queue the fragment if
@@ -1221,7 +1244,7 @@
 			/* Now we can deliver the reassembled skb */
 			irttp_do_data_indication(self, skb);
 		} else {
-			DEBUG(1, __FUNCTION__ "(), Truncated frame\n");
+			IRDA_DEBUG(1, __FUNCTION__ "(), Truncated frame\n");
 			
 			/* Free the part of the SDU that is too big */
 			dev_kfree_skb(skb);
@@ -1246,7 +1269,7 @@
 {
 	struct sk_buff* skb;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
@@ -1279,10 +1302,10 @@
       	ASSERT(self != NULL, return NULL;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
 
-	DEBUG(4, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
-	      self->rx_sdu_size);
+	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
+		   self->rx_sdu_size);
 
-	skb = dev_alloc_skb(self->rx_sdu_size);
+	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
 	if (!skb)
 		return NULL;
 
@@ -1302,11 +1325,12 @@
 		
 		dev_kfree_skb(frag);
 	}
-	DEBUG(4, __FUNCTION__ "(), frame len=%d\n", n);
-	/* Set the new length */
+	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
 
-	DEBUG(4, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
+	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
 	ASSERT(n <= self->rx_sdu_size, return NULL;);
+
+	/* Set the new length */
 	skb_trim(skb, n);
 
 	self->rx_sdu_size = 0;
@@ -1325,7 +1349,7 @@
 	struct sk_buff *frag;
 	__u8 *frame;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
@@ -1334,22 +1358,9 @@
 	/*
 	 *  Split frame into a number of segments
 	 */
-	while (skb->len > 0) {
-		/*
-		 *  Instead of making the last segment, we just
-		 *  queue what is left of the original skb
-		 */
-		if (skb->len < self->max_seg_size) {
-			DEBUG(4, __FUNCTION__ 
-			       "(), queuing last segment\n");
-
-			frame = skb_push(skb, TTP_HEADER);
-			frame[0] = 0x00; /* Clear more bit */
-			skb_queue_tail(&self->tx_queue, skb);
-			
-			return;
-		}
-		
+	while (skb->len > self->max_seg_size) {
+		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
+
 		/* Make new segment */
 		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
 		if (!frag)
@@ -1357,19 +1368,54 @@
 
 		skb_reserve(frag, self->max_header_size);
 
-		/*
-		 *  Copy data from the original skb into this fragment. We
-		 *  first insert the TTP header with the more bit set
-		 */
-		frame = skb_put(frag, self->max_seg_size+TTP_HEADER);
+		/* Copy data from the original skb into this fragment. */
+		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
+		       self->max_seg_size);
+
+		/* Insert TTP header, with the more bit set */
+		frame = skb_push(frag, TTP_HEADER);
 		frame[0] = TTP_MORE;
-		memcpy(frag->data+1, skb->data, self->max_seg_size);
 		
 		/* Hide the copied data from the original skb */
 		skb_pull(skb, self->max_seg_size);
-		
+
+		/* Queue fragment */
 		skb_queue_tail(&self->tx_queue, frag);
 	}
+	/* Queue what is left of the original skb */
+	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
+	
+	frame = skb_push(skb, TTP_HEADER);
+	frame[0] = 0x00; /* Clear more bit */
+
+	/* Queue fragment */
+	skb_queue_tail(&self->tx_queue, skb);
+}
+
+/*
+ * Function irttp_param_max_sdu_size (self, param)
+ *
+ *    Handle the MaxSduSize parameter in the connect frames, this function
+ *    will be called both when this parameter needs to be inserted into, and
+ *    extracted from the connect frames
+ */
+static int irttp_param_max_sdu_size(void *instance, param_t *param, int get)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+
+	if (get)
+		param->pv.i = self->tx_max_sdu_size;
+	else
+		self->tx_max_sdu_size = param->pv.i;
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
+	
+	return 0;
 }
 
 /*
@@ -1382,18 +1428,15 @@
 {
 	struct tsap_cb *self = (struct tsap_cb *) data;
 
-	DEBUG(4, __FUNCTION__ "()\n");
-	
 	/* Check that we still exist */
-	if (!self || self->magic != TTP_TSAP_MAGIC) {
+	if (!self || self->magic != TTP_TSAP_MAGIC)
 		return;
-	}
-
+	
 	irttp_run_rx_queue(self);
 	irttp_run_tx_queue(self);
-
+		
 	/*  Give avay some credits to peer?  */
-	if ((self->remote_credit < LOW_THRESHOLD) && 
+	if ((self->remote_credit < TTP_LOW_THRESHOLD) && 
 	    (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
 	{
 		irttp_give_credit(self);
@@ -1414,13 +1457,13 @@
 				irttp_disconnect_request(self, NULL, P_NORMAL);
 		} else {
 			/* Try again later */
-			irttp_start_todo_timer(self, 100);
+			irttp_start_todo_timer(self, 1*HZ);
 			
 			/* No reason to try and close now */
 			return;
 		}
 	}
-
+	
 	/* Check if it's closing time */
 	if (self->close_pend)
 		irttp_close_tsap(self);
@@ -1442,7 +1485,7 @@
 	self->todo_timer.data     = (unsigned long) self;
 	self->todo_timer.function = &irttp_todo_expired;
 	self->todo_timer.expires  = jiffies + timeout;
-	
+
 	add_timer(&self->todo_timer);
 }
 
@@ -1467,42 +1510,40 @@
 
 	self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps);
 	while (self != NULL) {
-		if (!self || self->magic != TTP_TSAP_MAGIC) {
-			DEBUG(1, "irttp_proc_read: bad ptr self\n");
+		if (!self || self->magic != TTP_TSAP_MAGIC)
 			return len;
-		}
 
 		len += sprintf(buf+len, "TSAP %d, ", i++);
 		len += sprintf(buf+len, "stsap_sel: %02x, ", 
-				self->stsap_sel);
+			       self->stsap_sel);
 		len += sprintf(buf+len, "dtsap_sel: %02x\n", 
-				self->dtsap_sel);
+			       self->dtsap_sel);
 		len += sprintf(buf+len, "  connected: %s, ",
-				self->connected? "TRUE":"FALSE");
+			       self->connected? "TRUE":"FALSE");
 		len += sprintf(buf+len, "avail credit: %d, ",
-				self->avail_credit);
+			       self->avail_credit);
 		len += sprintf(buf+len, "remote credit: %d, ",
-				self->remote_credit);
+			       self->remote_credit);
 		len += sprintf(buf+len, "send credit: %d\n",
-				self->send_credit);
+			       self->send_credit);
 		len += sprintf(buf+len, "  tx packets: %d, ",
-				self->stats.tx_packets);
+			       self->stats.tx_packets);
 		len += sprintf(buf+len, "rx packets: %d, ",
-				self->stats.rx_packets);
+			       self->stats.rx_packets);
 		len += sprintf(buf+len, "tx_queue len: %d ", 
-				skb_queue_len(&self->tx_queue));
+			       skb_queue_len(&self->tx_queue));
 		len += sprintf(buf+len, "rx_queue len: %d\n", 
-				skb_queue_len(&self->rx_queue));
+			       skb_queue_len(&self->rx_queue));
 		len += sprintf(buf+len, "  tx_sdu_busy: %s, ",
-				self->tx_sdu_busy? "TRUE":"FALSE");
+			       self->tx_sdu_busy? "TRUE":"FALSE");
 		len += sprintf(buf+len, "rx_sdu_busy: %s\n",
-				self->rx_sdu_busy? "TRUE":"FALSE");
+			       self->rx_sdu_busy? "TRUE":"FALSE");
 		len += sprintf(buf+len, "  max_seg_size: %d, ",
-				self->max_seg_size);
+			       self->max_seg_size);
 		len += sprintf(buf+len, "tx_max_sdu_size: %d, ",
-				self->tx_max_sdu_size);
+			       self->tx_max_sdu_size);
 		len += sprintf(buf+len, "rx_max_sdu_size: %d\n",
-				self->rx_max_sdu_size);
+			       self->rx_max_sdu_size);
 
 		len += sprintf(buf+len, "  Used by (%s)\n", 
 				self->notify.name);
diff -urN linux-2.2.15-pre2/net/irda/parameters.c linux/net/irda/parameters.c
--- linux-2.2.15-pre2/net/irda/parameters.c	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/parameters.c	Mon Dec  3 21:57:53 2001
@@ -0,0 +1,575 @@
+/*********************************************************************
+ *                
+ * Filename:      parameters.c
+ * Version:       1.0
+ * Description:   A more general way to handle (pi,pl,pv) parameters
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Mon Jun  7 10:25:11 1999
+ * Modified at:   Tue Dec 14 16:03:57 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 <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/parameters.h>
+
+static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, 
+				PV_TYPE type, PI_HANDLER func);
+static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, 
+			       PV_TYPE type, PI_HANDLER func);
+static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, 
+			       PV_TYPE type, PI_HANDLER func);
+static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, 
+				 PV_TYPE type, PI_HANDLER func);
+
+static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, 
+			       PV_TYPE type, PI_HANDLER func);
+static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, 
+				PV_TYPE type, PI_HANDLER func);
+
+/* Parameter value call table. Must match PV_TYPE */
+static PV_HANDLER pv_extract_table[] = {
+	irda_extract_integer, /* Handler for any length integers */
+	irda_extract_integer, /* Handler for 8  bits integers */
+	irda_extract_integer, /* Handler for 16 bits integers */
+	irda_extract_string,  /* Handler for strings */
+	irda_extract_integer, /* Handler for 32 bits integers */
+	irda_extract_octseq,  /* Handler for octet sequences */
+	irda_extract_no_value /* Handler for no value parameters */
+};
+
+static PV_HANDLER pv_insert_table[] = {
+	irda_insert_integer, /* Handler for any length integers */
+	irda_insert_integer, /* Handler for 8  bits integers */
+	irda_insert_integer, /* Handler for 16 bits integers */
+	NULL,                /* Handler for strings */
+	irda_insert_integer, /* Handler for 32 bits integers */
+	NULL,                /* Handler for octet sequences */
+	irda_insert_no_value /* Handler for no value parameters */
+};
+
+/*
+ * Function irda_insert_no_value (self, buf, len, pi, type, func)
+ *
+ *    
+ *
+ */
+static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, 
+				PV_TYPE type, PI_HANDLER func)
+{
+	param_t p;
+	int ret;
+
+	p.pi = pi;
+	p.pl = 0;
+
+	/* Call handler for this parameter */
+	ret = (*func)(self, &p, PV_GET);
+
+	/* Extract values anyway, since handler may need them */
+	irda_param_pack(buf, "bb", p.pi, p.pl);
+
+	if (ret < 0)
+		return ret;
+	 
+	return 2; /* Inserted pl+2 bytes */
+}
+
+/*
+ * Function irda_extract_no_value (self, buf, len, type, func)
+ *
+ *    Extracts a parameter without a pv field (pl=0)
+ *
+ */
+static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, 
+				 PV_TYPE type, PI_HANDLER func)
+{
+	param_t p;
+	int ret;
+
+	/* Extract values anyway, since handler may need them */
+	irda_param_unpack(buf, "bb", &p.pi, &p.pl);
+
+	/* Call handler for this parameter */
+	ret = (*func)(self, &p, PV_PUT);
+
+	if (ret < 0)
+		return ret;
+	 
+	return 2; /* Extracted pl+2 bytes */
+}
+
+/*
+ * Function irda_insert_integer (self, buf, len, pi, type, func)
+ *
+ *    
+ *
+ */
+static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, 
+			       PV_TYPE type, PI_HANDLER func)
+{
+	param_t p;
+	int n = 0;
+	int err;
+
+	p.pi = pi;             /* In case handler needs to know */
+	p.pl = type & PV_MASK; /* The integer type codes the lenght as well */
+	p.pv.i = 0;            /* Clear value */
+
+	/* Call handler for this parameter */
+	err = (*func)(self, &p, PV_GET);
+	if (err < 0)
+		return err; 
+
+	/* 
+	 * If parameter lenght is still 0, then (1) this is an any length 
+	 * integer, and (2) the handler function does not care which length
+	 * we choose to use, so we pick the one the gives the fewest bytes.
+	 */
+	if (p.pl == 0) {
+		if (p.pv.i < 0xff) {
+			IRDA_DEBUG(2, __FUNCTION__ "(), using 1 byte\n");
+			p.pl = 1;
+		} else if (p.pv.i < 0xffff) {
+			IRDA_DEBUG(2, __FUNCTION__ "(), using 2 bytes\n");
+			p.pl = 2;
+		} else {
+			IRDA_DEBUG(2, __FUNCTION__ "(), using 4 bytes\n");
+			p.pl = 4; /* Default length */
+		}
+	}
+	/* Check if buffer is long enough for insertion */
+	if (len < (2+p.pl)) {
+		WARNING(__FUNCTION__ "(), buffer to short for insertion!\n");
+		return -1;
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), pi=%#x, pl=%d, pi=%d\n", p.pi, p.pl, p.pv.i);
+	switch (p.pl) {
+	case 1:
+		n += irda_param_pack(buf, "bbb", p.pi, p.pl, p.pv.b);
+		break;
+	case 2:
+		if (type & PV_BIG_ENDIAN)
+			cpu_to_be16s(&p.pv.s);
+		else
+			cpu_to_le16s(&p.pv.s);
+		n += irda_param_pack(buf, "bbs", p.pi, p.pl, p.pv.s);
+		break;
+	case 4:
+		if (type & PV_BIG_ENDIAN)
+			cpu_to_be32s(&p.pv.i);
+		else
+			cpu_to_le32s(&p.pv.i);
+		n += irda_param_pack(buf, "bbi", p.pi, p.pl, p.pv.i);
+
+		break;
+	default:
+		WARNING(__FUNCTION__ "() length %d not supported\n", p.pl);
+		/* Skip parameter */ 
+		return -1;
+	}
+
+	return p.pl+2; /* Inserted pl+2 bytes */
+}
+
+/*
+ * Function irda_extract integer (self, buf, len, pi, type, func)
+ *
+ *    Extract a possibly variable length integer from buffer, and call 
+ *    handler for processing of the parameter
+ */
+static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, 
+				PV_TYPE type, PI_HANDLER func)
+{
+	param_t p;
+	int n = 0;
+	int err;
+
+	p.pi = pi;     /* In case handler needs to know */
+	p.pl = buf[1]; /* Extract lenght of value */
+	p.pv.i = 0;    /* Clear value */
+
+	/* Check if buffer is long enough for parsing */
+	if (len < (2+p.pl)) {
+		WARNING(__FUNCTION__ "(), buffer to short for parsing! "
+			"Need %d bytes, but len is only %d\n", p.pl, len);
+		return -1;
+	}
+
+	/* 
+	 * Check that the integer length is what we expect it to be. If the
+	 * handler want a 16 bits integer then a 32 bits is not good enough
+	 */
+	if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
+		ERROR(__FUNCTION__ "(), invalid parameter length! "
+		      "Expected %d bytes, but value had %d bytes!\n",
+		      type & PV_MASK, p.pl);
+		
+		/* Skip parameter */
+		return p.pl+2;
+	}
+
+	switch (p.pl) {
+	case 1:
+		n += irda_param_unpack(buf+2, "b", &p.pv.b);
+		break;
+	case 2:
+		n += irda_param_unpack(buf+2, "s", &p.pv.s);
+		if (type & PV_BIG_ENDIAN)
+			be16_to_cpus(&p.pv.s);
+		else
+			le16_to_cpus(&p.pv.s);
+		break;
+	case 4:
+		n += irda_param_unpack(buf+2, "i", &p.pv.i);
+		if (type & PV_BIG_ENDIAN)
+			be32_to_cpus(&p.pv.i);
+		else
+			le32_to_cpus(&p.pv.i);
+		break;
+	default:
+		WARNING(__FUNCTION__ "() length %d not supported\n", p.pl);
+
+		/* Skip parameter */ 
+		return p.pl+2;
+	}
+
+	/* Call handler for this parameter */
+	err = (*func)(self, &p, PV_PUT);
+	if (err < 0)
+		return err; 
+
+	return p.pl+2; /* Extracted pl+2 bytes */
+}
+
+/*
+ * Function irda_extract_string (self, buf, len, type, func)
+ *
+ *    
+ *
+ */
+static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, 
+			       PV_TYPE type, PI_HANDLER func)
+{
+	char str[33];
+	param_t p;
+	int err;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	p.pi = pi;     /* In case handler needs to know */
+	p.pl = buf[1]; /* Extract lenght of value */
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), pi=%#x, pl=%d\n", p.pi, p.pl);
+
+	/* Check if buffer is long enough for parsing */
+	if (len < (2+p.pl)) {
+		WARNING(__FUNCTION__ "(), buffer to short for parsing! "
+			"Need %d bytes, but len is only %d\n", p.pl, len);
+		return -1;
+	}
+
+	/* Should be safe to copy string like this since we have already 
+	 * checked that the buffer is long enough */
+	strncpy(str, buf+2, p.pl);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), str=0x%02x 0x%02x\n", (__u8) str[0], 
+	      (__u8) str[1]);
+	
+	/* Null terminate string */
+	str[p.pl+1] = '\0';
+
+	p.pv.c = str; /* Handler will need to take a copy */
+
+	/* Call handler for this parameter */
+	err = (*func)(self, &p, PV_PUT);
+	if (err < 0)
+		return err; 
+
+	return p.pl+2; /* Extracted pl+2 bytes */
+}
+
+/*
+ * Function irda_extract_octseq (self, buf, len, type, func)
+ *
+ *    
+ *
+ */
+static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi,
+			       PV_TYPE type, PI_HANDLER func)
+{
+	param_t p;
+
+	p.pi = pi;     /* In case handler needs to know */
+	p.pl = buf[1]; /* Extract lenght of value */
+
+	/* Check if buffer is long enough for parsing */
+	if (len < (2+p.pl)) {
+		WARNING(__FUNCTION__ "(), buffer to short for parsing! "
+			"Need %d bytes, but len is only %d\n", p.pl, len);
+		return -1;
+	}
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), not impl\n");
+	
+	return p.pl+2; /* Extracted pl+2 bytes */
+}
+
+/*
+ * Function irda_param_pack (skb, fmt, ...)
+ *
+ *    Format:
+ *        'i' = 32 bits integer
+ *        's' = string
+ *
+ */
+int irda_param_pack(__u8 *buf, char *fmt, ...)
+{
+	va_list args;
+	char *p;
+	int n = 0;
+	pv_t arg;
+	
+	va_start(args, fmt);
+
+	for (p = fmt; *p != '\0'; p++) {
+		switch (*p) {
+		case 'b':  /* 8 bits unsigned byte */
+			buf[n++] = va_arg(args, __u8);
+			break;
+		case 's':  /* 16 bits unsigned short */
+			arg.s = va_arg(args, __u16);
+			put_unaligned(arg.s, (__u16 *)(buf+n)); n+=2;
+			break;
+		case 'i':  /* 32 bits unsigned integer */
+			arg.i = va_arg(args, __u32);
+			put_unaligned(arg.i, (__u32 *)(buf+n)); n+=4;
+			break;
+		case 'c': /* \0 terminated string */
+			arg.c = va_arg(args, char *);
+			strcpy(buf+n, arg.c);
+			n += strlen(arg.c) + 1;
+			break;
+		default:
+			va_end(args);
+			return -1;
+		}
+		
+	}
+	va_end(args);
+
+	return 0;
+}
+
+/*
+ * Function irda_param_unpack (skb, fmt, ...)
+ *
+ *    
+ *
+ */
+int irda_param_unpack(__u8 *buf, char *fmt, ...)
+{
+	va_list args;
+	char *p;
+	int n = 0;
+	pv_t arg;
+
+	va_start(args, fmt);
+
+	for (p = fmt; *p != '\0'; p++) {
+		switch (*p) {
+		case 'b':  /* 8 bits byte */
+			arg.bp = va_arg(args, __u8 *);
+			*arg.bp = buf[n++];
+			break;
+		case 's':  /* 16 bits short */
+			arg.sp = va_arg(args, __u16 *);
+			*arg.sp = get_unaligned((__u16 *)(buf+n)); n+=2;
+			break;
+		case 'i':  /* 32 bits unsigned integer */
+			arg.ip = va_arg(args, __u32 *);
+			*arg.ip = get_unaligned((__u32 *)(buf+n)); n+=4;
+			break;
+#if 0
+		case 'c':   /* \0 terminated string */
+			arg.c = va_arg(args, char *);
+			strcpy(arg.c, buf+n);
+			n += strlen(arg.c) + 1;
+			break;
+#endif
+		default:
+			va_end(args);
+			return -1;
+		}
+		
+	}
+	va_end(args);
+
+	return 0;
+}
+
+/*
+ * Function irda_param_insert (self, pi, buf, len, info)
+ *
+ *    Insert the specified parameter (pi) into buffer. Returns number of
+ *    bytes inserted
+ */
+int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, 
+		      pi_param_info_t *info)
+{
+	pi_minor_info_t *pi_minor_info;
+	__u8 pi_minor;
+	__u8 pi_major;
+	int type;
+	int ret = -1;
+	int n = 0;
+
+	ASSERT(buf != NULL, return ret;);
+	ASSERT(info != 0, return ret;);
+
+	pi_minor = pi & info->pi_mask;
+	pi_major = pi >> info->pi_major_offset;
+
+	/* Check if the identifier value (pi) is valid */
+	if ((pi_major > info->len-1) || 
+	    (pi_minor > info->tables[pi_major].len-1))
+	{
+		IRDA_DEBUG(0, __FUNCTION__ 
+		      "(), no handler for parameter=0x%02x\n", pi);
+		
+		/* Skip this parameter */
+		return -1;
+	}
+	
+	/* Lookup the info on how to parse this parameter */
+	pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor];
+
+	/* Find expected data type for this parameter identifier (pi)*/
+	type = pi_minor_info->type;
+
+	/*  Check if handler has been implemented */
+	if (!pi_minor_info->func) {
+		MESSAGE(__FUNCTION__"(), no handler for pi=%#x\n", pi);
+		/* Skip this parameter */
+		return -1;
+	}
+	
+	/* Insert parameter value */
+	ret = (*pv_insert_table[type & PV_MASK])(self, buf+n, len, pi, type, 
+						 pi_minor_info->func);
+	return ret;
+}
+
+/*
+ * Function irda_param_extract_all (self, buf, len, info)
+ *
+ *    Parse all parameters. If len is correct, then everything should be
+ *    safe. Returns the number of bytes that was parsed
+ *
+ */
+int irda_param_extract(void *self, __u8 *buf, int len, pi_param_info_t *info)
+{
+	pi_minor_info_t *pi_minor_info;
+	__u8 pi_minor;
+	__u8 pi_major;
+	int type;
+	int ret = -1;
+	int n = 0;
+
+	ASSERT(buf != NULL, return ret;);
+	ASSERT(info != 0, return ret;);
+
+	pi_minor = buf[n] & info->pi_mask;
+	pi_major = buf[n] >> info->pi_major_offset;
+	
+	/* Check if the identifier value (pi) is valid */
+	if ((pi_major > info->len-1) || 
+	    (pi_minor > info->tables[pi_major].len-1))
+	{
+		IRDA_DEBUG(0, __FUNCTION__ "(), no handler for parameter=0x%02x\n",
+		      buf[0]);
+		
+		/* Skip this parameter */
+		n += (2 + buf[n+1]);
+		len -= (2 + buf[n+1]);
+
+		return 0;  /* Continue */
+	}
+
+	/* Lookup the info on how to parse this parameter */
+	pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor];
+
+	/* Find expected data type for this parameter identifier (pi)*/
+	type = pi_minor_info->type;
+	
+	IRDA_DEBUG(3, __FUNCTION__ "(), pi=[%d,%d], type=%d\n",
+	      pi_major, pi_minor, type);
+	
+	/*  Check if handler has been implemented */
+	if (!pi_minor_info->func) {
+		MESSAGE(__FUNCTION__"(), no handler for pi=%#x\n", buf[n]);
+		/* Skip this parameter */
+		n += (2 + buf[n+1]);
+		len -= (2 + buf[n+1]);
+
+		return 0; /* Continue */
+	}
+
+	/* Parse parameter value */
+	ret = (*pv_extract_table[type & PV_MASK])(self, buf+n, len, buf[n],
+						  type, pi_minor_info->func);
+	return ret;
+}
+
+/*
+ * Function irda_param_extract_all (self, buf, len, info)
+ *
+ *    Parse all parameters. If len is correct, then everything should be
+ *    safe. Returns the number of bytes that was parsed
+ *
+ */
+int irda_param_extract_all(void *self, __u8 *buf, int len, 
+			   pi_param_info_t *info)
+{
+	int ret = -1;
+	int n = 0;
+
+	ASSERT(buf != NULL, return ret;);
+	ASSERT(info != 0, return ret;);
+
+	/*
+	 * Parse all parameters. Each parameter must be at least two bytes
+	 * long or else there is no point in trying to parse it
+	 */
+	while (len > 2) {
+		ret = irda_param_extract(self, buf+n, len, info);
+		if (ret < 0)
+			return ret;
+
+		n += ret;
+		len -= ret;
+	}
+	return n;
+}
+
diff -urN linux-2.2.15-pre2/net/irda/qos.c linux/net/irda/qos.c
--- linux-2.2.15-pre2/net/irda/qos.c	Sun May 30 10:17:04 1999
+++ linux/net/irda/qos.c	Mon Dec  3 21:57:53 2001
@@ -1,12 +1,12 @@
 /*********************************************************************
- *                
+ *                                
  * Filename:      qos.c
- * Version:       0.8
- * Description:   IrLAP QoS negotiation
- * Status:        Experimental.
+ * Version:       1.0
+ * Description:   IrLAP QoS parameter negotiation
+ * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Sep  9 00:00:26 1997
- * Modified at:   Mon May  3 21:15:08 1999
+ * Modified at:   Sun Dec 12 13:47:09 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
@@ -16,17 +16,24 @@
  *     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>
 #include <asm/byteorder.h>
 
 #include <net/irda/irda.h>
+#include <net/irda/parameters.h>
 #include <net/irda/qos.h>
 #include <net/irda/irlap.h>
 #ifdef CONFIG_IRDA_COMPRESSION
@@ -36,17 +43,69 @@
 #define CI_BZIP2  27 /* Random pick */
 #endif
 
-int min_turn_time[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 };
-int baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000, 1152000,
-		     4000000 };
-int data_size[]  = { 64, 128, 256, 512, 1024, 2048 };
-int add_bofs[]   = { 48, 24, 12, 5, 3, 2, 1, 0 };
-int max_turn_time[] = { 500, 250, 100, 50 };
-int link_disc_time[] = { 3, 8, 12, 16, 20, 25, 30, 40 };
+static int irlap_param_baud_rate(void *instance, param_t *param, int get);
+static int irlap_param_link_disconnect(void *instance, param_t *parm, int get);
+static int irlap_param_max_turn_time(void *instance, param_t *param, int get);
+static int irlap_param_data_size(void *instance, param_t *param, int get);
+static int irlap_param_window_size(void *instance, param_t *param, int get);
+static int irlap_param_additional_bofs(void *instance, param_t *parm, int get);
+static int irlap_param_min_turn_time(void *instance, param_t *param, int get);
+
+__u32 min_turn_times[]  = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
+__u32 baud_rates[]      = { 2400, 9600, 19200, 38400, 57600, 115200, 576000, 
+			    1152000, 4000000, 16000000 };           /* bps */
+__u32 data_sizes[]      = { 64, 128, 256, 512, 1024, 2048 };        /* bytes */
+__u32 add_bofs[]        = { 48, 24, 12, 5, 3, 2, 1, 0 };            /* bytes */
+__u32 max_turn_times[]  = { 500, 250, 100, 50 };                    /* ms */
+__u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 };         /* secs */
 
 #ifdef CONFIG_IRDA_COMPRESSION
-int compression[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
+__u32 compressions[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
 #endif
+
+__u32 max_line_capacities[10][4] = {
+       /* 500 ms     250 ms  100 ms  50 ms (max turn time) */
+	{    100,      0,      0,     0 }, /*     2400 bps */
+	{    400,      0,      0,     0 }, /*     9600 bps */
+	{    800,      0,      0,     0 }, /*    19200 bps */
+	{   1600,      0,      0,     0 }, /*    38400 bps */
+	{   2360,      0,      0,     0 }, /*    57600 bps */
+	{   4800,   2400,    960,   480 }, /*   115200 bps */
+	{  28800,  11520,   5760,  2880 }, /*   576000 bps */
+	{  57600,  28800,  11520,  5760 }, /*  1152000 bps */
+	{ 200000, 100000,  40000, 20000 }, /*  4000000 bps */
+	{ 800000, 400000, 160000, 80000 }, /* 16000000 bps */
+};
+
+static pi_minor_info_t pi_minor_call_table_type_0[] = {
+	{ NULL, 0 },
+/* 01 */{ irlap_param_baud_rate,       PV_INTEGER | PV_LITTLE_ENDIAN },
+	{ NULL, 0 },
+	{ NULL, 0 },
+	{ NULL, 0 },
+	{ NULL, 0 },
+	{ NULL, 0 },
+	{ NULL, 0 },
+/* 08 */{ irlap_param_link_disconnect, PV_INT_8_BITS }
+};
+
+static pi_minor_info_t pi_minor_call_table_type_1[] = {
+	{ NULL, 0 },
+	{ NULL, 0 },
+/* 82 */{ irlap_param_max_turn_time,   PV_INT_8_BITS },
+/* 83 */{ irlap_param_data_size,       PV_INT_8_BITS },
+/* 84 */{ irlap_param_window_size,     PV_INT_8_BITS },
+/* 85 */{ irlap_param_additional_bofs, PV_INT_8_BITS },
+/* 86 */{ irlap_param_min_turn_time,   PV_INT_8_BITS },
+};
+
+static pi_major_info_t pi_major_call_table[] = {
+	{ pi_minor_call_table_type_0, 9 },
+	{ pi_minor_call_table_type_1, 7 },
+};
+
+static pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 };
+
 /*
  * Function irda_qos_compute_intersection (qos, new)
  *
@@ -81,7 +140,7 @@
  *    set the maximum QoS possible and then "and in" their own limitations
  * 
  */
-void irda_init_max_qos_capabilies( struct qos_info *qos)
+void irda_init_max_qos_capabilies(struct qos_info *qos)
 {
 	/* 
 	 *  These are the maximum supported values as specified on pages
@@ -104,164 +163,117 @@
 }
 
 /*
+ * Function irlap_adjust_qos_settings (qos)
+ *
+ *     Adjust QoS settings in case some values are not possible to use because
+ *     of other settings
+ */
+void irlap_adjust_qos_settings(struct qos_info *qos)
+{
+	__u32 line_capacity;
+	int index;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* 
+	 * Not allowed to use a max turn time less than 500 ms if the baudrate
+	 * is less than 115200
+	 */
+	if ((qos->baud_rate.value < 115200) && 
+	    (qos->max_turn_time.value < 500))
+	{
+		IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), adjusting max turn time from %d to 500 ms\n",
+			   qos->max_turn_time.value);
+		qos->max_turn_time.value = 500;
+	}
+	
+	/*
+	 * The data size must be adjusted according to the baud rate and max 
+	 * turn time
+	 */
+	index = value_index(qos->data_size.value, data_sizes);
+	line_capacity = irlap_max_line_capacity(qos->baud_rate.value, 
+						qos->max_turn_time.value);
+
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+	while ((qos->data_size.value > line_capacity) && (index > 0)) {
+		qos->data_size.value = data_sizes[index--];
+		IRDA_DEBUG(2, __FUNCTION__ 
+			   "(), redusing data size to %d\n",
+			   qos->data_size.value);
+	}
+#else /* Use method descibed in section 6.6.11 of IrLAP */
+	while (irlap_requested_line_capacity(qos) > line_capacity) {
+		ASSERT(index != 0, return;);
+
+		/* Must be able to send at least one frame */
+		if (qos->window_size.value > 1) {
+			qos->window_size.value--;
+			IRDA_DEBUG(2, __FUNCTION__ 
+				   "(), redusing window size to %d\n",
+				   qos->window_size.value);
+		} else if (index > 1) {
+			qos->data_size.value = data_sizes[index--];
+			IRDA_DEBUG(2, __FUNCTION__ 
+				   "(), redusing data size to %d\n",
+				   qos->data_size.value);
+		} else {
+			WARNING(__FUNCTION__ "(), nothing more we can do!\n");
+		}
+	}
+#endif CONFIG_IRDA_DYNAMIC_WINDOW
+}
+
+/*
  * Function irlap_negotiate (qos_device, qos_session, skb)
  *
  *    Negotiate QoS values, not really that much negotiation :-)
  *    We just set the QoS capabilities for the peer station
  *
  */
-void irda_qos_negotiate(struct qos_info *qos_rx, struct qos_info *qos_tx, 
-			struct sk_buff *skb) 
+int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb) 
 {
-	int n=0;
+	int ret;
 #ifdef CONFIG_IRDA_COMPRESSION
 	int comp_seen = FALSE;
 #endif
-	__u8 length;
-	__u8 *frame;
-	__u8 final_byte;
-	__u8 code;
-	__u8 byte;
- 	__u16 final_word;
-	__u16_host_order word;
-
-	ASSERT( qos_tx != NULL, return;);
-	ASSERT( qos_rx != NULL, return;);
-	ASSERT( skb != NULL, return;);
-
-	frame = skb->data;
-
-	while( n < skb->len-2) {
-		code = frame[n++];
-		/* Length */
-		length = frame[n++];
-
-		/*  
-		 *  Get the value, since baud_rate may need two bytes, we
-		 *  Just use word size all the time
-		 */
-		switch( length) {
-		case 1:
-			byte = frame[n++];
-			word.word = byte; /* To make things a little easier */
-			break;
-		case 2:
-#ifdef __LITTLE_ENDIAN
-			word.byte[0] = frame[n++];
-			word.byte[1] = frame[n++];
-#else ifdef __BIG_ENDIAN
-			word.byte[1] = frame[n++];
-			word.byte[0] = frame[n++];
-#endif
-			byte = 0;
-			break;
-		default:
-			DEBUG( 0, __FUNCTION__ "Error\n");
-			word.word = byte = 0;
-			n += length;
-			
-			break;
-		}
-
-		switch(code) {
-		case PI_BAUD_RATE:
-			/* 
-			 *  Stations must agree on baud rate, so calculate
-                         *  intersection 
-			 */
-			DEBUG( 4, "Requested BAUD_RATE: 0x%04x\n", word.word);
-			final_word = word.word & qos_rx->baud_rate.bits;
-			DEBUG( 4, "Final BAUD_RATE: 0x%04x\n", final_word);
-			qos_tx->baud_rate.bits = final_word;
-			qos_rx->baud_rate.bits = final_word;
-			break;
-		case PI_MAX_TURN_TIME:
-			/*
-			 *  Negotiated independently for each station
-			 */
-			DEBUG(4, __FUNCTION__ "(), MAX_TURN_TIME: %02x\n", 
-			      byte);
-			qos_tx->max_turn_time.bits = byte;
-			break;
-		case PI_DATA_SIZE:
-			/*
-			 *  Negotiated independently for each station
-			 */
-			DEBUG( 4, "DATA_SIZE: %02x\n", byte);
-			qos_tx->data_size.bits = byte;
-			break;
-		case PI_WINDOW_SIZE:
-			/*
-			 *  Negotiated independently for each station
-			 */
-			qos_tx->window_size.bits = byte;
-			break;
-		case PI_ADD_BOFS:
-			/*
-			 *  Negotiated independently for each station
-			 */
-			DEBUG( 4, "ADD_BOFS: %02x\n", byte);
-			qos_tx->additional_bofs.bits = byte;	
-			break;
-		case PI_MIN_TURN_TIME:
-			DEBUG( 4, "MIN_TURN_TIME: %02x\n", byte);
-			qos_tx->min_turn_time.bits = byte;
-			break;
-		case PI_LINK_DISC:
-			/*  
-			 *  Stations must agree on link disconnect/threshold 
-			 *  time.
-			 */
-			DEBUG( 4, "LINK_DISC: %02x\n", byte);
-			
-			final_byte = byte & qos_rx->link_disc_time.bits;
-			DEBUG( 4, "Final LINK_DISC: %02x\n", final_byte);
-			qos_tx->link_disc_time.bits = final_byte;
-			qos_rx->link_disc_time.bits = final_byte;
-			break;
-#ifdef CONFIG_IRDA_COMPRESSION
-		case PI_COMPRESSION:
-			final_byte = byte & qos_rx->compression.bits;
-			qos_rx->compression.bits = byte;
-			qos_tx->compression.bits = byte;
-			comp_seen = TRUE;
-			break;
-#endif
-		default:
-			DEBUG( 0, __FUNCTION__ "(), Unknown value\n");
-			break;
-		}
-	}
+	ret = irda_param_extract_all(self, skb->data, skb->len, 
+				     &irlap_param_info);
+	
 #ifdef CONFIG_IRDA_COMPRESSION
-	if ( !comp_seen) {
-		DEBUG( 4, __FUNCTION__ "(), Compression not seen!\n");
-		qos_tx->compression.bits = 0x00;
-		qos_rx->compression.bits = 0x00;
+	if (!comp_seen) {
+		IRDA_DEBUG( 4, __FUNCTION__ "(), Compression not seen!\n");
+		self->qos_tx.compression.bits = 0x00;
+		self->qos_rx.compression.bits = 0x00;
 	}
 #endif
+
 	/* Convert the negotiated bits to values */
-	irda_qos_bits_to_value( qos_tx);
-	irda_qos_bits_to_value( qos_rx);
-		
-	DEBUG( 4, "Setting BAUD_RATE to %d bps.\n", 
-	       qos_tx->baud_rate.value);
-	DEBUG( 4, "Setting DATA_SIZE to %d bytes\n",
-	       qos_tx->data_size.value);
-	DEBUG( 4, "Setting WINDOW_SIZE to %d\n", 
-	       qos_tx->window_size.value);
-	DEBUG( 4, "Setting XBOFS to %d\n", 
-	       qos_tx->additional_bofs.value);
-	DEBUG( 4, "Setting MAX_TURN_TIME to %d ms.\n",
-	       qos_tx->max_turn_time.value);
-	DEBUG( 4, "Setting MIN_TURN_TIME to %d usecs.\n",
-	       qos_tx->min_turn_time.value);
-	DEBUG( 4, "Setting LINK_DISC to %d secs.\n", 
-	       qos_tx->link_disc_time.value);
+	irda_qos_bits_to_value(&self->qos_tx);
+	irda_qos_bits_to_value(&self->qos_rx);
+
+	irlap_adjust_qos_settings(&self->qos_tx);
+
+	IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n", 
+		   self->qos_tx.baud_rate.value);
+	IRDA_DEBUG(2, "Setting DATA_SIZE to %d bytes\n",
+		   self->qos_tx.data_size.value);
+	IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n", 
+		   self->qos_tx.window_size.value);
+	IRDA_DEBUG(2, "Setting XBOFS to %d\n", 
+		   self->qos_tx.additional_bofs.value);
+	IRDA_DEBUG(2, "Setting MAX_TURN_TIME to %d ms.\n",
+		   self->qos_tx.max_turn_time.value);
+	IRDA_DEBUG(2, "Setting MIN_TURN_TIME to %d usecs.\n",
+		   self->qos_tx.min_turn_time.value);
+	IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n", 
+		   self->qos_tx.link_disc_time.value);
 #ifdef CONFIG_IRDA_COMPRESSION
-	DEBUG( 4, "Setting COMPRESSION to %d\n", 
-	       qos_tx->compression.value);
-#endif
-	
+	IRDA_DEBUG(2, "Setting COMPRESSION to %d\n", 
+		   self->qos_tx.compression.value);
+#endif	
+	return ret;
 }
 
 /*
@@ -270,100 +282,299 @@
  *    Insert QoS negotiaion pararameters into frame
  *
  */
-int irda_insert_qos_negotiation_params(struct qos_info *qos, __u8 *frame)
+int irlap_insert_qos_negotiation_params(struct irlap_cb *self, 
+					struct sk_buff *skb)
 {
-	int n;
-	__u16_host_order word;
+	int ret;
 
-	ASSERT( qos != NULL, return 0;);
-	ASSERT( frame != NULL, return 0;);
+	/* Insert data rate */
+	ret = irda_param_insert(self, PI_BAUD_RATE, skb->tail, 
+				skb_tailroom(skb), &irlap_param_info);
+	if (ret < 0)
+		return ret;
+	skb_put(skb, ret);
+
+	/* Insert max turnaround time */
+	ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb->tail, 
+				skb_tailroom(skb), &irlap_param_info);
+	if (ret < 0)
+		return ret;
+	skb_put(skb, ret);
+
+	/* Insert data size */
+	ret = irda_param_insert(self, PI_DATA_SIZE, skb->tail, 
+				skb_tailroom(skb), &irlap_param_info);
+	if (ret < 0)
+		return ret;
+	skb_put(skb, ret);
+
+	/* Insert window size */
+	ret = irda_param_insert(self, PI_WINDOW_SIZE, skb->tail, 
+				skb_tailroom(skb), &irlap_param_info);
+	if (ret < 0)
+		return ret;
+	skb_put(skb, ret);
+
+	/* Insert additional BOFs */
+	ret = irda_param_insert(self, PI_ADD_BOFS, skb->tail, 
+				skb_tailroom(skb), &irlap_param_info);
+	if (ret < 0)
+		return ret;
+	skb_put(skb, ret);
+
+	/* Insert minimum turnaround time */
+	ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb->tail, 
+				skb_tailroom(skb), &irlap_param_info);
+	if (ret < 0)
+		return ret;
+	skb_put(skb, ret);
+
+	/* Insert link disconnect/threshold time */
+	ret = irda_param_insert(self, PI_LINK_DISC, skb->tail, 
+				skb_tailroom(skb), &irlap_param_info);
+	if (ret < 0)
+		return ret;
+	skb_put(skb, ret);
+
+	return 0;
+}
 
-	n = 0;
+/*
+ * Function irlap_param_baud_rate (instance, param, get)
+ *
+ *    Negotiate data-rate
+ *
+ */
+static int irlap_param_baud_rate(void *instance, param_t *param, int get)
+{
+	__u16 final;
 
-	/* Set baud rate */
-	if (qos->baud_rate.bits < 256) {
-		frame[n++] = PI_BAUD_RATE;
-		frame[n++] = 0x01;   /* length 1 */
-		frame[n++] = qos->baud_rate.bits;
+	struct irlap_cb *self = (struct irlap_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
+
+	if (get) {
+		param->pv.i = self->qos_rx.baud_rate.bits;
+		IRDA_DEBUG(2, __FUNCTION__ "(), baud rate = 0x%02x\n", 
+			   param->pv.i);		
 	} else {
-		frame[n++] = PI_BAUD_RATE;
-		frame[n++] = 0x02;   /* length 2 */
-		
 		/* 
-		 *  qos->baud_rate.bits is in host byte order, so make sure
-		 *  we transmit it in little endian format 
+		 *  Stations must agree on baud rate, so calculate
+		 *  intersection 
 		 */
-		word.word = qos->baud_rate.bits;
-#ifdef __LITTLE_ENDIAN
-		frame[n++] = word.byte[0]; /* LSB */
-		frame[n++] = word.byte[1]; /* MSB */
-#else ifdef __BIG_ENDIAN
-		frame[n++] = word.byte[1]; /* LSB */
-		frame[n++] = word.byte[0]; /* MSB */
-#endif
+		IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", param->pv.s);
+		final = param->pv.s & self->qos_rx.baud_rate.bits;
+
+		IRDA_DEBUG(2, "Final BAUD_RATE: 0x%04x\n", final);
+		self->qos_tx.baud_rate.bits = final;
+		self->qos_rx.baud_rate.bits = final;
 	}
 
-	/* Set Maximum Turn Around Time */
-	frame[n++] = PI_MAX_TURN_TIME;
-	frame[n++] = 0x01;   /* length 1 */
-	frame[n++] = qos->max_turn_time.bits;
-	
-	/* Set data size */
-	frame[n++] = PI_DATA_SIZE;
-	frame[n++] = 0x01;   /* length 1 */
-	frame[n++] = qos->data_size.bits;
-
-	/* Set window size */
-	frame[n++] = PI_WINDOW_SIZE;
-	frame[n++] = 0x01;   /* length 1 */
-	frame[n++] = qos->window_size.bits;
-
-	/* Set additional BOFs */
-	frame[n++] = PI_ADD_BOFS;
-	frame[n++] = 0x01;   /* length 1 */
-	frame[n++] = qos->additional_bofs.bits;
-
-	/* Set minimum turn around time */
-	frame[n++] = PI_MIN_TURN_TIME;
-	frame[n++] = 0x01;   /* length 1 */
-	frame[n++] = qos->min_turn_time.bits;
-
-	/* Set Link Disconnect/Threshold Time */
-	frame[n++] = PI_LINK_DISC;
-	frame[n++] = 0x01;   /* length 1 */
-	frame[n++] = qos->link_disc_time.bits;
-#ifdef CONFIG_IRDA_COMPRESSION
-	/* Set compression bits*/
-	if ( qos->compression.bits) {
-		DEBUG( 4, __FUNCTION__ "(), inserting compresion bits\n");
-		frame[n++] = PI_COMPRESSION;
-		frame[n++] = 0x01;   /* length 1 */
-		frame[n++] = qos->compression.bits;
+	return 0;
+}
+
+/*
+ * Function irlap_param_link_disconnect (instance, param, get)
+ *
+ *    Negotiate link disconnect/threshold time. 
+ *
+ */
+static int irlap_param_link_disconnect(void *instance, param_t *param, int get)
+{
+	__u16 final;
+	
+	struct irlap_cb *self = (struct irlap_cb *) instance;
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	
+	if (get)
+		param->pv.b = self->qos_rx.link_disc_time.bits;
+	else {
+		/*  
+		 *  Stations must agree on link disconnect/threshold 
+		 *  time.
+		 */
+		IRDA_DEBUG(2, "LINK_DISC: %02x\n", param->pv.b);
+		final = param->pv.b & self->qos_rx.link_disc_time.bits;
+
+		IRDA_DEBUG(2, "Final LINK_DISC: %02x\n", final);
+		self->qos_tx.link_disc_time.bits = final;
+		self->qos_rx.link_disc_time.bits = final;
 	}
-#endif
-	return n;
+	return 0;
 }
 
-int byte_value( __u8 byte, int *array) 
+/*
+ * Function irlap_param_max_turn_time (instance, param, get)
+ *
+ *    Negotiate the maximum turnaround time. This is a type 1 parameter and
+ *    will be negotiated independently for each station
+ *
+ */
+static int irlap_param_max_turn_time(void *instance, param_t *param, int get)
 {
-	int index;
+	struct irlap_cb *self = (struct irlap_cb *) instance;
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	
+	if (get)
+		param->pv.b = self->qos_rx.max_turn_time.bits;
+	else
+		self->qos_tx.max_turn_time.bits = param->pv.b;
+
+	return 0;
+}
+
+/*
+ * Function irlap_param_data_size (instance, param, get)
+ *
+ *    Negotiate the data size. This is a type 1 parameter and
+ *    will be negotiated independently for each station
+ *
+ */
+static int irlap_param_data_size(void *instance, param_t *param, int get)
+{
+	struct irlap_cb *self = (struct irlap_cb *) instance;
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	
+	if (get)
+		param->pv.b = self->qos_rx.data_size.bits;
+	else
+		self->qos_tx.data_size.bits = param->pv.b;
 
-	ASSERT( array != NULL, return -1;);
+	return 0;
+}
+
+/*
+ * Function irlap_param_window_size (instance, param, get)
+ *
+ *    Negotiate the window size. This is a type 1 parameter and
+ *    will be negotiated independently for each station
+ *
+ */
+static int irlap_param_window_size(void *instance, param_t *param, int get)
+{
+	struct irlap_cb *self = (struct irlap_cb *) instance;
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	
+	if (get)
+		param->pv.b = self->qos_rx.window_size.bits;
+	else
+		self->qos_tx.window_size.bits = param->pv.b;
 
-	index = msb_index( byte);
-	return index_value( index, array);
+	return 0;
 }
 
+/*
+ * Function irlap_param_additional_bofs (instance, param, get)
+ *
+ *    Negotiate additional BOF characters. This is a type 1 parameter and
+ *    will be negotiated independently for each station.
+ */
+static int irlap_param_additional_bofs(void *instance, param_t *param, int get)
+{
+	struct irlap_cb *self = (struct irlap_cb *) instance;
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	
+	if (get)
+		param->pv.b = self->qos_rx.additional_bofs.bits;
+	else
+		self->qos_tx.additional_bofs.bits = param->pv.b;
 
-/* __u8 value_byte( int value, int *array) */
-/* { */
-/* 	int index; */
-/* 	__u8 byte; */
+	return 0;
+}
 
-/* 	index = value_index( value, array); */
+/*
+ * Function irlap_param_min_turn_time (instance, param, get)
+ *
+ *    Negotiate the minimum turn around time. This is a type 1 parameter and
+ *    will be negotiated independently for each station
+ */
+static int irlap_param_min_turn_time(void *instance, param_t *param, int get)
+{
+	struct irlap_cb *self = (struct irlap_cb *) instance;
+	
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
+	
+	if (get)
+		param->pv.b = self->qos_rx.min_turn_time.bits;
+	else
+		self->qos_tx.min_turn_time.bits = param->pv.b;
 
-/* 	byte =  */
-/* } */
+	return 0;
+}
+
+/*
+ * Function irlap_max_line_capacity (speed, max_turn_time, min_turn_time)
+ *
+ *    Calculate the maximum line capacity
+ *
+ */
+__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
+{
+	__u32 line_capacity;
+	int i,j;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, max_turn_time=%d\n",
+		   speed, max_turn_time);
+
+	i = value_index(speed, baud_rates);
+	j = value_index(max_turn_time, max_turn_times);
+
+	ASSERT(((i >=0) && (i <=10)), return 0;);
+	ASSERT(((j >=0) && (j <=4)), return 0;);
+
+	line_capacity = max_line_capacities[i][j];
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), line capacity=%d bytes\n", 
+		   line_capacity);
+	
+	return line_capacity;
+}
+
+__u32 irlap_requested_line_capacity(struct qos_info *qos)
+{	__u32 line_capacity;
+	
+	line_capacity = qos->window_size.value * 
+		(qos->data_size.value + 6 + qos->additional_bofs.value) +
+		irlap_min_turn_time_in_bytes(qos->baud_rate.value, 
+					     qos->min_turn_time.value);
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), requested line capacity=%d\n",
+		   line_capacity);
+	
+	return line_capacity;			       		  
+}
+
+__u32 irlap_min_turn_time_in_bytes(__u32 speed, __u32 min_turn_time)
+{
+	__u32 bytes;
+	
+	bytes = speed * min_turn_time / 10000000;
+	
+	return bytes;
+}
+
+__u32 byte_value(__u8 byte, __u32 *array) 
+{
+	int index;
+
+	ASSERT(array != NULL, return -1;);
+
+	index = msb_index(byte);
+
+	return index_value(index, array);
+}
 
 /*
  * Function msb_index (word)
@@ -371,18 +582,18 @@
  *    Returns index to most significant bit (MSB) in word
  *
  */
-int msb_index ( __u16 word) 
+int msb_index (__u16 word) 
 {
 	__u16 msb = 0x8000;
 	int index = 15;   /* Current MSB */
 	
-	while( msb) {
-		if ( word & msb)
+	while (msb) {
+		if (word & msb)
 			break;   /* Found it! */
 		msb >>=1;
 		index--;
 	}
-
+	
 	return index;
 }
 
@@ -391,12 +602,12 @@
  *
  *    Returns the index to the value in the specified array
  */
-int value_index( int value, int *array) 
+int value_index(__u32 value, __u32 *array) 
 {
 	int i;
 	
-	for( i=0;i<8;i++)
-		if ( array[i] == value)
+	for (i=0;i<8;i++)
+		if (array[i] == value)
 			break;
 	return i;
 }
@@ -407,44 +618,50 @@
  *    Returns value to index in array, easy!
  *
  */
-int index_value( int index, int *array) 
+__u32 index_value(int index, __u32 *array) 
 {
 	return array[index];
 }
 
-void irda_qos_bits_to_value( struct qos_info *qos)
+void irda_qos_bits_to_value(struct qos_info *qos)
 {
 	int index;
 
-	ASSERT( qos != NULL, return;);
+	ASSERT(qos != NULL, return;);
 	
-	index = msb_index( qos->baud_rate.bits);
+	index = msb_index(qos->baud_rate.bits);
 	qos->baud_rate.value = baud_rates[index];
 
-	index = msb_index( qos->data_size.bits);
-	qos->data_size.value = data_size[index];
+	index = msb_index(qos->data_size.bits);
+	qos->data_size.value = data_sizes[index];
 
-	index = msb_index( qos->window_size.bits);
+	index = msb_index(qos->window_size.bits);
 	qos->window_size.value = index+1;
 
-	index = msb_index( qos->min_turn_time.bits);
-	qos->min_turn_time.value = min_turn_time[index];
+	index = msb_index(qos->min_turn_time.bits);
+	qos->min_turn_time.value = min_turn_times[index];
 	
-	index = msb_index( qos->max_turn_time.bits);
-	qos->max_turn_time.value = max_turn_time[index];
+	index = msb_index(qos->max_turn_time.bits);
+	qos->max_turn_time.value = max_turn_times[index];
 
-	index = msb_index( qos->link_disc_time.bits);
-	qos->link_disc_time.value = link_disc_time[index];
+	index = msb_index(qos->link_disc_time.bits);
+	qos->link_disc_time.value = link_disc_times[index];
 	
-	index = msb_index( qos->additional_bofs.bits);
+	index = msb_index(qos->additional_bofs.bits);
 	qos->additional_bofs.value = add_bofs[index];
 
 #ifdef CONFIG_IRDA_COMPRESSION
-	index = msb_index( qos->compression.bits);
-	if ( index >= 0)
-		qos->compression.value = compression[index];
+	index = msb_index(qos->compression.bits);
+	if (index >= 0)
+		qos->compression.value = compressions[index];
 	else 
 		qos->compression.value = 0;
 #endif
 }
+
+
+
+
+
+
 
diff -urN linux-2.2.15-pre2/net/irda/timer.c linux/net/irda/timer.c
--- linux-2.2.15-pre2/net/irda/timer.c	Sun Mar  7 15:26:44 1999
+++ linux/net/irda/timer.c	Mon Dec  3 21:57:53 2001
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Thu Feb  4 10:49:38 1999
+ * Modified at:   Wed Dec  8 12:50:34 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 
@@ -31,84 +32,88 @@
 #include <net/irda/irlap.h>
 #include <net/irda/irlmp_event.h>
 
-static void irlap_slot_timer_expired( unsigned long data);
-static void irlap_query_timer_expired( unsigned long data);
-static void irlap_final_timer_expired( unsigned long data);
-static void irlap_wd_timer_expired( unsigned long data);
-static void irlap_backoff_timer_expired( unsigned long data);
+static void irlap_slot_timer_expired(void* data);
+static void irlap_query_timer_expired(void* data);
+static void irlap_final_timer_expired(void* data);
+static void irlap_wd_timer_expired(void* data);
+static void irlap_backoff_timer_expired(void* data);
 
-static void irda_device_media_busy_expired( unsigned long data); 
+static void irlap_media_busy_expired(void* data); 
 /*
  * Function irda_start_timer (timer, timeout)
  *
  *    Start an IrDA timer
  *
  */
-void irda_start_timer( struct timer_list *ptimer, int timeout, int data,
-		       TIMER_CALLBACK callback) 
+void irda_start_timer(struct timer_list *ptimer, int timeout, void *data,
+		      TIMER_CALLBACK callback) 
 {
-	del_timer( ptimer);
+	del_timer(ptimer);
  
 	ptimer->data = (unsigned long) data;
-	ptimer->function = callback;
+
+	/* 
+	 * For most architectures void * is the same as unsigned long, but
+	 * at least we try to use void * as long as possible. Since the 
+	 * timer functions use unsigned long, we cast the function here
+	 */
+	ptimer->function = (void (*)(unsigned long)) callback;
 	ptimer->expires = jiffies + timeout;
 	
-	add_timer( ptimer);
+	add_timer(ptimer);
 }
 
-inline void irlap_start_slot_timer( struct irlap_cb *self, int timeout)
+void irlap_start_slot_timer(struct irlap_cb *self, int timeout)
 {
-	irda_start_timer( &self->slot_timer, timeout, (unsigned long) self, 
-			  irlap_slot_timer_expired);
+	irda_start_timer(&self->slot_timer, timeout, (void *) self, 
+			 irlap_slot_timer_expired);
 }
 
-inline void irlap_start_query_timer( struct irlap_cb *self, int timeout)
+void irlap_start_query_timer(struct irlap_cb *self, int timeout)
 {
-	irda_start_timer( &self->query_timer, timeout, (unsigned long) self, 
+	irda_start_timer( &self->query_timer, timeout, (void *) self, 
 			  irlap_query_timer_expired);
 }
 
-inline void irlap_start_final_timer( struct irlap_cb *self, int timeout)
+void irlap_start_final_timer(struct irlap_cb *self, int timeout)
 {
-	irda_start_timer( &self->final_timer, timeout,  (unsigned long) self, 
-			  irlap_final_timer_expired);
+	irda_start_timer(&self->final_timer, timeout, (void *) self, 
+			 irlap_final_timer_expired);
 }
 
-inline void irlap_start_wd_timer( struct irlap_cb *self, int timeout)
+void irlap_start_wd_timer(struct irlap_cb *self, int timeout)
 {
-	irda_start_timer( &self->wd_timer, timeout, (unsigned long) self, 
-			  irlap_wd_timer_expired);
+	irda_start_timer(&self->wd_timer, timeout, (void *) self, 
+			 irlap_wd_timer_expired);
 }
 
-inline void irlap_start_backoff_timer( struct irlap_cb *self, int timeout)
+void irlap_start_backoff_timer(struct irlap_cb *self, int timeout)
 {
-	irda_start_timer( &self->backoff_timer, timeout, (unsigned long) self, 
-			  irlap_backoff_timer_expired);
+	irda_start_timer(&self->backoff_timer, timeout, (void *) self, 
+			 irlap_backoff_timer_expired);
 }
 
-inline void irda_device_start_mbusy_timer( struct irda_device *self) 
+void irlap_start_mbusy_timer(struct irlap_cb *self)
 {
-	irda_start_timer( &self->media_busy_timer, MEDIABUSY_TIMEOUT, 
-			  (unsigned long) self, 
-			  irda_device_media_busy_expired);
-	
+	irda_start_timer(&self->media_busy_timer, MEDIABUSY_TIMEOUT, 
+			 (void *) self, irlap_media_busy_expired);
 }
 
-inline void irlmp_start_watchdog_timer( struct lsap_cb *self, int timeout) 
+void irlmp_start_watchdog_timer(struct lsap_cb *self, int timeout) 
 {
-	irda_start_timer( &self->watchdog_timer, timeout, (unsigned long) self,
-			  irlmp_watchdog_timer_expired);
+	irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
+			 irlmp_watchdog_timer_expired);
 }
 
-inline void irlmp_start_discovery_timer(struct irlmp_cb *self, int timeout) 
+void irlmp_start_discovery_timer(struct irlmp_cb *self, int timeout) 
 {
-	irda_start_timer(&self->discovery_timer, timeout, (unsigned long) self,
+	irda_start_timer(&self->discovery_timer, timeout, (void *) self,
 			 irlmp_discovery_timer_expired);
 }
 
-inline void irlmp_start_idle_timer(struct lap_cb *self, int timeout) 
+void irlmp_start_idle_timer(struct lap_cb *self, int timeout) 
 {
-	irda_start_timer(&self->idle_timer, timeout, (unsigned long) self,
+	irda_start_timer(&self->idle_timer, timeout, (void *) self,
 			 irlmp_idle_timer_expired);
 }
 
@@ -118,16 +123,14 @@
  *    IrLAP slot timer has expired
  *
  */
-static void irlap_slot_timer_expired( unsigned long data)
+static void irlap_slot_timer_expired(void *data)
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	DEBUG( 4, "Slot timer expired!\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	irlap_do_event( self, SLOT_TIMER_EXPIRED, NULL, NULL);
+	irlap_do_event(self, SLOT_TIMER_EXPIRED, NULL, NULL);
 } 
 
 /*
@@ -136,16 +139,14 @@
  *    IrLAP query timer has expired
  *
  */
-static void irlap_query_timer_expired( unsigned long data)
+static void irlap_query_timer_expired(void *data)
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	DEBUG( 4, "Query timer expired!\n");
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-
-	irlap_do_event( self, QUERY_TIMER_EXPIRED, NULL, NULL);
+	irlap_do_event(self, QUERY_TIMER_EXPIRED, NULL, NULL);
 } 
 
 /*
@@ -154,16 +155,14 @@
  *    
  *
  */
-static void irlap_final_timer_expired( unsigned long data)
+static void irlap_final_timer_expired(void *data)
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	DEBUG( 4, "Final timer expired!\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	irlap_do_event( self, FINAL_TIMER_EXPIRED, NULL, NULL);
+	irlap_do_event(self, FINAL_TIMER_EXPIRED, NULL, NULL);
 }
 
 /*
@@ -172,16 +171,14 @@
  *    
  *
  */
-static void irlap_wd_timer_expired( unsigned long data)
+static void irlap_wd_timer_expired(void *data)
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 	
-	DEBUG( 4, "WD timer expired!\n");
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	
-	irlap_do_event( self, WD_TIMER_EXPIRED, NULL, NULL);
+	irlap_do_event(self, WD_TIMER_EXPIRED, NULL, NULL);
 }
 
 /*
@@ -190,16 +187,14 @@
  *    
  *
  */
-static void irlap_backoff_timer_expired( unsigned long data)
+static void irlap_backoff_timer_expired(void *data)
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 	
-	DEBUG( 0, "Backoff timer expired!\n");
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 	
-	irlap_do_event( self, BACKOFF_TIMER_EXPIRED, NULL, NULL);
+	irlap_do_event(self, BACKOFF_TIMER_EXPIRED, NULL, NULL);
 }
 
 
@@ -208,14 +203,15 @@
  *
  *    
  */
-void irda_device_media_busy_expired( unsigned long data) 
+void irlap_media_busy_expired(void* data)
 {
-	struct irda_device *self = ( struct irda_device *) data;
+	struct irlap_cb *self = (struct irlap_cb *) data;
 
-	DEBUG( 4, "Mediabusy timer expired!\n");
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+
+	irda_device_set_media_busy(self->netdev, FALSE);
 
-	irda_device_set_media_busy( self, FALSE);
+	/* Send any pending Ultra frames if any */
+	if (!skb_queue_empty(&self->txq_ultra))
+		irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
 }
diff -urN linux-2.2.15-pre2/net/irda/wrapper.c linux/net/irda/wrapper.c
--- linux-2.2.15-pre2/net/irda/wrapper.c	Mon Jun  7 16:19:59 1999
+++ linux/net/irda/wrapper.c	Mon Dec  3 21:57:53 2001
@@ -3,13 +3,15 @@
  * Filename:      wrapper.c
  * Version:       1.2
  * Description:   IrDA SIR async wrapper layer
- * Status:        Experimental.
+ * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri May 28 20:30:24 1999
+ * Modified at:   Sat Jan 15 13:32:27 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * Modified at:   Fri May 28  3:11 CST 1999
+ * Modified by:   Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -24,6 +26,7 @@
  ********************************************************************/
 
 #include <linux/skbuff.h>
+#include <linux/string.h>
 #include <asm/byteorder.h>
 
 #include <net/irda/irda.h>
@@ -36,12 +39,21 @@
 
 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_outside_frame(struct device *dev, 
+				struct net_device_stats *stats, 
+				iobuff_t *rx_buff, __u8 byte);
+static void state_begin_frame(struct device *dev, 
+			      struct net_device_stats *stats, 
+			      iobuff_t *rx_buff, __u8 byte);
+static void state_link_escape(struct device *dev, 
+			      struct net_device_stats *stats, 
+			      iobuff_t *rx_buff, __u8 byte);
+static void state_inside_frame(struct device *dev, 
+			       struct net_device_stats *stats, 
+			       iobuff_t *rx_buff, __u8 byte);
 
-static void (*state[])(struct irda_device *idev, __u8 byte) = 
+static void (*state[])(struct device *dev, struct net_device_stats *stats, 
+		       iobuff_t *rx_buff, __u8 byte) = 
 { 
 	state_outside_frame,
 	state_begin_frame,
@@ -50,16 +62,16 @@
 };
 
 /*
- * Function async_wrap (skb, *tx_buff)
+ * Function async_wrap (skb, *tx_buff, buffsize)
  *
  *    Makes a new buffer with wrapping and stuffing, should check that 
  *    we don't get tx buffer overflow.
  */
 int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
 {
+	int xbofs;
  	int i;
 	int n;
-	int xbofs;
 	union {
 		__u16 value;
 		__u8 bytes[2];
@@ -69,21 +81,28 @@
 	fcs.value = INIT_FCS;
 	n = 0;
 
-	if (skb->len > 2048) {
-		DEBUG(0, __FUNCTION__ "Warning size=%d of sk_buff to big!\n", 
-		      (int) skb->len);
-		return 0;
-	}
-	
 	/*
 	 *  Send  XBOF's for required min. turn time and for the negotiated
 	 *  additional XBOFS
 	 */
-	if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC) {
-		DEBUG(1, __FUNCTION__ "(), wrong magic in skb!\n");
+	if (((struct irda_skb_cb *)(skb->cb))->magic != LAP_MAGIC) {
+		/* 
+		 * This will happen for all frames sent from user-space.
+		 * Nothing to worry about, but we set the default number of 
+		 * BOF's
+		 */
+		IRDA_DEBUG(1, __FUNCTION__ "(), wrong magic in skb!\n");
 		xbofs = 10;
 	} else
-		xbofs = ((struct irlap_skb_cb *)(skb->cb))->xbofs;
+		xbofs = ((struct irda_skb_cb *)(skb->cb))->xbofs;
+
+	IRDA_DEBUG(4, __FUNCTION__ "(), xbofs=%d\n", xbofs);
+
+	/* Check that we never use more than 115 + 48 xbofs */
+	if (xbofs > 163) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), too many xbofs (%d)\n", xbofs);
+		xbofs = 163;
+	}
 
 	memset(tx_buff+n, XBOF, xbofs);
 	n += xbofs;
@@ -119,40 +138,6 @@
 }
 
 /*
- * Function async_bump (idev)
- *
- *    Got a frame, make a copy of it, and pass it up the stack!
- *
- */
-static inline void async_bump(struct irda_device *idev, __u8 *buf, int len)
-{
-       	struct sk_buff *skb;
-
-	skb = dev_alloc_skb(len+1);
-	if (!skb)  {
-		idev->stats.rx_dropped++;
-		return;
-	}
-
-	/*  Align IP header to 20 bytes */
-	skb_reserve(skb, 1);
-	
-        /* Copy data without CRC */
-	memcpy(skb_put(skb, len-2), buf, len-2); 
-	
-	/* 
-	 *  Feed it to IrLAP layer 
-	 */
-	skb->dev = &idev->netdev;
-	skb->mac.raw  = skb->data;
-	skb->protocol = htons(ETH_P_IRDA);
-
-	netif_rx(skb);
-	idev->stats.rx_packets++;
-	idev->stats.rx_bytes += skb->len;	
-}
-
-/*
  * Function stuff_byte (byte, buf)
  *
  *    Byte stuff one single byte and put the result in buffer pointed to by
@@ -179,36 +164,75 @@
 }
 
 /*
- * Function async_unwrap (skb)
+ * Function async_bump (buf, len, stats)
+ *
+ *    Got a frame, make a copy of it, and pass it up the stack! We can try
+ *    to inline it since it's only called from state_inside_frame
+ */
+inline void async_bump(struct device *dev, struct net_device_stats *stats,
+		       __u8 *buf, int len)
+{
+       	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(len+1);
+	if (!skb)  {
+		stats->rx_dropped++;
+		return;
+	}
+
+	/* Align IP header to 20 bytes */
+	skb_reserve(skb, 1);
+	
+        /* Copy data without CRC */
+	memcpy(skb_put(skb, len-2), buf, len-2); 
+	
+	/* Feed it to IrLAP layer */
+	skb->dev = dev;
+	skb->mac.raw  = skb->data;
+	skb->protocol = htons(ETH_P_IRDA);
+
+	netif_rx(skb);
+
+	stats->rx_packets++;
+	stats->rx_bytes += len;	
+}
+
+/*
+ * Function async_unwrap_char (dev, rx_buff, byte)
  *
  *    Parse and de-stuff frame received from the IrDA-port
  *
  */
-inline void async_unwrap_char(struct irda_device *idev, __u8 byte)
+inline void async_unwrap_char(struct device *dev, 
+			      struct net_device_stats *stats, 
+			      iobuff_t *rx_buff, __u8 byte)
 {
-	(*state[idev->rx_buff.state]) (idev, byte);
+	(*state[rx_buff->state])(dev, stats, rx_buff, byte);
 }
 	 
 /*
- * Function state_outside_frame (idev, byte)
+ * Function state_outside_frame (dev, rx_buff, byte)
  *
- *    
+ *    Not receiving any frame (or just bogus data)
  *
  */
-static void state_outside_frame(struct irda_device *idev, __u8 byte)
+static void state_outside_frame(struct device *dev, 
+				struct net_device_stats *stats, 
+				iobuff_t *rx_buff, __u8 byte)
 {
 	switch (byte) {
 	case BOF:
-		idev->rx_buff.state = BEGIN_FRAME;
-		idev->rx_buff.in_frame = TRUE;
+		rx_buff->state = BEGIN_FRAME;
+		rx_buff->in_frame = TRUE;
 		break;
 	case XBOF:
 		/* idev->xbofs++; */
 		break;
 	case EOF:
-		irda_device_set_media_busy( idev, TRUE);
+		irda_device_set_media_busy(dev, TRUE);
 		break;
 	default:
+		irda_device_set_media_busy(dev, TRUE);
 		break;
 	}
 }
@@ -219,58 +243,58 @@
  *    Begin of frame detected
  *
  */
-static void state_begin_frame(struct irda_device *idev, __u8 byte)
+static void state_begin_frame(struct device *dev, 
+			      struct net_device_stats *stats, 
+			      iobuff_t *rx_buff, __u8 byte)
 {
+	/* Time to initialize receive buffer */
+	rx_buff->data = rx_buff->head;
+	rx_buff->len = 0;
+	rx_buff->fcs = INIT_FCS;
+
 	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;
+		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++;
+		rx_buff->state = OUTSIDE_FRAME;
+		IRDA_DEBUG(1, __FUNCTION__ "(), abort frame\n");
+		stats->rx_errors++;
+		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;
+	default:
+		rx_buff->data[rx_buff->len++] = byte;
+		rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
+		rx_buff->state = INSIDE_FRAME;
 		break;
 	}
 }
 
 /*
- * Function state_link_escape (idev, byte)
+ * Function state_link_escape (dev, byte)
  *
- *    
+ *    Found link escape character
  *
  */
-static void state_link_escape(struct irda_device *idev, __u8 byte)
+static void state_link_escape(struct device *dev, 
+			      struct net_device_stats *stats, 
+			      iobuff_t *rx_buff, __u8 byte)
 {
 	switch (byte) {
 	case BOF: /* New frame? */
-		idev->rx_buff.state = BEGIN_FRAME;
-		irda_device_set_media_busy(idev, TRUE);
+		rx_buff->state = BEGIN_FRAME;
+		irda_device_set_media_busy(dev, TRUE);
 		break;
 	case CE:
-		DEBUG(4, "WARNING: State not defined\n");
+		WARNING(__FUNCTION__ "(), state not defined\n");
 		break;
 	case EOF: /* Abort frame */
-		idev->rx_buff.state = OUTSIDE_FRAME;
+		rx_buff->state = OUTSIDE_FRAME;
 		break;
 	default:
 		/* 
@@ -278,59 +302,65 @@
 		 *  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;
+		if (rx_buff->len < rx_buff->truesize)  {
+			rx_buff->data[rx_buff->len++] = byte;
+			rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
+			rx_buff->state = INSIDE_FRAME;
 		} else {
-			DEBUG(1, __FUNCTION__ 
-			      "(), Rx buffer overflow, aborting\n");
-			idev->rx_buff.state = OUTSIDE_FRAME;
+			IRDA_DEBUG(1, __FUNCTION__ "(), rx buffer overflow\n");
+			rx_buff->state = OUTSIDE_FRAME;
 		}
 		break;
 	}
 }
 
 /*
- * Function state_inside_frame (idev, byte)
+ * Function state_inside_frame (dev, byte)
  *
  *    Handle bytes received within a frame
  *
  */
-static void state_inside_frame(struct irda_device *idev, __u8 byte)
+static void state_inside_frame(struct device *dev, 
+			       struct net_device_stats *stats,
+			       iobuff_t *rx_buff, __u8 byte)
 {
+	int ret = 0; 
+
 	switch (byte) {
 	case BOF: /* New frame? */
-		idev->rx_buff.state = BEGIN_FRAME;
-		irda_device_set_media_busy(idev, TRUE);
+		rx_buff->state = BEGIN_FRAME;
+		irda_device_set_media_busy(dev, TRUE);
 		break;
 	case CE: /* Stuffed char */
-		idev->rx_buff.state = LINK_ESCAPE;
+		rx_buff->state = LINK_ESCAPE;
 		break;
 	case EOF: /* End of frame */
-		idev->rx_buff.state = OUTSIDE_FRAME;
-		idev->rx_buff.in_frame = FALSE;
+		rx_buff->state = OUTSIDE_FRAME;
+		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);
+		/* Test FCS and signal success if the frame is good */
+		if (rx_buff->fcs == GOOD_FCS) {
+			/* Deliver frame */
+			async_bump(dev, stats, rx_buff->data, rx_buff->len);
+			ret = TRUE;
+			break;
 		} else {
 			/* Wrong CRC, discard frame!  */
-			irda_device_set_media_busy(idev, TRUE); 
-			
-			idev->stats.rx_errors++;
-			idev->stats.rx_crc_errors++;
+			irda_device_set_media_busy(dev, TRUE); 
+
+			IRDA_DEBUG(1, __FUNCTION__ "(), crc error\n");
+			stats->rx_errors++;
+			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);
+		if (rx_buff->len < rx_buff->truesize)  {
+			rx_buff->data[rx_buff->len++] = byte;
+			rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
 		} else {
-			DEBUG(1, __FUNCTION__ 
+			IRDA_DEBUG(1, __FUNCTION__ 
 			      "(), Rx buffer overflow, aborting\n");
-			idev->rx_buff.state = OUTSIDE_FRAME;
+			rx_buff->state = OUTSIDE_FRAME;
 		}
 		break;
 	}
diff -urN linux-2.2.15-pre2/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- linux-2.2.15-pre2/net/wanrouter/wanmain.c	Tue Jan  4 10:12:27 2000
+++ linux/net/wanrouter/wanmain.c	Mon Dec  3 21:57:53 2001
@@ -118,6 +118,7 @@
 {
 	int err;
 	extern void wanpipe_init(void);
+	extern void wanpipe_init2(void);
 
 	printk(KERN_INFO "%s v%u.%u %s\n",
 		fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright);
@@ -132,6 +133,7 @@
 
 #ifdef CONFIG_VENDOR_SANGOMA
 	wanpipe_init();
+	wanpipe_init2();
 #endif	
  
 	return err;
diff -urN linux-2.2.15-pre2/scripts/Menuconfig linux/scripts/Menuconfig
--- linux-2.2.15-pre2/scripts/Menuconfig	Tue Jan  4 10:12:27 2000
+++ linux/scripts/Menuconfig	Mon Dec  3 21:57:53 2001
@@ -1220,7 +1220,7 @@
 
 DIALOG="./scripts/lxdialog/lxdialog"
 
-kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}"
+kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
 
 backtitle="Linux Kernel v$kernel_version Configuration"
 
