diff -u --recursive --new-file v2.3.2/linux/CREDITS linux/CREDITS
--- v2.3.2/linux/CREDITS	Sat May 15 23:46:02 1999
+++ linux/CREDITS	Sun May 16 10:26:44 1999
@@ -1534,6 +1534,15 @@
 E: orc@pell.chi.il.us
 D: improved memory detection code.
 
+N: Mikulas Patocka
+E: mikulas@artax.karlin.mff.cuni.cz
+W: http://artax.karlin.mff.cuni.cz/~mikulas/
+P: 1024/BB11D2D5 A0 F1 28 4A C4 14 1E CF  92 58 7A 8F 69 BC A4 D3
+D: Read/write HPFS filesystem
+S: Weissova 8
+S: 644 00 Brno
+S: Czech Republic
+
 N: Vojtech Pavlik
 E: vojtech@ucw.cz
 D: Joystick driver
@@ -1839,7 +1848,7 @@
 
 N: Chris Smith
 E: csmith@convex.com
-D: HPFS filesystem
+D: Read only HPFS filesystem
 S: Richardson, Texas
 S: USA
 
diff -u --recursive --new-file v2.3.2/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.2/linux/Documentation/Configure.help	Sat May 15 23:46:02 1999
+++ linux/Documentation/Configure.help	Sun May 16 10:26:44 1999
@@ -7322,14 +7322,24 @@
   directories that are mount points on the local filesystem (this is
   how nfsd behaves on Sun systems), say yes here. If unsure, say N.
 
-OS/2 HPFS filesystem support (read only)
+OS/2 HPFS filesystem support (read/write)
 CONFIG_HPFS_FS
   OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
   is the filesystem used for organizing files on OS/2 hard disk
-  partitions. Say Y if you want to be able to read files from an OS/2
-  HPFS partition of your hard drive. OS/2 floppies however are in
-  regular MSDOS format, so you don't need this option in order to be
-  able to read them. Read Documentation/filesystems/hpfs.txt. 
+  partitions. Say Y if you want to be able to read and write files
+  on an OS/2 HPFS partition of your hard drive. OS/2 floppies however
+  are in regular MSDOS format, so you don't need this option in order
+  to be able to read them. Read Documentation/filesystems/hpfs.txt. 
+  
+  Write support is new and experimental. I don't think it's so
+  "experimental" that it corrupts disks. (but you know: "There's no
+  warranty") There are many checks and filesystem is remounted read-only
+  if any inconsistency found. I use it quite long time and it works.
+
+  This driver may not be able to write to HPFS386 disks on Warp server.
+  HPFS386 on Warp client seems to work ok. If some unknown HPFS386
+  structures are deteced, they are not destroyed and filesystem is
+  remounted read-only.
 
   This filesystem is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
diff -u --recursive --new-file v2.3.2/linux/Documentation/filesystems/hpfs.txt linux/Documentation/filesystems/hpfs.txt
--- v2.3.2/linux/Documentation/filesystems/hpfs.txt	Sat May 15 23:46:02 1999
+++ linux/Documentation/filesystems/hpfs.txt	Sun May 16 10:26:44 1999
@@ -1,4 +1,4 @@
-Read/Write HPFS 1.98b
+Read/Write HPFS 1.99b
 1998-1999, Mikulas Patocka
 
 email: mikulas@artax.karlin.mff.cuni.cz
@@ -58,9 +58,9 @@
 because kernel creates different files with names like bootsect.S and
 bootsect.s. When searching for file thats name has characters >= 128, codepages
 are used - see below.
-OS/2 ignores dots and spaces at the end of file name, so this driver does. If
-you create 'a. ...', the file 'a' will be created, but you can still access it
-under names 'a.', 'a..', 'a .  . . ' etc.
+OS/2 ignores dots and spaces at the end of file name, so this driver does as
+well. If you create 'a. ...', the file 'a' will be created, but you can still
+access it under names 'a.', 'a..', 'a .  . . ' etc.
 
 
 Extended attributes
@@ -162,9 +162,6 @@
 Renaming files so that only case changes doesn't work. This driver supports it
 but vfs doesn't. Something like 'mv file FILE' won't work.
 
-When you try to create file with bad filename (too long or containing forbidden
-characters), you get ENOENT error instead of EINVAL or ENAMETOOLONG.
-
 All atimes and directory mtimes are not updated. That's because of performance
 reasons. If you extremely wish to update them, let me know, I'll write it (but
 it will be slow).
@@ -266,6 +263,10 @@
        Fixed a bug when chmoding or chowning root directory
 1.98 Fixed a deadlock when using old_readdir
      Better directory handling; workaround for "unbalanced tree" bug in OS/2
+1.99 Corrected a possible problem when there's not enough space while deleting
+	file
+     Now it tries to truncate the file if there's not enough space when deleting
+     Removed a lot of redundat code
 
 
  vim: set textwidth=80:
diff -u --recursive --new-file v2.3.2/linux/Documentation/mtrr.txt linux/Documentation/mtrr.txt
--- v2.3.2/linux/Documentation/mtrr.txt	Mon May 10 10:32:45 1999
+++ linux/Documentation/mtrr.txt	Sun May 16 10:13:20 1999
@@ -1,5 +1,5 @@
 MTRR (Memory Type Range Register) control
-2 May 1998
+16 May 1999
 Richard Gooch
 <rgooch@atnf.csiro.au>
 
@@ -31,8 +31,10 @@
 reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
 reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
 ===============================================================================
-Creating MTRRs from the shell:
+Creating MTRRs from the C-shell:
 # echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
+or if you use bash:
+# echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr
 
 And the result thereof:
 % cat /proc/mtrr
@@ -79,8 +81,10 @@
 NOTE: You can only create type=uncachable region, if the first
 region that you created is type=write-combining.
 ===============================================================================
-Removing MTRRs from the shell:
+Removing MTRRs from the C-shell:
 % echo "disable=2" >! /proc/mtrr
+or using bash:
+% echo "disable=2" >| /proc/mtrr
 ===============================================================================
 Reading MTRRs from a C programme using ioctl()'s:
 
diff -u --recursive --new-file v2.3.2/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.2/linux/MAINTAINERS	Sat May  8 12:49:46 1999
+++ linux/MAINTAINERS	Sun May 16 10:26:44 1999
@@ -361,6 +361,12 @@
 W:	http://www.uni-mainz.de/~langm000/linux.html
 S:	Maintained
 
+HPFS FILESYSTEM
+P:	Mikulas Patocka
+M:	mikulas@artax.karlin.mff.cuni.cz
+W:	http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
+S:	Maintained
+
 IDE DRIVER [GENERAL]
 P:	Andre Hedrick
 M:	hedrick@astro.dyer.vanderbilt.edu
diff -u --recursive --new-file v2.3.2/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.3.2/linux/arch/i386/Makefile	Wed Dec 30 14:17:25 1998
+++ linux/arch/i386/Makefile	Sun May 16 13:17:22 1999
@@ -25,22 +25,27 @@
 
 ifdef CONFIG_M386
 CFLAGS := $(CFLAGS) -m386 -DCPU=386
+AFLAGS := $(AFLAGS) -DCPU=386
 endif
 
 ifdef CONFIG_M486
 CFLAGS := $(CFLAGS) -m486 -DCPU=486
+AFLAGS := $(AFLAGS) -DCPU=486
 endif
 
 ifdef CONFIG_M586
-CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586
+CFLAGS := $(CFLAGS) -DCPU=586
+AFLAGS := $(AFLAGS) -DCPU=586
 endif
 
 ifdef CONFIG_M586TSC
-CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586
+CFLAGS := $(CFLAGS) -DCPU=586
+AFLAGS := $(AFLAGS) -DCPU=586
 endif
 
 ifdef CONFIG_M686
-CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686
+CFLAGS := $(CFLAGS) -DCPU=686
+AFLAGS := $(AFLAGS) -DCPU=686
 endif
 
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
diff -u --recursive --new-file v2.3.2/linux/arch/i386/lib/checksum.S linux/arch/i386/lib/checksum.S
--- v2.3.2/linux/arch/i386/lib/checksum.S	Fri Jan 15 14:36:20 1999
+++ linux/arch/i386/lib/checksum.S	Sun May 16 13:17:22 1999
@@ -117,9 +117,11 @@
 #else /* CPU==686 */
 
 csum_partial:
-	movl 12(%esp),%eax	# Function arg: unsigned int sum
-	movl 8(%esp),%ecx	# Function arg: int len
-	movl 4(%esp),%esi	# Function arg:	const unsigned char *buf
+	pushl %esi
+	pushl %ebx
+	movl 20(%esp),%eax	# Function arg: unsigned int sum
+	movl 16(%esp),%ecx	# Function arg: int len
+	movl 12(%esp),%esi	# Function arg:	const unsigned char *buf
 
 	testl $2, %esi         
 	jnz 30f                 
@@ -204,6 +206,8 @@
 	addl %ebx,%eax
 	adcl $0,%eax
 80: 
+	popl %ebx
+	popl %esi
 	ret
 				
 #endif /* CPU==686 */ 
@@ -369,7 +373,7 @@
 
 #define ROUND1(x) \
 	SRC(movl x(%esi), %ebx	)	;	\
-	addl %ebx, %eax\n		;	\
+	addl %ebx, %eax			;	\
 	DST(movl %ebx, x(%edi)	)	; 
 
 #define ROUND(x) \
diff -u --recursive --new-file v2.3.2/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c
--- v2.3.2/linux/arch/m68k/atari/stdma.c	Thu Feb 12 16:30:12 1998
+++ linux/arch/m68k/atari/stdma.c	Sat May 15 15:05:35 1999
@@ -43,7 +43,7 @@
 						/* int func to be called */
 static void (*stdma_isr)(int, void *, struct pt_regs *) = NULL;
 static void	*stdma_isr_data = NULL;		/* data passed to isr */
-static struct wait_queue *stdma_wait = NULL;	/* wait queue for ST-DMA */
+static DECLARE_WAIT_QUEUE_HEAD(stdma_wait);	/* wait queue for ST-DMA */
 
 
 
diff -u --recursive --new-file v2.3.2/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c
--- v2.3.2/linux/arch/m68k/mac/adb-bus.c	Mon Oct  5 13:54:39 1998
+++ linux/arch/m68k/mac/adb-bus.c	Sat May 15 15:05:35 1999
@@ -2328,12 +2328,12 @@
 	struct adb_request req;
 };
 
-static struct wait_queue *adb_wait;
+static DECLARE_WAIT_QUEUE_HEAD(adb_wait);
 
 static int adb_wait_reply(struct adbdev_state *state, struct file *file)
 {
 	int ret = 0;
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait,current);
 
 	add_wait_queue(&adb_wait, &wait);
 	current->state = TASK_INTERRUPTIBLE;
@@ -2552,12 +2552,12 @@
 	struct adb_request req;
 };
 
-static struct wait_queue *adb_wait;
+static DECLARE_WAIT_QUEUE_HEAD(adb_wait);
 
 static int adb_wait_reply(struct adbdev_state *state, struct file *file)
 {
 	int ret = 0;
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 
 #if (ADBDEBUG & ADBDEBUG_DEVICE)
 	printk("ADB request: wait_reply (blocking ... \n");
diff -u --recursive --new-file v2.3.2/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c
--- v2.3.2/linux/arch/mips/kernel/irixsig.c	Thu Nov  5 09:58:29 1998
+++ linux/arch/mips/kernel/irixsig.c	Sat May 15 15:05:35 1999
@@ -666,7 +666,7 @@
 			    int options, struct rusage *ru)
 {
 	int flag, retval;
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait,current);
 	struct task_struct *p;
 
 	lock_kernel();
diff -u --recursive --new-file v2.3.2/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.3.2/linux/arch/ppc/8xx_io/uart.c	Wed Dec 23 09:44:40 1998
+++ linux/arch/ppc/8xx_io/uart.c	Sat May 15 15:05:35 1999
@@ -155,8 +155,8 @@
 	long			pgrp; /* pgrp of opening process */
 	struct tq_struct	tqueue;
 	struct tq_struct	tqueue_hangup;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
 
 	/* CPM Buffer Descriptor pointers.
 	*/
@@ -1733,7 +1733,7 @@
 			   ser_info_t *info)
 {
 #ifdef DO_THIS_LATER
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 #endif
 	struct serial_state *state = info->state;
 	int		retval;
diff -u --recursive --new-file v2.3.2/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.3.2/linux/arch/sparc/defconfig	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc/defconfig	Sat May 15 11:12:09 1999
@@ -229,6 +229,7 @@
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
 CONFIG_VFAT_FS=m
+CONFIG_EFS_FS=m
 CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 CONFIG_MINIX_FS=m
diff -u --recursive --new-file v2.3.2/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.2/linux/arch/sparc64/defconfig	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc64/defconfig	Sat May 15 11:12:09 1999
@@ -267,6 +267,7 @@
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
 CONFIG_VFAT_FS=m
+CONFIG_EFS_FS=m
 CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 CONFIG_MINIX_FS=m
diff -u --recursive --new-file v2.3.2/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.2/linux/arch/sparc64/kernel/sys_sparc32.c	Wed Mar 10 16:53:37 1999
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Sun May 16 10:39:51 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.107 1999/03/05 13:21:02 davem Exp $
+/* $Id: sys_sparc32.c,v 1.108 1999/05/16 10:50:32 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -2363,6 +2363,94 @@
 	__scm_destroy(scm);
 }
 
+/* In these cases we (currently) can just copy to data over verbatim
+ * because all CMSGs created by the kernel have well defined types which
+ * have the same layout in both the 32-bit and 64-bit API.  One must add
+ * some special cased conversions here if we start sending control messages
+ * with incompatible types.
+ *
+ * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
+ * we do our work.  The remaining cases are:
+ *
+ * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean
+ *		IP_TTL		int			32-bit clean
+ *		IP_TOS		__u8			32-bit clean
+ *		IP_RECVOPTS	variable length		32-bit clean
+ *		IP_RETOPTS	variable length		32-bit clean
+ *		(these last two are clean because the types are defined
+ *		 by the IPv4 protocol)
+ *		IP_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in	32-bit clean
+ * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in6	32-bit clean
+ *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean
+ *		IPV6_HOPLIMIT	int			32-bit clean
+ *		IPV6_FLOWINFO	u32			32-bit clean
+ *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean
+ *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean
+ *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean
+ *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean
+ */
+static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
+{
+	unsigned char *workbuf, *wp;
+	unsigned long bufsz, space_avail;
+	struct cmsghdr *ucmsg;
+
+	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
+	space_avail = kmsg->msg_controllen + bufsz;
+	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
+	if(workbuf == NULL)
+		goto fail;
+
+	/* To make this more sane we assume the kernel sends back properly
+	 * formatted control messages.  Because of how the kernel will truncate
+	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
+	 */
+	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
+	while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) {
+		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
+		int clen64, clen32;
+
+		/* UCMSG is the 64-bit format CMSG entry in user-space.
+		 * KCMSG32 is within the kernel space temporary buffer
+		 * we use to convert into a 32-bit style CMSG.
+		 */
+		__get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
+		__get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
+		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+
+		clen64 = kcmsg32->cmsg_len;
+		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		kcmsg32->cmsg_len = clen32;
+
+		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
+		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
+	}
+
+	/* Copy back fixed up data, and adjust pointers. */
+	bufsz = (wp - workbuf);
+	copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz);
+
+	kmsg->msg_control = (struct cmsghdr *)
+		(((char *)orig_cmsg_uptr) + bufsz);
+	kmsg->msg_controllen = space_avail - bufsz;
+
+	kfree(workbuf);
+	return;
+
+fail:
+	/* If we leave the 64-bit format CMSG chunks in there,
+	 * the application could get confused and crash.  So to
+	 * ensure greater recovery, we report no CMSGs.
+	 */
+	kmsg->msg_controllen += bufsz;
+	kmsg->msg_control = (void *) orig_cmsg_uptr;
+}
+
 asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
 {
 	struct socket *sock;
@@ -2455,6 +2543,14 @@
 				if(scm.fp)
 					__scm_destroy(&scm);
 			} else {
+				/* If recvmsg processing itself placed some
+				 * control messages into user space, it's is
+				 * using 64-bit CMSG processing, so we need
+				 * to fix it up before we tack on more stuff.
+				 */
+				if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+					cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
+
 				/* Wheee... */
 				if(sock->passcred)
 					put_cmsg32(&kern_msg,
@@ -2471,9 +2567,9 @@
 	if(uaddr != NULL && err >= 0)
 		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
 	if(cmsg_ptr != 0 && err >= 0) {
-		u32 ucmsg_ptr = ((u32)(unsigned long)kern_msg.msg_control);
-		err  = __put_user(ucmsg_ptr, &user_msg->msg_control);
-		err |= __put_user(kern_msg.msg_controllen, &user_msg->msg_controllen);
+		unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
+		__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr);
+		err |= __put_user(uclen, &user_msg->msg_controllen);
 	}
 	if(err >= 0)
 		err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
diff -u --recursive --new-file v2.3.2/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- v2.3.2/linux/arch/sparc64/solaris/fs.c	Fri May 14 18:55:13 1999
+++ linux/arch/sparc64/solaris/fs.c	Sat May 15 11:12:09 1999
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.12 1999/01/02 16:46:06 davem Exp $
+/* $Id: fs.c,v 1.13 1999/05/14 07:24:37 davem Exp $
  * fs.c: fs related syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.3.2/linux/arch/sparc64/solaris/ipc.c linux/arch/sparc64/solaris/ipc.c
--- v2.3.2/linux/arch/sparc64/solaris/ipc.c	Tue Aug  4 16:03:35 1998
+++ linux/arch/sparc64/solaris/ipc.c	Sat May 15 11:12:09 1999
@@ -1,4 +1,4 @@
-/* $Id: ipc.c,v 1.3 1998/07/30 11:29:47 davem Exp $
+/* $Id: ipc.c,v 1.4 1999/05/13 07:11:37 jj Exp $
  * ipc.c: Solaris IPC emulation
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/smp_lock.h>
+#include <linux/wait.h>
 #include <linux/shm.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
diff -u --recursive --new-file v2.3.2/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c
--- v2.3.2/linux/drivers/acorn/block/fd1772.c	Thu Jan  7 08:46:58 1999
+++ linux/drivers/acorn/block/fd1772.c	Sat May 15 15:05:35 1999
@@ -267,7 +267,7 @@
 
 /* Synchronization of FDC1772 access. */
 static volatile int fdc_busy = 0;
-static struct wait_queue *fdc_wait = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
 
 
 static unsigned int changed_floppies = 0xff, fake_change = 0;
diff -u --recursive --new-file v2.3.2/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c
--- v2.3.2/linux/drivers/acorn/block/mfmhd.c	Mon Aug 24 13:14:09 1998
+++ linux/drivers/acorn/block/mfmhd.c	Sat May 15 15:05:35 1999
@@ -195,7 +195,7 @@
 static int mfm_sizes[MFM_MAXDRIVES << 6];
 static int mfm_blocksizes[MFM_MAXDRIVES << 6];
 static int mfm_sectsizes[MFM_MAXDRIVES << 6];
-static struct wait_queue *mfm_wait_open = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open);
 
 /* Stuff from the assembly routines */
 extern unsigned int hdc63463_baseaddress;	/* Controller base address */
diff -u --recursive --new-file v2.3.2/linux/drivers/ap1000/ap.c linux/drivers/ap1000/ap.c
--- v2.3.2/linux/drivers/ap1000/ap.c	Mon Aug 24 13:45:51 1998
+++ linux/drivers/ap1000/ap.c	Sat May 15 15:05:35 1999
@@ -36,7 +36,7 @@
 #define NUM_APDEVS 8
 #define MAX_REQUESTS 1
 
-static struct wait_queue * busy_wait = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
 
 static int ap_blocksizes[NUM_APDEVS];
 static int ap_length[NUM_APDEVS];
diff -u --recursive --new-file v2.3.2/linux/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c
--- v2.3.2/linux/drivers/ap1000/ddv.c	Mon Aug 24 13:02:44 1998
+++ linux/drivers/ap1000/ddv.c	Sat May 15 15:05:35 1999
@@ -84,7 +84,7 @@
 static char *ddv_opcodep = NULL;
 static struct request *next_request = NULL;
 
-static struct wait_queue * busy_wait = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
 
 static int ddv_blocksizes[NUM_DDVDEVS]; /* in bytes */
 int ddv_sect_length[NUM_DDVDEVS]; /* in sectors */
@@ -93,7 +93,7 @@
 /* these are used by the ddv_daemon, which services remote disk requests */
 static struct remote_request *rem_queue = NULL;
 static struct remote_request *rem_queue_end;
-static struct wait_queue *ddv_daemon_wait = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(ddv_daemon_wait);
 
 static int opiu_kernel_loaded = 0;
 
diff -u --recursive --new-file v2.3.2/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.3.2/linux/drivers/block/Makefile	Fri May 14 18:55:13 1999
+++ linux/drivers/block/Makefile	Sat May 15 23:43:04 1999
@@ -20,7 +20,7 @@
 
 
 L_TARGET := block.a
-L_OBJS   := genhd.o
+L_OBJS   := genhd.o blkpg.o
 M_OBJS   :=
 MOD_LIST_NAME := BLOCK_MODULES
 LX_OBJS := ll_rw_blk.o
diff -u --recursive --new-file v2.3.2/linux/drivers/block/acsi.c linux/drivers/block/acsi.c
--- v2.3.2/linux/drivers/block/acsi.c	Fri May 14 18:55:13 1999
+++ linux/drivers/block/acsi.c	Sat May 15 23:43:04 1999
@@ -64,6 +64,7 @@
 typedef void Scsi_Device; /* hack to avoid including scsi.h */
 #include <scsi/scsi_ioctl.h>
 #include <linux/hdreg.h> /* for HDIO_GETGEO */
+#include <linux/blkpg.h>
 
 #include <asm/setup.h>
 #include <asm/pgtable.h>
@@ -1125,8 +1126,8 @@
 		return -EINVAL;
 	switch (cmd) {
 	  case HDIO_GETGEO:
-		/* HDIO_GETGEO is supported more for getting the partition's start
-		 * sector... */
+		/* HDIO_GETGEO is supported more for getting the partition's
+		 * start sector... */
 	  { struct hd_geometry *geo = (struct hd_geometry *)arg;
 	    /* just fake some geometry here, it's nonsense anyway; to make it
 		 * easy, use Adaptec's usual 64/32 mapping */
@@ -1147,19 +1148,18 @@
 	  case BLKGETSIZE:   /* Return device size */
 		return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects,
 				(long *) arg);
-		
+
+	  case BLKROSET:
+	  case BLKROGET:
 	  case BLKFLSBUF:
-		if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-		if(!inode->i_rdev) return -EINVAL;
-		fsync_dev(inode->i_rdev);
-		invalidate_buffers(inode->i_rdev);
-		return 0;
+	  case BLKPG:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
 
 	  case BLKRRPART: /* Re-read partition tables */
 	        if (!capable(CAP_SYS_ADMIN)) 
 			return -EACCES;
 		return revalidate_acsidisk(inode->i_rdev, 1);
-	  RO_IOCTLS(inode->i_rdev,arg);
+
 	  default:
 		return -EINVAL;
 	}
diff -u --recursive --new-file v2.3.2/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v2.3.2/linux/drivers/block/ataflop.c	Fri May 14 18:55:13 1999
+++ linux/drivers/block/ataflop.c	Sat May 15 23:43:04 1999
@@ -93,6 +93,7 @@
 
 #define MAJOR_NR FLOPPY_MAJOR
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 
 #define	FD_MAX_UNITS 2
 
@@ -1584,7 +1585,12 @@
 
 	device = inode->i_rdev;
 	switch (cmd) {
-		RO_IOCTLS (device, param);
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKFLSBUF:
+			return blk_ioctl(device, cmd, param);
 	}
 	drive = MINOR (device);
 	type  = drive >> 2;
@@ -1620,22 +1626,6 @@
 		getprm.stretch = dtp->stretch;
 		if (copy_to_user((void *)param, &getprm, sizeof(getprm)))
 			return -EFAULT;
-		return 0;
-	case BLKRASET:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		if (param > 0xff)
-			return -EINVAL;
-		read_ahead[MAJOR(inode->i_rdev)] = param;
-		return 0;
-	case BLKRAGET:
-		return put_user(read_ahead[MAJOR(inode->i_rdev)],
-				(int *) param);
-	case BLKFLSBUF:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		fsync_dev(inode->i_rdev);
-		invalidate_buffers(inode->i_rdev);
 		return 0;
 	}
 	if (!IOCTL_ALLOWED)
