## Automatically generated incremental diff
## From:   linux-2.2.8-pre5
## To:     linux-2.2.8-pre6
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp hpa $

diff -urN linux-2.2.8-pre5/arch/alpha/config.in linux-2.2.8-pre6/arch/alpha/config.in
--- linux-2.2.8-pre5/arch/alpha/config.in	1999-02-01 12:03:20.000000000 -0800
+++ linux-2.2.8-pre6/arch/alpha/config.in	2003-08-15 15:06:14.000000000 -0700
@@ -54,12 +54,10 @@
 unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
 unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
 unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
-unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
 
 if [ "$CONFIG_ALPHA_GENERIC" = "y" ]
 then
 	define_bool CONFIG_PCI y
-	define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
 fi
 if [ "$CONFIG_ALPHA_BOOK1" = "y" ]
 then
@@ -108,7 +106,7 @@
 	then
 		define_bool CONFIG_ALPHA_EV5 y
 	else
-	define_bool CONFIG_ALPHA_EV4 y
+		define_bool CONFIG_ALPHA_EV4 y
 	fi
 	define_bool CONFIG_ALPHA_T2 y
 fi
@@ -141,11 +139,6 @@
 then
 	define_bool CONFIG_ALPHA_EV4 y
 fi
-if [ "$CONFIG_ALPHA_EV4" = "y" ]
-then
-	# EV45 and older do not support all rounding modes in hw:
-	define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
-fi
 
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
 	-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
diff -urN linux-2.2.8-pre5/arch/alpha/kernel/entry.S linux-2.2.8-pre6/arch/alpha/kernel/entry.S
--- linux-2.2.8-pre5/arch/alpha/kernel/entry.S	1999-02-01 10:41:47.000000000 -0800
+++ linux-2.2.8-pre6/arch/alpha/kernel/entry.S	2003-08-15 15:06:14.000000000 -0700
@@ -6,8 +6,6 @@
 
 #include <asm/system.h>
 
-#define halt	.long PAL_halt
-#define rti	.long PAL_rti
 #define SIGCHLD 20
 
 #define NR_SYSCALLS 371
@@ -98,7 +96,7 @@
 	call_pal PAL_swpipl;		\
 	stq	$21,HAE_CACHE($19);	\
 	stq	$21,0($20);		\
-	bis	$0,$0,$16;		\
+	mov	$0,$16;			\
 	call_pal PAL_swpipl;		\
 	ldq	$0,0($30);		\
 	ldq	$1,8($30);		\
@@ -127,8 +125,8 @@
 entInt:
 	SAVE_ALL
 	lda	$8,0x3fff
-	bic	$30,$8,$8
 	lda	$26,ret_from_sys_call
+	bic	$30,$8,$8
 	jsr	$31,do_entInt
 .end entInt
 
@@ -170,8 +168,8 @@
 entArith:
 	SAVE_ALL
 	lda	$8,0x3fff
-	bic	$30,$8,$8
 	lda	$26,ret_from_sys_call
+	bic	$30,$8,$8
 	jsr	$31,do_entArith
 .end entArith
 
@@ -181,8 +179,8 @@
 entIF:
 	SAVE_ALL
 	lda	$8,0x3fff
-	bic	$30,$8,$8
 	lda	$26,ret_from_sys_call
+	bic	$30,$8,$8
 	jsr	$31,do_entIF
 .end entIF
 
@@ -192,8 +190,8 @@
 entDbg:
 	SAVE_ALL
 	lda	$8,0x3fff
-	bic	$30,$8,$8
 	lda	$26,ret_from_sys_call
+	bic	$30,$8,$8
 	jsr	$31,do_entDbg
 .end entDbg
 
@@ -212,18 +210,18 @@
 kernel_clone:
 	.frame $30, 0, $26
 	.prologue 0
-	subq $30,6*8,$30
-	stq $31,0($30)
-	stq $26,8($30)
-	stq $29,16($30)
-	stq $16,24($30)
-	stq $17,32($30)
-	stq $18,40($30)
-	bis $31,2,$0	/* Register v0: syscall nr for fork() */
+	subq	$30,6*8,$30
+	stq	$31,0($30)
+	stq	$26,8($30)
+	stq	$29,16($30)
+	stq	$16,24($30)
+	stq	$17,32($30)
+	stq	$18,40($30)
+	bis	$31,2,$0	/* Register v0: syscall nr for fork() */
 	SAVE_ALL
-	bsr $26,sys_clone
-	stq $0,0($30)
-	br $31,ret_from_sys_call
+	bsr	$26,sys_clone
+	stq	$0,0($30)
+	br	ret_from_sys_call
 .end	kernel_clone
 
 /*
@@ -233,32 +231,32 @@
 .globl	__kernel_thread
 .ent	__kernel_thread
 __kernel_thread:
-	ldgp $29,0($27)		/* we can be called from a module */
+	ldgp	$29,0($27)	/* we can be called from a module */
 	.frame $30, 4*8, $26
-	subq $30,4*8,$30
-	stq $10,16($30)
-	stq $9,8($30)
-	stq $26,0($30)
+	subq	$30,4*8,$30
+	stq	$10,16($30)
+	stq	$9,8($30)
+	stq	$26,0($30)
 	.prologue 1
-	bis $17,$17,$9		/* save fn */
-	bis $18,$18,$10		/* save arg */
-	bsr $26,kernel_clone
-	bne $20,1f		/* $20 is non-zero in child */
-	ldq $26,0($30)
-	ldq $9,8($30)
-	ldq $10,16($30)
-	addq $30,4*8,$30
-	ret $31,($26),1
+	mov	$17,$9		/* save fn */		
+	mov	$18,$10		/* save arg */
+	bsr	$26,kernel_clone
+	bne	$20,1f		/* $20 is non-zero in child */
+	ldq	$26,0($30)
+	ldq	$9,8($30)
+	ldq	$10,16($30)
+	addq	$30,4*8,$30
+	ret	$31,($26),1
 /* this is in child: look out as we don't have any stack here.. */
-1:	bis $9,$9,$27		/* get fn */
-	lda $8,0x3fff
-	bis $10,$10,$16		/* get arg */
-	bic $30,$8,$8		/* get current */
-	jsr $26,($27)
+1:	mov	$9,$27		/* get fn */
+	lda	$8,0x3fff
+	mov	$10,$16		/* get arg */
+	bic	$30,$8,$8	/* get current */
+	jsr	$26,($27)
 	ldgp	$29,0($26)
-	bis $0,$0,$16
-	jsr $26,sys_exit
-	call_pal PAL_halt
+	mov	$0,$16
+	mov	$31,$26
+	jsr	$31,sys_exit
 .end	__kernel_thread
 
 /*
@@ -286,202 +284,199 @@
 .align 3
 .ent	do_switch_stack
 do_switch_stack:
-	lda $30,-SWITCH_STACK_SIZE($30)
-	stq  $9,0($30)
-	stq $10,8($30)
-	stq $11,16($30)
-	stq $12,24($30)
-	stq $13,32($30)
-	stq $14,40($30)
-	stq $15,48($30)
-	stq $26,56($30)
-	stt $f0,64($30)
-	stt $f1,72($30)
-	stt $f2,80($30)
-	stt $f3,88($30)
-	stt $f4,96($30)
-	stt $f5,104($30)
-	stt $f6,112($30)
-	stt $f7,120($30)
-	stt $f8,128($30)
-	stt $f9,136($30)
-	stt $f10,144($30)
-	stt $f11,152($30)
-	stt $f12,160($30)
-	stt $f13,168($30)
-	stt $f14,176($30)
-	stt $f15,184($30)
-	stt $f16,192($30)
-	stt $f17,200($30)
-	stt $f18,208($30)
-	stt $f19,216($30)
-	stt $f20,224($30)
-	stt $f21,232($30)
-	stt $f22,240($30)
-	stt $f23,248($30)
-	stt $f24,256($30)
-	stt $f25,264($30)
-	stt $f26,272($30)
-	stt $f27,280($30)
-	mf_fpcr $f0		# get fpcr
-	stt $f28,288($30)
-	stt $f29,296($30)
-	stt $f30,304($30)
-	stt $f0,312($30)	# save fpcr in slot of $f31
-	ldt $f0,64($30)		# dont let "do_switch_stack" change fp state.
-	ret $31,($1),1
+	lda	$30,-SWITCH_STACK_SIZE($30)
+	stq	$9,0($30)
+	stq	$10,8($30)
+	stq	$11,16($30)
+	stq	$12,24($30)
+	stq	$13,32($30)
+	stq	$14,40($30)
+	stq	$15,48($30)
+	stq	$26,56($30)
+	stt	$f0,64($30)
+	stt	$f1,72($30)
+	stt	$f2,80($30)
+	stt	$f3,88($30)
+	stt	$f4,96($30)
+	stt	$f5,104($30)
+	stt	$f6,112($30)
+	stt	$f7,120($30)
+	stt	$f8,128($30)
+	stt	$f9,136($30)
+	stt	$f10,144($30)
+	stt	$f11,152($30)
+	stt	$f12,160($30)
+	stt	$f13,168($30)
+	stt	$f14,176($30)
+	stt	$f15,184($30)
+	stt	$f16,192($30)
+	stt	$f17,200($30)
+	stt	$f18,208($30)
+	stt	$f19,216($30)
+	stt	$f20,224($30)
+	stt	$f21,232($30)
+	stt	$f22,240($30)
+	stt	$f23,248($30)
+	stt	$f24,256($30)
+	stt	$f25,264($30)
+	stt	$f26,272($30)
+	stt	$f27,280($30)
+	mf_fpcr	$f0		# get fpcr
+	stt	$f28,288($30)
+	stt	$f29,296($30)
+	stt	$f30,304($30)
+	stt	$f0,312($30)	# save fpcr in slot of $f31
+	ldt	$f0,64($30)	# dont let "do_switch_stack" change fp state.
+	ret	$31,($1),1
 .end do_switch_stack
 
 .align 3
 .ent	undo_switch_stack
 undo_switch_stack:
-	ldq  $9,0($30)
-	ldq $10,8($30)
-	ldq $11,16($30)
-	ldq $12,24($30)
-	ldq $13,32($30)
-	ldq $14,40($30)
-	ldq $15,48($30)
-	ldq $26,56($30)
-	ldt $f30,312($30)	# get saved fpcr
-	ldt $f0,64($30)
-	ldt $f1,72($30)
-	ldt $f2,80($30)
-	ldt $f3,88($30)
-	mt_fpcr $f30		# install saved fpcr
-	ldt $f4,96($30)
-	ldt $f5,104($30)
-	ldt $f6,112($30)
-	ldt $f7,120($30)
-	ldt $f8,128($30)
-	ldt $f9,136($30)
-	ldt $f10,144($30)
-	ldt $f11,152($30)
-	ldt $f12,160($30)
-	ldt $f13,168($30)
-	ldt $f14,176($30)
-	ldt $f15,184($30)
-	ldt $f16,192($30)
-	ldt $f17,200($30)
-	ldt $f18,208($30)
-	ldt $f19,216($30)
-	ldt $f20,224($30)
-	ldt $f21,232($30)
-	ldt $f22,240($30)
-	ldt $f23,248($30)
-	ldt $f24,256($30)
-	ldt $f25,264($30)
-	ldt $f26,272($30)
-	ldt $f27,280($30)
-	ldt $f28,288($30)
-	ldt $f29,296($30)
-	ldt $f30,304($30)
-	lda $30,SWITCH_STACK_SIZE($30)
-	ret $31,($1),1
+	ldq	$9,0($30)
+	ldq	$10,8($30)
+	ldq	$11,16($30)
+	ldq	$12,24($30)
+	ldq	$13,32($30)
+	ldq	$14,40($30)
+	ldq	$15,48($30)
+	ldq	$26,56($30)
+	ldt	$f30,312($30)	# get saved fpcr
+	ldt	$f0,64($30)
+	ldt	$f1,72($30)
+	ldt	$f2,80($30)
+	ldt	$f3,88($30)
+	mt_fpcr	$f30		# install saved fpcr
+	ldt	$f4,96($30)
+	ldt	$f5,104($30)
+	ldt	$f6,112($30)
+	ldt	$f7,120($30)
+	ldt	$f8,128($30)
+	ldt	$f9,136($30)
+	ldt	$f10,144($30)
+	ldt	$f11,152($30)
+	ldt	$f12,160($30)
+	ldt	$f13,168($30)
+	ldt	$f14,176($30)
+	ldt	$f15,184($30)
+	ldt	$f16,192($30)
+	ldt	$f17,200($30)
+	ldt	$f18,208($30)
+	ldt	$f19,216($30)
+	ldt	$f20,224($30)
+	ldt	$f21,232($30)
+	ldt	$f22,240($30)
+	ldt	$f23,248($30)
+	ldt	$f24,256($30)
+	ldt	$f25,264($30)
+	ldt	$f26,272($30)
+	ldt	$f27,280($30)
+	ldt	$f28,288($30)
+	ldt	$f29,296($30)
+	ldt	$f30,304($30)
+	lda	$30,SWITCH_STACK_SIZE($30)
+	ret	$31,($1),1
 .end undo_switch_stack
 
 .align 3
 .globl	entUna
 .ent	entUna
 entUna:
-	lda $30,-256($30)
-	stq $0,0($30)
-	ldq $0,256($30)		/* get PS */
-	stq $1,8($30)
-	stq $2,16($30)
-	stq $3,24($30)
-	and $0,8,$0		/* user mode? */
-	stq $4,32($30)
-	bne $0,entUnaUser	/* yup -> do user-level unaligned fault */
-	stq $5,40($30)
-	stq $6,48($30)
-	stq $7,56($30)
-	stq $8,64($30)
-	stq $9,72($30)
-	stq $10,80($30)
-	stq $11,88($30)
-	stq $12,96($30)
-	stq $13,104($30)
-	stq $14,112($30)
-	stq $15,120($30)
+	lda	$30,-256($30)
+	stq	$0,0($30)
+	ldq	$0,256($30)	/* get PS */
+	stq	$1,8($30)
+	stq	$2,16($30)
+	stq	$3,24($30)
+	and	$0,8,$0		/* user mode? */
+	stq	$4,32($30)
+	bne	$0,entUnaUser	/* yup -> do user-level unaligned fault */
+	stq	$5,40($30)
+	stq	$6,48($30)
+	stq	$7,56($30)
+	stq	$8,64($30)
+	stq	$9,72($30)
+	stq	$10,80($30)
+	stq	$11,88($30)
+	stq	$12,96($30)
+	stq	$13,104($30)
+	stq	$14,112($30)
+	stq	$15,120($30)
 	/* 16-18 PAL-saved */
-	stq $19,152($30)
-	stq $20,160($30)
-	stq $21,168($30)
-	stq $22,176($30)
-	stq $23,184($30)
-	stq $24,192($30)
-	stq $25,200($30)
-	stq $26,208($30)
-	stq $27,216($30)
-	stq $28,224($30)
-	stq $29,232($30)
-	stq $30,240($30)
-	stq $31,248($30)
-	lda $8,0x3fff
-	bic $30,$8,$8
-	jsr $26,do_entUna
-	ldq $0,0($30)
-	ldq $1,8($30)
-	ldq $2,16($30)
-	ldq $3,24($30)
-	ldq $4,32($30)
-	ldq $5,40($30)
-	ldq $6,48($30)
-	ldq $7,56($30)
-	ldq $8,64($30)
-	ldq $9,72($30)
-	ldq $10,80($30)
-	ldq $11,88($30)
-	ldq $12,96($30)
-	ldq $13,104($30)
-	ldq $14,112($30)
-	ldq $15,120($30)
+	stq	$19,152($30)
+	stq	$20,160($30)
+	stq	$21,168($30)
+	stq	$22,176($30)
+	stq	$23,184($30)
+	stq	$24,192($30)
+	stq	$25,200($30)
+	stq	$26,208($30)
+	stq	$27,216($30)
+	stq	$28,224($30)
+	stq	$29,232($30)
+	lda	$8,0x3fff
+	stq	$31,248($30)
+	bic	$30,$8,$8
+	jsr	$26,do_entUna
+	ldq	$0,0($30)
+	ldq	$1,8($30)
+	ldq	$2,16($30)
+	ldq	$3,24($30)
+	ldq	$4,32($30)
+	ldq	$5,40($30)
+	ldq	$6,48($30)
+	ldq	$7,56($30)
+	ldq	$8,64($30)
+	ldq	$9,72($30)
+	ldq	$10,80($30)
+	ldq	$11,88($30)
+	ldq	$12,96($30)
+	ldq	$13,104($30)
+	ldq	$14,112($30)
+	ldq	$15,120($30)
 	/* 16-18 PAL-saved */
-	ldq $19,152($30)
-	ldq $20,160($30)
-	ldq $21,168($30)
-	ldq $22,176($30)
-	ldq $23,184($30)
-	ldq $24,192($30)
-	ldq $25,200($30)
-	ldq $26,208($30)
-	ldq $27,216($30)
-	ldq $28,224($30)
-	ldq $29,232($30)
-	ldq $30,240($30)
-	lda $30,256($30)
-	rti
+	ldq	$19,152($30)
+	ldq	$20,160($30)
+	ldq	$21,168($30)
+	ldq	$22,176($30)
+	ldq	$23,184($30)
+	ldq	$24,192($30)
+	ldq	$25,200($30)
+	ldq	$26,208($30)
+	ldq	$27,216($30)
+	ldq	$28,224($30)
+	ldq	$29,232($30)
+	lda	$30,256($30)
+	call_pal PAL_rti
 .end entUna
 
 .align 3
 .ent	entUnaUser
 entUnaUser:
-	ldq $0,0($30)			/* restore original $0 */
-	lda $30,256($30)		/* pop entUna's stack frame */
-	SAVE_ALL			/* setup normal kernel stack */
-	lda $30,-56($30)
-	stq $9,0($30)
-	stq $10,8($30)
-	stq $11,16($30)
-	stq $12,24($30)
-	stq $13,32($30)
-	stq $14,40($30)
-	stq $15,48($30)
-	lda $8,0x3fff
-	addq $30,56,$19
-	bic $30,$8,$8
-	jsr $26,do_entUnaUser
-	ldq $9,0($30)
-	ldq $10,8($30)
-	ldq $11,16($30)
-	ldq $12,24($30)
-	ldq $13,32($30)
-	ldq $14,40($30)
-	ldq $15,48($30)
-	lda $30,56($30)
-	br $31,ret_from_sys_call
-
+	ldq	$0,0($30)	/* restore original $0 */
+	lda	$30,256($30)	/* pop entUna's stack frame */
+	SAVE_ALL		/* setup normal kernel stack */
+	lda	$30,-56($30)
+	stq	$9,0($30)
+	stq	$10,8($30)
+	stq	$11,16($30)
+	stq	$12,24($30)
+	stq	$13,32($30)
+	stq	$14,40($30)
+	stq	$15,48($30)
+	lda	$8,0x3fff
+	addq	$30,56,$19
+	bic	$30,$8,$8
+	jsr	$26,do_entUnaUser
+	ldq	$9,0($30)
+	ldq	$10,8($30)
+	ldq	$11,16($30)
+	ldq	$12,24($30)
+	ldq	$13,32($30)
+	ldq	$14,40($30)
+	ldq	$15,48($30)
+	lda	$30,56($30)
+	br	ret_from_sys_call
 .end	entUnaUser
 
 /*
@@ -491,36 +486,36 @@
 .globl	sys_fork
 .ent	sys_fork
 sys_fork:
-	bsr $1,do_switch_stack
-	bis $31,SIGCHLD,$16
-	bis $31,$31,$17
-	bis $30,$30,$18
-	jsr $26,alpha_clone
-	bsr $1,undo_switch_stack
-	ret $31,($26),1
+	bsr	$1,do_switch_stack
+	bis	$31,SIGCHLD,$16
+	mov	$31,$17
+	mov	$30,$18
+	jsr	$26,alpha_clone
+	bsr	$1,undo_switch_stack
+	ret	$31,($26),1
 .end	sys_fork
 
 .align 3
 .globl	sys_clone
 .ent	sys_clone
 sys_clone:
-	bsr $1,do_switch_stack
+	bsr	$1,do_switch_stack
 	/* arg1 and arg2 come from the user */
-	bis $30,$30,$18
-	jsr $26,alpha_clone
-	bsr $1,undo_switch_stack
-	ret $31,($26),1
+	mov	$30,$18
+	jsr	$26,alpha_clone
+	bsr	$1,undo_switch_stack
+	ret	$31,($26),1
 .end	sys_clone
 
 .align 3
 .globl	sys_vfork
 .ent	sys_vfork
 sys_vfork:
-	bsr $1,do_switch_stack
-	bis $30,$30,$16
-	jsr $26,alpha_vfork
-	bsr $1,undo_switch_stack
-	ret $31,($26),1
+	bsr	$1,do_switch_stack
+	mov	$30,$16
+	jsr	$26,alpha_vfork
+	bsr	$1,undo_switch_stack
+	ret	$31,($26),1
 .end	sys_vfork
 
 .align 3
@@ -528,12 +523,12 @@
 .ent    alpha_switch_to
 alpha_switch_to:
 	.prologue 0
-	bsr $1,do_switch_stack
+	bsr	$1,do_switch_stack
 	call_pal PAL_swpctx
-	lda $16,-2($31)
-	call_pal PAL_tbi
-	bsr $1,undo_switch_stack
-	ret $31,($26),1
+	unop
+	bsr	$1,undo_switch_stack
+	mov	$17,$0
+	ret	$31,($26),1
 .end alpha_switch_to
 
 /*
@@ -592,7 +587,7 @@
 	bne	$5,signal_return
 restore_all:
 	RESTORE_ALL
-	rti
+	call_pal PAL_rti
 
 
 /* PTRACE syscall handler */
@@ -620,7 +615,7 @@
 	s8addq	$0,$2,$2
 	beq	$1,1f
 	ldq	$27,0($2)
-1:	jsr	$26,($27),alpha_ni_syscall
+1:	jsr	$26,($27),sys_gettimeofday
 	ldgp	$29,0($26)
 
 	/* check return.. */
@@ -646,15 +641,15 @@
 	stq	$1,72($30)	/* a3 for return */
 
 	bsr	$1,do_switch_stack
-	bis	$19,$19,$9	/* save old syscall number */
-	bis	$20,$20,$10	/* save old a3 */
+	mov	$19,$9		/* save old syscall number */
+	mov	$20,$10		/* save old a3 */
 	jsr     $26,syscall_trace
-	bis	$9,$9,$19
-	bis	$10,$10,$20
+	mov	$9,$19
+	mov	$10,$20
 	bsr	$1,undo_switch_stack
 
-	bis	$31,$31,$26	/* tell "ret_from_sys_call" that we can restart */
-	br	$31,ret_from_sys_call
+	mov	$31,$26		/* tell "ret_from_sys_call" we can restart */
+	br	ret_from_sys_call
 
 	.align 3
 handle_bottom_half:
@@ -665,7 +660,7 @@
 	ldq	$19,0($30)
 	ldq	$20,8($30)
 	addq	$30,16,$30
-	br	$31,ret_from_handle_bh
+	br	ret_from_handle_bh
 
 	.align 3
 syscall_error:
@@ -683,38 +678,35 @@
 	subq	$31,$0,$0	/* with error in v0 */
 	addq	$31,1,$1	/* set a3 for errno return */
 	stq	$0,0($30)
-	bis	$31,$31,$26	/* tell "ret_from_sys_call" we can restart */
+	mov	$31,$26		/* tell "ret_from_sys_call" we can restart */
 	stq	$1,72($30)	/* a3 for return */
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 
 ret_success:
 	stq	$0,0($30)
 	stq	$31,72($30)	/* a3=0 => no error */
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 
 .align 3
 signal_return:
-	bis	$30,$30,$17
+	mov	$30,$17
 	br	$1,do_switch_stack
-	bis	$30,$30,$18
-	bis	$31,$31,$16
+	mov	$30,$18
+	mov	$31,$16
 	jsr	$26,do_signal
 	bsr	$1,undo_switch_stack
-	br	$31,restore_all
+	br	restore_all
 .end entSys
 
 #ifdef __SMP__
-        .globl  ret_from_smpfork
+        .globl  ret_from_smp_fork
 .align 3
-.ent ret_from_smpfork
-ret_from_smpfork:
-	.set at
-	mb	/* Make the changed data visible before the freed lock. */
-	stq	$31,scheduler_lock	
+.ent ret_from_smp_fork
+ret_from_smp_fork:
 	lda	$26,ret_from_sys_call
+	mov	$17,$16
 	jsr	$31,schedule_tail
-	.set noat
-.end ret_from_smpfork
+.end ret_from_smp_fork
 #endif /* __SMP__ */
 
 .align 3
@@ -727,51 +719,51 @@
 	ldq	$19,0($30)
 	ldq	$20,8($30)
 	addq	$30,16,$30
-	br	$31,ret_from_reschedule
+	br	ret_from_reschedule
 .end reschedule
 
 .align 3
 .ent sys_sigreturn
 sys_sigreturn:
-	bis	$30,$30,$17
+	mov	$30,$17
+	lda	$18,-SWITCH_STACK_SIZE($30)
 	lda	$30,-SWITCH_STACK_SIZE($30)
-	bis	$30,$30,$18
 	jsr	$26,do_sigreturn
 	br	$1,undo_switch_stack
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 .end sys_sigreturn
 
 .align 3
 .ent sys_rt_sigreturn
 sys_rt_sigreturn:
-	bis	$30,$30,$17
+	mov	$30,$17
+	lda	$18,-SWITCH_STACK_SIZE($30)
 	lda	$30,-SWITCH_STACK_SIZE($30)
-	bis	$30,$30,$18
 	jsr	$26,do_rt_sigreturn
 	br	$1,undo_switch_stack
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 .end sys_rt_sigreturn
 
 .align 3
 .ent sys_sigsuspend
 sys_sigsuspend:
-	bis	$30,$30,$17
+	mov	$30,$17
 	br	$1,do_switch_stack
-	bis	$30,$30,$18
+	mov	$30,$18
 	jsr	$26,do_sigsuspend
 	lda	$30,SWITCH_STACK_SIZE($30)
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 .end sys_sigsuspend
 
 .align 3
 .ent sys_rt_sigsuspend
 sys_rt_sigsuspend:
-	bis	$30,$30,$18
+	mov	$30,$18
 	br	$1,do_switch_stack
-	bis	$30,$30,$19
+	mov	$30,$19
 	jsr	$26,do_rt_sigsuspend
 	lda	$30,SWITCH_STACK_SIZE($30)
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 .end sys_rt_sigsuspend
 
 	.data
diff -urN linux-2.2.8-pre5/arch/alpha/kernel/osf_sys.c linux-2.2.8-pre6/arch/alpha/kernel/osf_sys.c
--- linux-2.2.8-pre5/arch/alpha/kernel/osf_sys.c	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/arch/alpha/kernel/osf_sys.c	2003-08-15 15:06:14.000000000 -0700
@@ -885,7 +885,21 @@
 	case GSI_IEEE_FP_CONTROL:
 		/* Return current software fp control & status bits.  */
 		/* Note that DU doesn't verify available space here.  */
-		w = current->tss.flags & IEEE_SW_MASK;
+
+		/* EV6 implements most of the bits in hardware.  If
+		   UNDZ is not set, UNFD is maintained in software.  */
+		if (implver() == IMPLVER_EV6) {
+			unsigned long fpcr = rdfpcr();
+			w = ieee_fpcr_to_swcr(fpcr);
+			if (!(fpcr & FPCR_UNDZ)) {
+				w &= ~IEEE_TRAP_ENABLE_UNF;
+				w |= current->tss.flags & IEEE_TRAP_ENABLE_UNF;
+			}
+		} else {
+			/* Otherwise we are forced to do everything in sw.  */
+			w = current->tss.flags & IEEE_SW_MASK;
+		}
+
 		if (put_user(w, (unsigned long *) buffer))
 			return -EFAULT;
 		return 0;
@@ -935,7 +949,7 @@
 {
 	switch (op) {
 	case SSI_IEEE_FP_CONTROL: {
-		unsigned long swcr, fpcr;
+		unsigned long swcr, fpcr, undz;
 
 		/* 
 		 * Alpha Architecture Handbook 4.7.7.3:
@@ -950,11 +964,12 @@
 		current->tss.flags &= ~IEEE_SW_MASK;
 		current->tss.flags |= swcr & IEEE_SW_MASK;
 
-		/* Update the real fpcr.  For exceptions that are disabled in
-		   software but have not been seen, enable the exception in
-		   hardware so that we can update our software status mask.  */
-		fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
-		fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
+		/* Update the real fpcr.  Keep UNFD off if not UNDZ.  */
+		fpcr = rdfpcr();
+		undz = (fpcr & FPCR_UNDZ);
+		fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ);
+		fpcr |= ieee_swcr_to_fpcr(swcr);
+		fpcr &= ~(undz << 1);
 		wrfpcr(fpcr);
 		   
 		return 0;
diff -urN linux-2.2.8-pre5/arch/alpha/kernel/process.c linux-2.2.8-pre6/arch/alpha/kernel/process.c
--- linux-2.2.8-pre5/arch/alpha/kernel/process.c	1999-01-20 11:08:43.000000000 -0800
+++ linux-2.2.8-pre6/arch/alpha/kernel/process.c	2003-08-15 15:06:14.000000000 -0700
@@ -237,10 +237,13 @@
 
 void flush_thread(void)
 {
-	/* Arrange for each exec'ed process to start off with a 
-	   clean slate with respect to the FPU.  */
+	/* Arrange for each exec'ed process to start off with a clean slate
+	   with respect to the FPU.  This is all exceptions disabled.  Note
+           that EV6 defines UNFD valid only with UNDZ, which we don't want
+	   for IEEE conformance -- so that disabled bit remains in software.  */
+
 	current->tss.flags &= ~IEEE_SW_MASK;
-	wrfpcr(FPCR_DYN_NORMAL);
+	wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED);
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -270,8 +273,6 @@
 			(struct pt_regs *) (swstack+1));
 }
 
-extern void ret_from_sys_call(void);
-extern void ret_from_smpfork(void);
 /*
  * Copy an alpha thread..
  *
@@ -282,9 +283,13 @@
  * Use the passed "regs" pointer to determine how much space we need
  * for a kernel fork().
  */
+
 int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	struct task_struct * p, struct pt_regs * regs)
 {
+	extern void ret_from_sys_call(void);
+	extern void ret_from_smp_fork(void);
+
 	struct pt_regs * childregs;
 	struct switch_stack * childstack, *stack;
 	unsigned long stack_offset;
@@ -292,18 +297,18 @@
 	stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
 	if (!(regs->ps & 8))
 		stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
-	childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p);
+	childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (long)p);
 		
 	*childregs = *regs;
 	childregs->r0 = 0;
 	childregs->r19 = 0;
-	childregs->r20 = 1;	/* OSF/1 has some strange fork() semantics.. */
+	childregs->r20 = 1;	/* OSF/1 has some strange fork() semantics.  */
 	regs->r20 = 0;
 	stack = ((struct switch_stack *) regs) - 1;
 	childstack = ((struct switch_stack *) childregs) - 1;
 	*childstack = *stack;
 #ifdef __SMP__
-	childstack->r26 = (unsigned long) ret_from_smpfork;
+	childstack->r26 = (unsigned long) ret_from_smp_fork;
 #else
 	childstack->r26 = (unsigned long) ret_from_sys_call;
 #endif
@@ -328,10 +333,12 @@
 	dump->start_code  = current->mm->start_code;
 	dump->start_data  = current->mm->start_data;
 	dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
-	dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
-	dump->u_dsize = (current->mm->brk + (PAGE_SIZE - 1) - dump->start_data) >> PAGE_SHIFT;
-	dump->u_ssize =
-	  (current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	dump->u_tsize = ((current->mm->end_code - dump->start_code)
+			 >> PAGE_SHIFT);
+	dump->u_dsize = ((current->mm->brk + PAGE_SIZE-1 - dump->start_data)
+			 >> PAGE_SHIFT);
+	dump->u_ssize = (current->mm->start_stack - dump->start_stack
+			 + PAGE_SIZE-1) >> PAGE_SHIFT;
 
 	/*
 	 * We store the registers in an order/format that is
diff -urN linux-2.2.8-pre5/arch/alpha/kernel/smp.c linux-2.2.8-pre6/arch/alpha/kernel/smp.c
--- linux-2.2.8-pre5/arch/alpha/kernel/smp.c	1999-03-28 22:36:32.000000000 -0800
+++ linux-2.2.8-pre6/arch/alpha/kernel/smp.c	2003-08-15 15:06:14.000000000 -0700
@@ -37,7 +37,18 @@
 #define DBGS(args)
 #endif
 
-struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
+struct ipi_msg_flush_tb_struct {
+	volatile unsigned int flush_tb_mask;
+	union {
+		struct mm_struct *	flush_mm;
+		struct vm_area_struct *	flush_vma;
+	} p;
+	unsigned long flush_addr;
+	unsigned long flush_end;
+};
+
+static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
+static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED;
 
 struct cpuinfo_alpha cpu_data[NR_CPUS];
 
@@ -786,7 +797,7 @@
 	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
 	long timeout = 1000000;
 
-	spin_lock_own(&kernel_flag, "flush_tlb_all");
+	spin_lock(&flush_tb_lock);
 
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	send_ipi_message(to_whom, IPI_TLB_ALL);
@@ -803,6 +814,8 @@
 		       ipi_msg_flush_tb.flush_tb_mask);
 		ipi_msg_flush_tb.flush_tb_mask = 0;
 	}
+
+	spin_unlock(&flush_tb_lock);
 }
 
 void
@@ -811,7 +824,7 @@
 	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
 	long timeout = 1000000;
 
-	spin_lock_own(&kernel_flag, "flush_tlb_mm");
+	spin_lock(&flush_tb_lock);
 
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	ipi_msg_flush_tb.p.flush_mm = mm;
@@ -833,6 +846,8 @@
 		       ipi_msg_flush_tb.flush_tb_mask);
 		ipi_msg_flush_tb.flush_tb_mask = 0;
 	}
+
+	spin_unlock(&flush_tb_lock);
 }
 
 void
@@ -843,7 +858,7 @@
 	struct mm_struct * mm = vma->vm_mm;
 	int timeout = 1000000;
 
-	spin_lock_own(&kernel_flag, "flush_tlb_page");
+	spin_lock(&flush_tb_lock);
 
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	ipi_msg_flush_tb.p.flush_vma = vma;
@@ -866,6 +881,8 @@
 		       ipi_msg_flush_tb.flush_tb_mask);
 		ipi_msg_flush_tb.flush_tb_mask = 0;
 	}
+
+	spin_unlock(&flush_tb_lock);
 }
 
 void
diff -urN linux-2.2.8-pre5/arch/alpha/kernel/traps.c linux-2.2.8-pre6/arch/alpha/kernel/traps.c
--- linux-2.2.8-pre5/arch/alpha/kernel/traps.c	1999-02-01 10:41:47.000000000 -0800
+++ linux-2.2.8-pre6/arch/alpha/kernel/traps.c	2003-08-15 15:06:14.000000000 -0700
@@ -125,13 +125,16 @@
 	    unsigned long a2, unsigned long a3, unsigned long a4,
 	    unsigned long a5, struct pt_regs regs)
 {
-	if ((summary & 1)) {
-		/*
-		 * Software-completion summary bit is set, so try to
-		 * emulate the instruction.
-		 */
-		if (alpha_fp_emul_imprecise(&regs, write_mask)) {
-			return;		/* emulation was successful */
+	if (summary & 1) {
+		/* Software-completion summary bit is set, so try to
+		   emulate the instruction.  */
+		if (implver() == IMPLVER_EV6) {
+			/* Whee!  EV6 has precice exceptions.  */
+			if (alpha_fp_emul(regs.pc - 4))
+				return;
+		} else {
+			if (alpha_fp_emul_imprecise(&regs, write_mask))
+				return;
 		}
 	}
 
@@ -141,7 +144,7 @@
 		current->comm, regs.pc, summary, write_mask);
 #endif
 	die_if_kernel("Arithmetic fault", &regs, 0, 0);
-	force_sig(SIGFPE, current);
+	send_sig(SIGFPE, current, 1);
 	unlock_kernel();
 }
 
@@ -150,14 +153,17 @@
 	 unsigned long a2, unsigned long a3, unsigned long a4,
 	 unsigned long a5, struct pt_regs regs)
 {
-	lock_kernel();
 	die_if_kernel("Instruction fault", &regs, type, 0);
 	switch (type) {
 	      case 0: /* breakpoint */
 		if (ptrace_cancel_bpt(current)) {
 			regs.pc -= 4;	/* make pc point to former bpt */
 		}
-		force_sig(SIGTRAP, current);
+		send_sig(SIGTRAP, current, 1);
+		break;
+
+	      case 1: /* bugcheck */
+		send_sig(SIGTRAP, current, 1);
 		break;
 
 	      case 2: /* gentrap */
@@ -171,14 +177,13 @@
 		switch ((long) regs.r16) {
 		      case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
 		      case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
-		      case GEN_FLTINE:
-			force_sig(SIGFPE, current);
+		      case GEN_FLTINE: case GEN_ROPRAND:
+			send_sig(SIGFPE, current, 1);
 			break;
 
 		      case GEN_DECOVF:
 		      case GEN_DECDIV:
 		      case GEN_DECINV:
-		      case GEN_ROPRAND:
 		      case GEN_ASSERTERR:
 		      case GEN_NULPTRERR:
 		      case GEN_STKOVF:
@@ -193,42 +198,29 @@
 		      case GEN_SUBRNG5:
 		      case GEN_SUBRNG6:
 		      case GEN_SUBRNG7:
-			force_sig(SIGILL, current);
+			send_sig(SIGTRAP, current, 1);
 			break;
 		}
 		break;
 
-	      case 1: /* bugcheck */
 	      case 3: /* FEN fault */
-		force_sig(SIGILL, current);
+		send_sig(SIGILL, current, 1);
 		break;
 
 	      case 4: /* opDEC */
-#ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION
-		{
-			unsigned int opcode;
-
-			/* get opcode of faulting instruction: */
-			get_user(opcode, (__u32*)(regs.pc - 4));
-			opcode >>= 26;
-			if (opcode == 0x16) {
-				/*
-				 * It's a FLTI instruction, emulate it
-				 * (we don't do no stinkin' VAX fp...)
-				 */
-				if (!alpha_fp_emul(regs.pc - 4))
-					force_sig(SIGFPE, current);
-				break;
-			}
+		if (implver() == IMPLVER_EV4) {
+			/* EV4 does not implement anything except normal
+			   rounding.  Everything else will come here as
+			   an illegal instruction.  Emulate them.  */
+			if (alpha_fp_emul(regs.pc - 4))
+				return;
 		}
-#endif
-		force_sig(SIGILL, current);
+		send_sig(SIGILL, current, 1);
 		break;
 
 	      default:
 		panic("do_entIF: unexpected instruction-fault type");
 	}
-	unlock_kernel();
 }
 
 /* There is an ifdef in the PALcode in MILO that enables a 
@@ -877,14 +869,14 @@
 give_sigsegv:
 	regs->pc -= 4;  /* make pc point to faulting insn */
 	lock_kernel();
-	force_sig(SIGSEGV, current);
+	send_sig(SIGSEGV, current, 1);
 	unlock_kernel();
 	return;
 
 give_sigbus:
 	regs->pc -= 4;
 	lock_kernel();
-	force_sig(SIGBUS, current);
+	send_sig(SIGBUS, current, 1);
 	unlock_kernel();
 	return;
 }
diff -urN linux-2.2.8-pre5/arch/alpha/math-emu/fp-emul.c linux-2.2.8-pre6/arch/alpha/math-emu/fp-emul.c
--- linux-2.2.8-pre5/arch/alpha/math-emu/fp-emul.c	1998-08-09 12:09:06.000000000 -0700
+++ linux-2.2.8-pre6/arch/alpha/math-emu/fp-emul.c	2003-08-15 15:06:14.000000000 -0700
@@ -13,6 +13,7 @@
 #define OPC_INTL	0x11
 #define OPC_INTS	0x12
 #define OPC_INTM	0x13
+#define OPC_FLTC	0x14
 #define OPC_FLTV	0x15
 #define OPC_FLTI	0x16
 #define OPC_FLTL	0x17
@@ -21,33 +22,37 @@
 
 #define	OPC_JSR		0x1a
 
+#define OP_FUN(OP,FUN)	((OP << 26) | (FUN << 5))
+
 /*
- * "Base" function codes for the FLTI-class instructions.  These
- * instructions all have opcode 0x16.  Note that in most cases these
- * actually correspond to the "chopped" form of the instruction.  Not
- * to worry---we extract the qualifier bits separately and deal with
- * them separately.  Notice that base function code 0x2c is used for
- * both CVTTS and CVTST.  The other bits in the function code are used
- * to distinguish the two.
+ * "Base" function codes for the FLTI-class instructions.
+ * Note that in most cases these actually correspond to the "chopped"
+ * form of the instruction.  Not to worry---we extract the qualifier
+ * bits separately and deal with them separately.  Notice that base
+ * function code 0x2c is used for both CVTTS and CVTST.  The other bits
+ * in the function code are used to distinguish the two.
  */
-#define FLTI_FUNC_ADDS			0x000
-#define FLTI_FUNC_ADDT			0x020
-#define FLTI_FUNC_CMPTEQ		0x025
-#define FLTI_FUNC_CMPTLT		0x026
-#define FLTI_FUNC_CMPTLE		0x027
-#define FLTI_FUNC_CMPTUN		0x024
-#define FLTI_FUNC_CVTTS_or_CVTST	0x02c
-#define FLTI_FUNC_CVTTQ			0x02f
-#define FLTI_FUNC_CVTQS			0x03c
-#define FLTI_FUNC_CVTQT			0x03e
-#define FLTI_FUNC_DIVS			0x003
-#define FLTI_FUNC_DIVT			0x023
-#define FLTI_FUNC_MULS			0x002
-#define FLTI_FUNC_MULT			0x022
-#define FLTI_FUNC_SUBS			0x001
-#define FLTI_FUNC_SUBT			0x021
+#define FLTI_FUNC_ADDS			OP_FUN(OPC_FLTI, 0x000)
+#define FLTI_FUNC_ADDT			OP_FUN(OPC_FLTI, 0x020)
+#define FLTI_FUNC_CMPTEQ		OP_FUN(OPC_FLTI, 0x025)
+#define FLTI_FUNC_CMPTLT		OP_FUN(OPC_FLTI, 0x026)
+#define FLTI_FUNC_CMPTLE		OP_FUN(OPC_FLTI, 0x027)
+#define FLTI_FUNC_CMPTUN		OP_FUN(OPC_FLTI, 0x024)
+#define FLTI_FUNC_CVTTS_or_CVTST	OP_FUN(OPC_FLTI, 0x02c)
+#define FLTI_FUNC_CVTTQ			OP_FUN(OPC_FLTI, 0x02f)
+#define FLTI_FUNC_CVTQS			OP_FUN(OPC_FLTI, 0x03c)
+#define FLTI_FUNC_CVTQT			OP_FUN(OPC_FLTI, 0x03e)
+#define FLTI_FUNC_DIVS			OP_FUN(OPC_FLTI, 0x003)
+#define FLTI_FUNC_DIVT			OP_FUN(OPC_FLTI, 0x023)
+#define FLTI_FUNC_MULS			OP_FUN(OPC_FLTI, 0x002)
+#define FLTI_FUNC_MULT			OP_FUN(OPC_FLTI, 0x022)
+#define FLTI_FUNC_SUBS			OP_FUN(OPC_FLTI, 0x001)
+#define FLTI_FUNC_SUBT			OP_FUN(OPC_FLTI, 0x021)
+
+#define FLTC_FUNC_SQRTS			OP_FUN(OPC_FLTC, 0x00B)
+#define FLTC_FUNC_SQRTT			OP_FUN(OPC_FLTC, 0x02B)
 
-#define FLTI_FUNC_CVTQL			0x030	/* opcode 0x17 */
+#define FLTL_FUNC_CVTQL			OP_FUN(OPC_FLTL, 0x030)
 
 #define MISC_TRAPB	0x0000
 #define MISC_EXCB	0x0400
@@ -101,7 +106,7 @@
 long
 alpha_fp_emul (unsigned long pc)
 {
-	unsigned long opcode, fa, fb, fc, func, mode;
+	unsigned long op_fun, fa, fb, fc, func, mode;
 	unsigned long fpcw = current->tss.flags;
 	unsigned long va, vb, vc, res, fpcr;
 	__u32 insn;
@@ -110,10 +115,11 @@
 
 	get_user(insn, (__u32*)pc);
 	fc     = (insn >>  0) &  0x1f;	/* destination register */
-	func   = (insn >>  5) & 0x7ff;
 	fb     = (insn >> 16) &  0x1f;
 	fa     = (insn >> 21) &  0x1f;
-	opcode = insn >> 26;
+	func   = (insn >>  5) & 0x7ff;
+	mode   = (insn >>  5) & 0xc0;
+	op_fun = insn & OP_FUN(0x3f, 0x3f);
 	
 	va = alpha_read_fp_reg(fa);
 	vb = alpha_read_fp_reg(fb);
@@ -123,7 +129,6 @@
 	 * Try the operation in software.  First, obtain the rounding
 	 * mode...
 	 */
-	mode = func & 0xc0;
 	if (mode == 0xc0) {
 	    /* dynamic---get rounding mode from fpcr: */
 	    mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT;
@@ -135,8 +140,7 @@
 		something_is_wrong();
 	}
 
-	/* least 6 bits contain operation code: */
-	switch (func & 0x3f) {
+	switch (op_fun) {
 	      case FLTI_FUNC_CMPTEQ:
 		res = ieee_CMPTEQ(va, vb, &vc);
 		break;
@@ -153,7 +157,7 @@
 		res = ieee_CMPTUN(va, vb, &vc);
 		break;
 
-	      case FLTI_FUNC_CVTQL:
+	      case FLTL_FUNC_CVTQL:
 		/*
 		 * Notice: We can get here only due to an integer
 		 * overflow.  Such overflows are reported as invalid
@@ -222,6 +226,14 @@
 		res = ieee_CVTTQ(mode, vb, &vc);
 		break;
 
+	      case FLTC_FUNC_SQRTS:
+		res = ieee_SQRTS(mode, vb, &vc);
+		break;
+
+	      case FLTC_FUNC_SQRTT:
+		res = ieee_SQRTT(mode, vb, &vc);
+		break;
+
 	      default:
 		printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n",
 		       func & 0x3f, pc);
@@ -247,7 +259,7 @@
 
 		/* Update hardware control register */
 		fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
-		fpcr |= ieee_swcr_to_fpcr(fpcw | (~fpcw&IEEE_STATUS_MASK)>>16);
+		fpcr |= ieee_swcr_to_fpcr(fpcw);
 		wrfpcr(fpcr);
 
 		/* Do we generate a signal?  */
@@ -319,6 +331,7 @@
 			write_mask &= ~(1UL << rc);
 			break;
 
+		      case OPC_FLTC:
 		      case OPC_FLTV:
 		      case OPC_FLTI:
 		      case OPC_FLTL:
@@ -326,13 +339,11 @@
 			break;
 		}
 		if (!write_mask) {
-			if ((opcode == OPC_FLTI || opcode == OPC_FLTL)
-			    && alpha_fp_emul(trigger_pc))
-			{
-			    /* re-execute insns in trap-shadow: */
-			    regs->pc = trigger_pc + 4;
-			    MOD_DEC_USE_COUNT;
-			    return 1;
+			if (alpha_fp_emul(trigger_pc)) {
+				/* re-execute insns in trap-shadow: */
+				regs->pc = trigger_pc + 4;
+				MOD_DEC_USE_COUNT;
+				return 1;
 			}
 			break;
 		}
diff -urN linux-2.2.8-pre5/arch/alpha/math-emu/ieee-math.c linux-2.2.8-pre6/arch/alpha/math-emu/ieee-math.c
--- linux-2.2.8-pre5/arch/alpha/math-emu/ieee-math.c	1998-09-06 10:34:33.000000000 -0700
+++ linux-2.2.8-pre6/arch/alpha/math-emu/ieee-math.c	2003-08-15 15:06:14.000000000 -0700
@@ -22,6 +22,7 @@
  * functions are used on exceptional numbers only (well, assuming you
  * don't turn on the "trap on inexact"...).
  */
+#include <linux/sched.h>
 #include "ieee-math.h"
 
 #define STICKY_S	0x20000000	/* both in longword 0 of fraction */
@@ -1340,3 +1341,41 @@
 	op_c.e -= 9;		/* remove excess exp from original shift */
 	return round_t_ieee(f, &op_c, c);
 }
+
+/*
+ * Sqrt a = b, where a and b are ieee s-floating numbers.  "f"
+ * contains the rounding mode etc.
+ */
+unsigned long
+ieee_SQRTS (int f, unsigned long a, unsigned long *b)
+{
+	fpclass_t a_type;
+	EXTENDED op_a, op_b;
+
+	*b = IEEE_QNaN;
+	a_type = extend_ieee(a, &op_a, SINGLE);
+	if (op_a.s == 0) {
+		/* FIXME -- handle positive denormals.  */
+		send_sig(SIGFPE, current, 1);
+	}
+	return FPCR_INV;
+}
+
+/*
+ * Sqrt a = b, where a and b are ieee t-floating numbers.  "f"
+ * contains the rounding mode etc.
+ */
+unsigned long
+ieee_SQRTT (int f, unsigned long a, unsigned long *b)
+{
+	fpclass_t a_type;
+	EXTENDED op_a, op_b;
+
+	*b = IEEE_QNaN;
+	a_type = extend_ieee(a, &op_a, DOUBLE);
+	if (op_a.s == 0) {
+		/* FIXME -- handle positive denormals.  */
+		send_sig(SIGFPE, current, 1);
+	}
+	return FPCR_INV;
+}
diff -urN linux-2.2.8-pre5/arch/alpha/math-emu/ieee-math.h linux-2.2.8-pre6/arch/alpha/math-emu/ieee-math.h
--- linux-2.2.8-pre5/arch/alpha/math-emu/ieee-math.h	1995-12-21 22:22:05.000000000 -0800
+++ linux-2.2.8-pre6/arch/alpha/math-emu/ieee-math.h	2003-08-15 15:06:14.000000000 -0700
@@ -48,5 +48,7 @@
 				unsigned long *c);
 extern unsigned long ieee_DIVT (int rm, unsigned long a, unsigned long b,
 				unsigned long *c);
+extern unsigned long ieee_SQRTS (int rm, unsigned long a, unsigned long *b);
+extern unsigned long ieee_SQRTT (int rm, unsigned long a, unsigned long *b);
 
 #endif /* __ieee_math_h__ */
diff -urN linux-2.2.8-pre5/arch/i386/kernel/i386_ksyms.c linux-2.2.8-pre6/arch/i386/kernel/i386_ksyms.c
--- linux-2.2.8-pre5/arch/i386/kernel/i386_ksyms.c	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/arch/i386/kernel/i386_ksyms.c	2003-08-15 15:06:14.000000000 -0700
@@ -92,7 +92,7 @@
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(mtrr_hook);
+EXPORT_SYMBOL(smp_call_function);
 #endif
 
 #ifdef CONFIG_MCA
diff -urN linux-2.2.8-pre5/arch/i386/kernel/irq.c linux-2.2.8-pre6/arch/i386/kernel/irq.c
--- linux-2.2.8-pre5/arch/i386/kernel/irq.c	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/arch/i386/kernel/irq.c	2003-08-15 15:06:14.000000000 -0700
@@ -322,7 +322,7 @@
 BUILD_SMP_INTERRUPT(reschedule_interrupt)
 BUILD_SMP_INTERRUPT(invalidate_interrupt)
 BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
-BUILD_SMP_INTERRUPT(mtrr_interrupt)
+BUILD_SMP_INTERRUPT(call_function_interrupt)
 BUILD_SMP_INTERRUPT(spurious_interrupt)
 
 /*
@@ -1094,8 +1094,8 @@
 	/* self generated IPI for local APIC timer */
 	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
 
-	/* IPI for MTRR control */
-	set_intr_gate(MTRR_CHANGE_VECTOR, mtrr_interrupt);
+	/* IPI for generic function call */
+	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
 
 	/* IPI vector for APIC spurious interrupts */
 	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
diff -urN linux-2.2.8-pre5/arch/i386/kernel/irq.h linux-2.2.8-pre6/arch/i386/kernel/irq.h
--- linux-2.2.8-pre5/arch/i386/kernel/irq.h	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/arch/i386/kernel/irq.h	2003-08-15 15:06:14.000000000 -0700
@@ -65,7 +65,7 @@
 #define INVALIDATE_TLB_VECTOR	0x31
 #define STOP_CPU_VECTOR		0x40
 #define LOCAL_TIMER_VECTOR	0x41
-#define MTRR_CHANGE_VECTOR	0x50
+#define CALL_FUNCTION_VECTOR	0x50
 
 /*
  * First APIC vector available to drivers: (vectors 0x51-0xfe)
@@ -99,7 +99,6 @@
 extern int i8259A_irq_pending(unsigned int irq);
 extern void ack_APIC_irq(void);
 extern void FASTCALL(send_IPI_self(int vector));
-extern void smp_send_mtrr(void);
 extern void init_VISWS_APIC_irqs(void);
 extern void setup_IO_APIC(void);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
diff -urN linux-2.2.8-pre5/arch/i386/kernel/mtrr.c linux-2.2.8-pre6/arch/i386/kernel/mtrr.c
--- linux-2.2.8-pre5/arch/i386/kernel/mtrr.c	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/arch/i386/kernel/mtrr.c	2003-08-15 15:06:14.000000000 -0700
@@ -132,11 +132,70 @@
 	       Fixed harmless compiler warning in include/asm-i386/mtrr.h
 	       Fixed version numbering and history for v1.23 -> v1.24.
   v1.26
-  
-  v1.26ac	Alan Cox <alan@redhat.com>
-  		Added some K6-II/III support. This needs back merging with
-  		Richard's current code before it goes to Linus really.
-  		
+    19990118   Richard Gooch <rgooch@atnf.csiro.au>
+	       PLACEHOLDER.
+  v1.27
+    19990123   Richard Gooch <rgooch@atnf.csiro.au>
+	       Changed locking to spin with reschedule.
+	       Made use of new <smp_call_function>.
+  v1.28
+    19990201   Zoltan Boszormenyi <zboszor@mol.hu>
+	       Extended the driver to be able to use Cyrix style ARRs.
+    19990204   Richard Gooch <rgooch@atnf.csiro.au>
+	       Restructured Cyrix support.
+  v1.29
+    19990204   Zoltan Boszormenyi <zboszor@mol.hu>
+	       Refined ARR support: enable MAPEN in set_mtrr_prepare()
+	       and disable MAPEN in set_mtrr_done().
+    19990205   Richard Gooch <rgooch@atnf.csiro.au>
+	       Minor cleanups.
+  v1.30
+    19990208   Zoltan Boszormenyi <zboszor@mol.hu>
+               Protect plain 6x86s (and other processors without the
+               Page Global Enable feature) against accessing CR4 in
+               set_mtrr_prepare() and set_mtrr_done().
+    19990210   Richard Gooch <rgooch@atnf.csiro.au>
+	       Turned <set_mtrr_up> and <get_mtrr> into function pointers.
+  v1.31
+    19990212   Zoltan Boszormenyi <zboszor@mol.hu>
+               Major rewrite of cyrix_arr_init(): do not touch ARRs,
+               leave them as the BIOS have set them up.
+               Enable usage of all 8 ARRs.
+               Avoid multiplications by 3 everywhere and other
+               code clean ups/speed ups.
+    19990213   Zoltan Boszormenyi <zboszor@mol.hu>
+               Set up other Cyrix processors identical to the boot cpu.
+               Since Cyrix don't support Intel APIC, this is l'art pour l'art.
+               Weigh ARRs by size:
+               If size <= 32M is given, set up ARR# we were given.
+               If size >  32M is given, set up ARR7 only if it is free,
+               fail otherwise.
+    19990214   Zoltan Boszormenyi <zboszor@mol.hu>
+               Also check for size >= 256K if we are to set up ARR7,
+               mtrr_add() returns the value it gets from set_mtrr()
+    19990218   Zoltan Boszormenyi <zboszor@mol.hu>
+               Remove Cyrix "coma bug" workaround from here.
+               Moved to linux/arch/i386/kernel/setup.c and
+               linux/include/asm-i386/bugs.h
+    19990228   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added #ifdef CONFIG_DEVFS_FS
+	       Added MTRRIOC_KILL_ENTRY ioctl(2)
+	       Trap for counter underflow in <mtrr_file_del>.
+	       Trap for 4 MiB aligned regions for PPro, stepping <= 7.
+    19990301   Richard Gooch <rgooch@atnf.csiro.au>
+	       Created <get_free_region> hook.
+    19990305   Richard Gooch <rgooch@atnf.csiro.au>
+	       Temporarily disable AMD support now MTRR capability flag is set.
+  v1.32
+    19990308   Zoltan Boszormenyi <zboszor@mol.hu>
+	       Adjust my changes (19990212-19990218) to Richard Gooch's
+	       latest changes. (19990228-19990305)
+  v1.33
+    19990309   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed typo in <printk> message.
+    19990310   Richard Gooch <rgooch@atnf.csiro.au>
+	       Support K6-II/III based on Alan Cox's <alan@redhat.com> patches.
+  v1.34
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -173,7 +232,7 @@
 #include <asm/hardirq.h>
 #include "irq.h"
 
-#define MTRR_VERSION            "1.26 (19981001)"
+#define MTRR_VERSION            "1.34 (19990310)"
 
 #define TRUE  1
 #define FALSE 0
@@ -203,7 +262,7 @@
 #  define MTRR_CHANGE_MASK_DEFTYPE   0x04
 #endif
 
-/* In the intel processor's MTRR interface, the MTRR type is always held in
+/* In the Intel processor's MTRR interface, the MTRR type is always held in
    an 8 bit field: */
 typedef u8 mtrr_type;
 
@@ -213,9 +272,12 @@
 #ifdef __SMP__
 #  define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
 #else
-#  define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type,TRUE)
+#  define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \
+						       TRUE)
 #endif
 
+#define spin_lock_reschedule(lock) while (!spin_trylock(lock)) schedule ();
+
 #ifndef CONFIG_PROC_FS
 #  define compute_ascii() while (0)
 #endif
@@ -231,7 +293,6 @@
 #ifdef CONFIG_PROC_FS
 static void compute_ascii (void);
 #endif
-static int k6_has_ranges(void);
 
 
 struct set_mtrr_context
@@ -240,36 +301,30 @@
     unsigned long deftype_lo;
     unsigned long deftype_hi;
     unsigned long cr4val;
+    unsigned long ccr3;
 };
 
-/*
- *	No point continually digging through complex CPU conditionals..
- */
- 
-static int mtrr_flags;
-
-#define MTRR_PRESENT		1
-#define MTRR_WRCOMB		2
 
-/* Put the processor into a state where MTRRs can be safely set. */
-static void set_mtrr_prepare(struct set_mtrr_context *ctxt)
+/*  Put the processor into a state where MTRRs can be safely set  */
+static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
 {
     unsigned long tmp;
 
-    /* disable interrupts locally */
+    /*  Disable interrupts locally  */
     __save_flags (ctxt->flags); __cli ();
 
-    if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-    	return;
+    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return;
 
-    /* save value of CR4 and clear Page Global Enable (bit 7) */
-    asm volatile ("movl  %%cr4, %0\n\t"
-		  "movl  %0, %1\n\t"
-		  "andb  $0x7f, %b1\n\t"
-		  "movl  %1, %%cr4\n\t"
-                  : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
-    /* disable and flush caches. Note that wbinvd flushes the TLBs as
-       a side-effect. */
+    /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+    if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+	asm volatile ("movl  %%cr4, %0\n\t"
+		      "movl  %0, %1\n\t"
+		      "andb  $0x7f, %b1\n\t"
+		      "movl  %1, %%cr4\n\t"
+		      : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
+
+    /*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+	a side-effect  */
     asm volatile ("movl  %%cr0, %0\n\t"
 		  "orl   $0x40000000, %0\n\t"
 		  "wbinvd\n\t"
@@ -277,110 +332,108 @@
 		  "wbinvd\n\t"
 		  : "=r" (tmp) : : "memory");
 
-    /* disable MTRRs, and set the default type to uncached. */
-    rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
-    wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	/*  Disable MTRRs, and set the default type to uncached  */
+	rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+	break;
+      case X86_VENDOR_CYRIX:
+	tmp = getCx86 (CX86_CCR3);
+	setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10);
+	ctxt->ccr3 = tmp;
+	break;
+    }
 }   /*  End Function set_mtrr_prepare  */
 
-
-/* Restore the processor after a set_mtrr_prepare */
-static void set_mtrr_done(struct set_mtrr_context *ctxt)
+/*  Restore the processor after a set_mtrr_prepare  */
+static void set_mtrr_done (struct set_mtrr_context *ctxt)
 {
     unsigned long tmp;
 
-    if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-    	return;
-    	
-    /* flush caches and TLBs */
+    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+    {
+	__restore_flags (ctxt->flags);
+	return;
+    }
+
+    /*  Flush caches and TLBs  */
     asm volatile ("wbinvd" : : : "memory" );
 
-    /* restore MTRRdefType */
-    wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+    /*  Restore MTRRdefType  */
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+	break;
+      case X86_VENDOR_CYRIX:
+	setCx86 (CX86_CCR3, ctxt->ccr3);
+	break;
+    }
 
-    /* enable caches */
+    /*  Enable caches  */
     asm volatile ("movl  %%cr0, %0\n\t"
 		  "andl  $0xbfffffff, %0\n\t"
 		  "movl  %0, %%cr0\n\t"
 		  : "=r" (tmp) : : "memory");
 
-    /* restore value of CR4 */
-    asm volatile ("movl  %0, %%cr4"
-                  : : "r" (ctxt->cr4val) : "memory");
+    /*  Restore value of CR4  */
+    if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+	asm volatile ("movl  %0, %%cr4"
+		      : : "r" (ctxt->cr4val) : "memory");
 