diff -u --recursive --new-file v2.3.2/linux/drivers/block/blkpg.c linux/drivers/block/blkpg.c
--- v2.3.2/linux/drivers/block/blkpg.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/blkpg.c	Sat May 15 23:43:04 1999
@@ -0,0 +1,288 @@
+/*
+ * Partition table and disk geometry handling
+ *
+ * This obsoletes the partition-handling code in genhd.c:
+ * Userspace can look at a disk in arbitrary format and tell
+ * the kernel what partitions there are on the disk, and how
+ * these should be numbered.
+ * It also allows one to repartition a disk that is being used.
+ *
+ * A single ioctl with lots of subfunctions:
+ *
+ * Device number stuff:
+ *    get_whole_disk()          (given the device number of a partition, find
+ *                               the device number of the encompassing disk)
+ *    get_all_partitions()      (given the device number of a disk, return the
+ *                               device numbers of all its known partitions)
+ *
+ * Partition stuff:
+ *    add_partition()
+ *    delete_partition()
+ *    test_partition_in_use()   (also for test_disk_in_use)
+ *
+ * Geometry stuff:
+ *    get_geometry()
+ *    set_geometry()
+ *    get_bios_drivedata()
+ *
+ * For today, only the partition stuff - aeb, 990515
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>			/* for BLKRASET, ... */
+#include <linux/sched.h>		/* for capable() */
+#include <linux/blk.h>			/* for set_device_ro() */
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/swap.h>			/* for is_swap_partition() */
+
+#include <asm/uaccess.h>
+
+/*
+ * What is the data describing a partition?
+ *
+ * 1. a device number (kdev_t)
+ * 2. a starting sector and number of sectors (hd_struct)
+ *    given in the part[] array of the gendisk structure for the drive.
+ *
+ * The number of sectors is replicated in the sizes[] array of
+ * the gendisk structure for the major, which again is copied to
+ * the blk_size[][] array.
+ * (However, hd_struct has the number of 512-byte sectors,
+ *  g->sizes[] and blk_size[][] have the number of 1024-byte blocks.)
+ * Note that several drives may have the same major.
+ */
+
+/* a linear search, superfluous when dev is a pointer */
+static struct gendisk *get_gendisk(kdev_t dev) {
+	struct gendisk *g;
+	int m = MAJOR(dev);
+
+	for (g = gendisk_head; g; g = g->next)
+		if (g->major == m)
+			break;
+	return g;
+}
+
+/* moved here from md.c - will be discarded later */
+char *partition_name (kdev_t dev) {
+	static char name[40];		/* kdevname returns 32 bytes */
+					/* disk_name requires 32 bytes */
+	struct gendisk *hd = get_gendisk (dev);
+
+	if (!hd) {
+		sprintf (name, "[dev %s]", kdevname(dev));
+		return (name);
+	}
+
+	return disk_name (hd, MINOR(dev), name);  /* routine in genhd.c */
+}
+
+/*
+ * Add a partition.
+ *
+ * returns: EINVAL: bad parameters
+ *          ENXIO: cannot find drive
+ *          EBUSY: proposed partition overlaps an existing one
+ *                 or has the same number as an existing one
+ *          0: all OK.
+ */
+int add_partition(kdev_t dev, struct blkpg_partition *p) {
+	struct gendisk *g;
+	long long ppstart, pplength;
+	long pstart, plength;
+	int i, drive, first_minor, end_minor, minor;
+
+	/* convert bytes to sectors, check for fit in a hd_struct */
+	ppstart = (p->start >> 9);
+	pplength = (p->length >> 9);
+	pstart = ppstart;
+	plength = pplength;
+	if (pstart != ppstart || plength != pplength
+	    || pstart < 0 || plength < 0)
+		return -EINVAL;
+
+	/* find the drive major */
+	g = get_gendisk(dev);
+	if (!g)
+		return -ENXIO;
+
+	/* existing drive? */
+	drive = (MINOR(dev) >> g->minor_shift);
+	first_minor = (drive << g->minor_shift);
+	end_minor   = first_minor + g->max_p;
+	if (drive >= g->nr_real)
+		return -ENXIO;
+
+	/* drive and partition number OK? */
+	if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
+		return -EINVAL;
+
+	/* partition number in use? */
+	minor = first_minor + p->pno;
+	if (g->part[minor].nr_sects != 0)
+		return -EBUSY;
+
+	/* overlap? */
+	for (i=first_minor+1; i<end_minor; i++)
+		if (!(pstart+plength <= g->part[i].start_sect ||
+		      pstart >= g->part[i].start_sect + g->part[i].nr_sects))
+			return -EBUSY;
+
+	/* all seems OK */
+	g->part[minor].start_sect = pstart;
+	g->part[minor].nr_sects = plength;
+	if (g->sizes)
+		g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9));
+	return 0;
+}
+
+/*
+ * Delete a partition given by partition number
+ *
+ * returns: EINVAL: bad parameters
+ *          ENXIO: cannot find partition
+ *          EBUSY: partition is busy
+ *          0: all OK.
+ *
+ * Note that the dev argument refers to the entire disk, not the partition.
+ */
+int del_partition(kdev_t dev, struct blkpg_partition *p) {
+	struct gendisk *g;
+	kdev_t devp;
+	int drive, first_minor, minor;
+
+	/* find the drive major */
+	g = get_gendisk(dev);
+	if (!g)
+		return -ENXIO;
+
+	/* drive and partition number OK? */
+	drive = (MINOR(dev) >> g->minor_shift);
+	first_minor = (drive << g->minor_shift);
+	if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
+		return -EINVAL;
+
+	/* existing drive and partition? */
+	minor = first_minor + p->pno;
+	if (drive >= g->nr_real || g->part[minor].nr_sects == 0)
+		return -ENXIO;
+
+	/* partition in use? Incomplete check for now. */
+	devp = MKDEV(MAJOR(dev), minor);
+	if (get_super(devp) ||		/* mounted? */
+	    is_swap_partition(devp))
+		return -EBUSY;
+
+	/* all seems OK */
+	fsync_dev(devp);
+	invalidate_buffers(devp);
+
+	g->part[minor].start_sect = 0;
+	g->part[minor].nr_sects = 0;
+	if (g->sizes)
+		g->sizes[minor] = 0;
+
+	return 0;
+}
+
+int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int len;
+
+	if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
+		return -EFAULT;
+
+	switch (a.op) {
+		case BLKPG_ADD_PARTITION:
+		case BLKPG_DEL_PARTITION:
+			len = a.datalen;
+			if (len < sizeof(struct blkpg_partition))
+				return -EINVAL;
+			if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+				return -EFAULT;
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			if (a.op == BLKPG_ADD_PARTITION)
+				return add_partition(dev, &p);
+			else
+				return del_partition(dev, &p);
+		default:
+			return -EINVAL;
+	}
+}
+
+/*
+ * Common ioctl's for block devices
+ */
+
+int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
+{
+	int intval;
+
+	switch (cmd) {
+		case BLKROSET:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			if (get_user(intval, (int *)(arg)))
+				return -EFAULT;
+			set_device_ro(dev, intval);
+			return 0;
+		case BLKROGET:
+			intval = (is_read_only(dev) != 0);
+			return put_user(intval, (int *)(arg));
+
+		case BLKRASET:
+			if(!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			if(!dev || arg > 0xff)
+				return -EINVAL;
+			read_ahead[MAJOR(dev)] = arg;
+			return 0;
+		case BLKRAGET:
+			if (!arg)
+				return -EINVAL;
+			return put_user(read_ahead[MAJOR(dev)], (long *) arg);
+
+		case BLKFLSBUF:
+			if(!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			if (!dev)
+				return -EINVAL;
+			fsync_dev(dev);
+			invalidate_buffers(dev);
+			return 0;
+
+		case BLKSSZGET:
+			/* get block device sector size as needed e.g. by fdisk */
+			intval = get_hardsect_size(dev);
+			return put_user(intval, (int *) arg);
+
+#if 0
+		case BLKGETSIZE:
+			/* Today get_gendisk() requires a linear scan;
+			   add this when dev has pointer type. */
+			g = get_gendisk(dev);
+			if (!g)
+				longval = 0;
+			else
+				longval = g->part[MINOR(dev)].nr_sects;
+			return put_user(longval, (long *) arg);
+#endif
+#if 0
+		case BLKRRPART: /* Re-read partition tables */
+			if (!capable(CAP_SYS_ADMIN)) 
+				return -EACCES;
+			return reread_partitions(dev, 1);
+#endif
+
+		case BLKPG:
+			return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
+			
+		default:
+			return -EINVAL;
+	}
+}
+
diff -u --recursive --new-file v2.3.2/linux/drivers/block/cmd646.c linux/drivers/block/cmd646.c
--- v2.3.2/linux/drivers/block/cmd646.c	Fri May 14 18:55:13 1999
+++ linux/drivers/block/cmd646.c	Sat May 15 11:12:09 1999
@@ -1,4 +1,4 @@
-/* $Id: cmd646.c,v 1.11 1998/12/13 08:36:54 davem Exp $
+/* $Id: cmd646.c,v 1.12 1999/05/14 07:21:01 davem Exp $
  * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines.
  *           Note, this driver is not used at all on other systems because
  *           there the "BIOS" has done all of the following already.
diff -u --recursive --new-file v2.3.2/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.2/linux/drivers/block/floppy.c	Fri May 14 18:55:13 1999
+++ linux/drivers/block/floppy.c	Sat May 15 23:43:04 1999
@@ -198,6 +198,7 @@
 #define MAJOR_NR FLOPPY_MAJOR
 
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 #include <linux/cdrom.h> /* for the compatibility eject ioctl */
 
 #ifndef fd_get_dma_residue
@@ -3293,7 +3294,7 @@
 		LOCK_FDC(drive,1);
 		if (cmd != FDDEFPRM)
 			/* notice a disk change immediately, else
-			 * we loose our settings immediately*/
+			 * we lose our settings immediately*/
 			CALL(poll_drive(1, FD_RAW_NEED_DISK));
 		user_params[drive] = *g;
 		if (buffer_drive == drive)
@@ -3402,7 +3403,12 @@
 
 	device = inode->i_rdev;
 	switch (cmd) {
-		RO_IOCTLS(device,param);
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKFLSBUF:
+			return blk_ioctl(device, cmd, param);
 	}
 	type = TYPE(device);
 	drive = DRIVE(device);
@@ -3432,19 +3438,6 @@
 			loc.start = 0;
 			return _COPYOUT(loc);
 		}
-		case BLKRASET:
-			if(!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if(param > 0xff) return -EINVAL;
-			read_ahead[MAJOR(inode->i_rdev)] = param;
-			return 0;
-                case BLKRAGET:
-			return put_user(read_ahead[MAJOR(inode->i_rdev)],
-					(long *) param);
-		case BLKFLSBUF:
-			if(!capable(CAP_SYS_ADMIN)) return -EACCES;
-			fsync_dev(inode->i_rdev);
-			invalidate_buffers(inode->i_rdev);
-			return 0;
 
 		case BLKGETSIZE:
 			ECALL(get_floppy_geometry(drive, type, &g));
diff -u --recursive --new-file v2.3.2/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.3.2/linux/drivers/block/genhd.c	Fri May 14 18:55:13 1999
+++ linux/drivers/block/genhd.c	Sat May 15 23:43:04 1999
@@ -66,10 +66,10 @@
 #endif
 
 /*
- * disk_name() is used by genhd.c and md.c.
- * It formats the devicename of the indicated disk
- * into the supplied buffer, and returns a pointer
- * to that same buffer (for convenience).
+ * disk_name() is used by genhd.c and blkpg.c.
+ * It formats the devicename of the indicated disk into
+ * the supplied buffer (of size at least 32), and returns
+ * a pointer to that same buffer (for convenience).
  */
 char *disk_name (struct gendisk *hd, int minor, char *buf)
 {
@@ -121,7 +121,7 @@
 
 static void add_partition (struct gendisk *hd, int minor, int start, int size)
 {
-	char buf[8];
+	char buf[32];
 	hd->part[minor].start_sect = start;
 	hd->part[minor].nr_sects   = size;
 	printk(" %s", disk_name(hd, minor, buf));
@@ -134,12 +134,12 @@
 		SYS_IND(p) == LINUX_EXTENDED_PARTITION);
 }
 
-static int sector_partition_scale(kdev_t dev)
+int get_hardsect_size(kdev_t dev)
 {
-       if (hardsect_size[MAJOR(dev)] != NULL)
-               return (hardsect_size[MAJOR(dev)][MINOR(dev)]/512);
-       else
-               return (1);
+	if (hardsect_size[MAJOR(dev)] != NULL)
+		return hardsect_size[MAJOR(dev)][MINOR(dev)];
+	else
+		return 512;
 }
 
 static unsigned int get_ptable_blocksize(kdev_t dev)
@@ -209,7 +209,7 @@
 	struct partition *p;
 	unsigned long first_sector, first_size, this_sector, this_size;
 	int mask = (1 << hd->minor_shift) - 1;
-	int sector_size = sector_partition_scale(dev);
+	int sector_size = get_hardsect_size(dev) / 512;
 	int i;
 
 	first_sector = hd->part[MINOR(dev)].start_sect;
@@ -453,7 +453,7 @@
 	struct partition *p;
 	unsigned char *data;
 	int mask = (1 << hd->minor_shift) - 1;
-	int sector_size = sector_partition_scale(dev);
+	int sector_size = get_hardsect_size(dev) / 512;
 #ifdef CONFIG_BSD_DISKLABEL
 	/* no bsd disklabel as a default */
 	kdev_t bsd_kdev = 0;
@@ -883,10 +883,7 @@
 	int			 blocksize;
 
 	old_blocksize = get_ptable_blocksize(dev);
-	if (hardsect_size[MAJOR(dev)] != NULL)
-		blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
-	else
-		blocksize = 512;
+	blocksize = get_hardsect_size(dev);
 
 	set_blocksize(dev,blocksize);
 	res = 0;
@@ -1223,7 +1220,7 @@
 {
 	static int first_time = 1;
 	unsigned long first_sector;
-	char buf[8];
+	char buf[32];
 
 	if (first_time)
 		printk("Partition check:\n");
@@ -1307,28 +1304,21 @@
 	int end_minor	= dev->max_nr * dev->max_p;
 
 	blk_size[dev->major] = NULL;
-	for (i = 0 ; i < end_minor; i++) {
+	for (i = 0; i < end_minor; i++) {
 		dev->part[i].start_sect = 0;
 		dev->part[i].nr_sects = 0;
+		dev->sizes[i] = 0;
 	}
 	dev->init(dev);	
-	for (drive = 0 ; drive < dev->nr_real ; drive++) {
-		int first_minor	= drive << dev->minor_shift;
-		current_minor = 1 + first_minor;
-		check_partition(dev, MKDEV(dev->major, first_minor));
-	}
-	if (dev->sizes != NULL) {	/* optional safeguard in ll_rw_blk.c */
-		for (i = 0; i < end_minor; i++)
-			dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
-		blk_size[dev->major] = dev->sizes;
-	}
+	for (drive = 0; drive < dev->nr_real; drive++)
+		resetup_one_dev(dev, drive);
 }
 
 __initfunc(void device_setup(void))
 {
 	extern void console_map_init(void);
 #ifdef CONFIG_PARPORT
-	extern int parport_init(void);
+	extern int parport_init(void) __init;
 #endif
 #ifdef CONFIG_MD_BOOT
         extern void md_setup_drive(void) __init;
diff -u --recursive --new-file v2.3.2/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v2.3.2/linux/drivers/block/hd.c	Fri May 14 18:55:13 1999
+++ linux/drivers/block/hd.c	Sat May 15 23:43:04 1999
@@ -604,31 +604,25 @@
 			g.start = hd[MINOR(inode->i_rdev)].start_sect;
 			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
 		}
-		case BLKRASET:
-			if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-			if(arg > 0xff) return -EINVAL;
-			read_ahead[MAJOR(inode->i_rdev)] = arg;
-			return 0;
-		case BLKRAGET:
-			if (!arg)  return -EINVAL;
-			return put_user(read_ahead[MAJOR(inode->i_rdev)],
-					(long *) arg); 
+
          	case BLKGETSIZE:   /* Return device size */
 			if (!arg)  return -EINVAL;
 			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
 					(long *) arg);
-		case BLKFLSBUF:
-			if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-			fsync_dev(inode->i_rdev);
-			invalidate_buffers(inode->i_rdev);
-			return 0;
 
 		case BLKRRPART: /* Re-read partition tables */
 			if (!capable(CAP_SYS_ADMIN)) 
 				return -EACCES;
 			return revalidate_hddisk(inode->i_rdev, 1);
 
-		RO_IOCTLS(inode->i_rdev,arg);
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKFLSBUF:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
 		default:
 			return -EINVAL;
 	}
@@ -836,7 +830,7 @@
 	if (DEVICE_BUSY || USAGE > maxusage) {
 		restore_flags(flags);
 		return -EBUSY;
-	};
+	}
 	DEVICE_BUSY = 1;
 	restore_flags(flags);
 
@@ -854,7 +848,7 @@
 		invalidate_buffers(devi);
 		gdev->part[minor].start_sect = 0;
 		gdev->part[minor].nr_sects = 0;
-	};
+	}
 
 #ifdef MAYBE_REINIT
 	MAYBE_REINIT;
diff -u --recursive --new-file v2.3.2/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.2/linux/drivers/block/ide.c	Fri May 14 18:55:14 1999
+++ linux/drivers/block/ide.c	Sun May 16 10:56:16 1999
@@ -122,6 +122,7 @@
 #include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/genhd.h>
+#include <linux/blkpg.h>
 #include <linux/malloc.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -2232,17 +2233,6 @@
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
 		}
-		case BLKSSZGET:
-			/* Block size of media */
-			return put_user(blksize_size[HWIF(drive)->major]
-						    [minor&PARTN_MASK],
-						    (int *)arg);
-		
-		case BLKFLSBUF:
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			fsync_dev(inode->i_rdev);
-			invalidate_buffers(inode->i_rdev);
-			return 0;
 
 	 	case BLKGETSIZE:   /* Return device size */
 			return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
@@ -2383,7 +2373,12 @@
 			drive->nice1 = (arg >> IDE_NICE_1) & 1;
 			return 0;
 
-		RO_IOCTLS(inode->i_rdev, arg);
+		case BLKROSET:
+		case BLKROGET:
+		case BLKFLSBUF:
+		case BLKSSZGET:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
 
 		default:
 			if (drive->driver != NULL)
@@ -2917,121 +2912,10 @@
  * Returns 1 if the geometry translation was successful.
  */
 
-#define ANDRIES_GEOMETRY	0
-
 int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
 {
 	ide_drive_t *drive;
 
-#if ANDRIES_GEOMETRY
-	/*
-	 * This is the documented list of values (some version of)
-	 * OnTrack DM uses.
-	 */
-
-	static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
-
-	/*
-	 * This is a pure phantasy list - known to be incorrect.
-	 *
-	 * In fact it seems that EZD does not do anything to the CHS
-	 * values in the partition table, so whether EZD is present
-	 * or not should probably not influence the geometry.
-	 */
-
-	static const byte ez_head_vals[] = {4, 8, 16, 32, 64, 128, 240, 255, 0};        const byte *heads;
-	unsigned long tracks;
-
-	drive = get_info_ptr(i_rdev);
-	if (!drive)
-		return 0;
-
-	if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) {
-		/*
-		 * Update the current 3D drive values.
-		 */
-		drive->id->cur_cyls	= drive->bios_cyl;
-		drive->id->cur_heads	= drive->bios_head;
-		drive->id->cur_sectors	= drive->bios_sect;
-		return 0;	/* we already have a translation */
-	}
-
-	if (xparm == -1) {
-		int ret = 0;
-#if FAKE_FDISK_FOR_EZDRIVE
-		if (drive->remap_0_to_1 == 0) {
-			drive->remap_0_to_1 = 1;
-			printk("%s [remap 0->1]", msg);
-			msg = NULL;
-			ret = 1;
-		}
-		if (drive->bios_head > 16)
-#endif /* FAKE_FDISK_FOR_EZDRIVE */
-		{
-			/*
-			 * Update the current 3D drive values.
-			 */
-			drive->id->cur_cyls	= drive->bios_cyl;
-			drive->id->cur_heads	= drive->bios_head;
-			drive->id->cur_sectors	= drive->bios_sect;
-			return ret;	/* we already have a translation */
-		}
-	}
-
-	if (msg)
-		printk("%s ", msg);
-
-	if (drive->forced_geom) {
-		/*
-		 * Update the current 3D drive values.
-		 */
-		drive->id->cur_cyls	= drive->bios_cyl;
-		drive->id->cur_heads	= drive->bios_head;
-		drive->id->cur_sectors	= drive->bios_sect;
-		return 0;
-	}
-
-#if 1
-	/* There used to be code here that assigned drive->id->CHS
-	   to drive->CHS and that to drive->bios_CHS. However,
-	   some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
-	   In such cases that code was wrong.  Moreover,
-	   there seems to be no reason to do any of these things. */
-#else
-	if (drive->id) {
-		drive->cyl  = drive->id->cyls;
-		drive->head = drive->id->heads;
-		drive->sect = drive->id->sectors;
-	}
-	drive->bios_cyl  = drive->cyl;
-	drive->bios_head = drive->head;
-	drive->bios_sect = drive->sect;
-	drive->special.b.set_geometry = 1;
-
-#endif
-
-	tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
-	drive->bios_sect = 63;
-	if (xparm > 1) {
-		drive->bios_head = xparm;
-		drive->bios_cyl = tracks / drive->bios_head;
-	} else {
-		heads = (xparm == -1) ? ez_head_vals : dm_head_vals;
-		while (drive->bios_cyl >= 1024) {
-			drive->bios_head = *heads;
-			drive->bios_cyl = tracks / drive->bios_head;
-			if (0 == *++heads)
-				break;
-		}
-		if (xparm == 1) {
-			drive->sect0 = 63;
-			drive->bios_cyl = (tracks - 1) / drive->bios_head;
-			printk("[remap +63] ");
-		}
-	}
-
-#else /* ANDRIES_GEOMETRY */
-
 	static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
 	const byte *heads = head_vals;
 	unsigned long tracks;
@@ -3106,7 +2990,6 @@
 			printk("[remap +63] ");
 		}
 	}
-#endif /* ANDRIES_GEOMETRY */
 
 	drive->part[0].nr_sects = current_capacity(drive);
 	printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
diff -u --recursive --new-file v2.3.2/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.3.2/linux/drivers/block/md.c	Fri May 14 18:55:14 1999
+++ linux/drivers/block/md.c	Sat May 15 23:43:04 1999
@@ -59,6 +59,7 @@
 #define MD_DRIVER
 
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/atomic.h>
@@ -98,36 +99,6 @@
 
 int md_thread(void * arg);
 
-static struct gendisk *find_gendisk (kdev_t dev)
-{
-  struct gendisk *tmp=gendisk_head;
-
-  while (tmp != NULL)
-  {
-    if (tmp->major==MAJOR(dev))
-      return (tmp);
-    
-    tmp=tmp->next;
-  }
-
-  return (NULL);
-}
-
-char *partition_name (kdev_t dev)
-{
-  static char name[40];		/* This should be long
-				   enough for a device name ! */
-  struct gendisk *hd = find_gendisk (dev);
-
-  if (!hd)
-  {
-    sprintf (name, "[dev %s]", kdevname(dev));
-    return (name);
-  }
-
-  return disk_name (hd, MINOR(dev), name);  /* routine in genhd.c */
-}
-
 static int legacy_raid_sb (int minor, int pnum)
 {
 	int i, factor;
@@ -653,24 +624,7 @@
       return err;
     break;
 
-    case BLKFLSBUF:
-    fsync_dev (inode->i_rdev);
-    invalidate_buffers (inode->i_rdev);
-    break;
-
-    case BLKRASET:
-    if (arg > 0xff)
-      return -EINVAL;
-    read_ahead[MAJOR(inode->i_rdev)] = arg;
-    return 0;
     
-    case BLKRAGET:
-    if  (!arg)  return -EINVAL;
-    err = put_user (read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
-    if (err)
-      return err;
-    break;
-
     /* We have a problem here : there is no easy way to give a CHS
        virtual geometry. We currently pretend that we have a 2 heads
        4 sectors (with a BIG number of cylinders...). This drives dosfs
@@ -693,7 +647,12 @@
       return err;
     break;
     
-    RO_IOCTLS(inode->i_rdev,arg);
+    case BLKROSET:
+    case BLKROGET:
+    case BLKRAGET:
+    case BLKRASET:
+    case BLKFLSBUF:
+	  return blk_ioctl(inode->i_rdev, cmd, arg);
     
     default:
     return -EINVAL;
@@ -901,7 +860,6 @@
 EXPORT_SYMBOL(md_maxreadahead);
 EXPORT_SYMBOL(register_md_personality);
 EXPORT_SYMBOL(unregister_md_personality);
-EXPORT_SYMBOL(partition_name);
 EXPORT_SYMBOL(md_dev);
 EXPORT_SYMBOL(md_error);
 EXPORT_SYMBOL(md_register_thread);
diff -u --recursive --new-file v2.3.2/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.3.2/linux/drivers/block/paride/pd.c	Mon Sep 28 10:51:16 1998
+++ linux/drivers/block/paride/pd.c	Sat May 15 23:43:04 1999
@@ -208,6 +208,7 @@
 #define DEVICE_OFF(device)
 
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 
 #include "pseudo.h"
 
@@ -331,7 +332,7 @@
 static int pd_poffs;			/* partition offset of current minor */
 static char * pd_buf;                   /* buffer for request in progress */
 
-static struct wait_queue *pd_wait_open = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(pd_wait_open);
 
 static char *pd_errs[17] = { "ERR","INDEX","ECC","DRQ","SEEK","WRERR",
                              "READY","BUSY","AMNF","TK0NF","ABRT","MCR",
@@ -483,35 +484,23 @@
 		}
                 put_user(pd_hd[dev].start_sect,(long *)&geo->start);
                 return 0;
-            case BLKRASET:
-                if(!capable(CAP_SYS_ADMIN)) return -EACCES;
-                if(!(inode->i_rdev)) return -EINVAL;
-                if(arg > 0xff) return -EINVAL;
-                read_ahead[MAJOR(inode->i_rdev)] = arg;
-                return 0;
-            case BLKRAGET:
-                if (!arg) return -EINVAL;
-                err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
-                if (err) return (err);
-                put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
-                return (0);
             case BLKGETSIZE:
                 if (!arg) return -EINVAL;
                 err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
                 if (err) return (err);
                 put_user(pd_hd[dev].nr_sects,(long *) arg);
                 return (0);
-            case BLKFLSBUF:
-                if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-                if(!(inode->i_rdev)) return -EINVAL;
-                fsync_dev(inode->i_rdev);
-                invalidate_buffers(inode->i_rdev);
-                return 0;
             case BLKRRPART:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
                 return pd_revalidate(inode->i_rdev);
-            RO_IOCTLS(inode->i_rdev,arg);
+	    case BLKROSET:
+	    case BLKROGET:
+	    case BLKRASET:
+	    case BLKRAGET:
+	    case BLKFLSBUF:
+	    case BLKPG:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
             default:
                 return -EINVAL;
         }
diff -u --recursive --new-file v2.3.2/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.3.2/linux/drivers/block/paride/pf.c	Wed Nov  4 10:04:43 1998
+++ linux/drivers/block/paride/pf.c	Sat May 15 23:43:04 1999
@@ -205,6 +205,7 @@
 #define DEVICE_OFF(device)
 
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 
 #include "pseudo.h"
 
@@ -433,31 +434,18 @@
                 }
                 put_user(0,(long *)&geo->start);
                 return 0;
-            case BLKRASET:
-                if(!capable(CAP_SYS_ADMIN)) return -EACCES;
-                if(!(inode->i_rdev)) return -EINVAL;
-                if(arg > 0xff) return -EINVAL;
-                read_ahead[MAJOR(inode->i_rdev)] = arg;
-                return 0;
-            case BLKRAGET:
-                if (!arg) return -EINVAL;
-                err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
-                if (err) return (err);
-                put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
-                return (0);
             case BLKGETSIZE:
                 if (!arg) return -EINVAL;
                 err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
                 if (err) return (err);
                 put_user(PF.capacity,(long *) arg);
                 return (0);
-            case BLKFLSBUF:
-                if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-                if(!(inode->i_rdev)) return -EINVAL;
-                fsync_dev(inode->i_rdev);
-                invalidate_buffers(inode->i_rdev);
-                return 0;
-            RO_IOCTLS(inode->i_rdev,arg);
+	    case BLKROSET:
+	    case BLKROGET:
+	    case BLKRASET:
+	    case BLKRAGET:
+	    case BLKFLSBUF:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
             default:
                 return -EINVAL;
         }
diff -u --recursive --new-file v2.3.2/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.3.2/linux/drivers/block/ps2esdi.c	Fri May 14 18:55:14 1999
+++ linux/drivers/block/ps2esdi.c	Sat May 15 23:43:04 1999
@@ -42,6 +42,7 @@
 #include <linux/genhd.h>
 #include <linux/ps2esdi.h>
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 #include <linux/mca.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -1140,15 +1141,7 @@
 				return (0);
 			}
 			break;
-		case BLKRASET:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			if (!inode->i_rdev)
-				return -EINVAL;
-			if (arg > 0xff)
-				return -EINVAL;
-			read_ahead[MAJOR(inode->i_rdev)] = arg;
-			return 0;
+
 		case BLKGETSIZE:
 			if (arg) {
 				if ((err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long))))
@@ -1158,20 +1151,19 @@
 				return (0);
 			}
 			break;
-		case BLKFLSBUF:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			if (!inode->i_rdev)
-				return -EINVAL;
-			fsync_dev(inode->i_rdev);
-			invalidate_buffers(inode->i_rdev);
-			return 0;
 
 		case BLKRRPART:
                         if (!capable(CAP_SYS_ADMIN)) 
 				return -EACCES;
 			return (ps2esdi_reread_partitions(inode->i_rdev));
-			RO_IOCTLS(inode->i_rdev, arg);
+
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKFLSBUF:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
 		}
 	return (-EINVAL);
 }
diff -u --recursive --new-file v2.3.2/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.3.2/linux/drivers/block/rd.c	Fri May 14 18:55:14 1999
+++ linux/drivers/block/rd.c	Sat May 15 23:43:04 1999
@@ -72,6 +72,7 @@
  */
 #define MAJOR_NR RAMDISK_MAJOR
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 
 /*
  * We use a block size of 512 bytes in comparision to BLOCK_SIZE
@@ -198,11 +199,10 @@
 			if (!arg)  return -EINVAL;
 			return put_user(rd_length[minor] >> RDBLK_SIZE_BITS, (long *) arg);
 
-		case BLKSSZGET:	   /* Block size of media */
-			if (!arg)  return -EINVAL;
-			return put_user(rd_blocksizes[minor], (int *)arg);
-
-		RO_IOCTLS(inode->i_rdev, arg);
+		case BLKROSET:
+		case BLKROGET:
+		case BLKSSZGET:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
 
 		default:
 			return -EINVAL;
@@ -519,7 +519,7 @@
 	}
 
 	if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) {
-		printk("RAMDISK: image too big! (%d/%d blocks)\n",
+		printk("RAMDISK: image too big! (%d/%ld blocks)\n",
 		       nblocks, rd_length[unit] >> RDBLK_SIZE_BITS);
 		goto done;
 	}
diff -u --recursive --new-file v2.3.2/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.3.2/linux/drivers/block/xd.c	Fri May 14 18:55:15 1999
+++ linux/drivers/block/xd.c	Sat May 15 23:43:04 1999
@@ -49,6 +49,7 @@
 
 #define MAJOR_NR XT_DISK_MAJOR
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 
 #include "xd.h"
 
@@ -337,21 +338,9 @@
 			g.start = xd_struct[MINOR(inode->i_rdev)].start_sect;
 			return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0;
 		}
-		case BLKRASET:
-			if(!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if(arg > 0xff) return -EINVAL;
-			read_ahead[MAJOR(inode->i_rdev)] = arg;
-			return 0;
-		case BLKRAGET:
-			return put_user(read_ahead[MAJOR(inode->i_rdev)], (long*) arg);
 		case BLKGETSIZE:
 			if (!arg) return -EINVAL;
 			return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
-		case BLKFLSBUF:   /* Return devices size */
-			if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-			fsync_dev(inode->i_rdev);
-			invalidate_buffers(inode->i_rdev);
-			return 0;
 		case HDIO_SET_DMA:
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 			if (xdc_busy) return -EBUSY;
@@ -369,7 +358,15 @@
 			if (!capable(CAP_SYS_ADMIN)) 
 				return -EACCES;
 			return xd_reread_partitions(inode->i_rdev);
-		RO_IOCTLS(inode->i_rdev,arg);
+
+		case BLKFLSBUF:
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
 		default:
 			return -EINVAL;
 	}
diff -u --recursive --new-file v2.3.2/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c
--- v2.3.2/linux/drivers/cdrom/gscd.c	Sat Oct 31 10:28:25 1998
+++ linux/drivers/cdrom/gscd.c	Sat May 15 15:05:36 1999
@@ -76,7 +76,7 @@
 MODULE_PARM(gscd, "h");
 
 /* Kommt spaeter vielleicht noch mal dran ...
- *    static struct wait_queue *gscd_waitq = NULL;
+ *    static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq);
  */ 
 
 static void gscd_transfer         (void);
diff -u --recursive --new-file v2.3.2/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.3.2/linux/drivers/cdrom/sbpcd.c	Fri May 14 18:55:15 1999
+++ linux/drivers/cdrom/sbpcd.c	Sat May 15 15:05:36 1999
@@ -585,7 +585,7 @@
 /*==========================================================================*/
 
 #if FUTURE
-static struct wait_queue *sbp_waitq = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq);
 #endif FUTURE
 
 static int teac=SBP_TEAC_SPEED;
diff -u --recursive --new-file v2.3.2/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.3.2/linux/drivers/char/cyclades.c	Fri May 14 18:55:15 1999
+++ linux/drivers/char/cyclades.c	Sat May 15 23:43:04 1999
@@ -1264,7 +1264,7 @@
 							    TTY_OVERRUN;
                                         *tty->flip.char_buf_ptr++ = 0;
                                         /* If the flip buffer itself is
-                                           overflowing, we still loose
+                                           overflowing, we still lose
                                            the next incoming character.
                                          */
                                         if(tty->flip.count
diff -u --recursive --new-file v2.3.2/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c
--- v2.3.2/linux/drivers/char/dn_keyb.c	Mon Apr 26 13:28:07 1999
+++ linux/drivers/char/dn_keyb.c	Sat May 15 15:05:36 1999
@@ -47,7 +47,7 @@
 static unsigned int kbd_mode=APOLLO_KBD_MODE_KEYB;
 static short mouse_dx,mouse_dy,mouse_buttons;
 static int mouse_ready=0,mouse_update_allowed=0,mouse_active=0;
-static struct wait_queue *mouse_wait=NULL;
+static DECLARE_WAIT_QUEUE_HEAD(mouse_wait);
 static struct fasync_struct *mouse_fasyncptr=NULL;
 
 #if 0
diff -u --recursive --new-file v2.3.2/linux/drivers/char/h8.c linux/drivers/char/h8.c
--- v2.3.2/linux/drivers/char/h8.c	Mon Aug 24 13:02:44 1998
+++ linux/drivers/char/h8.c	Sat May 15 15:05:36 1999
@@ -160,7 +160,7 @@
  */
 int cpu_speed_divisor = -1;			
 int h8_event_mask = 0;			
-struct wait_queue *h8_monitor_wait = NULL;
+DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
 unsigned int h8_command_mask = 0;
 int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
 int h8_uthermal_window = UTH_HYSTERESIS;		      
@@ -170,7 +170,7 @@
 u_char h8_current_temp = 0;
 u_char h8_system_temp = 0;
 int h8_sync_channel = 0;
-struct wait_queue *h8_sync_wait = NULL;
+DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
 int h8_init_performed;
 
 /* CPU speeds and clock divisor values */
diff -u --recursive --new-file v2.3.2/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.3.2/linux/drivers/char/keyboard.c	Fri May 14 18:55:16 1999
+++ linux/drivers/char/keyboard.c	Sun May 16 10:12:38 1999
@@ -279,7 +279,8 @@
 		u_char type;
 
 		/* the XOR below used to be an OR */
-		int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
+		int shift_final = (shift_state | kbd->slockstate) ^
+		    kbd->lockstate;
 		ushort *key_map = key_maps[shift_final];
 
 		if (key_map != NULL) {
@@ -311,6 +312,7 @@
 			/* we have at least to update shift_state */
 #if 1			/* how? two almost equivalent choices follow */
 			compute_shiftstate();
+			kbd->slockstate = 0; /* play it safe */
 #else
 			keysym = U(plain_map[keycode]);
 			type = KTYP(keysym);
@@ -472,6 +474,7 @@
 
 static void boot_it(void)
 {
+	if (kbd->slockstate & ~shift_state) return;
 	ctrl_alt_del();
 }
 
@@ -741,7 +744,7 @@
 	    for(j=0; j<BITS_PER_LONG; j++,k++)
 	      if(test_bit(k, key_down)) {
 		sym = U(plain_map[k]);
-		if(KTYP(sym) == KT_SHIFT) {
+		if(KTYP(sym) == KT_SHIFT || KTYP(sym) == KT_SLOCK) {
 		  val = KVAL(sym);
 		  if (val == KVAL(K_CAPSSHIFT))
 		    val = KVAL(K_SHIFT);
@@ -793,9 +796,15 @@
 
 static void do_slock(unsigned char value, char up_flag)
 {
+	do_shift(value,up_flag);
 	if (up_flag || rep)
 		return;
 	chg_vc_kbd_slock(kbd, value);
+	/* try to make Alt, oops, AltGr and such work */
+	if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
+		kbd->slockstate = 0;
+		chg_vc_kbd_slock(kbd, value);
+	}
 }
 
 /*
diff -u --recursive --new-file v2.3.2/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- v2.3.2/linux/drivers/char/pcxx.c	Wed Mar 10 16:51:35 1999
+++ linux/drivers/char/pcxx.c	Sat May 15 15:05:36 1999
@@ -326,7 +326,7 @@
 
 static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info)
 {
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 	int	retval = 0;
 	int	do_clocal = 0;
 
diff -u --recursive --new-file v2.3.2/linux/drivers/char/pcxx.h linux/drivers/char/pcxx.h
--- v2.3.2/linux/drivers/char/pcxx.h	Sun Apr 13 10:18:20 1997
+++ linux/drivers/char/pcxx.h	Sat May 15 15:05:36 1999
@@ -88,8 +88,8 @@
 	int							blocked_open;
 	int							close_delay;
 	int							event;
-	struct wait_queue			*open_wait;
-	struct wait_queue			*close_wait;
+	wait_queue_head_t			open_wait;
+	wait_queue_head_t			close_wait;
 	struct tq_struct			tqueue;
 							/* ------------ Async control data ------------- */
 	unchar						modemfake;      /* Modem values to be forced */
diff -u --recursive --new-file v2.3.2/linux/drivers/char/planb.c linux/drivers/char/planb.c
--- v2.3.2/linux/drivers/char/planb.c	Mon May 10 10:17:28 1999
+++ linux/drivers/char/planb.c	Sat May 15 15:05:36 1999
@@ -379,7 +379,7 @@
 
 static void __planb_wait(struct planb *pb)
 {
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 
 	add_wait_queue(&pb->lockq, &wait);
 repeat:
diff -u --recursive --new-file v2.3.2/linux/drivers/char/planb.h linux/drivers/char/planb.h
--- v2.3.2/linux/drivers/char/planb.h	Fri May  7 11:05:30 1999
+++ linux/drivers/char/planb.h	Sat May 15 15:05:36 1999
@@ -175,7 +175,7 @@
 	unsigned int tab_size;
 	int     maxlines;
 	int lock;
-	struct wait_queue *lockq;
+	wait_queue_head_t lockq;
 	unsigned int	irq;			/* interrupt number */
 	volatile unsigned int intr_mask;
 
@@ -190,13 +190,13 @@
 	unsigned long ch1_cmd_phys;
 	volatile unsigned char *mask;		/* Clipmask buffer */
 	int suspend;
-	struct wait_queue *suspendq;
+	wait_queue_head_t suspendq;
 	struct planb_suspend suspended;
 	int	cmd_buff_inited;		/* cmd buffer inited? */
 
 	int grabbing;
 	unsigned int gcount;
-	struct wait_queue *capq;
+	wait_queue_head_t capq;
 	int last_fr;
 	int prev_last_fr;
         unsigned char *fbuffer;
diff -u --recursive --new-file v2.3.2/linux/drivers/char/serial167.c linux/drivers/char/serial167.c
--- v2.3.2/linux/drivers/char/serial167.c	Thu Nov  5 09:58:43 1998
+++ linux/drivers/char/serial167.c	Sat May 15 15:05:36 1999
@@ -2007,7 +2007,7 @@
 block_til_ready(struct tty_struct *tty, struct file * filp,
                            struct cyclades_port *info)
 {
-  struct wait_queue wait = { current, NULL };
+  DECLARE_WAITQUEUE(wait, current);
   unsigned long flags;
   int channel;
   int retval;
diff -u --recursive --new-file v2.3.2/linux/drivers/isdn/avmb1/capidev.h linux/drivers/isdn/avmb1/capidev.h
--- v2.3.2/linux/drivers/isdn/avmb1/capidev.h	Thu May 29 21:53:05 1997
+++ linux/drivers/isdn/avmb1/capidev.h	Sat May 15 15:05:36 1999
@@ -22,7 +22,7 @@
 	int is_registered;
 	__u16 applid;
 	struct sk_buff_head recv_queue;
-	struct wait_queue *recv_wait;
+	wait_queue_head_t recv_wait;
 	__u16 errcode;
 };
 
diff -u --recursive --new-file v2.3.2/linux/drivers/isdn/pcbit/pcbit.h linux/drivers/isdn/pcbit/pcbit.h
--- v2.3.2/linux/drivers/isdn/pcbit/pcbit.h	Tue Aug  4 10:31:59 1998
+++ linux/drivers/isdn/pcbit/pcbit.h	Sat May 15 15:05:36 1999
@@ -68,7 +68,7 @@
 	struct frame_buf *write_queue;
 
 	/* Protocol start */
-	struct wait_queue *set_running_wq;
+	wait_queue_head_t set_running_wq;
 	struct timer_list set_running_timer;
 
 	struct timer_list error_recover_timer;
diff -u --recursive --new-file v2.3.2/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- v2.3.2/linux/drivers/macintosh/adb.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/adb.c	Sat May 15 15:05:36 1999
@@ -375,7 +375,7 @@
 	spinlock_t	lock;
 	atomic_t	n_pending;
 	struct adb_request *completed;
-	struct wait_queue *wait_queue;
+	wait_queue_head_t wait_queue;
 	int		inuse;
 };
 
@@ -458,7 +458,7 @@
 	int ret;
 	struct adbdev_state *state = file->private_data;
 	struct adb_request *req;
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 
 	if (count < 2)
diff -u --recursive --new-file v2.3.2/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.3.2/linux/drivers/macintosh/mac_keyb.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/mac_keyb.c	Sat May 15 15:05:36 1999
@@ -251,7 +251,7 @@
 extern int console_loglevel;
 
 extern struct kbd_struct kbd_table[];
-extern struct wait_queue * keypress_wait;
+extern struct wait_queue_head_t keypress_wait;
 
 extern void handle_scancode(unsigned char, int);
 
diff -u --recursive --new-file v2.3.2/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.3.2/linux/drivers/macintosh/macserial.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/macserial.c	Sat May 15 15:05:36 1999
@@ -1595,7 +1595,7 @@
 static int block_til_ready(struct tty_struct *tty, struct file * filp,
 			   struct mac_serial *info)
 {
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait,current);
 	int		retval;
 	int		do_clocal = 0;
 
diff -u --recursive --new-file v2.3.2/linux/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h
--- v2.3.2/linux/drivers/macintosh/macserial.h	Wed Mar 10 21:48:46 1999
+++ linux/drivers/macintosh/macserial.h	Sat May 15 15:05:36 1999
@@ -153,8 +153,8 @@
 	struct tq_struct	tqueue_hangup;
 	struct termios		normal_termios;
 	struct termios		callout_termios;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
 };
 
 
diff -u --recursive --new-file v2.3.2/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.3.2/linux/drivers/misc/parport_init.c	Tue May 11 09:55:49 1999
+++ linux/drivers/misc/parport_init.c	Sun May 16 10:55:21 1999
@@ -20,10 +20,11 @@
 
 #ifndef MODULE
 static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
+static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
 static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
 static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
 
-extern int parport_pc_init(int *io, int *irq, int *dma);
+extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
 extern int parport_ax_init(void);
 
 static int parport_setup_ptr __initdata = 0;
@@ -121,7 +122,7 @@
 	parport_proc_init();
 #endif
 #ifdef CONFIG_PARPORT_PC
-	parport_pc_init(io, irq, dma);
+	parport_pc_init(io, io_hi, irq, dma);
 #endif
 #ifdef CONFIG_PARPORT_AX
 	parport_ax_init();
diff -u --recursive --new-file v2.3.2/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.3.2/linux/drivers/misc/parport_pc.c	Mon May 10 10:26:31 1999
+++ linux/drivers/misc/parport_pc.c	Sun May 16 10:10:00 1999
@@ -36,6 +36,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -53,7 +54,7 @@
    than PARPORT_MAX (in <linux/parport.h>).  */
 #define PARPORT_PC_MAX_PORTS  8
 
-static int user_specified = 0;
+static int user_specified __initdata = 0;
 
 static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -62,27 +63,27 @@
 
 void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPDATA);
+	outb(d, EPPDATA(p));
 }
 
 unsigned char parport_pc_read_epp(struct parport *p)
 {
-	return inb(p->base+EPPDATA);
+	return inb(EPPDATA(p));
 }
 
 void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPADDR);
+	outb(d, EPPADDR(p));
 }
 
 unsigned char parport_pc_read_epp_addr(struct parport *p)
 {
-	return inb(p->base+EPPADDR);
+	return inb(EPPADDR(p));
 }
 
 int parport_pc_check_epp_timeout(struct parport *p)
 {
-	if (!(inb(p->base+STATUS) & 1))
+	if (!(inb(STATUS(p)) & 1))
 		return 0;
 	parport_pc_epp_clear_timeout(p);
 	return 1;
@@ -90,24 +91,24 @@
 
 unsigned char parport_pc_read_configb(struct parport *p)
 {
-	return inb(p->base+CONFIGB);
+	return inb(CONFIGB(p));
 }
 
 void parport_pc_write_data(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+DATA);
+	outb(d, DATA(p));
 }
 
 unsigned char parport_pc_read_data(struct parport *p)
 {
-	return inb(p->base+DATA);
+	return inb(DATA(p));
 }
 
 void parport_pc_write_control(struct parport *p, unsigned char d)
 {
 	struct parport_pc_private *priv = p->private_data;
 	priv->ctr = d;/* update soft copy */
-	outb(d, p->base+CONTROL);
+	outb(d, CONTROL(p));
 }
 
 unsigned char parport_pc_read_control(struct parport *p)
@@ -121,34 +122,34 @@
 	struct parport_pc_private *priv = p->private_data;
 	unsigned char ctr = priv->ctr;
 	ctr = (ctr & ~mask) ^ val;
-	outb (ctr, p->base+CONTROL);
+	outb (ctr, CONTROL(p));
 	return priv->ctr = ctr; /* update soft copy */
 }
 
 void parport_pc_write_status(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+STATUS);
+	outb(d, STATUS(p));
 }
 
 unsigned char parport_pc_read_status(struct parport *p)
 {
-	return inb(p->base+STATUS);
+	return inb(STATUS(p));
 }
 
 void parport_pc_write_econtrol(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+ECONTROL);
+	outb(d, ECONTROL(p));
 }
 
 unsigned char parport_pc_read_econtrol(struct parport *p)
 {
-	return inb(p->base+ECONTROL);
+	return inb(ECONTROL(p));
 }
 
 unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask,  unsigned char val)
 {
-	unsigned char old = inb(p->base+ECONTROL);
-	outb(((old & ~mask) ^ val), p->base+ECONTROL);
+	unsigned char old = inb(ECONTROL(p));
+	outb(((old & ~mask) ^ val), ECONTROL(p));
 	return old;
 }
 
@@ -159,12 +160,12 @@
 
 void parport_pc_write_fifo(struct parport *p, unsigned char v)
 {
-	outb (v, p->base+CONFIGA);
+	outb (v, CONFIGA(p));
 }
 
 unsigned char parport_pc_read_fifo(struct parport *p)
 {
-	return inb (p->base+CONFIGA);
+	return inb (CONFIGA(p));
 }
 
 void parport_pc_disable_irq(struct parport *p)
@@ -183,7 +184,7 @@
 		free_irq(p->irq, p);
 	release_region(p->base, p->size);
 	if (p->modes & PARPORT_MODE_PCECR)
-		release_region(p->base+0x400, 3);
+		release_region(p->base_hi, 3);
 }
 
 int parport_pc_claim_resources(struct parport *p)
@@ -195,7 +196,7 @@
 			return err;
 	request_region(p->base, p->size, p->name);
 	if (p->modes & PARPORT_MODE_PCECR)
-		request_region(p->base+0x400, 3, p->name);
+		request_region(p->base_hi, 3, p->name);
 	return 0;
 }
 