-    /* re-enable interrupts locally (if enabled previously) */
+    /*  Re-enable interrupts locally (if enabled previously)  */
     __restore_flags (ctxt->flags);
 }   /*  End Function set_mtrr_done  */
 
-
-/* this function returns the number of variable MTRRs */
+/*  This function returns the number of variable MTRRs  */
 static unsigned int get_num_var_ranges (void)
 {
     unsigned long config, dummy;
-    
-    if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-    	return 2;
 
-    rdmsr(MTRRcap_MSR, config, dummy);
-    return (config & 0xff);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	rdmsr (MTRRcap_MSR, config, dummy);
+	return (config & 0xff);
+	/*break;*/
+      case X86_VENDOR_CYRIX:
+	/*  Cyrix have 8 ARRs */
+	return 8;
+	/*break;*/
+      case X86_VENDOR_AMD:
+	return 2;
+	/*break;*/
+    }
+    return 0;
 }   /*  End Function get_num_var_ranges  */
 
-
-/* non-zero if we have the write-combining memory type. */
+/*  Returns non-zero if we have the write-combining memory type  */
 static int have_wrcomb (void)
 {
     unsigned long config, dummy;
 
-    rdmsr(MTRRcap_MSR, config, dummy);
-    return (config & (1<<10));
-}
-
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	rdmsr (MTRRcap_MSR, config, dummy);
+	return (config & (1<<10));
+	/*break;*/
+      case X86_VENDOR_CYRIX:
+      case X86_VENDOR_AMD:
+	return 1;
+	/*break;*/
+    }
+    return 0;
+}   /*  End Function have_wrcomb  */
 
-static void get_mtrr (unsigned int reg, unsigned long *base,
-		      unsigned long *size, mtrr_type *type)
+static void intel_get_mtrr (unsigned int reg, unsigned long *base,
+			    unsigned long *size, mtrr_type *type)
 {
     unsigned long dummy, mask_lo, base_lo;
 
-    if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-    {
-        unsigned long low, high;
-    	rdmsr(0xC0000085,  low, high);
-    	/* Upper dword is region 1, lower is region 0 */
-    	if(reg==1)
-    		low=high;
-    	/* The base masks off on the right alignment */
-    	*base=low&0xFFFE0000;
-    	*type=0;
-    	if(low&1)
-    		*type=MTRR_TYPE_UNCACHABLE;
-    	if(low&2)
-    		*type=MTRR_TYPE_WRCOMB;
-    	if(!(low&3))
-    	{
-    		*size=0;
-    		return;
-    	}
-    	
-	/*
-	 *	This needs a little explaining. The size is stored as an
-	 *	inverted mask of bits of 128K granularity 15 bits long offset
-	 *	2 bits
-	 *
-	 *	So to get a size we do invert the mask and add 1 to the lowest
-	 *	mask bit (4 as its 2 bits in). This gives us a size we then shift
-	 *	to turn into 128K blocks
-	 *
-	 *	eg		111 1111 1111 1100      is 512K
-	 *
-	 *	invert		000 0000 0000 0011
-	 *	+1		000 0000 0000 0100
-	 *	*128K	...
-	 */
-
-    	low=(~low)&0x1FFFC;
-	*size = (low+4)<<15;
-	return;	
-    }
-    rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy);
+    rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
     if ((mask_lo & 0x800) == 0) {
 	/* Invalid (i.e. free) range. */
 	*base = 0;
@@ -404,11 +457,104 @@
 
     *base = (base_lo & 0xfffff000UL);
     *type = (base_lo & 0xff);
-}   /*  End Function get_mtrr  */
+}   /*  End Function intel_get_mtrr  */
+
+static void cyrix_get_arr (unsigned int reg, unsigned long *base,
+			   unsigned long *size, mtrr_type *type)
+{
+    unsigned long flags;
+    unsigned char arr, ccr3, rcr, shift;
+
+    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
+
+    /* Save flags and disable interrupts */
+    __save_flags (flags); __cli ();
+
+    ccr3 = getCx86 (CX86_CCR3);
+    setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10);		/* enable MAPEN */
+    ((unsigned char *) base)[3]  = getCx86 (arr);
+    ((unsigned char *) base)[2]  = getCx86 (arr+1);
+    ((unsigned char *) base)[1]  = getCx86 (arr+2);
+    rcr = getCx86(CX86_RCR_BASE + reg);
+    setCx86 (CX86_CCR3, ccr3);				/* disable MAPEN */
+
+    /* Enable interrupts if it was enabled previously */
+    __restore_flags (flags);
+    
+    shift = ((unsigned char *) base)[1] & 0x0f;
+    *base &= 0xfffff000UL;
+
+    /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
+     * Note: shift==0xf means 4G, this is unsupported.
+     */
+    if (shift)
+      *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+    else
+      *size = 0;
+
+    /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
+    if (reg < 7) {
+      switch (rcr) {
+	case  1: *type = MTRR_TYPE_UNCACHABLE; break;
+	case  8: *type = MTRR_TYPE_WRBACK;     break;
+	case  9: *type = MTRR_TYPE_WRCOMB;     break;
+	case 24:
+	default: *type = MTRR_TYPE_WRTHROUGH;  break;
+      }
+    } else {
+      switch (rcr) {
+	case  0: *type = MTRR_TYPE_UNCACHABLE; break;
+	case  8: *type = MTRR_TYPE_WRCOMB;     break;
+	case  9: *type = MTRR_TYPE_WRBACK;     break;
+	case 25:
+	default: *type = MTRR_TYPE_WRTHROUGH;  break;
+      }
+    }
+}   /*  End Function cyrix_get_arr  */
+
+static void amd_get_mtrr (unsigned int reg, unsigned long *base,
+			  unsigned long *size, mtrr_type *type)
+{
+    unsigned long low, high;
+
+    rdmsr (0xC0000085, low, high);
+    /*  Upper dword is region 1, lower is region 0  */
+    if (reg == 1) low = high;
+    /*  The base masks off on the right alignment  */
+    *base = low & 0xFFFE0000;
+    *type = 0;
+    if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
+    if (low & 2) *type = MTRR_TYPE_WRCOMB;
+    if ( !(low & 3) )
+    {
+	*size = 0;
+	return;
+    }
+    /*
+     *	This needs a little explaining. The size is stored as an
+     *	inverted mask of bits of 128K granularity 15 bits long offset
+     *	2 bits
+     *
+     *	So to get a size we do invert the mask and add 1 to the lowest
+     *	mask bit (4 as its 2 bits in). This gives us a size we then shift
+     *	to turn into 128K blocks
+     *
+     *	eg		111 1111 1111 1100      is 512K
+     *
+     *	invert		000 0000 0000 0011
+     *	+1		000 0000 0000 0100
+     *	*128K	...
+     */
+    low = (~low) & 0x1FFFC;
+    *size = (low + 4) << 15;
+    return;
+}   /*  End Function amd_get_mtrr  */
 
+static void (*get_mtrr) (unsigned int reg, unsigned long *base,
+			 unsigned long *size, mtrr_type *type) = NULL;
 
-static void set_mtrr_up (unsigned int reg, unsigned long base,
-			 unsigned long size, mtrr_type type, int do_safe)
+static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
+			       unsigned long size, mtrr_type type, int do_safe)
 /*  [SUMMARY] Set variable MTRR register on the local CPU.
     <reg> The register to set.
     <base> The base address of the region.
@@ -416,65 +562,110 @@
     <type> The type of the region.
     <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
     be done externally.
+    [RETURNS] Nothing.
 */
 {
     struct set_mtrr_context ctxt;
 
     if (do_safe) set_mtrr_prepare (&ctxt);
-    
-    if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+    if (size == 0)
     {
-	    if (size == 0)
-	    {
-		/* The invalid bit is kept in the mask, so we simply clear the
-		   relevant mask register to disable a range. */
-		wrmsr (MTRRphysMask_MSR (reg), 0, 0);
-	    }
-	    else
-	    {
-		wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
-		wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
-	    }
+	/* The invalid bit is kept in the mask, so we simply clear the
+	   relevant mask register to disable a range. */
+	wrmsr (MTRRphysMask_MSR (reg), 0, 0);
     }
-    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+    else
     {
-        u32 low, high;
-        unsigned long flags;
-        /*
-         *	Low is MTRR0 , High MTRR 1
-         */
-        rdmsr(0xC0000085, low, high);
-        /*
-         *	Blank to disable
-         */
-        if(size==0)
-        	*(reg?&high:&low)=0;
-        else
-        	/* Set the register to the base (already shifted for us), the
-        	   type (off by one) and an inverted bitmask of the size
-        	   
-        	   The size is the only odd bit. We are fed say 512K
-        	   We invert this and we get 111 1111 1111 1011 but
-        	   if you subtract one and invert you get the desired
-        	   111 1111 1111 1100 mask 
-        	*/
-        	
-		*(reg?&high:&low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
-	
-	/*
-	 *	The writeback rule is quite specific. See the manual. Its
-	 *	disable local interrupts, write back the cache, set the mtrr
-	 */
-	 
-	save_flags(flags);
-	__cli();
-	__asm__ __volatile__("wbinvd" : : : "memory");
-	wrmsr(0xC0000085, low, high);
-	restore_flags(flags);
+	wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
+	wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
     }
     if (do_safe) set_mtrr_done (&ctxt);
-}   /*  End Function set_mtrr_up  */
+}   /*  End Function intel_set_mtrr_up  */
+
+static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
+			      unsigned long size, mtrr_type type, int do_safe)
+{
+    struct set_mtrr_context ctxt;
+    unsigned char arr, arr_type, arr_size;
+
+    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
+
+    /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
+    size >>= (reg < 7 ? 12 : 18);
+    size &= 0x7fff; /* make sure arr_size <= 14 */
+    for(arr_size = 0; size; arr_size++, size >>= 1);
+
+    if (reg<7) {
+      switch (type) {
+	case MTRR_TYPE_UNCACHABLE:	arr_type =  1; break;
+	case MTRR_TYPE_WRCOMB:		arr_type =  9; break;
+	case MTRR_TYPE_WRTHROUGH:	arr_type = 24; break;
+	default:			arr_type =  8; break;
+      }
+    } else {
+      switch (type) {
+	case MTRR_TYPE_UNCACHABLE:	arr_type =  0; break;
+	case MTRR_TYPE_WRCOMB:		arr_type =  8; break;
+	case MTRR_TYPE_WRTHROUGH:	arr_type = 25; break;
+	default:			arr_type =  9; break;
+      }
+    }
+
+    if (do_safe) set_mtrr_prepare (&ctxt);
+    setCx86(arr,    ((unsigned char *) &base)[3]);
+    setCx86(arr+1,  ((unsigned char *) &base)[2]);
+    setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
+    setCx86(CX86_RCR_BASE + reg, arr_type);
+    if (do_safe) set_mtrr_done (&ctxt);
+}   /*  End Function cyrix_set_arr_up  */
+
+static void amd_set_mtrr_up (unsigned int reg, unsigned long base,
+			     unsigned long size, mtrr_type type, int do_safe)
+/*  [SUMMARY] Set variable MTRR register on the local CPU.
+    <reg> The register to set.
+    <base> The base address of the region.
+    <size> The size of the region. If this is 0 the region is disabled.
+    <type> The type of the region.
+    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+    be done externally.
+    [RETURNS] Nothing.
+*/
+{
+    u32 low, high;
+    struct set_mtrr_context ctxt;
+
+    if (do_safe) set_mtrr_prepare (&ctxt);
+    /*
+     *	Low is MTRR0 , High MTRR 1
+     */
+    rdmsr (0xC0000085, low, high);
+    /*
+     *	Blank to disable
+     */
+    if (size == 0)
+	*(reg ? &high : &low) = 0;
+    else
+	/* Set the register to the base (already shifted for us), the
+	   type (off by one) and an inverted bitmask of the size
+        	   
+	   The size is the only odd bit. We are fed say 512K
+	   We invert this and we get 111 1111 1111 1011 but
+	   if you subtract one and invert you get the desired
+	   111 1111 1111 1100 mask 
+	   */
+	*(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
+    /*
+     *	The writeback rule is quite specific. See the manual. Its
+     *	disable local interrupts, write back the cache, set the mtrr
+     */
+    __asm__ __volatile__ ("wbinvd" : : : "memory");
+    wrmsr (0xC0000085, low, high);
+    if (do_safe) set_mtrr_done (&ctxt);
+}   /*  End Function amd_set_mtrr_up  */
 
+static void (*set_mtrr_up) (unsigned int reg, unsigned long base,
+			    unsigned long size, mtrr_type type,
+			    int do_safe) = NULL;
      
 #ifdef __SMP__
 
@@ -487,7 +678,7 @@
 };
 
 
-/* Get the MSR pair relating to a var range. */
+/*  Get the MSR pair relating to a var range  */
 __initfunc(static void get_mtrr_var_range (unsigned int index,
 					   struct mtrr_var_range *vr))
 {
@@ -496,8 +687,8 @@
 }   /*  End Function get_mtrr_var_range  */
 
 
-/* Set the MSR pair relating to a var range. Returns TRUE if
-   changes are made. */
+/*  Set the MSR pair relating to a var range. Returns TRUE if
+    changes are made  */
 __initfunc(static int set_mtrr_var_range_testing (unsigned int index,
 						  struct mtrr_var_range *vr))
 {
@@ -521,8 +712,7 @@
     }
     
     return changed;
-}
-
+}   /*  End Function set_mtrr_var_range_testing  */
 
 __initfunc(static void get_fixed_ranges(mtrr_type *frs))
 {
@@ -536,8 +726,7 @@
  
     for (i = 0; i < 8; i++)
 	rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
-}
-
+}   /*  End Function get_fixed_ranges  */
 
 __initfunc(static int set_fixed_ranges_testing(mtrr_type *frs))
 {
@@ -567,10 +756,8 @@
 	    changed = TRUE;
 	}
     }
-
     return changed;
-}
-
+}   /*  End Function set_fixed_ranges_testing  */
 
 struct mtrr_state
 {
@@ -582,7 +769,7 @@
 };
 
 
-/* Grab all of the MTRR state for this CPU into *state. */
+/*  Grab all of the MTRR state for this CPU into *state  */
 __initfunc(static void get_mtrr_state(struct mtrr_state *state))
 {
     unsigned int nvrs, i;
@@ -591,28 +778,22 @@
 
     nvrs = state->num_var_ranges = get_num_var_ranges();
     vrs = state->var_ranges 
-              = kmalloc(nvrs * sizeof(struct mtrr_var_range), GFP_KERNEL);
+              = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
     if (vrs == NULL)
 	nvrs = state->num_var_ranges = 0;
 
     for (i = 0; i < nvrs; i++)
-	get_mtrr_var_range(i, &vrs[i]);
+	get_mtrr_var_range (i, &vrs[i]);
     
-    if(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
-    {
-	    get_fixed_ranges(state->fixed_ranges);
+    get_fixed_ranges (state->fixed_ranges);
 
-	    rdmsr(MTRRdefType_MSR, lo, dummy);
-	    state->def_type = (lo & 0xff);
-	    state->enabled = (lo & 0xc00) >> 10;
-	    return;
-    }
-    state->def_type = 0;
-    state->enabled = 1;
+    rdmsr (MTRRdefType_MSR, lo, dummy);
+    state->def_type = (lo & 0xff);
+    state->enabled = (lo & 0xc00) >> 10;
 }   /*  End Function get_mtrr_state  */
 
 
-/* Free resources associated with a struct mtrr_state */
+/*  Free resources associated with a struct mtrr_state  */
 __initfunc(static void finalize_mtrr_state(struct mtrr_state *state))
 {
     if (state->var_ranges) kfree (state->var_ranges);
@@ -631,18 +812,15 @@
     unsigned int i;
     unsigned long change_mask = 0;
 
-    if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-    	return 0UL;
-    	
     for (i = 0; i < state->num_var_ranges; i++)
-	if (set_mtrr_var_range_testing(i, &state->var_ranges[i]))
+	if ( set_mtrr_var_range_testing (i, &state->var_ranges[i]) )
 	    change_mask |= MTRR_CHANGE_MASK_VARIABLE;
 
-    if (set_fixed_ranges_testing(state->fixed_ranges))
+    if ( set_fixed_ranges_testing(state->fixed_ranges) )
 	change_mask |= MTRR_CHANGE_MASK_FIXED;
     
-    /* set_mtrr_restore restores the old value of MTRRdefType,
-       so to set it we fiddle with the saved value. */
+    /*  Set_mtrr_restore restores the old value of MTRRdefType,
+	so to set it we fiddle with the saved value  */
     if ((ctxt->deftype_lo & 0xff) != state->def_type
 	|| ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled)
     {
@@ -655,76 +833,63 @@
 
  
 static atomic_t undone_count;
-static void (*handler_func) (struct set_mtrr_context *ctxt, void *info);
-static void *handler_info;
 static volatile int wait_barrier_execute = FALSE;
 static volatile int wait_barrier_cache_enable = FALSE;
 
-static void sync_handler (void)
+struct set_mtrr_data
+{
+    unsigned long smp_base;
+    unsigned long smp_size;
+    unsigned int smp_reg;
+    mtrr_type smp_type;
+};
+
+static void ipi_handler (void *info)
 /*  [SUMMARY] Synchronisation handler. Executed by "other" CPUs.
     [RETURNS] Nothing.
 */
 {
+    struct set_mtrr_data *data = info;
     struct set_mtrr_context ctxt;
 
     set_mtrr_prepare (&ctxt);
-    /*  Notify master CPU that I'm at the barrier and then wait  */
+    /*  Notify master that I've flushed and disabled my cache  */
     atomic_dec (&undone_count);
     while (wait_barrier_execute) barrier ();
     /*  The master has cleared me to execute  */
-    (*handler_func) (&ctxt, handler_info);
+    (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size,
+		    data->smp_type, FALSE);
     /*  Notify master CPU that I've executed the function  */
     atomic_dec (&undone_count);
     /*  Wait for master to clear me to enable cache and return  */
     while (wait_barrier_cache_enable) barrier ();
     set_mtrr_done (&ctxt);
-}   /*  End Function sync_handler  */
+}   /*  End Function ipi_handler  */
 
-static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt,
-					  void *info),
-			 void *info, int local)
-/*  [SUMMARY] Execute a function on all CPUs, with caches flushed and disabled.
-    [PURPOSE] This function will synchronise all CPUs, flush and disable caches
-    on all CPUs, then call a specified function. When the specified function
-    finishes on all CPUs, caches are enabled on all CPUs.
-    <handler> The function to execute.
-    <info> An arbitrary information pointer which is passed to <<handler>>.
-    <local> If TRUE <<handler>> is executed locally.
-    [RETURNS] Nothing.
-*/
+static void set_mtrr_smp (unsigned int reg, unsigned long base,
+			  unsigned long size, mtrr_type type)
 {
-    unsigned long timeout;
+    struct set_mtrr_data data;
     struct set_mtrr_context ctxt;
 
-    mtrr_hook = sync_handler;
-    handler_func = handler;
-    handler_info = info;
+    data.smp_reg = reg;
+    data.smp_base = base;
+    data.smp_size = size;
+    data.smp_type = type;
     wait_barrier_execute = TRUE;
     wait_barrier_cache_enable = TRUE;
-    /*  Send a message to all other CPUs and wait for them to enter the
-	barrier  */
     atomic_set (&undone_count, smp_num_cpus - 1);
-    smp_send_mtrr();
-    /*  Wait for it to be done  */
-    timeout = jiffies + JIFFIE_TIMEOUT;
-    while ( (atomic_read (&undone_count) > 0) &&
-	    time_before(jiffies, timeout) )
-	barrier ();
-    if (atomic_read (&undone_count) > 0)
-    {
+    /*  Flush and disable the local CPU's cache	and start the ball rolling on
+	other CPUs  */
+    set_mtrr_prepare (&ctxt);
+    if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
 	panic ("mtrr: timed out waiting for other CPUs\n");
-    }
-    mtrr_hook = NULL;
-    /*  All other CPUs should be waiting for the barrier, with their caches
-	already flushed and disabled. Prepare for function completion
-	notification  */
+    /*  Wait for all other CPUs to flush and disable their caches  */
+    while (atomic_read (&undone_count) > 0) barrier ();
+    /* Set up for completion wait and then release other CPUs to change MTRRs*/
     atomic_set (&undone_count, smp_num_cpus - 1);
-    /*  Flush and disable the local CPU's cache	and release the barier, which
-	should cause the other CPUs to execute the function. Also execute it
-	locally if required  */
-    set_mtrr_prepare (&ctxt);
     wait_barrier_execute = FALSE;
-    if (local) (*handler) (&ctxt, info);
+    (*set_mtrr_up) (reg, base, size, type, FALSE);
     /*  Now wait for other CPUs to complete the function  */
     while (atomic_read (&undone_count) > 0) barrier ();
     /*  Now all CPUs should have finished the function. Release the barrier to
@@ -732,41 +897,10 @@
 	then enable the local cache and return  */
     wait_barrier_cache_enable = FALSE;
     set_mtrr_done (&ctxt);
-    handler_func = NULL;
-    handler_info = NULL;
-}   /*  End Function do_all_cpus  */
-
-
-struct set_mtrr_data
-{
-    unsigned long smp_base;
-    unsigned long smp_size;
-    unsigned int smp_reg;
-    mtrr_type smp_type;
-};
-
-static void set_mtrr_handler (struct set_mtrr_context *ctxt, void *info)
-{
-    struct set_mtrr_data *data = info;
-
-    set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, data->smp_type,
-		 FALSE);
-}   /*  End Function set_mtrr_handler  */
-
-static void set_mtrr_smp (unsigned int reg, unsigned long base,
-			  unsigned long size, mtrr_type type)
-{
-    struct set_mtrr_data data;
-
-    data.smp_reg = reg;
-    data.smp_base = base;
-    data.smp_size = size;
-    data.smp_type = type;
-    do_all_cpus (set_mtrr_handler, &data, TRUE);
 }   /*  End Function set_mtrr_smp  */
 
 
-/* Some BIOS's are fucked and don't set all MTRRs the same! */
+/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
 __initfunc(static void mtrr_state_warn (unsigned long mask))
 {
     if (!mask) return;
@@ -809,6 +943,58 @@
 #endif
 }   /*  End Function init_table  */
 
+static int generic_get_free_region (unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free MTRR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+    int i, max;
+    mtrr_type ltype;
+    unsigned long lbase, lsize;
+
+    max = get_num_var_ranges ();
+    for (i = 0; i < max; ++i)
+    {
+	(*get_mtrr) (i, &lbase, &lsize, &ltype);
+	if (lsize < 1) return i;
+    }
+    return -ENOSPC;
+}   /*  End Function generic_get_free_region  */
+
+static int cyrix_get_free_region (unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free ARR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+    int i;
+    mtrr_type ltype;
+    unsigned long lbase, lsize;
+
+    /* If we are to set up a region >32M then look at ARR7 immediately */
+    if (size > 0x2000000UL) {
+	cyrix_get_arr (7, &lbase, &lsize, &ltype);
+	if (lsize < 1) return 7;
+    /* else try ARR0-ARR6 first */
+    } else {
+	for (i = 0; i < 7; i++)
+	{
+	    cyrix_get_arr (i, &lbase, &lsize, &ltype);
+	    if (lsize < 1) return i;
+	}
+	/* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
+	cyrix_get_arr (i, &lbase, &lsize, &ltype);
+	if ((lsize < 1) && (size >= 0x40000)) return i;
+    }
+    return -ENOSPC;
+}   /*  End Function cyrix_get_free_region  */
+
+static int (*get_free_region) (unsigned long base,
+			       unsigned long size) = generic_get_free_region;
+
 int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
 	      char increment)
 /*  [SUMMARY] Add an MTRR entry.
@@ -826,11 +1012,44 @@
     mtrr_type ltype;
     unsigned long lbase, lsize, last;
 
-    if (!(mtrr_flags&MTRR_PRESENT))
-    	return -ENODEV;
-    	
-    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
+    switch (boot_cpu_data.x86_vendor)
     {
+      case X86_VENDOR_INTEL:
+	/*  For Intel PPro stepping <= 7, must be 4 MiB aligned  */
+	if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
+	     (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) )
+	{
+	    printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
+	    return -EINVAL;
+	}
+	/*  Fall through  */
+      case X86_VENDOR_CYRIX:
+	if ( (base & 0xfff) || (size & 0xfff) )
+	{
+	    printk ("mtrr: size and base must be multiples of 4 kiB\n");
+	    printk ("mtrr: size: %lx  base: %lx\n", size, base);
+	    return -EINVAL;
+	}
+	if (base + size < 0x100000)
+	{
+	    printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
+		    base, size);
+	    return -EINVAL;
+	}
+	/*  Check upper bits of base and last are equal and lower bits are 0
+	    for base and 1 for last  */
+	last = base + size - 1;
+	for (lbase = base; !(lbase & 1) && (last & 1);
+	     lbase = lbase >> 1, last = last >> 1);
+	if (lbase != last)
+	{
+	    printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
+		    base, size);
+	    return -EINVAL;
+	}
+	break;
+      case X86_VENDOR_AMD:
     	/* Apply the K6 block alignment and size rules 
     	   In order
     	      o Uncached or gathering only
@@ -838,54 +1057,32 @@
     	      o Power of 2 block
     	      o base suitably aligned to the power
     	  */
-    	if(type > 1 || size < (1<<17) || (size & ~(size-1))-size || (base&(size-1)))
-    		return -EINVAL;
+    	if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+	    (size & ~(size-1))-size || (base & (size-1)))
+	    return -EINVAL;
+	break;
+      default:
+	return -EINVAL;
+	/*break;*/
     }
-    	
-    if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+    if (type >= MTRR_NUM_TYPES)
     {
-	    if ( (base & 0xfff) || (size & 0xfff) )
-	    {
-		printk ("mtrr: size and base must be multiples of 4kB\n");
-		printk ("mtrr: size: %lx  base: %lx\n", size, base);
-		return -EINVAL;
-	    }
-	    if (base + size < 0x100000)
-	    {
-		printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n",
-			base, size);
-		return -EINVAL;
-	    }
-	    /*  Check upper bits of base and last are equal and lower bits are 0 for
-		base and 1 for last  */
-	    last = base + size - 1;
-	    for (lbase = base; !(lbase & 1) && (last & 1);
-		 lbase = lbase >> 1, last = last >> 1);
-	    if (lbase != last)
-	    {
-		printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
-			base, size);
-		return -EINVAL;
-	    }
-	    if (type >= MTRR_NUM_TYPES)
-	    {
-		printk ("mtrr: type: %u illegal\n", type);
-		return -EINVAL;
-	    }
-	    /*  If the type is WC, check that this processor supports it  */
-	    if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
-	    {
-	        printk ("mtrr: your processor doesn't support write-combining\n");
-	        return -EINVAL;
-	    }
+	printk ("mtrr: type: %u illegal\n", type);
+	return -EINVAL;
+    }
+    /*  If the type is WC, check that this processor supports it  */
+    if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
+    {
+        printk ("mtrr: your processor doesn't support write-combining\n");
+        return -ENOSYS;
     }
     increment = increment ? 1 : 0;
     max = get_num_var_ranges ();
     /*  Search for existing MTRR  */
-    spin_lock (&main_lock);
+    spin_lock_reschedule (&main_lock);
     for (i = 0; i < max; ++i)
     {
-	get_mtrr (i, &lbase, &lsize, &ltype);
+	(*get_mtrr) (i, &lbase, &lsize, &ltype);
 	if (base >= lbase + lsize) continue;
 	if ( (base < lbase) && (base + size <= lbase) ) continue;
 	/*  At this point we know there is some kind of overlap/enclosure  */
@@ -911,19 +1108,18 @@
 	return i;
     }
     /*  Search for an empty MTRR  */
-    for (i = 0; i < max; ++i)
+    i = (*get_free_region) (base, size);
+    if (i < 0)
     {
-	get_mtrr (i, &lbase, &lsize, &ltype);
-	if (lsize > 0) continue;
-	set_mtrr (i, base, size, type);
-	usage_table[i] = 1;
-	compute_ascii ();
 	spin_unlock (&main_lock);
+	printk ("mtrr: no more MTRRs available\n");
 	return i;
     }
+    set_mtrr (i, base, size, type);
+    usage_table[i] = 1;
+    compute_ascii ();
     spin_unlock (&main_lock);
-    printk ("mtrr: no more MTRRs available\n");
-    return -ENOSPC;
+    return i;
 }   /*  End Function mtrr_add  */
 
 int mtrr_del (int reg, unsigned long base, unsigned long size)
@@ -941,15 +1137,15 @@
     mtrr_type ltype;
     unsigned long lbase, lsize;
 
-    if ( !(mtrr_flags&MTRR_PRESENT) ) return -ENODEV;
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
     max = get_num_var_ranges ();