@@ -223,8 +224,8 @@
 {
 	size_t got = 0;
 	for (; got < length; got++) {
-		*((char*)buf)++ = inb (p->base+EPPDATA);
-		if (inb (p->base+STATUS) & 0x01)
+		*((char*)buf)++ = inb (EPPDATA(p));
+		if (inb (STATUS(p)) & 0x01)
 			break;
 	}
 	return got;
@@ -234,8 +235,8 @@
 {
 	size_t written = 0;
 	for (; written < length; written++) {
-		outb (*((char*)buf)++, p->base+EPPDATA);
-		if (inb (p->base+STATUS) & 0x01)
+		outb (*((char*)buf)++, EPPDATA(p));
+		if (inb (STATUS(p)) & 0x01)
 			break;
 	}
 	return written;
@@ -350,7 +351,7 @@
 /*
  * Checks for port existence, all ports support SPP MODE
  */
-static int parport_SPP_supported(struct parport *pb)
+static int __init parport_SPP_supported(struct parport *pb)
 {
 	unsigned char r, w;
 
@@ -370,11 +371,11 @@
 	 * allow reads, so read_control just returns a software
 	 * copy. Some ports _do_ allow reads, so bypass the software
 	 * copy here.  In addition, some bits aren't writable. */
-	r = inb (pb->base+CONTROL);
+	r = inb (CONTROL (pb));
 	if ((r & 0x3f) == w) {
 		w = 0xe;
 		parport_pc_write_control (pb, w);
-		r = inb (pb->base+CONTROL);
+		r = inb (CONTROL(pb));
 		parport_pc_write_control (pb, 0xc);
 		if ((r & 0x3f) == w)
 			return PARPORT_MODE_PCSPP;
@@ -425,7 +426,7 @@
  * We will write 0x2c to ECR and 0xcc to CTR since both of these
  * values are "safe" on the CTR since bits 6-7 of CTR are unused.
  */
-static int parport_ECR_present(struct parport *pb)
+static int __init parport_ECR_present(struct parport *pb)
 {
 	unsigned char r;
 
@@ -458,7 +459,7 @@
 	return 0;
 }
 
-static int parport_ECP_supported(struct parport *pb)
+static int __init parport_ECP_supported(struct parport *pb)
 {
 	int i;
 	unsigned char oecr;
@@ -493,7 +494,7 @@
  *	or writing a 1 to the bit (SMC, UMC, WinBond), others ???
  *	This bit is always high in non EPP modes.
  */
-static int parport_EPP_supported(struct parport *pb)
+static int __init parport_EPP_supported(struct parport *pb)
 {
 	/* If EPP timeout bit clear then EPP available */
 	if (!parport_pc_epp_clear_timeout(pb))
@@ -514,7 +515,7 @@
 	return 0;
 }
 
-static int parport_ECPEPP_supported(struct parport *pb)
+static int __init parport_ECPEPP_supported(struct parport *pb)
 {
 	int mode;
 	unsigned char oecr;
@@ -550,7 +551,7 @@
  * be misdetected here is rather academic. 
  */
 
-static int parport_PS2_supported(struct parport *pb)
+static int __init parport_PS2_supported(struct parport *pb)
 {
 	int ok = 0;
 	unsigned char octr = parport_pc_read_control(pb);
@@ -570,7 +571,7 @@
 	return ok?PARPORT_MODE_PCPS2:0;
 }
 
-static int parport_ECPPS2_supported(struct parport *pb)
+static int __init parport_ECPPS2_supported(struct parport *pb)
 {
 	int mode;
 	unsigned char oecr;
@@ -590,7 +591,7 @@
 /* --- IRQ detection -------------------------------------- */
 
 /* Only if supports ECP mode */
-static int programmable_irq_support(struct parport *pb)
+static int __init programmable_irq_support(struct parport *pb)
 {
 	int irq, intrLine;
 	unsigned char oecr = parport_pc_read_econtrol(pb);
@@ -607,7 +608,7 @@
 	return irq;
 }
 
-static int irq_probe_ECP(struct parport *pb)
+static int __init irq_probe_ECP(struct parport *pb)
 {
 	int irqs, i;
 
@@ -634,7 +635,7 @@
  * This detection seems that only works in National Semiconductors
  * This doesn't work in SMC, LGS, and Winbond 
  */
-static int irq_probe_EPP(struct parport *pb)
+static int __init irq_probe_EPP(struct parport *pb)
 {
 	int irqs;
 	unsigned char octr = parport_pc_read_control(pb);
@@ -675,7 +676,7 @@
 	return pb->irq;
 }
 
-static int irq_probe_SPP(struct parport *pb)
+static int __init irq_probe_SPP(struct parport *pb)
 {
 	int irqs;
 	unsigned char octr = parport_pc_read_control(pb);
@@ -723,7 +724,7 @@
  * When ECP is available we can autoprobe for IRQs.
  * NOTE: If we can autoprobe it, we can register the IRQ.
  */
-static int parport_irq_probe(struct parport *pb)
+static int __init parport_irq_probe(struct parport *pb)
 {
 	if (pb->modes & PARPORT_MODE_PCECR) {
 		pb->irq = programmable_irq_support(pb);
@@ -754,7 +755,9 @@
 
 /* --- Initialisation code -------------------------------- */
 
-static int probe_one_port(unsigned long int base, int irq, int dma)
+static int __init probe_one_port(unsigned long int base,
+				 unsigned long int base_hi,
+				 int irq, int dma)
 {
 	struct parport *p;
 	int probedirq = PARPORT_IRQ_NONE;
@@ -770,8 +773,9 @@
 		return 0;
 	}
 	((struct parport_pc_private *) (p->private_data))->ctr = 0xc;
+	p->base_hi = base_hi;
 	if (p->base != 0x3bc) {
-		if (!check_region(base+0x400,3)) {
+		if (base_hi && !check_region(base_hi,3)) {
 			p->modes |= parport_ECR_present(p);	
 			p->modes |= parport_ECP_supported(p);
 			p->modes |= parport_ECPPS2_supported(p);
@@ -791,6 +795,8 @@
 	p->size = (p->modes & (PARPORT_MODE_PCEPP 
 			       | PARPORT_MODE_PCECPEPP))?8:3;
 	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
+	if (p->base_hi && (p->modes & PARPORT_MODE_PCECR))
+		printk (" (0x%lx)", p->base_hi);
 	if (p->irq == PARPORT_IRQ_AUTO) {
 		p->irq = PARPORT_IRQ_NONE;
 		parport_irq_probe(p);
@@ -829,11 +835,14 @@
 	/* Done probing.  Now put the port into a sensible start-up state. */
 	if (p->modes & PARPORT_MODE_PCECR)
 		/*
-		 * Put the ECP detected port in the more SPP like mode.
+		 * Put the ECP detected port in PS2 mode.
 		 */
-		parport_pc_write_econtrol(p, 0x0);
-	parport_pc_write_control(p, 0xc);
+		parport_pc_write_econtrol(p, 0x24);
 	parport_pc_write_data(p, 0);
+	parport_pc_write_control(p, 0x8);
+	udelay (50);
+	parport_pc_write_control(p, 0xc);
+	udelay (50);
 
 	if (parport_probe_hook)
 		(*parport_probe_hook)(p);
@@ -841,20 +850,22 @@
 	return 1;
 }
 
-int parport_pc_init(int *io, int *irq, int *dma)
+int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
 {
 	int count = 0, i = 0;
 	if (io && *io) {
 		/* Only probe the ports we were given. */
 		user_specified = 1;
 		do {
-			count += probe_one_port(*(io++), *(irq++), *(dma++));
+			if (!*io_hi) *io_hi = 0x400 + *io;
+			count += probe_one_port(*(io++), *(io_hi++),
+						*(irq++), *(dma++));
 		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
 	} else {
 		/* Probe all the likely ports. */
-		count += probe_one_port(0x3bc, irq[0], dma[0]);
-		count += probe_one_port(0x378, irq[0], dma[0]);
-		count += probe_one_port(0x278, irq[0], dma[0]);
+		count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
+		count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
+		count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
 	}
 
 	return count;
@@ -862,10 +873,12 @@
 
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
+static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
 static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
 
@@ -877,7 +890,7 @@
 	for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
 	parport_parse_irqs(i, irq, irqval);
 
-	return (parport_pc_init(io, irqval, dma)?0:1);
+	return (parport_pc_init(io, io_hi, irqval, dma)?0:1);
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v2.3.2/linux/drivers/net/cosa.c linux/drivers/net/cosa.c
--- v2.3.2/linux/drivers/net/cosa.c	Sun Mar  7 15:47:46 1999
+++ linux/drivers/net/cosa.c	Sat May 15 15:05:36 1999
@@ -126,7 +126,8 @@
 	struct semaphore rsem, wsem;
 	char *rxdata;
 	int rxsize;
-	struct wait_queue *txwaitq, *rxwaitq;
+	wait_queue_head_t txwaitq; 
+	wait_queue_head_t rxwaitq;
 	int tx_status, rx_status;
 
 	/* SPPP/HDLC device parts */
@@ -762,7 +763,7 @@
 static ssize_t cosa_read(struct file *file,
 	char *buf, size_t count, loff_t *ppos)
 {
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 	int flags;
 	struct channel_data *chan = (struct channel_data *)file->private_data;
 	struct cosa_data *cosa = chan->cosa;
@@ -833,7 +834,7 @@
 	const char *buf, size_t count, loff_t *ppos)
 {
 	struct channel_data *chan = (struct channel_data *)file->private_data;
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 	struct cosa_data *cosa = chan->cosa;
 	unsigned int flags;
 	char *kbuf;
diff -u --recursive --new-file v2.3.2/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v2.3.2/linux/drivers/net/de620.c	Mon Mar  2 11:55:41 1998
+++ linux/drivers/net/de620.c	Sat May 15 23:43:04 1999
@@ -664,7 +664,7 @@
 	if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) {
 		/* Ouch... Forget it! Skip all and start afresh... */
 		printk("%s: Ring overrun? Restoring...\n", dev->name);
-		/* You win some, you loose some. And sometimes plenty... */
+		/* You win some, you lose some. And sometimes plenty... */
 		adapter_init(dev);
 		((struct net_device_stats *)(dev->priv))->rx_over_errors++;
 		return 0;
diff -u --recursive --new-file v2.3.2/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.3.2/linux/drivers/net/sunhme.c	Mon Mar 15 16:11:30 1999
+++ linux/drivers/net/sunhme.c	Sat May 15 11:12:09 1999
@@ -1834,7 +1834,7 @@
 #define RXD(x)
 #endif
 
-/* Originally I use to handle the allocation failure by just giving back just
+/* Originally I used to handle the allocation failure by just giving back just
  * that one ring buffer to the happy meal.  Problem is that usually when that
  * condition is triggered, the happy meal expects you to do something reasonable
  * with all of the packets it has DMA'd in.  So now I just drop the entire
diff -u --recursive --new-file v2.3.2/linux/drivers/net/z85230.h linux/drivers/net/z85230.h
--- v2.3.2/linux/drivers/net/z85230.h	Sat Oct 17 15:33:45 1998
+++ linux/drivers/net/z85230.h	Sat May 15 15:05:36 1999
@@ -331,8 +331,8 @@
 	int			line;		/* Minor number */
 	struct termios		normal_termios;	/* Terminal settings */
 	struct termios		callout_termios;
-	struct wait_queue	*open_wait;	/* Tasks waiting to open */
-	struct wait_queue	*close_wait;	/* and for close to end */
+	wait_queue_head_t	open_wait;	/* Tasks waiting to open */
+	wait_queue_head_t	close_wait;	/* and for close to end */
 	unsigned long		event;		/* Pending events */
 	int			fdcount;    	/* # of fd on device */
 	int			blocked_open;	/* # of blocked opens */
diff -u --recursive --new-file v2.3.2/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.3.2/linux/drivers/sbus/char/pcikbd.c	Fri May 14 18:55:21 1999
+++ linux/drivers/sbus/char/pcikbd.c	Sun May 16 19:15:57 1999
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.28 1999/05/12 11:15:05 davem Exp $
+/* $Id: pcikbd.c,v 1.29 1999/05/16 13:47:53 ecd Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -982,6 +982,8 @@
 		return -ENOMEM;
 	}
 	memset(queue, 0, sizeof(*queue));
+
+	init_waitqueue_head(&queue->proc_list);
 
 	if (request_irq(pcimouse_irq, &pcimouse_interrupt,
 		        SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) {
diff -u --recursive --new-file v2.3.2/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c
--- v2.3.2/linux/drivers/scsi/sd_ioctl.c	Wed Feb 24 16:27:54 1999
+++ linux/drivers/scsi/sd_ioctl.c	Sat May 15 23:43:04 1999
@@ -15,6 +15,7 @@
 
 #define MAJOR_NR	SCSI_DISK0_MAJOR
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 #include "scsi.h"
 #include <scsi/scsi_ioctl.h>
 #include "hosts.h"
@@ -79,41 +80,19 @@
 		 (long *) arg);
 	return 0;
 
+    case BLKROSET:
+    case BLKROGET:
     case BLKRASET:
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-	if(!(inode->i_rdev)) return -EINVAL;
-	if(arg > 0xff) return -EINVAL;
-	read_ahead[MAJOR(inode->i_rdev)] = arg;
-	return 0;
-
     case BLKRAGET:
-	if (!arg)
-		return -EINVAL;
-	error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
-	if (error)
-	    return error;
-	put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
-	return 0;
-
     case BLKFLSBUF:
-	if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-	if(!(inode->i_rdev)) return -EINVAL;
-	fsync_dev(inode->i_rdev);
-	invalidate_buffers(inode->i_rdev);
-	return 0;
-	
+    case BLKSSZGET:
+    case BLKPG:
+	return blk_ioctl(inode->i_rdev, cmd, arg);
+
     case BLKRRPART: /* Re-read partition tables */
         if (!capable(CAP_SYS_ADMIN))
                 return -EACCES;
 	return revalidate_scsidisk(dev, 1);
-
-    case BLKSSZGET:
-	/* Block size of media */
-	return put_user(blksize_size[MAJOR(dev)][MINOR(dev)&0x0F],
-		(int *)arg);
-				
-    RO_IOCTLS(dev, arg);
 
     default:
 	return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg);
diff -u --recursive --new-file v2.3.2/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.3.2/linux/drivers/scsi/sr_ioctl.c	Sat May 15 23:46:03 1999
+++ linux/drivers/scsi/sr_ioctl.c	Sat May 15 23:43:04 1999
@@ -7,6 +7,7 @@
 #include <linux/string.h>
 
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 #include "scsi.h"
 #include "hosts.h"
 #include <scsi/scsi_ioctl.h>
@@ -768,7 +769,7 @@
 int sr_dev_ioctl(struct cdrom_device_info *cdi,
                  unsigned int cmd, unsigned long arg)
 {
-    int target, err;
+    int target;
     
     target = MINOR(cdi->dev);
     
@@ -855,40 +856,14 @@
         spin_unlock_irqrestore(&io_request_lock, flags);
         return rc;
     }
-    case BLKRAGET:
-	if (!arg)
-		return -EINVAL;
-	err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
-	if (err)
-		return err;
-	put_user(read_ahead[MAJOR(cdi->dev)], (long *) arg);
-	return 0;
 
+    case BLKROSET:
+    case BLKROGET:
     case BLKRASET:
-	if(!capable(CAP_SYS_ADMIN))
-        	return -EACCES;
-	if(!(cdi->dev))
-        	return -EINVAL;
-	if(arg > 0xff)
-        	return -EINVAL;
-	read_ahead[MAJOR(cdi->dev)] = arg;
-	return 0;
-
-    case BLKSSZGET:
-	/* Block size of media */
-	return put_user(blksize_size[MAJOR(cdi->dev)][MINOR(cdi->dev)],
-		(int *)arg);
-
-    RO_IOCTLS(cdi->dev,arg);
-
+    case BLKRAGET:
     case BLKFLSBUF:
-	if(!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-	if(!(cdi->dev))
-		return -EINVAL;
-	fsync_dev(cdi->dev);
-	invalidate_buffers(cdi->dev);
-	return 0;
+    case BLKSSZGET:
+	return blk_ioctl(cdi->dev, cmd, arg);
 
     default:
 	return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
diff -u --recursive --new-file v2.3.2/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v2.3.2/linux/drivers/scsi/st.h	Sun Sep  6 09:48:30 1998
+++ linux/drivers/scsi/st.h	Sat May 15 15:05:36 1999
@@ -65,7 +65,7 @@
 typedef struct {
   kdev_t devt;
   unsigned capacity;
-  struct wait_queue * waiting;
+  wait_queue_head_t waiting;
   Scsi_Device* device;
   struct semaphore sem;
   ST_buffer * buffer;
diff -u --recursive --new-file v2.3.2/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c
--- v2.3.2/linux/drivers/sgi/char/sgiserial.c	Thu Nov  5 09:58:44 1998
+++ linux/drivers/sgi/char/sgiserial.c	Sat May 15 15:05:36 1999
@@ -33,7 +33,7 @@
 #define NUM_SERIAL 1     /* One chip on board. */
 #define NUM_CHANNELS (NUM_SERIAL * 2)
 
-extern struct wait_queue * keypress_wait;
+extern struct wait_queue_head_t keypress_wait;
 
 struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, };
 struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, };
@@ -1519,7 +1519,7 @@
 static int block_til_ready(struct tty_struct *tty, struct file * filp,
 			   struct sgi_serial *info)
 {
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 	int		retval;
 	int		do_clocal = 0;
 
diff -u --recursive --new-file v2.3.2/linux/drivers/sgi/char/sgiserial.h linux/drivers/sgi/char/sgiserial.h
--- v2.3.2/linux/drivers/sgi/char/sgiserial.h	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/sgiserial.h	Sat May 15 15:05:36 1999
@@ -158,8 +158,8 @@
 	struct tq_struct	tqueue_hangup;
 	struct termios		normal_termios;
 	struct termios		callout_termios;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
 };
 
 
diff -u --recursive --new-file v2.3.2/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.3.2/linux/drivers/sgi/char/shmiq.c	Mon Aug 24 13:14:10 1998
+++ linux/drivers/sgi/char/shmiq.c	Sat May 15 15:05:36 1999
@@ -82,7 +82,7 @@
 	int    events;
 	int    mapped;
 	
-	struct wait_queue    *proc_list;
+	wait_queue_head_t     proc_list;
 	struct fasync_struct *fasync;
 } shmiqs [MAX_SHMI_QUEUES];
 
diff -u --recursive --new-file v2.3.2/linux/drivers/sgi/char/usema.c linux/drivers/sgi/char/usema.c
--- v2.3.2/linux/drivers/sgi/char/usema.c	Mon Aug 24 13:02:44 1998
+++ linux/drivers/sgi/char/usema.c	Sat May 15 15:05:36 1999
@@ -39,7 +39,7 @@
 
 struct irix_usema {
 	struct file *filp;
-	struct wait_queue *proc_list;
+	wait_queue_head_t proc_list;
 };
 
 static int
diff -u --recursive --new-file v2.3.2/linux/drivers/sound/lowlevel/awe_compat.h linux/drivers/sound/lowlevel/awe_compat.h
--- v2.3.2/linux/drivers/sound/lowlevel/awe_compat.h	Sun Mar  7 15:22:06 1999
+++ linux/drivers/sound/lowlevel/awe_compat.h	Sat May 15 15:05:36 1999
@@ -245,7 +245,7 @@
 #endif /* AWE_MODULE_SUPPORT */
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
-inline static void interruptible_sleep_on_timeout(struct wait_queue **q, unsigned long timeout)
+inline static void interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout)
 {
 	current->timeout = jiffies + timeout;
 	interruptible_sleep_on(q);
diff -u --recursive --new-file v2.3.2/linux/drivers/sound/lowlevel/awe_wave.c linux/drivers/sound/lowlevel/awe_wave.c
--- v2.3.2/linux/drivers/sound/lowlevel/awe_wave.c	Sun Mar  7 15:22:06 1999
+++ linux/drivers/sound/lowlevel/awe_wave.c	Sat May 15 15:05:36 1999
@@ -979,7 +979,7 @@
 }
 #else
 
-static struct wait_queue *awe_sleeper = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(awe_sleeper);
 static void awe_wait(unsigned short delay)
 {
 	interruptible_sleep_on_timeout(&awe_sleeper, (HZ * (unsigned long)delay + 44099) / 44100);
diff -u --recursive --new-file v2.3.2/linux/drivers/sound/msnd.h linux/drivers/sound/msnd.h
--- v2.3.2/linux/drivers/sound/msnd.h	Wed Dec 16 12:52:01 1998
+++ linux/drivers/sound/msnd.h	Sat May 15 15:05:37 1999
@@ -231,8 +231,9 @@
 #define F_EXT_MIDI_INUSE		9
 #define F_INT_MIDI_INUSE		10
 #define F_DISABLE_WRITE_NDELAY		11
-	struct wait_queue *writeblock, *readblock;
-	struct wait_queue *writeflush;
+	wait_queue_head_t writeblock;
+	wait_queue_head_t readblock;
+	wait_queue_head_t writeflush;
 #ifndef LINUX20
 	spinlock_t lock;
 #endif
diff -u --recursive --new-file v2.3.2/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.2/linux/drivers/usb/Config.in	Sat May 15 23:46:03 1999
+++ linux/drivers/usb/Config.in	Sun May 16 22:23:31 1999
@@ -14,7 +14,12 @@
 tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
 if [ ! "$CONFIG_USB" = "n" ]; then
   bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
+
   bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
+  if [ "$CONFIG_USB_OHCI" = "y" ]; then
+     bool '  Enable tons of OHCI debugging output?' CONFIG_USB_OHCI_DEBUG
+  fi
+
   bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD
   if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then
      bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
diff -u --recursive --new-file v2.3.2/linux/drivers/usb/README.ohci linux/drivers/usb/README.ohci
--- v2.3.2/linux/drivers/usb/README.ohci	Tue May 11 10:04:03 1999
+++ linux/drivers/usb/README.ohci	Sun May 16 22:23:31 1999
@@ -1,3 +1,31 @@
+May 16, 1999 16:20:54
+
+EDs are now allocated dynamically from their device's pool.  Root hub
+status changes should stop the infinite "no device connected" messages
+that occurred after removing a device.
+
+TODO:
+
+~ Add the concept of a td_group to lump TDs associated with a single
+  data transfer request from the higher layers.  This will be needed
+  for bulk and all larger transfers that will span multiple TDs but
+  which need to allocate/free them as a group as things happen.  I
+  am thinking about create_td_group and free_td_group functions...
+~ Add bulk transfer support.
+~ Add Isochronous transfer support.  These have their own special
+  format TDs to allow for several DMA data pointers.  Kinda neat, but
+  likely harder to use through a generic interface in practice.
+~ Support dynamic allocation & growth of the TD/ED pools.  Merge them
+  into global pools rather than a today's static per device allocation.
+
+KNOWN BUGS:
+
+~ Unplugging a hub causes khubd to Oops.  I don't think this is
+  directly related to OHCI, but due to the fact that the interrupt TD
+  for the hub is never stopped.  We need a usb_release_irq() that gets
+  called using the "IRQ handle" that should be returned by
+  usb_request_irq().
+
 May 09, 1999 16:25:58
 
 Cool, things are working "well" now.  (I'm not getting oops's from the
diff -u --recursive --new-file v2.3.2/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c
--- v2.3.2/linux/drivers/usb/ohci-debug.c	Tue May 11 10:04:03 1999
+++ linux/drivers/usb/ohci-debug.c	Sun May 16 22:23:31 1999
@@ -80,17 +80,18 @@
 
 	printk(KERN_DEBUG "   ohci ED:\n");
 	printk(KERN_DEBUG "     status     =  0x%x\n", stat);
-	printk(KERN_DEBUG "       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
+	printk(KERN_DEBUG "       %sMPS %d%s%s%s%s tc%d e%d fa%d%s\n",
 			skip ? "Skip " : "",
 			mps,
-			isoc ? "Isoc. " : "",
+			isoc ? " Isoc." : "",
 			low_speed ? " LowSpd" : "",
 			(dir == OHCI_ED_D_IN) ? " Input" :
 			(dir == OHCI_ED_D_OUT) ? " Output" : "",
 			halted ? " Halted" : "",
 			toggle,
 			endnum,
-			funcaddr);
+			funcaddr,
+			(stat & ED_ALLOCATED) ? " Allocated" : "");
 	printk(KERN_DEBUG "     tail_td    =  0x%x\n", ed->tail_td);
 	printk(KERN_DEBUG "     head_td    =  0x%x\n", ed_head_td(ed));
 	printk(KERN_DEBUG "     next_ed    =  0x%x\n", ed->next_ed);
@@ -108,19 +109,21 @@
 
 	printk(KERN_DEBUG "   ohci TD hardware fields:\n");
 	printk(KERN_DEBUG "      info     =  0x%x\n", td->info);
-	printk(KERN_DEBUG "        %s%s%s%d %s\n",
+	printk(KERN_DEBUG "        %s%s%s%d %s %s%d\n",
 		td_round ? "Rounding " : "",
 		(td_dir == OHCI_TD_D_IN) ? "Input " :
 		(td_dir == OHCI_TD_D_OUT) ? "Output " :
 		(td_dir == OHCI_TD_D_SETUP) ? "Setup " : "",
 		"IntDelay ", td_int_delay,
 		(td_toggle < 2) ? " " :
-		(td_toggle & 1) ? "Data1 " : "Data0 ");
-	printk(KERN_DEBUG "        %s%d %s0x%x, %sAccessed, %sActive\n",
-		"ErrorCnt ", td_errcnt,
-		"ComplCode ", td_cc,
+		(td_toggle & 1) ? "Data1" : "Data0",
+		"ErrorCnt ", td_errcnt);
+	printk(KERN_DEBUG "        ComplCode 0x%x, %sAccessed, %sActive\n",
+		td_cc,
 		td_cc_accessed(*td) ? "" : "Not ",
 		td_active(*td) ? "" : "Not ");
+
+	printk(KERN_DEBUG "        %s\n", td_allocated(*td) ? "Allocated" : "Free");
 
 	printk(KERN_DEBUG "      cur_buf  =  0x%x\n", td->cur_buf);
 	printk(KERN_DEBUG "      next_td  =  0x%x\n", td->next_td);
diff -u --recursive --new-file v2.3.2/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.2/linux/drivers/usb/ohci.c	Sat May 15 23:46:03 1999
+++ linux/drivers/usb/ohci.c	Sun May 16 22:23:31 1999
@@ -29,7 +29,7 @@
  *
  * No filesystems were harmed in the development of this code.
  *
- * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $
+ * $Id: ohci.c,v 1.43 1999/05/16 22:35:24 greg Exp $
  */
 
 #include <linux/config.h>
@@ -59,31 +59,30 @@
 
 static DECLARE_WAIT_QUEUE_HEAD(ohci_configure);
 
-#ifdef OHCI_TIMER
-static struct timer_list ohci_timer;	/* timer for root hub polling */
+#ifdef CONFIG_USB_OHCI_DEBUG
+#define OHCI_DEBUG    /* to make typing it easier.. */
 #endif
 
+#ifdef OHCI_DEBUG
+int MegaDebug = 0;	/* SIGUSR2 to the control thread toggles this */
+#endif
 
-static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td)
-{
-	unsigned int status;
-
-	status = td->info & OHCI_TD_CC;
-
-	/* TODO Debugging code for TD failures goes here */
-
-	return status;
-} /* ohci_td_result() */
 
+#ifdef OHCI_TIMER
+static struct timer_list ohci_timer;	/* timer for root hub polling */
+#endif
 
 static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
 
 /*
- * Add a TD to the end of the TD list on a given ED.  If td->next_td
- * points to any more TDs, they will be added as well (naturally).
- * Otherwise td->next_td must be 0.
+ * Add a TD to the end of the TD list on a given ED.  This function
+ * does NOT advance the ED's tail_td pointer beyond the given TD.  To
+ * add multiple TDs, call this function once for each TD.  Do not
+ * "simply" update tail_td yourself... This function does more than
+ * that.
  * 
- * The SKIP flag will be cleared after this function.
+ * If this ED is on the controller, you MUST set its SKIP flag before
+ * calling this function.
  *
  * Important!  This function needs locking and atomicity as it works
  * in parallel with the HC's DMA.  Locking ohci_edtd_lock while using
@@ -93,54 +92,62 @@
  */
 static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed)
 {
-	/* don't let the HC pull anything from underneath us */
-	ed->status |= OHCI_ED_SKIP;
+	struct ohci_td *dummy_td, *prev_td;
+
+	if (ed->tail_td == 0) {
+		printk("eek! an ED without a dummy_td\n");
+	}
+
+	/* The ED's tail_td is constant, always pointing to the
+	 * dummy_td.  The reason the ED never processes the dummy is
+	 * that it stops processing TDs as soon as head_td == tail_td.
+	 * When it advances to this last dummy TD it conveniently stops. */
+	dummy_td = bus_to_virt(ed->tail_td);
 
-	if (ed_head_td(ed) == 0) {	/* empty list, put it on the head */
-		set_ed_head_td(ed, virt_to_bus(td));
-		ed->tail_td = 0;
+	/* Dummy's data pointer is used to point to the previous TD */
+	if (ed_head_td(ed) != ed->tail_td) {
+		prev_td = (struct ohci_td *) dummy_td->data;
 	} else {
-		struct ohci_td *tail, *head;
-		head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed));
-		tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td);
-		if (!tail) {	/* no tail, single element list */
-			td->next_td = head->next_td;
-			head->next_td = virt_to_bus(td);
-			ed->tail_td = virt_to_bus(td);
-		} else {	/* append to the list */
-			td->next_td = tail->next_td;
-			tail->next_td = virt_to_bus(td);
-			ed->tail_td = virt_to_bus(td);
-		}
+		/* if the ED is empty, previous is meaningless */
+		/* We'll be inserting into the head of the list */
+		prev_td = NULL;
 	}
 
-	/* save the ED link in each of the TDs added */
+	/* Store the new back pointer and set up this TD's next */
+	dummy_td->data = td;
+	td->next_td = ed->tail_td;
+
+	/* Store the TD pointer back to the ED */
 	td->ed = ed;
-	while (td->next_td != 0) {
-		td = bus_to_virt(td->next_td);
-		td->ed = ed;
-	}
 
-	/* turn off the SKIP flag */
-	ed->status &= ~OHCI_ED_SKIP;
+	if (!prev_td) { /* No previous TD? then insert us at the head */
+		if (ed_head_td(ed) != ed->tail_td)
+			printk(KERN_DEBUG "Suspicious ED...\n");
+		set_ed_head_td(ed, virt_to_bus(td));	/* put it on the ED */
+	} else {
+		/* add the TD to the end */
+		prev_td->next_td = virt_to_bus(td);
+	}
 } /* ohci_add_td_to_ed() */
 
 
 inline void ohci_start_control(struct ohci *ohci)
 {
 	/* tell the HC to start processing the control list */
-	writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus);
+	writel_set(OHCI_USB_CLE, &ohci->regs->control);
+	writel_set(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus);
 }
 
 inline void ohci_start_bulk(struct ohci *ohci)
 {
 	/* tell the HC to start processing the bulk list */
-	writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus);
+	writel_set(OHCI_USB_BLE, &ohci->regs->control);
+	writel_set(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus);
 }
 
 inline void ohci_start_periodic(struct ohci *ohci)
 {
-	/* enable processing periodc transfers starting next frame */
+	/* enable processing periodic (intr) transfers starting next frame */
 	writel_set(OHCI_USB_PLE, &ohci->regs->control);
 }
 
@@ -152,6 +159,7 @@
 
 /*
  * Add an ED to the hardware register ED list pointed to by hw_listhead_p
+ * This function only makes sense for Control and Bulk EDs.
  */
 static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p)
 {
@@ -172,11 +180,11 @@
 	writel(virt_to_bus(ed), hw_listhead_p);
 
 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-} /* ohci_add_ed() */
+} /* ohci_add_ed_to_hw() */
 
 
 /*
- *  Put another control ED on the controller's list
+ *  Put a control ED on the controller's list
  */
 void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed)
 {
@@ -184,37 +192,146 @@
 	ohci_start_control(ohci);
 } /* ohci_add_control_ed() */
 
+/*
+ *  Put a bulk ED on the controller's list
+ */
+void ohci_add_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	ohci_add_ed_to_hw(ed, &ohci->regs->ed_bulkhead);
+	ohci_start_bulk(ohci);
+} /* ohci_add_bulk_ed() */
 
-#if 0
 /*
- *  Put another control ED on the controller's list
+ *  Put a periodic ED on the appropriate list given the period.
  */
 void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
 {
-	ohci_add_ed_to_hw(ed, /* XXX */);
+	struct ohci_ed *int_ed;
+	unsigned long flags;
+
+	/*
+	 * Pick a good frequency endpoint based on the requested period
+	 */
+	int_ed = &ohci->root_hub->ed[ms_to_ed_int(period)];
+#ifdef OHCI_DEBUG
+	printk("usb-ohci: Using INT ED queue %d for %dms period\n",
+			ms_to_ed_int(period), period);
+#endif
+
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+	/*
+	 * Insert this ED at the front of the list.
+	 */
+	ed->next_ed = int_ed->next_ed;
+	int_ed->next_ed = virt_to_bus(ed);
+
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+
 	ohci_start_periodic(ohci);
-} /* ohci_add_control_ed() */
+} /* ohci_add_periodic_ed() */
+
+/*
+ *  Put an isochronous ED on the controller's list
+ */
+inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	ohci_add_periodic_ed(ohci, ed, 1);
+}
+
+
+/*
+ * This will be used for the interrupt to wake us up on the next SOF
+ */
+DECLARE_WAIT_QUEUE_HEAD(start_of_frame_wakeup);
+
+/*
+ * Guarantee that an ED is safe to be modified by the HCD (us).
+ *
+ * This function can NOT be called from an interrupt.
+ */
+void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_type)
+{
+	__u32 hw_listcurrent;
+
+	/* tell the controller to skip this ED */
+	ed->status |= OHCI_ED_SKIP;
+
+	switch (ed_type) {
+	case HCD_ED_CONTROL:
+		hw_listcurrent = readl(regs->ed_controlcurrent);
+		break;
+	case HCD_ED_BULK:
+		hw_listcurrent = readl(regs->ed_bulkcurrent);
+		break;
+	case HCD_ED_ISOC:
+	case HCD_ED_INT:
+		hw_listcurrent = readl(regs->ed_periodcurrent);
+		break;
+	default:
+		return;
+	}
+
+	/* 
+	 * If the HC is processing this ED we need to wait until the
+	 * at least the next frame.
+	 */
+	if (virt_to_bus(ed) == hw_listcurrent) {
+		DECLARE_WAITQUEUE(wait, current);
+
+#ifdef OHCI_DEBUG
+		printk("Waiting a frame for OHC to finish with ED %p\n", ed);
 #endif
 
+		add_wait_queue(&start_of_frame_wakeup, &wait);
+
+		/* clear the SOF interrupt status and enable it */
+		writel(OHCI_INTR_SF, &regs->intrstatus);
+		writel(OHCI_INTR_SF, &regs->intrenable);
+
+		schedule_timeout(HZ/10);
+
+		remove_wait_queue(&start_of_frame_wakeup, &wait);
+	}
+
+	return; /* The ED is now safe */
+} /* ohci_wait_for_ed_safe() */
+
 
 /*
- *  Remove an ED from the HC list whos bus headpointer is pointed to
- *  by hw_listhead_p
+ *  Remove an ED from the HC's list.
+ *  This function can ONLY be used for Control or Bulk EDs.
  *  
  *  Note that the SKIP bit is left on in the removed ED.
  */
-void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p)
+void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_type)
 {
 	unsigned long flags;
+	struct ohci_regs *regs = ohci->regs;
 	struct ohci_ed *cur;
 	__u32 bus_ed = virt_to_bus(ed);
 	__u32 bus_cur;
+	__u32 *hw_listhead_p;
 
 	if (ed == NULL || !bus_ed)
 		return;
 
-	/* tell the controller this skip ED */
-	ed->status |= OHCI_ED_SKIP;
+	switch (ed_type) {
+	case HCD_ED_CONTROL:
+		hw_listhead_p = &regs->ed_controlhead;
+		break;
+	case HCD_ED_BULK:
+		hw_listhead_p = &regs->ed_bulkhead;
+		break;
+	default:
+		printk("Unknown HCD ED type %d.\n", ed_type);
+		return;
+	}
+
+	/*
+	 * Tell the controller to this skip ED and make sure it is not the
+	 * being accessed by the HC as we speak.
+	 */
+	ohci_wait_for_ed_safe(regs, ed, ed_type);
 
 	bus_cur = readl(hw_listhead_p);
 
@@ -232,7 +349,7 @@
 		struct ohci_ed *prev;
 
 		/* walk the list and unlink the ED if found */
-		for (;;) {
+		do {
 			prev = cur;
 			cur = bus_to_virt(cur->next_ed);
 
@@ -241,17 +358,14 @@
 				prev->next_ed = cur->next_ed;
 				break;
 			}
-
-			if (cur->next_ed == 0)
-				break;
-		}
+		} while (cur->next_ed != 0);
 	}
 
 	/* clear any links from the ED for safety */
 	ed->next_ed = 0;
 
 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-} /* ohci_remove_ed_from_hw() */
+} /* ohci_remove_norm_ed_from_hw() */
 
 /*
  *  Remove an ED from the controller's control list.  Note that the SKIP bit
@@ -259,7 +373,7 @@
  */
 inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed)
 {
-	ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead);
+	ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_CONTROL);
 }
 
 /*
@@ -268,7 +382,7 @@
  */
 inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
 {
-	ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead);
+	ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_BULK);
 }
 
 
@@ -321,7 +435,8 @@
 	td->next_td = 0;  /* remove the TDs links */
 	td->ed = NULL;
 
-	/* TODO return this TD to the pool of free TDs */
+	/* return this TD to the pool of free TDs */
+	ohci_free_td(td);
 
 	/* unset the "skip me bit" in this ED */
 	ed->status &= ~OHCI_ED_SKIP;
@@ -332,15 +447,21 @@
 
 /*
  * Get a pointer (virtual) to an available TD from the given device's
- * pool.
- *
- * Return NULL if none are left.
+ * pool.  Return NULL if none are left.
  */
 static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
 {
 	int idx;
 
+#if 0
+	printk(KERN_DEBUG "in ohci_get_free_td()\n");
+#endif
+
+	/* FIXME: this is horribly inefficient */
 	for (idx=0; idx < NUM_TDS; idx++) {
+#if 0
+		show_ohci_td(&dev->td[idx]);
+#endif
 		if (!td_allocated(dev->td[idx])) {
 			struct ohci_td *new_td = &dev->td[idx];
 			/* zero out the TD */
@@ -353,12 +474,53 @@
 		}
 	}
 
-	printk("usb-ohci error: unable to allocate a TD\n");
+	printk("usb-ohci: unable to allocate a TD\n");
 	return NULL;
 } /* ohci_get_free_td() */
 
 
 /*
+ * Get a pointer (virtual) to an available TD from the given device's
+ * pool.  Return NULL if none are left.
+ */
+static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
+{
+	int idx;
+
+	/* FIXME: this is horribly inefficient */
+	for (idx=0; idx < NUM_EDS; idx++) {
+		if (!ed_allocated(dev->ed[idx])) {
+			struct ohci_ed *new_ed = &dev->ed[idx];
+			/* zero out the ED */
+			memset(new_ed, 0, sizeof(*new_ed));
+			/* all new EDs start with the SKIP bit set */
+			new_ed->status |= OHCI_ED_SKIP;
+			/* mark it as allocated */
+			allocate_ed(new_ed);
+			return new_ed;
+		}
+	}
+
+	printk("usb-ohci: unable to allocate an ED\n");
+	return NULL;
+} /* ohci_get_free_ed() */
+
+
+void ohci_free_ed(struct ohci_ed *ed)
+{
+	if (!ed)
+		return;
+
+	if (ed->tail_td == 0) {
+		printk("yikes! an ED without a dummy_td\n");
+	} else
+		ohci_free_td((struct ohci_td *)bus_to_virt(ed->tail_td));
+
+	ed->status &= ~(__u32)ED_ALLOCATED;
+} /* ohci_free_ed() */
+
+
+/*
  *  Initialize a TD
  *
  * 	dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP
@@ -379,10 +541,58 @@
 	td->dev_id = dev_id;
 	td->completed = completed;
 
+#if 0
+	printk(KERN_DEBUG "ohci_fill_new_td created:\n");
+	show_ohci_td(td);
+#endif
+
 	return td;
 } /* ohci_fill_new_td() */
 
 
+/*
+ *  Initialize a new ED on device dev, including allocating and putting the
+ *  dummy tail_td on its queue if it doesn't already have one.  Any
+ *  TDs on this ED other than the dummy will be lost (so there better
+ *  not be any!).  This assumes that the ED is Allocated and will
+ *  force the Allocated bit on.
+ */
+struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed, int maxpacketsize, int lowspeed, int endp_id, int isoc_tds)
+{
+	struct ohci_td *dummy_td;
+
+	if (ed_head_td(ed) != ed->tail_td)
+		printk("Reusing a non-empty ED %p!\n", ed);
+
+	if (!ed->tail_td) {
+		dummy_td = ohci_get_free_td(dev);
+		if (dummy_td == NULL) {
+			printk("Error allocating dummy TD for ED %p\n", ed);
+			return NULL;	/* no dummy available! */
+		}
+		make_dumb_td(dummy_td);	/* flag it as a dummy */
+		ed->tail_td = virt_to_bus(dummy_td);
+	} else {
+		dummy_td = bus_to_virt(ed->tail_td);
+		if (!td_dummy(*dummy_td))
+			printk("ED %p's dummy %p is screwy\n", ed, dummy_td);
+	}
+
+	/* set the head TD to the dummy and clear the Carry & Halted bits */
+	ed->_head_td = ed->tail_td;
+
+	ed->status = \
+		ed_set_maxpacket(maxpacketsize) |
+		ed_set_speed(lowspeed) |
+		(endp_id & 0x7ff) |
+		((isoc_tds == 0) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC);
+	allocate_ed(ed);
+	ed->next_ed = 0;
+
+	return ed;
+} /* ohci_fill_ed() */
+
+
 /**********************************
  * OHCI interrupt list operations *
  **********************************/
@@ -404,26 +614,26 @@
 	struct ohci_td *td;
 	struct ohci_ed *interrupt_ed;	/* endpoint descriptor for this irq */
 
-	/*
-	 * Pick a good frequency endpoint based on the requested period
-	 */
-	interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)];
+	/* Get an ED and TD */
+	interrupt_ed = ohci_get_free_ed(dev);
+	if (!interrupt_ed) {
+		printk("Out of EDs on device %p in ohci_request_irq\n", dev);
+		return -1;
+	}
+
+	td = ohci_get_free_td(dev);
+	if (!td) {
+		printk("Out of TDs in ohci_request_irq\n");
+		ohci_free_ed(interrupt_ed);
+		return -1;
+	}
 
 	/*
 	 * Set the max packet size, device speed, endpoint number, usb
 	 * device number (function address), and type of TD.
-	 *
-	 * FIXME: Isochronous transfers need a pool of special 32 byte
-	 * TDs (32 byte aligned) in order to be supported.
 	 */
-	interrupt_ed->status = \
-		ed_set_maxpacket(usb_maxpacket(pipe)) |
-		ed_set_speed(usb_pipeslow(pipe)) |
-		usb_pipe_endpdev(pipe) |
-		OHCI_ED_F_NORM;
-
-	td = ohci_get_free_td(dev);
-	/* FIXME: check for NULL */
+	ohci_fill_ed(dev, interrupt_ed, usb_maxpacket(pipe), usb_pipeslow(pipe),
+		usb_pipe_endpdev(pipe), 0 /* normal TDs */);
 
 	/* Fill in the TD */
 	ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)),
@@ -432,42 +642,23 @@
 			&dev->data, DATA_BUF_LEN,
 			dev_id, handler);
 	/*
-	 * TODO: be aware that OHCI won't advance out of the 4kb
-	 * page cur_buf started in.  It'll wrap around to the start
-	 * of the page...  annoying or useful? you decide.
-	 *
-	 * We should make sure dev->data doesn't cross a page...
+	 * TODO: be aware of how the OHCI controller deals with DMA
+	 * spanning more than one page.
 	 */
 
-	/* FIXME: this just guarantees that its the end of the list */
-	td->next_td = 0;
+	/*
+	 *  Put the TD onto our ED and make sure its ready to run
+	 */
+	ohci_add_td_to_ed(td, interrupt_ed);
+	interrupt_ed->status &= ~OHCI_ED_SKIP;
+	ohci_unhalt_ed(interrupt_ed);
 
 	/* Linus did this. see asm/system.h; scary concept... I don't
 	 * know if its needed here or not but it won't hurt. */
 	wmb();
 
-	/*
-	 *  Put the TD onto our ED
-	 */
-	{
-		unsigned long flags;
-		spin_lock_irqsave(&ohci_edtd_lock, flags);
-		ohci_add_td_to_ed(td, interrupt_ed);
-		spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-	}
-
-#if 0
 	/* Assimilate the new ED into the collective */
-	/*
-	 *  When dynamic ED allocation is done, this call will be
-	 *  useful.  For now, the correct ED already on the
-	 *  controller's proper periodic ED lists was chosen above.
-	 */
 	ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
-#else
-	/* enable periodic (interrupt) transfers on the HC */
-	ohci_start_periodic(dev->ohci);
-#endif
 
 	return 0;
 } /* ohci_request_irq() */
@@ -486,6 +677,12 @@
  */
 static int ohci_control_completed(int stats, void *buffer, void *dev_id)
 {
+	/* pass the TDs completion status back to control_msg */
+	if (dev_id) {
+		int *completion_status = (int *)dev_id;
+		*completion_status = stats;
+	}
+
 	wake_up(&control_wakeup);
 	return 0;
 } /* ohci_control_completed() */
@@ -502,44 +699,46 @@
  *   - The command itself
  *   - An optional data phase (if len > 0)
  *   - Status complete phase
+ *
+ * This function can NOT be called from an interrupt.
  */
 static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len)
 {
 	struct ohci_device *dev = usb_to_ohci(usb);
-	/*
-	 * ideally dev->ed should be linked into the root hub's
-	 * control_ed list and used instead of just using it directly.
-	 * This could present a problem as is with more than one
-	 * device.  (but who wants to use a keyboard AND a mouse
-	 * anyways? ;)
-	 */
-	struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
+	struct ohci_ed *control_ed = ohci_get_free_ed(dev);
 	struct ohci_td *setup_td, *data_td, *status_td;
 	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
+	int completion_status = -1;
 
-#if 0
-	printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len);
+#ifdef OHCI_DEBUG 
+	printk(KERN_DEBUG "ohci_control_msg %p (ohci_dev: %p) pipe %x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len);
 #endif
+	if (!control_ed) {
+		printk("usb-ohci: couldn't get ED for dev %p\n", dev);
+		return -1;
+	}
+
+	/* get a TD to send this control message with */
+	setup_td = ohci_get_free_td(dev);
+	if (!setup_td) {
+		printk("usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev);
+		ohci_free_ed(control_ed);
+		return -1;
+	}
 
 	/*
 	 * Set the max packet size, device speed, endpoint number, usb
 	 * device number (function address), and type of TD.
 	 *
 	 */
-	control_ed->status = \
-		ed_set_maxpacket(usb_maxpacket(pipe)) |
-		ed_set_speed(usb_pipeslow(pipe)) |
-		usb_pipe_endpdev(pipe) |
-		OHCI_ED_F_NORM;
+	ohci_fill_ed(dev, control_ed, usb_maxpacket(pipe), usb_pipeslow(pipe),
+		usb_pipe_endpdev(pipe), 0 /* normal TDs */);
 
 	/*
 	 * Build the control TD
 	 */
 
-	/* get a TD to send this control message with */
-	setup_td = ohci_get_free_td(dev);
-	/* TODO check for NULL */
-
 	/*
 	 * Set the not accessed condition code, allow odd sized data,
 	 * and set the data transfer type to SETUP.  Setup DATA always
@@ -555,7 +754,13 @@
 			NULL, NULL);
 
 	/* allocate the next TD */
-	data_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+	data_td = ohci_get_free_td(dev);
+	if (!data_td) {
+		printk("usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev);
+		ohci_free_td(setup_td);
+		ohci_free_ed(control_ed);
+		return -1;
+	}
 
 	/* link to the next TD */
 	setup_td->next_td = virt_to_bus(data_td);
@@ -570,48 +775,59 @@
 				NULL, NULL);
 
 		/*
-		 * XXX we should check that the data buffer doesn't
-		 * cross a 4096 byte boundary.  If so, it needs to be
-		 * copied into a single 4096 byte aligned area for the
-		 * OHCI's TD logic to see it all, or multiple TDs need
-		 * to be made for each page.
+		 * TODO: Normal TDs can transfer up to 8192 bytes on OHCI.
+		 * However, for that to happen, the data must -start-
+		 * on a nice 4kb page.  We need to check for data
+		 * sizes > 4096 and, if they cross more than two 4096
+		 * byte pages of memory one or more additional TDs
+		 * will need to be created.  (repeat doing this in a
+		 * loop until all of the DATA is on a TD)
 		 *
-		 * It's not likely a control transfer will run into
-		 * this problem.. (famous last words)
+		 * Control transfers are -highly unlikely- to need to
+		 * transfer this much data.. but who knows.. sadistic
+		 * hardware is sure to exist.
 		 */
 
 		status_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+		if (!status_td) {
+			printk("usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
+			ohci_free_td(setup_td);
+			ohci_free_td(data_td);
+			ohci_free_ed(control_ed);
+			return -1;
+		}
+
 		data_td->next_td = virt_to_bus(status_td);
 	} else {
 		status_td = data_td; /* no data_td, use it for status */
 	}
 
-	/* The control status packet always uses a DATA1 */
+	/* The control status packet always uses a DATA1
+	 * Give "dev_id" the address of completion_status so that the
+	 * TDs status can be passed back to us from the IRQ. */
 	ohci_fill_new_td(status_td,
 			td_set_dir_in(usb_pipeout(pipe) | (len == 0)),
 			TOGGLE_DATA1,
-			0,
-			NULL, 0,
-			NULL, ohci_control_completed);
+			0 /* flags */,
+			NULL /* data */, 0 /* data len */,
+			&completion_status, ohci_control_completed);
 	status_td->next_td = 0; /* end of TDs */
 
 	/*
-	 * Start the control transaction..
-	 */
-	current->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue(&control_wakeup, &wait);
-
-	/*
 	 * Add the chain of 2-3 control TDs to the control ED's TD list
 	 */
-	{
-		unsigned long flags;
-		spin_lock_irqsave(&ohci_edtd_lock, flags);
-		ohci_add_td_to_ed(setup_td, control_ed);
-		spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-	}
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+	control_ed->status |= OHCI_ED_SKIP;
+	ohci_add_td_to_ed(setup_td, control_ed);
+	if (data_td != status_td)
+		ohci_add_td_to_ed(data_td, control_ed);
+	ohci_add_td_to_ed(status_td, control_ed);
+	control_ed->status &= ~OHCI_ED_SKIP;
+	ohci_unhalt_ed(control_ed);
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 
-#if 0
+#ifdef OHCI_DEBUG
+	if (MegaDebug) {
 	/* complete transaction debugging output (before) */
 	printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed));
 	show_ohci_ed(control_ed);
@@ -623,48 +839,55 @@
 	}
 	printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td));
 	show_ohci_td(status_td);
+	printk(KERN_DEBUG " Controller Status:\n");
+	show_ohci_status(dev->ohci);
+	}
 #endif
 
+	/*
+	 * Start the control transaction..
+	 */
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue(&control_wakeup, &wait);
+
 	/* Give the ED to the HC */
 	ohci_add_control_ed(dev->ohci, control_ed);
 
-	/* FIXME:
-	 * this should really check to see that the transaction completed.
-	 */
 	schedule_timeout(HZ/10);
 
 	remove_wait_queue(&control_wakeup, &wait);
 
-#if 0
+#ifdef OHCI_DEBUG
+	if (MegaDebug) {
 	/* complete transaction debugging output (after) */
-	printk(KERN_DEBUG " (after) Control ED:\n");
+	printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed));
 	show_ohci_ed(control_ed);
-	printk(KERN_DEBUG " (after) Setup TD:\n");
+	printk(KERN_DEBUG " *after* Setup TD %lx:\n", virt_to_bus(setup_td));
 	show_ohci_td(setup_td);
 	if (data_td != status_td) {
-		printk(KERN_DEBUG " (after) Data TD:\n");
+		printk(KERN_DEBUG " *after* Data TD %lx:\n", virt_to_bus(data_td));
 		show_ohci_td(data_td);
 	}
-	printk(KERN_DEBUG " (after) Status TD:\n");
+	printk(KERN_DEBUG " *after* Status TD %lx:\n", virt_to_bus(status_td));
 	show_ohci_td(status_td);
+	printk(KERN_DEBUG " *after* Controller Status:\n");
+	show_ohci_status(dev->ohci);
+	}
 #endif
 
-	/* clean up incase it failed */
-	/* XXX only do this if their ed pointer still points to control_ed
-	 * incase they've been reclaimed and used by something else
-	 * already. -greg */
-	ohci_remove_td_from_ed(setup_td, control_ed);
-	ohci_remove_td_from_ed(data_td, control_ed);
-	ohci_remove_td_from_ed(status_td, control_ed);
-
-	/* remove the control ED */
+	/* clean up */
+	ohci_free_td(setup_td);
+	if (data_td != status_td)
+		ohci_free_td(data_td);
+	ohci_free_td(status_td);
+	/* remove the control ED from the HC */
 	ohci_remove_control_ed(dev->ohci, control_ed);
+	ohci_free_ed(control_ed);	 /* return it to the pool */
 
 #if 0
 	printk(KERN_DEBUG "leaving ohci_control_msg\n");
 #endif
-
-	return ohci_td_result(dev, status_td);
+	return completion_status;
 } /* ohci_control_msg() */
 
 
@@ -675,6 +898,7 @@
 {
 	struct usb_device *usb_dev;
 	struct ohci_device *dev;
+	int idx;
 
 	/*
 	 * Allocate the generic USB device
@@ -696,6 +920,12 @@
 
 	memset(dev, 0, sizeof(*dev));
 
+	/* Initialize all EDs in a new device with the skip flag so that
+	 * they are ignored by the controller until set otherwise. */
+	for (idx = 0; idx < NUM_EDS; ++idx) {
+		dev->ed[idx].status |= OHCI_ED_SKIP;
+	}
+
 	/*
 	 * Link them together
 	 */
@@ -752,10 +982,10 @@
  */
 static int reset_hc(struct ohci *ohci)
 {
-	int timeout = 1000;  /* prevent an infinite loop */
+	int timeout = 10000;  /* prevent an infinite loop */
 
 #if 0
-	printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci);
+	printk(KERN_INFO "usb-ohci: resetting HC %p\n", ohci);
 #endif
 
 	writel(~0x0, &ohci->regs->intrdisable);    /* Disable HC interrupts */
@@ -770,7 +1000,7 @@
 		udelay(1);
 	}
 
-	printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci);
+	printk(KERN_INFO "usb-ohci: HC %p reset.\n", ohci);
 
 	return 0;
 } /* reset_hc() */
@@ -783,6 +1013,7 @@
 {
 	int ret = 0;
 	int fminterval;
+	__u32 what_to_enable;
 
 	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
 #if 0
@@ -812,9 +1043,13 @@
 	 * useful for debugging and as a bus heartbeat. -greg
 	 */
 	/* Choose the interrupts we care about */
-	writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */
-		OHCI_INTR_WDH | OHCI_INTR_FNO,
-		&ohci->regs->intrenable);
+	what_to_enable = OHCI_INTR_MIE |
+#ifdef OHCI_RHSC_INT
+			OHCI_INTR_RHSC |
+#endif
+			/* | OHCI_INTR_FNO */
+			OHCI_INTR_WDH;
+	writel( what_to_enable, &ohci->regs->intrenable);
 
 	/* Enter the USB Operational state & start the frames a flowing.. */
 	writel_set(OHCI_USB_OPER, &ohci->regs->control);
@@ -861,7 +1096,7 @@
 	/*
 	 * Wait for the reset to complete.
 	 */
-	wait_ms(10);
+	wait_ms(20);
 
 	/* check port status to see that the reset completed */
 	status = readl(&ohci->regs->roothub.portstatus[port]);
@@ -886,10 +1121,12 @@
 	struct usb_device *usb_dev;
 	struct ohci_device *dev;
 	/* memory I/O address of the port status register */
-	void *portaddr = &ohci->regs->roothub.portstatus[port];
+	__u32 *portaddr = &ohci->regs->roothub.portstatus[port];
 	int portstatus;	
 
-	printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port);
+#ifdef OHCI_DEBUG
+	printk(KERN_DEBUG "ohci_connect_change on port %d\n", port);
+#endif
 
 	/*
 	 * Because of the status change we have to forget
@@ -903,6 +1140,14 @@
 	/* disable the port if nothing is connected */
 	if (!(portstatus & PORT_CCS)) {
 		writel(PORT_CCS, portaddr);
+		/* We need to reset the CSC bit -after- disabling the
+		 * port because it causes the CSC bit to come on
+		 * again... */
+		wait_ms(20);
+		writel(PORT_CSC, portaddr);
+#ifdef OHCI_DEBUG
+		printk(KERN_DEBUG "ohci port %d disabled, nothing connected.\n", port);
+#endif
 		return;
 	}
 
@@ -943,15 +1188,18 @@
 	struct ohci_regs *regs = ohci->regs;
 	int num = 0;
 	int maxport = readl(&ohci->regs->roothub) & 0xff;
+	__u32 rh_change_flags = PORT_CSC | PORT_PESC;	/* root hub status changes */
 