-    spin_lock (&main_lock);
+    spin_lock_reschedule (&main_lock);
     if (reg < 0)
     {
 	/*  Search for existing MTRR  */
 	for (i = 0; i < max; ++i)
 	{
-	    get_mtrr (i, &lbase, &lsize, &ltype);
+	    (*get_mtrr) (i, &lbase, &lsize, &ltype);
 	    if ( (lbase == base) && (lsize == size) )
 	    {
 		reg = i;
@@ -969,7 +1165,7 @@
 	printk ("mtrr: register: %d too big\n", reg);
 	return -EINVAL;
     }
-    get_mtrr (reg, &lbase, &lsize, &ltype);
+    (*get_mtrr) (reg, &lbase, &lsize, &ltype);
     if (lsize < 1)
     {
 	spin_unlock (&main_lock);
@@ -1020,7 +1216,9 @@
 
     reg = mtrr_del (-1, base, size);
     if (reg < 0) return reg;
-    if (fcount != NULL) --fcount[reg];
+    if (fcount == NULL) return reg;
+    if (fcount[reg] < 1) return -EINVAL;
+    --fcount[reg];
     return reg;
 }   /*  End Function mtrr_file_del  */
 
@@ -1126,11 +1324,18 @@
 	err = mtrr_file_del (sentry.base, sentry.size, file);
 	if (err < 0) return err;
 	break;
+      case MTRRIOC_KILL_ENTRY:
+	if ( !suser () ) return -EPERM;
+	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+	    return -EFAULT;
+	err = mtrr_del (-1, sentry.base, sentry.size);
+	if (err < 0) return err;
+	break;
       case MTRRIOC_GET_ENTRY:
 	if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
 	    return -EFAULT;
 	if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
-	get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type);
+	(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
 	gentry.type = type;
 	if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
 	     return -EFAULT;
@@ -1222,7 +1427,7 @@
     max = get_num_var_ranges ();
     for (i = 0; i < max; i++)
     {
-	get_mtrr (i, &base, &size, &type);
+	(*get_mtrr) (i, &base, &size, &type);
 	if (size < 1) usage_table[i] = 0;
 	else
 	{
@@ -1255,28 +1460,165 @@
 
 #ifdef __SMP__
 
+typedef struct {
+  unsigned long base;
+  unsigned long size;
+  mtrr_type type;
+} arr_state_t;
+
+arr_state_t arr_state[8] __initdata = {
+  {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
+  {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
+};
+
+unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
+
+__initfunc(static void cyrix_arr_init_secondary(void))
+{
+    struct set_mtrr_context ctxt;
+    int i;
+
+    set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+
+     /* the CCRs are not contiguous */
+    for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]);
+    for(   ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]);
+    for(i=0; i<8; i++)
+      cyrix_set_arr_up(i,
+        arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE);
+
+    set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
+}   /*  End Function cyrix_arr_init_secondary  */
+
+#endif
+
+/*
+ * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
+ * with the SMM (System Management Mode) mode. So we need the following:
+ * Check whether SMI_LOCK (CCR3 bit 0) is set
+ *   if it is set, write a warning message: ARR3 cannot be changed!
+ *     (it cannot be changed until the next processor reset)
+ *   if it is reset, then we can change it, set all the needed bits:
+ *   - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
+ *   - disable access to SMM memory (CCR1 bit 2 reset)
+ *   - disable SMM mode (CCR1 bit 1 reset)
+ *   - disable write protection of ARR3 (CCR6 bit 1 reset)
+ *   - (maybe) disable ARR3
+ * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
+ */
+__initfunc(static void cyrix_arr_init(void))
+{
+    struct set_mtrr_context ctxt;
+    unsigned char ccr[7];
+    int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
+#ifdef __SMP__
+    int i;
+#endif
+
+    set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+
+    /* Save all CCRs locally */
+    ccr[0] = getCx86 (CX86_CCR0);
+    ccr[1] = getCx86 (CX86_CCR1);
+    ccr[2] = getCx86 (CX86_CCR2);
+    ccr[3] = ctxt.ccr3;
+    ccr[4] = getCx86 (CX86_CCR4);
+    ccr[5] = getCx86 (CX86_CCR5);
+    ccr[6] = getCx86 (CX86_CCR6);
+
+    if (ccr[3] & 1)
+      ccrc[3] = 1;
+    else {
+      /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+       * access to SMM memory through ARR3 (bit 7).
+       */
+/*
+      if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
+      if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
+      if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
+*/
+      if (ccr[6] & 0x02) {
+        ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */
+        setCx86 (CX86_CCR6, ccr[6]);
+      }
+      /* Disable ARR3. */
+      /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
+    }
+    /* If we changed CCR1 in memory, change it in the processor, too. */
+    if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]);
+
+    /* Enable ARR usage by the processor */
+    if (!(ccr[5] & 0x20)) {
+      ccr[5] |= 0x20; ccrc[5] = 1;
+      setCx86 (CX86_CCR5, ccr[5]);
+    }
+
+#ifdef __SMP__
+    for(i=0; i<7; i++) ccr_state[i] = ccr[i];
+    for(i=0; i<8; i++)
+      cyrix_get_arr(i,
+        &arr_state[i].base, &arr_state[i].size, &arr_state[i].type);
+#endif
+
+    set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
+
+    if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n");
+    if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n");
+/*
+    if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
+    if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
+    if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
+*/
+    if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");
+}   /*  End Function cyrix_arr_init  */
+
+__initfunc(static void mtrr_setup (void))
+{
+    printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	get_mtrr = intel_get_mtrr;
+	set_mtrr_up = intel_set_mtrr_up;
+	break;
+      case X86_VENDOR_CYRIX:
+	printk ("mtrr: Using Cyrix style ARRs\n");
+	get_mtrr = cyrix_get_arr;
+	set_mtrr_up = cyrix_set_arr_up;
+	get_free_region = cyrix_get_free_region;
+	break;
+      case X86_VENDOR_AMD:
+	get_mtrr = amd_get_mtrr;
+	set_mtrr_up = amd_set_mtrr_up;
+	break;
+    }
+}   /*  End Function mtrr_setup  */
+
+#ifdef __SMP__
+
 static volatile unsigned long smp_changes_mask __initdata = 0;
 static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
 
 __initfunc(void mtrr_init_boot_cpu (void))
 {
-    printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
-    if (boot_cpu_data.x86_capability & X86_FEATURE_MTRR)
-    {
-	get_mtrr_state (&smp_mtrr_state);
-    }
-    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && k6_has_ranges())
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
+    mtrr_setup ();
+    switch (boot_cpu_data.x86_vendor)
     {
+      case X86_VENDOR_INTEL:
 	get_mtrr_state (&smp_mtrr_state);
+	break;
+      case X86_VENDOR_CYRIX:
+	cyrix_arr_init ();
+	break;
     }
 }   /*  End Function mtrr_init_boot_cpu  */
 
-__initfunc(void mtrr_init_secondary_cpu (void))
+__initfunc(static void intel_mtrr_init_secondary_cpu (void))
 {
     unsigned long mask, count;
     struct set_mtrr_context ctxt;
 
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
     /*  Note that this is not ideal, since the cache is only flushed/disabled
 	for this CPU while the MTRRs are changed, but changing this requires
 	more invasive changes to the way the kernel boots  */
@@ -1289,53 +1631,57 @@
 	if (mask & 0x01) set_bit (count, &smp_changes_mask);
 	mask >>= 1;
     }
-}   /*  End Function mtrr_init_secondary_cpu  */
-
-#endif  /*  __SMP__  */
+}   /*  End Function intel_mtrr_init_secondary_cpu  */
 
-/*
- *	The extended memory handling is available on the K6-III and the
- *	K6-II stepping 8 and higher only.
- */
- 
-static int k6_has_ranges(void)
+__initfunc(void mtrr_init_secondary_cpu (void))
 {
-	if(boot_cpu_data.x86 !=5)
-		return 0;
-	if(boot_cpu_data.x86_model == 9 ||
-		(boot_cpu_data.x86_model == 8 && 
-		 boot_cpu_data.x86_mask >= 8))
-		 return 1;
-	return 0;
-}
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	intel_mtrr_init_secondary_cpu ();
+	break;
+      case X86_VENDOR_CYRIX:
+	/* This is _completely theoretical_!
+	 * I assume here that one day Cyrix will support Intel APIC.
+	 * In reality on non-Intel CPUs we won't even get to this routine.
+	 * Hopefully no one will plug two Cyrix processors in a dual P5 board.
+	 *  :-)
+	 */
+	cyrix_arr_init_secondary ();
+	break;
+      default:
+	printk ("mtrr: SMP support incomplete for this vendor\n");
+	break;
+    }
+}   /*  End Function mtrr_init_secondary_cpu  */
+#endif  /*  __SMP__  */
 
 __initfunc(int mtrr_init(void))
 {
-    if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD  && k6_has_ranges())
-    {
-#  ifdef CONFIG_PROC_FS
-	proc_register (&proc_root, &proc_root_mtrr);
-#  endif
-    	mtrr_flags|=MTRR_PRESENT|MTRR_WRCOMB;
-    	init_table();
-    	return 0;
-    }
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) )
-    	return 0;
-#  ifndef __SMP__
-    printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
-#  endif
-
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
 #  ifdef __SMP__
-    finalize_mtrr_state (&smp_mtrr_state);
-    mtrr_state_warn (smp_changes_mask);
-#  endif /* __SMP__ */
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	finalize_mtrr_state (&smp_mtrr_state);
+	mtrr_state_warn (smp_changes_mask);
+	break;
+    }
+#  else /* __SMP__ */
+    mtrr_setup ();
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_CYRIX:
+	cyrix_arr_init ();
+	break;
+    }
+#  endif  /*  !__SMP__  */
 
 #  ifdef CONFIG_PROC_FS
     proc_register (&proc_root, &proc_root_mtrr);
 #  endif
 
-    mtrr_flags|=MTRR_PRESENT;
     init_table ();
     return 0;
 }   /*  End Function mtrr_init  */
diff -urN linux-2.2.8-pre5/arch/i386/kernel/setup.c linux-2.2.8-pre6/arch/i386/kernel/setup.c
--- linux-2.2.8-pre5/arch/i386/kernel/setup.c	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/arch/i386/kernel/setup.c	2003-08-15 15:06:14.000000000 -0700
@@ -5,6 +5,10 @@
  *
  *  Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
  *  and Martin Mares, November 1997.
+ *
+ *  Force Cyrix 6x86(MX) and M II processors to report MTRR capability
+ *  and fix against Cyrix "coma bug" by
+ *      Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
  */
 
 /*
@@ -395,6 +399,14 @@
 	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
 	c->x86_model_id[48] = 0;
+	/*  Set MTRR capability flag if appropriate  */
+	if(boot_cpu_data.x86 !=5)
+		return 1;
+	if((boot_cpu_data.x86_model == 9) ||
+	   ((boot_cpu_data.x86_model == 8) && 
+	    (boot_cpu_data.x86_mask >= 8)))
+		c->x86_capability |= X86_FEATURE_MTRR;
+
 	return 1;
 }
 
@@ -574,6 +586,10 @@
 			(c->x86_model)++;
 		} else             /* 686 */
 			p = Cx86_cb+1;
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		c->x86_capability |= X86_FEATURE_MTRR;
+		/* 6x86's contain this bug */
+		c->coma_bug = 1;
 		break;
 
 	case 4: /* MediaGX/GXm */
@@ -598,11 +614,14 @@
 
         case 5: /* 6x86MX/M II */
 		if (dir1 > 7) dir0_msn++;  /* M II */
+		else c->coma_bug = 1;      /* 6x86MX, it has the bug. */
 		tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
 		Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
 		p = Cx86_cb+tmp;
         	if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
 			(c->x86_model)++;
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		c->x86_capability |= X86_FEATURE_MTRR;
 		break;
 
 	case 0xf:  /* Cyrix 486 without DEVID registers */
@@ -856,7 +875,7 @@
 	int sep_bug;
 	static char *x86_cap_flags[] = {
 	        "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
-	        "cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
+	        "cx8", "9", "10", "sep", "mtrr", "pge", "14", "cmov",
 	        "16", "17", "psn", "19", "20", "21", "22", "mmx",
 	        "24", "kni", "26", "27", "28", "29", "30", "31"
 	};
@@ -904,7 +923,6 @@
 		} else if (c->x86_vendor == X86_VENDOR_INTEL) {
 			x86_cap_flags[6] = "pae";
 			x86_cap_flags[9] = "apic";
-			x86_cap_flags[12] = "mtrr";
 			x86_cap_flags[14] = "mca";
 			x86_cap_flags[16] = "pat";
 			x86_cap_flags[17] = "pse36";
@@ -923,6 +941,7 @@
 			        "hlt_bug\t\t: %s\n"
 			        "sep_bug\t\t: %s\n"
 			        "f00f_bug\t: %s\n"
+			        "coma_bug\t: %s\n"
 			        "fpu\t\t: %s\n"
 			        "fpu_exception\t: %s\n"
 			        "cpuid level\t: %d\n"
@@ -932,6 +951,7 @@
 			     c->hlt_works_ok ? "no" : "yes",
 			     sep_bug ? "yes" : "no",
 			     c->f00f_bug ? "yes" : "no",
+			     c->coma_bug ? "yes" : "no",
 			     c->hard_math ? "yes" : "no",
 			     (c->hard_math && ignore_irq13) ? "yes" : "no",
 			     c->cpuid_level,
diff -urN linux-2.2.8-pre5/arch/i386/kernel/smp.c linux-2.2.8-pre6/arch/i386/kernel/smp.c
--- linux-2.2.8-pre5/arch/i386/kernel/smp.c	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/arch/i386/kernel/smp.c	2003-08-15 15:06:14.000000000 -0700
@@ -44,6 +44,8 @@
 
 #include "irq.h"
 
+#define JIFFIE_TIMEOUT 100
+
 extern void update_one_process( struct task_struct *p,
 				unsigned long ticks, unsigned long user,
 				unsigned long system, int cpu);
@@ -1651,15 +1653,84 @@
 	send_IPI_allbutself(STOP_CPU_VECTOR);
 }
 
-/*
- * this function sends an 'reload MTRR state' IPI to all other CPUs
- * in the system. it goes straight through, completion processing
- * is done on the mttr.c level.
+/* Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
  */
-
-void smp_send_mtrr(void)
+struct smp_call_function_struct {
+	void (*func) (void *info);
+	void *info;
+	atomic_t unstarted_count;
+	atomic_t unfinished_count;
+	int wait;
+};
+static volatile struct smp_call_function_struct *smp_call_function_data = NULL;
+
+/*
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+int smp_call_function (void (*func) (void *info), void *info, int retry,
+		       int wait)
+/*  [SUMMARY] Run a function on all other CPUs.
+    <func> The function to run. This must be fast and non-blocking.
+    <info> An arbitrary pointer to pass to the function.
+    <retry> If true, keep retrying until ready.
+    <wait> If true, wait until function has completed on other CPUs.
+    [RETURNS] 0 on success, else a negative status code. Does not return until
+    remote CPUs are nearly ready to execute <<func>> or are or have executed.
+*/
 {
-	send_IPI_allbutself(MTRR_CHANGE_VECTOR);
+	unsigned long timeout;
+	struct smp_call_function_struct data;
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+	if (retry) {
+		while (1) {
+			if (smp_call_function_data) {
+				schedule ();  /*  Give a mate a go  */
+				continue;
+			}
+			spin_lock (&lock);
+			if (smp_call_function_data) {
+				spin_unlock (&lock);  /*  Bad luck  */
+				continue;
+			}
+			/*  Mine, all mine!  */
+			break;
+		}
+	}
+	else {
+		if (smp_call_function_data) return -EBUSY;
+		spin_lock (&lock);
+		if (smp_call_function_data) {
+			spin_unlock (&lock);
+			return -EBUSY;
+		}
+	}
+	smp_call_function_data = &data;
+	spin_unlock (&lock);
+	data.func = func;
+	data.info = info;
+	atomic_set (&data.unstarted_count, smp_num_cpus - 1);
+	data.wait = wait;
+	if (wait) atomic_set (&data.unfinished_count, smp_num_cpus - 1);
+	/*  Send a message to all other CPUs and wait for them to respond  */
+	send_IPI_allbutself (CALL_FUNCTION_VECTOR);
+	/*  Wait for response  */
+	timeout = jiffies + JIFFIE_TIMEOUT;
+	while ( (atomic_read (&data.unstarted_count) > 0) &&
+		time_before (jiffies, timeout) )
+		barrier ();
+	if (atomic_read (&data.unstarted_count) > 0) {
+		smp_call_function_data = NULL;
+		return -ETIMEDOUT;
+	}
+	if (wait)
+		while (atomic_read (&data.unfinished_count) > 0)
+			barrier ();
+	smp_call_function_data = NULL;
+	return 0;
 }
 
 /*
@@ -1798,12 +1869,19 @@
 	stop_this_cpu();
 }
 
-void (*mtrr_hook) (void) = NULL;
-
-asmlinkage void smp_mtrr_interrupt(void)
+asmlinkage void smp_call_function_interrupt(void)
 {
-	ack_APIC_irq();
-	if (mtrr_hook) (*mtrr_hook)();
+	void (*func) (void *info) = smp_call_function_data->func;
+	void *info = smp_call_function_data->info;
+	int wait = smp_call_function_data->wait;
+
+	ack_APIC_irq ();
+	/*  Notify initiating CPU that I've grabbed the data and am about to
+	    execute the function  */
+	atomic_dec (&smp_call_function_data->unstarted_count);
+	/*  At this point the structure may be out of scope unless wait==1  */
+	(*func) (info);
+	if (wait) atomic_dec (&smp_call_function_data->unfinished_count);
 }
 
 /*
diff -urN linux-2.2.8-pre5/CREDITS linux-2.2.8-pre6/CREDITS
--- linux-2.2.8-pre5/CREDITS	1999-04-23 08:42:03.000000000 -0700
+++ linux-2.2.8-pre6/CREDITS	2003-08-15 15:06:14.000000000 -0700
@@ -256,6 +256,10 @@
 D: Configuration help text support
 D: Linux CD and Support Giveaway List
 
+N: Zoltan Boszormenyi
+E: zboszor@mol.hu
+D: MTRR emulation with Cyrix style ARR registers
+
 N: John Boyd
 E: boyd@cis.ohio-state.edu
 D: Co-author of wd7000 SCSI driver
diff -urN linux-2.2.8-pre5/Documentation/Configure.help linux-2.2.8-pre6/Documentation/Configure.help
--- linux-2.2.8-pre5/Documentation/Configure.help	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/Documentation/Configure.help	2003-08-15 15:06:14.000000000 -0700
@@ -8666,17 +8666,24 @@
 
 MTRR control and configuration
 CONFIG_MTRR
-  On Intel Pentium Pro and Pentium II systems the Memory Type Range
-  Registers (MTRRs) may be used to control processor access to memory
-  ranges. This is most useful when you have a video (VGA) card on a
-  PCI or AGP bus. Enabling write-combining allows bus write transfers
-  to be combined into a larger transfer before bursting over the
-  PCI/AGP bus. This can increase performance of image write operations
-  2.5 times or more. This option creates a /proc/mtrr file which may
-  be used to manipulate your MTRRs. Typically the X server should use
-  this. This should have a reasonably generic interface so that
-  similar control registers on other processors can be easily
-  supported.
+  On Intel P6 family processors (Pentium Pro, Pentium II and later)
+  the Memory Type Range Registers (MTRRs) may be used to control
+  processor access to memory ranges. This is most useful when you have
+  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
+  allows bus write transfers to be combined into a larger transfer
+  before bursting over the PCI/AGP bus. This can increase performance
+  of image write operations 2.5 times or more. This option creates a
+  /proc/mtrr file which may be used to manipulate your
+  MTRRs. Typically the X server should use this. This should have a
+  reasonably generic interface so that similar control registers on
+  other processors can be easily supported.
+
+  The Cyrix 6x86, 6x86MX and M II processors have Address Range
+  Registers (ARRs) which provide a similar functionality to MTRRs. For
+  these, the ARRs are used to emulate the MTRRs.
+
+  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
+  MTRRs. These are supported.
 
   Saying Y here also fixes a problem with buggy SMP BIOSes which only
   set the MTRRs for the boot CPU and not the secondary CPUs. This can
diff -urN linux-2.2.8-pre5/Documentation/mtrr.txt linux-2.2.8-pre6/Documentation/mtrr.txt
--- linux-2.2.8-pre5/Documentation/mtrr.txt	1998-05-02 17:42:08.000000000 -0700
+++ linux-2.2.8-pre6/Documentation/mtrr.txt	2003-08-15 15:06:14.000000000 -0700
@@ -62,6 +62,23 @@
 ioctl() interface, so users won't have to do anything. If you use a
 commercial X server, lobby your vendor to add support for MTRRs.
 ===============================================================================
+Creating overlapping MTRRs:
+
+%echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
+%echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
+
+And the results: cat /proc/mtrr
+reg00: base=0x00000000 (   0MB), size=  64MB: write-back, count=1
+reg01: base=0xfb000000 (4016MB), size=  16MB: write-combining, count=1
+reg02: base=0xfb000000 (4016MB), size=   4kB: uncachable, count=1
+
+Some cards (especially Voodoo Graphics boards) need this 4 kB area 
+excluded from the beginning of the region because it is used for
+registers.
+
+NOTE: You can only create type=uncachable region, if the first
+region that you created is type=write-combining.
+===============================================================================
 Removing MTRRs from the shell:
 % echo "disable=2" >! /proc/mtrr
 ===============================================================================
diff -urN linux-2.2.8-pre5/Documentation/networking/ip-sysctl.txt linux-2.2.8-pre6/Documentation/networking/ip-sysctl.txt
--- linux-2.2.8-pre5/Documentation/networking/ip-sysctl.txt	2003-08-15 15:06:13.000000000 -0700
+++ linux-2.2.8-pre6/Documentation/networking/ip-sysctl.txt	2003-08-15 15:06:14.000000000 -0700
@@ -211,4 +211,4 @@
 Updated by:
 Andi Kleen
 ak@muc.de
-$Id: ip-sysctl.txt,v 1.8 1999/01/02 16:37:06 davem Exp $
+$Id: ip-sysctl.txt,v 1.9 1999/05/08 02:58:44 davem Exp $
diff -urN linux-2.2.8-pre5/drivers/char/lp.c linux-2.2.8-pre6/drivers/char/lp.c
--- linux-2.2.8-pre5/drivers/char/lp.c	1999-03-11 09:27:06.000000000 -0800
+++ linux-2.2.8-pre6/drivers/char/lp.c	2003-08-15 15:06:14.000000000 -0700
@@ -202,9 +202,7 @@
 /* Test if the printer is not acking the strobe */
 #define	LP_NO_ACKING(status)	((status) & LP_PACK)
 /* Test if the printer has error conditions */
-#define LP_NO_ERROR(status)					\
-	 (((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) ==	\
-	 (LP_PSELECD|LP_PERRORP))
+#define LP_NO_ERROR(status)	((status) & LP_PERRORP)
 
 #undef LP_DEBUG
 #undef LP_READ_DEBUG
@@ -424,7 +422,10 @@
 {
 	unsigned int last = lp_table[minor].last_error;
 	unsigned char status = r_str(minor);
-	if ((status & LP_POUTPA)) {
+	if (status & LP_PERRORP)
+		/* No error. */
+		last = 0;
+	else if ((status & LP_POUTPA)) {
 		if (last != LP_POUTPA) {
 			last = LP_POUTPA;
 			printk(KERN_INFO "lp%d out of paper\n", minor);
@@ -434,13 +435,12 @@
 			last = LP_PSELECD;
 			printk(KERN_INFO "lp%d off-line\n", minor);
 		}
-	} else if (!(status & LP_PERRORP)) {
+	} else {
 		if (last != LP_PERRORP) {
 			last = LP_PERRORP;
-			printk(KERN_INFO "lp%d on fire!\n", minor);
+			printk(KERN_INFO "lp%d on fire\n", minor);
 		}
 	}
-	else last = 0;
 
 	lp_table[minor].last_error = last;
 
diff -urN linux-2.2.8-pre5/drivers/char/mem.c linux-2.2.8-pre6/drivers/char/mem.c
--- linux-2.2.8-pre5/drivers/char/mem.c	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/drivers/char/mem.c	2003-08-15 15:06:14.000000000 -0700
@@ -57,7 +57,10 @@
 #ifdef CONFIG_USB_OHCI
 int ohci_init(void);
 #endif
-
+#ifdef CONFIG_USB_OHCI_HCD
+int ohci_hcd_init(void);
+#endif
+     
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
 			    const char * buf, size_t count, loff_t *ppos)
 {
@@ -612,6 +615,9 @@
 #ifdef CONFIG_USB_OHCI
 	ohci_init();
 #endif
+#ifdef CONFIG_USB_OHCI_HCD
+        ohci_hcd_init(); 
+#endif
 #endif
 #if defined (CONFIG_FB)
 	fbmem_init();
diff -urN linux-2.2.8-pre5/drivers/char/planb.c linux-2.2.8-pre6/drivers/char/planb.c
--- linux-2.2.8-pre5/drivers/char/planb.c	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/drivers/char/planb.c	2003-08-15 15:06:14.000000000 -0700
@@ -29,7 +29,6 @@
 
 /* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */
 
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/init.h>
 #include <linux/errno.h>
diff -urN linux-2.2.8-pre5/drivers/Makefile linux-2.2.8-pre6/drivers/Makefile
--- linux-2.2.8-pre5/drivers/Makefile	1999-04-24 18:45:18.000000000 -0700
+++ linux-2.2.8-pre6/drivers/Makefile	2003-08-15 15:06:14.000000000 -0700
@@ -47,7 +47,11 @@
 ifeq ($(CONFIG_USB),y)
 SUB_DIRS += usb
 MOD_SUB_DIRS += usb
-endif
+else
+  ifeq ($(CONFIG_USB),m)
+  MOD_SUB_DIRS += usb
+  endif
+endif 
 
 # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel,
 # but some of the low-level things may also be modules.
diff -urN linux-2.2.8-pre5/drivers/misc/parport_ieee1284.c linux-2.2.8-pre6/drivers/misc/parport_ieee1284.c
--- linux-2.2.8-pre5/drivers/misc/parport_ieee1284.c	1999-03-11 09:27:06.000000000 -0800
+++ linux-2.2.8-pre6/drivers/misc/parport_ieee1284.c	2003-08-15 15:06:14.000000000 -0700
@@ -48,25 +48,22 @@
 int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) 
 {
 	/* make sure it's a valid state, set nStrobe & nAutoFeed high */
-	parport_write_control(port, (parport_read_control(port) \
-		& ~1 ) & ~2);
+	parport_frob_control (port, (1|2), 0);
 	udelay(1);
 	parport_write_data(port, mode);
 	udelay(400);
 	/* nSelectIn high, nAutoFd low */
-	parport_write_control(port, (parport_read_control(port) & ~8) | 2);
+	parport_frob_control(port, (2|8), 2);
 	if (parport_wait_peripheral(port, 0x78, 0x38)) {
-		parport_write_control(port, 
-				      (parport_read_control(port) & ~2) | 8);
+		parport_frob_control(port, (2|8), 8);
 		return 0; 
 	}
 	/* nStrobe low */
-	parport_write_control(port, parport_read_control(port) | 1);
+	parport_frob_control (port, 1, 1);
 	udelay(1);				     /* Strobe wait */
 	/* nStrobe high, nAutoFeed low, last step before transferring 
 	 *  reverse data */
-	parport_write_control(port, (parport_read_control(port) \
-		& ~1) & ~2);
+	parport_frob_control (port, (1|2), 0);
 	udelay(1);
 	/* Data available? */
 	parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK);
diff -urN linux-2.2.8-pre5/drivers/misc/parport_pc.c linux-2.2.8-pre6/drivers/misc/parport_pc.c
--- linux-2.2.8-pre5/drivers/misc/parport_pc.c	1999-03-11 09:27:06.000000000 -0800
+++ linux-2.2.8-pre6/drivers/misc/parport_pc.c	2003-08-15 15:06:14.000000000 -0700
@@ -53,6 +53,8 @@
    than PARPORT_MAX (in <linux/parport.h>).  */
 #define PARPORT_PC_MAX_PORTS  8
 
+static int user_specified = 0;
+
 static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
@@ -103,19 +105,24 @@
 
 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);
 }
 
 unsigned char parport_pc_read_control(struct parport *p)
 {
-	return inb(p->base+CONTROL);
+	struct parport_pc_private *priv = p->private_data;
+	return priv->ctr;
 }
 
 unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
 {
-	unsigned char old = inb(p->base+CONTROL);
-	outb(((old & ~mask) ^ val), p->base+CONTROL);
-	return old;
+	struct parport_pc_private *priv = p->private_data;
+	unsigned char ctr = priv->ctr;
+	ctr = (ctr & ~mask) ^ val;
+	outb (ctr, p->base+CONTROL);
+	return priv->ctr = ctr; /* update soft copy */
 }
 
 void parport_pc_write_status(struct parport *p, unsigned char d)
@@ -345,6 +352,8 @@
  */
 static int parport_SPP_supported(struct parport *pb)
 {
+	unsigned char r, w;
+
 	/*
 	 * first clear an eventually pending EPP timeout 
 	 * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
@@ -354,14 +363,54 @@
 	parport_pc_epp_clear_timeout(pb);
 
 	/* Do a simple read-write test to make sure the port exists. */
-	parport_pc_write_control(pb, 0xc);
-	parport_pc_write_data(pb, 0xaa);
-	if (parport_pc_read_data(pb) != 0xaa) return 0;
-	
-	parport_pc_write_data(pb, 0x55);
-	if (parport_pc_read_data(pb) != 0x55) return 0;
+	w = 0xc;
+	parport_pc_write_control(pb, w);
+
+	/* Can we read from the control register?  Some ports don't
+	 * 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);
+	if ((r & 0x3f) == w) {
+		w = 0xe;
+		parport_pc_write_control (pb, w);
+		r = inb (pb->base+CONTROL);
+		parport_pc_write_control (pb, 0xc);
+		if ((r & 0x3f) == w)
+			return PARPORT_MODE_PCSPP;
+	}
+
+	if (user_specified)
+		/* That didn't work, but the user thinks there's a
+		 * port here. */
+		printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
+			pb->base, w, r);
+
+	/* Try the data register.  The data lines aren't tri-stated at
+	 * this stage, so we expect back what we wrote. */
+	w = 0xaa;
+	parport_pc_write_data (pb, w);
+	r = parport_pc_read_data (pb);
+	if (r == w) {
+		w = 0x55;
+		parport_pc_write_data (pb, w);
+		r = parport_pc_read_data (pb);
+		if (r == w)
+			return PARPORT_MODE_PCSPP;
+	}
+
+	if (user_specified)
+		/* Didn't work with 0xaa, but the user is convinced
+		 * this is the place. */
+		printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
+			pb->base, w, r);
+
+	/* It's possible that we can't read the control register or
+	   the data register.  In that case just believe the user. */
+	if (user_specified)
+		return PARPORT_MODE_PCSPP;
 
-	return PARPORT_MODE_PCSPP;
+	return 0;
 }
 
 /* Check for ECP
@@ -712,6 +761,15 @@
 	if (check_region(base, 3)) return 0;
 	if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops)))
 		return 0;
+	p->private_data = kmalloc (sizeof (struct parport_pc_private),
+				   GFP_KERNEL);
+	if (!p->private_data) {
+		/* Not enough memory. */
+		printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
+		parport_unregister_port (p);
+		return 0;
+	}
+	((struct parport_pc_private *) (p->private_data))->ctr = 0xc;
 	if (p->base != 0x3bc) {
 		if (!check_region(base+0x400,3)) {
 			p->modes |= parport_ECR_present(p);	
@@ -725,6 +783,7 @@
 	}
 	if (!parport_SPP_supported(p)) {
 		/* No port. */
+		kfree (p->private_data);
 		parport_unregister_port (p);
 		return 0;
 	}
@@ -787,6 +846,7 @@
 	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++));
 		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
@@ -829,6 +889,7 @@
 			if (!(p->flags & PARPORT_FLAG_COMA)) 
 				parport_quiesce(p);
 			parport_proc_unregister(p);
+			kfree (p->private_data);
 			parport_unregister_port(p);
 		}
 		p = tmp;
diff -urN linux-2.2.8-pre5/drivers/net/ethertap.c linux-2.2.8-pre6/drivers/net/ethertap.c
--- linux-2.2.8-pre5/drivers/net/ethertap.c	1998-10-23 08:12:32.000000000 -0700
+++ linux-2.2.8-pre6/drivers/net/ethertap.c	2003-08-15 15:06:14.000000000 -0700
@@ -98,6 +98,7 @@
 
 	ether_setup(dev);
 
+	dev->hard_header_len = 16;
 	dev->tx_queue_len = 0;
 	dev->flags|=IFF_NOARP;
 	tap_map[dev->base_addr]=dev;
diff -urN linux-2.2.8-pre5/drivers/usb/Config.in linux-2.2.8-pre6/drivers/usb/Config.in
--- linux-2.2.8-pre5/drivers/usb/Config.in	1999-04-28 11:14:03.000000000 -0700
+++ linux-2.2.8-pre6/drivers/usb/Config.in	2003-08-15 15:06:14.000000000 -0700
@@ -16,6 +16,10 @@
   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
+    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
+    fi
 
     bool 'USB mouse support' CONFIG_USB_MOUSE
     bool 'USB keyboard support' CONFIG_USB_KBD
diff -urN linux-2.2.8-pre5/drivers/usb/Makefile linux-2.2.8-pre6/drivers/usb/Makefile
--- linux-2.2.8-pre5/drivers/usb/Makefile	1999-04-28 11:14:03.000000000 -0700
+++ linux-2.2.8-pre6/drivers/usb/Makefile	2003-08-15 15:06:14.000000000 -0700
@@ -59,7 +59,17 @@
   endif
 endif
 
-
+ifeq ($(CONFIG_USB_OHCI_HCD),y)
+  ifeq ($(CONFIG_USB), y)
+    L_OBJS += ohci-hcd.o ohci-root-hub.o
+  else
+    ifeq ($(CONFIG_USB),m)
+      USBO_OBJS += ohci-hcd.o ohci-root-hub.o
+      M_OBJS += usb-ohci-hcd.o
+      MIX_OBJS += $(USBX_OBJS)
+    endif
+  endif
+endif
 include $(TOPDIR)/Rules.make
 
 keymap.o: keymap.c
@@ -73,3 +83,6 @@
 usb-ohci.o: ohci.o ohci-debug.o $(USBX_OBJS)
 	$(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o $(USBX_OBJS)
 
+usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
+       
diff -urN linux-2.2.8-pre5/drivers/usb/ohci-hcd.c linux-2.2.8-pre6/drivers/usb/ohci-hcd.c
--- linux-2.2.8-pre5/drivers/usb/ohci-hcd.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.8-pre6/drivers/usb/ohci-hcd.c	2003-08-15 15:06:14.000000000 -0700
@@ -0,0 +1,1488 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ *
+ * The OHCI HCD layer is a simple but nearly complete implementation of what the
+ * USB people would call a HCD  for the OHCI. 
+ * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+ * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
+ * 
+ * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
+ * [ Open Host Controller Interface driver for USB. ]
+ * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
+ * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
+ * [ $Log: ohci.c,v $ ]
+ * [ Revision 1.1  1999/04/05 08:32:30  greg ]
+ * 
+ * 
+ * v2.1 1999/05/09 ep_addr correction, code clean up
+ * v2.0 1999/05/04 
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c) (APM not tested; hub, usb_device, bus and related stuff)
+ * from Greg Smith (ohci.c) (reset controller handling, hub)
+ * 
+ * v1.0 1999/04/27 initial release
+ * ohci-hcd.c
+ */
+
+/* #define OHCI_DBG  */  /* printk some debug information */
+
+ 
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "usb.h"
+#include "ohci-hcd.h"
+#include "inits.h" 
+
+ 
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+static int apm_resume = 0;
+#endif
+
+ 
+
+static struct wait_queue *control_wakeup;         
+static struct wait_queue *root_hub = NULL;
+ 
+static __u8 cc_to_status[16] = { /* mapping of the OHCI CC to the UHCI status codes; first guess */
+/* Activ, Stalled, Data Buffer Err, Babble Detected : NAK recvd, CRC/Timeout, Bitstuff, reservd */
+/* No  Error  */		0x00,
+/* CRC Error  */		0x04,
+/* Bit Stuff  */		0x02,
+/* Data Togg  */ 		0x40,
+/* Stall      */		0x40,
+/* DevNotResp */		0x04,
+/* PIDCheck   */		0x04,
+/* UnExpPID   */		0x40,
+/* DataOver   */		0x20,
+/* DataUnder  */ 		0x20,
+/* reservd    */		0x40,
+/* reservd    */		0x40,
+/* BufferOver */		0x20,
+/* BuffUnder  */		0x20,
+/* Not Access */		0x80,
+/* Not Access */		0x80
+ };
+ 
+ 
+/********
+ **** Interface functions
+ ***********************************************/
+ 
+static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
+{
+
+	struct ohci * ohci = ohci_in; 
+	usb_device_irq handler=(void *) lw0;
+	void *dev_id = (void *) lw1;
+	int ret;
+	
+	OHCI_DEBUG({ int i; printk("USB HC IRQ <<<: %x: data(%d):", ep_addr, data_len);)
+	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+	
+ 	ret = handler(cc_to_status[status & 0xf], data, dev_id);
+	if(ret == 0) return 0; /* 0 .. do not requeue  */
+	if(status > 0) return -1; /* error occured do not requeue ? */
+	ohci_trans_req(ohci, ep_addr, 0, NULL, data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); /* requeue int request */
+	return 0;
+}
+
+static int sohci_ctrl_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw)
+{  
+	*(int * )lw0 = status;
+	wake_up(&control_wakeup);
+
+	OHCI_DEBUG( { int i; printk("USB HC CTRL<<<: %x: ctrl(%d):", ep_addr, ctrl_len);)
+	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) ctrl)[i]);)
+	OHCI_DEBUG( printk(" data(%d):", data_len);) 
+	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+    return 0;                       
+} 
+                                                             
+static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+{
+	struct ohci * ohci = usb_dev->bus->hcpriv;
+	union ep_addr_ ep_addr;
+	
+	ep_addr.iep = 0;
+	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */
+				| (pipe  & 0x80)  	 			/* direction */
+				| (1 << 5);						/* type = int*/
+	ep_addr.bep.fa = ((pipe >> 8) & 0x7f);			/* device address */
+
+	OHCI_DEBUG( printk("USB HC IRQ >>>: %x: every %d ms\n", ep_addr.iep, period);) 
+	
+	usb_ohci_add_ep(ohci, ep_addr.iep, period, 1, sohci_int_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
+	
+   	ohci_trans_req(ohci, ep_addr.iep, 0, NULL, ((struct ohci_device *) usb_dev->hcpriv)->data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id);
+	return 0;
+}
+
+
+static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
+{
+	struct wait_queue wait = { current, NULL }; 
+	struct ohci * ohci = usb_dev->bus->hcpriv;
+	int status;
+	union ep_addr_ ep_addr;
+
+    ep_addr.iep = 0;
+	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */		
+				| (pipe  & 0x80)  				/* direction */
+				|  (1 << 6);					/* type = ctrl*/
+	ep_addr.bep.fa	= ((pipe >> 8) & 0x7f);				/* device address */
+	
+	status = 0xf; /* CC not Accessed */
+	OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: %x: ctrl(%d):", ep_addr.iep, 8);)
+	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) cmd)[i]);)
+	OHCI_DEBUG( printk(" data(%d):", len);) 
+	OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk("\n"); })
+	
+	usb_ohci_add_ep(ohci, ep_addr.iep, 0, 1, sohci_ctrl_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
+	
+	current->state = TASK_UNINTERRUPTIBLE;
+    add_wait_queue(&control_wakeup, &wait);   
+ 
+	ohci_trans_req(ohci, ep_addr.iep, 8, cmd, data, len, (__OHCI_BAG) &status, 0);
+
+	schedule_timeout(HZ/10);
+
+    remove_wait_queue(&control_wakeup, &wait); 
+     
+    OHCI_DEBUG(printk("USB HC status::: %x\n", cc_to_status[status & 0x0f]);)
+     
+	return cc_to_status[status & 0x0f];
+}
+
+
+static int sohci_usb_deallocate(struct usb_device *usb_dev) {
+    struct ohci_device *dev = usb_to_ohci(usb_dev); 
+	union ep_addr_ ep_addr;
+
+	ep_addr.iep = 0;
+	
+	OHCI_DEBUG(printk("USB HC dealloc %x\n", usb_dev->devnum);)
+
+	/* wait_ms(20); */
+
+	if(usb_dev->devnum >=0) {
+		ep_addr.bep.fa = usb_dev->devnum;
+    	usb_ohci_rm_function(((struct ohci_device *)usb_dev->hcpriv)->ohci, ep_addr.iep);
+	}
+	
+    USB_FREE(dev);
+	USB_FREE(usb_dev);
+
+	return 0;
+}
+
+static struct usb_device *sohci_usb_allocate(struct usb_device *parent) {
+ 
+	struct usb_device *usb_dev;
+	struct ohci_device *dev;
+	
+	
+	USB_ALLOC(usb_dev, sizeof(*usb_dev));
+	if (!usb_dev)
+		return NULL;
+		
+	memset(usb_dev, 0, sizeof(*usb_dev));
+
+	USB_ALLOC(dev, sizeof(*dev));
+	if (!dev) {
+		USB_FREE(usb_dev);
+		return NULL;
+	}
+
+	/* Initialize "dev" */
+	memset(dev, 0, sizeof(*dev));
+
+	usb_dev->hcpriv = dev;
+	dev->usb = usb_dev;
+
+	usb_dev->parent = parent;
+
+	if (parent) {
+		usb_dev->bus = parent->bus;
+		dev->ohci = usb_to_ohci(parent)->ohci;
+	}
+	return usb_dev;
+}
+
+struct usb_operations sohci_device_operations = {
+	sohci_usb_allocate,
+	sohci_usb_deallocate,
+	sohci_control_msg,
+	sohci_request_irq,
+};
+
+ 
+/******
+ *** ED handling functions
+ ************************************/
+
+
+
+/* 
+ * search for the right place to insert an interrupt ed into the int tree 
+ * do some load ballancing
+ * */
+
+static int usb_ohci_int_ballance(struct ohci * ohci, int interval, int load) {
+
+  int i,j;
+  
+  j = 0;   /* search for the least loaded interrupt endpoint branch of all 32 branches */
+  for(i=0; i< 32; i++) if(ohci->ohci_int_load[j] > ohci->ohci_int_load[i]) j=i; 
+
+  if(interval < 1) interval = 1;
+  if(interval > 32) interval = 32;
+  for(i= 0; ((interval >> i) > 1 ); interval &= (0xfffe << i++ )); /* interval = 2^int(ld(interval)) */
+  
+
+  for(i=j%interval; i< 32; i+=interval) ohci->ohci_int_load[i] += load;
+  j = interval + (j % interval); 
+  
+  OHCI_DEBUG(printk("USB HC new int ed on pos : %x \n",j);)
+  
+  return j;
+}
+
+/* get the ed from the endpoint / device adress */
+
+struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in) {
+
+union ep_addr_ ep_addr;
+struct usb_ohci_ed *tmp;
+unsigned int mask;
+
+mask = 0;
+ep_addr.iep = ep_addr_in;
+
+#ifdef VROOTHUB
+ if(ep_addr.bep.fa == ohci->root_hub_funct_addr) {
+ 	if((ep_addr.bep.ep & 0x0f) == 0)
+ 		return &ohci->ed_rh_ep0; /* root hub ep0 */
+ 	else
+ 		return &ohci->ed_rh_epi; /* root hub int ep */
+ }
+#endif
+
+ tmp = ohci->ed_func_ep0[ep_addr.bep.fa];
+ mask = ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); 
+ ep_addr.bep.ep &= mask; /* mask out direction of ctrl ep */
+ 
+  while (tmp != NULL) {
+    if (tmp->ep_addr.iep == ep_addr.iep) 
+      return tmp;
+    tmp = tmp->ed_list;
+  }
+  return NULL;
+}
+ 
+spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+/* add a new endpoint ep_addr */
+struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr_in, int interval, int load, f_handler handler, int ep_size, int speed) {
+   
+  struct usb_ohci_ed * ed; 
+  struct usb_ohci_td * td;
+  union ep_addr_ ep_addr;
+ 
+   
+  int int_junk;
+ 
+  struct usb_ohci_ed *tmp;
+
+  ep_addr.iep = ep_addr_in ;
+  ep_addr.bep.ep &= ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); /* mask out direction of ctrl ep */
+
+  spin_lock(&usb_ed_lock);
+  
+  tmp =  ohci_find_ep(ohci, ep_addr.iep);
+  if (tmp != NULL) { 
+  
+#ifdef VROOTHUB
+  	if(ep_addr.bep.fa == ohci->root_hub_funct_addr) {
+ 		if((ep_addr.bep.ep & 0x0f) != 0) { /* root hub int ep */
+			ohci->ed_rh_epi.handler = handler;
+ 			ohci_init_rh_int_timer(ohci, interval);
+ 		}
+ 		else { /* root hub ep0 */
+ 			 ohci->ed_rh_ep0.handler = handler;
+ 		}			 	
+ 	}
+
+ 	else 
+#endif 
+
+ 		{
+ 		tmp->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7)
+  		
+    	| (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0)
+    	| (speed << 13)
+    	| ep_size <<16;
+ 
+  		tmp->handler = handler; 
+  	}
+ 	spin_unlock(&usb_ed_lock);
+    return tmp;    /* ed  already in use */
+  }
+  
+  
+  OHCI_ALLOC(td, sizeof(td)); /* dummy td; end of td list for ed */
+  OHCI_ALLOC(ed, sizeof(ed));
+  td->prev_td = NULL;
+  
+  ed->hw.tail_td = virt_to_bus(&td->hw);
+  ed->hw.head_td = ed->hw.tail_td;
+  ed->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7)
+  /*  | ((ep_addr.bep.port & 0x80)? 0x1000 : 0x0800 ) */
+    | (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0)
+    | (speed << 13)
+    | ep_size <<16;
+  
+  ed->handler = handler;
+
+  switch((ep_addr.bep.ep >> 5) & 0x03) {
+  case CTRL:
+    ed->hw.next_ed = 0;
+    if(ohci->ed_controltail == NULL) {
+      writel(virt_to_bus(&ed->hw), &ohci->regs->ed_controlhead);
+    }
+    else {
+      ohci->ed_controltail->hw.next_ed = virt_to_bus(&ed->hw);
+    }
+    ed->ed_prev = ohci->ed_controltail;
+    ohci->ed_controltail = ed;	  
+    break;
+  case BULK:  
+    ed->hw.next_ed = 0;
+    if(ohci->ed_bulktail == NULL) {
+      writel(virt_to_bus(&ed->hw), &ohci->regs->ed_bulkhead);
+    }
+    else {
+      ohci->ed_bulktail->hw.next_ed = virt_to_bus(&ed->hw);
+    }
+    ed->ed_prev = ohci->ed_bulktail;
+    ohci->ed_bulktail = ed;	  
+    break;
+  case INT:
+    int_junk = usb_ohci_int_ballance(ohci, interval, load);
+    ed->hw.next_ed = ohci->hc_area->ed[int_junk].next_ed; 
+    ohci->hc_area->ed[int_junk].next_ed = virt_to_bus(&ed->hw);
+    ed->ed_prev = (struct usb_ohci_ed *) &ohci->hc_area->ed[int_junk];
+    break;
+  case ISO:
+    ed->hw.next_ed = 0;
+    ohci->ed_isotail->hw.next_ed = virt_to_bus(&ed->hw);
+    ed->ed_prev = ohci->ed_isotail;
+    ohci->ed_isotail = ed;	  
+    break;
+  }
+  ed->ep_addr  = ep_addr;
+  
+  /* Add it to the "hash"-table of known endpoint descriptors */      
+  
+  ed->ed_list = ohci->ed_func_ep0[ed->ep_addr.bep.fa];
+  ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed; 
+
+  spin_unlock(&usb_ed_lock);
+  
+  OHCI_DEBUG(printk("USB HC new ed %x: %x :", ep_addr.iep, (unsigned int ) ed); )
+  OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; )
+  return 0;
+}
+
+/*****
+ * Request the removal of an endpoint
+ * 
+ * put the ep on the rm_list and request a stop of the bulk or ctrl list 
+ * real removal is done at the next start of frame hardware interrupt 
+ */
+int usb_ohci_rm_ep(struct ohci * ohci, struct  usb_ohci_ed *ed)
+{    
+  unsigned int flags;
+  struct usb_ohci_ed *tmp;
+  
+  OHCI_DEBUG(printk("USB HC remove ed %x: %x :\n", ed->ep_addr.iep, (unsigned int ) ed); )
+
+  spin_lock_irqsave(&usb_ed_lock, flags);
+
+  tmp = ohci->ed_func_ep0[ed->ep_addr.bep.fa];
+  if (tmp == NULL) {
+  	spin_unlock_irqrestore(&usb_ed_lock, flags);
+    return 0;
+  }
+
+  if(tmp == ed) {
+     ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed->ed_list;
+  }
+  else {
+    while (tmp->ed_list != ed) {
+      if (tmp->ed_list == NULL) {
+        spin_unlock_irqrestore(&usb_ed_lock, flags);
+		return 0;
+	  }
+      tmp = tmp->ed_list;
+    }
+    tmp->ed_list = ed->ed_list;
+  }
+  ed->ed_list = ohci->ed_rm_list;
+  ohci->ed_rm_list = ed;
+  ed->hw.info  |=  OHCI_ED_SKIP;
+
+  switch((ed->ep_addr.bep.ep >> 5) & 0x03) {
+  	case CTRL:
+    	writel_mask(~(0x01<<4), &ohci->regs->control); /* stop CTRL list */
+    	break;
+  	case BULK:
+    	writel_mask(~(0x01<<5), &ohci->regs->control); /* stop BULK list */
+    	break;
+  }
+
+
+  writel( OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
+
+  spin_unlock_irqrestore(&usb_ed_lock, flags);
+
+  return 1;
+}
+
+/* we have requested to stop the bulk or CTRL list,
+ * now we can remove the eds on the rm_list */
+ 
+static int ohci_rm_eds(struct ohci * ohci) {
+
+  unsigned int flags;
+  struct usb_ohci_ed *ed;
+  struct usb_ohci_ed *ed_tmp;
+  struct usb_ohci_td *td;
+  __u32 td_hw_tmp;
+  __u32 td_hw;
+  
+  spin_lock_irqsave(&usb_ed_lock, flags);
+
+  ed = ohci->ed_rm_list;
+
+  while (ed != NULL) {
+    
+    switch((ed->ep_addr.bep.ep >> 5) & 0x03) {
+    case CTRL: 
+      if(ed->ed_prev == NULL) {
+		writel(ed->hw.next_ed, &ohci->regs->ed_controlhead);
+      }
+      else {
+		ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      }
+      if(ohci->ed_controltail == ed) {
+		ohci->ed_controltail = ed->ed_prev;
+      }
+      break;
+    case BULK: 
+      if(ed->ed_prev == NULL) {
+		writel(ed->hw.next_ed, &ohci->regs->ed_bulkhead);
+      }
+      else {
+		ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      }
+      if(ohci->ed_bulktail == ed) {
+		ohci->ed_bulktail = ed->ed_prev;
+      }
+      break;
+    case INT: 
+      	ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      break;
+    case ISO:
+      ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      if(ohci->ed_isotail == ed) {
+		ohci->ed_isotail = ed->ed_prev;
+      }
+      break;
+    }
+    
+    if(ed->hw.next_ed != 0) ((struct usb_ohci_ed *) bus_to_virt(ed->hw.next_ed))->ed_prev = ed->ed_prev;
+    
+
+/* tds directly connected to ed */
+ 
+	td_hw = ed->hw.head_td & 0xfffffff0;
+    while(td_hw != 0) {
+    	td = bus_to_virt(td_hw);
+    	td_hw_tmp = td_hw;
+    	td_hw = td->hw.next_td;
+    	OHCI_FREE(td); /* free pending tds */ 
+    	if(td_hw_tmp == ed->hw.tail_td) break;
+    	
+    }
+     
+    /* mark TDs on the hc done list (if there are any) */      
+	td_hw = readl(&ohci->regs->donehead) & 0xfffffff0;
+    while(td_hw != 0) {
+    	td = bus_to_virt(td_hw);
+    	td_hw = td->hw.next_td;
+    	if(td->ep == ed) td->ep = 0;
+   	}
+ 
+    /* mark TDs on the hcca done list (if there are any) */      
+	td_hw = ohci->hc_area->hcca.done_head & 0xfffffff0 ;
+	
+    while(td_hw != 0) { 
+    	td = bus_to_virt(td_hw); 
+    	td_hw = td->hw.next_td;
+    	if(td->ep == ed) td->ep = 0;
+   	}
+
+    ed_tmp = ed;
+    ed = ed->ed_list;
+    OHCI_FREE(ed_tmp);  /* free ed */ 
+  }
+  writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
+  writel(0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
+  writel_set((0x01<<4), &ohci->regs->control);   /* start CTRL u. (BULK list) */ 
+
+  spin_unlock_irqrestore(&usb_ed_lock, flags);
+  
+  ohci->ed_rm_list = NULL;
+  OHCI_DEBUG(printk("USB HC after rm ed control: %4x  intrstat: %4x intrenable: %4x\n", readl(&ohci->regs->control),readl(&ohci->regs->intrstatus),readl(&ohci->regs->intrenable));)
+ 
+
+  return 0;
+}
+
+/* remove all endpoints of a function (device) */
+int usb_ohci_rm_function( struct ohci * ohci, unsigned int ep_addr_in)
+{    
+  struct usb_ohci_ed *ed;
+  struct usb_ohci_ed *tmp;
+  union ep_addr_ ep_addr;
+
+ 
+  
+  ep_addr.iep = ep_addr_in;
+
+  for(ed = ohci->ed_func_ep0[ep_addr.bep.fa]; ed != NULL;) {
+	tmp = ed;
+    ed = ed->ed_list;
+    usb_ohci_rm_ep(ohci, tmp);
+  }
+ 
+
+  
+  return 1;
+}
+
+
+
+
+
+/******
+ *** TD handling functions
+ ************************************/
+
+
+#define FILL_TD(TD_PT, HANDLER, INFO, DATA, LEN, LW0, LW1)  \
+    td_pt = (TD_PT); \
+    td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); \
+    td_pt1->ep = usb_ep; \
+    td_pt1->handler = (HANDLER); \
+    td_pt1->buffer_start = (DATA); \
+    td_pt1->lw0 = (LW0); \
+    td_pt1->lw1 = (LW1); \
+    td_pt1->hw.info = (INFO); \
+    td_pt1->hw.cur_buf = virt_to_bus(DATA); \
+    td_pt1->hw.buf_end = td_pt1->hw.cur_buf + (LEN) - 1; \
+    td_pt1->hw.next_td = virt_to_bus(td_pt); \
+    usb_ep->hw.tail_td = virt_to_bus(td_pt); \
+    td_pt->prev_td = td_pt1; \
+    td_pt->hw.next_td = 0
+
+spinlock_t usb_req_lock = SPIN_LOCK_UNLOCKED;
+
+int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) {
+
+  int ed_type;
+  unsigned int flags;
+  struct usb_ohci_td *td_pt;
+  struct usb_ohci_td *td_pt1;
+  struct usb_ohci_td *td_pt_a1, *td_pt_a2, *td_pt_a3;
+  struct usb_ohci_ed *usb_ep;
+  f_handler handler;
+
+  
+ td_pt_a1 =NULL;
+ td_pt_a2 =NULL;
+ td_pt_a3 =NULL;
+  
+  usb_ep = ohci_find_ep(ohci, ep_addr);
+  if(usb_ep == NULL ) return -1; /* not known ep */
+  
+  handler = usb_ep->handler;
+ 
+#ifdef VROOTHUB 
+  if(usb_ep == &ohci->ed_rh_ep0) { /* root hub ep 0 control endpoint */  
+    root_hub_control_msg(ohci, 8, ctrl, data, data_len, lw0, lw1, handler);
+    return 0;
+  }
+
+  if(usb_ep == &ohci->ed_rh_epi) { /* root hub interrupt endpoint */
+  
+    root_hub_int_req(ohci, 8, ctrl, data, data_len, lw0, lw1, handler);  
+	return 0;
+  }
+#endif
+  /*  struct usb_ohci_ed * usb_ep = usb_ohci_add_ep(pipe, ohci, interval, 1); */
+ 
+   ed_type = ((((union ep_addr_)ep_addr).bep.ep >> 5) & 0x07);
+  
+  switch(ed_type) {
+  case BULK_IN:
+  case BULK_OUT:   
+  case INT_IN:
+  case INT_OUT:    
+    OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1));
+    break;
+
+  case CTRL_IN:
+  case CTRL_OUT:
+    OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1));
+    OHCI_ALLOC(td_pt_a3, sizeof(td_pt_a3));  
+    if(data_len > 0) {
+      OHCI_ALLOC(td_pt_a2, sizeof(td_pt_a2));
+    }
+    break;
+
+  case ISO_IN:
+  case ISO_OUT:
+
+  }
+    
+  spin_lock_irqsave(&usb_req_lock, flags);
+  
+  switch(ed_type) {
+  case BULK_IN:
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 );
+    writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+    break;
+
+  case BULK_OUT: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 );
+    writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+    break;
+
+  case INT_IN: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 );  
+    break;
+
+  case INT_OUT: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 );
+    break;
+
+  case CTRL_IN: 
+    FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 );  
+    if(data_len > 0) { 
+      FILL_TD( td_pt_a2, NULL, TD_CC | TD_R |  TD_DP_IN | TD_T_DATA1, data, data_len, 0, 0 );  
+    } 
+    FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_OUT | TD_T_DATA1, NULL, 0, lw0, lw1 );
+    writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+    break;
+
+  case CTRL_OUT:     
+    FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 );  
+    if(data_len > 0) { 
+      FILL_TD( td_pt_a2, NULL, TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1, data, data_len, 0, 0 );  
+    } 
+    FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_IN | TD_T_DATA1, NULL, 0, lw0, lw1 );
+    writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+    break;
+
+  case ISO_IN:
+  case ISO_OUT:
+    break;
+  }
+
+
+  
+
+ td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); 
+
+ 
+  if(td_pt_a3 != NULL) td_pt_a3->prev_td = NULL;
+  	else if (td_pt_a2 != NULL) td_pt_a2->prev_td = NULL;
+  	  	else if (td_pt_a1 != NULL) td_pt_a1->prev_td = NULL;
+  	  
+  spin_unlock_irqrestore(&usb_req_lock, flags);
+  return 0;
+}
+
+
+/******
+ *** Done List handling functions
+ ************************************/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+ 
+static struct usb_ohci_td * ohci_reverse_done_list(struct ohci * ohci) {
+
+  __u32 td_list_hc;
+  struct usb_ohci_td      * td_list = NULL;
+  struct usb_ohci_td      * td_rev = NULL;
+  	
+	td_list_hc = ohci->hc_area->hcca.done_head & 0xfffffff0;
+    ohci->hc_area->hcca.done_head = 0;
+    
+ 	while(td_list_hc) {
+		
+		td_list = (struct  usb_ohci_td *) bus_to_virt(td_list_hc);
+		td_list->next_dl_td = td_rev;
+			
+		td_rev = td_list;
+		td_list_hc = td_list->hw.next_td & 0xfffffff0;
+	}
+ return td_list;
+}
+
+/* all done requests are replied here */
+static int usb_ohci_done_list(struct ohci *  ohci) {
+
+  struct usb_ohci_td      * td = NULL;
+  struct usb_ohci_td      * td_list; 
+  struct usb_ohci_td      * td_list_next = NULL;
+  struct usb_ohci_td      * td_err = NULL;
+	__u32 td_hw;
+ 
+	
+  td_list = ohci_reverse_done_list(ohci);
+
+  while(td_list) {
+   	td_list_next = td_list->next_dl_td;
+    td = td_list;
+
+    if(td->ep == NULL) { /* removed ep */
+   		OHCI_FREE(td_list);
+   		break;
+   	}
+   	
+   	/* the HC halts an ED if an error occurs; put all pendings TDs of an halted ED on the
+   	 * done list; they are marked with an 0xf CC_error code 
+   	 */
+   	 
+ 	if(TD_CC_GET(td_list->hw.info) != TD_CC_NOERROR) { /* on error move all pending tds of an ed into the done list */
+ 		printk("******* USB BUS error %x @ep %x\n", TD_CC_GET(td_list->hw.info), td_list->ep->ep_addr.iep);
+    td_err= td_list;
+	td_hw = td_list->ep->hw.head_td & 0xfffffff0;
+    while(td_hw != 0) { 
+    	if(td_hw == td_list->ep->hw.tail_td) break;
+    	td = bus_to_virt(td_hw);
+    	td_err->next_dl_td = td;
+    	td_err= td;
+    	td_hw = td->hw.next_td;
+    }
+    td_list->ep->hw.head_td = td_list->ep->hw.tail_td;
+    td->next_dl_td = td_list_next;
+    td_list_next = td_list->next_dl_td;
+ 	
+    }
+  /*  send the reply  */
+ 	if(td_list->handler != NULL)  {
+    	if(td_list->prev_td == NULL) {
+			td_list->handler((void *) ohci,
+						td_list->ep->ep_addr.iep,
+						0, 
+						NULL, 
+						td_list->buffer_start, 
+						td_list->hw.buf_end-virt_to_bus(td_list->buffer_start)+1, 
+						TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1);
+			OHCI_FREE(td_list);			
+   	  	}
+      	else {
+      		if(td_list->prev_td->prev_td == NULL) { /* cntrl 2 Transactions dataless */
+	  		td_list->handler((void *) ohci,
+	  		            td_list->ep->ep_addr.iep,
+	  					td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1,
+	  					td_list->prev_td->buffer_start, 
+	  					NULL,
+	  					0, 
+	  					(TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1);
+			OHCI_FREE(td_list->prev_td);
+			OHCI_FREE(td_list);
+			}
+			else { /* cntrl 3 Transactions */
+	  			td_list->handler((void *) ohci,
+	  					td_list->ep->ep_addr.iep, 
+	  					td_list->prev_td->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->prev_td->buffer_start)+1, 
+	  					td_list->prev_td->prev_td->buffer_start, 
+	  					td_list->prev_td->buffer_start, 
+	  					td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1, 
+	  					(TD_CC_GET(td_list->prev_td->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->prev_td->hw.info)
+	  						: (TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1); 
+				OHCI_FREE(td_list->prev_td->prev_td);			
+				OHCI_FREE(td_list->prev_td);
+				OHCI_FREE(td_list);
+					
+			}
+      	} 
+    	
+    }
+    td_list = td_list_next;
+  }  
+  return 0; 
+}
+
+
+
+/******
+ *** HC functions
+ ************************************/
+ 
+
+ 
+void reset_hc(struct ohci *ohci) {
+	int retries = 5;
+	int timeout = 30;
+	int fminterval;
+	
+	if(readl(&ohci->regs->control) & 0x100) { /* SMM owns the HC */
+		writel(0x08,  &ohci->regs->cmdstatus); /* request ownership */
+		printk("USB HC TakeOver from SMM\n");
+		do {
+			wait_ms(100);
+			if(--retries) { 
+				printk("USB HC TakeOver timed out!\n");
+				break;
+			}
+		}
+		while(readl(&ohci->regs->control) & 0x100); 
+	}	
+		
+	writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+	OHCI_DEBUG(printk("USB HC reset_hc: %x ; retries: %d\n", readl(&ohci->regs->control), 5-retries);)
+	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+	writel(1,  &ohci->regs->cmdstatus);	   /* HC Reset */
+	while ((readl(&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
+		if (--timeout == 0) {
+			printk("USB HC reset timed out!\n");
+			return;
+		}	
+		udelay(1);
+	}
+	/* set the timing */
+	fminterval |= (((fminterval -210) * 6)/7)<<16; 
+	writel(fminterval, &ohci->regs->fminterval);
+	writel(((fminterval&0x3fff)*9)/10, &ohci->regs->periodicstart);
+}
+
+
+/*
+ * Reset and start an OHCI controller
+ */
+void start_hc(struct ohci *ohci)
+{
+   /*  int fminterval; */
+    unsigned int mask;
+  /*  fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+	reset_hc(ohci); */
+ 
+
+	writel(virt_to_bus(&ohci->hc_area->hcca), &ohci->regs->hcca); /* a reset clears this */
+ 
+	/* Choose the interrupts we care about now, others later on demand */
+	mask = OHCI_INTR_MIE | OHCI_INTR_WDH;
+	/* | OHCI_INTR_SO | OHCI_INTR_UE |OHCI_INTR_RHSC |OHCI_INTR_SF|  
+		OHCI_INTR_FNO */
+		
+
+	 
+	writel((0x00), &ohci->regs->control); /* USB Reset BUS */
+	wait_ms(10);
+	  
+	writel((0x97), &ohci->regs->control); /* USB Operational  */
+	
+ 	writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */
+	wait_ms(50); 
+		
+	OHCI_DEBUG(printk("USB HC rstart_hc_operational: %x\n", readl(&ohci->regs->control)); )
+ 	OHCI_DEBUG(printk("USB HC roothubstata: %x \n", readl( &(ohci->regs->roothub.a) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstatb: %x \n", readl( &(ohci->regs->roothub.b) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstatu: %x \n", readl( &(ohci->regs->roothub.status) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) )); )
+   	OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) )); )
+  
+	/* control_wakeup = NULL; */
+	writel(mask, &ohci->regs->intrenable);
+	writel(mask, &ohci->regs->intrstatus);
+ 
+#ifdef VROOTHUB
+	{
+
+	struct usb_device * usb_dev;
+	struct ohci_device *dev;
+
+	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+	dev = usb_dev->hcpriv; 
+
+	dev->ohci = ohci; 
+
+	usb_connect(usb_dev);
+
+	ohci->root_hub->usb->children[0] = usb_dev;
+
+	usb_new_device(usb_dev);
+	}
+#endif
+
+ 
+	
+}
+
+
+
+
+static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
+{
+  struct ohci *ohci = __ohci;
+  struct ohci_regs *regs = ohci->regs;
+ 
+  int ints; 
+
+ 
+ if((ohci->hc_area->hcca.done_head != 0) && !(ohci->hc_area->hcca.done_head & 0x01)) {
+    ints =  OHCI_INTR_WDH;
+  }
+  else { 
+    if((ints = (readl(&regs->intrstatus) & readl(&regs->intrenable))) == 0)
+      return;
+   } 
+   
+  ohci->intrstatus |= ints;
+  OHCI_DEBUG(printk("USB HC interrupt: %x (%x) \n", ints, readl(&ohci->regs->intrstatus));)
+
+  /* ints &= ~(OHCI_INTR_WDH);  WH Bit will be set by done list subroutine */
+ /*  if(ints & OHCI_INTR_FNO) {
+   	writel(OHCI_INTR_FNO,  &regs->intrstatus);
+   	if (waitqueue_active(&ohci_tasks)) wake_up(&ohci_tasks);
+  } */
+  
+  if(ints & OHCI_INTR_WDH) {
+   	writel(OHCI_INTR_WDH,  &regs->intrdisable);	
+   	ohci->intrstatus &= (~OHCI_INTR_WDH);
+	usb_ohci_done_list(ohci); /* prepare out channel list */
+	writel(OHCI_INTR_WDH, &ohci->regs->intrstatus);
+	writel(OHCI_INTR_WDH, &ohci->regs->intrenable);
+   	 
+  }
+  
+  if(ints & OHCI_INTR_SF) {
+  	writel(OHCI_INTR_SF,  &regs->intrdisable);	
+  	writel(OHCI_INTR_SF, &ohci->regs->intrstatus);
+	ohci->intrstatus &= (~OHCI_INTR_SF);
+  	if(ohci->ed_rm_list != NULL) {
+			ohci_rm_eds(ohci);
+ 	 }
+  }
+#ifndef VROOTHUB 
+  if(ints & OHCI_INTR_RHSC) {  
+  	writel(OHCI_INTR_RHSC, &regs->intrdisable);
+  	writel(OHCI_INTR_RHSC, &ohci->regs->intrstatus);
+	wake_up(&root_hub);
+
+  }
+ #endif
+
+  writel(OHCI_INTR_MIE, &regs->intrenable);
+	
+}
+ 
+#ifndef VROOTHUB
+/*
+ * This gets called if the connect status on the root
+ * hub (and the root hub only) changes.
+ */
+static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr)
+{
+	struct usb_device *usb_dev;
+    struct ohci_device *dev;
+	OHCI_DEBUG(printk("uhci_connect_change: called for %d stat %x\n", port_nr,readl(&ohci->regs->roothub.portstatus[port_nr]) );)
+
+	/*
+	 * Even if the status says we're connected,
+	 * the fact that the status bits changed may
+	 * that we got disconnected and then reconnected.
+	 *
+	 * So start off by getting rid of any old devices..
+	 */
+	usb_disconnect(&ohci->root_hub->usb->children[port_nr]);
+
+	 if(!(readl(&ohci->regs->roothub.portstatus[port_nr]) & RH_PS_CCS)) {
+	 	writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[port_nr]);
+		return; /* nothing connected */
+	}
+	/*
+	 * Ok, we got a new connection. Allocate a device to it,
+	 * and find out what it wants to do..
+	 */
+	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+	dev = usb_dev->hcpriv; 
+	dev->ohci = ohci; 
+	usb_connect(dev->usb);
+	ohci->root_hub->usb->children[port_nr] = usb_dev;
+	wait_ms(200); /* wait for powerup */
+    /* reset port/device */
+ 	writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[port_nr]); /* reset port */
+ 	while(!(readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_PRSC)) wait_ms(10); /* reset active ? */
+ 	writel(RH_PS_PES, &ohci->regs->roothub.portstatus[port_nr]); /* enable port */
+ 	wait_ms(10);
+	/* Get speed information */
+	usb_dev->slow = (readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_LSDA) ? 1 : 0;
+
+	/*
+	 * Ok, all the stuff specific to the root hub has been done.
+	 * The rest is generic for any new USB attach, regardless of
+	 * hub type.
+	 */
+	usb_new_device(usb_dev);
+}
+#endif
+ 
+
+
+/*
+ * Allocate the resources required for running an OHCI controller.
+ * Host controller interrupts must not be running while calling this
+ * function.
+ *
+ * The mem_base parameter must be the usable -virtual- address of the
+ * host controller's memory mapped I/O registers.
+ *
+ * This is where OHCI triumphs over UHCI, because good is dumb.
+ * Note how much simpler this function is than in uhci.c.
+ *
+ * OHCI hardware takes care of most of the scheduling of different
+ * transfer types with the correct prioritization for us.
+ */
+
+
+static struct ohci *alloc_ohci(void* mem_base)
+{
+	int i,j;
+	struct ohci *ohci;
+	struct ohci_hc_area *hc_area;
+	struct usb_bus *bus;
+	struct ohci_device *dev;
+	struct usb_device *usb;
+
+	/*
+	 * Here we allocate some dummy  EDs as well as the
+	 * OHCI host controller communications area.  The HCCA is just
+	 * a nice pool of memory with pointers to endpoint descriptors
+	 * for the different interrupts.
+	 *
+	 * The first page of memory  contains the HCCA and ohci structure
+	 */
+	hc_area = (struct  ohci_hc_area *) __get_free_pages(GFP_KERNEL, 1);
+	if (!hc_area)
+		return NULL;
+	memset(hc_area, 0, sizeof(*hc_area));
+    ohci = &hc_area->ohci;
+	ohci->irq = -1;
+	ohci->regs = mem_base;
+    
+	ohci->hc_area = hc_area;
+	/* Tell the controller where the HCCA is */
+	writel(virt_to_bus(&hc_area->hcca), &ohci->regs->hcca);
+	
+ 
+	/*
+	 * Initialize the ED polling "tree",  full tree;
+         * dummy eds ed[i] (hc should skip them) 
+         * i == 0 is the end of the iso list;
+		 * 1 is the   1ms node, 
+         * 2,3        2ms nodes,
+         * 4,5,6,7    4ms nodes,
+         * 8  ... 15  8ms nodes,
+         * 16 ... 31  16ms nodes,
+         * 32 ... 63  32ms nodes
+         * Sequenzes:
+		 * 32-16- 8-4-2-1-0
+         * 33-17- 9-5-3-1-0
+         * 34-18-10-6-2-1-0
+         * 35-19-11-7-3-1-0
+         * 36-20-12-4-2-1-0
+         * 37-21-13-5-3-1-0
+         * 38-22-14-6-2-1-0
+         * 39-23-15-7-3-1-0
+         * 40-24- 8-4-2-1-0
+         * 41-25- 9-5-3-1-0
+         * 42-26-10-6-2-1-0
+         *     :      :
+         * 63-31-15-7-3-1-0
+	 */
+        hc_area->ed[ED_ISO].info |=  OHCI_ED_SKIP; /* place holder, so skip it */
+        hc_area->ed[ED_ISO].next_ed =  0x0000;       /* end of iso list */
+
+        hc_area->ed[1].next_ed = virt_to_bus(&(hc_area->ed[ED_ISO]));
+        hc_area->ed[1].info |=  OHCI_ED_SKIP; /* place holder, skip it */
+	     
+        j=1;
+        for (i = 2; i < (NUM_INTS * 2); i++) {
+          	if (i >= NUM_INTS) 
+	   		 	hc_area->hcca.int_table[i - NUM_INTS] = virt_to_bus(&(hc_area->ed[i]));
+           
+          	if( i == j*4) j *= 2;
+	    	hc_area->ed[i].next_ed = virt_to_bus(&(hc_area->ed[j+ i%j]));
+            hc_area->ed[i].info |=  OHCI_ED_SKIP; /* place holder, skip it */
+        }
+
+
+	/*
+	 * for load ballancing of the interrupt branches 
+	 */
+	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+
+	/*
+	 * Store the end of control and bulk list eds. So, we know where we can add
+	 * elements to these lists.
+	 */
+	ohci->ed_isotail     = (struct usb_ohci_ed *) &(hc_area->ed[ED_ISO]);
+        ohci->ed_controltail = NULL;
+        ohci->ed_bulktail    = NULL;
+	
+	/*
+	 * Tell the controller where the control and bulk lists are
+	 * The lists are empty now.
+	 */	
+	writel(0, &ohci->regs->ed_controlhead);
+	writel(0, &ohci->regs->ed_bulkhead);
+
+	
+	USB_ALLOC(bus, sizeof(*bus));
+	if (!bus)
+		return NULL;
+
+	memset(bus, 0, sizeof(*bus));
+
+	ohci->bus = bus;
+	bus->hcpriv = (void *) ohci;
+	bus->op = &sohci_device_operations;
+
+	 
+	usb = sohci_usb_allocate(NULL);
+	if (!usb)
+		return NULL;
+
+	dev = ohci->root_hub = usb_to_ohci(usb);
+
+	usb->bus = bus;
+	/* bus->root_hub = ohci_to_usb(ohci->root_hub); */
+	dev->ohci = ohci;
+	
+	/* Initialize the root hub */
+	 
+	usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
+	usb_init_root_hub(usb);
+
+	return ohci;
+} 
+
+
+/*
+ * De-allocate all resources..
+ */
+
+static void release_ohci(struct ohci *ohci)
+{
+	int i;
+	union ep_addr_ ep_addr;
+	ep_addr.iep = 0;
+	
+    OHCI_DEBUG(printk("USB HC release ohci \n");)
+    
+	if (ohci->irq >= 0) {
+		free_irq(ohci->irq, ohci);
+		ohci->irq = -1;
+	}
+
+    /* stop hc */
+	writel(OHCI_USB_SUSPEND, &ohci->regs->control);
+		
+	/* deallocate all EDs and TDs */
+	for(i=0; i < 128; i ++) {
+		ep_addr.bep.fa = i;
+		usb_ohci_rm_function(ohci, ep_addr.iep);
+	}
+	ohci_rm_eds(ohci); /* remove eds */
+	
+    /* disconnect all devices */    
+	if(ohci->root_hub)
+		for(i = 0; i < ohci->root_hub->usb->maxchild; i++)
+			  usb_disconnect(ohci->root_hub->usb->children + i);
+	    
+    USB_FREE(ohci->root_hub->usb);
+    USB_FREE(ohci->root_hub);
+    USB_FREE(ohci->bus);
+    
+	/* unmap the IO address space */
+	iounmap(ohci->regs);
+       
+	
+	free_pages((unsigned int) ohci->hc_area, 1);
+	
+}
+
+ 
+void cleanup_drivers(void);
+
+static int ohci_roothub_thread(void * __ohci)
+{
+        struct ohci *ohci = (struct ohci *)__ohci;
+        lock_kernel(); 
+
+        /*
+         * This thread doesn't need any user-level access,
+         * so get rid of all our resources..
+         */
+        printk("ohci_roothub_thread at %p\n", &ohci_roothub_thread);
+        exit_mm(current);
+        exit_files(current);
+        exit_fs(current);
+
+
+        strcpy(current->comm, "root-hub");
+
+         
+		start_hc(ohci);
+		writel( 0x10000, &ohci->regs->roothub.status);
+		wait_ms(50); /* root hub power on */
+         do {
+#ifdef CONFIG_APM
+		if (apm_resume) {
+			apm_resume = 0;
+			start_hc(ohci);
+			continue;
+		}
+#endif
+ 	 
+         OHCI_DEBUG(printk("USB RH tasks: int: %x\n", ohci->intrstatus); )
+#ifndef VROOTHUB
+		/*	if (ohci->intrstatus & OHCI_INTR_RHSC)  */
+			{
+				int port_nr;
+	     		for(port_nr=0; port_nr< ohci->root_hub->usb->maxchild; port_nr++)
+	     			if(readl(&ohci->regs->roothub.portstatus[port_nr]) & (RH_PS_CSC | RH_PS_PRSC)) {		
+	     		 		ohci_connect_change(ohci, port_nr);
+	     		 		writel(0xffff0000, &ohci->regs->roothub.portstatus[port_nr]);
+	     		 	}
+	     		 ohci->intrstatus &= ~(OHCI_INTR_RHSC);
+	     		 writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
+	    	}
+#endif
+ 
+         interruptible_sleep_on(&root_hub);
+ 
+      	} while (!signal_pending(current)); 
+             	
+#ifdef VROOTHUB
+		ohci_del_rh_int_timer(ohci);
+#endif
+ 
+
+		cleanup_drivers();
+      /*  reset_hc(ohci); */
+	 
+        release_ohci(ohci);
+        MOD_DEC_USE_COUNT;
+
+	    printk("ohci_control_thread exiting\n");
+
+        return 0;
+}
+
+
+ 
+
+/*
+ * Increment the module usage count, start the control thread and
+ * return success.
+ */
+static int found_ohci(int irq, void* mem_base)
+{
+	int retval;
+	struct ohci *ohci;
+    OHCI_DEBUG(printk("USB HC found  ohci: irq= %d membase= %x \n", irq, (int)mem_base);)
+	/* Allocate the running OHCI structures */
+	ohci = alloc_ohci(mem_base);
+	if (!ohci) {
+	  return -ENOMEM;
+	}
+
+	reset_hc(ohci);
+
+	retval = -EBUSY;
+	if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
+		int pid;
+
+		MOD_INC_USE_COUNT; 
+		ohci->irq = irq;
+		 
+		pid = kernel_thread(ohci_roothub_thread, ohci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+		if (pid >= 0) 
+		 	return 0;
+		
+
+		MOD_DEC_USE_COUNT;
+		retval = pid;
+	}
+	
+	release_ohci(ohci);
+	return retval;
+}
+ 
+static int start_ohci(struct pci_dev *dev)
+{
+	unsigned int mem_base = dev->base_address[0];
+
+	/* If its OHCI, its memory */
+	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
+		return -ENODEV;
+
+	/* Get the memory address and map it for IO */
+	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	/* 
+	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
+	 * as the Alpha) [?]  What should I use instead...
+	 *
+	 * The iounmap() is done on in release_ohci.
+	 */
+	mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
+
+	if (!mem_base) {
+		printk("Error mapping OHCI memory\n");
+		return -EFAULT;
+	}
+
+	return found_ohci(dev->irq, (void *) mem_base);
+} 
+
+
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+	static int down = 0;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (down) {
+			printk(KERN_DEBUG "ohci: received extra suspend event\n");
+			break;
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (!down) {
+			printk(KERN_DEBUG "ohci: received bogus resume event\n");
+			break;
+		}
+		down = 0;
+		if (waitqueue_active(&root_hub)) {
+			apm_resume = 1;
+			wake_up(&root_hub);
+		}
+		break;
+	}
+	return 0;
+}
+#endif
+
+
+ int usb_mouse_init(void); 
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+	apm_unregister_callback(&handle_apm_event);
+#endif
+}
+
+#define ohci_hcd_init init_module
+
+#endif
+
+#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
+#define PCI_CLASS_SERIAL_USB_OHCI_PG 0x10
+ 
+
+int ohci_hcd_init(void)
+{
+  int retval;
+  struct pci_dev *dev = NULL;
+ 
+  retval = -ENODEV;
+   
+  dev = NULL;
+  while((dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev))) { /* OHCI */
+    retval = start_ohci(dev);
+    if (retval < 0) break;
+
+    
+#ifdef CONFIG_USB_MOUSE
+		usb_mouse_init();
+#endif
+#ifdef CONFIG_USB_KBD		
+		usb_kbd_init();
+#endif		
+		hub_init();
+#ifdef CONFIG_USB_AUDIO		
+		usb_audio_init();
+#endif		
+#ifdef CONFIG_APM
+		apm_register_callback(&handle_apm_event);
+#endif
+  
+    return 0;
+  }
+  return retval;
+}
+
+void cleanup_drivers(void)
+{
+	 hub_cleanup(); 
+#ifdef CONFIG_USB_MOUSE
+	 usb_mouse_cleanup();
+#endif
+}
+
diff -urN linux-2.2.8-pre5/drivers/usb/ohci-hcd.h linux-2.2.8-pre6/drivers/usb/ohci-hcd.h
--- linux-2.2.8-pre5/drivers/usb/ohci-hcd.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.8-pre6/drivers/usb/ohci-hcd.h	2003-08-15 15:06:14.000000000 -0700
@@ -0,0 +1,402 @@
+ /*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ *
+ * The OHCI HCD layer is a simple but nearly complete implementation of what the
+ * USB people would call a HCD  for the OHCI. 
+ * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+ * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
+ * 
+ * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
+ * [ Open Host Controller Interface driver for USB. ]
+ * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
+ * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
+ * [ $Log: ohci.c,v $ ]
+ * [ Revision 1.1  1999/04/05 08:32:30  greg ]
+ * 
+ * 
+ * v2.1 1999/05/09 ep_addr correction, code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27
+ * ohci-hcd.h
+ */
+
+#ifdef CONFIG_USB_OHCI_VROOTHUB
+#define VROOTHUB  
+#endif
+/* enables virtual root hub 
+ * (root hub will be managed by the hub controller 
+ *  hub.c of the alternate usb driver)
+ *  last time I did more testing without virtual root hub 
+ *  -> the virtual root hub could be more unstable now */
+ 
+ 
+  
+#ifdef OHCI_DBG
+#define OHCI_DEBUG(X) X
+#else 
+#define OHCI_DEBUG(X)
+#endif 
+
+/* for readl writel functions */
+#include <linux/list.h>
+#include <asm/io.h>
+
+/* for ED and TD structures */
+
+typedef void * __OHCI_BAG;
+typedef int (*f_handler )(void * ohci, unsigned int ep_addr, int cmd_len, void *cmd, void *data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1);
+
+
+
+struct ep_address {
+  __u8 ep;  /* bit 7: IN/-OUT, 6,5: type 10..CTRL 00..ISO  11..BULK 10..INT, 3..0: ep nr */ 
+  __u8 fa;    /* function address */
+  __u8 hc;
+  __u8 host;
+};
+
+union ep_addr_ {
+  unsigned int iep;
+  struct ep_address bep;
+};
+
+/*
+ * ED and TD descriptors has to be 16-byte aligned
+ */
+struct ohci_hw_ed {
+  __u32 info;       
+  __u32 tail_td;	/* TD Queue tail pointer */
+  __u32 head_td;	/* TD Queue head pointer */
+  __u32 next_ed;	/* Next ED */
+} __attribute((aligned(16)));
+
+
+struct usb_ohci_ed {
+  struct ohci_hw_ed hw;
+  /*  struct ohci * ohci; */
+  f_handler handler;
+  union ep_addr_ ep_addr;
+  struct usb_ohci_ed *ed_list;
+  struct usb_ohci_ed *ed_prev;
+} __attribute((aligned(32)));
+
+ /* OHCI Hardware fields */
+struct ohci_hw_td {     
+  __u32 info;
+  __u32 cur_buf;		/* Current Buffer Pointer */
+  __u32 next_td;		/* Next TD Pointer */
+  __u32 buf_end;		/* Memory Buffer End Pointer */
+} __attribute((aligned(16)));
+
+/* TD info field */
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x04)
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R        0x00040000
+#define TD_DI       0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+/* CC Codes */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED     0x0F
+
+
+
+struct usb_ohci_td {
+  struct ohci_hw_td hw;
+  void *  buffer_start;
+  f_handler handler; 
+  struct usb_ohci_td *prev_td;
+  struct usb_ohci_ed *ep;
+  struct usb_ohci_td *next_dl_td;
+  __OHCI_BAG lw0;
+  __OHCI_BAG lw1;
+} __attribute((aligned(32)));
+
+
+
+/* TD types */
+#define BULK		0x03
+#define INT			0x01
+#define CTRL		0x02
+#define ISO			0x00
+/* TD types with direction */
+#define BULK_IN		0x07
+#define BULK_OUT	0x03
+#define INT_IN		0x05
+#define INT_OUT		0x01
+#define CTRL_IN		0x06
+#define CTRL_OUT	0x02
+#define ISO_IN		0x04
+#define ISO_OUT		0x00
+
+struct ohci_rep_td {
+  int cmd_len;
+  void * cmd;
+  void * data;
+  int data_len;
+  f_handler handler;
+  struct ohci_rep_td *next_td;
+  int ep_addr;
+  __OHCI_BAG lw0;
+  __OHCI_BAG lw1;
+  __u32 status;
+} __attribute((aligned(32))); 
+
+#define OHCI_ED_SKIP	(1 << 14)
+#define OHCI_ED_MPS	(0x7ff << 16)
+#define OHCI_ED_F_NORM	(0)
+#define OHCI_ED_F_ISOC	(1 << 15)
+#define OHCI_ED_S_LOW	(1 << 13)
+#define OHCI_ED_S_HIGH	(0)
+#define OHCI_ED_D	(3 << 11)
+#define OHCI_ED_D_IN	(2 << 11)
+#define OHCI_ED_D_OUT	(1 << 11)
+#define OHCI_ED_EN	(0xf << 7)
+#define OHCI_ED_FA	(0x7f)
+
+ 
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+    __u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u32	done_head;		/* info returned for an interrupt */
+	u8		reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+  
+
+#define ED_INT_1	1
+#define ED_INT_2	2
+#define ED_INT_4	4
+#define ED_INT_8	8
+#define ED_INT_16	16
+#define ED_INT_32	32
+#define ED_CONTROL	64
+#define ED_BULK		65
+#define ED_ISO		0	/* same as 1ms interrupt queue */
+ 
+
+/*
+ * 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!)
+ * 
+ * Although I suppose several "ports" could be connected directly to
+ * internal laptop devices such as a keyboard, mouse, camera and
+ * serial/parallel ports.  hmm...  That'd be neat.
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[MAX_ROOT_PORTS];
+	} roothub;
+} __attribute((aligned(32)));
+
+
+/* 
+ * Read a MMIO register and re-write it after ANDing with (m)
+ */
+#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
+
+/*
+ * Read a MMIO register and re-write it after ORing with (b)
+ */
+#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
+
+/*
+ * cmdstatus register */
+#define OHCI_CLF  0x02
+#define OHCI_BLF  0x04
+
+/*
+ * Interrupt register masks
+ */
+#define OHCI_INTR_SO	(1)
+#define OHCI_INTR_WDH	(1 << 1)
+#define OHCI_INTR_SF	(1 << 2)
+#define OHCI_INTR_RD	(1 << 3)
+#define OHCI_INTR_UE	(1 << 4)
+#define OHCI_INTR_FNO	(1 << 5)
+#define OHCI_INTR_RHSC	(1 << 6)
+#define OHCI_INTR_OC	(1 << 30)
+#define OHCI_INTR_MIE	(1 << 31)
+
+/*
+ * Control register masks
+ */
+#define OHCI_USB_OPER		(2 << 6)
+#define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+struct ohci {
+    	int irq;
+	    struct ohci_regs *regs;					/* OHCI controller's memory */	
+	    struct ohci_hc_area *hc_area;			/* hcca, int ed-tree, ohci itself .. */                
+        int root_hub_funct_addr;                /* Address of Root Hub endpoint */       
+        int ohci_int_load[32];                       /* load of the 32 Interrupt Chains (for load ballancing)*/     
+        struct usb_ohci_ed * ed_rm_list;        /* list of all endpoints to be removed */
+        struct usb_ohci_ed * ed_bulktail;       /* last endpoint of bulk list */
+        struct usb_ohci_ed * ed_controltail;    /* last endpoint of control list */
+        struct usb_ohci_ed * ed_isotail;        /* last endpoint of iso list */
+        struct ohci_device * root_hub;
+        struct usb_ohci_ed ed_rh_ep0;
+        struct usb_ohci_ed ed_rh_epi;
+        struct ohci_rep_td *td_rh_epi;
+        int intrstatus;
+        struct usb_ohci_ed *ed_func_ep0[128];   /* "hash"-table for ep to ed mapping */
+        struct ohci_rep_td *repl_queue;			/* for internal requests */
+        int rh_int_interval;
+        int rh_int_timer;   
+        struct usb_bus *bus;
+       
+       
+};
+
+/*
+ *  Warning: This constant must not be so large as to cause the
+ *  ohci_device structure to exceed one 4096 byte page.  Or "weird
+ *  things will happen" as the alloc_ohci() function assumes that
+ *  its less than one page at the moment.  (FIXME)
+ */
+#define NUM_TDS	4		/* num of preallocated transfer descriptors */
+#define NUM_EDS 80		/* num of preallocated endpoint descriptors */
+
+struct ohci_hc_area {
+
+	struct ohci_hcca 	hcca;		/* OHCI mem. mapped IO area 256 Bytes*/
+
+	struct ohci_hw_ed		ed[NUM_EDS];	/* Endpoint Descriptors 80 * 16  : 1280 Bytes */
+	struct ohci_hw_td		td[NUM_TDS];	/* Transfer Descriptors 2 * 32   : 64 Bytes */
+        struct ohci             ohci;
+        
+};
+struct ohci_device {
+	struct usb_device	*usb;
+	struct ohci			*ohci;
+	unsigned long		data[16];
+};
+
+#define ohci_to_usb(uhci)	((ohci)->usb)
+#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
+
+/* Debugging code */
+/*void show_ed(struct ohci_ed *ed);
+void show_td(struct ohci_td *td);
+void show_status(struct ohci *ohci); */
+
+/* hcd */
+int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int cmd_len, void  *cmd, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1); 
+struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr, int interval, int load, f_handler handler, int ep_size, int speed);
+int usb_ohci_rm_function(struct ohci * ohci, unsigned int ep_addr); 
+int usb_ohci_rm_ep(struct ohci * ohci, struct  usb_ohci_ed *ed);
+struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in);
+
+/* roothub */
+int ohci_del_rh_int_timer(struct ohci * ohci);
+int	ohci_init_rh_int_timer(struct ohci * ohci, int interval);  	
+int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int root_hub_send_irq(struct ohci * ohci, void * data, int data_len );
+int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int send_replies(struct ohci * ohci);
+
+  
+ 
+
+/* Root-Hub Register info */
+
+#define RH_PS_CCS            0x00000001   
+#define RH_PS_PES            0x00000002   
+#define RH_PS_PSS            0x00000004   
+#define RH_PS_POCI           0x00000008   
+#define RH_PS_PRS            0x00000010  
+#define RH_PS_PPS            0x00000100   
+#define RH_PS_LSDA           0x00000200    
+#define RH_PS_CSC            0x00010000 
+#define RH_PS_PESC           0x00020000   
+#define RH_PS_PSSC           0x00040000    
+#define RH_PS_OCIC           0x00080000    
+#define RH_PS_PRSC           0x00100000   
+
+
+#ifdef OHCI_DBG
+#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d\n", -- __ohci_free_cnt)
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("OHCI ALLO: %d\n", ++ __ohci_free_cnt)
+#define USB_FREE(x) kfree(x); printk("USB FREE: %d\n", -- __ohci_free1_cnt)
+#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("USB ALLO: %d\n", ++ __ohci_free1_cnt)
+static int __ohci_free_cnt = 0;
+static int __ohci_free1_cnt = 0;
+#else
+#define OHCI_FREE(x) kfree(x) 
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) 
+#define USB_FREE(x) kfree(x) 
+#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) 
+#endif
+ 
diff -urN linux-2.2.8-pre5/drivers/usb/ohci-root-hub.c linux-2.2.8-pre6/drivers/usb/ohci-root-hub.c
--- linux-2.2.8-pre5/drivers/usb/ohci-root-hub.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.8-pre6/drivers/usb/ohci-root-hub.c	2003-08-15 15:06:14.000000000 -0700
@@ -0,0 +1,604 @@
+/*
+ * HCD (OHCI) Virtual Root Hub for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
+ *
+ * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
+ * This piece of code lets it look like it resides on the usb
+ * like the other hubs.
+ * (for anyone who wants to do a control operation on the root hub)
+ *  
+ * v2.1 1999/05/09 
+ * v2.0 1999/05/04
+ * v1.0 1999/04/27
+ * ohci-root-hub.c
+ *  
+ */
+ 
+
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+
+#include "usb.h"
+#include "ohci-hcd.h" 
+
+#ifdef VROOTHUB 
+
+#include "ohci-root-hub.h"
+
+
+static __u8 root_hub_dev_des[] =
+{
+        0x12,       /*  __u8  bLength; */
+		0x01,       /*  __u8  bDescriptorType; Device */
+		0x00,	    /*  __u16 bcdUSB; v1.0 */
+        0x01,
+		0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+		0x00,	    /*  __u8  bDeviceSubClass; */
+		0x00,       /*  __u8  bDeviceProtocol; */
+		0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+		0x00,       /*  __u16 idVendor; */
+        0x00,
+		0x00,       /*  __u16 idProduct; */
+        0x00,
+		0x00,       /*  __u16 bcdDevice; */
+        0x00,
+		0x00,       /*  __u8  iManufacturer; */
+		0x00,       /*  __u8  iProduct; */
+		0x00,       /*  __u8  iSerialNumber; */
+        0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+		0x09,       /*  __u8  bLength; */
+		0x02,       /*  __u8  bDescriptorType; Configuration */
+		0x19,       /*  __u16 wTotalLength; */
+        0x00,
+		0x01,       /*  __u8  bNumInterfaces; */
+		0x01,       /*  __u8  bConfigurationValue; */
+		0x00,       /*  __u8  iConfiguration; */
+		0x40,       /*  __u8  bmAttributes; 
+                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+		0x00,       /*  __u8  MaxPower; */
+      
+     /* interface */	  
+        0x09,       /*  __u8  if_bLength; */
+        0x04,       /*  __u8  if_bDescriptorType; Interface */
+        0x00,       /*  __u8  if_bInterfaceNumber; */
+        0x00,       /*  __u8  if_bAlternateSetting; */
+        0x01,       /*  __u8  if_bNumEndpoints; */
+        0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+        0x00,       /*  __u8  if_bInterfaceSubClass; */
+        0x00,       /*  __u8  if_bInterfaceProtocol; */
+        0x00,       /*  __u8  if_iInterface; */
+     
+     /* endpoint */
+        0x07,       /*  __u8  ep_bLength; */
+        0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+        0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+        0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+        0x40,       /*  __u16 ep_wMaxPacketSize; 64 Bytes */
+        0x00,
+        0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+/* 
+For OHCI we need just the  2nd Byte, so we 
+don't need this constant byte-array 
+
+static __u8 root_hub_hub_des[] =
+{ 
+        0x00,       *  __u8  bLength; *
+		0x29,       *  __u8  bDescriptorType; Hub-descriptor *
+        0x02,       *  __u8  bNbrPorts; *
+        0x00,       * __u16  wHubCharacteristics; *
+        0x00,
+        0x01,       *  __u8  bPwrOn2pwrGood; 2ms * 
+        0x00,       *  __u8  bHubContrCurrent; 0 mA *
+        0x00,       *  __u8  DeviceRemovable; *** 8 Ports max *** *
+        0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *
+};
+*/
+
+
+int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int leni, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler)
+{ 
+
+  __u32 stat;
+  __u32 rep_handler;
+  int req_reply=0;
+  union ep_addr_ ep_addr;
+  union ep_addr_ ep_addr_ret;
+        __u8 * cmd = rh_cmd;
+	__u8 * data = rh_data;
+	int i;
+	int len =leni;
+
+        __u8  bmRequestType = cmd[0];
+        __u8  bRequest      = cmd[1];
+        __u16 wValue        = cmd[3] << 8 | cmd [2];
+        __u16 wIndex        = cmd[5] << 8 | cmd [4];
+        __u16 wLength       = cmd[7] << 8 | cmd [6];
+printk("USB root hub: adr: %8x cmd(%8x): ", ohci->root_hub_funct_addr, 8);
+for(i=0;i<8;i++)
+	printk("%2x", ((char *)rh_cmd)[i]);
+ 
+printk(" ; \n");
+
+	ep_addr_ret.iep = 0;
+	ep_addr_ret.bep.fa = ohci->root_hub_funct_addr;
+	ep_addr_ret.bep.ep =  (bmRequestType & 0x80) | 0x40;
+
+  switch (bmRequestType | bRequest << 8) {
+   /* Request Destination:
+      without flags: Device, 
+      RH_INTERFACE: interface, 
+      RH_ENDPOINT: endpoint,
+      RH_CLASS means HUB here, 
+      RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+   */
+  
+   case RH_GET_STATUS:
+     len = 2; 
+     data[0] = 0x01;
+     data[1] = 0x00;
+     req_reply = RH_ACK; 
+     break;
+   case RH_GET_STATUS | RH_INTERFACE:
+     len = 2; 
+     data[0] = 0x00;
+     data[1] = 0x00;     
+     req_reply = RH_ACK;
+     break;
+   case RH_GET_STATUS | RH_ENDPOINT:
+     len = 2; 
+     data[0] = 0x00;
+     data[1] = 0x00;     
+     req_reply = RH_ACK;
+     break;
+   case RH_GET_STATUS | RH_CLASS: /* HUB_STATUS */
+     stat = readl(&ohci->regs->roothub.status) & 0x7fff7fff; /* bit 31 u. 15 has other meaning */ 
+     data[0] = stat & 0xff;
+     data[1] = (stat >> 8) & 0xff;
+     data[2] = (stat >> 16) & 0xff;
+     data[3] = (stat >> 24) & 0xff;
+     len = 4;
+     req_reply = RH_ACK; 
+     break;
+   case RH_GET_STATUS | RH_OTHER | RH_CLASS: /* PORT_STATUS */
+     stat = readl(&ohci->regs->roothub.portstatus[wIndex-1]);
+     data[0] = stat & 0xff;
+     data[1] = (stat >> 8) & 0xff;
+     data[2] = (stat >> 16) & 0xff;
+     data[3] = (stat >> 24) & 0xff;
+     len = 4;
+     req_reply = RH_ACK; 
+     printk("rh: stat %4x wIndex %4x;\n", stat , wIndex);
+     break;
+
+   case RH_CLEAR_FEATURE:
+     switch (wValue) {
+       case (RH_DEVICE_REMOTE_WAKEUP):
+       default:
+     }
+     break;
+
+   case RH_CLEAR_FEATURE | RH_ENDPOINT:  
+     switch (wValue) {
+       case (RH_ENDPOINT_STALL): 
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       default:
+     }
+     break;
+
+   case RH_CLEAR_FEATURE | RH_CLASS:
+     switch (wValue) {
+       /*     case (RH_C_HUB_LOCAL_POWER):  OHCI says: no switching of this one */
+       case (RH_C_HUB_OVER_CURRENT):
+         writel(RH_PS_OCIC, &ohci->regs->roothub.status);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       default:
+     }
+     break;
+   case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+     switch (wValue) {
+       case (RH_PORT_ENABLE):
+	     writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_SUSPEND):
+         writel(RH_PS_POCI, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_POWER):
+         writel(RH_PS_LSDA, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_CONNECTION):
+         writel(RH_PS_CSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_ENABLE):
+         writel(RH_PS_PESC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_SUSPEND):
+         writel(RH_PS_PSSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_OVER_CURRENT):
+         writel(RH_PS_OCIC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_RESET):
+         writel(RH_PS_PRSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       /*
+       case (RH_PORT_CONNECTION):
+       case (RH_PORT_OVER_CURRENT):
+       case (RH_PORT_RESET):
+       case (RH_PORT_LOW_SPEED):
+       */
+       default:
+     }
+     break;
+   case RH_SET_FEATURE:  
+     switch (wValue) {
+       case (RH_DEVICE_REMOTE_WAKEUP):
+       default:
+     }
+     break;
+
+   case RH_SET_FEATURE | RH_ENDPOINT:
+     switch (wValue) {
+       case (RH_ENDPOINT_STALL):
+       default:
+     }
+     break;
+
+   case RH_SET_FEATURE | RH_CLASS: 
+     switch (wValue) {
+       /* case (RH_C_HUB_LOCAL_POWER): Root Hub has no local Power 
+       case (RH_C_HUB_OVER_CURRENT): */
+      default:
+     }
+     break;
+   case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+     switch (wValue) {
+       case (RH_PORT_SUSPEND):
+         writel(RH_PS_PSS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_RESET):
+         if((readl(&ohci->regs->roothub.portstatus[wIndex-1]) &1) != 0)  /* BUG IN HUP CODE *********/
+         writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_POWER):
+         writel(RH_PS_PPS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_ENABLE):
+         writel(RH_PS_PES, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       /*
+       case (RH_PORT_CONNECTION):
+       case (RH_PORT_OVER_CURRENT):
+       case (RH_PORT_LOW_SPEED):
+       case (RH_C_PORT_CONNECTION):
+       case (RH_C_PORT_ENABLE):
+       case (RH_C_PORT_SUSPEND):
+       case (RH_C_PORT_OVER_CURRENT):
+       case (RH_C_PORT_RESET):
+       */
+       default:  
+     }
+     break;
+
+  case RH_SET_ADDRESS:
+     ohci->root_hub_funct_addr = wValue; 
+	/* ohci->ed_func_ep0[wValue] = &ohci->ed_rh_ep0;
+	 ohci->ed_func_ep0[wValue]->ep_addr.bep.fa = wValue; 
+	 ohci->ed_func_ep0[wValue]->ed_list = &ohci->ed_rh_epi; */
+	 ohci->ed_rh_epi.ed_list = NULL;
+	 ohci->ed_rh_epi.ep_addr.bep.fa = wValue;
+	 ohci->ed_rh_epi.ep_addr.bep.ep = 0xa1; /* Int in port 1 */
+     ohci->ed_func_ep0[0]= NULL;
+     len = 0;
+     req_reply = RH_ACK;
+     break;
+
+   case RH_GET_DESCRIPTOR:
+     switch ((wValue & 0xff00) >> 8) {
+     case (0x01): /* device descriptor */
+       len = min(sizeof(root_hub_dev_des), wLength);
+       memcpy(data, root_hub_dev_des, len);
+       req_reply = RH_ACK;
+       break;
+     case (0x02): /* configuration descriptor */
+       len = min(sizeof(root_hub_config_des), wLength);
+       memcpy(data, root_hub_config_des, len);
+       req_reply = RH_ACK;
+       break;
+     case (0x03): /* string descriptors */
+     default:
+     }
+     break;
+  case RH_GET_DESCRIPTOR | RH_CLASS:
+     data[1] = 0x29;
+     stat = readl(&ohci->regs->roothub.a);  
+     data[2] = stat & 0xff;        /* number of ports */
+     data[0] = (data[2] / 8) * 2 + 9; /* length of descriptor */
+     if(data[0] > wLength) {
+       req_reply =  RH_REQ_ERR;
+       break;
+     }
+     data[3] = (stat >> 8) & 0xff;
+     data[4] = (stat >> 16) & 0xff;
+     data[5] = (stat >> 24) & 0xff;
+     data[6] = 0; /* Root Hub needs no current from bus */
+     stat = readl(&ohci->regs->roothub.b); 
+     if(data[2] <= 8) { /* less than 8 Ports */
+       data[7] = stat & 0xff;
+       data[8] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1 ?, stat >> 16 for USB Rev. 1.0 */
+     }
+     else {
+       data[7] = stat & 0xff;
+       data[8] = (stat >> 8) & 0xff;
+       data[9] = (stat >> 16) & 0xff;  /* 0xff for USB Rev. 1.1?, stat >> 16 for USB Rev. 1.0 */
+       data[10] = (stat >> 24) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 24 for USB Rev. 1.0 */
+     }
+     len = data[0];
+     req_reply = RH_ACK;
+     break;
+
+   case RH_SET_DESCRIPTOR:
+     break;
+
+   case RH_GET_CONFIGURATION:
+     len = 1;
+     data[0] = 0x01;
+     req_reply = RH_ACK;
+     break;
+
+   case RH_SET_CONFIGURATION: /* start it up */
+     writel( 0x10000, &ohci->regs->roothub.status);
+     /*writel( OHCI_INTR_RHSC, &ohci->regs->intrenable);*/
+     len = 0;
+     req_reply = RH_ACK;
+     break;
+   /*  Optional or meaningless requests 
+     case RH_GET_STATE | RH_OTHER | RH_CLASS:
+     case RH_GET_INTERFACE | RH_INTERFACE:
+     case RH_SET_INTERFACE | RH_INTERFACE:
+     case RH_SYNC_FRAME | RH_ENDPOINT: 
+   */
+
+  /* Vendor Requests, we are the vendor!
+	Will the USB-Consortium give us a Vendor Id
+	for a virtual hub-device :-) ?
+     We could use these requests for configuration purposes on the HCD Driver, not used in the altenate usb !*/ 
+
+  case RH_SET_FEATURE | RH_VENDOR: /* remove all endpoints of device wIndex = Dev << 8  */
+    switch(wValue) {
+    case RH_REMOVE_EP:
+      ep_addr.iep = 0;
+      ep_addr.bep.ep = wIndex & 0xff;
+      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
+      usb_ohci_rm_function(ohci, ep_addr.iep);
+      len=0;
+      req_reply = RH_ACK;
+      break;
+    }
+    break;
+  case RH_SET_FEATURE | RH_ENDPOINT | RH_VENDOR: /* remove endpoint wIndex = Dev << 8 | EP */
+    switch(wValue) {
+    case RH_REMOVE_EP: 
+      ep_addr.iep = 0;
+      ep_addr.bep.ep = wIndex & 0xff;
+      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
+      usb_ohci_rm_ep(ohci, ohci_find_ep(ohci, ep_addr.iep));
+      len=0;
+      req_reply = RH_ACK;
+      break;
+    }
+    break;
+  case RH_SET_EP | RH_ENDPOINT | RH_VENDOR:   
+    ep_addr.bep.ep = data[0];
+    ep_addr.bep.fa = data[1];
+    ep_addr.bep.hc = data[2];
+    ep_addr.bep.host = data[3];  
+    rep_handler  = data[7] << 24 |data[6] << 16 | data[5] << 8 | data[4];
+    /*  struct usb_ohci_ed *usb_ohci_add_ep(union ep_addr_ ep_addr,
+	struct ohci * ohci, int interval, int load, int (*handler)(int, void*), int ep_size, int speed) */
+    usb_ohci_add_ep(ohci, ep_addr.iep, data[8], data[9], (f_handler) rep_handler, data[11] << 8 | data[10] , data[12]);
+    len=0;
+    req_reply = RH_ACK;
+    break;
+
+  default: 
+  }
+ printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));
+  printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));
+
+  /* if (req_reply == RH_ACK) len; */
+  queue_reply(ohci, ep_addr_ret.iep, 8, rh_cmd, data, len, lw0, lw1, handler);
+  return 0;
+}
+
+int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler){
+
+	struct ohci_rep_td *td;
+ 	struct ohci_rep_td *tmp;
+ 	union ep_addr_ ep_addr;
+ 	
+ 	td = kmalloc(sizeof(td),GFP_KERNEL);
+ 	tmp = ohci->td_rh_epi;
+ 	td->next_td = NULL;
+ 	if(tmp == NULL) { /* queue td */
+ 		ohci->td_rh_epi = td;	
+ 	}
+ 	else {
+ 		while(tmp->next_td != NULL) tmp = tmp->next_td;
+ 		tmp->next_td = td;
+ 	}
+ 	ep_addr.iep = 0;
+ 	ep_addr.bep.fa = ohci->root_hub_funct_addr;
+ 	ep_addr.bep.ep = 0xA1; /* INT IN EP endpoint 1 */
+  	td->cmd_len = 0;
+  	td->cmd = NULL;
+  	td->data = data;
+  	td->data_len = data_len;
+  	td->handler = handler; 
+  	td->next_td = NULL;
+  	td->ep_addr = ep_addr.iep;
+	td->lw0 = lw0;
+	td->lw1 = lw1;
+	ohci_init_rh_int_timer(ohci, 255);
+	return 0;
+}
+
+
+/* prepare Interrupt pipe transaction data; HUP INTERRUPT ENDPOINT */ 
+int root_hub_send_irq(struct ohci * ohci, void * rh_data, int rh_len ) {
+
+  int num_ports;
+  int i;
+  int ret;
+  int len;
+
+  __u8 * data = rh_data;
+
+  num_ports = readl(&ohci->regs->roothub.a) & 0xff; 
+  data[0] = (readl(&ohci->regs->roothub.status) & 0x00030000)>0?1:0;
+  ret = data[0];
+
+  for(i=0; i < num_ports; i++) {
+    data[i/8] |= ((readl(&ohci->regs->roothub.portstatus[i]) & 0x001f0000)>0?1:0) << ((i+1) % 8);
+    ret += data[i/8];
+  }
+  len = i/8 + 1;
+  
+  if (ret > 0) return len;
+
+  return  RH_NACK;
+}
+
+
+
+
+ 
+static struct timer_list rh_int_timer;
+
+/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+static void rh_int_timer_do(unsigned long ptr) {
+	int len; 
+	int interval;
+	struct ohci * ohci = (struct ohci *) ptr;
+    struct ohci_rep_td *td = ohci->td_rh_epi;
+
+	if(td != NULL) { /* if ther is a TD handle the INT request */
+		
+		len = root_hub_send_irq(ohci, td->data, td->data_len );
+		if(len > 0) {
+			ohci->td_rh_epi = td->next_td;
+			td->next_td = ohci->repl_queue; 
+			ohci->repl_queue = td;
+			send_replies(ohci);
+		}
+	}	
+	interval = ohci->rh_int_interval;
+	init_timer(& rh_int_timer);
+	rh_int_timer.function = rh_int_timer_do;
+	rh_int_timer.data = (unsigned long) ohci;
+	rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
+	add_timer(&rh_int_timer);
+}
+
+/* Root Hub INTs are polled by this timer */
+int ohci_init_rh_int_timer(struct ohci * ohci, int interval) {
+
+	if(!(ohci->rh_int_timer)) { 
+		ohci->rh_int_timer = 1;
+		ohci->rh_int_interval = interval;
+		init_timer(& rh_int_timer);
+		rh_int_timer.function = rh_int_timer_do;
+		rh_int_timer.data = (unsigned long) ohci;
+		rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
+		add_timer(&rh_int_timer);
+	}
+	return 0;
+}
+
+int ohci_del_rh_int_timer(struct ohci * ohci) {
+	del_timer(&rh_int_timer);
+	return 0;
+}
+/* for root hub replies, queue the reply, (it will be sent immediately now) */
+
+int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler) {
+
+ struct ohci_rep_td *td;
+ int status = 0;
+ 
+printk("queue_reply ep: %x len: %x\n", ep_addr, len);
+td = kmalloc(sizeof(td), GFP_KERNEL);
+
+  if (len < 0) { status = len; len = 0;}
+  td->cmd_len = cmd_len;
+  td->cmd = cmd;
+  td->data = data;
+  td->data_len = len;
+  td->handler = handler; 
+  td->next_td = ohci->repl_queue; ohci->repl_queue = td;
+  td->ep_addr = ep_addr;
+  td->lw0 = lw0;
+  td->lw1 = lw1;
+  td->status = status;
+  send_replies(ohci);
+return 0;
+}
+
+/* for root hub replies; send the reply */
+int send_replies(struct ohci * ohci) { 
+	struct ohci_rep_td *td;
+	struct ohci_rep_td *tmp;
+
+	td = ohci->repl_queue; ohci->repl_queue = NULL;
+	while ( td != NULL) {
+		td->handler((void *) ohci, td->ep_addr,td->cmd_len,td->cmd, td->data, td->data_len, td->status, td->lw0, td->lw1); 
+		tmp = td;
+		td = td->next_td;
+	
+		kfree(tmp);
+	}
+	return 0;
+}
+ 
+#endif
diff -urN linux-2.2.8-pre5/drivers/usb/ohci-root-hub.h linux-2.2.8-pre6/drivers/usb/ohci-root-hub.h
--- linux-2.2.8-pre5/drivers/usb/ohci-root-hub.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.8-pre6/drivers/usb/ohci-root-hub.h	2003-08-15 15:06:14.000000000 -0700
@@ -0,0 +1,71 @@
+/*
+ * HCD (OHCI) Virtual Root Hub Protocol for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
+ *
+ * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
+ * This piece of code lets it look like it resides on the bus 
+ * like the other hubs.
+ * (for anyone who wants to do a control operation on the root hub)
+ *  
+ * v1.0 1999/04/27
+ * ohci-root-hub.h
+ *  
+ */
+ 
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS			0x0500
+#define RH_GET_DESCRIPTOR		0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14  
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+ 
+#define min(a,b) (((a)<(b))?(a):(b))  
+ 
diff -urN linux-2.2.8-pre5/drivers/usb/README.ohci_hcd linux-2.2.8-pre6/drivers/usb/README.ohci_hcd
--- linux-2.2.8-pre5/drivers/usb/README.ohci_hcd	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.8-pre6/drivers/usb/README.ohci_hcd	2003-08-15 15:06:14.000000000 -0700
@@ -0,0 +1,112 @@
+
+The OHCI HCD layer is a simple but nearly complete implementation of what the
+USB people would call a HCD  for the OHCI. 
+ (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
+The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
+
+- Roman Weissgaerber <weissg@vienna.at>
+
+
+ * v2.1 1999/05/09 ep_addr correction, code cleanup
+ * v0.2.0 1999/05/04 
+ * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
+ * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
+ * 
+ * v0.1.0 1999/04/27 initial release
+ 
+to remove the module try:
+killall root-hub
+:
+rmmod usb-ohci-hcd
+
+Features:
+- virtual root hub, all basic hub descriptors and commands (state: complete) 
+  this is an option now (v0.2.0)
+  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
+  default is without. 
+  (at the moment: the Virtual Root Hub option is not recommended)
+  
+  files: ohci-root-hub.c, ohci-root-hub.h 
+ 
+
+- Endpoint Descriptor (ED) handling more static approach 
+ (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
+ as long as the function (device) is alive or another configuration is choosen.
+ In the HCD layer the EDs has to be allocated manually either by calling a subroutine
+ or by sending a USB root hub vendor specific command to the virtual root hub.
+ At the alternate linux usb stack EDs will be added (allocated) at their first use.
+ 
+ files: ohci-hcd.c ohci-hcd.h
+ routines:   (do not use for drivers, use the top layer alternate usb commands instead)
+ 
+ int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
+            int interval, int load, f_handler handler, int ep_size, int speed)
+       adds an endpoint, (if the endpoint already exists some parameters will be updated)
+       
+ int usb_ohci_rm_ep(struct  usb_ohci_ed *ed, struct ohci * ohci) 
+       removes an endpoint and all pending TDs of that EP
+       
+  usb_ohci_rm_function( struct ohci * ohci, union ep_addr_ ep_addr)
+       removes all Endpoints of a function (device)
+
+- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
+  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
+  to take care of buffer allocation.
+  files: ohci-hcd.c ohci-hcd.h 
+
+  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
+  
+  int ohci_trans_req(struct ohci * ohci, int ep_addr, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
+  
+  CTRL: ctrl, ctrl_len ... cmd buffer 
+        data, data_len ... data buffer (in or out)
+  INT, BULK:  ctrl = NULL, ctrl_len=0,
+  		data, data_len ... data buffer (in or out)
+  ISO: tbd
+
+  There is no buffer reinsertion done by the internal HCD function. 
+  (The interface layer does this for a INT-pipe on request.)
+  If you want a transfer then you have to 
+  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
+  you can send as many as you like. They should come back by the callback f_handler in
+  the same order (for each endpoint, not globally) If an error occurs all
+  queued transfers of an endpoint will return unsent. They will be marked with an error status.
+  
+  e.g double-buffering for int transfers:
+
+   	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  and when a data0 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  and when a data1 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
+  The alternate usb uses them for dev_id and usb_device_irq handler.
+
+
+- Done list handling: returns the requests (callback f_handler in ED) and does 
+  some error handling, root-hub request dequeuing
+  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
+
+ep_addr union or int  is for addressing devices&endpoints: 
+__u8 ep_addr.bep.ep ... bit 3..0  endpoint address
+						bit 4     0
+						bit 6,5  type: eg. 10 CTRL, 11 BULK, 01 INT, 00 ISO
+						bit 7	direction 1 IN, 0 OUT
+
+__u8 ep_addr.bep.fa ... bit 6..0  function address
+						bit 7	  0
+
+(__u8 ep_addr.bep.hc ... host controller nr) not used
+(__u8 ep_addr.bep.host ... host nr) not used
+
+
+  
diff -urN linux-2.2.8-pre5/drivers/usb/usb.h linux-2.2.8-pre6/drivers/usb/usb.h
--- linux-2.2.8-pre5/drivers/usb/usb.h	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/drivers/usb/usb.h	2003-08-15 15:06:14.000000000 -0700
@@ -9,7 +9,7 @@
 static __inline__ void wait_ms(unsigned int ms)
 {
         current->state = TASK_UNINTERRUPTIBLE;
-        schedule_timeout(1 + ms / 10);
+        schedule_timeout(1 + ms * HZ / 1000);
 }
 
 
diff -urN linux-2.2.8-pre5/drivers/video/vesafb.c linux-2.2.8-pre6/drivers/video/vesafb.c
--- linux-2.2.8-pre5/drivers/video/vesafb.c	1999-04-12 09:57:34.000000000 -0700
+++ linux-2.2.8-pre6/drivers/video/vesafb.c	2003-08-15 15:06:14.000000000 -0700
@@ -635,10 +635,8 @@
 		video_cmap_len = 256;
 	}
 	request_region(0x3c0, 32, "vga+");
-#ifdef CONFIG_MTRR
 	if (mtrr)
 		mtrr_add((unsigned long)video_base, video_size, MTRR_TYPE_WRCOMB, 1);
-#endif
 	
 	strcpy(fb_info.modename, "VESA VGA");
 	fb_info.changevar = NULL;
diff -urN linux-2.2.8-pre5/fs/nfs/dir.c linux-2.2.8-pre6/fs/nfs/dir.c
--- linux-2.2.8-pre5/fs/nfs/dir.c	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/fs/nfs/dir.c	2003-08-15 15:06:14.000000000 -0700
@@ -371,10 +371,19 @@
 
 	/*
 	 * If it's the last lookup in a series, we use a stricter
-	 * cache consistency check!
+	 * cache consistency check by looking at the parent mtime.
+	 *
+	 * If it's been modified in the last hour, be really strict.
+	 * (This still means that we can avoid doing unnecessary
+	 * work on directories like /usr/share/bin etc which basically
+	 * never change).
 	 */
-	if (!(flags & LOOKUP_CONTINUE))
-		timeout = 0;
+	if (!(flags & LOOKUP_CONTINUE)) {
+		long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+
+		if (diff < 15*60)
+			timeout = 0;
+	}
 	
 	return time_after(jiffies,dentry->d_time + timeout);
 }