-#if 1
+#ifdef OHCI_DEBUG
 	printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci);
 #endif
 
 	do {
-		if (readl(&regs->roothub.portstatus[num]) & PORT_CSC) {
-			/* reset the connect status change bit */
-			writel(PORT_CSC, &regs->roothub.portstatus[num]);
+		__u32 *portstatus_p = &regs->roothub.portstatus[num];
+		if (readl(portstatus_p) & rh_change_flags) {
+			/* acknowledge the root hub status changes */
+			writel_set(rh_change_flags, portstatus_p);
+			/* disable the port if nothing is on it */
 			/* check the port for a nifty device */
 			ohci_connect_change(ohci, num);
 		}
@@ -977,8 +1225,8 @@
 		int maxport = ohci->root_hub->usb->maxchild;
 
 		do {
-			if (readl(&ohci->regs->roothub.portstatus[num]) &
-					PORT_CSC) {
+			__u32 *portstatus_p = &ohci->regs->roothub.portstatus[num];
+			if (readl(portstatus_p) & PORT_CSC) {
 				if (waitqueue_active(&ohci_configure))
 					wake_up(&ohci_configure);
 				return;
@@ -1037,6 +1285,9 @@
 	while (td != NULL) {
 		struct ohci_td *next_td = td->next_dl_td;
 
+		if (td_dummy(*td))
+			printk("yikes! reaping a dummy TD\n");
+
 		/* FIXME: munge td->info into a future standard status format */
 		/* Check if TD should be re-queued */
 		if ((td->completed != NULL) &&
@@ -1044,14 +1295,15 @@
 		{
 			/* Mark the TD as active again:
 			 * Set the not accessed condition code
-			 * FIXME: should this reset OHCI_TD_ERRCNT?
+			 * Reset the Error count
+			 * [FIXME: report errors to the device's driver]
 			 */
 			td->info |= OHCI_TD_CC_NEW;
+			clear_td_errorcount(td);
 
 			/* point it back to the start of the data buffer */
 			td->cur_buf = virt_to_bus(td->data);
 
-			/* XXX disabled for debugging reasons right now.. */
 			/* insert it back on its ED */
 			ohci_add_td_to_ed(td, td->ed);
 		} else {
@@ -1066,9 +1318,6 @@
 } /* ohci_reap_donelist() */
 
 
-#if 0
-static int in_int = 0;
-#endif
 /*
  * Get annoyed at the controller for bothering us.
  * This pretty much follows the OHCI v1.0a spec, section 5.3.
@@ -1080,19 +1329,10 @@
 	struct ohci_hcca *hcca = ohci->root_hub->hcca;
 	__u32 status, context;
 
-#if 0
-	/* for debugging to keep IRQs from running away. */
-	if (in_int >= 2)
-		return;
-	++in_int;
-	return;
-#endif
-
 	/* Save the status of the interrupts that are enabled */
 	status = readl(&regs->intrstatus);
 	status &= readl(&regs->intrenable);
 
-
 	/* make context = the interrupt status bits that we care about */
 	if (hcca->donehead != 0) {
 		context = OHCI_INTR_WDH;   /* hcca donehead needs processing */
@@ -1122,6 +1362,10 @@
 		context &= ~OHCI_INTR_WDH;  /* mark this as checked */
 	}
 
+#ifdef OHCI_RHSC_INT
+	/* NOTE: this is very funky on some USB controllers (ie: it
+	 * doesn't work right).  Using the ohci_timer instead to poll
+	 * the root hub is a much better choice. */
 	/* Process any root hub status changes */
 	if (context & OHCI_INTR_RHSC) {
 		/* Wake the thread to process root hub events */
@@ -1134,10 +1378,17 @@
 		 * The control thread will re-enable it after it has
 		 * checked the root hub status.
 		 */
-	} else {
-		/* check the root hub status anyways. Some controllers
-		 * might not generate the interrupt properly. (?) */
-		ohci_root_hub_events(ohci);
+	}
+#endif
+
+	/* Start of Frame interrupts, used during safe ED removal */
+	if (context & (OHCI_INTR_SF)) {
+		writel(OHCI_INTR_SF, &regs->intrstatus);
+		if (waitqueue_active(&start_of_frame_wakeup))
+			wake_up(&start_of_frame_wakeup);
+		/* Do NOT mark the frame start interrupt as checked
+		 * as we don't want to receive any more of them until
+		 * asked. */
 	}
 
 	/* Check those "other" pesky bits */
@@ -1166,8 +1417,8 @@
 		context &= ~OHCI_INTR_OC;  /* mark this as checked */
 	}
 
-	/* Mask out any remaining unprocessed interrupts so we don't
-	 * get any more of them. */
+	/* Mask out any remaining unprocessed or unmasked interrupts
+	 * so that we don't get any more of them. */
 	if (context & ~OHCI_INTR_MIE) {
 		writel(context, &regs->intrdisable);
 	}
@@ -1275,7 +1526,9 @@
 
 	/*
 	 * Initialize the polling table to call interrupts at the
-	 * intended intervals.
+	 * intended intervals.  Note that these EDs are just
+	 * placeholders.  They have their SKIP bit set and are used as
+	 * list heads to insert real EDs onto.
 	 */
 	dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_1]);
 	for (i = 1; i < NUM_INTS; i++) {
@@ -1297,18 +1550,14 @@
 	}
 
 	/*
-	 * Tell the controller where the control and bulk lists are
+	 * Tell the controller where the control and bulk lists are.
 	 * The lists start out empty.
 	 */
 	writel(0, &ohci->regs->ed_controlhead);
 	writel(0, &ohci->regs->ed_bulkhead);
-	/*
-	writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead);
-	writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead);
-	*/
 
-#if 0
-	printk(KERN_DEBUG "alloc_ohci(): controller\n");
+#ifdef OHCI_DEBUG
+	printk(KERN_INFO "alloc_ohci(): controller\n");
 	show_ohci_status(ohci);
 #endif
 
@@ -1325,7 +1574,7 @@
  */
 static void release_ohci(struct ohci *ohci)
 {
-	printk(KERN_DEBUG "entering release_ohci %p\n", ohci);
+	printk(KERN_INFO "Releasing OHCI controller 0x%p\n", ohci);
 
 #ifdef OHCI_TIMER
 	/* stop our timer */
@@ -1378,7 +1627,7 @@
 	 * This thread doesn't need any user-level access,
 	 * so get rid of all of our resources..
 	 */
-	printk("ohci_control_thread code at %p\n", &ohci_control_thread);
+	printk(KERN_INFO "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread);
 	exit_mm(current);
 	exit_files(current);
 	exit_fs(current);
@@ -1391,7 +1640,7 @@
 	if (start_hc(ohci) < 0) {
 		printk("usb-ohci: failed to start the controller\n");
 		release_ohci(ohci);
-		printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
+		printk(KERN_INFO "leaving ohci_control_thread %p\n", __ohci);
 		return 0;
 	}
 
@@ -1405,11 +1654,11 @@
 		ohci_check_configuration(ohci);
 
 		/* re-enable root hub status change interrupts. */
-#if 0
+#ifdef OHCI_RHSC_INT
 		writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
 #endif
 
-		printk(KERN_DEBUG "ohci-control thread sleeping\n");
+		printk(KERN_INFO "ohci-control thread sleeping\n");
 		interruptible_sleep_on(&ohci_configure);
 #ifdef CONFIG_APM
 		if (apm_resume) {
@@ -1431,9 +1680,14 @@
 			spin_unlock_irq(&current->sigmask_lock);
 
 			if(signr == SIGUSR1) {
-				/* FIXME: have it do a full ed/td queue dump */
+				/* TODO: have it do a full ed/td queue dump? */
 				printk(KERN_DEBUG "OHCI status dump:\n");
 				show_ohci_status(ohci);
+			} else if (signr == SIGUSR2) {
+				/* toggle mega TD/ED debugging output */
+				MegaDebug = !MegaDebug;
+				printk(KERN_DEBUG "usb-ohci: Mega debugging %sabled.\n",
+						MegaDebug ? "en" : "dis");
 			} else {
 				/* unknown signal, exit the thread */
 				break;
@@ -1444,7 +1698,7 @@
 	reset_hc(ohci);
 	release_ohci(ohci);
 
-	printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
+	printk(KERN_INFO "ohci-control thread for 0x%p exiting\n", __ohci);
 
 	return 0;
 } /* ohci_control_thread() */
@@ -1538,8 +1792,8 @@
 
 		ohci->irq = irq;
 
-#if 0
-		printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n");
+#ifdef OHCI_DEBUG
+		printk(KERN_INFO "usb-ohci: forking ohci-control thread for 0x%p\n", ohci);
 #endif
 
 		/* fork off the handler */
@@ -1555,7 +1809,7 @@
 	}
 	release_ohci(ohci);
 
-#if 0
+#ifdef OHCI_DEBUG
 	printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base);
 #endif
 
@@ -1597,6 +1851,11 @@
 	}
         MOD_INC_USE_COUNT;
 
+#ifdef OHCI_DEBUG
+	printk("usb-ohci: Warning! Gobs of debugging output has been enabled.\n");
+	printk("          Check your kern.debug logs for the bulk of it.\n");
+#endif
+
 	if (found_ohci(dev->irq, (void *) mem_base) < 0) {
 		MOD_DEC_USE_COUNT;
 		return -1;
@@ -1672,6 +1931,7 @@
 	}
 	return retval;
 } /* ohci_init */
+
 
 /* vim:sw=8
  */
diff -u --recursive --new-file v2.3.2/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- v2.3.2/linux/drivers/usb/ohci.h	Sat May 15 23:46:04 1999
+++ linux/drivers/usb/ohci.h	Sun May 16 22:23:31 1999
@@ -6,7 +6,7 @@
  *
  * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
  *
- * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $
+ * $Id: ohci.h,v 1.24 1999/05/16 10:18:26 greg Exp $
  */
 
 #include <linux/list.h>
@@ -37,7 +37,9 @@
 	struct ohci_td *next_dl_td;	/* used during donelist processing */
 	void *data;			/* virt. address of the the buffer */
 	usb_device_irq completed;	/* Completion handler routine */
-	int allocated;			/* boolean: is this TD allocated? */
+	int hcd_flags;			/* Flags for the HCD: */
+		/* bit0 = boolean: Is this TD allocated? */
+		/* bit1 = boolean: Is this a dummy (end of list) TD? */
 
 	/* User or Device class driver specific fields */
 	void *dev_id;	/* user defined pointer passed to irq handler */
@@ -59,6 +61,7 @@
 #define td_force_toggle(b)	(((b) | 2) << 24)
 #define OHCI_TD_ERRCNT	(3 << 26)	/* error count */
 #define td_errorcount(td)	(((td).info >> 26) & 3)
+#define clear_td_errorcount(td)	((td)->info &= ~(__u32)OHCI_TD_ERRCNT)
 #define OHCI_TD_CC	(0xf << 28)	/* condition code */
 #define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf)
 #define OHCI_TD_CC_NEW	(OHCI_TD_CC)	/* set this on all unaccessed TDs! */
@@ -68,9 +71,16 @@
 #define td_active(td)	(!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
 #define td_done(td)	(td_cc_noerror((td)) || (td_errorcount((td)) == 3))
 
-#define td_allocated(td)	((td).allocated)
-#define allocate_td(td)		((td)->allocated = 1)
-#define ohci_free_td(td)	((td)->allocated = 0)
+/*
+ * Macros to use the td->hcd_flags field.
+ */
+#define td_allocated(td)	((td).hcd_flags & 1)
+#define allocate_td(td)		((td)->hcd_flags |= 1)
+#define ohci_free_td(td)	((td)->hcd_flags &= ~(__u32)1)
+
+#define td_dummy(td)		((td).hcd_flags & 2)
+#define make_dumb_td(td)	((td)->hcd_flags |= 2)
+#define clear_dumb_td(td)	((td)->hcd_flags &= ~(__u32)2)
 
 
 /*
@@ -114,14 +124,14 @@
 #define OHCI_ED_FA	(0x7f)
 
 
-/* NOTE: bits 27-31 of the status dword are reserved for the driver */
+/* NOTE: bits 27-31 of the status dword are reserved for the HCD */
 /*
  * We'll use this status flag for to mark if an ED is in use by the
- * driver or not.  If the bit is set, it is used.
- *
- * FIXME: implement this!
+ * driver or not.  If the bit is set, it is being used.
  */
-#define ED_USED	(1 << 31)
+#define ED_ALLOCATED	(1 << 31)
+#define ed_allocated(ed)	((ed).status & ED_ALLOCATED)
+#define allocate_ed(ed)		((ed)->status |= ED_ALLOCATED)
 
 /*
  * The HCCA (Host Controller Communications Area) is a 256 byte
@@ -187,16 +197,17 @@
 
 /* .... */
 
+/*
+ * These are the index of the placeholder EDs for the root hub to
+ * build the interrupt transfer ED tree out of.
+ */
 #define ED_INT_1	0
 #define ED_INT_2	1
 #define ED_INT_4	2
 #define ED_INT_8	3
 #define ED_INT_16	4
 #define ED_INT_32	5
-#define ED_CONTROL	6
-#define ED_BULK		7
 #define ED_ISO		ED_INT_1	/* same as 1ms interrupt queue */
-#define ED_FIRST_AVAIL  8		/* first non-reserved ED */
 
 /*
  * Given a period p in ms, convert it to the closest endpoint
@@ -215,7 +226,9 @@
  * This is the maximum number of root hub ports.  I don't think we'll
  * ever see more than two as that's the space available on an ATX
  * motherboard's case, but it could happen.  The OHCI spec allows for
- * up to 15... (which is insane!)
+ * up to 15... (which is insane given that they each need to supply up
+ * to 500ma; that would be 7.5 amps!).  I have seen a PCI card with 4
+ * downstream ports on it.
  * 
  * Although I suppose several "ports" could be connected directly to
  * internal laptop devices such as a keyboard, mouse, camera and
@@ -259,6 +272,15 @@
 	} roothub;
 } __attribute((aligned(32)));
 
+/*
+ * These are used by internal ED managing functions as a
+ * parameter to state the type of ED to deal with (when it matters).
+ */
+#define HCD_ED_ISOC     (0)
+#define HCD_ED_INT      (1)
+#define HCD_ED_CONTROL  (2)
+#define HCD_ED_BULK     (3)
+
 /* 
  * Read a MMIO register and re-write it after ANDing with (m)
  */
@@ -352,9 +374,9 @@
 #define OHCI_TIMER		/* enable the OHCI timer */
 #define OHCI_TIMER_FREQ	(234)	/* ms between each root hub status check */
 
-#undef OHCI_RHSC_INT		/* don't use root hub status interrupts */
+#undef OHCI_RHSC_INT		/* Don't use root hub status interrupts! */
 
-/* Debugging code */
+/* Debugging code [ohci-debug.c] */
 void show_ohci_ed(struct ohci_ed *ed);
 void show_ohci_td(struct ohci_td *td);
 void show_ohci_status(struct ohci *ohci);
diff -u --recursive --new-file v2.3.2/linux/fs/ChangeLog linux/fs/ChangeLog
--- v2.3.2/linux/fs/ChangeLog	Fri Dec 18 07:09:35 1998
+++ linux/fs/ChangeLog	Sat May 15 23:43:05 1999
@@ -144,24 +144,12 @@
 	* rmdir of immutable/append-only directory shouldn't be allowed. Fixed.
 
 Remains unfixed:
-	* UMSDOS_rename is broken. Call it with the dest. existing and being an
-		empty directory and you've got EBUSY. At least it doesn't do
-		any harm, so that will wait several days till rename cleanup.
-		Sigh... It will wait a bit more. Problems with fat-derived
-		filesystems are much worse than I thought. Idea of changing
-		inode under dentry is broken by design - guess where the
-		semaphore sits, for one.
-	* umsdos: weird. rename() shouldn't return -EEXIST. BTW, manpage
-		for rename(2) is obviously bogus - it mentions EEXIST and
-		on the next line (correctly) says that EINVAL should be
-		returned. Under the same conditions.
 	* rename's handling of races is, erm, not optimal. Looks like I know
 		what to do, but this thing needs some more cleanup - we can
 		take care of almost all races in VFS and be much more graceful
 		wrt locking. Moreover, it would give strong lookup atomicity.
 		But it's a lot of changes to lookup and dcache code, so it will
 		go after the fs drivers' cleanup.
-	* hfs allows mknod. Only for regular files ;-/ IMHO it's bogus.
 	* affs allows HARD links to directories. VFS is, to put it politely,
 		not too ready to cope with _that_. And I'm not sure it should
 		be - looks like they are pretty much similar to symlinks.
@@ -169,8 +157,3 @@
 		braindead filesystems). I've submitted a patch to Linus, but
 		looks like it wasn't applied.
 	* msdos: shouldn't we treat SYS as IMMUTABLE? Makes sense, IMHO.
-	* minix, qnx and sysv do NOT allow to mkdir sticky directories.
-	* {minix,sysv}/namei.c (do_{minix,syv}_{rename,unlink}):
-		Stuff related to retries still needs cleanup/fixing.
-		Looks like I've found an extremely low-probability race
-		there...
diff -u --recursive --new-file v2.3.2/linux/fs/Config.in linux/fs/Config.in
--- v2.3.2/linux/fs/Config.in	Sat May 15 23:46:04 1999
+++ linux/fs/Config.in	Sun May 16 10:27:40 1999
@@ -36,7 +36,7 @@
 if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool '   NTFS read-write support (DANGEROUS)' CONFIG_NTFS_RW
 fi
-tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
+tristate 'OS/2 HPFS filesystem support (read/write) (NEW)' CONFIG_HPFS_FS
 bool '/proc filesystem support' CONFIG_PROC_FS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
   # It compiles as a module for testing only.  It should not be used
diff -u --recursive --new-file v2.3.2/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.3.2/linux/fs/affs/namei.c	Fri Apr 23 21:20:37 1999
+++ linux/fs/affs/namei.c	Sat May 15 23:43:05 1999
@@ -315,7 +315,7 @@
 	error       = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
 	if (error)
 		goto out_iput;
-	inode->i_mode = S_IFDIR | S_ISVTX | (mode & 0777 & ~current->fs->umask);
+	inode->i_mode = S_IFDIR | S_ISVTX | mode;
 	inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
 	d_instantiate(dentry,inode);
 	mark_inode_dirty(inode);
diff -u --recursive --new-file v2.3.2/linux/fs/devices.c linux/fs/devices.c
--- v2.3.2/linux/fs/devices.c	Fri May 14 18:55:24 1999
+++ linux/fs/devices.c	Sat May 15 23:43:04 1999
@@ -193,7 +193,7 @@
  * it. Thus it is called only upon a 'mount' or 'open'. This
  * is the best way of combining speed and utility, I think.
  * People changing diskettes in the middle of an operation deserve
- * to loose :-)
+ * to lose :-)
  */
 int check_disk_change(kdev_t dev)
 {
diff -u --recursive --new-file v2.3.2/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.3.2/linux/fs/ext2/namei.c	Fri May 14 18:55:24 1999
+++ linux/fs/ext2/namei.c	Sat May 15 23:43:05 1999
@@ -490,7 +490,7 @@
 	inode->i_nlink = 2;
 	mark_buffer_dirty(dir_block, 1);
 	brelse (dir_block);
-	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
+	inode->i_mode = S_IFDIR | mode;
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
 	mark_inode_dirty(inode);
diff -u --recursive --new-file v2.3.2/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c
--- v2.3.2/linux/fs/ext2/truncate.c	Sat May 15 23:46:04 1999
+++ linux/fs/ext2/truncate.c	Sun May 16 13:55:46 1999
@@ -384,7 +384,7 @@
 		
 void ext2_truncate (struct inode * inode)
 {
-	int err, offset, retry;
+	int err, offset;
 
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	    S_ISLNK(inode->i_mode)))
@@ -393,7 +393,7 @@
 		return;
 	ext2_discard_prealloc(inode);
 	while (1) {
-		retry = trunc_direct(inode);
+		int retry = trunc_direct(inode);
 		retry |= trunc_indirect (inode, 
 				EXT2_IND_BLOCK,
 				(u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK],
diff -u --recursive --new-file v2.3.2/linux/fs/hfs/bnode.c linux/fs/hfs/bnode.c
--- v2.3.2/linux/fs/hfs/bnode.c	Fri May 14 18:55:24 1999
+++ linux/fs/hfs/bnode.c	Sat May 15 15:02:50 1999
@@ -228,7 +228,7 @@
 			break;
 
 		case HFS_LOCK_NONE:
-			while (bn->lock || witqueue_active(&bn->wqueue)) {
+			while (bn->lock || waitqueue_active(&bn->wqueue)) {
 				hfs_sleep_on(&bn->rqueue);
 			}
 			++bn->count;
diff -u --recursive --new-file v2.3.2/linux/fs/hfs/catalog.c linux/fs/hfs/catalog.c
--- v2.3.2/linux/fs/hfs/catalog.c	Fri May 14 18:55:24 1999
+++ linux/fs/hfs/catalog.c	Sat May 15 15:02:50 1999
@@ -647,7 +647,7 @@
  */
 static inline void start_write(struct hfs_cat_entry *dir)
 {
-	if (dir->u.dir.readers || wait_queue_active(&dir->u.dir.read_wait)) {
+	if (dir->u.dir.readers || waitqueue_active(&dir->u.dir.read_wait)) {
 		hfs_sleep_on(&dir->u.dir.write_wait);
 	}
 	++dir->u.dir.writers;
@@ -658,7 +658,7 @@
  */
 static inline void start_read(struct hfs_cat_entry *dir)
 {
-	if (dir->u.dir.writers || wait_queue_active(&dir->u.dir.write_wait)) {
+	if (dir->u.dir.writers || waitqueue_active(&dir->u.dir.write_wait)) {
 		hfs_sleep_on(&dir->u.dir.read_wait);
 	}
 	++dir->u.dir.readers;
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/alloc.c linux/fs/hpfs/alloc.c
--- v2.3.2/linux/fs/hpfs/alloc.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/alloc.c	Sun May 16 10:27:40 1999
@@ -307,6 +307,7 @@
 	if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
 		for (j = 0; j < 512; j++) {
 			unsigned k;
+			if (!bmp[j]) continue;
 			for (k = bmp[j]; k; k >>= 1) if (k & 1) if (!--n) {
 				hpfs_brelse4(&qbh);
 				return 0;
@@ -327,9 +328,9 @@
 	if (bmp) {
 		for (j = 0; j < 512; j++) {
 			unsigned k;
+			if (!bmp[j]) continue;
 			for (k = 0xf; k; k <<= 4)
 				if ((bmp[j] & k) == k) {
-					/*printk("%08x,%08x\n",j,i);*/
 					if (!--n) {
 						hpfs_brelse4(&qbh);
 						return 0;
@@ -372,8 +373,13 @@
 			 int lock)
 {
 	struct dnode *d;
-	if (!(*dno = alloc_in_dirband(s, near, lock)))
-		if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) return NULL;
+	if (hpfs_count_one_bitmap(s, s->s_hpfs_dmap) > FREE_DNODES_ADD) {
+		if (!(*dno = alloc_in_dirband(s, near, lock)))
+			if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) return NULL;
+	} else {
+		if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock)))
+			if (!(*dno = alloc_in_dirband(s, near, lock))) return NULL;
+	}
 	if (!(d = hpfs_get_4sectors(s, *dno, qbh))) {
 		hpfs_free_dnode(s, *dno);
 		return NULL;
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/dentry.c linux/fs/hpfs/dentry.c
--- v2.3.2/linux/fs/hpfs/dentry.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/dentry.c	Sun May 16 10:27:40 1999
@@ -16,14 +16,14 @@
 {
 	unsigned long	 hash;
 	int		 i;
-	int l = qstr->len;
+	unsigned l = qstr->len;
 
 	if (l == 1) if (qstr->name[0]=='.') goto x;
 	if (l == 2) if (qstr->name[0]=='.' || qstr->name[1]=='.') goto x;
-	if (hpfs_chk_name((char *)qstr->name,l))
-		/*return -ENAMETOOLONG;*/
-		return -ENOENT;
 	hpfs_adjust_length((char *)qstr->name, &l);
+	/*if (hpfs_chk_name((char *)qstr->name,&l))*/
+		/*return -ENAMETOOLONG;*/
+		/*return -ENOENT;*/
 	x:
 
 	hash = init_name_hash();
@@ -36,15 +36,15 @@
 
 int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
 {
-	int al=a->len;
-	int bl=b->len;
+	unsigned al=a->len;
+	unsigned bl=b->len;
 	hpfs_adjust_length((char *)a->name, &al);
-	hpfs_adjust_length((char *)b->name, &bl);
+	/*hpfs_adjust_length((char *)b->name, &bl);*/
 	/* 'a' is the qstr of an already existing dentry, so the name
 	 * must be valid. 'b' must be validated first.
 	 */
 
-	if (hpfs_chk_name((char *)b->name, bl)) return 1;
+	if (hpfs_chk_name((char *)b->name, &bl)) return 1;
 	if (hpfs_compare_names(dentry->d_sb, (char *)a->name, al, (char *)b->name, bl, 0)) return 1;
 	return 0;
 }
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/dir.c linux/fs/hpfs/dir.c
--- v2.3.2/linux/fs/hpfs/dir.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/dir.c	Sun May 16 10:27:40 1999
@@ -30,8 +30,6 @@
 	char *tempname;
 	int c1, c2 = 0;
 
-	if (!inode) return -EBADF;
-	if (!S_ISDIR(inode->i_mode)) return -EBADF;
 	if (inode->i_sb->s_hpfs_chk) {
 		if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode"))
 			return -EFSERROR;
@@ -150,57 +148,30 @@
 struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
 {
 	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
+	unsigned len = dentry->d_name.len;
 	struct quad_buffer_head qbh;
 	struct hpfs_dirent *de;
-	struct inode *inode;
 	ino_t ino;
-
+	int err;
 	struct inode *result = NULL;
-	if (dir == 0) return -ENOENT;
-	hpfs_adjust_length((char *)name, &len);
+
+	if ((err = hpfs_chk_name((char *)name, &len))) {
+		if (err == -ENAMETOOLONG) return ERR_PTR(-ENAMETOOLONG);
+		goto end_add;
+	}
+
 	hpfs_lock_inode(dir);
-	if (!S_ISDIR(dir->i_mode)) goto bail;
 	/*
-	 * Read in the directory entry. "." is there under the name ^A^A .
-	 * Always read the dir even for . and .. in case we need the dates.
-	 *
-	 * M.P.: No - we can't read '^A^A' for current directory. In some cases
-	 * the information under '^A^A' is incomplete (missing ea_size, bad
-	 * fnode number) - chkdsk ignores such errors and it doesn't seem to
-	 * matter under OS/2.
-	 */
-	if (name[0] == '.' && len == 1) {
-		result = dir;
-		dir->i_count++;
-		goto end;
-	} else if (name[0] == '.' && name[1] == '.' && len == 2) {
-		struct buffer_head *bh;
-		struct fnode *fnode;
-		if (dir->i_ino == dir->i_sb->s_hpfs_root) {
-			result = dir;
-			dir->i_count++;
-			goto end;
-		}
-		if (dir->i_hpfs_parent_dir == dir->i_sb->s_hpfs_root) {
-			result = dir->i_sb->s_root->d_inode;
-			result->i_count++;
-			goto end;
-		}
-		if (!(fnode = hpfs_map_fnode(dir->i_sb, dir->i_hpfs_parent_dir, &bh))) goto bail;
-		de = map_fnode_dirent(dir->i_sb, dir->i_hpfs_parent_dir, fnode, &qbh);
-		brelse(bh);
-	} else
-		de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh, NULL);
+	 * '.' and '..' will never be passed here.
+	 */
+
+	de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh);
 
 	/*
 	 * This is not really a bailout, just means file not found.
 	 */
 
-	if (!de) {
-		result = NULL;
-		goto end;
-	}
+	if (!de) goto end;
 
 	/*
 	 * Get inode number, what we're after.
@@ -213,18 +184,18 @@
 	 */
 
 	hpfs_lock_iget(dir->i_sb, de->directory || (de->ea_size && dir->i_sb->s_hpfs_eas) ? 1 : 2);
-	if (!(inode = iget(dir->i_sb, ino))) {
+	if (!(result = iget(dir->i_sb, ino))) {
 		hpfs_unlock_iget(dir->i_sb);
-		hpfs_error(inode->i_sb, "hpfs_lookup: can't get inode");
+		hpfs_error(result->i_sb, "hpfs_lookup: can't get inode");
 		goto bail1;
 	}
-	if (!de->directory) inode->i_hpfs_parent_dir = dir->i_ino;
+	if (!de->directory) result->i_hpfs_parent_dir = dir->i_ino;
 	hpfs_unlock_iget(dir->i_sb);
 
-	hpfs_decide_conv(inode, (char *)name, len);
+	hpfs_decide_conv(result, (char *)name, len);
 
 	if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) {
-		hpfs_error(inode->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");
+		hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");
 		goto bail1;
 	}
 
@@ -233,24 +204,24 @@
 	 * inode.
 	 */
 
-	if (!inode->i_ctime) {
-		if (!(inode->i_ctime = local_to_gmt(dir->i_sb, de->creation_date)))
-			inode->i_ctime = 1;
-		inode->i_mtime = local_to_gmt(dir->i_sb, de->write_date);
-		inode->i_atime = local_to_gmt(dir->i_sb, de->read_date);
-		inode->i_hpfs_ea_size = de->ea_size;
-		if (!inode->i_hpfs_ea_mode && de->read_only)
-			inode->i_mode &= ~0222;
+	if (!result->i_ctime) {
+		if (!(result->i_ctime = local_to_gmt(dir->i_sb, de->creation_date)))
+			result->i_ctime = 1;
+		result->i_mtime = local_to_gmt(dir->i_sb, de->write_date);
+		result->i_atime = local_to_gmt(dir->i_sb, de->read_date);
+		result->i_hpfs_ea_size = de->ea_size;
+		if (!result->i_hpfs_ea_mode && de->read_only)
+			result->i_mode &= ~0222;
 		if (!de->directory) {
-			if (inode->i_size == -1) {
-				inode->i_size = de->file_size;
+			if (result->i_size == -1) {
+				result->i_size = de->file_size;
 			/*
 			 * i_blocks should count the fnode and any anodes.
 			 * We count 1 for the fnode and don't bother about
 			 * anodes -- the disk heads are on the directory band
 			 * and we want them to stay there.
 			 */
-				inode->i_blocks = 1 + ((inode->i_size + 511) >> 9);
+				result->i_blocks = 1 + ((result->i_size + 511) >> 9);
 			}
 		}
 	}
@@ -261,9 +232,9 @@
 	 * Made it.
 	 */
 
-	result = inode;
 	end:
 	hpfs_unlock_inode(dir);
+	end_add:
 	hpfs_set_dentry_operations(dentry);
 	d_add(dentry, result);
 	return NULL;
@@ -275,7 +246,7 @@
 	
 	hpfs_brelse4(&qbh);
 	
-	bail:
+	/*bail:*/
 
 	hpfs_unlock_inode(dir);
 	return ERR_PTR(-ENOENT);
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/dnode.c linux/fs/hpfs/dnode.c
--- v2.3.2/linux/fs/hpfs/dnode.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/dnode.c	Sun May 16 10:27:40 1999
@@ -368,7 +368,6 @@
 	struct quad_buffer_head qbh;
 	dnode_secno dno;
 	int c;
-	int depth = cdepth;
 	int c1, c2 = 0;
 	dno = i->i_hpfs_dno;
 	down:
@@ -385,7 +384,6 @@
 			if (de->down) {
 				dno = de_down_pointer(de);
 				hpfs_brelse4(&qbh);
-				depth++;
 				goto down;
 			}
 			break;
@@ -393,7 +391,7 @@
 	}
 	hpfs_brelse4(&qbh);
 	if (!cdepth) hpfs_lock_creation(i->i_sb);
-	if (hpfs_check_free_dnodes(i->i_sb, depth + 2)) {
+	if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) {
 		c = 1;
 		goto ret;
 	}	
@@ -574,11 +572,6 @@
 		goto end;
 	}
 
-	/*{
-		static int cnt_t_ = 0;
-		if (cnt_t_++ & 1) goto endm;
-	}*/
-
 	if (!de->last) {
 		struct hpfs_dirent *de_next = de_next_de(de);
 		struct hpfs_dirent *de_cp;
@@ -607,7 +600,6 @@
 		kfree(de_cp);
 		goto try_it_again;
 	} else {
-		/*printk("HPFS: warning: not balancing tree\n");*/
 		struct hpfs_dirent *de_prev = dnode_pre_last_de(dnode);
 		struct hpfs_dirent *de_cp;
 		struct dnode *d1;
@@ -692,20 +684,21 @@
 {
 	struct dnode *dnode = qbh->data;
 	dnode_secno down = 0;
+	int lock = 0;
 	loff_t t;
 	if (de->first || de->last) {
 		hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno);
 		hpfs_brelse4(qbh);
 		return 1;
 	}
-	if (de->down) {
-		if ((down = de_down_pointer(de)) && depth) {
-			hpfs_lock_creation(i->i_sb);
-			if (hpfs_check_free_dnodes(i->i_sb, depth + 2)) {
-				hpfs_brelse4(qbh);
-				hpfs_unlock_creation(i->i_sb);
-				return 2;
-			}
+	if (de->down) down = de_down_pointer(de);
+	if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) {
+		lock = 1;
+		hpfs_lock_creation(i->i_sb);
+		if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) {
+			hpfs_brelse4(qbh);
+			hpfs_unlock_creation(i->i_sb);
+			return 2;
 		}
 	}
 	i->i_version = ++event;
@@ -716,10 +709,12 @@
 	if (down) {
 		dnode_secno a = move_to_top(i, down, dno);
 		for_all_poss(i, hpfs_pos_subst, 5, t);
-		if (depth) hpfs_unlock_creation(i->i_sb);
 		if (a) delete_empty_dnode(i, a);
+		if (lock) hpfs_unlock_creation(i->i_sb);
 		return !a;
-	} else delete_empty_dnode(i, dno);
+	}
+	delete_empty_dnode(i, dno);
+	if (lock) hpfs_unlock_creation(i->i_sb);
 	return 0;
 }
 
@@ -888,15 +883,13 @@
 /* Find a dirent in tree */
 
 struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, char *name, unsigned len,
-			       dnode_secno *dd, struct quad_buffer_head *qbh, int *depth)
+			       dnode_secno *dd, struct quad_buffer_head *qbh)
 {
 	struct dnode *dnode;
 	struct hpfs_dirent *de;
 	struct hpfs_dirent *de_end;
 	int c1, c2 = 0;
 
-	if (depth) *depth = 0;
-
 	if (!S_ISDIR(inode->i_mode)) hpfs_error(inode->i_sb, "map_dirent: not a directory\n");
 	again:
 	if (inode->i_sb->s_hpfs_chk)
@@ -914,7 +907,6 @@
 			if (de->down) {
 				dno = de_down_pointer(de);
 				hpfs_brelse4(qbh);
-				if (depth) (*depth)++;
 				goto again;
 			}
 		break;
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/file.c linux/fs/hpfs/file.c
--- v2.3.2/linux/fs/hpfs/file.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/file.c	Sun May 16 10:27:40 1999
@@ -54,7 +54,6 @@
 	i->i_hpfs_n_secs = 0;
 	hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
 	i->i_blocks = 1 + ((i->i_size + 511) >> 9);
-	/*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
 	hpfs_write_inode(i);
 }
 
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/hpfs_fn.h linux/fs/hpfs/hpfs_fn.h
--- v2.3.2/linux/fs/hpfs/hpfs_fn.h	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/hpfs_fn.h	Sun May 16 10:27:40 1999
@@ -42,6 +42,9 @@
 #define ANODE_RD_AHEAD	16
 #define DNODE_RD_AHEAD	4
 
+#define FREE_DNODES_ADD	58
+#define FREE_DNODES_DEL	29
+
 #define CHKCOND(x,y) if (!(x)) printk y
 
 #ifdef DBG
@@ -237,7 +240,7 @@
 void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *);
 dnode_secno hpfs_de_as_down_as_possible(struct super_block *, dnode_secno dno);
 struct hpfs_dirent *map_pos_dirent(struct inode *, loff_t *, struct quad_buffer_head *);
-struct hpfs_dirent *map_dirent(struct inode *, dnode_secno, char *, unsigned, dnode_secno *, struct quad_buffer_head *, int *depth);
+struct hpfs_dirent *map_dirent(struct inode *, dnode_secno, char *, unsigned, dnode_secno *, struct quad_buffer_head *);
 void hpfs_remove_dtree(struct super_block *, dnode_secno);
 struct hpfs_dirent *map_fnode_dirent(struct super_block *, fnode_secno, struct fnode *, struct quad_buffer_head *);
 
@@ -285,7 +288,7 @@
 /* name.c */
 
 unsigned char hpfs_upcase(unsigned char *, unsigned char);
-int hpfs_chk_name(unsigned char *, unsigned);
+int hpfs_chk_name(unsigned char *, unsigned *);
 char *hpfs_translate_name(struct super_block *, unsigned char *, unsigned, int, int);
 int hpfs_compare_names(struct super_block *, unsigned char *, unsigned, unsigned char *, unsigned, int);
 int hpfs_is_name_long(unsigned char *, unsigned);
@@ -310,5 +313,6 @@
 int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
 int hpfs_remount_fs(struct super_block *, int *, char *);
 void hpfs_put_super(struct super_block *);
+unsigned hpfs_count_one_bitmap(struct super_block *, secno);
 int hpfs_statfs(struct super_block *, struct statfs *, int);
 struct super_block *hpfs_read_super(struct super_block *, void *, int);
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/inode.c linux/fs/hpfs/inode.c
--- v2.3.2/linux/fs/hpfs/inode.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/inode.c	Sun May 16 10:27:40 1999
@@ -128,6 +128,7 @@
 	unsigned char *ea;
 	int ea_size;
 	i->i_op = 0;
+	/*i->i_hpfs_sem = MUTEX;*/
 	init_MUTEX(&i->i_hpfs_sem);
 	i->i_uid = sb->s_hpfs_uid;
 	i->i_gid = sb->s_hpfs_gid;
@@ -199,27 +200,27 @@
 			return;
 		}
 		if ((ea = hpfs_get_ea(i->i_sb, fnode, "MODE", &ea_size))) {
+			int rdev = 0;
+			umode_t mode = sb->s_hpfs_mode;
 			if (ea_size == 2) {
-				i->i_mode = ea[0] + (ea[1] << 8);
+				mode = ea[0] + (ea[1] << 8);
 				i->i_hpfs_ea_mode = 1;
 			}
 			kfree(ea);
-			if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) {
+			i->i_mode = mode;
+			if (S_ISBLK(mode) || S_ISCHR(mode)) {
 				if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) {
 					if (ea_size == 4)
-						i->i_rdev = to_kdev_t(ea[0] + (ea[1] << 8) + (ea[2] << 16) + (ea[3] << 24));
+						rdev = ea[0] + (ea[1] << 8) + (ea[2] << 16) + (ea[3] << 24);
 					kfree(ea);
 				}
 			}
-			if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode) || S_ISFIFO(i->i_mode) || S_ISSOCK(i->i_mode)) {
+			if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
 				brelse(bh);
 				i->i_nlink = 1;
 				i->i_size = 0;
 				i->i_blocks = 1;
-				i->i_op = NULL;
-				if (S_ISBLK(i->i_mode)) i->i_op = (struct inode_operations *) &blkdev_inode_operations;
-				if (S_ISCHR(i->i_mode)) i->i_op = (struct inode_operations *) &chrdev_inode_operations;
-				if (S_ISFIFO(i->i_mode)) init_fifo(i);
+				init_special_inode(i, mode, rdev);
 				return;
 			}
 		}
@@ -341,7 +342,7 @@
 		hpfs_brelse4(&qbh);
 	}
 	if (S_ISDIR(i->i_mode)) {
-		if ((de = map_dirent(i, i->i_hpfs_dno, "\001\001", 2, NULL, &qbh, NULL))) {
+		if ((de = map_dirent(i, i->i_hpfs_dno, "\001\001", 2, NULL, &qbh))) {
 			de->write_date = gmt_to_local(i->i_sb, i->i_mtime);
 			de->read_date = gmt_to_local(i->i_sb, i->i_atime);
 			de->creation_date = gmt_to_local(i->i_sb, i->i_ctime);
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/name.c linux/fs/hpfs/name.c
--- v2.3.2/linux/fs/hpfs/name.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/name.c	Sun May 16 10:27:40 1999
@@ -70,13 +70,15 @@
 	return dir[a];
 }
 
-int hpfs_chk_name(unsigned char *name, unsigned len)
+int hpfs_chk_name(unsigned char *name, unsigned *len)
 {
 	int i;
-	if (!len || len > 254) return 1;
-	for (i = 0; i < len; i++) if (not_allowed_char(name[i])) return 1;
-	if (len == 1) if (name[0] == '.') return 1;
-	if (len == 2) if (name[0] == '.' && name[1] == '.') return 1;
+	if (*len > 254) return -ENAMETOOLONG;
+	hpfs_adjust_length(name, len);
+	if (!*len) return -EINVAL;
+	for (i = 0; i < *len; i++) if (not_allowed_char(name[i])) return -EINVAL;
+	if (*len == 1) if (name[0] == '.') return -EINVAL;
+	if (*len == 2) if (name[0] == '.' && name[1] == '.') return -EINVAL;
 	return 0;
 }
 
@@ -101,7 +103,7 @@
 }
 
 int hpfs_compare_names(struct super_block *s, unsigned char *n1, unsigned l1,
-		  unsigned char *n2, unsigned l2, int last)
+		       unsigned char *n2, unsigned l2, int last)
 {
 	unsigned l = l1 < l2 ? l1 : l2;
 	unsigned i;
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/namei.c linux/fs/hpfs/namei.c
--- v2.3.2/linux/fs/hpfs/namei.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/namei.c	Sun May 16 10:27:40 1999
@@ -11,7 +11,7 @@
 int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
+	unsigned len = dentry->d_name.len;
 	struct quad_buffer_head qbh0;
 	struct buffer_head *bh;
 	struct hpfs_dirent *de;
@@ -22,14 +22,8 @@
 	dnode_secno dno;
 	int r;
 	struct hpfs_dirent dee;
-	if (!dir) return -ENOENT;
-	if (!S_ISDIR(dir->i_mode)) {
-		return -ENOTDIR;
-	}
-	hpfs_adjust_length((char *)name, &len);
-	if (hpfs_chk_name((char *)name, len)) {
-		return -ENAMETOOLONG;
-	}	
+	int err;
+	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
 	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
 	if (!(dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1))) goto bail1;
 	memset(&dee, 0, sizeof dee);
@@ -105,25 +99,15 @@
 int hpfs_create(struct inode *dir, struct dentry *dentry, int mode)
 {
 	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
-	struct inode *result;
+	unsigned len = dentry->d_name.len;
+	struct inode *result = NULL;
 	struct buffer_head *bh;
 	struct fnode *fnode;
 	fnode_secno fno;
 	int r;
 	struct hpfs_dirent dee;
-	result = NULL;
-	if (!dir) return -ENOENT;
-	if (!S_ISDIR(dir->i_mode)) {
-		return -ENOTDIR;
-	}
-	if (!S_ISREG(mode)) {
-		return -EINVAL;
-	}
-	hpfs_adjust_length((char *)name, &len);
-	if (hpfs_chk_name((char *)name, len)) {
-		return -ENAMETOOLONG;
-	}	
+	int err;
+	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
 	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
 	memset(&dee, 0, sizeof dee);
 	if (!(mode & 0222)) dee.read_only = 1;
@@ -178,28 +162,16 @@
 int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 {
 	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
+	unsigned len = dentry->d_name.len;
 	struct buffer_head *bh;
 	struct fnode *fnode;
 	fnode_secno fno;
 	int r;
 	struct hpfs_dirent dee;
 	struct inode *result = NULL;
-	if (!dir) return -ENOENT;
-	if (dir->i_sb->s_hpfs_eas < 2) {
-		/*iput(dir);*/
-		return -EPERM;
-	}
-	if (!S_ISDIR(dir->i_mode)) {
-		return -ENOTDIR;
-	}
-	if (!S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) && !S_ISSOCK(mode)) {
-		return -EINVAL;
-	}
-	hpfs_adjust_length((char *)name, &len);
-	if (hpfs_chk_name((char *)name, len)) {
-		return -ENAMETOOLONG;
-	}	
+	int err;
+	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
+	if (dir->i_sb->s_hpfs_eas < 2) return -EPERM;
 	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
 	memset(&dee, 0, sizeof dee);
 	if (!(mode & 0222)) dee.read_only = 1;
@@ -227,17 +199,12 @@
 		result->i_hpfs_ea_size = 0;
 		/*if (result->i_blocks == -1) result->i_blocks = 1;
 		if (result->i_size == -1) result->i_size = 0;*/
-		result->i_mode = mode;
 		result->i_uid = current->fsuid;
 		result->i_gid = current->fsgid;
-		if (!S_ISFIFO(mode)) result->i_rdev = to_kdev_t(rdev);
 		result->i_nlink = 1;
 		result->i_size = 0;
 		result->i_blocks = 1;
-		result->i_op = NULL;
-		if (S_ISBLK(result->i_mode)) result->i_op = (struct inode_operations *) &blkdev_inode_operations;
-		if (S_ISCHR(result->i_mode)) result->i_op = (struct inode_operations *) &chrdev_inode_operations;
-		if (S_ISFIFO(result->i_mode)) init_fifo(result);
+		init_special_inode(result, mode, rdev);
 		hpfs_write_inode_nolock(result);
 		d_instantiate(dentry, result);
 	}
@@ -258,24 +225,16 @@
 int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
 {
 	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
+	unsigned len = dentry->d_name.len;
 	struct buffer_head *bh;
 	struct fnode *fnode;
 	fnode_secno fno;
 	int r;
 	struct hpfs_dirent dee;
 	struct inode *result;
-	if (!dir) return -ENOENT;
-	if (dir->i_sb->s_hpfs_eas < 2) {
-		return -EPERM;
-	}
-	if (!S_ISDIR(dir->i_mode)) {
-		return -ENOTDIR;
-	}
-	hpfs_adjust_length((char *)name, &len);
-	if (hpfs_chk_name((char *)name, len)) {
-		return -ENAMETOOLONG;
-	}
+	int err;
+	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
+	if (dir->i_sb->s_hpfs_eas < 2) return -EPERM;
 	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
 	memset(&dee, 0, sizeof dee);
 	dee.archive = 1;
@@ -331,16 +290,18 @@
 int hpfs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
+	unsigned len = dentry->d_name.len;
 	struct quad_buffer_head qbh;
 	struct hpfs_dirent *de;
 	struct inode *inode = dentry->d_inode;
 	dnode_secno dno;
 	fnode_secno fno;
-	int depth, r;
+	int r;
+	int rep = 0;
 	hpfs_adjust_length((char *)name, &len);
+	again:
 	hpfs_lock_2inodes(dir, inode);
-	if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh, &depth))) {
+	if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh))) {
 		hpfs_unlock_2inodes(dir, inode);
 		return -ENOENT;
 	}