@@ -389,14 +398,10 @@
 static inline int nfs_neg_need_reval(struct dentry *dentry)
 {
 	unsigned long timeout = 30 * HZ;
-	struct inode *dir = dentry->d_parent->d_inode;
+	long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
 
-	if (dir) {
-		/* Modified in the last two minutes? */
-		long diff = CURRENT_TIME - dir->i_mtime;
-		if (diff < 2*60)
-			timeout = 1 * HZ;
-	}
+	if (diff < 5*60)
+		timeout = 1 * HZ;
 
 	return time_after(jiffies, dentry->d_time + timeout);
 }
diff -urN linux-2.2.8-pre5/fs/proc/array.c linux-2.2.8-pre6/fs/proc/array.c
--- linux-2.2.8-pre5/fs/proc/array.c	1999-03-10 21:49:10.000000000 -0800
+++ linux-2.2.8-pre6/fs/proc/array.c	2003-08-15 15:06:14.000000000 -0700
@@ -896,7 +896,7 @@
 
 	return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
 		pid,
 		tsk->comm,
 		state,
@@ -938,7 +938,8 @@
 		wchan,
 		tsk->nswap,
 		tsk->cnswap,
-		tsk->exit_signal);
+		tsk->exit_signal,
+		tsk->processor);
 }
 		
 static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
diff -urN linux-2.2.8-pre5/fs/super.c linux-2.2.8-pre6/fs/super.c
--- linux-2.2.8-pre5/fs/super.c	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/fs/super.c	2003-08-15 15:06:14.000000000 -0700
@@ -1131,6 +1131,7 @@
 			sb = get_empty_super(); /* "can't fail" */
 			sb->s_dev = get_unnamed_dev();
 			sb->s_flags = root_mountflags;
+			sema_init(&sb->s_vfs_rename_sem,1);
 			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
 			if (vfsmnt) {
 				if (nfs_root_mount(sb) >= 0) {
diff -urN linux-2.2.8-pre5/include/asm-alpha/fpu.h linux-2.2.8-pre6/include/asm-alpha/fpu.h
--- linux-2.2.8-pre5/include/asm-alpha/fpu.h	1998-03-15 09:57:33.000000000 -0800
+++ linux-2.2.8-pre6/include/asm-alpha/fpu.h	2003-08-15 15:06:14.000000000 -0700
@@ -81,6 +81,18 @@
 	return fp;
 }
 
+static inline unsigned long
+ieee_fpcr_to_swcr(unsigned long fp)
+{
+	unsigned long sw;
+	sw = (fp >> 35) & IEEE_STATUS_MASK;
+	sw |= (~fp >> 48) & (IEEE_TRAP_ENABLE_INV
+			     | IEEE_TRAP_ENABLE_DZE
+			     | IEEE_TRAP_ENABLE_OVF);
+	sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE);
+	return sw;
+}
+
 #ifdef __KERNEL__
 
 /* The following two functions don't need trapb/excb instructions
diff -urN linux-2.2.8-pre5/include/asm-alpha/pgtable.h linux-2.2.8-pre6/include/asm-alpha/pgtable.h
--- linux-2.2.8-pre5/include/asm-alpha/pgtable.h	1999-03-10 18:11:51.000000000 -0800
+++ linux-2.2.8-pre6/include/asm-alpha/pgtable.h	2003-08-15 15:06:14.000000000 -0700
@@ -167,19 +167,6 @@
 
 #else /* __SMP__ */
 
-/* ipi_msg_flush_tb is owned by the holder of the global kernel lock. */
-struct ipi_msg_flush_tb_struct {
-	volatile unsigned int flush_tb_mask;
-	union {
-		struct mm_struct *	flush_mm;
-		struct vm_area_struct *	flush_vma;
-	} p;
-	unsigned long flush_addr;
-	unsigned long flush_end;
-};
-
-extern struct ipi_msg_flush_tb_struct ipi_msg_flush_tb;
-
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
diff -urN linux-2.2.8-pre5/include/asm-alpha/system.h linux-2.2.8-pre6/include/asm-alpha/system.h
--- linux-2.2.8-pre5/include/asm-alpha/system.h	1999-01-16 17:02:51.000000000 -0800
+++ linux-2.2.8-pre6/include/asm-alpha/system.h	2003-08-15 15:06:14.000000000 -0700
@@ -97,12 +97,15 @@
 
 extern void halt(void) __attribute__((noreturn));
 
-#define switch_to(prev,next) do {					\
-	current = next;							\
-	alpha_switch_to((unsigned long) &current->tss - IDENT_ADDR);	\
+#define switch_to(prev,next,last)			\
+do {							\
+	unsigned long pcbb;				\
+	current = (next);				\
+	pcbb = virt_to_phys(&current->tss);		\
+	(last) = alpha_switch_to(pcbb, (prev));		\
 } while (0)
 
-extern void alpha_switch_to(unsigned long pctxp);
+extern struct task_struct* alpha_switch_to(unsigned long, struct task_struct*);
 
 #define mb() \
 __asm__ __volatile__("mb": : :"memory")
@@ -119,6 +122,34 @@
 #define draina() \
 __asm__ __volatile__ ("call_pal %0 #draina" : : "i" (PAL_draina) : "memory")
 