@@ -355,29 +316,49 @@
 		return -EISDIR;
 	}
 	fno = de->fnode;
-	if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, depth)) == 1) hpfs_error(dir->i_sb, "there was error when removing dirent");
+	if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, 1)) == 1) hpfs_error(dir->i_sb, "there was error when removing dirent");
 	if (r != 2) {
 		inode->i_nlink--;
 		hpfs_unlock_2inodes(dir, inode);
 		d_delete(dentry);
-	} else hpfs_unlock_2inodes(dir, inode);
+	} else {	/* no space for deleting, try to truncate file */
+		struct iattr newattrs;
+		hpfs_unlock_2inodes(dir, inode);
+		if (rep || dentry->d_count > 1 || permission(inode, MAY_WRITE) || get_write_access(inode)) goto ret;
+		/*printk("HPFS: truncating file before delete.\n");*/
+		down(&inode->i_sem);	/* do_truncate should be called here, but it's */
+		newattrs.ia_size = 0;	/* not exported */
+		newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+		if (notify_change(dentry, &newattrs)) {
+			up(&inode->i_sem);
+			put_write_access(inode);
+			goto ret;
+		}
+		vmtruncate(inode, 0);
+		if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode);
+		up(&inode->i_sem);
+		put_write_access(inode);
+		rep = 1;
+		goto again;
+	}
+	ret:
 	return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
 }
 
 int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
+	unsigned len = dentry->d_name.len;
 	struct quad_buffer_head qbh;
 	struct hpfs_dirent *de;
 	struct inode *inode = dentry->d_inode;
 	dnode_secno dno;
 	fnode_secno fno;
 	int n_items = 0;
-	int depth, r;
+	int r;
 	hpfs_adjust_length((char *)name, &len);
 	hpfs_lock_2inodes(dir, inode);
-	if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh, &depth))) {
+	if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh))) {
 		hpfs_unlock_2inodes(dir, inode);
 		return -ENOENT;
 	}	
@@ -391,8 +372,6 @@
 		hpfs_unlock_2inodes(dir, inode);
 		return -ENOTDIR;
 	}
-	/*shrink_dcache_parent(dentry);
-	if (dentry->d_count > 1) {*/
 	if (!list_empty(&dentry->d_hash)) {
 		hpfs_brelse4(&qbh);
 		hpfs_unlock_2inodes(dir, inode);
@@ -405,7 +384,7 @@
 		return -ENOTEMPTY;
 	}
 	fno = de->fnode;
-	if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, depth)) == 1)
+	if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, 1)) == 1)
 		hpfs_error(dir->i_sb, "there was error when removing dirent");
 	if (r != 2) {
 		dir->i_nlink--;
@@ -445,7 +424,7 @@
 {
 	struct inode *inode = dinode->d_inode;
 	char *link;
-	int len;
+	unsigned len;
 	struct buffer_head *bh;
 	struct fnode *fnode;
 	if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) {
@@ -471,40 +450,29 @@
 	int old_len = old_dentry->d_name.len;
 	char *new_name = (char *)new_dentry->d_name.name;
 	int new_len = new_dentry->d_name.len;
-	struct inode *i;
+	struct inode *i = old_dentry->d_inode;
 	struct inode *new_inode = new_dentry->d_inode;
 	struct quad_buffer_head qbh, qbh1;
 	struct hpfs_dirent *dep, *nde;
 	struct hpfs_dirent de;
 	dnode_secno dno;
-	int depth, r;
-	int err = 0;
+	int r;
 	struct buffer_head *bh;
 	struct fnode *fnode;
+	int err;
+	if ((err = hpfs_chk_name((char *)new_name, &new_len))) return err;
+	err = 0;
 	hpfs_adjust_length((char *)old_name, &old_len);
-	hpfs_adjust_length((char *)new_name, &new_len);
-	if (hpfs_chk_name((char *)new_name, new_len) || hpfs_chk_name((char *)old_name, old_len)) {
-		err = -ENAMETOOLONG;
-		goto end2;
-	}
-	if (!(i = old_dentry->d_inode)) {
-		hpfs_error(old_dir->i_sb, "hpfs_rename: grrr, could not get inode");
-		err = -ENOENT;
-		goto end2;
-	}
-	if (i->i_sb != old_dir->i_sb || i->i_sb != new_dir->i_sb) {
-		err = -EINVAL; /* Do not allow to move mount points */
-		goto end1_;
-	}
 
 	hpfs_lock_3inodes(old_dir, new_dir, i);
 	
-	if (is_subdir(new_dentry, old_dentry) || (new_inode && S_ISDIR(new_inode->i_mode))) {
+	/* Erm? Moving over the empty non-busy directory is perfectly legal */
+	if (new_inode && S_ISDIR(new_inode->i_mode)) {
 		err = -EINVAL;
 		goto end1;
 	}
 
-	if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh, &depth))) {
+	if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh))) {
 		hpfs_error(i->i_sb, "lookup succeeded but map dirent failed");
 		err = -ENOENT;
 		goto end1;
@@ -514,10 +482,10 @@
 
 	if (new_inode) {
 		hpfs_brelse4(&qbh);
-		if ((nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1, NULL))) {
+		if ((nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) {
 			int r;
-			if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, depth)) != 2) {
-				if (!(nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1, NULL))) {
+			if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
+				if (!(nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) {
 					hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent #2");
 					goto end1;
 				}
@@ -539,7 +507,7 @@
 	if (new_dir == old_dir) hpfs_brelse4(&qbh);
 
 	hpfs_lock_creation(i->i_sb);
-	if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, depth + 2))) {
+	if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, 1))) {
 		hpfs_unlock_creation(i->i_sb);
 		if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!");
 		err = r == 1 ? -ENOSPC : -EFSERROR;
@@ -548,7 +516,7 @@
 	}
 	
 	if (new_dir == old_dir)
-		if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh, &depth))) {
+		if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh))) {
 			hpfs_unlock_creation(i->i_sb);
 			hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2");
 			err = -ENOENT;
@@ -577,12 +545,9 @@
 		mark_buffer_dirty(bh, 1);
 		brelse(bh);
 	}
-	d_move(old_dentry, new_dentry);
 	i->i_hpfs_conv = i->i_sb->s_hpfs_conv;
 	hpfs_decide_conv(i, (char *)new_name, new_len);
 	end1:
 	hpfs_unlock_3inodes(old_dir, new_dir, i);
-	end1_:
-	end2:
 	return err;
 }
diff -u --recursive --new-file v2.3.2/linux/fs/hpfs/super.c linux/fs/hpfs/super.c
--- v2.3.2/linux/fs/hpfs/super.c	Sat May 15 23:46:04 1999
+++ linux/fs/hpfs/super.c	Sun May 16 10:27:40 1999
@@ -105,7 +105,7 @@
 	MOD_DEC_USE_COUNT;
 }
 
-static unsigned count_one_bitmap(struct super_block *s, secno secno)
+unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
 {
 	struct quad_buffer_head qbh;
 	unsigned *bits;
@@ -114,6 +114,7 @@
 	count = 0;
 	for (i = 0; i < 2048 / sizeof(unsigned); i++) {
 		unsigned b; 
+		if (!bits[i]) continue;
 		for (b = bits[i]; b; b>>=1) count += b & 1;
 	}
 	hpfs_brelse4(&qbh);
@@ -126,7 +127,7 @@
 	n_bands = (s->s_hpfs_fs_size + 0x3fff) >> 14;
 	count = 0;
 	for (n = 0; n < n_bands; n++)
-		count += count_one_bitmap(s, s->s_hpfs_bmp_dir[n]);
+		count += hpfs_count_one_bitmap(s, s->s_hpfs_bmp_dir[n]);
 	return count;
 }
 
@@ -135,7 +136,7 @@
 	struct statfs tmp;
 	/*if (s->s_hpfs_n_free == -1) {*/
 		s->s_hpfs_n_free = count_bitmaps(s);
-		s->s_hpfs_n_free_dnodes = count_one_bitmap(s, s->s_hpfs_dmap);
+		s->s_hpfs_n_free_dnodes = hpfs_count_one_bitmap(s, s->s_hpfs_dmap);
 	/*}*/
 	tmp.f_type = s->s_magic;
 	tmp.f_bsize = 512;
@@ -379,7 +380,8 @@
 	s->s_hpfs_cp_table = NULL;
 
 	s->s_hpfs_creation_de_lock = s->s_hpfs_rd_inode = 0;
-	s->s_hpfs_creation_de = s->s_hpfs_iget_q = NULL;
+	init_waitqueue_head(&s->s_hpfs_creation_de);
+	init_waitqueue_head(&s->s_hpfs_iget_q);
 
 	uid = current->uid;
 	gid = current->gid;
@@ -540,7 +542,7 @@
 
 	root_dno = hpfs_fnode_dno(s, s->s_hpfs_root);
 	if (root_dno)
-		de = map_dirent(s->s_root->d_inode, root_dno, "\001\001", 2, NULL, &qbh, NULL);
+		de = map_dirent(s->s_root->d_inode, root_dno, "\001\001", 2, NULL, &qbh);
 	if (!root_dno || !de) hpfs_error(s, "unable to find root dir");
 	else {
 		s->s_root->d_inode->i_atime = local_to_gmt(s, de->read_date);
diff -u --recursive --new-file v2.3.2/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.3.2/linux/fs/minix/namei.c	Fri May 14 18:55:25 1999
+++ linux/fs/minix/namei.c	Sat May 15 23:43:05 1999
@@ -297,7 +297,7 @@
 	inode->i_nlink = 2;
 	mark_buffer_dirty(dir_block, 1);
 	brelse(dir_block);
-	inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
+	inode->i_mode = S_IFDIR | mode;
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
 	mark_inode_dirty(inode);
diff -u --recursive --new-file v2.3.2/linux/fs/namei.c linux/fs/namei.c
--- v2.3.2/linux/fs/namei.c	Fri May 14 18:55:25 1999
+++ linux/fs/namei.c	Sat May 15 23:43:05 1999
@@ -882,10 +882,6 @@
 	return error;
 }
 
-/*
- * Look out: this function may change a normal dentry
- * into a directory dentry (different size)..
- */
 static inline int do_mkdir(const char * pathname, int mode)
 {
 	int error;
@@ -919,7 +915,7 @@
 		goto exit_lock;
 
 	DQUOT_INIT(dir->d_inode);
-	mode &= 0777 & ~current->fs->umask;
+	mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask;
 	error = dir->d_inode->i_op->mkdir(dir->d_inode, dentry, mode);
 
 exit_lock:
diff -u --recursive --new-file v2.3.2/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.2/linux/fs/nfsd/vfs.c	Mon Apr 12 10:03:45 1999
+++ linux/fs/nfsd/vfs.c	Sat May 15 23:43:05 1999
@@ -691,6 +691,8 @@
 		break;
 	case S_IFDIR:
 		opfunc = (nfsd_dirop_t) dirp->i_op->mkdir;
+		/* Odd, indeed, but filesystems did it anyway */
+		iap->ia_mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask;
 		break;
 	case S_IFCHR:
 	case S_IFBLK:
diff -u --recursive --new-file v2.3.2/linux/fs/super.c linux/fs/super.c
--- v2.3.2/linux/fs/super.c	Fri May 14 18:55:26 1999
+++ linux/fs/super.c	Sat May 15 23:43:04 1999
@@ -846,7 +846,8 @@
  * Anyone using this new feature must know what he/she is doing.
  */
 
-int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
+int do_mount(kdev_t dev, const char * dev_name, const char * dir_name,
+	     const char * type, int flags, void * data)
 {
 	struct dentry * dir_d;
 	struct super_block * sb;
diff -u --recursive --new-file v2.3.2/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.3.2/linux/fs/sysv/namei.c	Fri May 14 18:55:26 1999
+++ linux/fs/sysv/namei.c	Sat May 15 23:43:05 1999
@@ -291,7 +291,7 @@
 	inode->i_nlink = 2;
 	mark_buffer_dirty(dir_block, 1);
 	brelse(dir_block);
-	inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
+	inode->i_mode = S_IFDIR | mode;
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
 	mark_inode_dirty(inode);
diff -u --recursive --new-file v2.3.2/linux/fs/ufs/namei.c linux/fs/ufs/namei.c
--- v2.3.2/linux/fs/ufs/namei.c	Fri May 14 18:55:27 1999
+++ linux/fs/ufs/namei.c	Sat May 15 23:43:05 1999
@@ -539,7 +539,7 @@
 	inode->i_nlink = 2;
 	mark_buffer_dirty(dir_block, 1);
 	brelse (dir_block);
-	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
+	inode->i_mode = S_IFDIR | mode;
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
 	mark_inode_dirty(inode);
diff -u --recursive --new-file v2.3.2/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.3.2/linux/include/asm-alpha/processor.h	Mon Jan 18 09:55:30 1999
+++ linux/include/asm-alpha/processor.h	Sat May 15 23:43:04 1999
@@ -85,7 +85,7 @@
  * is the frame pointer in schedule() and $15 is saved at offset 48 by
  * entry.S:do_switch_stack).
  *
- * Under heavy swap load I've seen this loose in an ugly way.  So do
+ * Under heavy swap load I've seen this lose in an ugly way.  So do
  * some extra sanity checking on the ranges we expect these pointers
  * to be in so that we can fail gracefully.  This is just for ps after
  * all.  -- r~
diff -u --recursive --new-file v2.3.2/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.3.2/linux/include/asm-alpha/semaphore.h	Fri May  7 10:55:26 1999
+++ linux/include/asm-alpha/semaphore.h	Sat May 15 15:05:37 1999
@@ -16,7 +16,7 @@
 	/* Careful, inline assembly knows about the position of these two.  */
 	atomic_t count;
 	atomic_t waking;		/* biased by -1 */
-	struct wait_queue *wait;
+	wait_queue_head_t wait;
 };
 
 #define MUTEX ((struct semaphore) \