+enum implver_enum {
+	IMPLVER_EV4,
+	IMPLVER_EV5,
+	IMPLVER_EV6
+};
+
+#ifdef CONFIG_ALPHA_GENERIC
+#define implver()				\
+({ unsigned long __implver;			\
+   __asm__ ("implver %0" : "=r"(__implver));	\
+   (enum implver_enum) __implver; })
+#else
+/* Try to eliminate some dead code.  */
+#ifdef CONFIG_ALPHA_EV4
+#define implver() IMPLVER_EV4
+#endif
+#ifdef CONFIG_ALPHA_EV5
+#define implver() IMPLVER_EV5
+#endif
+#ifdef CONFIG_ALPHA_EV6
+#define implver() IMPLVER_EV6
+#endif
+#endif
+
+#define amask(mask)						\
+({ unsigned long __amask, __input = (mask);			\
+   __asm__ ("amask %1,%0" : "=r"(__amask) : "rI"(__input));	\
+   __amask; })
 
 static inline unsigned long 
 wrperfmon(unsigned long perf_fun, unsigned long arg)
diff -urN linux-2.2.8-pre5/include/asm-arm/arch-ebsa285/irq.h linux-2.2.8-pre6/include/asm-arm/arch-ebsa285/irq.h
--- linux-2.2.8-pre5/include/asm-arm/arch-ebsa285/irq.h	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/include/asm-arm/arch-ebsa285/irq.h	2003-08-15 15:06:14.000000000 -0700
@@ -10,6 +10,7 @@
  *  26-Jan-1999	PJB	Don't use IACK on CATS
  *  16-Mar-1999	RMK	Added autodetect of ISA PICs
  */
+#include <linux/config.h>
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 #include <asm/irq.h>
diff -urN linux-2.2.8-pre5/include/asm-arm/arch-ebsa285/memory.h linux-2.2.8-pre6/include/asm-arm/arch-ebsa285/memory.h
--- linux-2.2.8-pre5/include/asm-arm/arch-ebsa285/memory.h	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/include/asm-arm/arch-ebsa285/memory.h	2003-08-15 15:06:14.000000000 -0700
@@ -15,6 +15,8 @@
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
+#include <linux/config.h>
+
 #if defined(CONFIG_HOST_FOOTBRIDGE)
 
 /*
diff -urN linux-2.2.8-pre5/include/asm-i386/bugs.h linux-2.2.8-pre6/include/asm-i386/bugs.h
--- linux-2.2.8-pre5/include/asm-i386/bugs.h	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/include/asm-i386/bugs.h	2003-08-15 15:06:14.000000000 -0700
@@ -277,6 +277,7 @@
 	    ((Cx86_dir0_msb == 5) || (Cx86_dir0_msb == 3))) {
 		int eax, dummy;
 		unsigned char ccr3, ccr4;
+		__u32 old_cap;
 
 		cli();
 		ccr3 = getCx86(CX86_CCR3);
@@ -288,8 +289,11 @@
 
 		/* we have up to level 1 available on the Cx6x86(L|MX) */
 		boot_cpu_data.cpuid_level = 1;
+		/*  Need to preserve some externally computed capabilities  */
+		old_cap = boot_cpu_data.x86_capability & X86_FEATURE_MTRR;
 		cpuid(1, &eax, &dummy, &dummy,
 		      &boot_cpu_data.x86_capability);
+		boot_cpu_data.x86_capability |= old_cap;
 
 		boot_cpu_data.x86 = (eax >> 8) & 15;
 		/*
@@ -345,6 +349,24 @@
 }
  
 /*
+ * In setup.c's cyrix_model() we have set the boot_cpu_data.coma_bug
+ * on certain processors that we know contain this bug and now we
+ * enable the workaround for it.
+ */
+
+__initfunc(static void check_cyrix_coma(void))
+{
+	if (boot_cpu_data.coma_bug) {
+		unsigned char ccr1;
+		cli();
+		ccr1 = getCx86 (CX86_CCR1);
+		setCx86 (CX86_CCR1, ccr1 | 0x10);
+		sti();
+		printk("Cyrix processor with \"coma bug\" found, workaround enabled\n");
+	}
+}
+ 
+/*
  * Check wether we are able to run this kernel safely on SMP.
  *
  * - In order to run on a i386, we need to be compiled for i386
@@ -402,5 +424,6 @@
 	check_popad();
 	check_amd_k6();
 	check_pentium_f00f();
+	check_cyrix_coma();
 	system_utsname.machine[1] = '0' + boot_cpu_data.x86;
 }
diff -urN linux-2.2.8-pre5/include/asm-i386/mtrr.h linux-2.2.8-pre6/include/asm-i386/mtrr.h
--- linux-2.2.8-pre5/include/asm-i386/mtrr.h	1999-04-27 09:57:58.000000000 -0700
+++ linux-2.2.8-pre6/include/asm-i386/mtrr.h	2003-08-15 15:06:14.000000000 -0700
@@ -1,6 +1,6 @@
 /*  Generic MTRR (Memory Type Range Register) ioctls.
 
-    Copyright (C) 1997-1998  Richard Gooch
+    Copyright (C) 1997-1999  Richard Gooch
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -44,10 +44,11 @@
 };
 
 /*  These are the various ioctls  */
-#define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry)
-#define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry)
-#define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry)
+#define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE,  0, struct mtrr_sentry)
+#define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE,  1, struct mtrr_sentry)
+#define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE,  2, struct mtrr_sentry)
 #define MTRRIOC_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry)
+#define MTRRIOC_KILL_ENTRY       _IOW(MTRR_IOCTL_BASE,  4, struct mtrr_sentry)
 
 /*  These are the region types  */
 #define MTRR_TYPE_UNCACHABLE 0
@@ -75,7 +76,7 @@
 #ifdef __KERNEL__
 
 /*  The following functions are for use by other drivers  */
-# if defined(CONFIG_MTRR) || defined(CONFIG_MTRR_MODULE)
+# ifdef CONFIG_MTRR
 extern int mtrr_add (unsigned long base, unsigned long size,
 		     unsigned int type, char increment);
 extern int mtrr_del (int reg, unsigned long base, unsigned long size);
diff -urN linux-2.2.8-pre5/include/asm-i386/processor.h linux-2.2.8-pre6/include/asm-i386/processor.h
--- linux-2.2.8-pre5/include/asm-i386/processor.h	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/include/asm-i386/processor.h	2003-08-15 15:06:14.000000000 -0700
@@ -35,6 +35,7 @@
 				    call  */
 	int	fdiv_bug;
 	int	f00f_bug;
+	int	coma_bug;
 	unsigned long loops_per_sec;
 	unsigned long *pgd_quick;
 	unsigned long *pte_quick;
@@ -119,12 +120,17 @@
 /*
  *      Cyrix CPU configuration register indexes
  */
+#define CX86_CCR0 0xc0
+#define CX86_CCR1 0xc1
 #define CX86_CCR2 0xc2
 #define CX86_CCR3 0xc3
 #define CX86_CCR4 0xe8
 #define CX86_CCR5 0xe9
+#define CX86_CCR6 0xea
 #define CX86_DIR0 0xfe
 #define CX86_DIR1 0xff
+#define CX86_ARR_BASE 0xc4
+#define CX86_RCR_BASE 0xdc
 
 /*
  *      Cyrix CPU indexed register access macros
diff -urN linux-2.2.8-pre5/include/linux/mc146818rtc.h linux-2.2.8-pre6/include/linux/mc146818rtc.h
--- linux-2.2.8-pre5/include/linux/mc146818rtc.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.8-pre6/include/linux/mc146818rtc.h	1999-04-27 09:57:56.000000000 -0700
@@ -0,0 +1,149 @@
+/* mc146818rtc.h - register definitions for the Real-Time-Clock / CMOS RAM
+ * Copyright Torsten Duwe <duwe@informatik.uni-erlangen.de> 1993
+ * derived from Data Sheet, Copyright Motorola 1984 (!).
+ * It was written to be part of the Linux operating system.
+ */
+/* permission is hereby granted to copy, modify and redistribute this code
+ * in terms of the GNU Library General Public License, Version 2 or later,
+ * at your option.
+ */
+
+#ifndef _MC146818RTC_H
+#define _MC146818RTC_H
+#include <asm/io.h>
+
+#ifndef RTC_PORT
+#define RTC_PORT(x)	(0x70 + (x))
+#define RTC_ALWAYS_BCD	1
+#endif
+
+#define CMOS_READ(addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+inb_p(RTC_PORT(1)); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+outb_p((val),RTC_PORT(1)); \
+})
+
+/**********************************************************************
+ * register summary
+ **********************************************************************/
+#define RTC_SECONDS		0
+#define RTC_SECONDS_ALARM	1
+#define RTC_MINUTES		2
+#define RTC_MINUTES_ALARM	3
+#define RTC_HOURS		4
+#define RTC_HOURS_ALARM		5
+/* RTC_*_alarm is always true if 2 MSBs are set */
+# define RTC_ALARM_DONT_CARE 	0xC0
+
+#define RTC_DAY_OF_WEEK		6
+#define RTC_DAY_OF_MONTH	7
+#define RTC_MONTH		8
+#define RTC_YEAR		9
+
+/* control registers - Moto names
+ */
+#define RTC_REG_A		10
+#define RTC_REG_B		11
+#define RTC_REG_C		12
+#define RTC_REG_D		13
+
+/**********************************************************************
+ * register details
+ **********************************************************************/
+#define RTC_FREQ_SELECT	RTC_REG_A
+
+/* update-in-progress  - set to "1" 244 microsecs before RTC goes off the bus,
+ * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
+ * totalling to a max high interval of 2.228 ms.
+ */
+# define RTC_UIP		0x80
+# define RTC_DIV_CTL		0x70
+   /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
+#  define RTC_REF_CLCK_4MHZ	0x00
+#  define RTC_REF_CLCK_1MHZ	0x10
+#  define RTC_REF_CLCK_32KHZ	0x20
+   /* 2 values for divider stage reset, others for "testing purposes only" */
+#  define RTC_DIV_RESET1	0x60
+#  define RTC_DIV_RESET2	0x70
+  /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
+# define RTC_RATE_SELECT 	0x0F
+
+/**********************************************************************/
+#define RTC_CONTROL	RTC_REG_B
+# define RTC_SET 0x80		/* disable updates for clock setting */
+# define RTC_PIE 0x40		/* periodic interrupt enable */
+# define RTC_AIE 0x20		/* alarm interrupt enable */
+# define RTC_UIE 0x10		/* update-finished interrupt enable */
+# define RTC_SQWE 0x08		/* enable square-wave output */
+# define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+# define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+# define RTC_DST_EN 0x01	/* auto switch DST - works f. USA only */
+
+/**********************************************************************/
+#define RTC_INTR_FLAGS	RTC_REG_C
+/* caution - cleared by read */
+# define RTC_IRQF 0x80		/* any of the following 3 is active */
+# define RTC_PF 0x40
+# define RTC_AF 0x20
+# define RTC_UF 0x10
+
+/**********************************************************************/
+#define RTC_VALID	RTC_REG_D
+# define RTC_VRT 0x80		/* valid RAM and time */
+/**********************************************************************/
+
+/* example: !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) 
+ * determines if the following two #defines are needed
+ */
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+/*
+ * The struct used to pass data via the following ioctl. Similar to the
+ * struct tm in <time.h>, but it needs to be here so that the kernel 
+ * source is self contained, allowing cross-compiles, etc. etc.
+ */
+
+struct rtc_time {
+	int tm_sec;
+	int tm_min;
+	int tm_hour;
+	int tm_mday;
+	int tm_mon;
+	int tm_year;
+	int tm_wday;
+	int tm_yday;
+	int tm_isdst;
+};
+
+/*
+ * ioctl calls that are permitted to the /dev/rtc interface, if 
+ * CONFIG_RTC was enabled.
+ */
+
+#define RTC_AIE_ON	_IO('p', 0x01)	/* Alarm int. enable on		*/
+#define RTC_AIE_OFF	_IO('p', 0x02)	/* ... off			*/
+#define RTC_UIE_ON	_IO('p', 0x03)	/* Update int. enable on	*/
+#define RTC_UIE_OFF	_IO('p', 0x04)	/* ... off			*/
+#define RTC_PIE_ON	_IO('p', 0x05)	/* Periodic int. enable on	*/
+#define RTC_PIE_OFF	_IO('p', 0x06)	/* ... off			*/
+
+#define RTC_ALM_SET	_IOW('p', 0x07, struct rtc_time) /* Set alarm time  */
+#define RTC_ALM_READ	_IOR('p', 0x08, struct rtc_time) /* Read alarm time */
+#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time) /* Read RTC time   */
+#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
+#define RTC_IRQP_READ	_IOR('p', 0x0b, unsigned long)	 /* Read IRQ rate   */
+#define RTC_IRQP_SET	_IOW('p', 0x0c, unsigned long)	 /* Set IRQ rate    */
+#define RTC_EPOCH_READ	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
+#define RTC_EPOCH_SET	_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
+
+
+#endif /* _MC146818RTC_H */
diff -urN linux-2.2.8-pre5/include/linux/parport_pc.h linux-2.2.8-pre6/include/linux/parport_pc.h
--- linux-2.2.8-pre5/include/linux/parport_pc.h	1999-04-27 09:56:22.000000000 -0700
+++ linux-2.2.8-pre6/include/linux/parport_pc.h	2003-08-15 15:06:14.000000000 -0700
@@ -14,8 +14,15 @@
 #define STATUS   0x1
 #define DATA     0
 
+/* Private data for PC low-level driver. */
+struct parport_pc_private {
+	/* Contents of CTR. */
+	unsigned char ctr;
+};
+
 extern int parport_pc_epp_clear_timeout(struct parport *pb);
 
+extern volatile unsigned char parport_pc_ctr;
 
 extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
@@ -62,19 +69,24 @@
 
 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);
 }
 
 extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
 {
-	return inb(p->base+CONTROL);
+	struct parport_pc_private *priv = p->private_data;
+	return priv->ctr;
 }
 
 extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
 {
-	unsigned char old = inb(p->base+CONTROL);
-	outb(((old & ~mask) ^ val), p->base+CONTROL);
-	return old;
+	struct parport_pc_private *priv = p->private_data;
+	unsigned char ctr = priv->ctr;
+	ctr = (ctr & ~mask) ^ val;
+	outb (ctr, p->base+CONTROL);
+	return priv->ctr = ctr; /* update soft copy */
 }
 
 extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
diff -urN linux-2.2.8-pre5/include/linux/smp.h linux-2.2.8-pre6/include/linux/smp.h
--- linux-2.2.8-pre5/include/linux/smp.h	1999-04-27 09:56:21.000000000 -0700
+++ linux-2.2.8-pre6/include/linux/smp.h	2003-08-15 15:06:14.000000000 -0700
@@ -42,6 +42,12 @@
 extern void smp_commence(void);
 
 /*
+ * Call a function on all other processors
+ */
+extern int smp_call_function (void (*func) (void *info), void *info,
+			      int retry, int wait);
+
+/*
  * True once the per process idle is forked
  */
 extern int smp_threads_ready;
@@ -60,7 +66,7 @@
 					 * when rebooting
 					 */
 #define MSG_RESCHEDULE		0x0003	/* Reschedule request from master CPU*/
-#define MSG_MTRR_CHANGE         0x0004  /* Change MTRR */
+#define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
 
 #else
 
@@ -68,12 +74,13 @@
  *	These macros fold the SMP functionality into a single CPU system
  */
  
-#define smp_num_cpus			1
-#define smp_processor_id()		0
-#define hard_smp_processor_id()		0
-#define smp_threads_ready		1
+#define smp_num_cpus				1
+#define smp_processor_id()			0
+#define hard_smp_processor_id()			0
+#define smp_threads_ready			1
 #define kernel_lock()
-#define cpu_logical_map(cpu)		0
+#define cpu_logical_map(cpu)			0
+#define smp_call_function(func,info,retry,wait)
 
 #endif
 #endif
diff -urN linux-2.2.8-pre5/include/net/tcp.h linux-2.2.8-pre6/include/net/tcp.h
--- linux-2.2.8-pre5/include/net/tcp.h	1999-04-28 09:51:57.000000000 -0700
+++ linux-2.2.8-pre6/include/net/tcp.h	2003-08-15 15:06:14.000000000 -0700
@@ -174,6 +174,7 @@
 	struct tcp_func		*af_specific;
 	struct tcp_bind_bucket	*tb;
 	struct tcp_tw_bucket	*next_death;
+	struct tcp_tw_bucket	**pprev_death;
 	int			death_slot;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	struct in6_addr		v6_daddr;
@@ -716,6 +717,22 @@
 	return (new_win && (new_win > (cur_win << 1)));
 }
 
+/* Recalculate snd_ssthresh, we want to set it to:
+ *
+ * 	one half the current congestion window, but no
+ *	less than two segments
+ *
+ * We must take into account the current send window
+ * as well, however we keep track of that using different
+ * units so a conversion is necessary.  -DaveM
+ */
+extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
+{
+	__u32 snd_wnd_packets = tp->snd_wnd / tp->mss_cache;
+
+	return max(min(snd_wnd_packets, tp->snd_cwnd) >> 1, 2);
+}
+
 /* TCP timestamps are only 32-bits, this causes a slight
  * complication on 64-bit systems since we store a snapshot
  * of jiffies in the buffer control blocks below.  We decidely
diff -urN linux-2.2.8-pre5/kernel/sched.c linux-2.2.8-pre6/kernel/sched.c
--- linux-2.2.8-pre5/kernel/sched.c	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/kernel/sched.c	2003-08-15 15:06:14.000000000 -0700
@@ -672,6 +672,7 @@
 {
 	__schedule_tail(prev);
 }
+
 /*
  *  'schedule()' is the scheduler function. It's a very simple and nice
  * scheduler: it's not perfect, but certainly works for most things.
@@ -820,7 +821,7 @@
 	kstat.context_swtch++;
 	get_mmu_context(next);
 	switch_to(prev, next, prev);
-	schedule_tail(prev);
+	__schedule_tail(prev);
 
 same_process:
   
diff -urN linux-2.2.8-pre5/net/core/iovec.c linux-2.2.8-pre6/net/core/iovec.c
--- linux-2.2.8-pre5/net/core/iovec.c	1998-09-21 14:19:00.000000000 -0700
+++ linux-2.2.8-pre6/net/core/iovec.c	2003-08-15 15:06:14.000000000 -0700
@@ -59,8 +59,15 @@
 		goto out;
 	m->msg_iov=iov;
 
-	for (err = 0, ct = 0; ct < m->msg_iovlen; ct++)
+	for (err = 0, ct = 0; ct < m->msg_iovlen; ct++) {
 		err += iov[ct].iov_len;
+		/* Goal is not to verify user data, but to prevent returning
+		   negative value, which is interpreted as errno.
+		   Overflow is still possible, but it is harmless.
+		 */
+		if (err < 0)
+			return -EMSGSIZE;
+	}
 out:
 	return err;
 }
diff -urN linux-2.2.8-pre5/net/core/sock.c linux-2.2.8-pre6/net/core/sock.c
--- linux-2.2.8-pre5/net/core/sock.c	2003-08-15 15:06:14.000000000 -0700
+++ linux-2.2.8-pre6/net/core/sock.c	2003-08-15 15:06:14.000000000 -0700
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.79 1999/03/28 10:18:25 davem Exp $
+ * Version:	$Id: sock.c,v 1.80 1999/05/08 03:04:34 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -urN linux-2.2.8-pre5/net/ipv4/devinet.c linux-2.2.8-pre6/net/ipv4/devinet.c
--- linux-2.2.8-pre5/net/ipv4/devinet.c	1999-03-25 09:23:34.000000000 -0800
+++ linux-2.2.8-pre6/net/ipv4/devinet.c	2003-08-15 15:06:14.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  *	NET3	IP device support routines.
  *
- *	Version: $Id: devinet.c,v 1.27 1999/03/25 10:04:06 davem Exp $
+ *	Version: $Id: devinet.c,v 1.28 1999/05/08 20:00:16 davem Exp $
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -712,6 +712,7 @@
 				ifa->ifa_mask = inet_make_mask(8);
 				ifa->ifa_dev = in_dev;
 				ifa->ifa_scope = RT_SCOPE_HOST;
+				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 				inet_insert_ifa(in_dev, ifa);
 			}
 		}
diff -urN linux-2.2.8-pre5/net/ipv4/route.c linux-2.2.8-pre6/net/ipv4/route.c
--- linux-2.2.8-pre5/net/ipv4/route.c	1999-04-22 19:45:19.000000000 -0700
+++ linux-2.2.8-pre6/net/ipv4/route.c	2003-08-15 15:06:14.000000000 -0700
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.66 1999/04/22 10:07:35 davem Exp $
+ * Version:	$Id: route.c,v 1.67 1999/05/08 20:00:20 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1492,13 +1492,16 @@
 			return -ENODEV;	/* Wrong error code */
 
 		if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) {
-			key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
+			if (!key.src)
+				key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
 			goto make_route;
 		}
-		if (MULTICAST(daddr))
-			key.src = inet_select_addr(dev_out, 0, key.scope);
-		else if (!daddr)
-			key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
+		if (!key.src) {
+			if (MULTICAST(daddr))
+				key.src = inet_select_addr(dev_out, 0, key.scope);
+			else if (!daddr)
+				key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
+		}
 	}
 
 	if (!key.dst) {
diff -urN linux-2.2.8-pre5/net/ipv4/tcp_input.c linux-2.2.8-pre6/net/ipv4/tcp_input.c
--- linux-2.2.8-pre5/net/ipv4/tcp_input.c	1999-04-28 09:51:57.000000000 -0700
+++ linux-2.2.8-pre6/net/ipv4/tcp_input.c	2003-08-15 15:06:14.000000000 -0700
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.163 1999/04/28 16:08:05 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.164 1999/05/08 21:09:52 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -497,8 +497,7 @@
 		if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
 			tp->dup_acks++;
 			if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
-                                tp->snd_ssthresh =
-					max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
+                                tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
                                 tp->snd_cwnd = (tp->snd_ssthresh + 3);
 				tp->high_seq = tp->snd_nxt;
 				if(!tp->fackets_out)
diff -urN linux-2.2.8-pre5/net/ipv4/tcp_ipv4.c linux-2.2.8-pre6/net/ipv4/tcp_ipv4.c
--- linux-2.2.8-pre5/net/ipv4/tcp_ipv4.c	1999-04-28 09:51:57.000000000 -0700
+++ linux-2.2.8-pre6/net/ipv4/tcp_ipv4.c	2003-08-15 15:06:14.000000000 -0700
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.174 1999/04/28 16:08:19 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.175 1999/05/08 21:09:54 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -819,7 +819,7 @@
 	switch (type) {
 	case ICMP_SOURCE_QUENCH:
 #ifndef OLD_SOURCE_QUENCH /* This is deprecated */
-		tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
 		tp->snd_cwnd = tp->snd_ssthresh;
 		tp->snd_cwnd_cnt = 0;
 		tp->high_seq = tp->snd_nxt;
diff -urN linux-2.2.8-pre5/net/ipv4/tcp_output.c linux-2.2.8-pre6/net/ipv4/tcp_output.c
--- linux-2.2.8-pre5/net/ipv4/tcp_output.c	1999-04-28 09:51:57.000000000 -0700
+++ linux-2.2.8-pre6/net/ipv4/tcp_output.c	2003-08-15 15:06:14.000000000 -0700
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.107 1999/04/28 16:08:12 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.108 1999/05/08 21:48:59 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -521,24 +521,39 @@
 void tcp_simple_retransmit(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct sk_buff *skb; 
-	unsigned int mss = tcp_current_mss(sk); 
+	struct sk_buff *skb, *old_next_skb;
+	unsigned int mss = tcp_current_mss(sk);
 
  	/* Don't muck with the congestion window here. */
  	tp->dup_acks = 0;
  	tp->high_seq = tp->snd_nxt;
- 	tp->retrans_head = NULL; 
+ 	tp->retrans_head = NULL;
 
  	/* Input control flow will see that this was retransmitted
 	 * and not use it for RTT calculation in the absence of
 	 * the timestamp option.
 	 */
-	for (skb = skb_peek(&sk->write_queue);
+	for (old_next_skb = skb = skb_peek(&sk->write_queue);
 	     ((skb != tp->send_head) &&
 	      (skb != (struct sk_buff *)&sk->write_queue));
-	     skb = skb->next) 
-		if (skb->len > mss)
-			tcp_retransmit_skb(sk, skb); 
+	     skb = skb->next) {
+		int resend_skb = 0;
+
+		/* Our goal is to push out the packets which we
+		 * sent already, but are being chopped up now to
+		 * account for the PMTU information we have.
+		 *
+		 * As we resend the queue, packets are fragmented
+		 * into two pieces, and when we try to send the
+		 * second piece it may be collapsed together with
+		 * a subsequent packet, and so on.  -DaveM
+		 */
+		if (old_next_skb != skb || skb->len > mss)
+			resend_skb = 1;
+		old_next_skb = skb->next;
+		if (resend_skb != 0)
+			tcp_retransmit_skb(sk, skb);
+	}
 }
 
 static __inline__ void update_retrans_head(struct sock *sk)
diff -urN linux-2.2.8-pre5/net/ipv4/tcp_timer.c linux-2.2.8-pre6/net/ipv4/tcp_timer.c
--- linux-2.2.8-pre5/net/ipv4/tcp_timer.c	1999-04-28 09:51:57.000000000 -0700
+++ linux-2.2.8-pre6/net/ipv4/tcp_timer.c	2003-08-15 15:06:14.000000000 -0700
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.60 1999/04/28 16:08:21 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.62 1999/05/08 21:09:55 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -317,48 +317,47 @@
 void tcp_tw_schedule(struct tcp_tw_bucket *tw)
 {
 	int slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
+	struct tcp_tw_bucket **tpp = &tcp_tw_death_row[slot];
+
+	if((tw->next_death = *tpp) != NULL)
+		(*tpp)->pprev_death = &tw->next_death;
+	*tpp = tw;
+	tw->pprev_death = tpp;
 
 	tw->death_slot = slot;
-	tw->next_death = tcp_tw_death_row[slot];
-	tcp_tw_death_row[slot] = tw;
+
 	tcp_inc_slow_timer(TCP_SLT_TWKILL);
 }
 
 /* Happens rarely if at all, no care about scalability here. */
 void tcp_tw_reschedule(struct tcp_tw_bucket *tw)
 {
-	struct tcp_tw_bucket *walk;
-	int slot = tw->death_slot;
+	struct tcp_tw_bucket **tpp;
+	int slot;
+
+	if(tw->next_death)
+		tw->next_death->pprev_death = tw->pprev_death;
+	*tw->pprev_death = tw->next_death;
+	tw->pprev_death = NULL;
 
-	walk = tcp_tw_death_row[slot];
-	if(walk == tw) {
-		tcp_tw_death_row[slot] = tw->next_death;
-	} else {
-		while(walk->next_death != tw)
-			walk = walk->next_death;
-		walk->next_death = tw->next_death;
-	}
 	slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
+	tpp = &tcp_tw_death_row[slot];
+	if((tw->next_death = *tpp) != NULL)
+		(*tpp)->pprev_death = &tw->next_death;
+	*tpp = tw;
+	tw->pprev_death = tpp;
+
 	tw->death_slot = slot;
-	tw->next_death = tcp_tw_death_row[slot];
-	tcp_tw_death_row[slot] = tw;
 	/* Timer was incremented when we first entered the table. */
 }
 
 /* This is for handling early-kills of TIME_WAIT sockets. */
 void tcp_tw_deschedule(struct tcp_tw_bucket *tw)
 {
-	struct tcp_tw_bucket *walk;
-	int slot = tw->death_slot;
-
-	walk = tcp_tw_death_row[slot];
-	if(walk == tw) {
-		tcp_tw_death_row[slot] = tw->next_death;
-	} else {
-		while(walk->next_death != tw)
-			walk = walk->next_death;
-		walk->next_death = tw->next_death;
-	}
+	if(tw->next_death)
+		tw->next_death->pprev_death = tw->pprev_death;
+	*tw->pprev_death = tw->next_death;
+	tw->pprev_death = NULL;
 	tcp_dec_slow_timer(TCP_SLT_TWKILL);
 }
 
@@ -478,7 +477,7 @@
 		 * means it must be an accurate representation of our current
 		 * sending rate _and_ the snd_wnd.
 		 */
-		tp->snd_ssthresh = max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
 		tp->snd_cwnd_cnt = 0;
 		tp->snd_cwnd = 1;
 	}
diff -urN linux-2.2.8-pre5/net/ipv4/udp.c linux-2.2.8-pre6/net/ipv4/udp.c
--- linux-2.2.8-pre5/net/ipv4/udp.c	1999-03-21 07:22:00.000000000 -0800
+++ linux-2.2.8-pre6/net/ipv4/udp.c	2003-08-15 15:06:14.000000000 -0700
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.65 1999/03/21 05:22:49 davem Exp $
+ * Version:	$Id: udp.c,v 1.66 1999/05/08 20:00:25 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -955,7 +955,7 @@
 	 * Error for blocking case is chosen to masquerade
    	 * as some normal condition.
 	 */
-	return (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;	
+	return (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;	
 #endif
 }
 
diff -urN linux-2.2.8-pre5/net/ipv6/udp.c linux-2.2.8-pre6/net/ipv6/udp.c
--- linux-2.2.8-pre5/net/ipv6/udp.c	1999-04-22 19:45:20.000000000 -0700
+++ linux-2.2.8-pre6/net/ipv6/udp.c	2003-08-15 15:06:14.000000000 -0700
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.39 1999/04/22 10:07:47 davem Exp $
+ *	$Id: udp.c,v 1.40 1999/05/08 20:00:32 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -381,7 +381,7 @@
 			/* Error for blocking case is chosen to masquerade
 			   as some normal condition.
 			 */
-			err = (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+			err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
 			udp_stats_in6.UdpInErrors++;
 			goto out_free;
 		}
@@ -398,7 +398,7 @@
 			/* Error for blocking case is chosen to masquerade
 			   as some normal condition.
 			 */
-			err = (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+			err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
 			udp_stats_in6.UdpInErrors++;
 			goto out_free;
 		}
diff -urN linux-2.2.8-pre5/net/unix/af_unix.c linux-2.2.8-pre6/net/unix/af_unix.c
--- linux-2.2.8-pre5/net/unix/af_unix.c	1999-03-25 09:23:34.000000000 -0800
+++ linux-2.2.8-pre6/net/unix/af_unix.c	2003-08-15 15:06:14.000000000 -0700
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.75 1999/03/22 05:02:45 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.76 1999/05/08 05:54:55 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -322,7 +322,7 @@
 	{
 		if (sk->type==SOCK_STREAM && unix_our_peer(sk, skpair))
 		{
-			skpair->state_change(skpair);
+			skpair->data_ready(skpair,0);
 			skpair->shutdown=SHUTDOWN_MASK;	/* No more writes*/
 		}
 		unix_unlock(skpair); /* It may now die */
@@ -1409,7 +1409,10 @@
 			if (mode&SEND_SHUTDOWN)
 				peer_mode |= RCV_SHUTDOWN;
 			other->shutdown |= peer_mode;
-			other->state_change(other);
+			if (peer_mode&RCV_SHUTDOWN)
+				other->data_ready(other,0);
+			else
+				other->state_change(other);
 		}
 	}
 	return 0;