diff -u --recursive --new-file v2.3.2/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h
--- v2.3.2/linux/include/asm-arm/semaphore.h	Fri May 14 18:55:27 1999
+++ linux/include/asm-arm/semaphore.h	Sat May 15 15:05:37 1999
@@ -10,7 +10,7 @@
 struct semaphore {
 	atomic_t count;
 	int waking;
-	struct wait_queue * wait;
+	wait_queue_head_t wait;
 };
 
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL })
diff -u --recursive --new-file v2.3.2/linux/include/asm-m68k/adb_mouse.h linux/include/asm-m68k/adb_mouse.h
--- v2.3.2/linux/include/asm-m68k/adb_mouse.h	Wed Sep  2 09:39:18 1998
+++ linux/include/asm-m68k/adb_mouse.h	Sat May 15 15:05:37 1999
@@ -16,7 +16,7 @@
 	short		dy;
 	int		ready;
 	int		active;
-	struct wait_queue *wait;
+	wait_queue_head_t wait;
 	struct fasync_struct *fasyncptr;
 };
 
diff -u --recursive --new-file v2.3.2/linux/include/asm-m68k/atari_joystick.h linux/include/asm-m68k/atari_joystick.h
--- v2.3.2/linux/include/asm-m68k/atari_joystick.h	Sat Mar 30 04:11:24 1996
+++ linux/include/asm-m68k/atari_joystick.h	Sat May 15 15:05:37 1999
@@ -16,7 +16,7 @@
 	char		dir;
 	int		ready;
 	int		active;
-	struct wait_queue *wait;
+	wait_queue_head_t wait;
 };
 
 #endif
diff -u --recursive --new-file v2.3.2/linux/include/asm-m68k/mac_mouse.h linux/include/asm-m68k/mac_mouse.h
--- v2.3.2/linux/include/asm-m68k/mac_mouse.h	Thu Feb 12 16:30:13 1998
+++ linux/include/asm-m68k/mac_mouse.h	Sat May 15 15:05:37 1999
@@ -16,7 +16,7 @@
 	short		dy;
 	int		ready;
 	int		active;
-	struct wait_queue *wait;
+	wait_queue_head_t wait;
 	struct fasync_struct *fasyncptr;
 };
 
diff -u --recursive --new-file v2.3.2/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.3.2/linux/include/asm-m68k/semaphore.h	Fri May 14 18:55:28 1999
+++ linux/include/asm-m68k/semaphore.h	Sat May 15 15:05:37 1999
@@ -18,7 +18,7 @@
 struct semaphore {
 	atomic_t count;
 	atomic_t waking;
-	struct wait_queue * wait;
+	wait_queue_head_t wait;
 };
 
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
diff -u --recursive --new-file v2.3.2/linux/include/asm-mips/semaphore.h linux/include/asm-mips/semaphore.h
--- v2.3.2/linux/include/asm-mips/semaphore.h	Thu Jan 14 15:53:25 1999
+++ linux/include/asm-mips/semaphore.h	Sat May 15 15:05:37 1999
@@ -17,7 +17,7 @@
 struct semaphore {
 	atomic_t count;
 	atomic_t waking;
-	struct wait_queue * wait;
+	wait_queue_head_t wait;
 };
 
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
diff -u --recursive --new-file v2.3.2/linux/include/asm-ppc/adb_mouse.h linux/include/asm-ppc/adb_mouse.h
--- v2.3.2/linux/include/asm-ppc/adb_mouse.h	Mon Jan 12 15:18:13 1998
+++ linux/include/asm-ppc/adb_mouse.h	Sat May 15 15:05:37 1999
@@ -16,7 +16,7 @@
 	short		dy;
 	int		ready;
 	int		active;
-	struct wait_queue *wait;
+	wait_queue_head_t wait;
 	struct fasync_struct *fasyncptr;
 };
 
diff -u --recursive --new-file v2.3.2/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.3.2/linux/include/asm-ppc/semaphore.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/semaphore.h	Sat May 15 15:05:37 1999
@@ -13,7 +13,7 @@
 struct semaphore {
 	atomic_t count;
 	atomic_t waking;
-	struct wait_queue *wait;
+	wait_queue_head_t wait;
 };
 
 #define sema_init(sem, val)	atomic_set(&((sem)->count), (val))
diff -u --recursive --new-file v2.3.2/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h
--- v2.3.2/linux/include/asm-sparc/io.h	Fri May 14 18:55:28 1999
+++ linux/include/asm-sparc/io.h	Sat May 15 11:12:09 1999
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.18 1998/09/21 05:07:17 jj Exp $ */
+/* $Id: io.h,v 1.19 1999/05/14 07:26:09 davem Exp $ */
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
 
diff -u --recursive --new-file v2.3.2/linux/include/asm-sparc64/hdreg.h linux/include/asm-sparc64/hdreg.h
--- v2.3.2/linux/include/asm-sparc64/hdreg.h	Fri May 14 18:55:28 1999
+++ linux/include/asm-sparc64/hdreg.h	Sat May 15 11:12:09 1999
@@ -1,4 +1,4 @@
-/* $Id: hdreg.h,v 1.9 1998/05/08 21:05:28 davem Exp $
+/* $Id: hdreg.h,v 1.1 1999/05/14 07:23:13 davem Exp $
  * hdreg.h: Ultra/PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.2/linux/include/asm-sparc64/ide.h linux/include/asm-sparc64/ide.h
--- v2.3.2/linux/include/asm-sparc64/ide.h	Fri May 14 18:55:28 1999
+++ linux/include/asm-sparc64/ide.h	Sat May 15 11:12:10 1999
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.12 1999/04/17 14:25:29 davem Exp $
+/* $Id: ide.h,v 1.14 1999/05/15 05:02:35 davem Exp $
  * ide.h: Ultra/PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,8 @@
 #ifdef __KERNEL__
 
 #include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/hdreg.h>
 
 #undef  MAX_HWIFS
 #define MAX_HWIFS	2
diff -u --recursive --new-file v2.3.2/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h
--- v2.3.2/linux/include/asm-sparc64/io.h	Fri May 14 18:55:29 1999
+++ linux/include/asm-sparc64/io.h	Sat May 15 11:12:10 1999
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.19 1998/08/23 05:41:46 ecd Exp $ */
+/* $Id: io.h,v 1.20 1999/05/14 07:23:18 davem Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
diff -u --recursive --new-file v2.3.2/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.3.2/linux/include/linux/blk.h	Tue May 11 13:05:32 1999
+++ linux/include/linux/blk.h	Sun May 16 13:19:06 1999
@@ -85,12 +85,6 @@
 
 #endif
 
-#define RO_IOCTLS(dev,where) \
-  case BLKROSET: { int __val;  if (!capable(CAP_SYS_ADMIN)) return -EACCES; \
-		   if (get_user(__val, (int *)(where))) return -EFAULT; \
-		   set_device_ro((dev),__val); return 0; } \
-  case BLKROGET: { int __val = (is_read_only(dev) != 0) ; \
-		    return put_user(__val,(int *) (where)); }
 		 
 #if defined(MAJOR_NR) || defined(IDE_DRIVER)
 
diff -u --recursive --new-file v2.3.2/linux/include/linux/blkpg.h linux/include/linux/blkpg.h
--- v2.3.2/linux/include/linux/blkpg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/blkpg.h	Sat May 15 23:43:04 1999
@@ -0,0 +1,64 @@
+#ifndef _LINUX_BLKPG_H
+#define _LINUX_BLKPG_H
+
+/*
+ * Partition table and disk geometry handling
+ *
+ * A single ioctl with lots of subfunctions:
+ *
+ * Device number stuff:
+ *    get_whole_disk()		(given the device number of a partition,
+ *                               find the device number of the encompassing disk)
+ *    get_all_partitions()	(given the device number of a disk, return the
+ *				 device numbers of all its known partitions)
+ *
+ * Partition stuff:
+ *    add_partition()
+ *    delete_partition()
+ *    test_partition_in_use()	(also for test_disk_in_use)
+ *
+ * Geometry stuff:
+ *    get_geometry()
+ *    set_geometry()
+ *    get_bios_drivedata()
+ *
+ * For today, only the partition stuff - aeb, 990515
+ */
+#include <linux/ioctl.h>
+
+#define BLKPG      _IO(0x12,105)
+
+/* The argument structure */
+struct blkpg_ioctl_arg {
+        int op;
+        int flags;
+        int datalen;
+        void *data;
+} *p;
+
+/* The subfunctions (for the op field) */
+#define BLKPG_ADD_PARTITION	1
+#define BLKPG_DEL_PARTITION	2
+
+/* Sizes of name fields. Unused at present. */
+#define BLKPG_DEVNAMELTH	64
+#define BLKPG_VOLNAMELTH	64
+
+/* The data structure for ADD_PARTITION and DEL_PARTITION */
+struct blkpg_partition {
+	long long start;		/* starting offset in bytes */
+	long long length;		/* length in bytes */
+	int pno;			/* partition number */
+	char devname[BLKPG_DEVNAMELTH];	/* partition name, like sda5 or c0d1p2,
+					   to be used in kernel messages */
+	char volname[BLKPG_VOLNAMELTH];	/* volume label */
+};
+
+#ifdef __KERNEL__
+
+extern char * partition_name(kdev_t dev);
+extern int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_BLKPG_H */
diff -u --recursive --new-file v2.3.2/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.2/linux/include/linux/fs.h	Sat May 15 23:46:05 1999
+++ linux/include/linux/fs.h	Sun May 16 13:18:20 1999
@@ -140,6 +140,7 @@
 #define IS_NOATIME(inode)	__IS_FLG(inode, MS_NOATIME)
 #define IS_NODIRATIME(inode)	__IS_FLG(inode, MS_NODIRATIME)
 
+
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
 
@@ -154,7 +155,13 @@
 #define BLKFRAGET  _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
 #define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
 #define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
-#define BLKSSZGET  _IO(0x12,104)/* get block device sector size (reserved for) */
+#define BLKSSZGET  _IO(0x12,104)/* get block device sector size */
+#if 0
+#define BLKPG      _IO(0x12,105)/* See blkpg.h */
+/* This was here just to show that the number is taken -
+   probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */
+#endif
+
 
 #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
 #define FIBMAP	   _IO(0x00,1)	/* bmap access */
@@ -724,7 +731,6 @@
 extern char * cdevname(kdev_t dev);
 extern char * kdevname(kdev_t dev);
 extern void init_special_inode(struct inode *, umode_t, int);
-
 
 extern void init_fifo(struct inode * inode);
 extern struct inode_operations fifo_inode_operations;
diff -u --recursive --new-file v2.3.2/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v2.3.2/linux/include/linux/genhd.h	Sat May 15 23:46:05 1999
+++ linux/include/linux/genhd.h	Sun May 16 13:18:19 1999
@@ -39,7 +39,7 @@
 #endif
 
 #define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
-#define EZD_PARTITION		0x55	/* EZ-DRIVE:  same as DM6 (we think) */
+#define EZD_PARTITION		0x55	/* EZ-DRIVE */
 #define DM6_AUX1PARTITION	0x51	/* no DDO:  use xlated geom */
 #define DM6_AUX3PARTITION	0x53	/* no DDO:  use xlated geom */
 	
@@ -70,8 +70,8 @@
 	int max_nr;			/* maximum number of real devices */
 
 	void (*init)(struct gendisk *);	/* Initialization called before we do our thing */
-	struct hd_struct *part;		/* partition table */
-	int *sizes;			/* device size in blocks, copied to blk_size[] */
+	struct hd_struct *part;		/* [indexed by minor] */
+	int *sizes;			/* [idem], device size in blocks */
 	int nr_real;			/* number of real devices */
 
 	void *real_devices;		/* internal use */
@@ -226,14 +226,12 @@
 
 #endif /* CONFIG_UNIXWARE_DISKLABEL */
 
+#ifdef __KERNEL__
 extern struct gendisk *gendisk_head;	/* linked list of disks */
 
-/*
- * disk_name() is used by genhd.c and md.c.
- * It formats the devicename of the indicated disk
- * into the supplied buffer, and returns a pointer
- * to that same buffer (for convenience).
- */
 char *disk_name (struct gendisk *hd, int minor, char *buf);
+
+int get_hardsect_size(kdev_t dev);
+#endif
 
 #endif
diff -u --recursive --new-file v2.3.2/linux/include/linux/hpfs_fs_sb.h linux/include/linux/hpfs_fs_sb.h
--- v2.3.2/linux/include/linux/hpfs_fs_sb.h	Sat May 15 23:46:05 1999
+++ linux/include/linux/hpfs_fs_sb.h	Sun May 16 10:33:30 1999
@@ -24,13 +24,13 @@
 	unsigned sb_rd_inode : 2;	/* lookup tells read_inode: 1-read fnode
 					   2-don't read fnode, file
 					   3-don't read fnode, direcotry */
-	struct wait_queue *sb_iget_q;
+	wait_queue_head_t sb_iget_q;
 	unsigned char *sb_cp_table;	/* code page tables: */
 					/* 	128 bytes uppercasing table & */
 					/*	128 bytes lowercasing table */
 	unsigned *sb_bmp_dir;		/* main bitmap directory */
 	unsigned sb_c_bitmap;		/* current bitmap */
-	struct wait_queue *sb_creation_de;/* when creating dirents, nobody else
+	wait_queue_head_t sb_creation_de;/* when creating dirents, nobody else
 					   can alloc blocks */
 	unsigned sb_creation_de_lock : 1;
 	/*unsigned sb_mounting : 1;*/
@@ -55,7 +55,7 @@
 #define s_hpfs_chk u.hpfs_sb.sb_chk
 #define s_hpfs_was_error u.hpfs_sb.sb_was_error
 #define s_hpfs_chkdsk u.hpfs_sb.sb_chkdsk
-#define s_hpfs_rd_fnode u.hpfs_sb.sb_rd_fnode
+/*#define s_hpfs_rd_fnode u.hpfs_sb.sb_rd_fnode*/
 #define s_hpfs_rd_inode u.hpfs_sb.sb_rd_inode
 #define s_hpfs_cp_table u.hpfs_sb.sb_cp_table
 #define s_hpfs_bmp_dir u.hpfs_sb.sb_bmp_dir
diff -u --recursive --new-file v2.3.2/linux/include/linux/istallion.h linux/include/linux/istallion.h
--- v2.3.2/linux/include/linux/istallion.h	Wed Feb  4 14:52:16 1998
+++ linux/include/linux/istallion.h	Sat May 15 15:05:37 1999
@@ -70,9 +70,9 @@
 	long			pgrp;
 	unsigned int		rxmarkmsk;
 	struct tty_struct	*tty;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-	struct wait_queue	*raw_wait;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+	wait_queue_head_t	raw_wait;
 	struct tq_struct	tqhangup;
 	struct termios		normaltermios;
 	struct termios		callouttermios;
diff -u --recursive --new-file v2.3.2/linux/include/linux/lp_m68k.h linux/include/linux/lp_m68k.h
--- v2.3.2/linux/include/linux/lp_m68k.h	Fri Nov 20 11:44:06 1998
+++ linux/include/linux/lp_m68k.h	Sat May 15 15:05:37 1999
@@ -116,7 +116,7 @@
 	unsigned int chars;	/*busy timeout */
 	unsigned int time;	/*wait time */
 	unsigned int wait;
-	struct wait_queue *lp_wait_q; /*strobe wait */
+	struct wait_queue_head_t lp_wait_q; /*strobe wait */
 	void *base;			/* hardware drivers internal use*/
 	enum lp_type type;
 	char lp_buffer[LP_BUFFER_SIZE];
diff -u --recursive --new-file v2.3.2/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.3.2/linux/include/linux/netdevice.h	Tue May 11 13:05:03 1999
+++ linux/include/linux/netdevice.h	Sun May 16 18:28:33 1999
@@ -405,7 +405,7 @@
 extern __inline__ void dev_lock_wait(void)
 {
 	while (atomic_read(&dev_lockct)) {
-		current->counter = 0;
+		current->policy |= SCHED_YIELD;
 		schedule();
 	}
 }
diff -u --recursive --new-file v2.3.2/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.2/linux/include/linux/parport.h	Fri May 14 18:55:29 1999
+++ linux/include/linux/parport.h	Sun May 16 13:19:20 1999
@@ -184,6 +184,7 @@
 /* A parallel port */
 struct parport {
 	unsigned long base;	/* base address */
+	unsigned long base_hi;	/* base address (ECR) */
 	unsigned int size;	/* IO extent */
 	const char *name;
 	int irq;		/* interrupt (or -1 for none) */
diff -u --recursive --new-file v2.3.2/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- v2.3.2/linux/include/linux/parport_pc.h	Tue May 11 13:04:45 1999
+++ linux/include/linux/parport_pc.h	Sun May 16 13:18:35 1999
@@ -5,14 +5,14 @@
 
 /* --- register definitions ------------------------------- */
 
-#define ECONTROL 0x402
-#define CONFIGB  0x401
-#define CONFIGA  0x400
-#define EPPDATA  0x4
-#define EPPADDR  0x3
-#define CONTROL  0x2
-#define STATUS   0x1
-#define DATA     0
+#define ECONTROL(p)	((p)->base_hi + 0x02)
+#define CONFIGB(p)	((p)->base_hi + 0x01)
+#define CONFIGA(p)	((p)->base_hi + 0x00)
+#define EPPDATA(p)	((p)->base    + 0x04)
+#define EPPADDR(p)	((p)->base    + 0x03)
+#define CONTROL(p)	((p)->base    + 0x02)
+#define STATUS(p)	((p)->base    + 0x01)
+#define DATA(p)		((p)->base    + 0x00)
 
 /* Private data for PC low-level driver. */
 struct parport_pc_private {
@@ -26,27 +26,27 @@
 
 extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPDATA);
+	outb(d, EPPDATA(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
 {
-	return inb(p->base+EPPDATA);
+	return inb(EPPDATA(p));
 }
 
 extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPADDR);
+	outb(d, EPPADDR(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p)
 {
-	return inb(p->base+EPPADDR);
+	return inb(EPPADDR(p));
 }
 
 extern __inline__ int parport_pc_check_epp_timeout(struct parport *p)
 {
-	if (!(inb(p->base+STATUS) & 1))
+	if (!(inb(STATUS(p)) & 1))
 		return 0;
 	parport_pc_epp_clear_timeout(p);
 	return 1;
@@ -54,24 +54,24 @@
 
 extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
 {
-	return inb(p->base+CONFIGB);
+	return inb(CONFIGB(p));
 }
 
 extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+DATA);
+	outb(d, DATA(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
 {
-	return inb(p->base+DATA);
+	return inb(DATA(p));
 }
 
 extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
 {
 	struct parport_pc_private *priv = p->private_data;
 	priv->ctr = d;/* update soft copy */
-	outb(d, p->base+CONTROL);
+	outb(d, CONTROL(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
@@ -85,34 +85,34 @@
 	struct parport_pc_private *priv = p->private_data;
 	unsigned char ctr = priv->ctr;
 	ctr = (ctr & ~mask) ^ val;
-	outb (ctr, p->base+CONTROL);
+	outb (ctr, CONTROL(p));
 	return priv->ctr = ctr; /* update soft copy */
 }
 
 extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+STATUS);
+	outb(d, STATUS(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
 {
-	return inb(p->base+STATUS);
+	return inb(STATUS(p));
 }
 
 extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+ECONTROL);
+	outb(d, ECONTROL(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_econtrol(struct parport *p)
 {
-	return inb(p->base+ECONTROL);
+	return inb(ECONTROL(p));
 }
 
 extern __inline__ unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask,  unsigned char val)
 {
-	unsigned char old = inb(p->base+ECONTROL);
-	outb(((old & ~mask) ^ val), p->base+ECONTROL);
+	unsigned char old = inb(ECONTROL(p));
+	outb(((old & ~mask) ^ val), ECONTROL(p));
 	return old;
 }
 
diff -u --recursive --new-file v2.3.2/linux/include/linux/rpcsock.h linux/include/linux/rpcsock.h
--- v2.3.2/linux/include/linux/rpcsock.h	Thu Dec 12 06:54:20 1996
+++ linux/include/linux/rpcsock.h	Sat May 15 15:05:37 1999
@@ -77,7 +77,7 @@
 	struct rpc_wait *	w_next;
 	struct rpc_ioreq *	w_req;
 	int			w_result;
-	struct wait_queue *	w_wait;
+	wait_queue_head_t 	w_wait;
 	rpc_callback_fn_t	w_handler;
 	void *			w_cdata;
 	char			w_queued;
@@ -94,8 +94,8 @@
 	unsigned long		cwnd;
 	struct rpc_wait *	pending;
 	struct rpc_wait *	free;
-	struct wait_queue *	backlog;
-	struct wait_queue *	shutwait;
+	wait_queue_head_t	backlog;
+	wait_queue_head_t	shutwait;
 	int			shutdown;
 };
 
diff -u --recursive --new-file v2.3.2/linux/include/linux/serial167.h linux/include/linux/serial167.h
--- v2.3.2/linux/include/linux/serial167.h	Mon Oct  5 14:12:12 1998
+++ linux/include/linux/serial167.h	Sat May 15 15:05:37 1999
@@ -54,8 +54,8 @@
 	struct tq_struct	tqueue;
 	struct termios		normal_termios;
 	struct termios		callout_termios;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
         struct cyclades_monitor mon;
 };
 
diff -u --recursive --new-file v2.3.2/linux/include/linux/stallion.h linux/include/linux/stallion.h
--- v2.3.2/linux/include/linux/stallion.h	Wed Feb  4 14:52:16 1998
+++ linux/include/linux/stallion.h	Sat May 15 15:05:37 1999
@@ -95,8 +95,8 @@
 	unsigned long		hwid;
 	void			*uartp;
 	struct tty_struct	*tty;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
 	struct termios		normaltermios;
 	struct termios		callouttermios;
 	struct tq_struct	tqueue;
diff -u --recursive --new-file v2.3.2/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.3.2/linux/include/linux/swap.h	Tue May 11 13:03:58 1999
+++ linux/include/linux/swap.h	Sun May 16 13:18:20 1999
@@ -113,6 +113,7 @@
 /* linux/mm/swapfile.c */
 extern unsigned int nr_swapfiles;
 extern struct swap_info_struct swap_info[];
+extern int is_swap_partition(kdev_t);
 void si_swapinfo(struct sysinfo *);
 unsigned long get_swap_page(void);
 extern void FASTCALL(swap_free(unsigned long));
diff -u --recursive --new-file v2.3.2/linux/include/linux/umsdos_fs_i.h linux/include/linux/umsdos_fs_i.h
--- v2.3.2/linux/include/linux/umsdos_fs_i.h	Sun Dec 27 22:18:28 1998
+++ linux/include/linux/umsdos_fs_i.h	Sat May 15 15:05:37 1999
@@ -47,7 +47,7 @@
  */
 
 struct dir_locking_info {
-	struct wait_queue *p;
+	wait_queue_head_t p;
 	short int looking;	/* How many process doing a lookup */
 	short int creating;	/* Is there any creation going on here
 				 *  Only one at a time, although one
diff -u --recursive --new-file v2.3.2/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.2/linux/kernel/ksyms.c	Sat May 15 23:46:05 1999
+++ linux/kernel/ksyms.c	Sat May 15 23:43:04 1999
@@ -32,6 +32,7 @@
 #include <linux/hdreg.h>
 #include <linux/skbuff.h>
 #include <linux/genhd.h>
+#include <linux/blkpg.h>
 #include <linux/swap.h>
 #include <linux/ctype.h>
 #include <linux/file.h>
@@ -327,6 +328,7 @@
 EXPORT_SYMBOL(kdevname);
 EXPORT_SYMBOL(bdevname);
 EXPORT_SYMBOL(cdevname);
+EXPORT_SYMBOL(partition_name);		/* md.c only */
 EXPORT_SYMBOL(simple_strtoul);
 EXPORT_SYMBOL(system_utsname);	/* UTS data */
 EXPORT_SYMBOL(uts_sem);		/* UTS semaphore */
diff -u --recursive --new-file v2.3.2/linux/mm/mlock.c linux/mm/mlock.c
--- v2.3.2/linux/mm/mlock.c	Fri Nov 20 11:43:19 1998
+++ linux/mm/mlock.c	Sun May 16 21:45:23 1999
@@ -115,10 +115,11 @@
 	if (!retval) {
 		/* keep track of amount of locked VM */
 		pages = (end - start) >> PAGE_SHIFT;
-		if (!(newflags & VM_LOCKED))
+		if (newflags & VM_LOCKED) {
 			pages = -pages;
-		vma->vm_mm->locked_vm += pages;
-		make_pages_present(start, end);
+			make_pages_present(start, end);
+		}
+		vma->vm_mm->locked_vm -= pages;
 	}
 	return retval;
 }
diff -u --recursive --new-file v2.3.2/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.2/linux/mm/swapfile.c	Sun Mar  7 15:49:14 1999
+++ linux/mm/swapfile.c	Sat May 15 23:43:05 1999
@@ -473,6 +473,18 @@
 	return len;
 }
 
+int is_swap_partition(kdev_t dev) {
+	struct swap_info_struct *ptr = swap_info;
+	int i;
+
+	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
+		if (ptr->flags & SWP_USED)
+			if (ptr->swap_device == dev)
+				return 1;
+	}
+	return 0;
+}
+
 /*
  * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
  *
diff -u --recursive --new-file v2.3.2/linux/net/core/filter.c linux/net/core/filter.c
--- v2.3.2/linux/net/core/filter.c	Thu Mar 25 09:23:34 1999
+++ linux/net/core/filter.c	Sat May 15 17:43:46 1999
@@ -106,7 +106,7 @@
 				continue;
 
 			case BPF_ALU|BPF_MUL|BPF_K:
-				A *= X;
+				A *= fentry->k;
 				continue;
 
 			case BPF_ALU|BPF_DIV|BPF_X:
diff -u --recursive --new-file v2.3.2/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.3.2/linux/net/ipv4/tcp_timer.c	Mon May 10 09:55:25 1999
+++ linux/net/ipv4/tcp_timer.c	Sat May 15 16:58:06 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.62 1999/05/08 21:09:55 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.63 1999/05/15 23:02:21 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -541,10 +541,6 @@
 						prev = conn; 
 						continue; 
 					}
-
-					if ((long)(now - conn->expires) <= 0)
-						break;
-
 
 					tcp_synq_unlink(tp, conn, prev);
 					if (conn->retrans >= sysctl_tcp_retries1) {
diff -u --recursive --new-file v2.3.2/linux/net/ipv6/exthdrs.c linux/net/ipv6/exthdrs.c
--- v2.3.2/linux/net/ipv6/exthdrs.c	Sun Oct  4 10:19:40 1998
+++ linux/net/ipv6/exthdrs.c	Sat May 15 23:43:05 1999
@@ -369,7 +369,7 @@
    Certainly, it is possible only for udp and raw sockets, but not for tcp.
 
    AUTH header has 4byte granular length, which kills all the idea
-   behind AUTOMATIC 64bit alignment of IPv6. Now we will loose
+   behind AUTOMATIC 64bit alignment of IPv6. Now we will lose
    cpu ticks, checking that sender did not something stupid
    and opt->hdrlen is even. Shit!		--ANK (980730)
  */
diff -u --recursive --new-file v2.3.2/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.3.2/linux/net/netlink/af_netlink.c	Fri May 14 18:55:32 1999
+++ linux/net/netlink/af_netlink.c	Sun May 16 18:28:33 1999
@@ -203,7 +203,7 @@
 	 */
 
 	while (netlink_locked(sk)) {
-		current->counter = 0;
+		current->policy |= SCHED_YIELD;
 		schedule();
 	}
 
