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

diff -urN linux-2.4.23-bk11/CREDITS linux-2.4.23-bk12/CREDITS
--- linux-2.4.23-bk11/CREDITS	2003-12-16 03:08:57.000000000 -0800
+++ linux-2.4.23-bk12/CREDITS	2003-12-16 03:09:10.000000000 -0800
@@ -2597,9 +2597,9 @@
 S: USA
 
 N: Luca Risolia
-E: luca_ing@libero.it
-D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chip
-S: Via Libertà 41/a
+E: luca.risolia@studio.unibo.it
+D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
+S: Via Liberta' 41-A
 S: Osio Sotto, 24046, Bergamo
 S: Italy
 
diff -urN linux-2.4.23-bk11/Documentation/Configure.help linux-2.4.23-bk12/Documentation/Configure.help
--- linux-2.4.23-bk11/Documentation/Configure.help	2003-12-16 03:08:58.000000000 -0800
+++ linux-2.4.23-bk12/Documentation/Configure.help	2003-12-16 03:09:10.000000000 -0800
@@ -15370,19 +15370,18 @@
 
   This driver has an optional plugin, which is distributed as a
   separate module only (released under GPL). It contains code that 
-  allows you to use higher resolutions and framerates, and can't
-  be included into the official Linux kernel for performance 
-  purposes.
-  At the moment the driver needs a third-part module for the CMOS 
+  allows you to use higher resolutions and framerates, and cannot
+  be included in the official Linux kernel for performance purposes.
+  At the moment the driver needs a third-party module for the CMOS 
   sensors, which is available on internet: it is recommended to read
   <file:Documentation/usb/w9968cf.txt> for more informations and for
   a list of supported cameras.
 
   This driver uses the Video For Linux and the I2C APIs. 
-  You must say Y or M to both "Video For Linux" and 
-  "I2C Support" to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+  You must say Y or M to both "Video For Linux" and "I2C Support" 
+  to use this driver. Information on this API and pointers to "v4l" 
+  programs may be found on the WWW at 
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
diff -urN linux-2.4.23-bk11/Documentation/usb/w9968cf.txt linux-2.4.23-bk12/Documentation/usb/w9968cf.txt
--- linux-2.4.23-bk11/Documentation/usb/w9968cf.txt	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.23-bk12/Documentation/usb/w9968cf.txt	2003-12-16 03:09:10.000000000 -0800
@@ -1,6 +1,7 @@
 
-         W996[87]CF JPEG USB Dual Mode Camera Chip driver for Linux 2.4
-         ==============================================================
+                   W996[87]CF JPEG USB Dual Mode Camera Chip
+                        Linux 2.4 driver (basic version)
+                   =========================================
 
                                - Documentation -
 
@@ -11,7 +12,7 @@
 2. License
 3. Overview
 4. Supported devices
-5. Kernel configuration and third-part module compilation
+5. Module dependencies
 6. Module loading
 7. Module paramaters
 8. Credits
@@ -19,7 +20,7 @@
 
 1. Copyright
 ============
-Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it>
+Copyright (C) 2002 2003 by Luca Risolia <luca.risolia@studio.unibo.it>
 
 
 2. License
@@ -45,20 +46,23 @@
 Winbond W9967CF and Winbond W9968CF JPEG USB Dual Mode Camera Chips, when they
 are being commanded by USB.
 
-The driver relies on the Video4Linux, USB and I2C core modules of the Linux
-kernel, version 2.4.19 or greater, and is not compatible in any way with
-previous versions. It has been designed to run properly on SMP systems
-as well. At the moment, an additional module, "ovcamchip", is mandatory; it
-provides support for some OmniVision CMOS sensors connected to the W996[87]CF
-chips.
-
-The driver is split into two modules: the basic one, "w9968cf", is needed for
-the supported devices to work; the second one, "w9968cf-vpp", is an optional
-module, which provides some useful video post-processing functions like video
-decoding, up-scaling and colour conversions (these routines can't be included
-into official kernels). Once the driver is installed, every time an application
-tries to open a recognized device, "w9968cf" checks the presence of the
-"w9968cf-vpp" module and loads it automatically by default.
+The full-featured driver is divided into two modules: the basic one, "w9968cf",
+is needed for the supported devices to work; the second one, "w9968cf-vpp",
+is an optional module, which provides some useful video post-processing
+functions like video decoding, up-scaling and colour conversions. Once the
+driver is installed, every time an application tries to open a recognized
+device, "w9968cf" checks the presence of the "w9968cf-vpp" module and loads it
+automatically by default.
+
+Please keep in mind that official kernels do NOT include the second module for
+performance purposes. However it is always recommended to download and install
+the latest and complete release of the driver, replacing the existing one, if
+present: it will be still even possible not to load the "w9968cf-vpp" module at
+all, if you ever want to. Another important missing feature of the version in
+the official Linux 2.4 kernels is the writeable /proc filesystem interface.
+
+The latest and full-featured version of the W996[87]CF driver can be found at:
+http://go.lamarinapunto.com/
 
 Up to 32 cameras can be handled at the same time. They can be connected and
 disconnected from the host many times without turning off the computer, if
@@ -67,15 +71,17 @@
 To change the default settings for each camera, many paramaters can be passed
 through command line when the module is loaded into memory.
 
-It is recommended to install the latest and full featured version of the 
-W996[87]CF driver, which can be found at:
-http://go.lamarinapunto.com/
+The driver relies on the Video4Linux, USB and I2C core modules of the official
+Linux kernels, version 2.4.19 or greater, and is not compatible in any way with
+previous versions. It has been designed to run properly on SMP systems as well.
+At the moment, an additional module, "ovcamchip", is mandatory; it provides
+support for some OmniVision CMOS sensors connected to the W996[87]CF chips.
 
-The "ovcamchip" module is part of the OV511 driver, version 2.25, which can be
+The "ovcamchip" module is part of the OV511 driver, version 2.27, which can be
 downloaded from internet:
 http://alpha.dyndns.org/ov511/
-To know how to patch, compile and load it, read the "Kernel configuration"
-paragraph.
+To know how to compile it, read the documentation included in the OV511 
+package.
 
 
 4. Supported devices
@@ -94,22 +100,21 @@
 The list above does NOT imply that all those devices work with this driver: up
 until now only webcams that have a CMOS sensor supported by the "ovcamchip"
 module work. 
-For a list of supported CMOS sensors, please visit the module author homepage:
-http://alpha.dyndns.org/ov511/
+For a list of supported CMOS sensors, please visit the the author's homepage on
+this module: http://alpha.dyndns.org/ov511/
 
 Possible external microcontrollers of those webcams are not supported: this
-means that still images can't be downloaded from the device memory.
+means that still images cannot be downloaded from the device memory.
 
 Furthermore, it's worth to note that I was only able to run tests on my
 "Creative Labs Video Blaster WebCam Go". Donations of other models, for
 additional testing and full support, would be much appreciated.
 
 
-5. Kernel configuration and third-part module compilation
-=========================================================
-As noted above, kernel 2.4.19 is the minimum for this driver; for it to work
-properly, the driver needs kernel support for Video4Linux, USB and I2C, and a
-third-part module for the CMOS sensor.
+5. Module dependencies
+======================
+The driver needs kernel support for Video4Linux, USB and I2C, and a third-party
+module for the CMOS sensor.
 
 The following options of the kernel configuration file must be enabled and
 corresponding modules must be compiled:
@@ -128,7 +133,7 @@
 	#
 	CONFIG_USB=m
 
-In addition, depending on the hardware being used, just one of the modules
+In addition, depending on the hardware being used, only one of the modules
 below is necessary:
 
 	# USB Host Controller Drivers
@@ -138,6 +143,12 @@
 	CONFIG_USB_UHCI_ALT=m
 	CONFIG_USB_OHCI=m
 
+And finally:
+
+	# USB Multimedia devices
+	#
+	CONFIG_USB_W9968CF=m
+
 Also, make sure "Enforce bandwidth allocation" is NOT enabled.
 
 The /proc filesystem can be optionally built into the kernel:
@@ -150,39 +161,18 @@
 	#
 	CONFIG_VIDEO_PROC_FS=y
 
-	# USB Multimedia devices
-	#
-	CONFIG_USB_W9968CF=m
-
 The last module we need is "ovcamchip.o". To obtain it, you have to download
-the OV511 driver, version 2.25 - don't use other versions - which is available
-at http://alpha.dyndns.org/ov511/ . Then you have to download the latest 
-version of the full featured W996[87]CF driver, which contains a patch for the
-"ovcamchip" module; it is available at http://go.lamarinapunto.com .
-Once you have obtained the packages, decompress, patch and compile the 
-"ovcamchip" module. In other words:
-
-	[user@localhost home]$ tar xvzf w9968cf-x.x.tar.gz
-	[user@localhost home]$ tar xvjf ov511-2.25.tar.bz2
-	[user@localhost home]$ cd ov511-2.25
-	[user@localhost ov511-2.25]$ patch -p1 <                              \
-	                             /path/to/w9968cf-x.x/ov511-2.25.patch
-	[user@localhost ov511-2.25]$ make
-
-It's worth to note that the full featured version of the W996[87]CF driver
-can also be installed overwriting the one in the kernel; in this case, read the
-documentation included in the package.
-
-If everything went well, the W996[87]CF driver can be immediatly used (see next
-paragraph).
+the OV511, version 2.27 - don't use other versions - and compile it according
+to its documentation. 
+The package is available at http://alpha.dyndns.org/ov511/ .
 
 
 6. Module loading
 =================
 To use the driver, it is necessary to load the "w9968cf" module into memory
-after every other module required; they are named, in order: "videodev",
-"usbcore", then "ehci-hcd", "usb-uhci", "uhci", "usb-ohci" (just one), and also
-"i2c-core" and "ovcamchip".
+after every other module required: for the 2.4 series of the kernel, they are
+named, in order: "videodev", "usbcore", then "ehci-hcd", "usb-uhci", "uhci",
+"usb-ohci" (just one), and also "i2c-core" and "ovcamchip".
 
 Loading can be done this way, from root:
 
@@ -213,11 +203,10 @@
 
 7. Module paramaters
 ====================
-
 Module paramaters are listed below:
 -------------------------------------------------------------------------------
 Name:           vppmod_load
-Type:           int
+Type:           bool
 Syntax:         <0|1>
 Description:    Automatic 'w9968cf-vpp' module loading: 0 disabled, 1 enabled.
                 If enabled, every time an application attempts to open a
@@ -258,22 +247,22 @@
 Name:           max_buffers
 Type:           int array (min = 0, max = 32)
 Syntax:         <n[,...]>
-Description:    Only for advanced users.
+Description:    For advanced users.
                 Specify the maximum number of video frame buffers to allocate
                 for each device, from 2 to 32.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           double_buffer
-Type:           int array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]> 
 Description:    Hardware double buffering: 0 disabled, 1 enabled.
                 It should be enabled if you want smooth video output: if you
-                obtain out of sync. video, disable it at all, or try to
+                obtain out of sync. video, disable it, or try to
                 decrease the 'clockdiv' module paramater value.
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           clamping
-Type:           int array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]> 
 Description:    Video data clamping: 0 disabled, 1 enabled.
 Default:        0 for every device.
@@ -288,13 +277,13 @@
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           largeview
-Type:           int array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]> 
 Description:    Large view: 0 disabled, 1 enabled.
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           upscaling
-Type:           int array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]> 
 Description:    Software scaling (for non-compressed video only):
                 0 disabled, 1 enabled.
@@ -316,9 +305,8 @@
                 YUV420P/YUV420 in any resolutions where width and height are
                 multiples of 16.
 Default:        2 for every device.
-Note:           If 'w9968cf-vpp' is not loaded, this paramater is set to,
-                forcing decompression is not allowed; in this case this 
-                paramater is set to 2.
+Note:           If 'w9968cf-vpp' is not loaded, forcing decompression is not
+                allowed; in this case this paramater is set to 2.
 -------------------------------------------------------------------------------
 Name:           force_palette
 Type:           int array (min = 0, max = 32)
@@ -342,7 +330,7 @@
 Note:           If 'w9968cf-vpp' is not loaded, this paramater is set to 9.
 -------------------------------------------------------------------------------
 Name:           force_rgb
-Type:           int array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Read RGB video data instead of BGR:
                 1 = use RGB component ordering.
@@ -351,28 +339,28 @@
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           autobright
-Type:           long array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    CMOS sensor automatically changes brightness:
                 0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           autoexp
-Type:           long array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    CMOS sensor automatically changes exposure:
                 0 = no, 1 = yes
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           lightfreq
-Type:           long array (min = 0, max = 32)
+Type:           int array (min = 0, max = 32)
 Syntax:         <50|60[,...]>
 Description:    Light frequency in Hz:
                 50 for European and Asian lighting, 60 for American lighting.
 Default:        50 for every device.
 -------------------------------------------------------------------------------
 Name:           bandingfilter
-Type:           long array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]> 
 Description:    Banding filter to reduce effects of fluorescent 
                 lighting:
@@ -382,7 +370,7 @@
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           clockdiv
-Type:           long array (min = 0, max = 32)
+Type:           int array (min = 0, max = 32)
 Syntax:         <-1|n[,...]>
 Description:    Force pixel clock divisor to a specific value (for experts):
                 n may vary from 0 to 127.
@@ -391,21 +379,21 @@
 Default:        -1 for every device.
 -------------------------------------------------------------------------------
 Name:           backlight
-Type:           long array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Objects are lit from behind:
                 0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           mirror
-Type:           long array (min = 0, max = 32)
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Reverse image horizontally:
                 0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
-Name:           sensor_mono
-Type:           long array (min = 0, max = 32)
+Name:           monochrome
+Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]> 
 Description:    The CMOS sensor is monochrome:
                 0 = no, 1 = yes
@@ -446,7 +434,7 @@
 Type:           int
 Syntax:         <n> 
 Description:    Debugging information level, from 0 to 6:
-                0 = none (be cautious)
+                0 = none (use carefully)
                 1 = critical errors
                 2 = significant informations
                 3 = configuration or general messages
@@ -458,7 +446,7 @@
 Default:        2
 -------------------------------------------------------------------------------
 Name:           specific_debug
-Type:           int
+Type:           bool
 Syntax:         <0|1>
 Description:    Enable or disable specific debugging messages:
                 0 = print messages concerning every level <= 'debug' level.
@@ -479,8 +467,6 @@
 - memory management code has been copied from the bttv driver by Ralph Metzler,
   Marcus Metzler and Gerd Knorr;
 
-- the low-level I2C read function has been written by Frédéric Jouault, who
-  also gave me commented logs about sniffed USB traffic taken from another
-  driver for another system;
+- the low-level I2C read function has been written by Frederic Jouault;
 
-- the low-level I2C fast write function has been written by Piotr Czerczak;
+- the low-level I2C fast write function has been written by Piotr Czerczak.
diff -urN linux-2.4.23-bk11/MAINTAINERS linux-2.4.23-bk12/MAINTAINERS
--- linux-2.4.23-bk11/MAINTAINERS	2003-12-16 03:08:58.000000000 -0800
+++ linux-2.4.23-bk12/MAINTAINERS	2003-12-16 03:09:10.000000000 -0800
@@ -2070,11 +2070,11 @@
 S:	Maintained
 
 USB W9968CF DRIVER
-P:      Luca Risolia
-M:      luca_ing@libero.it
-L:      linux-usb-devel@lists.sourceforge.net
-W:      http://go.lamarinapunto.com
-S:      Maintained
+P:	Luca Risolia
+M:	luca.risolia@studio.unibo.it
+L:	linux-usb-devel@lists.sourceforge.net
+W:	http://go.lamarinapunto.com
+S:	Maintained
 
 VFAT FILESYSTEM:
 P:	Gordon Chaffee
diff -urN linux-2.4.23-bk11/Makefile linux-2.4.23-bk12/Makefile
--- linux-2.4.23-bk11/Makefile	2003-12-16 03:08:58.000000000 -0800
+++ linux-2.4.23-bk12/Makefile	2003-12-16 03:09:10.000000000 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 23
-EXTRAVERSION = -bk11
+EXTRAVERSION = -bk12
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.23-bk11/arch/ppc64/Makefile linux-2.4.23-bk12/arch/ppc64/Makefile
--- linux-2.4.23-bk11/arch/ppc64/Makefile	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/Makefile	2003-12-16 03:09:13.000000000 -0800
@@ -19,11 +19,11 @@
 CHECKS		= checks
 endif
 
-HAS_BIARCH      := $(shell if gcc -m64 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi;)
+HAS_BIARCH      := $(shell if $(CC) -m64 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi;)
 ifeq ($(HAS_BIARCH),y)
 AS              := $(AS) -64
 LD              := $(LD) -m elf64ppc
-CC		:= gcc -m64
+CC		:= $(CC) -m64
 endif
 
 LINKFLAGS	= -T arch/ppc64/vmlinux.lds -Bstatic \
@@ -33,6 +33,11 @@
 		-mtraceback=full
 CPP		= $(CC) -E $(CFLAGS)
 
+HAVE_ZERO_BSS := $(shell if $(CC) -fno-zero-initialized-in-bss -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi)
+
+ifeq ($(HAVE_ZERO_BSS),y)
+CFLAGS		+= -fno-zero-initialized-in-bss
+endif
 
 HEAD := arch/ppc64/kernel/head.o
 
diff -urN linux-2.4.23-bk11/arch/ppc64/boot/Makefile linux-2.4.23-bk12/arch/ppc64/boot/Makefile
--- linux-2.4.23-bk11/arch/ppc64/boot/Makefile	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/boot/Makefile	2003-12-16 03:09:13.000000000 -0800
@@ -31,6 +31,10 @@
 
 OBJCOPYFLAGS = contents,alloc,load,readonly,data
 
+LDVARS=	\
+	--defsym _vmlinux_memsize=0x`$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | sed '$$s/^........\([^ ]*\).*/\1/p;d'` \
+	--defsym _vmlinux_filesize=0x`ls -l $(TOPDIR)/vmlinux | awk '{ printf "%x\n", $$5 }'`
+
 .c.o:
 	$(BOOTCC) $(BOOTCFLAGS) -c -o $*.o $<
 .S.o:
@@ -39,7 +43,7 @@
 CFLAGS	= $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
 LD_ARGS = -Ttext 0x00400000 -e _start
 
-OBJS = crt0.o string.o prom.o zImage.o zlib.o imagesize.o
+OBJS = crt0.o string.o prom.o zImage.o zlib.o
 LIBS =
 
 ifeq ($(CONFIG_SMP),y)
@@ -88,12 +92,13 @@
 	$(HOSTCC) $(HOSTCFLAGS) -o addnote addnote.c
 
 
-imagesize.c: $(TOPDIR)/vmlinux
-	ls -l $(TOPDIR)/vmlinux | awk '{printf "/* generated -- do not edit! */\nunsigned long vmlinux_filesize = %d;\n", $$5}' > imagesize.c
-	$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | awk '{i=$$1}END{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr(i,8)}' >> imagesize.c
-
 zImage.o: $(TOPDIR)/vmlinux
 
+uts_string: uts_string.txt
+	$(OBJCOPY) zImage.o \
+		--add-section=.kernel:$@=$@.txt \
+		--set-section-flags=.kernel:$@=$(OBJCOPYFLAGS)
+
 vmlinux .config System.map: % : $(TOPDIR)/% zImage.o
 	gzip -cvf9 $(TOPDIR)/$@ > kernel-$@.gz
 	$(OBJCOPY) zImage.o \
@@ -105,17 +110,23 @@
 		--add-section=.kernel:$@=ramdisk.image.gz \
 		--set-section-flags=.kernel:$@=$(OBJCOPYFLAGS)
 
-zImage: $(OBJS) addnote vmlinux .config System.map
-	$(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) $(LIBS)
+uts_string.txt: $(TOPDIR)/vmlinux
+	strings $(TOPDIR)/vmlinux | \
+	grep -E 'Linux version .* .gcc version' > $@
+
+zImage: $(OBJS) addnote uts_string vmlinux .config System.map
+	$(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) $(LIBS) \
+        $(LDVARS)
 	./addnote $@
 
-zImage.initrd: $(OBJS) addnote vmlinux .config System.map initrd
-	$(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) $(LIBS)
+zImage.initrd: $(OBJS) addnote uts_string vmlinux .config System.map initrd
+	$(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) $(LIBS) \
+        $(LDVARS)
 	./addnote $@
 
 clean:
 	rm -f add{note,RamDisk,SystemMap} $(OBJS) initrd.o \
-		vmlinux.{sm,initrd} zImage{,.initrd} imagesize.c \
+		vmlinux.{sm,initrd} zImage{,.initrd} uts_string.txt \
 		kernel-{vmlinux,.config,System.map}.gz
 
 fastdep:
diff -urN linux-2.4.23-bk11/arch/ppc64/boot/zImage.c linux-2.4.23-bk12/arch/ppc64/boot/zImage.c
--- linux-2.4.23-bk11/arch/ppc64/boot/zImage.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/boot/zImage.c	2003-12-16 03:09:13.000000000 -0800
@@ -12,7 +12,6 @@
 #include "ppc32-types.h"
 #include "zlib.h"
 #include <linux/elf.h>
-#include <linux/version.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/bootinfo.h>
@@ -53,8 +52,9 @@
 extern char _sysmap_end[];
 extern char _initrd_start[];
 extern char _initrd_end[];
-extern unsigned long vmlinux_filesize;
-extern unsigned long vmlinux_memsize;
+
+extern void *_vmlinux_filesize;
+extern void *_vmlinux_memsize;
 
 struct addr_range {
 	unsigned long addr;
@@ -69,8 +69,8 @@
 static char scratch[128<<10];	/* 128kB of scratch space for gunzip */
 
 typedef void (*kernel_entry_t)( unsigned long,
-                                unsigned long,
-                                void *,
+		                unsigned long,
+		                void *,
 				struct bi_record *);
 
 
@@ -86,13 +86,12 @@
 start(unsigned long a1, unsigned long a2, void *promptr)
 {
 	unsigned long i, claim_addr, claim_size;
+	unsigned long vmlinux_filesize;
 	extern char _start;
 	struct bi_record *bi_recs;
 	kernel_entry_t kernel_entry;
 	Elf64_Ehdr *elf64;
 	Elf64_Phdr *elf64ph;
-	/* tell userland tools about uname -r */
-	unsigned char this_uts[] = "Linux version " UTS_RELEASE;
 
 	prom = (int (*)(void *)) promptr;
 	chosen_handle = finddevice("/chosen");
@@ -104,20 +103,7 @@
 	if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
 		exit();
 
-	printf("zImage starting: loaded at 0x%x\n\r", (unsigned)&_start);
-	printf("%s\n\r", this_uts);
-
-#if 0
-	sysmap.size = (unsigned long)(_sysmap_end - _sysmap_start);
-	sysmap.memsize = sysmap.size;
-	if ( sysmap.size > 0 ) {
-		sysmap.addr = (RAM_END - sysmap.size) & ~0xFFF;
-		claim(sysmap.addr, RAM_END - sysmap.addr, 0);
-		printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r",
-		       sysmap.addr, (unsigned long)_sysmap_start, sysmap.size);
-		memcpy((void *)sysmap.addr, (void *)_sysmap_start, sysmap.size);
-	}
-#endif
+	printf("\n\rzImage starting: loaded at 0x%x\n\r", (unsigned)&_start);
 
 	initrd.size = (unsigned long)(_initrd_end - _initrd_start);
 	initrd.memsize = initrd.size;
@@ -133,12 +119,13 @@
 	vmlinuz.addr = (unsigned long)_vmlinux_start;
 	vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
 	vmlinux.addr = (unsigned long)(void *)-1;
+	vmlinux_filesize = (unsigned long)&_vmlinux_filesize;
 	vmlinux.size = PAGE_ALIGN(vmlinux_filesize);
-	vmlinux.memsize = vmlinux_memsize;
+	vmlinux.memsize = (unsigned long)&_vmlinux_memsize;
 
 	claim_size = vmlinux.memsize /* PPPBBB: + fudge for bi_recs */;
-	for(claim_addr = PROG_START; 
-	    claim_addr <= PROG_START * 8; 
+	for(claim_addr = PROG_START;
+	    claim_addr <= PROG_START * 8;
 	    claim_addr += 0x100000) {
 		printf("    trying: 0x%08lx\n\r", claim_addr);
 		vmlinux.addr = (unsigned long)claim(claim_addr, claim_size, 0);
diff -urN linux-2.4.23-bk11/arch/ppc64/boot/zImage.lds linux-2.4.23-bk12/arch/ppc64/boot/zImage.lds
--- linux-2.4.23-bk11/arch/ppc64/boot/zImage.lds	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/boot/zImage.lds	2003-12-16 03:09:13.000000000 -0800
@@ -58,6 +58,8 @@
     CONSTRUCTORS
   }
 
+  .kernel:uts_string : { *(.kernel:uts_string) }
+
   . = ALIGN(4096);
   _vmlinux_start =  .;
   .kernel:vmlinux : { *(.kernel:vmlinux) }
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/entry.S linux-2.4.23-bk12/arch/ppc64/kernel/entry.S
--- linux-2.4.23-bk11/arch/ppc64/kernel/entry.S	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/entry.S	2003-12-16 03:09:14.000000000 -0800
@@ -46,16 +46,17 @@
  */
 	.text
 _GLOBAL(DoSyscall)
-	std	r0,THREAD+LAST_SYSCALL(r13)
 	ld	r11,_CCR(r1)	/* Clear SO bit in CR */
 	lis	r10,0x1000
 	andc	r11,r11,r10
 	std	r11,_CCR(r1)
+	ld	r10,PACACURRENT(r13)
+	std	r0,THREAD+LAST_SYSCALL(r10)
 #ifdef SHOW_SYSCALLS
 # ifdef SHOW_SYSCALLS_TASK
 	LOADBASE(r31,show_syscalls_task)
 	ld	r31,show_syscalls_task@l(r31)
-	cmp	0,r13,r31
+	cmp	0,r10,r31
 	bne	1f
 # endif /* SHOW_SYSCALLS_TASK */
 	LOADADDR(r3,7f)
@@ -69,7 +70,7 @@
 	LOADADDR(r3,77f)
 	ld	r4,GPR8(r1)
 	ld	r5,GPR9(r1)
-	mr	r6,r13
+	ld	r6, PACACURRENT(r13)
 	bl	.printk
 	ld	r0,GPR0(r1)
 	ld	r3,GPR3(r1)
@@ -80,8 +81,8 @@
 	ld	r8,GPR8(r1)
 1:
 #endif /* SHOW_SYSCALLS */
-	ld	r10,TASK_PTRACE(r13)
-	andi.	r10,r10,PT_TRACESYS
+	ld	r11,TASK_PTRACE(r10)
+	andi.	r11,r11,PT_TRACESYS
 	bne-	50f
 	cmpli	0,r0,NR_syscalls
 	bge-	66f
@@ -90,10 +91,10 @@
  *
  */
 #ifdef CONFIG_BINFMT_ELF32
-	ld	r10,THREAD+THREAD_FLAGS(r13)
-	andi.	r10,r10,PPC_FLAG_32BIT
+	ld	r11,THREAD+THREAD_FLAGS(r10)
+	andi.	r11,r11,PPC_FLAG_32BIT
 	beq-	15f
-	LOADADDR(r10,.sys_call_table32)
+	LOADADDR(r11,.sys_call_table32)
 /* Now mung the first 4 parameters into shape, by making certain that
  * the high bits (most significant 32 bits in 64 bit reg) are 0
  * for the first 4 parameter regs(3-6).
@@ -105,10 +106,10 @@
 	b	17f
 15:
 #endif
-	LOADADDR(r10,.sys_call_table)
+	LOADADDR(r11,.sys_call_table)
 17:
 	slwi	r0,r0,3
-	ldx	r10,r10,r0	/* Fetch system call handler [ptr] */
+	ldx	r10,r11,r0	/* Fetch system call handler [ptr] */
 	mtlr	r10
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 	blrl			/* Call handler */
@@ -153,7 +154,8 @@
 	cmpli	0,r0,NR_syscalls
 	bge-	66f
 #ifdef CONFIG_BINFMT_ELF32
-	ld	r10,THREAD+THREAD_FLAGS(r13)
+	ld	r10,PACACURRENT(r13)
+	ld	r10,THREAD+THREAD_FLAGS(r10)
 	andi.	r10,r10,PPC_FLAG_32BIT
 	beq-	55f
 	LOADADDR(r10,.sys_call_table32)
@@ -214,7 +216,8 @@
 _GLOBAL(ppc64_rt_sigreturn)
 	bl	.sys_rt_sigreturn
 
-80:	ld	r10,TASK_PTRACE(r13)
+80:	ld	r10,PACACURRENT(r13)
+	ld	r10,TASK_PTRACE(r10)
 	andi.	r10,r10,PT_TRACESYS
 	bne-	81f
 	cmpi	0,r3,0
@@ -266,10 +269,9 @@
 	std	r6,TRAP(r1)
 	std	r1,KSP(r3)	/* Set old stack pointer */
 
-	mfspr	r5,SPRG3	/* Get Paca */
 	addi	r3,r3,-THREAD	/* old 'current' for return value */
-	addi	r13,r4,-THREAD	/* Convert THREAD to 'current' */
-	std	r13,PACACURRENT(r5)	/* Set new 'current' */
+	addi	r7,r4,-THREAD	/* Convert THREAD to 'current' */
+	std	r7,PACACURRENT(r13)	/* Set new 'current' */
 
 #ifdef CONFIG_PPC_ISERIES
 	ld	r7,THREAD_FLAGS(r4)	/* Get run light flag */
@@ -292,7 +294,8 @@
 
 _GLOBAL(ret_from_fork)
 	bl	.schedule_tail
-	ld	r0,TASK_PTRACE(r13)
+	ld	r4,PACACURRENT(r13)
+	ld	r0,TASK_PTRACE(r4)
 	andi.	r0,r0,PT_TRACESYS
 	beq+	.ret_from_except
 	bl	.syscall_trace
@@ -308,9 +311,8 @@
 	CHECKANYINT(r3,r4)
 	beq+	4f	/* skip do_IRQ if no interrupts */
 
-	mfspr	r5,SPRG3
 	li	r3,0
-	stb	r3,PACAPROCENABLED(r5)	/* ensure we are disabled */
+	stb	r3,PACAPROCENABLED(r13)	/* ensure we are disabled */
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	.do_IRQ
 	b	irq_recheck	/* loop back and handle more */
@@ -322,14 +324,16 @@
 	beq+	restore		/* if so, check need_resched and signals */
 _GLOBAL(ret_to_user_hook)
 	nop
-	/* NEED_RESCHED is a volatile long (64-bits) */ 
-	ld	r3,NEED_RESCHED(r13)
+	/* NEED_RESCHED is a volatile long (64-bits) */
+	ld	r3,PACACURRENT(r13)
+	ld	r3,NEED_RESCHED(r3)
 	cmpi	0,r3,0		/* check need_resched flag */
 	beq+	7f
 	bl	.schedule
 	/* SIGPENDING is an int (32-bits) */
-7:	
-	lwz	r5,SIGPENDING(r13) /* Check for pending unblocked signals */
+7:
+	ld	r5,PACACURRENT(r13)
+	lwz	r5,SIGPENDING(r5) /* Check for pending unblocked signals */
 	cmpwi	0,r5,0
 	beq+	restore
 	li	r3,0
@@ -372,26 +376,31 @@
 #endif
 	stdcx.	r0,0,r1		/* to clear the reservation */
 
-	mfspr	r4,SPRG3	/* current task's PACA */
 #ifdef DO_SOFT_DISABLE
 	ld	r0,SOFTE(r1)
-	stb	r0,PACAPROCENABLED(r4)
+	stb	r0,PACAPROCENABLED(r13)
 #endif
 	/* if returning to user mode, save kernel SP */
 	ld	r0,_MSR(r1)
 	andi.	r0,r0,MSR_PR
 	beq+	1f
+	ld	r4,PACACURRENT(r13)
 	addi	r0,r1,INT_FRAME_SIZE	/* size of frame */
-	std	r0,THREAD+KSP(r13)	/* save kernel stack pointer */
-	std	r1,PACAKSAVE(r4)	/* save exception stack pointer */
+	std	r0,THREAD+KSP(r4)	/* save kernel stack pointer */
+	std	r1,PACAKSAVE(r13)	/* save exception stack pointer */
+	REST_GPR(13,r1)
 1:
+	mfmsr	r0
+	li	r2, MSR_RI
+	andc	r0,r0,r2
+	mtmsrd	r0,1
+
 	ld	r0,_MSR(r1)
 	mtspr	SRR1,r0
 	ld	r2,_CCR(r1)
 	mtcrf	0xFF,r2
 	ld	r2,_NIP(r1)
 	mtspr	SRR0,r2
-	REST_GPR(13,r1)
 	ld	r0,GPR0(r1)
 	ld	r2,GPR2(r1)
 	ld	r3,GPR3(r1)
@@ -440,11 +449,10 @@
 	/* Unfortunately, the stack pointer and the MSR are also clobbered,
 	 * so they are saved in the PACA (SPRG3) which allows us to restore
 	 * our original state after RTAS returns.
-         */
-	mfspr	r4,SPRG3		/* Get PACA */
-	std	r1,PACAR1(r4)
+	 */
+	std	r1,PACAR1(r13)
 	mfmsr	r6
-        std	r6,PACASAVEDMSR(r4)
+	std	r6,PACASAVEDMSR(r13)
 
 	/* Setup our real return addr */	
 	SET_REG_TO_LABEL(r4,.rtas_return_loc)
@@ -473,13 +481,19 @@
 
 _STATIC(rtas_return_loc)
 	/* relocation is off at this point */
-	mfspr	r4,SPRG3	        /* Get PACA */
+	mfspr	r13,SPRG3	        /* Get PACA */
 	SET_REG_TO_CONST(r5, KERNELBASE)
-        sub     r4,r4,r5                /* RELOC the PACA base pointer */
-        
-        ld	r1,PACAR1(r4)           /* Restore our SP */
+	sub     r13,r13,r5              /* RELOC the PACA base pointer */
+
+	mfmsr	r6			/* Clear RI while SRR0/1 are live */
+	li	r0,MSR_RI
+	andc	r6,r6,r0
+	sync
+	mtmsrd	r6
+
+	ld	r1,PACAR1(r13)           /* Restore our SP */
 	LOADADDR(r3,.rtas_restore_regs)
-        ld	r4,PACASAVEDMSR(r4)     /* Restore our MSR */
+	ld	r4,PACASAVEDMSR(r13)     /* Restore our MSR */
 
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
@@ -492,9 +506,8 @@
 	REST_8GPRS(14, r1)		/* Restore the non-volatiles */
 	REST_10GPRS(22, r1)		/* ditto */
 
-	/* put back current in r13 */
-        mfspr	r4,SPRG3
-	ld	r13,PACACURRENT(r4)
+	/* put back paca in r13 */
+	mfspr	r13,SPRG3
 
 	ld	r4,_CCR(r1)
 	mtcr	r4
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/head.S linux-2.4.23-bk12/arch/ppc64/kernel/head.S
--- linux-2.4.23-bk11/arch/ppc64/kernel/head.S	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.23-bk12/arch/ppc64/kernel/head.S	2003-12-16 03:09:14.000000000 -0800
@@ -130,6 +130,10 @@
  * All of it must fit below the first exception vector at 0x100.
  */
 _GLOBAL(__secondary_hold)
+	mfmsr	r24
+	ori	r24,r24,MSR_RI
+	mtmsrd	r24			/* RI on */
+
 	/* Grab our linux cpu number */
 	mr      r24,r3
 
@@ -201,7 +205,7 @@
 		                        /*   assumes *_common < 16b   */ \
 	mfmsr   r23;                                                     \
 	rotldi  r23,r23,4;                                               \
-	ori     r23,r23,0x30B;          /* Set IR, DR, SF, ISF, HV    */ \
+	ori     r23,r23,0x32B;          /* Set IR, DR, RI, SF, ISF, HV*/ \
 	rotldi  r23,r23,60;             /* for generic handlers       */ \
 	mtspr   SRR0,r22;                                                \
 	mtspr   SRR1,r23;                                                \
@@ -285,7 +289,7 @@
 	SAVE_8GPRS(2, r1);              /* save r2 - r13 in stackframe */ \
 	SAVE_4GPRS(10, r1);                                               \
 	ld      r2,PACATOC(r20);	                                  \
-	ld      r13,PACACURRENT(r20)
+	mr	r13,r20
 
 /*
  * Note: code which follows this uses cr0.eq (set if from kernel),
@@ -436,8 +440,8 @@
 
 	.globl SystemReset_Iseries
 SystemReset_Iseries:
-	mfspr	25,SPRG3		/* Get paca address */
-	lhz	r24,PACAPACAINDEX(r25)	/* Get processor # */
+	mfspr	13,SPRG3		/* Get paca address */
+	lhz	r24,PACAPACAINDEX(r13)	/* Get processor # */
 	cmpi	0,r24,0			/* Are we processor 0? */
 	beq	.__start_initialization_iSeries	/* Start up the first processor */
 	mfspr	r4,CTRLF
@@ -448,7 +452,7 @@
 1:
 	HMT_LOW
 #ifdef CONFIG_SMP
-	lbz	r23,PACAPROCSTART(r25)	/* Test if this processor
+	lbz	r23,PACAPROCSTART(r13)	/* Test if this processor
 					 * should start */
 	sync
 	LOADADDR(r3,current_set)
@@ -478,7 +482,7 @@
 #endif /* CONFIG_SMP */
 	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
 	sc				/* Invoke the hypervisor via a system call */
-	mfspr	r25,SPRG3		/* Put r25 back ???? */
+	mfspr	r13,SPRG3		/* Put r13 back - why???? */
 	b	1b			/* If SMP not configured, secondaries
 					 * loop forever */
 
@@ -570,6 +574,12 @@
 	REST_GPR(0, r1)
 	REST_8GPRS(2, r1)
 	REST_4GPRS(10, r1)
+
+	mfmsr	r20
+	li	r21, MSR_RI
+	andc	r20,r20,r21
+	mtmsrd	r20,1
+
 	mtspr   SRR1,r23
 	mtspr   SRR0,r22
 	REST_4GPRS(20, r1)
@@ -1143,6 +1153,12 @@
 	lwz	r23,EX_CCR(r21)		/* get saved CR */
 	/* note that this is almost identical to maskable_exception_exit */
 	mtcr    r23                     /* restore CR */
+
+	mfmsr	r22
+	li	r23, MSR_RI
+	andc	r22,r22,r23
+	mtmsrd	r22,1
+
 	ld	r22,EX_SRR0(r21)	/* Get SRR0 from exc. frame */
 	ld	r23,EX_SRR1(r21)	/* Get SRR1 from exc. frame */
 	mtspr	SRR0,r22
@@ -1184,7 +1200,7 @@
 	slbmfee	r23,r22
 	rldicl  r23,r23,37,63
 	cmpwi   r23,0
-	beq     3f              /* Found an invalid entry              */
+	beq     4f              /* Found an invalid entry              */
 
 	addi	r22,r22,1
 	cmpldi	r22,64
@@ -1193,16 +1209,36 @@
 	/* No free entry - just take the next entry, round-robin */
 	/* XXX we should get the number of SLB entries from the naca */
 SLB_NUM_ENTRIES = 64
-	mfspr	r21,SPRG3
+2:	mfspr	r21,SPRG3
 	ld	r22,PACASTABRR(r21)
 	addi	r23,r22,1
 	cmpdi	r23,SLB_NUM_ENTRIES
-	blt	2f
+	blt	3f
 	li	r23,1
-2:	std	r23,PACASTABRR(r21)
+3:	std	r23,PACASTABRR(r21)
 
 	/* r20 = vsid, r22 = entry */
-3:
+
+	/*
+	 * Never cast out the segment for our kernel stack. Since we
+	 * dont invalidate the ERAT we could have a valid translation
+	 * for the kernel stack during the first part of exception exit
+	 * which gets invalidated due to a tlbie from another cpu at a
+	 * non recoverable point (after setting srr0/1) - Anton
+	 */
+	slbmfee	r23,r22
+	srdi	r23,r23,28
+	/*
+	 * This is incorrect (r1 is not the kernel stack) if we entered
+	 * from userspace but there is no critical window from userspace
+	 * so this should be OK. Also if we cast out the userspace stack
+	 * segment while in userspace we will fault it straight back in.
+	 */
+	srdi	r21,r1,28
+	cmpd	r21,r23
+	beq-	2b
+	
+4:
 	/* Put together the vsid portion of the entry. */
 	li      r21,0
 	rldimi  r21,r20,12,0
@@ -1237,6 +1273,12 @@
 	lwz	r23,EX_CCR(r21)		/* get saved CR */
 	/* note that this is almost identical to maskable_exception_exit */
 	mtcr    r23                     /* restore CR */
+
+	mfmsr	r22
+	li	r23, MSR_RI
+	andc	r22,r22,r23
+	mtmsrd	r22,1
+
 	ld	r22,EX_SRR0(r21)	/* Get SRR0 from exc. frame */
 	ld	r23,EX_SRR1(r21)	/* Get SRR1 from exc. frame */
 	mtspr	SRR0,r22
@@ -1295,21 +1337,21 @@
 	 * Indicate that r1 contains the kernel stack and
 	 * get the Kernel TOC and CURRENT pointers from the paca
 	 */
-	mfspr	r23,SPRG3		/* Get PACA */
-	std	r22,PACAKSAVE(r23)	/* r1 is now kernel sp */
-	ld	r2,PACATOC(r23)		/* Get Kernel TOC pointer */
+	std	r22,PACAKSAVE(r13)	/* r1 is now kernel sp */
+	ld	r2,PACATOC(r13)		/* Get Kernel TOC pointer */
 
 	/*
 	 * If from user state, update THREAD.regs
 	 */
 	beq	2f			/* Modify THREAD.regs if from user */
 	addi	r24,r1,STACK_FRAME_OVERHEAD
-	std	r24,THREAD+PT_REGS(r13)
+	ld	r22,PACACURRENT(r13)
+	std	r24,THREAD+PT_REGS(r22)
 2:
 	SET_REG_TO_CONST(r22, MSR_KERNEL)
 
 #ifdef DO_SOFT_DISABLE
-	stb	r20,PACAPROCENABLED(r23) /* possibly soft enable */
+	stb	r20,PACAPROCENABLED(r13) /* possibly soft enable */
 	ori	r22,r22,MSR_EE		/* always hard enable */
 #else
 	rldimi	r22,r20,15,48		/* Insert desired EE value */
@@ -1356,20 +1398,20 @@
 
 	/* Set up a paca value for this processor. */
 	LOADADDR(r24, paca) 		 /* Get base vaddr of Paca array  */
-	mulli	r25,r3,PACA_SIZE	 /* Calculate vaddr of right Paca */
-	add	r25,r25,r24              /* for this processor.           */
+	mulli	r13,r3,PACA_SIZE	 /* Calculate vaddr of right Paca */
+	add	r13,r13,r24              /* for this processor.           */
 
-	mtspr	SPRG3,r25		 /* Save vaddr of Paca in SPRG3   */
+	mtspr	SPRG3,r13		 /* Save vaddr of Paca in SPRG3   */
 	mr	r24,r3			 /* __secondary_start needs cpu#  */
 
 1:
 	HMT_LOW
-	lbz	r23,PACAPROCSTART(r25)	 /* Test if this processor should */
+	lbz	r23,PACAPROCSTART(r13)	 /* Test if this processor should */
 					 /* start.                        */
 	sync
 
         /* Create a temp kernel stack for use before relocation is on.    */
-        mr      r1,r25
+	mr	r1,r13
         addi    r1,r1,PACAGUARD
         addi    r1,r1,0x1000
         subi    r1,r1,STACK_FRAME_OVERHEAD
@@ -1609,16 +1651,17 @@
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
-	addi	r5,r13,THREAD
-	ld	r4,THREAD_FPEXC_MODE(r5)
+	ld	r4,PACACURRENT(r13)
+	addi	r5,r4,THREAD		/* Get THREAD */
+	ld	r20,THREAD_FPEXC_MODE(r5)
 	ori	r23,r23,MSR_FP
-	or	r23,r23,r4
+	or	r23,r23,r20
 	lfd	fr0,THREAD_FPSCR(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
 #ifndef CONFIG_SMP
 	/* Update last_task_used_math to 'current' */
-	std	r13,last_task_used_math@l(r3)
+	std	r4,last_task_used_math@l(r3)
 #endif /* CONFIG_SMP */
 	/* restore registers and return */
 	b	fast_exception_return
@@ -1685,7 +1728,7 @@
  * On entry the following are set:
  *   r1    = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
  *   r24   = cpu# (in Linux terms)
- *   r25   = paca virtual address
+ *   r13   = paca virtual address
  *   SPRG3 = paca virtual address
  */
 _GLOBAL(__secondary_start)
@@ -1697,10 +1740,10 @@
 	addi    r2,r2,0x4000
 	addi    r2,r2,0x4000
 
-	std	r2,PACATOC(r25)
+	std	r2,PACATOC(r13)
 	li	r6,0
-	std	r6,PACAKSAVE(r25)
-	stb	r6,PACAPROCENABLED(r25)
+	std	r6,PACAKSAVE(r13)
+	stb	r6,PACAPROCENABLED(r13)
 
 #ifndef CONFIG_PPC_ISERIES
 	/* Initialize the page table pointer register. */
@@ -1709,18 +1752,18 @@
 	mtspr	SDR1,r6			/* set the htab location  */
 #endif
 	/* Initialize the first segment table (or SLB) entry                */
-	ld	r3,PACASTABVIRT(r25)    /* get addr of segment table        */
+	ld	r3,PACASTABVIRT(r13)    /* get addr of segment table        */
 	bl	.stab_initialize
 
 	/* Initialize the kernel stack.  Just a repeat for iSeries.         */
 	LOADADDR(r3,current_set)
 	sldi	r28,r24,4		/* get current_set[cpu#] */
-	ldx	r13,r3,r28
-	std	r13,PACACURRENT(r25)
-	addi	r1,r13,TASK_UNION_SIZE
+	ldx	r28,r3,r28
+	std	r28,PACACURRENT(r13)
+	addi	r1,r28,TASK_UNION_SIZE
 	subi	r1,r1,STACK_FRAME_OVERHEAD
 
-	ld	r3,PACASTABREAL(r25)    /* get raddr of segment table       */
+	ld	r3,PACASTABREAL(r13)    /* get raddr of segment table       */
 	ori	r4,r3,1			/* turn on valid bit                */
 
 #ifdef CONFIG_PPC_ISERIES
@@ -1807,6 +1850,10 @@
 	bl	.reloc_offset
 	mr	r26,r3
 
+	mfmsr	r6
+	ori	r6,r6,MSR_RI
+	mtmsrd	r6			/* RI on */
+
 	/* setup the systemcfg pointer which is needed by *tab_initialize  */
 	LOADADDR(r6,systemcfg)
 	sub	r6,r6,r26                /* addr of the variable systemcfg */
@@ -1880,9 +1927,9 @@
 	/* stab_initialize                                                 */
 	li	r27,0x4000
 	ld	r6,PACA(r27)            /* Get the base paca pointer       */
-	sub	r6,r6,r26		/* convert to physical addr         */
-	mtspr	SPRG3,r6		/* PPPBBB: Temp... -Peter */
-	ld	r3,PACASTABREAL(r6)
+	sub	r13,r6,r26		/* convert to physical addr         */
+	mtspr	SPRG3,r13		/* PPPBBB: Temp... -Peter */
+	ld	r3,PACASTABREAL(r13)
 	ori	r4,r3,1			/* turn on valid bit                */
 
 	/* set the ASR */
@@ -1973,16 +2020,16 @@
 
 	LOADADDR(r4,naca)               /* Get naca ptr address           */
 	ld	r4,0(r4)                /* Get the location of the naca   */
-	ld	r4,PACA(r4)             /* Get the base paca pointer      */
-	mtspr	SPRG3,r4
+	ld	r13,PACA(r4)            /* Get the base paca pointer      */
+	mtspr	SPRG3,r13
 
 	/* ptr to current */
-	LOADADDR(r13,init_task_union)
-	std	r13,PACACURRENT(r4)
+	LOADADDR(r4,init_task_union)
+	std	r4,PACACURRENT(r13)
 
-	std	r2,PACATOC(r4)
+	std	r2,PACATOC(r13)
 	li	r5,0
-	std	r0,PACAKSAVE(r4)
+	std	r0,PACAKSAVE(r13)
 
 	/* ptr to hardware interrupt stack for processor 0                */
 	LOADADDR(r3, hardware_int_paca0)
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/ioctl32.c linux-2.4.23-bk12/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/ioctl32.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/ioctl32.c	2003-12-16 03:09:14.000000000 -0800
@@ -566,11 +566,52 @@
 		goto out;
 	}
 	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO:	len = sizeof(struct ethtool_drvinfo); break;
+	case ETHTOOL_GSTRINGS:	{
+		struct ethtool_gstrings *stringsaddr = (struct ethtool_gstrings *)A(data);
+		if (get_user(len, (u32 *)&stringsaddr->len)) {
+			err = -EFAULT;
+			goto out;
+		}
+		if (len > (PAGE_SIZE - sizeof(struct ethtool_gstrings))/ETH_GSTRING_LEN ) {
+			err = -EINVAL;
+			goto out;
+		}
+		len = (len*ETH_GSTRING_LEN) + sizeof(struct ethtool_gstrings);
+		break;
+	}
+	case ETHTOOL_GSTATS:	{
+		struct ethtool_stats *statsaddr = (struct ethtool_stats *)A(data);
+		if (get_user(len, (u32 *)&statsaddr->n_stats)) {
+			err = -EFAULT;
+			goto out;
+		}
+		if (len > (PAGE_SIZE - sizeof(struct ethtool_stats))/sizeof(u64) ) {
+			err = -EINVAL;
+			goto out;
+		}
+		len = (len*sizeof(u64)) + sizeof(struct ethtool_stats);
+		break;
+	}
+	case ETHTOOL_SWOL:
+	case ETHTOOL_GWOL:
+		len = sizeof(struct ethtool_wolinfo);
+		break;
+	case ETHTOOL_GDRVINFO:
+		len = sizeof(struct ethtool_drvinfo);
+		break;
 	case ETHTOOL_GMSGLVL:
 	case ETHTOOL_SMSGLVL:
 	case ETHTOOL_GLINK:
-	case ETHTOOL_NWAY_RST:	len = sizeof(struct ethtool_value); break;
+	case ETHTOOL_NWAY_RST:
+	case ETHTOOL_SSG:
+	case ETHTOOL_GSG:
+	case ETHTOOL_GTXCSUM:
+	case ETHTOOL_STXCSUM:
+	case ETHTOOL_GRXCSUM:
+	case ETHTOOL_SRXCSUM:
+	case ETHTOOL_PHYS_ID:
+		len = sizeof(struct ethtool_value);
+		break;
 	case ETHTOOL_GREGS: {
 		struct ethtool_regs *regaddr = (struct ethtool_regs *)A(data);
 		/* darned variable size arguments */
@@ -578,22 +619,44 @@
 			err = -EFAULT;
 			goto out;
 		}
+		if (len > PAGE_SIZE - sizeof(struct ethtool_regs)) {
+			err = -EINVAL;
+			goto out;
+		}
 		len += sizeof(struct ethtool_regs);
 		break;
 	}
-	case ETHTOOL_GEEPROM: 
-	case ETHTOOL_SEEPROM: { 
-		struct ethtool_eeprom *promaddr = (struct ethtool_eeprom *)A(data); 
-		/* darned variable size arguments */ 
-		if (get_user(len, (u32 *)&promaddr->len)) { 
-			err = -EFAULT; 
-			goto out; 
-		} 
-		len += sizeof(struct ethtool_eeprom); 
-		break; 
-	} 
+	case ETHTOOL_GEEPROM:
+	case ETHTOOL_SEEPROM: {
+		struct ethtool_eeprom *promaddr = (struct ethtool_eeprom *)A(data);
+		/* darned variable size arguments */
+		if (get_user(len, (u32 *)&promaddr->len)) {
+			err = -EFAULT;
+			goto out;
+		}
+		if (len > PAGE_SIZE - sizeof(struct ethtool_eeprom)) {
+			err = -EINVAL;
+			goto out;
+		}
+		len += sizeof(struct ethtool_eeprom);
+		break;
+	}
+	case ETHTOOL_GRINGPARAM:
+	case ETHTOOL_SRINGPARAM:
+		len = sizeof(struct ethtool_ringparam);
+		break;
+	case ETHTOOL_GPAUSEPARAM:
+	case ETHTOOL_SPAUSEPARAM:
+		len = sizeof(struct ethtool_pauseparam);
+		break;
+	case ETHTOOL_GCOALESCE:
+	case ETHTOOL_SCOALESCE:
+		len = sizeof(struct ethtool_coalesce);
+		break;
 	case ETHTOOL_GSET:
-	case ETHTOOL_SSET:	len = sizeof(struct ethtool_cmd); break;
+	case ETHTOOL_SSET:
+		len = sizeof(struct ethtool_cmd);
+		break;
 	default:
 		err = -EOPNOTSUPP;
 		goto out;
@@ -1238,12 +1301,16 @@
 	u32 iov_len;
 } sg_iovec32_t;
 
+#define EMU_SG_MAX 128
+
 static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
 {
 	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
 	sg_iovec_t *kiov;
 	int i;
 
+	if (sgp->iovec_count > EMU_SG_MAX)
+		return -EINVAL;
 	sgp->dxferp = kmalloc(sgp->iovec_count *
 			      sizeof(sg_iovec_t), GFP_KERNEL);
 	if (!sgp->dxferp)
@@ -1257,39 +1324,9 @@
 		if (__get_user(iov_base32, &uiov->iov_base) ||
 		    __get_user(kiov->iov_len, &uiov->iov_len))
 			return -EFAULT;
-
-		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
-		if (!kiov->iov_base)
-			return -ENOMEM;
-		if (copy_from_user(kiov->iov_base,
-				   (void *) A(iov_base32),
-				   kiov->iov_len))
+		if (verify_area(VERIFY_WRITE, (void *)A(iov_base32), kiov->iov_len))
 			return -EFAULT;
-
-		uiov++;
-		kiov++;
-	}
-
-	return 0;
-}
-
-static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
-{
-	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
-	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
-	int i;
-
-	for (i = 0; i < sgp->iovec_count; i++) {
-		u32 iov_base32;
-
-		if (__get_user(iov_base32, &uiov->iov_base))
-			return -EFAULT;
-
-		if (copy_to_user((void *) A(iov_base32),
-				 kiov->iov_base,
-				 kiov->iov_len))
-			return -EFAULT;
-
+		kiov->iov_base = (void *)A(iov_base32);
 		uiov++;
 		kiov++;
 	}
@@ -1299,16 +1336,6 @@
 
 static void free_sg_iovec(sg_io_hdr_t *sgp)
 {
-	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
-	int i;
-
-	for (i = 0; i < sgp->iovec_count; i++) {
-		if (kiov->iov_base) {
-			kfree(kiov->iov_base);
-			kiov->iov_base = NULL;
-		}
-		kiov++;
-	}
 	kfree(sgp->dxferp);
 	sgp->dxferp = NULL;
 }
@@ -1337,6 +1364,10 @@
 	sg_io64.sbp = NULL;
 
 	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	if (sg_io64.cmd_len > 4*PAGE_SIZE || sg_io64.mx_sb_len > 4*PAGE_SIZE) {
+		err = -EINVAL;
+		goto out;
+	}
 	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
 	if (!sg_io64.cmdp) {
 		err = -ENOMEM;
@@ -1371,6 +1402,10 @@
 			goto out;
 		}
 	} else {
+		if (sg_io64.dxfer_len > 4*PAGE_SIZE) {
+			err = -EINVAL;
+			goto out;
+		}
 		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
 		if (!sg_io64.dxferp) {
 			err = -ENOMEM;
@@ -1411,7 +1446,7 @@
 	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
 	if (sg_io64.dxferp) {
 		if (sg_io64.iovec_count)
-			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
+			;
 		else
 			err |= copy_to_user((void *)A(dxferp32),
 					    sg_io64.dxferp,
@@ -1467,6 +1502,8 @@
 	case PPPIOCSCOMPRESS32:
 		if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32)))
 			return -EFAULT;
+		if (data32.length > PAGE_SIZE)
+			return -EINVAL;
 		data.ptr = kmalloc (data32.length, GFP_KERNEL);
 		if (!data.ptr)
 			return -ENOMEM;
@@ -1669,10 +1706,9 @@
 		err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf);
 		if (err)
 			return -EFAULT;
-		data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL);
-		if (!data)
-			return -ENOMEM;
-		cdreadaudio.buf = data;
+		if (verify_area(VERIFY_WRITE, (void *)A(addr), cdreadaudio.nframes*2352))
+			return -EFAULT;
+		cdreadaudio.buf = (void *)A(addr);
 		break;
 	case CDROM_SEND_PACKET:
 		karg = &cgc;
@@ -1681,9 +1717,9 @@
 		err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen);
 		if (err)
 			return -EFAULT;
-		if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL)
-			return -ENOMEM;
-		cgc.buffer = data;
+		if (verify_area(VERIFY_WRITE, (void *)A(addr), cgc.buflen))
+			return -EFAULT;
+		cgc.buffer = (void *)A(addr);
 		break;
 	default:
 		do {
@@ -1698,18 +1734,6 @@
 	set_fs (KERNEL_DS);
 	err = sys_ioctl (fd, cmd, (unsigned long)karg);
 	set_fs (old_fs);
-	if (err)
-		goto out;
-	switch (cmd) {
-	case CDROMREADAUDIO:
-		err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352);
-		break;
-	case CDROM_SEND_PACKET:
-		err = copy_to_user((char *)A(addr), data, cgc.buflen);
-		break;
-	default:
-		break;
-	}
 out:	if (data)
 		kfree(data);
 	return err ? -EFAULT : 0;
@@ -2126,37 +2150,16 @@
 	if (iobuf32.buffer == (__kernel_caddr_t32) NULL || iobuf32.length == 0) {
 		iobuf.buffer = (void*)(unsigned long)iobuf32.buffer;
 	} else {
-		iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL);
-		if (iobuf.buffer == NULL) {
-			err = -ENOMEM;
-			goto out;
-		}
-
-		err = copy_from_user(iobuf.buffer, (void *)A(iobuf32.buffer), iobuf.length);
-		if (err) {
-			err = -EFAULT;
-			goto out;
-		}
+		iobuf.buffer = A(iobuf32.buffer);
+		if (verify_area(VERIFY_WRITE, iobuf.buffer, iobuf.length))
+			return -EINVAL;
 	}
 
 	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, cmd, (unsigned long)&iobuf);      
+	err = sys_ioctl (fd, cmd, (unsigned long)&iobuf);
 	set_fs (old_fs);
-        if (err)
-		goto out;
-
-        if (iobuf.buffer && iobuf.length > 0) {
-		err = copy_to_user((void *)A(iobuf32.buffer), iobuf.buffer, iobuf.length);
-		if (err) {
-			err = -EFAULT;
-			goto out;
-		}
-	}
-	err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length));
-
- out:
-        if (iobuf32.buffer && iobuf32.length > 0)
-		kfree(iobuf.buffer);
+	if (!err)
+		err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length));
 
 	return err;
 }
@@ -2179,40 +2182,19 @@
         
 	if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc32.length == 0) {
 		sioc.arg = (void*)(unsigned long)sioc32.arg;
-        } else {
-                sioc.arg = kmalloc(sioc.length, GFP_KERNEL);
-                if (sioc.arg == NULL) {
-                        err = -ENOMEM;
-			goto out;
-		}
-                
-                err = copy_from_user(sioc.arg, (void *)A(sioc32.arg), sioc32.length);
-                if (err) {
-                        err = -EFAULT;
-                        goto out;
-                }
-        }
-        
-        old_fs = get_fs(); set_fs (KERNEL_DS);
-        err = sys_ioctl (fd, cmd, (unsigned long)&sioc);	
-        set_fs (old_fs);
-        if (err) {
-                goto out;
+	} else {
+		sioc.arg = A(sioc32.arg);
+		if (verify_area(VERIFY_WRITE, sioc.arg, sioc32.length))
+			return -EFAULT;
 	}
-        
-        if (sioc.arg && sioc.length > 0) {
-                err = copy_to_user((void *)A(sioc32.arg), sioc.arg, sioc.length);
-                if (err) {
-                        err = -EFAULT;
-                        goto out;
-                }
-        }
-        err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length));
-        
- out:
-        if (sioc32.arg && sioc32.length > 0)
-		kfree(sioc.arg);
-        
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&sioc);
+	set_fs (old_fs);
+
+	if (!err)
+		err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length));
+
 	return err;
 }
 
@@ -2428,12 +2410,24 @@
 		return NULL;
 	}
 	if (ptr1) {
+		if (l->lv_allocated_le > 2*PAGE_SIZE/sizeof(pe_t)) {
+			kfree(l);
+			*errp = -EINVAL;
+			return NULL;
+		}
 		size = l->lv_allocated_le * sizeof(pe_t);
 		l->lv_current_pe = vmalloc(size);
 		if (l->lv_current_pe)
 			err = copy_from_user(l->lv_current_pe, (void *)A(ptr1), size);
 	}
 	if (!err && ptr2) {
+		/* small limit */
+		/* just verify area it? */
+		if (l->lv_remap_end > 256*PAGE_SIZE/sizeof(lv_block_exception_t)) {
+			put_lv_t(l);
+			*errp = -EINVAL;
+			return NULL;
+		}
 		size = l->lv_remap_end * sizeof(lv_block_exception_t);
 		l->lv_block_exception = lbe = vmalloc(size);
 		if (l->lv_block_exception) {
@@ -3597,17 +3591,11 @@
 		goto out;
 	uptr = (void *) A(udata);
 
-	err = -ENOMEM;
 	buflen = kurb->buffer_length;
-	kptr = kmalloc(buflen, GFP_KERNEL);
-	if (!kptr)
-		goto out;
-
-	kurb->buffer = kptr;
 
-	err = -EFAULT;
-	if (copy_from_user(kptr, uptr, buflen))
-		goto out_kptr;
+	err = verify_area(VERIFY_WRITE, uptr, buflen);
+	if (err)
+		goto out;
 
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
@@ -3618,15 +3606,9 @@
 		/* XXX Shit, this doesn't work for async URBs :-( XXX */
 		if (put_urb32(kurb, uurb)) {
 			err = -EFAULT;
-		} else if ((kurb->endpoint & USB_DIR_IN) != 0) {
-			if (copy_to_user(uptr, kptr, buflen))
-				err = -EFAULT;
 		}
 	}
 
-out_kptr:
-	kfree(kptr);
-
 out:
 	kfree(kurb);
 	return err;
@@ -3698,14 +3680,13 @@
 #define MEMWRITEOOB32 	_IOWR('M',3,struct mtd_oob_buf32)
 #define MEMREADOOB32 	_IOWR('M',4,struct mtd_oob_buf32)
 
-static inline int 
+static inline int
 mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	mm_segment_t 			old_fs 	= get_fs();
 	struct mtd_oob_buf32	*uarg 	= (struct mtd_oob_buf32 *)arg;
 	struct mtd_oob_buf		karg;
 	u32 tmp;
-	char *ptr;
 	int ret;
 
 	if (get_user(karg.start, &uarg->start) 		||
@@ -3713,21 +3694,12 @@
 	    get_user(tmp, &uarg->ptr))
 		return -EFAULT;
 
-	ptr = (char *)A(tmp);
-	if (0 >= karg.length) 
-		return -EINVAL;
-
-	karg.ptr = kmalloc(karg.length, GFP_KERNEL);
-	if (NULL == karg.ptr)
-		return -ENOMEM;
-
-	if (copy_from_user(karg.ptr, ptr, karg.length)) {
-		kfree(karg.ptr);
+	karg.ptr = A(tmp);
+	if (verify_area(VERIFY_WRITE, karg.ptr, karg.length))
 		return -EFAULT;
-	}
 
 	set_fs(KERNEL_DS);
-	if (MEMREADOOB32 == cmd) 
+	if (MEMREADOOB32 == cmd)
 		ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg);
 	else if (MEMWRITEOOB32 == cmd)
 		ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg);
@@ -3736,14 +3708,12 @@
 	set_fs(old_fs);
 
 	if (0 == ret && cmd == MEMREADOOB32) {
-		ret = copy_to_user(ptr, karg.ptr, karg.length);
-		ret |= put_user(karg.start, &uarg->start);
+		ret = put_user(karg.start, &uarg->start);
 		ret |= put_user(karg.length, &uarg->length);
 	}
 
-	kfree(karg.ptr);
-	return ((0 == ret) ? 0 : -EFAULT);
-}	
+	return ret;
+}
 
 /* Fix sizeof(sizeof()) breakage */
 #define BLKELVGET_32	_IOR(0x12,106,int)
@@ -3801,6 +3771,7 @@
 COMPATIBLE_IOCTL(TCSETAW),
 COMPATIBLE_IOCTL(TCSETAF),
 COMPATIBLE_IOCTL(TCSBRK),
+COMPATIBLE_IOCTL(TCSBRKP),
 COMPATIBLE_IOCTL(TCXONC),
 COMPATIBLE_IOCTL(TCFLSH),
 COMPATIBLE_IOCTL(TCGETS),
@@ -3836,6 +3807,8 @@
 COMPATIBLE_IOCTL(TIOCSSERIAL),
 COMPATIBLE_IOCTL(TIOCSERGETLSR),
 COMPATIBLE_IOCTL(TIOCSLTC),
+COMPATIBLE_IOCTL(TIOCMIWAIT),
+COMPATIBLE_IOCTL(TIOCGICOUNT),
 /* Big F */
 COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO),
 COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO),
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/mf_proc.c linux-2.4.23-bk12/arch/ppc64/kernel/mf_proc.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/mf_proc.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/mf_proc.c	2003-12-16 03:09:14.000000000 -0800
@@ -220,19 +220,22 @@
 
 int proc_mf_change_side(struct file *file, const char *buffer, unsigned long count, void *data)
 {
+	char side;
+
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
+	if (count == 0)
+		return 0;
+	if (get_user(side, buffer))
+		return -EFAULT;
 
-	if ((*buffer != 'A') &&
-	    (*buffer != 'B') &&
-	    (*buffer != 'C') &&
-	    (*buffer != 'D'))
+	if ((side != 'A') && (side != 'B') && (side != 'C') && (side != 'D'))
 	{
 		printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
 		return -EINVAL;
 	}
 
-	mf_setSide(*buffer);
+	mf_setSide(side);
 
 	return count;			
 }
@@ -256,20 +259,24 @@
 
 int proc_mf_change_src(struct file *file, const char *buffer, unsigned long count, void *data)
 {
+	char stkbuf[10];
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	if ((count < 4) && (count != 1))
-	{
+	if ((count < 4) && (count != 1)) {
 		printk(KERN_ERR "mf_proc: invalid src\n");
 		return -EINVAL;
 	}
 
-	if ((count == 1) && ((*buffer) == '\0'))
-	{
+	if (count > 9)
+		count = 9;
+	if (copy_from_user (stkbuf, buffer, count))
+		return -EFAULT;
+
+	if ((count == 1) && ((*stkbuf) == '\0')) {
 		mf_clearSrc();
 	} else {
-		mf_displaySrc(*(u32 *)buffer);
+		mf_displaySrc(*(u32 *)stkbuf);
 	}
 
 	return count;			
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/misc.S linux-2.4.23-bk12/arch/ppc64/kernel/misc.S
--- linux-2.4.23-bk11/arch/ppc64/kernel/misc.S	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/misc.S	2003-12-16 03:09:14.000000000 -0800
@@ -69,16 +69,14 @@
 _GLOBAL(__no_use_save_flags)
 	mfspr	r4,SPRG3
 	lbz	r3,PACAPROCENABLED(r4)
+	/* shift into position of MSR.EE */
+	sldi	r3,r3,15
 	blr
 
-/* void __no_use_restore_flags(unsigned long flags) */	
+/* void __no_use_restore_flags(unsigned long flags) */
 _GLOBAL(__no_use_restore_flags)
-/*
- * Just set/clear the MSR_EE bit through restore/flags but do not
- * change anything else.  This is needed by the RT system and makes
- * sense anyway.
- *    -- Cort
- */
+	/* shift from position of MSR.EE */
+	srdi	r3,r3,15
 	mfspr	r6,SPRG3
 	lbz	r5,PACAPROCENABLED(r6)
 	 /* Check if things are setup the way we want _already_. */
@@ -104,6 +102,8 @@
 	lbz	r3,PACAPROCENABLED(r5)
 	li	r4,0
 	stb	r4,PACAPROCENABLED(r5)
+	/* shift into position of MSR.EE */
+	sldi	r3,r3,15
 	blr			/* Done */
 
 _GLOBAL(__no_use_sti)
@@ -578,9 +578,10 @@
 	bnelr			/* return if parent */
 
 	li	r0,0		/* clear out p->thread.regs */
-	std	r0,THREAD+PT_REGS(r13)	/* since we don't have user ctx */
+	ld	r7,PACACURRENT(r13)
+	std	r0,THREAD+PT_REGS(r7)	/* since we don't have user ctx */
 	li	r0,RUN_FLAG		/* Run light on */
-	std	r0,THREAD+THREAD_FLAGS(r13)
+	std	r0,THREAD+THREAD_FLAGS(r7)
 
 	ld	r2,8(r6)
 	ld	r6,0(r6)
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/pmc.c linux-2.4.23-bk12/arch/ppc64/kernel/pmc.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/pmc.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/pmc.c	2003-12-16 03:09:14.000000000 -0800
@@ -74,7 +74,6 @@
                                 page_table_lock : SPIN_LOCK_UNLOCKED};
 
 extern spinlock_t hash_table_lock[];
-extern inline unsigned long get_lock_slot(unsigned long vpn);
 
 char *
 ppc64_pmc_stab(int file)
@@ -241,7 +240,7 @@
 		lock_slot = get_lock_slot(vpn); 
 		rpn = pa >> PAGE_SHIFT;
 
-		spin_lock(&hash_table_lock[lock_slot].lock);
+		spin_lock(&hash_table_lock[lock_slot]);
 		/* Get a pointer to the linux page table entry for this page
 		 * allocating pmd or pte pages along the way as needed.  Note
 		 * that the pmd & pte pages are not themselfs bolted.
@@ -266,7 +265,7 @@
 
 		*ptep = pte;
 
-		spin_unlock(&hash_table_lock[lock_slot].lock);
+		spin_unlock(&hash_table_lock[lock_slot]);
 	}
 
 	spin_unlock(&btmalloc_mm.page_table_lock);
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/proc_pmc.c linux-2.4.23-bk12/arch/ppc64/kernel/proc_pmc.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/proc_pmc.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/proc_pmc.c	2003-12-16 03:09:14.000000000 -0800
@@ -202,7 +202,7 @@
 			ent->nlink = 1;
 			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
 			ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
-			ent->write_proc = (void *)proc_ppc64_pmc_stab_read;
+			ent->write_proc = NULL;
 		}
 
 		ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, 
@@ -211,7 +211,7 @@
 			ent->nlink = 1;
 			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
 			ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
-			ent->write_proc = (void *)proc_ppc64_pmc_htab_read;
+			ent->write_proc = NULL;
 		}
 	}
 
@@ -221,7 +221,7 @@
 		ent->nlink = 1;
 		ent->data = (void *)proc_ppc64_pmc_system_root;
 		ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
-		ent->write_proc = (void *)proc_ppc64_pmc_stab_read;
+		ent->write_proc = NULL;
 	}
 
 	ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, 
@@ -230,7 +230,7 @@
 		ent->nlink = 1;
 		ent->data = (void *)proc_ppc64_pmc_system_root;
 		ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
-		ent->write_proc = (void *)proc_ppc64_pmc_htab_read;
+		ent->write_proc = NULL;
 	}
 
 	ent = create_proc_entry("profile", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
@@ -261,7 +261,7 @@
 			ent->nlink = 1;
 			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
 			ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
-			ent->write_proc = (void *)proc_ppc64_pmc_hw_read;
+			ent->write_proc = NULL;
 		}
 	}
 
@@ -271,7 +271,7 @@
 		ent->nlink = 1;
 		ent->data = (void *)proc_ppc64_pmc_system_root;
 		ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
-		ent->write_proc = (void *)proc_ppc64_pmc_hw_read;
+		ent->write_proc = NULL;
 	}
 }
 
@@ -449,6 +449,7 @@
 static ssize_t write_profile(struct file * file, const char * buf,
 			     size_t count, loff_t *ppos)
 {
+	return(0);
 }
 
 static ssize_t read_trace(struct file *file, char *buf,
@@ -473,6 +474,7 @@
 static ssize_t write_trace(struct file * file, const char * buf,
 			     size_t count, loff_t *ppos)
 {
+	return(0);
 }
 
 static ssize_t read_timeslice(struct file *file, char *buf,
@@ -481,7 +483,6 @@
 	unsigned long p = *ppos;
 	ssize_t read;
 	char * pnt;
-	unsigned int sample_step = 4;
 
 	if (p >= (perfmon_base.timeslice_length)) return 0;
 	if (count > (perfmon_base.timeslice_length) - p)
@@ -498,6 +499,7 @@
 static ssize_t write_timeslice(struct file * file, const char * buf,
 			       size_t count, loff_t *ppos)
 {
+	return(0);
 }
 
 int 
@@ -882,15 +884,24 @@
 
 int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data )
 {
-	if      ( ! strncmp( buffer, "stop", 4 ) )
+	char stkbuf[10];
+
+	if (count > 9)
+		count = 9;
+	if (copy_from_user (stkbuf, buffer, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+
+	if      ( ! strncmp( stkbuf, "stop", 4 ) )
 		proc_pmc_stop();
-	else if ( ! strncmp( buffer, "start", 5 ) )
+	else if ( ! strncmp( stkbuf, "start", 5 ) )
 		proc_pmc_start();
-	else if ( ! strncmp( buffer, "reset", 5 ) )
+	else if ( ! strncmp( stkbuf, "reset", 5 ) )
 		proc_pmc_reset();
-	else if ( ! strncmp( buffer, "cpi", 3 ) )
+	else if ( ! strncmp( stkbuf, "cpi", 3 ) )
 		proc_pmc_cpi();
-	else if ( ! strncmp( buffer, "tlb", 3 ) )
+	else if ( ! strncmp( stkbuf, "tlb", 3 ) )
 		proc_pmc_tlb();
 	
 	/* IMPLEMENT ME */
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/rtas-proc.c linux-2.4.23-bk12/arch/ppc64/kernel/rtas-proc.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/rtas-proc.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/rtas-proc.c	2003-12-16 03:09:14.000000000 -0800
@@ -273,12 +273,19 @@
 static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	struct rtc_time tm;
 	unsigned long nowtime;
 	char *dest;
 	int error;
 
-	nowtime = simple_strtoul(buf, &dest, 10);
+	if (39 < count)
+		count = 39;
+	if (copy_from_user(stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+	nowtime = simple_strtoul(stkbuf, &dest, 10);
 	if (*dest != '\0' && *dest != '\n') {
 		printk("ppc_rtas_poweron_write: Invalid time\n");
 		return count;
@@ -299,18 +306,23 @@
 static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	int n;
+
 	if (power_on_time == 0)
-		n = sprintf(buf, "Power on time not set\n");
+		n = snprintf(stkbuf, 40, "Power on time not set\n");
 	else
-		n = sprintf(buf, "%lu\n", power_on_time);
+		n = snprintf(stkbuf, 40, "%lu\n", power_on_time);
 
-	if (*ppos >= strlen(buf))
+	int sn = strlen(stkbuf) +1;
+	if (*ppos >= sn)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, stkbuf + (*ppos), n))
+		return -EFAULT;
 	*ppos += n;
 	return n;
 }
@@ -323,11 +335,17 @@
 {
 	unsigned long hex;
 
-	strcpy(progress_led, buf); /* save the string */
+	if (count >= MAX_LINELENGTH)
+		count = MAX_LINELENGTH -1;
+	if (copy_from_user(progress_led, buf, count))
+		return -EFAULT;
+
+	progress_led[count] = 0;
+
 	/* Lets see if the user passed hexdigits */
-	hex = simple_strtoul(buf, NULL, 10);
-	
-	ppc_md.progress ((char *)buf, hex);
+	hex = simple_strtoul(progress_led, NULL, 10);
+
+	ppc_md.progress((char *)progress_led, hex);
 	return count;
 
 	/* clear the line */ /* ppc_md.progress("                   ", 0xffff);*/
@@ -336,15 +354,32 @@
 static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos)
 {
-	int n = 0;
-	if (progress_led != NULL)
-		n = sprintf (buf, "%s\n", progress_led);
-	if (*ppos >= strlen(buf))
+	int n = 0, sn;
+	
+	if (progress_led == NULL)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+
+	char * tmpbuf = kmalloc(MAX_LINELENGTH, GFP_KERNEL);
+	if (!tmpbuf) {
+		printk(KERN_ERR "error: kmalloc failed\n");
+		return -ENOMEM;
+	}
+	n = sprintf (tmpbuf, "%s\n", progress_led);
+
+	sn = strlen (tmpbuf) +1;
+	if (*ppos >= sn) {
+		kfree(tmpbuf);
+		return 0;
+	}
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, tmpbuf + (*ppos), n)) {
+		kfree(tmpbuf);
+		return -EFAULT;
+	}
+	kfree(tmpbuf);
 	*ppos += n;
 	return n;
 }
@@ -355,12 +390,19 @@
 static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	struct rtc_time tm;
 	unsigned long nowtime;
 	char *dest;
 	int error;
 
-	nowtime = simple_strtoul(buf, &dest, 10);
+	if (39 < count)
+		count = 39;
+	if (copy_from_user(stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+	nowtime = simple_strtoul(stkbuf, &dest, 10);
 	if (*dest != '\0' && *dest != '\n') {
 		printk("ppc_rtas_clock_write: Invalid time\n");
 		return count;
@@ -388,21 +430,27 @@
 	year = ret[0]; mon  = ret[1]; day  = ret[2];
 	hour = ret[3]; min  = ret[4]; sec  = ret[5];
 
+	char stkbuf[40];  /* its small, its on stack */
+
 	if (error != 0){
 		printk(KERN_WARNING "error: reading the clock returned: %s\n", 
 				ppc_rtas_process_error(error));
-		n = sprintf (buf, "0");
+		n = snprintf(stkbuf, 40, "0");
 	} else { 
-		n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec));
+		n = snprintf(stkbuf, 40, "%lu\n", mktime(year, mon, day, hour, min, sec));
 	}
 	kfree(ret);
 
-	if (*ppos >= strlen(buf))
+	int sn = strlen(stkbuf) +1;
+	if (*ppos >= sn)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, stkbuf + (*ppos), n))
+		return -EFAULT;
+
 	*ppos += n;
 	return n;
 }
@@ -751,7 +799,7 @@
 		n += check_location_string(ret, buffer + n);
 		n += sprintf ( buffer+n, " ");
 		/* see how many characters we have printed */
-		sprintf ( t, "%s ", ret);
+		snprintf( t, 50, "%s ", ret);
 
 		pos += strlen(t);
 		if (pos >= llen) pos=0;
@@ -764,10 +812,18 @@
 static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	unsigned long freq;
 	char *dest;
 	int error;
-	freq = simple_strtoul(buf, &dest, 10);
+
+	if (39 < count)
+		count = 39;
+	if (copy_from_user(stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+	freq = simple_strtoul(stkbuf, &dest, 10);
 	if (*dest != '\0' && *dest != '\n') {
 		printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
 		return count;
@@ -785,15 +841,21 @@
 static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos)
 {
-	int n;
-	n = sprintf(buf, "%lu\n", rtas_tone_frequency);
+	int n, sn;
+	char stkbuf[40];  /* its small, its on stack */
 
-	if (*ppos >= strlen(buf))
+	n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency);
+
+	sn = strlen(stkbuf) +1;
+	if (*ppos >= sn)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, stkbuf + (*ppos), n))
+		return -EFAULT;
+
 	*ppos += n;
 	return n;
 }
@@ -803,10 +865,18 @@
 static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	unsigned long volume;
 	char *dest;
 	int error;
-	volume = simple_strtoul(buf, &dest, 10);
+
+	if (39 < count)
+		count = 39;
+	if (copy_from_user(stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+	volume = simple_strtoul(stkbuf, &dest, 10);
 	if (*dest != '\0' && *dest != '\n') {
 		printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
 		return count;
@@ -826,15 +896,20 @@
 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos)
 {
-	int n;
-	n = sprintf(buf, "%lu\n", rtas_tone_volume);
+	int n, sn;
+	char stkbuf[40];  /* its small, its on stack */
 
-	if (*ppos >= strlen(buf))
+	n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_volume);
+	sn = strlen(stkbuf) +1;
+	if (*ppos >= sn)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, stkbuf + (*ppos), n))
+		return -EFAULT;
+
 	*ppos += n;
 	return n;
 }
@@ -864,7 +939,7 @@
 static ssize_t ppc_rtas_errinjct_write(struct file * file, const char * buf,
 				       size_t count, loff_t *ppos)
 {
- 
+ 	char * tmpbuf;
 	char * ei_token;
 	char * workspace = NULL;
 	size_t max_len;
@@ -878,16 +953,26 @@
 		max_len = ERRINJCT_TOKEN_LEN;
 	}
 
-	token_len = strnlen(buf, max_len);
+	tmpbuf = (char *) kmalloc(max_len, GFP_KERNEL);
+	if (!tmpbuf) {
+		printk(KERN_WARNING "error: kmalloc failed\n");
+		return -ENOMEM;
+	}
+	if (copy_from_user (tmpbuf, buf, max_len)) {
+		kfree(tmpbuf);
+		return -EFAULT;
+	}
+	token_len = strnlen(tmpbuf, max_len);
 	token_len++; /* Add one for the null termination */
     
 	ei_token = (char *)kmalloc(token_len, GFP_KERNEL);
 	if (!ei_token) {
 		printk(KERN_WARNING "error: kmalloc failed\n");
+		kfree(tmpbuf);
 		return -ENOMEM;
 	}
 
-	strncpy(ei_token, buf, token_len);
+	strncpy(ei_token, tmpbuf, token_len);
     
 	if (count > token_len + WORKSPACE_SIZE) {
 		count = token_len + WORKSPACE_SIZE;
@@ -907,11 +992,12 @@
 		workspace = (char *)kmalloc(max_len, GFP_KERNEL);
 		if (!workspace) {
 			printk(KERN_WARNING "error: failed kmalloc\n");
+			kfree(tmpbuf);
 			kfree(ei_token);
 			return -ENOMEM;
 		}
 	
-		memcpy(workspace, buf, max_len);
+		memcpy(workspace, tmpbuf, max_len);
 	}
 
 	rc = rtas_errinjct(open_token, ei_token, workspace);
@@ -920,6 +1006,7 @@
 		kfree(workspace);
 	}
 	kfree(ei_token);
+	kfree(tmpbuf);
 
 	return rc < 0 ? rc : count;
 }
@@ -940,32 +1027,36 @@
 				      size_t count, loff_t *ppos) 
 {
 	char * buffer;
-	int i;
+	int i, sn;
 	int n = 0;
 
-	buffer = (char *)kmalloc(MAX_ERRINJCT_TOKENS * (ERRINJCT_TOKEN_LEN+1),
-				 GFP_KERNEL);
+	int m = MAX_ERRINJCT_TOKENS * (ERRINJCT_TOKEN_LEN+1);
+	buffer = (char *)kmalloc(m, GFP_KERNEL);
 	if (!buffer) {
 		printk(KERN_ERR "error: kmalloc failed\n");
 		return -ENOMEM;
 	}
 
 	for (i = 0; i < MAX_ERRINJCT_TOKENS && ei_token_list[i].value; i++) {
-		n += sprintf(buffer+n, ei_token_list[i].name);
-		n += sprintf(buffer+n, "\n");
+		n += snprintf(buffer+n, m-n, ei_token_list[i].name);
+		n += snprintf(buffer+n, m-n, "\n");
 	}
 
-	if (*ppos >= strlen(buffer)) {
+	sn = strlen(buffer) +1;
+	if (*ppos >= sn) {
 		kfree(buffer);
 		return 0;
 	}
-	if (n > strlen(buffer) - *ppos)
-		n = strlen(buffer) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 
 	if (n > count)
 		n = count;
 
-	memcpy(buf, buffer + *ppos, n);
+	if (copy_to_user(buf, buffer + *ppos, n)) {
+		kfree(buffer);
+		return -EFAULT;
+	}
 
 	*ppos += n;
 
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/scanlog.c linux-2.4.23-bk12/arch/ppc64/kernel/scanlog.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/scanlog.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/scanlog.c	2003-12-16 03:09:14.000000000 -0800
@@ -129,17 +129,25 @@
 static ssize_t scanlog_write(struct file * file, const char * buf,
 			     size_t count, loff_t *ppos)
 {
+	char stkbuf[20];
 	unsigned long status;
 
+	if (count > 19)
+		count = 19;
+	if (copy_from_user (stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+
 	if (buf) {
-		if (strncmp(buf, "reset", 5) == 0) {
+		if (strncmp(stkbuf, "reset", 5) == 0) {
 			DEBUG("reset scanlog\n");
 			status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, NULL, 0);
 			DEBUG("rtas returns %ld\n", status);
-		} else if (strncmp(buf, "debugon", 7) == 0) {
+		} else if (strncmp(stkbuf, "debugon", 7) == 0) {
 			printk(KERN_ERR "scanlog: debug on\n");
 			scanlog_debug = 1;
-		} else if (strncmp(buf, "debugoff", 8) == 0) {
+		} else if (strncmp(stkbuf, "debugoff", 8) == 0) {
 			printk(KERN_ERR "scanlog: debug off\n");
 			scanlog_debug = 0;
 		}
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/signal.c linux-2.4.23-bk12/arch/ppc64/kernel/signal.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/signal.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/signal.c	2003-12-16 03:09:14.000000000 -0800
@@ -296,7 +296,9 @@
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
 	}
 
-        return (void *)((newsp - frame_size) & -8ul);
+	/* The ABI requires quadword alignment for the stack. */
+	return (void *)((newsp - frame_size) & -16ul);
+
 }
 
 static int
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/signal32.c linux-2.4.23-bk12/arch/ppc64/kernel/signal32.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/signal32.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/signal32.c	2003-12-16 03:09:14.000000000 -0800
@@ -761,7 +761,7 @@
 	memset (d, 0, sizeof(siginfo_t32));
 	d->si_signo = s->si_signo;
 	d->si_errno = s->si_errno;
-	d->si_code = s->si_code & 0xffff;
+	d->si_code = (short)s->si_code;
 	if (s->si_signo >= SIGRTMIN) {
 		d->si_pid = s->si_pid;
 		d->si_uid = s->si_uid;
@@ -1067,7 +1067,8 @@
 	if (ka->sa.sa_flags & SA_SIGINFO)
 	{
 		siginfo64to32(&siginfo32bit,info);
-		*newspp -= sizeof(*rt_stack_frame);
+		/* The ABI requires quadword alignment for the stack. */
+		*newspp = (*newspp - sizeof(*rt_stack_frame)) & -16ul;
 		rt_stack_frame = (struct rt_sigframe_32 *) (u64)(*newspp) ;
     
 		if (verify_area(VERIFY_WRITE, rt_stack_frame, sizeof(*rt_stack_frame)))
@@ -1095,7 +1096,7 @@
 		}
 	} else {
 		/* Put a sigcontext on the stack */
-		*newspp -= sizeof(*sc);
+		*newspp = (*newspp - sizeof(*sc)) & -16ul;
 		sc = (struct sigcontext32 *)(u64)*newspp;
 		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
 			goto badframe;
@@ -1310,7 +1311,8 @@
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
 		else
 			newsp = regs->gpr[1];
-		newsp = frame = newsp - sizeof(struct sigregs32);
+		/* The ABI requires quadword alignment for the stack. */
+		newsp = frame = (newsp - sizeof(struct sigregs32)) & -16ul;
 
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal32(signr, ka, &info, oldset, regs, &newsp, frame);
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/smp.c linux-2.4.23-bk12/arch/ppc64/kernel/smp.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/smp.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/smp.c	2003-12-16 03:09:14.000000000 -0800
@@ -564,6 +564,7 @@
 	ret = 0;
 
  out:
+	call_data = NULL;
 	HMT_medium();
 	spin_unlock_bh(&call_lock);
 	return ret;
@@ -571,9 +572,20 @@
 
 void smp_call_function_interrupt(void)
 {
-	void (*func) (void *info) = call_data->func;
-	void *info = call_data->info;
-	int wait = call_data->wait;
+	void (*func) (void *info);
+	void *info;
+	int wait;
+
+
+	/* call_data will be NULL if the sender timed out while
+	 * waiting on us to receive the call.
+	 */
+	if (!call_data)
+		return;
+
+	func = call_data->func;
+	info = call_data->info;
+	wait = call_data->wait;
 
 	/*
 	 * Notify initiating CPU that I've grabbed the data and am
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/stab.c linux-2.4.23-bk12/arch/ppc64/kernel/stab.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/stab.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk12/arch/ppc64/kernel/stab.c	2003-12-16 03:09:14.000000000 -0800
@@ -159,7 +159,6 @@
 inline void make_slbe(unsigned long esid, unsigned long vsid, int large)
 {
 	unsigned long entry, castout_entry;
-	slb_dword0 castout_esid_data;
 	union {
 		unsigned long word0;
 		slb_dword0    data;
@@ -217,23 +216,37 @@
 
 	PMC_SW_PROCESSOR(stab_capacity_castouts); 
 
+	/*
+	 * Never cast out the segment for our own stack. Since we
+	 * dont invalidate the ERAT we could have a valid translation
+	 * for our stack during the first part of exception exit
+	 * which gets invalidated due to a tlbie from another cpu at a
+	 * non recoverable point (after setting srr0/1) - Anton
+	 */
+
 	castout_entry = get_paca()->xStab_data.next_round_robin;
-	__asm__ __volatile__("slbmfee  %0,%1" 
-			     : "=r" (castout_esid_data) 
-			     : "r" (castout_entry)); 
-
-	entry = castout_entry; 
-	castout_entry++; 
-	if(castout_entry >= naca->slb_size) {
-		castout_entry = 1; 
-	}
+	do {
+		entry = castout_entry;
+		castout_entry++;
+		if (castout_entry >= naca->slb_size)
+			castout_entry = 1;
+		asm volatile("slbmfee  %0,%1" : "=r" (esid_data) : "r" (entry));
+	} while (esid_data.data.esid == GET_ESID((unsigned long)_get_SP()));
+	
 	get_paca()->xStab_data.next_round_robin = castout_entry;
 
-	/* Invalidate the old entry. */
-	castout_esid_data.v = 0; /* Set the class to 0 */
-	/* slbie not needed as the previous mapping is still valid. */
-	__asm__ __volatile__("slbie  %0" : : "r" (castout_esid_data)); 
-	
+	/* We're executing this code on the interrupt stack, so the
+	 * above code might pick the kernel stack segment as the victim.
+	 *
+	 * Because of this, we need to invalidate the old entry. We need
+	 * to do this since it'll otherwise be in the ERAT and might come
+	 * back and haunt us if it get's thrown out of there at the wrong
+	 * time (i.e. similar to throwing out our own stack above).
+	 */
+
+	esid_data.data.v = 0;
+	__asm__ __volatile__("slbie  %0" : : "r" (esid_data));
+
 	/* 
 	 * Write the new SLB entry.
 	 */
diff -urN linux-2.4.23-bk11/arch/ppc64/kernel/sys_ppc32.c linux-2.4.23-bk12/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.23-bk11/arch/ppc64/kernel/sys_ppc32.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.23-bk12/arch/ppc64/kernel/sys_ppc32.c	2003-12-16 03:09:14.000000000 -0800
@@ -104,11 +104,37 @@
 	return ret;
 }
 
+asmlinkage int sys32_ustat(__kernel_dev_t32 dev, struct ustat32 * ubuf)
+{
+
+	struct super_block *s;
+	struct ustat32 tmp;
+	struct statfs sbuf;
+	int err = -EINVAL;
+
+	s = get_super(to_kdev_t(dev));
+	if (s == NULL)
+		goto out;
+	err = vfs_statfs(s, &sbuf);
+	drop_super(s);
+	if (err)
+		goto out;
 
+	memset(&tmp,0,sizeof(struct ustat));
+	tmp.f_tfree = sbuf.f_bfree;
+	tmp.f_tinode = sbuf.f_ffree;
+
+	err = copy_to_user(ubuf, &tmp, sizeof(struct ustat32)) ? -EFAULT : 0;
+
+out:
+	return err;
+
+}
 
 struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
 
 typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
+typedef __kernel_ssize_t32 ssize_t32;
 
 static long do_readv_writev32(int type, struct file *file,
 			      const struct iovec32 *vector, u32 count)
@@ -149,6 +175,11 @@
 		ivp->iov_len = (__kernel_size_t) len;
 		vector++;
 		ivp++;
+		if ((len < 0) || (tot_len != (ssize_t32)tot_len)) {
+			if (iov != iovstack)
+				kfree(iov);
+			return -EINVAL;
+		}
 		i--;
 	}
 
@@ -467,7 +498,7 @@
 };
                                 
 
-extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+extern asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr);
 
 /* Note: it is necessary to treat cmd and id as unsigned ints, 
  * with the corresponding cast to a signed int to insure that the 
@@ -476,9 +507,9 @@
  */
 asmlinkage long sys32_quotactl(u32 cmd_parm, const char *special, u32 id_parm, caddr_t addr)
 {
-	int cmd = (int)cmd_parm;
-	int id  = (int)id_parm;
-	int cmds = cmd >> SUBCMDSHIFT;
+	unsigned int cmd = cmd_parm;
+	qid_t id  = (qid_t)id_parm;
+	unsigned int cmds = cmd >> SUBCMDSHIFT;
 	int err;
 	struct v1c_mem_dqblk d;
 	mm_segment_t old_fs;
@@ -995,19 +1026,21 @@
 
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
-	int err;
-	
-	err = put_user (kbuf->f_type, &ubuf->f_type);
-	err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize);
-	err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks);
-	err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree);
-	err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail);
-	err |= __put_user (kbuf->f_files, &ubuf->f_files);
-	err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree);
-	err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen);
-	err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]);
-	err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]);
-	return err;
+	struct statfs32 tmp;
+	memset(&tmp, 0, sizeof(tmp));
+
+	tmp.f_type = kbuf->f_type;
+	tmp.f_bsize = kbuf->f_bsize;
+	tmp.f_blocks = kbuf->f_blocks;
+	tmp.f_bfree = kbuf->f_bfree;
+	tmp.f_bavail = kbuf->f_bavail;
+	tmp.f_files = kbuf->f_files;
+	tmp.f_ffree = kbuf->f_ffree;
+	tmp.f_namelen = kbuf->f_namelen;
+	tmp.f_fsid.val[0] = kbuf->f_fsid.val[0];
+	tmp.f_fsid.val[1] = kbuf->f_fsid.val[1];
+
+	return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
 extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
@@ -2567,7 +2600,7 @@
 	err = -EFAULT;
 	if (get_user(pad, (u32 *)uptr))
 		return err;
-	if (third == SETVAL)
+	if ((third & (~IPC_64)) == SETVAL)
 		fourth.val = (int)pad;
 	else
 		fourth.__pad = (void *)A(pad);
@@ -3488,7 +3521,7 @@
 	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
 		return -EFAULT;
 	if(kern_msg.msg_iovlen > UIO_MAXIOV)
-		return -EINVAL;
+		return -EMSGSIZE;
 	err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
 	if (err < 0)
 		goto out;
@@ -3726,7 +3759,7 @@
 	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
 		return -EFAULT;
 	if(kern_msg.msg_iovlen > UIO_MAXIOV)
-		return -EINVAL;
+		return -EMSGSIZE;
 
 	uaddr = kern_msg.msg_name;
 	uaddr_len = &user_msg->msg_namelen;
@@ -3987,8 +4020,10 @@
 	regs->nip = nip;
 	regs->gpr[1] = sp;
 	regs->msr = MSR_USER32;
+#ifndef CONFIG_SMP
 	if (last_task_used_math == current)
 		last_task_used_math = 0;
+#endif
 	current->thread.fpscr = 0;
 }
 
@@ -4607,8 +4642,6 @@
 extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
 				     size_t count, loff_t pos);
 
-typedef __kernel_ssize_t32 ssize_t32;
-
 asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf,
 				 __kernel_size_t32 count, u32 reg6, u32 poshi, u32 poslo)
 {
diff -urN linux-2.4.23-bk11/arch/ppc64/mm/fault.c linux-2.4.23-bk12/arch/ppc64/mm/fault.c
--- linux-2.4.23-bk11/arch/ppc64/mm/fault.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.23-bk12/arch/ppc64/mm/fault.c	2003-12-16 03:09:14.000000000 -0800
@@ -59,6 +59,44 @@
 #endif
 
 /*
+ * Check whether the instruction at regs->nip is a store using
+ * an update addressing form which will update r1.
+ */
+static int store_updates_sp(struct pt_regs *regs)
+{
+	unsigned int inst;
+
+	if (get_user(inst, (unsigned int *)regs->nip))
+		return 0;
+	/* check for 1 in the rA field */
+	if (((inst >> 16) & 0x1f) != 1)
+		return 0;
+	/* check major opcode */
+	switch (inst >> 26) {
+	case 37:	/* stwu */
+	case 39:	/* stbu */
+	case 45:	/* sthu */
+	case 53:	/* stfsu */
+	case 55:	/* stfdu */
+		return 1;
+	case 62:	/* std or stdu */
+		return (inst & 3) == 1;
+	case 31:
+		/* check minor opcode */
+		switch ((inst >> 1) & 0x3ff) {
+		case 181:	/* stdux */
+		case 183:	/* stwux */
+		case 247:	/* stbux */
+		case 439:	/* sthux */
+		case 695:	/* stfsux */
+		case 759:	/* stfdux */
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
  * The error_code parameter is
  *  - DSISR for a non-SLB data access fault,
  *  - SRR1 & 0x08000000 for a non-SLB instruction access fault
@@ -115,7 +153,39 @@
 		PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma->vm_flags = %lx, %lx\n", vma->vm_flags, VM_GROWSDOWN);
 		goto bad_area;
 	}
-	vma = find_vma_prev(mm, address, &prev_vma);
+
+	/*
+	 * N.B. The POWER/Open ABI allows programs to access up to
+	 * 288 bytes below the stack pointer.
+	 * The kernel signal delivery code writes up to about 1.5kB
+	 * below the stack pointer (r1) before decrementing it.
+	 * The exec code can write slightly over 640kB to the stack
+	 * before setting the user r1.  Thus we allow the stack to
+	 * expand to 1MB without further checks.
+	 */
+	if (address + 0x100000 < vma->vm_end) {
+		/* get user regs even if this fault is in kernel mode */
+		struct pt_regs *uregs = current->thread.regs;
+		if (uregs == NULL)
+			goto bad_area;
+
+		/*
+		 * A user-mode access to an address a long way below
+		 * the stack pointer is only valid if the instruction
+		 * is one which would update the stack pointer to the
+		 * address accessed if the instruction completed,
+		 * i.e. either stwu rs,n(r1) or stwux rs,r1,rb
+		 * (or the byte, halfword, float or double forms).
+		 *
+		 * If we don't check this then any write to the area
+		 * between the last mapped region and the stack will
+		 * expand the stack rather than segfaulting.
+		 */
+		if (address + 2048 < uregs->gpr[1]
+		    && (!user_mode(regs) || !store_updates_sp(regs)))
+			goto bad_area;
+	}
+
 	if (expand_stack(vma, address)) {
 		PPCDBG(PPCDBG_MM, "\tdo_page_fault: expand_stack\n");
 		goto bad_area;
diff -urN linux-2.4.23-bk11/arch/sparc/kernel/devices.c linux-2.4.23-bk12/arch/sparc/kernel/devices.c
--- linux-2.4.23-bk11/arch/sparc/kernel/devices.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.23-bk12/arch/sparc/kernel/devices.c	2003-12-16 03:09:14.000000000 -0800
@@ -72,7 +72,7 @@
 		if (linux_num_cpus == 0) {
 			printk("No CPU nodes found, cannot continue.\n");
 			/* Probably a sun4e, Sun is trying to trick us ;-) */
-			halt();
+			prom_halt();
 		}
 		printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
 	}
diff -urN linux-2.4.23-bk11/arch/sparc/kernel/ioport.c linux-2.4.23-bk12/arch/sparc/kernel/ioport.c
--- linux-2.4.23-bk11/arch/sparc/kernel/ioport.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.23-bk12/arch/sparc/kernel/ioport.c	2003-12-16 03:09:14.000000000 -0800
@@ -760,7 +760,7 @@
 	default:
 		printk("ioport_init: cpu type %d is unknown.\n",
 		    sparc_cpu_model);
-		halt();
+		prom_halt();
 	};
 
 }
diff -urN linux-2.4.23-bk11/arch/sparc64/kernel/ebus.c linux-2.4.23-bk12/arch/sparc64/kernel/ebus.c
--- linux-2.4.23-bk11/arch/sparc64/kernel/ebus.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.23-bk12/arch/sparc64/kernel/ebus.c	2003-12-16 03:09:14.000000000 -0800
@@ -177,7 +177,8 @@
 
 static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
 {
-	if (!strcmp(dev->prom_name, "i2c"))
+	if (!strcmp(dev->prom_name, "i2c") ||
+	    !strcmp(dev->prom_name, "SUNW,lombus"))
 		return 1;
 	return 0;
 }
diff -urN linux-2.4.23-bk11/drivers/pcmcia/yenta.c linux-2.4.23-bk12/drivers/pcmcia/yenta.c
--- linux-2.4.23-bk11/drivers/pcmcia/yenta.c	2003-06-13 07:51:35.000000000 -0700
+++ linux-2.4.23-bk12/drivers/pcmcia/yenta.c	2003-12-16 03:09:15.000000000 -0800
@@ -26,7 +26,7 @@
 #include "i82365.h"
 
 #if 0
-#define DEBUG(x,args...)	printk(__FUNCTION__ ": " x,##args)
+#define DEBUG(x,args...)	printk(KERN_DEBUG __FUNCTION__ ": " x,##args)
 #else
 #define DEBUG(x,args...)
 #endif
@@ -576,7 +576,8 @@
 	socket->cap.cb_dev = socket->dev;
 	socket->cap.bus = NULL;
 
-	printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);
+	printk(KERN_INFO "Yenta ISA IRQ mask 0x%04x, PCI irq %d\n",
+	       socket->cap.irq_mask, socket->cb_irq);
 }
 
 extern void cardbus_register(pci_socket_t *socket);
@@ -603,7 +604,8 @@
 
 	/* Figure out what the dang thing can do for the PCMCIA layer... */
 	yenta_get_socket_capabilities(socket, isa_interrupts);
-	printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
+	printk(KERN_INFO "Socket status: %08x\n",
+	       cb_readl(socket, CB_SOCKET_STATE));
 
 	/* Register it with the pcmcia layer.. */
 	cardbus_register(socket);
@@ -889,7 +891,7 @@
 	if (pci_enable_device(dev))
 		return -1;
 	if (!pci_resource_start(dev, 0)) {
-		printk("No cardbus resource!\n");
+		printk(KERN_ERR "No cardbus resource!\n");
 		return -1;
 	}
 
diff -urN linux-2.4.23-bk11/drivers/usb/pegasus.c linux-2.4.23-bk12/drivers/usb/pegasus.c
--- linux-2.4.23-bk11/drivers/usb/pegasus.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.23-bk12/drivers/usb/pegasus.c	2003-12-16 03:09:16.000000000 -0800
@@ -54,7 +54,7 @@
 			BMSR_100FULL | BMSR_ANEGCAPABLE)
 
 static int loopback = 0;
-static int mii_mode = 1;
+static int mii_mode = 0;
 static int multicast_filter_limit = 32;
 
 static struct usb_eth_dev usb_dev_id[] = {
@@ -486,7 +486,7 @@
 	if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF))
 		data[1] |= 0x10;	/* set 100 Mbps */
 	if (mii_mode)
-		data[1] = 0;
+		data[1] |= 1;
 	data[2] = (loopback & 1) ? 0x09 : 0x01;
 	memcpy(pegasus->eth_regs, data, sizeof(data));
 	set_registers(pegasus, EthCtrl0, 3, data);
@@ -900,6 +900,7 @@
 			info.cmd = ETHTOOL_GDRVINFO;
 			strncpy(info.driver, driver_name,
 			        sizeof (info.driver) - 1);
+			strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
 			strncpy(info.version, DRIVER_VERSION,
 				sizeof (info.version) - 1);
 			usb_make_path(pegasus->usb, info.bus_info,
diff -urN linux-2.4.23-bk11/drivers/usb/pegasus.h linux-2.4.23-bk12/drivers/usb/pegasus.h
--- linux-2.4.23-bk11/drivers/usb/pegasus.h	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.23-bk12/drivers/usb/pegasus.h	2003-12-16 03:09:16.000000000 -0800
@@ -133,8 +133,10 @@
 #define	VENDOR_LANEED		0x056e
 #define	VENDOR_LINKSYS		0x066b
 #define	VENDOR_MELCO		0x0411
+#define	VENDOR_MICROSOFT	0x045e
 #define	VENDOR_MOBILITY		0x1342
 #define VENDOR_NETGEAR		0x0846
+#define	VENDOR_OCT		0x0b39
 #define	VENDOR_SMARTBRIDGES	0x08d1
 #define	VENDOR_SMC		0x0707
 #define	VENDOR_SOHOWARE		0x15e8
@@ -170,7 +172,7 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
+		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
 PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8513,
 		DEFAULT_GPIO_RESET | PEGASUS_II )	
@@ -255,8 +257,12 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
+		DEFAULT_GPIO_RESET | PEGASUS_II )	
 PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
diff -urN linux-2.4.23-bk11/drivers/usb/printer.c linux-2.4.23-bk12/drivers/usb/printer.c
--- linux-2.4.23-bk11/drivers/usb/printer.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/printer.c	2003-12-16 03:09:16.000000000 -0800
@@ -22,8 +22,11 @@
  *	v0.7 - fixed bulk-IN read and poll (David Paschal)
  *	v0.8 - add devfs support
  *	v0.9 - fix unplug-while-open paths
- *	v0.10 - add proto_bias option (Pete Zaitcev)
- *	v0.11 - add hpoj.sourceforge.net ioctls (David Paschal)
+ *	v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
+ *	v0.11 - add proto_bias option (Pete Zaitcev)
+ *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
+ *	v0.13 - alloc space for statusbuf (<status> not on stack);
+ *		use usb_buffer_alloc() for read buf & write buf;
  */
 
 /*
@@ -58,12 +61,12 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.11"
+#define DRIVER_VERSION "v0.13"
 #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
 #define DRIVER_DESC "USB Printer Device Class driver"
 
 #define USBLP_BUF_SIZE		8192
-#define DEVICE_ID_SIZE		1024
+#define USBLP_DEVICE_ID_SIZE	1024
 
 /* ioctls: */
 #define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
@@ -115,12 +118,20 @@
 #define USBLP_LAST_PROTOCOL	3
 #define USBLP_MAX_PROTOCOLS	(USBLP_LAST_PROTOCOL+1)
 
+/*
+ * some arbitrary status buffer size;
+ * need a status buffer that is allocated via kmalloc(), not on stack
+ */
+#define STATUS_BUF_SIZE		8
+
 struct usblp {
 	struct usb_device 	*dev;			/* USB device */
 	devfs_handle_t		devfs;			/* devfs device */
 	struct semaphore	sem;			/* locks this struct, especially "dev" */
-	char			*buf;		/* writeurb.transfer_buffer */
-	struct urb		readurb, writeurb;	/* The urbs */
+	char			*writebuf;		/* write transfer_buffer */
+	char			*readbuf;		/* read transfer_buffer */
+	char			*statusbuf;		/* status transfer_buffer */
+	struct urb		*readurb, *writeurb;	/* The urbs */
 	wait_queue_head_t	wait;			/* Zzzzz ... */
 	int			readcount;		/* Counter for reads */
 	int			ifnum;			/* Interface number */
@@ -133,8 +144,11 @@
 	}			protocol[USBLP_MAX_PROTOCOLS];
 	int			current_protocol;
 	int			minor;			/* minor number of device */
+	int			wcomplete;		/* writing is completed */
+	int			rcomplete;		/* reading is completed */
 	unsigned int		quirks;			/* quirks flags */
 	unsigned char		used;			/* True if open */
+	unsigned char		present;		/* True if not disconnected */
 	unsigned char		bidir;			/* interface is bidirectional */
 	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
 							/* first 2 bytes are (big-endian) length */
@@ -146,8 +160,11 @@
 
 	dbg("usblp=0x%p", usblp);
 	dbg("dev=0x%p", usblp->dev);
-	dbg("devfs=0x%p", usblp->devfs);
-	dbg("buf=0x%p", usblp->buf);
+	dbg("present=%d", usblp->present);
+	dbg("readbuf=0x%p", usblp->readbuf);
+	dbg("writebuf=0x%p", usblp->writebuf);
+	dbg("readurb=0x%p", usblp->readurb);
+	dbg("writeurb=0x%p", usblp->writeurb);
 	dbg("readcount=%d", usblp->readcount);
 	dbg("ifnum=%d", usblp->ifnum);
     for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
@@ -157,6 +174,8 @@
     }
 	dbg("current_protocol=%d", usblp->current_protocol);
 	dbg("minor=%d", usblp->minor);
+	dbg("wcomplete=%d", usblp->wcomplete);
+	dbg("rcomplete=%d", usblp->rcomplete);
 	dbg("quirks=%d", usblp->quirks);
 	dbg("used=%d", usblp->used);
 	dbg("bidir=%d", usblp->bidir);
@@ -239,17 +258,31 @@
  * URB callback.
  */
 
-static void usblp_bulk(struct urb *urb)
+static void usblp_bulk_read(struct urb *urb)
 {
 	struct usblp *usblp = urb->context;
 
-	if (!usblp || !usblp->dev || !usblp->used)
+	if (!usblp || !usblp->dev || !usblp->used || !usblp->present)
 		return;
 
-	if (urb->status)
+	if (unlikely(urb->status))
 		warn("usblp%d: nonzero read/write bulk status received: %d",
 			usblp->minor, urb->status);
+	usblp->rcomplete = 1;
+	wake_up_interruptible(&usblp->wait);
+}
+
+static void usblp_bulk_write(struct urb *urb)
+{
+	struct usblp *usblp = urb->context;
+
+	if (!usblp || !usblp->dev || !usblp->used || !usblp->present)
+		return;
 
+	if (unlikely(urb->status))
+		warn("usblp%d: nonzero read/write bulk status received: %d",
+			usblp->minor, urb->status);
+	usblp->wcomplete = 1;
 	wake_up_interruptible(&usblp->wait);
 }
 
@@ -257,25 +290,28 @@
  * Get and print printer errors.
  */
 
-static char *usblp_messages[] = { "ok", "out of paper", "off-line", "unknown error" };
+static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
 
 static int usblp_check_status(struct usblp *usblp, int err)
 {
 	unsigned char status, newerr = 0;
 	int error;
 
-	error = usblp_read_status (usblp, &status);
+	error = usblp_read_status (usblp, usblp->statusbuf);
 	if (error < 0) {
 		err("usblp%d: error %d reading printer status",
 			usblp->minor, error);
 		return 0;
 	}
 
-	if (~status & LP_PERRORP) {
+	status = *usblp->statusbuf;
+
+	if (~status & LP_PERRORP)
 		newerr = 3;
-		if (status & LP_POUTPA) newerr = 1;
-		if (~status & LP_PSELECD) newerr = 2;
-	}
+	if (status & LP_POUTPA)
+		newerr = 1;
+	if (~status & LP_PSELECD)
+		newerr = 2;
 
 	if (newerr != err)
 		info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
@@ -300,7 +336,7 @@
 	usblp  = usblp_table[minor];
 
 	retval = -ENODEV;
-	if (!usblp || !usblp->dev)
+	if (!usblp || !usblp->dev || !usblp->present)
 		goto out;
 
 	retval = -EBUSY;
@@ -324,13 +360,14 @@
 	usblp->used = 1;
 	file->private_data = usblp;
 
-	usblp->writeurb.transfer_buffer_length = 0;
-	usblp->writeurb.status = 0;
+	usblp->writeurb->transfer_buffer_length = 0;
+	usblp->wcomplete = 1; /* we begin writeable */
+	usblp->rcomplete = 0;
 
 	if (usblp->bidir) {
 		usblp->readcount = 0;
-		usblp->readurb.dev = usblp->dev;
-		if (usb_submit_urb(&usblp->readurb) < 0) {
+		usblp->readurb->dev = usblp->dev;
+		if (usb_submit_urb(usblp->readurb) < 0) {
 			retval = -EIO;
 			usblp->used = 0;
 			file->private_data = NULL;
@@ -347,16 +384,20 @@
 	usblp_table [usblp->minor] = NULL;
 	info("usblp%d: removed", usblp->minor);
 
-	kfree (usblp->writeurb.transfer_buffer);
+	kfree (usblp->writebuf);
+	kfree (usblp->readbuf);
 	kfree (usblp->device_id_string);
+	kfree (usblp->statusbuf);
+	usb_free_urb(usblp->writeurb);
+	usb_free_urb(usblp->readurb);
 	kfree (usblp);
 }
 
 static void usblp_unlink_urbs(struct usblp *usblp)
 {
-	usb_unlink_urb(&usblp->writeurb);
+	usb_unlink_urb(usblp->writeurb);
 	if (usblp->bidir)
-		usb_unlink_urb(&usblp->readurb);
+		usb_unlink_urb(usblp->readurb);
 }
 
 static int usblp_release(struct inode *inode, struct file *file)
@@ -366,7 +407,7 @@
 	down (&usblp->sem);
 	lock_kernel();
 	usblp->used = 0;
-	if (usblp->dev) {
+	if (usblp->present) {
 		usblp_unlink_urbs(usblp);
 		up(&usblp->sem);
 	} else 		/* finish cleanup from disconnect */
@@ -380,21 +421,21 @@
 {
 	struct usblp *usblp = file->private_data;
 	poll_wait(file, &usblp->wait, wait);
- 	return ((!usblp->bidir || usblp->readurb.status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
- 			       | (usblp->writeurb.status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
+ 	return ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN  | POLLRDNORM)
+ 			       | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
 }
 
 static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct usblp *usblp = file->private_data;
 	int length, err, i;
-	unsigned char lpstatus, newChannel;
+	unsigned char newChannel;
 	int status;
 	int twoints[2];
 	int retval = 0;
 
 	down (&usblp->sem);
-	if (!usblp->dev) {
+	if (!usblp->present) {
 		retval = -ENODEV;
 		goto done;
 	}
@@ -534,24 +575,24 @@
 				break;
 
 			default:
-				retval = -EINVAL;
+				retval = -ENOTTY;
 		}
 	else	/* old-style ioctl value */
 		switch (cmd) {
 
 			case LPGETSTATUS:
-				if (usblp_read_status(usblp, &lpstatus)) {
+				if (usblp_read_status(usblp, usblp->statusbuf)) {
 					err("usblp%d: failed reading printer status", usblp->minor);
 					retval = -EIO;
 					goto done;
 				}
-				status = lpstatus;
+				status = *usblp->statusbuf;
 				if (copy_to_user ((int *)arg, &status, sizeof(int)))
 					retval = -EFAULT;
 				break;
 
 			default:
-				retval = -EINVAL;
+				retval = -ENOTTY;
 		}
 
 done:
@@ -561,41 +602,48 @@
 
 static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
+	DECLARE_WAITQUEUE(wait, current);
 	struct usblp *usblp = file->private_data;
 	int timeout, err = 0;
 	size_t writecount = 0;
 
 	while (writecount < count) {
-
-		// FIXME:  only use urb->status inside completion
-		// callbacks; this way is racey...
-		if (usblp->writeurb.status == -EINPROGRESS) {
-
+		if (!usblp->wcomplete) {
+			barrier();
 			if (file->f_flags & O_NONBLOCK)
 				return -EAGAIN;
 
 			timeout = USBLP_WRITE_TIMEOUT;
-			while (timeout && usblp->writeurb.status == -EINPROGRESS) {
+			add_wait_queue(&usblp->wait, &wait);
+			while ( 1==1 ) {
 
-				if (signal_pending(current))
+				if (signal_pending(current)) {
+					remove_wait_queue(&usblp->wait, &wait);
 					return writecount ? writecount : -EINTR;
-
-				timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
+				}
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (timeout && !usblp->wcomplete) {
+					timeout = schedule_timeout(timeout);
+				} else {
+					set_current_state(TASK_RUNNING);
+					break;
+				}
 			}
+			remove_wait_queue(&usblp->wait, &wait);
 		}
 
 		down (&usblp->sem);
-		if (!usblp->dev) {
+		if (!usblp->present) {
 			up (&usblp->sem);
 			return -ENODEV;
 		}
 
-		if (usblp->writeurb.status != 0) {
+		if (usblp->writeurb->status != 0) {
 			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
-				if (usblp->writeurb.status != -EINPROGRESS)
+				if (!usblp->wcomplete)
 					err("usblp%d: error %d writing to printer",
-						usblp->minor, usblp->writeurb.status);
-				err = usblp->writeurb.status;
+						usblp->minor, usblp->writeurb->status);
+				err = usblp->writeurb->status;
 			} else
 				err = usblp_check_status(usblp, err);
 			up (&usblp->sem);
@@ -607,25 +655,30 @@
 			continue;
 		}
 
-		writecount += usblp->writeurb.transfer_buffer_length;
-		usblp->writeurb.transfer_buffer_length = 0;
+		writecount += usblp->writeurb->transfer_buffer_length;
+		usblp->writeurb->transfer_buffer_length = 0;
 
 		if (writecount == count) {
 			up (&usblp->sem);
 			break;
 		}
 
-		usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
-							 (count - writecount) : USBLP_BUF_SIZE;
+		usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
+							  (count - writecount) : USBLP_BUF_SIZE;
 
-		if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
-				usblp->writeurb.transfer_buffer_length)) {
+		if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
+				usblp->writeurb->transfer_buffer_length)) {
 			up(&usblp->sem);
 			return writecount ? writecount : -EFAULT;
 		}
 
-		usblp->writeurb.dev = usblp->dev;
-		usb_submit_urb(&usblp->writeurb);
+		usblp->writeurb->dev = usblp->dev;
+		usblp->wcomplete = 0;
+		if (usb_submit_urb(usblp->writeurb)) {
+			count = -EIO;
+			up (&usblp->sem);
+			break;
+		}
 		up (&usblp->sem);
 	}
 
@@ -635,63 +688,77 @@
 static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 
 	if (!usblp->bidir)
 		return -EINVAL;
 
 	down (&usblp->sem);
-	if (!usblp->dev) {
+	if (!usblp->present) {
 		count = -ENODEV;
 		goto done;
 	}
 
-	if (usblp->readurb.status == -EINPROGRESS) {
+	if (!usblp->rcomplete) {
+		barrier();
 
 		if (file->f_flags & O_NONBLOCK) {
 			count = -EAGAIN;
 			goto done;
 		}
 
-		// FIXME:  only use urb->status inside completion
-		// callbacks; this way is racey...
-		while (usblp->readurb.status == -EINPROGRESS) {
+		add_wait_queue(&usblp->wait, &wait);
+		while (1==1) {
 			if (signal_pending(current)) {
 				count = -EINTR;
+				remove_wait_queue(&usblp->wait, &wait);
 				goto done;
 			}
 			up (&usblp->sem);
-			interruptible_sleep_on(&usblp->wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!usblp->rcomplete) {
+				schedule();
+			} else {
+				set_current_state(TASK_RUNNING);
+				break;
+			}
 			down (&usblp->sem);
 		}
+		remove_wait_queue(&usblp->wait, &wait);
 	}
 
-	if (!usblp->dev) {
+	if (!usblp->present) {
 		count = -ENODEV;
 		goto done;
 	}
 
-	if (usblp->readurb.status) {
+	if (usblp->readurb->status) {
 		err("usblp%d: error %d reading from printer",
-			usblp->minor, usblp->readurb.status);
-		usblp->readurb.dev = usblp->dev;
+			usblp->minor, usblp->readurb->status);
+		usblp->readurb->dev = usblp->dev;
  		usblp->readcount = 0;
-		usb_submit_urb(&usblp->readurb);
+		if (usb_submit_urb(usblp->readurb) < 0)
+			dbg("error submitting urb");
 		count = -EIO;
 		goto done;
 	}
 
-	count = count < usblp->readurb.actual_length - usblp->readcount ?
-		count :	usblp->readurb.actual_length - usblp->readcount;
+	count = count < usblp->readurb->actual_length - usblp->readcount ?
+		count :	usblp->readurb->actual_length - usblp->readcount;
 
-	if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) {
+	if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
 		count = -EFAULT;
 		goto done;
 	}
 
-	if ((usblp->readcount += count) == usblp->readurb.actual_length) {
+	if ((usblp->readcount += count) == usblp->readurb->actual_length) {
 		usblp->readcount = 0;
-		usblp->readurb.dev = usblp->dev;
-		usb_submit_urb(&usblp->readurb);
+		usblp->readurb->dev = usblp->dev;
+		usblp->rcomplete = 0;
+		if (usb_submit_urb(usblp->readurb)) {
+			count = -EIO;
+			goto done;
+		}
 	}
 
 done:
@@ -766,19 +833,42 @@
 		}
 	}
 
+	usblp->writeurb = usb_alloc_urb(0);
+	if (!usblp->writeurb) {
+		err("out of memory");
+		goto abort;
+	}
+	usblp->readurb = usb_alloc_urb(0);
+	if (!usblp->readurb) {
+		err("out of memory");
+		goto abort;
+	}
+
 	/* Malloc device ID string buffer to the largest expected length,
 	 * since we can re-query it on an ioctl and a dynamic string
 	 * could change in length. */
-	if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
+	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
 		err("out of memory for device_id_string");
 		goto abort;
 	}
 
-	/* Malloc write/read buffers in one chunk.  We somewhat wastefully
+	usblp->writebuf = usblp->readbuf = NULL;
+	/* Malloc write & read buffers.  We somewhat wastefully
 	 * malloc both regardless of bidirectionality, because the
 	 * alternate setting can be changed later via an ioctl. */
-	if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) {
-		err("out of memory for buf");
+	if (!(usblp->writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL))) {
+		err("out of memory for write buf");
+		goto abort;
+	}
+	if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL))) {
+		err("out of memory for read buf");
+		goto abort;
+	}
+
+	/* Allocate buffer for printer status */
+	usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
+	if (!usblp->statusbuf) {
+		err("out of memory for statusbuf");
 		goto abort;
 	}
 
@@ -818,17 +908,26 @@
 
 	info("usblp%d: USB %sdirectional printer dev %d "
 		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
-		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, ifnum,
+		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
+		usblp->ifnum,
 		usblp->protocol[usblp->current_protocol].alt_setting,
 		usblp->current_protocol, usblp->dev->descriptor.idVendor,
 		usblp->dev->descriptor.idProduct);
 
+	usblp->present = 1;
+
 	return usblp;
 
 abort:
 	if (usblp) {
-		if (usblp->buf) kfree(usblp->buf);
-		if (usblp->device_id_string) kfree(usblp->device_id_string);
+		if (usblp->writebuf)
+			kfree (usblp->writebuf);
+		if (usblp->readbuf)
+			kfree (usblp->readbuf);
+		kfree(usblp->statusbuf);
+		kfree(usblp->device_id_string);
+		usb_free_urb(usblp->writeurb);
+		usb_free_urb(usblp->readurb);
 		kfree(usblp);
 	}
 	return NULL;
@@ -943,19 +1042,19 @@
 		return r;
 	}
 
-	FILL_BULK_URB(&usblp->writeurb, usblp->dev,
+	usb_fill_bulk_urb(usblp->writeurb, usblp->dev,
 		usb_sndbulkpipe(usblp->dev,
-		 usblp->protocol[protocol].epwrite->bEndpointAddress),
-		usblp->buf, 0,
-		usblp_bulk, usblp);
+		  usblp->protocol[protocol].epwrite->bEndpointAddress),
+		usblp->writebuf, 0,
+		usblp_bulk_write, usblp);
 
 	usblp->bidir = (usblp->protocol[protocol].epread != 0);
 	if (usblp->bidir)
-		FILL_BULK_URB(&usblp->readurb, usblp->dev,
+		usb_fill_bulk_urb(usblp->readurb, usblp->dev,
 			usb_rcvbulkpipe(usblp->dev,
-			 usblp->protocol[protocol].epread->bEndpointAddress),
-			usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE,
-			usblp_bulk, usblp);
+			  usblp->protocol[protocol].epread->bEndpointAddress),
+			usblp->readbuf, USBLP_BUF_SIZE,
+			usblp_bulk_read, usblp);
 
 	usblp->current_protocol = protocol;
 	dbg("usblp%d set protocol %d", usblp->minor, protocol);
@@ -969,7 +1068,7 @@
 {
 	int err, length;
 
-	err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
+	err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
 	if (err < 0) {
 		dbg("usblp%d: error = %d reading IEEE-1284 Device ID string",
 			usblp->minor, err);
@@ -983,8 +1082,8 @@
 	length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1];
 	if (length < 2)
 		length = 2;
-	else if (length >= DEVICE_ID_SIZE)
-		length = DEVICE_ID_SIZE - 1;
+	else if (length >= USBLP_DEVICE_ID_SIZE)
+		length = USBLP_DEVICE_ID_SIZE - 1;
 	usblp->device_id_string[length] = '\0';
 
 	dbg("usblp%d Device ID string [len=%d]=\"%s\"",
@@ -1004,13 +1103,13 @@
 
 	down (&usblp->sem);
 	lock_kernel();
-	usblp->dev = NULL;
+	usblp->present = 0;
 
 	usblp_unlink_urbs(usblp);
 
 	if (!usblp->used)
 		usblp_cleanup (usblp);
-	else 	/* cleanup later, on close */
+	else 	/* cleanup later, on release */
 		up (&usblp->sem);
 	unlock_kernel();
 }
diff -urN linux-2.4.23-bk11/drivers/usb/scanner.c linux-2.4.23-bk12/drivers/usb/scanner.c
--- linux-2.4.23-bk11/drivers/usb/scanner.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/scanner.c	2003-12-16 03:09:16.000000000 -0800
@@ -385,6 +385,10 @@
  *    - Use static declarations for usb_scanner_init/usb_scanner_exit 
  *      (Daniele Bellucci).
  *
+ * 0.4.16  2003-11-04
+ *    - Added vendor/product ids for Epson, Genius, Microtek, Plustek, Reflecta, and
+ *      Visioneer scanners. Removed ids for HP PSC devices as these are supported by
+ *      the hpoj userspace driver.
  *
  * TODO
  *    - Performance
diff -urN linux-2.4.23-bk11/drivers/usb/scanner.h linux-2.4.23-bk12/drivers/usb/scanner.h
--- linux-2.4.23-bk11/drivers/usb/scanner.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/scanner.h	2003-12-16 03:09:16.000000000 -0800
@@ -44,7 +44,7 @@
 
 // #define DEBUG
 
-#define DRIVER_VERSION "0.4.15"
+#define DRIVER_VERSION "0.4.16"
 #define DRIVER_DESC "USB Scanner Driver"
 
 #include <linux/usb.h>
@@ -147,7 +147,12 @@
 	{ USB_DEVICE(0x0458, 0x2015) }, /* ColorPage HR7LE */
 	{ USB_DEVICE(0x0458, 0x2016) }, /* ColorPage HR6X */
 	{ USB_DEVICE(0x0458, 0x2018) },	/* ColorPage HR7X */
+	{ USB_DEVICE(0x0458, 0x201b) },	/* Colorpage Vivid 4x */
 	/* Hewlett Packard */
+	/* IMPORTANT: Hewlett-Packard multi-function peripherals (OfficeJet, 
+	   Printer/Scanner/Copier (PSC), LaserJet, or PhotoSmart printer)
+	   should not be added to this table because they are accessed by a
+	   userspace driver (hpoj) */
 	{ USB_DEVICE(0x03f0, 0x0101) },	/* ScanJet 4100C */
 	{ USB_DEVICE(0x03f0, 0x0102) },	/* PhotoSmart S20 */
 	{ USB_DEVICE(0x03f0, 0x0105) },	/* ScanJet 4200C */
@@ -169,10 +174,10 @@
 	{ USB_DEVICE(0x03F0, 0x1105) },	/* ScanJet 5470C */
 	{ USB_DEVICE(0x03f0, 0x1205) }, /* ScanJet 5550C */
 	{ USB_DEVICE(0x03f0, 0x1305) },	/* Scanjet 4570c */
-	{ USB_DEVICE(0x03f0, 0x1411) }, /* PSC 750 */
+	//	{ USB_DEVICE(0x03f0, 0x1411) }, /* PSC 750 - NOT SUPPORTED - use hpoj userspace driver */
 	{ USB_DEVICE(0x03f0, 0x2005) },	/* ScanJet 3570c */
 	{ USB_DEVICE(0x03f0, 0x2205) },	/* ScanJet 3500c */
-	{ USB_DEVICE(0x03f0, 0x2f11) }, /* PSC 1210 */
+	//	{ USB_DEVICE(0x03f0, 0x2f11) }, /* PSC 1210 - NOT SUPPORTED - use hpoj userspace driver */
 	/* Lexmark */
 	{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
 	{ USB_DEVICE(0x043d, 0x003d) }, /* X83 */
@@ -188,6 +193,7 @@
 	{ USB_DEVICE(0x05da, 0x30ce) },	/* ScanMaker 3800 */
 	{ USB_DEVICE(0x05da, 0x30cf) },	/* ScanMaker 4800 */
 	{ USB_DEVICE(0x05da, 0x30d4) },	/* ScanMaker 3830 + 3840 */
+	{ USB_DEVICE(0x05da, 0x30d8) },	/* ScanMaker 5900 */
 	{ USB_DEVICE(0x04a7, 0x0224) },	/* Scanport 3000 (actually Visioneer?)*/
 	/* The following SCSI-over-USB Microtek devices are supported by the
 	   microtek driver: Enable SCSI and USB Microtek in kernel config */
@@ -246,6 +252,7 @@
 	{ USB_DEVICE(0x07b3, 0x0400) }, /* OpticPro 1248U */
 	{ USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U (another one) */
 	{ USB_DEVICE(0x07b3, 0x0403) },	/* U16B */
+	{ USB_DEVICE(0x07b3, 0x0413) },	/* OpticSlim 1200 */
 	/* Primax/Colorado */
 	{ USB_DEVICE(0x0461, 0x0300) },	/* G2-300 #1 */
 	{ USB_DEVICE(0x0461, 0x0301) },	/* G2E-300 #1 */
@@ -262,6 +269,8 @@
 	{ USB_DEVICE(0x0461, 0x0383) },	/* G2E-600 */
 	/* Prolink */
 	{ USB_DEVICE(0x06dc, 0x0014) }, /* Winscan Pro 2448U */
+	/* Reflecta  */
+	{ USB_DEVICE(0x05e3, 0x0120) },	/* iScan 1800 */
 	/* Relisis */
 	// { USB_DEVICE(0x0475, 0x0103) },	/* Episode - undetected endpoint */
 	{ USB_DEVICE(0x0475, 0x0210) }, /* Scorpio Ultra 3 */
@@ -286,6 +295,7 @@
 	{ USB_DEVICE(0x04b8, 0x011c) }, /* Perfection 3200 */
 	{ USB_DEVICE(0x04b8, 0x011d) }, /* Perfection 1260 */
 	{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
+	{ USB_DEVICE(0x04b8, 0x011f) },	/* Perfection 1670 */
 	{ USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */
 	{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
 	/* Siemens */
@@ -310,6 +320,7 @@
 	{ USB_DEVICE(0x04a7, 0x0221) },	/* OneTouch 5300 USB */
 	{ USB_DEVICE(0x04a7, 0x0224) },	/* OneTouch 4800 USB */
 	{ USB_DEVICE(0x04a7, 0x0226) },	/* OneTouch 5800 USB */
+	{ USB_DEVICE(0x04a7, 0x0229) }, /* OneTouch 7100 USB */
 	{ USB_DEVICE(0x04a7, 0x022c) },	/* OneTouch 9020 USB */
 	{ USB_DEVICE(0x04a7, 0x0231) },	/* 6100 USB */
 	{ USB_DEVICE(0x04a7, 0x0311) },	/* 6200 EPP/USB */
diff -urN linux-2.4.23-bk11/drivers/usb/serial/ftdi_sio.c linux-2.4.23-bk12/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.23-bk11/drivers/usb/serial/ftdi_sio.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/ftdi_sio.c	2003-12-16 03:09:16.000000000 -0800
@@ -333,6 +333,10 @@
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) },
 	{ }						/* Terminating entry */
 };
 
@@ -407,6 +411,10 @@
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) },
 	{ }						/* Terminating entry */
 };
 
@@ -496,6 +504,10 @@
 	{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) },
 	{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
+	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) },
+	{ USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
+	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
+	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
 	{ }						/* Terminating entry */
 };
 
diff -urN linux-2.4.23-bk11/drivers/usb/serial/ftdi_sio.h linux-2.4.23-bk12/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.23-bk11/drivers/usb/serial/ftdi_sio.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/ftdi_sio.h	2003-12-16 03:09:16.000000000 -0800
@@ -145,6 +145,14 @@
 /* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
 #define OCT_US101_PID		0x0421	/* OCT US101 USB to RS-232 */
 
+/*
+ * Protego product ids
+ */
+#define PROTEGO_SPECIAL_1	0xFC70	/* special/unknown device */
+#define PROTEGO_R2X0		0xFC71	/* R200-USB TRNG unit (R210, R220, and R230) */
+#define PROTEGO_SPECIAL_3	0xFC72	/* special/unknown device */
+#define PROTEGO_SPECIAL_4	0xFC73	/* special/unknown device */ 
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff -urN linux-2.4.23-bk11/drivers/usb/serial/io_edgeport.c linux-2.4.23-bk12/drivers/usb/serial/io_edgeport.c
--- linux-2.4.23-bk11/drivers/usb/serial/io_edgeport.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/io_edgeport.c	2003-12-16 03:09:16.000000000 -0800
@@ -1468,15 +1468,19 @@
 	urb->transfer_flags |= USB_QUEUE_BULK;
 
 	urb->dev = edge_serial->serial->dev;
+	/* decrement the number of credits we have by the number we just sent */
+	edge_port->txCredits -= count;
+	edge_port->icount.tx += count;
+
 	status = usb_submit_urb(urb);
 	if (status) {
 		/* something went wrong */
 		dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
 		edge_port->write_in_progress = FALSE;
-	} else {
-		/* decrement the number of credits we have by the number we just sent */
-		edge_port->txCredits -= count;
-		edge_port->icount.tx += count;
+
+		/*revert the count if something bad happened...*/
+		edge_port->txCredits += count;
+		edge_port->icount.tx -= count;
 	}
 	dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count, edge_port->txCredits, fifo->count);
 }
diff -urN linux-2.4.23-bk11/drivers/usb/serial/io_fw_boot.h linux-2.4.23-bk12/drivers/usb/serial/io_fw_boot.h
--- linux-2.4.23-bk11/drivers/usb/serial/io_fw_boot.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/io_fw_boot.h	2003-12-16 03:09:16.000000000 -0800
@@ -17,7 +17,7 @@
 		unsigned short Addr;
 		unsigned short Len;
 		unsigned char  Data[0];
-	};
+	} __attribute__ ((packed));
 
 	struct edge_firmware_version_info {
 		unsigned char	 MajorVersion;
diff -urN linux-2.4.23-bk11/drivers/usb/serial/io_fw_boot2.h linux-2.4.23-bk12/drivers/usb/serial/io_fw_boot2.h
--- linux-2.4.23-bk11/drivers/usb/serial/io_fw_boot2.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/io_fw_boot2.h	2003-12-16 03:09:16.000000000 -0800
@@ -17,7 +17,7 @@
 		unsigned short Addr;
 		unsigned short Len;
 		unsigned char  Data[0];
-	};
+	} __attribute__ ((packed));
 
 	struct edge_firmware_version_info {
 		unsigned char	 MajorVersion;
diff -urN linux-2.4.23-bk11/drivers/usb/serial/io_fw_down.h linux-2.4.23-bk12/drivers/usb/serial/io_fw_down.h
--- linux-2.4.23-bk11/drivers/usb/serial/io_fw_down.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/io_fw_down.h	2003-12-16 03:09:16.000000000 -0800
@@ -17,7 +17,7 @@
 		unsigned short	Addr;
 		unsigned short	Len;
 		unsigned char	Data[0];
-	};
+	} __attribute ((packed));
 
 	struct edge_firmware_version_info {
 		unsigned char	MajorVersion;
diff -urN linux-2.4.23-bk11/drivers/usb/serial/io_fw_down2.h linux-2.4.23-bk12/drivers/usb/serial/io_fw_down2.h
--- linux-2.4.23-bk11/drivers/usb/serial/io_fw_down2.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/io_fw_down2.h	2003-12-16 03:09:16.000000000 -0800
@@ -17,7 +17,7 @@
 		unsigned short Addr;
 		unsigned short Len;
 		unsigned char  Data[0];
-	};
+	} __attribute__ ((packed));
 
 	struct edge_firmware_version_info {
 		unsigned char  MajorVersion;
diff -urN linux-2.4.23-bk11/drivers/usb/serial/mct_u232.c linux-2.4.23-bk12/drivers/usb/serial/mct_u232.c
--- linux-2.4.23-bk11/drivers/usb/serial/mct_u232.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/mct_u232.c	2003-12-16 03:09:16.000000000 -0800
@@ -24,6 +24,11 @@
  *   Basic tests have been performed with minicom/zmodem transfers and
  *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
  *
+ * 04-Nov-2003 Bill Marr <marr at flex dot com>
+ *   - Mimic Windows driver by sending 2 USB 'device request' messages
+ *     following normal 'baud rate change' message.  This allows data to be
+ *     transmitted to RS-232 devices which don't assert the 'CTS' signal.
+ *
  * 10-Nov-2001 Wolfgang Grandegger
  *   - Fixed an endianess problem with the baudrate selection for PowerPC.
  *
@@ -85,7 +90,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1"
+#define DRIVER_VERSION "v1.2"
 #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
 #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
 
@@ -201,6 +206,7 @@
 {
 	unsigned int divisor;
         int rc;
+        unsigned char zero_byte = 0;
 	divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                              MCT_U232_SET_BAUD_RATE_REQUEST,
@@ -210,6 +216,35 @@
 	if (rc < 0)
 		err("Set BAUD RATE %d failed (error = %d)", value, rc);
 	dbg("set_baud_rate: value: %d, divisor: 0x%x", value, divisor);
+
+	/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
+	   always sends two extra USB 'device request' messages after the
+	   'baud rate change' message.  The actual functionality of the
+	   request codes in these messages is not fully understood but these
+	   particular codes are never seen in any operation besides a baud
+	   rate change.  Both of these messages send a single byte of data
+	   whose value is always zero.  The second of these two extra messages
+	   is required in order for data to be properly written to an RS-232
+	   device which does not assert the 'CTS' signal. */
+
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     MCT_U232_SET_UNKNOWN1_REQUEST, 
+			     MCT_U232_SET_REQUEST_TYPE,
+			     0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE, 
+			     WDR_TIMEOUT);
+	if (rc < 0)
+		err("Sending USB device request code %d failed (error = %d)", 
+		    MCT_U232_SET_UNKNOWN1_REQUEST, rc);
+
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     MCT_U232_SET_UNKNOWN2_REQUEST, 
+			     MCT_U232_SET_REQUEST_TYPE,
+			     0, 0, &zero_byte, MCT_U232_SET_UNKNOWN2_SIZE, 
+			     WDR_TIMEOUT);
+	if (rc < 0)
+		err("Sending USB device request code %d failed (error = %d)", 
+		    MCT_U232_SET_UNKNOWN2_REQUEST, rc);
+
         return rc;
 } /* mct_u232_set_baud_rate */
 
diff -urN linux-2.4.23-bk11/drivers/usb/serial/mct_u232.h linux-2.4.23-bk12/drivers/usb/serial/mct_u232.h
--- linux-2.4.23-bk11/drivers/usb/serial/mct_u232.h	2001-12-21 09:41:55.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/mct_u232.h	2003-12-16 03:09:16.000000000 -0800
@@ -57,6 +57,21 @@
 #define MCT_U232_SET_MODEM_CTRL_REQUEST	10 /* Set Modem Control Register (MCR) */
 #define MCT_U232_SET_MODEM_CTRL_SIZE    1
 
+/* This USB device request code is not well understood.  It is transmitted by
+   the MCT-supplied Windows driver whenever the baud rate changes. 
+*/
+#define MCT_U232_SET_UNKNOWN1_REQUEST   11  /* Unknown functionality */
+#define MCT_U232_SET_UNKNOWN1_SIZE       1
+
+/* This USB device request code is not well understood.  It is transmitted by
+   the MCT-supplied Windows driver whenever the baud rate changes. 
+   
+   Without this USB device request, the USB/RS-232 adapter will not write to
+   RS-232 devices which do not assert the 'CTS' signal.
+*/
+#define MCT_U232_SET_UNKNOWN2_REQUEST   12  /* Unknown functionality */
+#define MCT_U232_SET_UNKNOWN2_SIZE       1
+
 /*
  * Baud rate (divisor)
  */
@@ -137,22 +152,31 @@
  * Baud rate (divisor)
  * -------------------
  *
- *   BmRequestType:  0x4 (0100 0000B)
- *   bRequest:       0x5
- *   wValue:         0x0
- *   wIndex:         0x0
- *   wLength:        0x4
+ *   BmRequestType:  0x40 (0100 0000B)
+ *   bRequest:       0x05
+ *   wValue:         0x0000
+ *   wIndex:         0x0000
+ *   wLength:        0x0004
  *   Data:           divisor = 115200 / baud_rate
  *
+ *   SniffUSB observations (Nov 2003): Contrary to the 'wLength' value of 4
+ *   shown above, observations with a Belkin F5U109 adapter, using the
+ *   MCT-supplied Windows98 driver (U2SPORT.VXD, "File version: 1.21P.0104 for
+ *   Win98/Me"), show this request has a length of 1 byte, presumably because
+ *   of the fact that the Belkin adapter and the 'Sitecom U232-P25' adapter
+ *   use a baud-rate code instead of a conventional RS-232 baud rate divisor.
+ *   The current source code for this driver does not reflect this fact, but
+ *   the driver works fine with this adapter/driver combination nonetheless.
+ *
  *
  * Line Control Register (LCR)
  * ---------------------------
  *
- *  BmRequestType:  0x4 (0100 0000B)    0xc (1100 0000B)
- *  bRequest:       0x7                 0x6
- *  wValue:         0x0
- *  wIndex:         0x0
- *  wLength:        0x1
+ *  BmRequestType:  0x40 (0100 0000B)    0xc0 (1100 0000B)
+ *  bRequest:       0x07                 0x06
+ *  wValue:         0x0000
+ *  wIndex:         0x0000
+ *  wLength:        0x0001
  *  Data:           LCR (see below)
  *
  *  Bit 7: Divisor Latch Access Bit (DLAB). When set, access to the data
@@ -186,18 +210,18 @@
  *
  *  SniffUSB observations: Bit 7 seems not to be used. There seem to be two bugs
  *  in the Win98 driver: the break does not work (bit 6 is not asserted) and the
- *  sticky parity bit is not cleared when set once. The LCR can also be read
+ *  stick parity bit is not cleared when set once. The LCR can also be read
  *  back with USB request 6 but this has never been observed with SniffUSB.
  *
  *
  * Modem Control Register (MCR)
  * ----------------------------
  *
- *  BmRequestType:  0x4  (0100 0000B)
- *  bRequest:       0xa
- *  wValue:         0x0
- *  wIndex:         0x0
- *  wLength:        0x1
+ *  BmRequestType:  0x40  (0100 0000B)
+ *  bRequest:       0x0a
+ *  wValue:         0x0000
+ *  wIndex:         0x0000
+ *  wLength:        0x0001
  *  Data:           MCR (Bit 4..7, see below)
  *
  *  Bit 7: Reserved, always 0.
@@ -226,11 +250,11 @@
  * Modem Status Register (MSR)
  * ---------------------------
  *
- *  BmRequestType:  0xc  (1100 0000B)
- *  bRequest:       0x2
- *  wValue:         0x0
- *  wIndex:         0x0
- *  wLength:        0x1
+ *  BmRequestType:  0xc0  (1100 0000B)
+ *  bRequest:       0x02
+ *  wValue:         0x0000
+ *  wIndex:         0x0000
+ *  wLength:        0x0001
  *  Data:           MSR (see below)
  *
  *  Bit 7: Data Carrier Detect (CD). Reflects the state of the DCD line on the
@@ -287,6 +311,41 @@
  *  minicom/zmodem transfers (CRC errors).
  *
  *
+ * Unknown #1
+ * -------------------
+ *
+ *   BmRequestType:  0x40 (0100 0000B)
+ *   bRequest:       0x0b
+ *   wValue:         0x0000
+ *   wIndex:         0x0000
+ *   wLength:        0x0001
+ *   Data:           0x00
+ *
+ *   SniffUSB observations (Nov 2003): With the MCT-supplied Windows98 driver
+ *   (U2SPORT.VXD, "File version: 1.21P.0104 for Win98/Me"), this request
+ *   occurs immediately after a "Baud rate (divisor)" message.  It was not
+ *   observed at any other time.  It is unclear what purpose this message
+ *   serves.
+ *
+ *
+ * Unknown #2
+ * -------------------
+ *
+ *   BmRequestType:  0x40 (0100 0000B)
+ *   bRequest:       0x0c
+ *   wValue:         0x0000
+ *   wIndex:         0x0000
+ *   wLength:        0x0001
+ *   Data:           0x00
+ *
+ *   SniffUSB observations (Nov 2003): With the MCT-supplied Windows98 driver
+ *   (U2SPORT.VXD, "File version: 1.21P.0104 for Win98/Me"), this request
+ *   occurs immediately after the 'Unknown #1' message (see above).  It was
+ *   not observed at any other time.  It is unclear what other purpose (if
+ *   any) this message might serve, but without it, the USB/RS-232 adapter
+ *   will not write to RS-232 devices which do not assert the 'CTS' signal.
+ *
+ *
  * Flow control
  * ------------
  *
diff -urN linux-2.4.23-bk11/drivers/usb/serial/pl2303.c linux-2.4.23-bk12/drivers/usb/serial/pl2303.c
--- linux-2.4.23-bk11/drivers/usb/serial/pl2303.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/pl2303.c	2003-12-16 03:09:16.000000000 -0800
@@ -69,6 +69,7 @@
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
 	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
 	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
 	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
 	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
@@ -156,6 +157,7 @@
 
 struct pl2303_private {
 	spinlock_t lock;
+	wait_queue_head_t delta_msr_wait;
 	u8 line_control;
 	u8 line_status;
 	u8 termios_initialized;
@@ -173,6 +175,7 @@
 			return -ENOMEM;
 		memset (priv, 0x00, sizeof (struct pl2303_private));
 		spin_lock_init(&priv->lock);
+		init_waitqueue_head(&priv->delta_msr_wait);
 		usb_set_serial_port_data(&serial->port[i], priv);
 	}
 	return 0;
@@ -563,6 +566,42 @@
 	return 0;
 }
 
+static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+{
+	struct pl2303_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+	unsigned int prevstatus;
+	unsigned int status;
+	unsigned int changed;
+
+	spin_lock_irqsave (&priv->lock, flags);
+	prevstatus = priv->line_status;
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	while (1) {
+		interruptible_sleep_on(&priv->delta_msr_wait);
+		/* see if a signal did it */
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		
+		spin_lock_irqsave (&priv->lock, flags);
+		status = priv->line_status;
+		spin_unlock_irqrestore (&priv->lock, flags);
+		
+		changed=prevstatus^status;
+		
+		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
+		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
+		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
+		    ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
+			return 0;
+		}
+		prevstatus = status;
+	}
+	/* NOTREACHED */
+	return 0;
+}
+
 static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
@@ -579,6 +618,10 @@
 			dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,  port->number);
 			return set_modem_info(port, cmd, (unsigned int *) arg);
 
+		case TIOCMIWAIT:
+			dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
+			return wait_modem_info(port, arg);
+		
 		default:
 			dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
 			break;
@@ -662,6 +705,7 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->line_status = data[UART_STATE];
 	spin_unlock_irqrestore(&priv->lock, flags);
+	wake_up_interruptible (&priv->delta_msr_wait);
 
 	return;
 }
diff -urN linux-2.4.23-bk11/drivers/usb/serial/pl2303.h linux-2.4.23-bk12/drivers/usb/serial/pl2303.h
--- linux-2.4.23-bk11/drivers/usb/serial/pl2303.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/pl2303.h	2003-12-16 03:09:16.000000000 -0800
@@ -12,6 +12,7 @@
 #define PL2303_PRODUCT_ID_RSAQ2	0x04bb
 
 #define ATEN_VENDOR_ID		0x0557
+#define ATEN_VENDOR_ID2		0x0547
 #define ATEN_PRODUCT_ID		0x2008
 
 #define IODATA_VENDOR_ID	0x04bb
diff -urN linux-2.4.23-bk11/drivers/usb/serial/visor.c linux-2.4.23-bk12/drivers/usb/serial/visor.c
--- linux-2.4.23-bk11/drivers/usb/serial/visor.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/visor.c	2003-12-16 03:09:16.000000000 -0800
@@ -211,6 +211,7 @@
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ }					/* Terminating entry */
@@ -241,6 +242,7 @@
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ }					/* Terminating entry */
diff -urN linux-2.4.23-bk11/drivers/usb/serial/visor.h linux-2.4.23-bk12/drivers/usb/serial/visor.h
--- linux-2.4.23-bk11/drivers/usb/serial/visor.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/serial/visor.h	2003-12-16 03:09:16.000000000 -0800
@@ -41,6 +41,7 @@
 #define SONY_CLIE_4_1_ID		0x009A
 #define SONY_CLIE_NX60_ID		0x00DA
 #define SONY_CLIE_NZ90V_ID		0x00E9
+#define SONY_CLIE_UX50_ID		0x0144
 
 #define SAMSUNG_VENDOR_ID		0x04E8
 #define SAMSUNG_SCH_I330_ID		0x8001
diff -urN linux-2.4.23-bk11/drivers/usb/storage/unusual_devs.h linux-2.4.23-bk12/drivers/usb/storage/unusual_devs.h
--- linux-2.4.23-bk11/drivers/usb/storage/unusual_devs.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/storage/unusual_devs.h	2003-12-16 03:09:16.000000000 -0800
@@ -45,6 +45,13 @@
  *
  */
 
+/* Patch submitted by Martin Berentsen <berentsen at sent5 dot uni-duisburg dot de> */
+#define US_FL_START_STOP  0x00000004   /* ignore START_STOP commands     */
+UNUSUAL_DEV(  0x0686, 0x4014, 0x0001, 0x0001, 
+		"Minolta",
+		"Dimage S414",
+		US_SC_SCSI, US_PR_BULK, NULL, US_FL_START_STOP), 
+
 UNUSUAL_DEV(  0x03ee, 0x0000, 0x0000, 0x0245, 
 		"Mitsumi",
 		"CD-R/RW Drive",
@@ -53,7 +60,7 @@
 UNUSUAL_DEV(  0x03ee, 0x6901, 0x0000, 0x0100,
 		"Mitsumi",
 		"USB FDD",
-		US_SC_UFI, US_PR_CBI, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_SINGLE_LUN ),
 
 UNUSUAL_DEV(  0x03f0, 0x0107, 0x0200, 0x0200, 
@@ -102,6 +109,12 @@
 		"Finecam S4",
 		US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
 
+/* Patch submitted by Stephane Galles <stephane.galles@free.fr> */
+UNUSUAL_DEV(  0x0482, 0x0103, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S5",
+		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+
 /* Reported by Paul Stewart <stewart@wetlogic.net>
  * This entry is needed because the device reports Sub=ff */
 UNUSUAL_DEV(  0x04a4, 0x0004, 0x0001, 0x0001,
@@ -257,7 +270,7 @@
 UNUSUAL_DEV(  0x054c, 0x002d, 0x0100, 0x0100, 
 		"Sony",
 		"Memorystick MSAC-US1",
-		US_SC_UFI, US_PR_CB, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_SINGLE_LUN ),
 
 /* Submitted by Klaus Mueller <k.mueller@intershop.de> */
@@ -298,6 +311,12 @@
 		US_SC_DEVICE,  US_PR_DEVICE, NULL,
 		US_FL_SINGLE_LUN),
 
+/* Fabrizio Fellini <fello@libero.it> */
+UNUSUAL_DEV(  0x0595, 0x4343, 0x0000, 0x2210,
+		"Fujifilm",
+		"Digital Camera EX-20 DSC",
+		US_SC_8070, US_PR_CBI, NULL, 0 ),
+
 UNUSUAL_DEV(  0x059f, 0xa601, 0x0200, 0x0200, 
 		"LaCie",
 		"USB Hard Disk",
@@ -354,6 +373,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
+/* Submitted Alexander Oltu <alexander@all-2.com> */
+UNUSUAL_DEV(  0x05e3, 0x0701, 0x0000, 0xffff, 
+		"", 
+		"USB TO IDE",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_MODE_XLATE ), 
+
 /* Reported by Peter Marks <peter.marks@turner.com>
  * Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly
  * 36 bytes of data.  No more, no less. That is the only reason this entry
@@ -400,6 +426,28 @@
                 "DIMAGE E223",
                 US_SC_SCSI, US_PR_DEVICE, NULL, 0 ),
 
+/* Following three Minolta cameras reported by Martin Pool
+ * <mbp@sourcefrog.net>.  Originally discovered by Kedar Petankar,
+ * Matthew Geier, Mikael Lofj"ard, Marcel de Boer.
+ */
+UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
+             "Minolta",
+             "DiMAGE 7",
+             US_SC_SCSI, US_PR_DEVICE, NULL,
+             0 ),
+
+UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001,
+             "Minolta",
+             "DiMAGE 7i",
+             US_SC_SCSI, US_PR_DEVICE, NULL,
+             0 ),
+
+UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001,
+             "Minolta",
+             "DiMAGE 7Hi",
+             US_SC_SCSI, US_PR_DEVICE, NULL,
+             0 ),
+
 UNUSUAL_DEV(  0x0693, 0x0002, 0x0100, 0x0100, 
 		"Hagiwara",
 		"FlashGate SmartMedia",
@@ -441,6 +489,11 @@
 		"Freecom",
 		"USB-IDE",
 		US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
+
+UNUSUAL_DEV(  0x07ab, 0xfc84, 0x0000, 0x9999,
+		"Freecom",
+		"FX-5/FX-50",
+		US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
 #endif
 
 UNUSUAL_DEV(  0x07af, 0x0004, 0x0100, 0x0133, 
@@ -528,6 +581,14 @@
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
 		US_FL_MODE_XLATE ),
 #endif
+#ifdef CONFIG_USB_STORAGE_SDDR55
+/* SM part - aeb <Andries.Brouwer@cwi.nl> */
+UNUSUAL_DEV(  0x07c4, 0xa109, 0x0000, 0xffff,
+		"Datafab Systems, Inc.",
+		"USB to CF + SM Combo (LC1)",
+		US_SC_SCSI, US_PR_SDDR55, NULL,
+		US_FL_SINGLE_LUN ),
+#endif
 
 /* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100
  * Only revision 1.13 tested (same for all of the above devices,
@@ -570,6 +631,14 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_MODE_XLATE ),
 
+/*Medion 6047 Digital Camera
+Davide Andrian <_nessuno_@katamail.com>
+*/
+UNUSUAL_DEV( 0x08ca, 0x2011, 0x0001, 0x0001,
+		"3MegaCam",
+		"3MegaCam",
+		US_SC_DEVICE, US_PR_BULK, NULL,
+		US_FL_MODE_XLATE ),
 /* aeb */
 UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
 		"Feiya",
@@ -605,8 +674,8 @@
 /* Submitted by Per Winkvist <per.winkvist@uk.com> */
 UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009,
                 "Pentax",
-                "Optio S",
-                US_SC_8070, US_PR_CBI, NULL,
+                "Optio S/S4",
+                US_SC_DEVICE, US_PR_DEVICE, NULL,
                 US_FL_FIX_INQUIRY ),
 		
 #ifdef CONFIG_USB_STORAGE_ISD200
@@ -617,13 +686,6 @@
 		0 ),
 #endif
 
-/* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
-UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
-		"USB",
-		"Solid state disk",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_INQUIRY ),
-
 /* Submitted by Joris Struyve <joris@struyve.be> */
 UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
 		"Medion",
@@ -640,6 +702,13 @@
 		"Jenoptik",
 		"JD 5200 z3",
 		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+
+/* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
+UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
+		"USB",
+		"Solid state disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
 		
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
diff -urN linux-2.4.23-bk11/drivers/usb/w9968cf.c linux-2.4.23-bk12/drivers/usb/w9968cf.c
--- linux-2.4.23-bk11/drivers/usb/w9968cf.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/w9968cf.c	2003-12-16 03:09:16.000000000 -0800
@@ -1,14 +1,14 @@
 /***************************************************************************
  * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
  *                                                                         *
- * Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it>            *
+ * Copyright (C) 2002 2003 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * - Memory management code from bttv driver by Ralph Metzler,             *
  *   Marcus Metzler and Gerd Knorr.                                        *
  * - I2C interface to kernel, high-level CMOS sensor control routines and  *
  *   some symbolic names from OV511 driver by Mark W. McClelland.          *
  * - Low-level I2C fast write function by Piotr Czerczak.                  *
- * - Low-level I2C read function by Frédéric Jouault.                      *
+ * - Low-level I2C read function by Frederic Jouault.                      *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -46,17 +46,19 @@
 #include "w9968cf.h"
 #include "w9968cf_decoder.h"
 
-EXPORT_NO_SYMBOLS;
-
-
 
 /****************************************************************************
- * Modules paramaters                                                       *
+ * Module macros and paramaters                                             *
  ****************************************************************************/
 
+MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION);
+MODULE_LICENSE(W9968CF_MODULE_LICENSE);
+MODULE_SUPPORTED_DEVICE("Video");
+
 static u8 vppmod_load = W9968CF_VPPMOD_LOAD;
 static u8 simcams = W9968CF_SIMCAMS;
-static int video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /* -1=first free */
+static s8 video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /* -1=first free */
 static u16 packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_PACKET_SIZE};
 static u8 max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BUFFERS};
 static u8 double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
@@ -74,10 +76,10 @@
 static u8 lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LIGHTFREQ};
 static u8 bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
                              W9968CF_BANDINGFILTER};
-static int clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
+static s8 clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
 static u8 backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
 static u8 mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
-static u8 sensor_mono[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_SENSOR_MONO};
+static u8 monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
 static u16 brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BRIGHTNESS};
 static u16 hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
 static u16 colour[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
@@ -88,36 +90,27 @@
 static u8 specific_debug = W9968CF_SPECIFIC_DEBUG;
 #endif
 
-MODULE_AUTHOR("Luca Risolia <luca_ing@libero.it>");
-
-MODULE_DESCRIPTION("Video4Linux driver for "
-                   "W996[87]CF JPEG USB Dual Mode Camera Chip");
-
-MODULE_SUPPORTED_DEVICE("Video");
-
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(vppmod_load, "i");
+MODULE_PARM(vppmod_load, "b");
 MODULE_PARM(simcams, "i");
 MODULE_PARM(video_nr, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
 MODULE_PARM(packet_size, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
 MODULE_PARM(max_buffers, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
-MODULE_PARM(double_buffer, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
-MODULE_PARM(clamping, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(double_buffer, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
+MODULE_PARM(clamping, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
 MODULE_PARM(filter_type, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
-MODULE_PARM(largeview, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(largeview, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
 MODULE_PARM(decompression, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
-MODULE_PARM(upscaling, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(upscaling, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
 MODULE_PARM(force_palette, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
 MODULE_PARM(force_rgb, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
-MODULE_PARM(autobright, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
-MODULE_PARM(autoexp, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
-MODULE_PARM(lightfreq, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
-MODULE_PARM(bandingfilter, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
-MODULE_PARM(clockdiv, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
-MODULE_PARM(backlight, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
-MODULE_PARM(mirror, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
-MODULE_PARM(sensor_mono, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(autobright, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
+MODULE_PARM(autoexp, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
+MODULE_PARM(lightfreq, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(bandingfilter, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
+MODULE_PARM(clockdiv, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(backlight, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
+MODULE_PARM(mirror, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
+MODULE_PARM(monochrome, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b");
 MODULE_PARM(brightness, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
 MODULE_PARM(hue, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
 MODULE_PARM(colour, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
@@ -125,7 +118,7 @@
 MODULE_PARM(whiteness, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
 #ifdef W9968CF_DEBUG
 MODULE_PARM(debug, "i");
-MODULE_PARM(specific_debug, "i");
+MODULE_PARM(specific_debug, "b");
 #endif
 
 MODULE_PARM_DESC(vppmod_load, 
@@ -163,7 +156,7 @@
                  "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
                  "\n");
 MODULE_PARM_DESC(max_buffers,
-                 "\n<n[,...]> Only for advanced users."
+                 "\n<n[,...]> For advanced users."
                  "\nSpecify the maximum number of video frame buffers"
                  "\nto allocate for each device, from 2 to "
                  __MODULE_STRING(W9968CF_MAX_BUFFERS)
@@ -206,7 +199,8 @@
                  "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
                  " for every device."
                  "\nIf 'w9968cf-vpp' is not loaded, this paramater is"
-                 " set to 0.");
+                 " set to 0."
+                 "\n");
 MODULE_PARM_DESC(decompression,
                  "\n<0|1|2[,...]> Software video decompression:"
                  "\n- 0 disables decompression (doesn't allow formats needing"
@@ -221,7 +215,8 @@
                  "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
                  " for every device."
                  "\nIf 'w9968cf-vpp' is not loaded, forcing decompression is "
-                 "\nnot allowed; in this case this paramater is set to 2.");
+                 "\nnot allowed; in this case this paramater is set to 2."
+                 "\n");
 MODULE_PARM_DESC(force_palette,
                  "\n<0"
                  "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
@@ -255,7 +250,8 @@
                  "\nInitial palette is "
                  __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
                  "\nIf 'w9968cf-vpp' is not loaded, this paramater is"
-                 " set to 9 (UYVY).");
+                 " set to 9 (UYVY)."
+                 "\n");
 MODULE_PARM_DESC(force_rgb, 
                  "\n<0|1[,...]> Read RGB video data instead of BGR:"
                  "\n 1 = use RGB component ordering."
@@ -314,10 +310,11 @@
                  "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
                  " for every device."
                  "\n");
-MODULE_PARM_DESC(sensor_mono,
-                 "\n<0|1[,...]> The OV CMOS sensor is monochrome:"
+MODULE_PARM_DESC(monochrome,
+                 "\n<0|1[,...]> Use OV CMOS sensor as monochrome sensor:"
                  "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_SENSOR_MONO)
+                 "\nNot all the sensors support monochrome color."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
                  " for every device."
                  "\n");
 MODULE_PARM_DESC(brightness, 
@@ -349,7 +346,7 @@
 #ifdef W9968CF_DEBUG
 MODULE_PARM_DESC(debug,
                  "\n<n> Debugging information level, from 0 to 6:"
-                 "\n0 = none (be cautious)"
+                 "\n0 = none (use carefully)"
                  "\n1 = critical errors"
                  "\n2 = significant informations"
                  "\n3 = configuration or general messages"
@@ -383,29 +380,23 @@
 static int w9968cf_release(struct inode*, struct file*);
 static ssize_t w9968cf_read(struct file*, char*, size_t, loff_t*);
 static int w9968cf_mmap(struct file*, struct vm_area_struct*);
-static int w9968cf_ioctl(struct inode*, struct file*,
-                         unsigned int, unsigned long);
-static int w9968cf_do_ioctl(struct w9968cf_device*, unsigned int, void*);
+static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);
+static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, void*);
 
-/* /proc interface */
 #if defined(CONFIG_VIDEO_PROC_FS)
+/* /proc interface */
 static void w9968cf_proc_create(void);
 static void w9968cf_proc_destroy(void);
 static void w9968cf_proc_create_dev(struct w9968cf_device*);
 static void w9968cf_proc_destroy_dev(struct w9968cf_device*);
 static int w9968cf_proc_read_global(char*, char**, off_t, int, int*, void*);
 static int w9968cf_proc_read_dev(char*, char**, off_t, int, int*, void*);
-#else
-static inline void w9968cf_proc_create(void) {}
-static inline void w9968cf_proc_destroy(void) {}
-static inline void w9968cf_proc_create_dev(struct w9968cf_device* cam) {}
-static inline void w9968cf_proc_destroy_dev(struct w9968cf_device* cam) {}
 #endif
 
 /* USB-specific */
-static void w9968cf_urb_complete(struct urb *urb);
 static int w9968cf_start_transfer(struct w9968cf_device*);
 static int w9968cf_stop_transfer(struct w9968cf_device*);
+static void w9968cf_urb_complete(struct urb *urb);
 static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
 static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
 static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
@@ -413,7 +404,6 @@
 static int w9968cf_read_sb(struct w9968cf_device*);
 static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
 
-
 /* Low-level I2C (SMBus) I/O */
 static int w9968cf_smbus_start(struct w9968cf_device*);
 static int w9968cf_smbus_stop(struct w9968cf_device*);
@@ -421,6 +411,7 @@
 static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
 static int w9968cf_smbus_write_ack(struct w9968cf_device*);
 static int w9968cf_smbus_read_ack(struct w9968cf_device*);
+static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
 static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
                                       u16 address, u8* value);
 static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, 
@@ -457,12 +448,11 @@
 static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
 static inline int w9968cf_sensor_cmd(struct w9968cf_device*, 
                                      unsigned int cmd, void *arg);
-static void w9968cf_sensor_configure(struct w9968cf_device*);
-static int w9968cf_sensor_change_settings(struct w9968cf_device*);
-static int w9968cf_sensor_get_picture(struct w9968cf_device*, 
-                                      struct video_picture*);
-static int w9968cf_sensor_set_picture(struct w9968cf_device*, 
-                                      struct video_picture pict);
+static int w9968cf_sensor_init(struct w9968cf_device*);
+static int w9968cf_sensor_update_settings(struct w9968cf_device*);
+static int w9968cf_sensor_get_picture(struct w9968cf_device*);
+static int w9968cf_sensor_update_picture(struct w9968cf_device*, 
+                                         struct video_picture pict);
 
 /* Other helper functions */
 static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
@@ -608,8 +598,6 @@
  * Memory management functions                                              *
  ****************************************************************************/
 
-/* Shameless copy from bttv-driver.c */
-
 /* Here we want the physical address of the memory.
    This is used when initializing the contents of the area. */
 static inline unsigned long kvirt_to_pa(unsigned long adr)
@@ -660,7 +648,6 @@
 	}
 	vfree(mem);
 }
-/* End of shameless copy */
 
 
 /*--------------------------------------------------------------------------
@@ -834,7 +821,7 @@
 	list_for_each(ptr, list) {
 		cam = list_entry(ptr, struct w9968cf_device, v4llist);
 		out += sprintf(out,"/dev/video%d       : %s\n", 
-		               cam->v4ldev.minor, symbolic(camlist, cam->id));
+		               cam->v4ldev->minor, symbolic(camlist, cam->id));
 	}
 
 	up(&w9968cf_devlist_sem);
@@ -865,21 +852,18 @@
 	int len;
 	char* out = page;
 
-	static struct video_picture pict; /* it has to be static */
-	static int rc = 0;
-
 	if (down_interruptible(&cam->procfs_sem))
 		return -ERESTARTSYS;
 
 	if (offset == 0)
-		rc = w9968cf_sensor_get_picture(cam, &pict);
+		w9968cf_sensor_get_picture(cam);
 
 	out += sprintf(out,"camera_model      : %s\n",
 	               symbolic(camlist, cam->id));
 	out += sprintf(out,"sensor_model      : %s\n",
 	               symbolic(senlist, cam->sensor));
 	out += sprintf(out,"sensor_monochrome : %s\n",
-	               YES_NO(cam->sensor_mono));
+	               YES_NO(cam->monochrome));
 	if (cam->users)
 		out += sprintf(out,"user_program      : %s\n",cam->command);
 	out += sprintf(out,"packet_size_bytes : %d\n", 
@@ -920,13 +904,11 @@
 	out += sprintf(out,"banding_filter    : %s\n",YES_NO(cam->bandfilt));
 	out += sprintf(out,"back_light        : %s\n",YES_NO(cam->backlight));
 	out += sprintf(out,"mirror            : %s\n",YES_NO(cam->mirror));
-	if (!rc) {
-		out += sprintf(out,"brightness        : %d\n",pict.brightness);
-		out += sprintf(out,"colour            : %d\n",pict.colour);
-		out += sprintf(out,"contrast          : %d\n",pict.contrast);
-		out += sprintf(out,"hue               : %d\n",pict.hue);
-		out += sprintf(out,"whiteness         : %d\n",pict.whiteness);
-	}
+	out += sprintf(out,"brightness        : %d\n",cam->picture.brightness);
+	out += sprintf(out,"colour            : %d\n",cam->picture.colour);
+	out += sprintf(out,"contrast          : %d\n",cam->picture.contrast);
+	out += sprintf(out,"hue               : %d\n",cam->picture.hue);
+	out += sprintf(out,"whiteness         : %d\n",cam->picture.whiteness);
 	out += sprintf(out,"hs_polarity       : %d\n",cam->hs_polarity);
 	out += sprintf(out,"vs_polarity       : %d\n",cam->vs_polarity);
 #ifdef W9968CF_DEBUG
@@ -954,34 +936,40 @@
 
 static void w9968cf_proc_create_dev(struct w9968cf_device* cam)
 {
-	char name[5];
+	char name[6];
 
 	if (!w9968cf_proc_entry)
 		return;
 
 	/* Create per-device readable entry */
-	sprintf(name, "dev%d", cam->v4ldev.minor);
-	cam->proc_dev = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, 
+	sprintf(name, "dev%d", cam->v4ldev->minor);
+	cam->proc_dev = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR,
 	                                       w9968cf_proc_entry,
 	                                       w9968cf_proc_read_dev,
 	                                       (void*)cam);
 	if (!cam->proc_dev)
 		return;
 	cam->proc_dev->owner = THIS_MODULE;
+
+	DBG(2, "Per-device entry /proc/video/w9968cf/dev%d created.",
+	    cam->v4ldev->minor)
 }
 
 
 static void w9968cf_proc_destroy_dev(struct w9968cf_device* cam)
 {
-	char name[5];
+	char name[6];
 
 	if (!cam->proc_dev)
 		return;
 
-	sprintf(name, "dev%d", cam->v4ldev.minor);
+	sprintf(name, "dev%d", cam->v4ldev->minor);
 
 	/* Destroy per-device entry */
 	remove_proc_entry(name, w9968cf_proc_entry);
+
+	DBG(2, "Per-device entry /proc/video/w9968cf/dev%d removed.",
+	    cam->v4ldev->minor)
 }
 
 
@@ -1010,7 +998,7 @@
 	else
 		DBG(2, "Unable to create /proc/video/w9968cf/global")
 
-	DBG(5, "/proc entries successfully created.")
+	DBG(2, "Main entry /proc/video/w9968cf/global created.")
 }
 
 
@@ -1024,7 +1012,7 @@
 
 	remove_proc_entry("w9968cf", video_proc_entry);
 
-	DBG(5, "/proc entries removed.")
+	DBG(2, "Main entry /proc/video/w9968cf/global removed.")
 }
 
 #endif /* CONFIG_VIDEO_PROC_FS */
@@ -1184,14 +1172,12 @@
 	for (i = 0; i < W9968CF_URBS; i++) {
 		urb = usb_alloc_urb(W9968CF_ISO_PACKETS);
 		cam->urb[i] = urb;
-
 		if (!urb) {
 			for (j = 0; j < i; j++)
 				usb_free_urb(cam->urb[j]);
 			DBG(1, "Couldn't allocate the URB structures.")
 			return -ENOMEM;
 		}
-
 		urb->dev = udev;
 		urb->context = (void*)cam;
 		urb->pipe = usb_rcvisocpipe(udev, 1);
@@ -1214,7 +1200,7 @@
 
 	t_size = (w*h*d)/16;
 
-	err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset  everything */
+	err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
 	err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
 
 	/* Transfer size */
@@ -1287,11 +1273,12 @@
 	spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
 
 	for (i = W9968CF_URBS-1; i >= 0; i--)
-		if (cam->urb[i])
+		if (cam->urb[i]) {
 			if (!usb_unlink_urb(cam->urb[i])) {
 				usb_free_urb(cam->urb[i]);
 				cam->urb[i] = NULL;
 			}
+		}
 
 	if (cam->disconnected)
 		goto exit;
@@ -1347,8 +1334,7 @@
 
 	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
 	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-	                      0, index, (void*)buff,
-	                      2, W9968CF_USB_CTRL_TIMEOUT);
+	                      0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
 
 	if (res < 0)
 		DBG(4, "Failed to read a register "
@@ -1360,7 +1346,7 @@
 
 
 /*--------------------------------------------------------------------------
-  Write data to the fast serial bus registers.
+  Write 64-bit data to the fast serial bus registers.
   Return 0 on success, -1 otherwise.
   --------------------------------------------------------------------------*/
 static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
@@ -1373,8 +1359,7 @@
 
 	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
 	                      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-	                      value, 0x06, (void*)data, 6,
-	                      W9968CF_USB_CTRL_TIMEOUT);
+	                      value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
 
 	if (res < 0)
 		DBG(4, "Failed to write the FSB registers "
@@ -1536,6 +1521,22 @@
 }
 
 
+/* This is seems to refresh the communication through the serial bus */
+static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
+{
+	int err = 0, j;
+
+	for (j = 1; j <= 10; j++) {
+		err = w9968cf_write_reg(cam, 0x0020, 0x01);
+		err += w9968cf_write_reg(cam, 0x0000, 0x01);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+
 /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
 static int 
 w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, 
@@ -1544,8 +1545,10 @@
 	u16* data = cam->data_buffer;
 	int err = 0;
 
-	 /* Enable SBUS outputs */
-	err += w9968cf_write_reg(cam, 0x0020, 0x01);
+	err += w9968cf_smbus_refresh_bus(cam);
+
+	/* Enable SBUS outputs */
+	err += w9968cf_write_sb(cam, 0x0020);
 
 	data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
 	data[0] |= (address & 0x40) ? 0x4000 : 0x0;
@@ -1589,7 +1592,7 @@
 	err += w9968cf_write_fsb(cam, data);
 
 	/* Disable SBUS outputs */
-	err += w9968cf_write_reg(cam, 0x0000, 0x01);
+	err += w9968cf_write_sb(cam, 0x0000);
 
 	if (!err)
 		DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
@@ -1626,7 +1629,7 @@
 	err += w9968cf_smbus_read_byte(cam, value);
 	err += w9968cf_smbus_write_ack(cam);
 	err += w9968cf_smbus_stop(cam);
- 
+
 	/* Serial data disable */
 	err += w9968cf_write_sb(cam, 0x0000);
 
@@ -1695,8 +1698,8 @@
                        int size, union i2c_smbus_data *data)
 {
 	struct w9968cf_device* cam = adapter->data;
-	u8 i, j;
-	int rc = 0, err = 0; 
+	u8 i;
+	int err = 0; 
 
 	switch (addr) {
 		case OV6xx0_SID:
@@ -1712,31 +1715,26 @@
 		addr <<= 1;
 
 		if (read_write == I2C_SMBUS_WRITE)
- 			rc = w9968cf_i2c_adap_write_byte(cam, addr, command);
+ 			err = w9968cf_i2c_adap_write_byte(cam, addr, command);
 		else if (read_write == I2C_SMBUS_READ) 
-			rc = w9968cf_i2c_adap_read_byte(cam,addr, &data->byte);
+			err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
 
 	} else if (size == I2C_SMBUS_BYTE_DATA) {
 		addr <<= 1;
 
 		if (read_write == I2C_SMBUS_WRITE)
- 			rc = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
+ 			err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
 			                                  command, data->byte);
 		else if (read_write == I2C_SMBUS_READ) {
 			for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
-				rc = w9968cf_i2c_adap_read_byte_data(cam, addr, 
+				err = w9968cf_i2c_adap_read_byte_data(cam,addr,
 				                         command, &data->byte);
-				if (rc < 0) {
-					/* Work around: this seems to wake up  
-					   the EEPROM from the stall state */
-					for (j = 0; j <= 10; j++) {
-					   err += w9968cf_write_sb(cam,0x0020);
-					   err += w9968cf_write_sb(cam,0x0000);
-					   if (err)
-					   	break;
+				if (err) {
+					if (w9968cf_smbus_refresh_bus(cam)) {
+						err = -EIO;
+						break;
 					}
-				}
-				else
+				} else
 					break;
 			}
 
@@ -1748,11 +1746,7 @@
 		return -EINVAL;
 	}
 
-	/* This works around a bug in the I2C core */
-	if (rc > 0)
-		rc = 0;
-
-	return rc;
+	return err;
 }
 
 
@@ -1768,41 +1762,22 @@
 {
 	struct w9968cf_device* cam = client->adapter->data;
 	const char* clientname = client->name;
-	int id = client->driver->id;
+	int id = client->driver->id, err = 0;
 
 	if (id == I2C_DRIVERID_OVCAMCHIP) {
-		int rc = 0;
-
 		cam->sensor_client = client;
-
-		rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, 
-		                        &cam->sensor_mono);
-		if (rc < 0) {
-			DBG(1, "CMOS sensor initialization failed (rc=%d)",rc);
-			cam->sensor_client = NULL;
-			return rc;
-		}
-
-		if (w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, 
-		                       &cam->sensor) < 0)
-			rc = -EIO;
-		else if (client->addr==OV7xx0_SID || client->addr==OV6xx0_SID)
-			w9968cf_sensor_configure(cam);
-		else
-			rc = -EINVAL;
-
-		if (rc < 0) {
+		err = w9968cf_sensor_init(cam);
+		if (err) {
 			cam->sensor_client = NULL;
-			cam->sensor = CC_UNKNOWN;
-			return rc;
+			return err;
 		}
-	} else	{
-		DBG(4, "Rejected client [%s] with [%s]", 
+	} else {
+		DBG(4, "Rejected client [%s] with driver [%s]", 
 		    clientname, client->driver->name)
-		return -1;
+		return -EINVAL;
 	}
 
-	DBG(2, "I2C attach client [%s] with [%s]",
+	DBG(5, "I2C attach client [%s] with driver [%s]",
 	    clientname, client->driver->name)
 
 	return 0;
@@ -1818,7 +1793,7 @@
 		cam->sensor_client = NULL;
 	}
 
-	DBG(2, "I2C detach [%s]", clientname)
+	DBG(5, "I2C detach client [%s]", clientname)
 
 	return 0;
 }
@@ -1846,7 +1821,7 @@
 
 static int w9968cf_i2c_init(struct w9968cf_device* cam)
 {
-	int rc = 0;
+	int err = 0;
 
 	static struct i2c_algorithm algo = {
 		.name =          "W996[87]CF algorithm",
@@ -1869,15 +1844,15 @@
 	strcpy(cam->i2c_adapter.name, "w9968cf");
 	cam->i2c_adapter.data = cam;
 
-	DBG(6, "Registering I2C bus with kernel...")
+	DBG(6, "Registering I2C adapter with kernel...")
 
-	rc = i2c_add_adapter(&cam->i2c_adapter);
-	if (rc)
-		DBG(5, "Failed to register the I2C bus.")
+	err = i2c_add_adapter(&cam->i2c_adapter);
+	if (err)
+		DBG(1, "Failed to register the I2C adapter.")
 	else
-		DBG(5, "I2C bus registered.")
+		DBG(5, "I2C adapter registered.")
 
-	return rc;
+	return err;
 }
 
 
@@ -1917,7 +1892,7 @@
   --------------------------------------------------------------------------*/
 static int w9968cf_init_chip(struct w9968cf_device* cam)
 {
-	int err = 0, rc = 0;
+	int err = 0;
 
 	err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
 	err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
@@ -1952,22 +1927,11 @@
 	err += w9968cf_set_window(cam, cam->window);
 
 	if (err)
-		goto error;
-
-	rc = w9968cf_sensor_change_settings(cam);
-	if (rc)
-		goto error;
-
-	DBG(5, "Chip successfully initialized.");
-	
-	return 0;
-
-error:
-	DBG(1, "Chip initialization failed.")
-	if (err)
-		return err;
+		DBG(1, "Chip initialization failed.")
 	else
-		return rc;
+		DBG(5, "Chip successfully initialized.")
+
+	return err;
 }
 
 
@@ -1979,7 +1943,7 @@
 w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
 {
 	u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
-	int err = 0, rc = 0;
+	int err = 0;
 
 	/* Make sure we are using a valid depth */
 	pict.depth = w9968cf_valid_depth(pict.palette);
@@ -2040,12 +2004,10 @@
 	else if (cam->filter_type == 2)
 		reg_v |= 0x000c;
 
-	err = w9968cf_write_reg(cam, reg_v, 0x16);
-	if (err)
+	if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
 		goto error;
 
-	rc = w9968cf_sensor_set_picture(cam, pict);
-	if (rc)
+	if ((err = w9968cf_sensor_update_picture(cam, pict)))
 		goto error;
 
 	/* If all went well, update the device data structure */
@@ -2064,10 +2026,7 @@
 
 error:
 	DBG(1, "Failed to change picture settings.")
-	if (err)
-		return err;
-	else 
-		return rc;
+	return err;
 }
 
 
@@ -2082,7 +2041,7 @@
 	u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
 	unsigned long fw, fh;
 	struct ovcamchip_window s_win;
-	int err=0, rc=0;
+	int err = 0;
 
 	/* Work around to avoid FP arithmetics */
 	#define __SC(x) ((x) << 10)
@@ -2126,8 +2085,8 @@
 		ch = h;
 	}
 
-	/* Setup the sensor window */
-	s_win.format = SENSOR_FORMAT;
+	/* Setup the window of the sensor */
+	s_win.format = VIDEO_PALETTE_UYVY;
 	s_win.width = cam->maxwidth;
 	s_win.height = cam->maxheight;
 	s_win.quarter = 0; /* full progressive video */
@@ -2156,7 +2115,7 @@
 				s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
 		}
 
-	/* We have to scale win.x and win.y offsets */	
+	/* We have to scale win.x and win.y offsets */
 	if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
 	     || (cam->vpp_flag & VPP_UPSCALE) ) {
 		ax = __SC(win.x)/fw;
@@ -2187,7 +2146,7 @@
 	y = ay + s_win.y;
 
 	/* Go ! */
-	if ((rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
+	if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
 		goto error;
 
 	err += w9968cf_write_reg(cam, scx + x, 0x10);
@@ -2232,10 +2191,7 @@
 
 error:
 	DBG(1, "Failed to change the capture area size.")
-	if (err)
-		return err;
-	else
-		return rc;
+	return err;
 }
 
 
@@ -2450,173 +2406,192 @@
 w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
 {
 	struct ovcamchip_control ctl;
-	int rc;
+	int err;
 
 	ctl.id = cid;
 	ctl.value = val;
 
-	rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
+	err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
 
-	return rc;
+	return err;
 }
 
+
 static int 
-w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int *val)
+w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
 {
 	struct ovcamchip_control ctl;
-	int rc;
+	int err;
 
 	ctl.id = cid;
 
-	rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
-	if (rc >= 0)
+	err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
+	if (!err)
 		*val = ctl.value;
 
-	return rc;
+	return err;
 }
 
 
 static inline int
-w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void *arg)
+w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
 {
 	struct i2c_client* c = cam->sensor_client;
+	int rc = 0;
 
-	DBG(6, "Executing CMOS sensor command...")
-
-	if (c && c->driver->command)
-		return c->driver->command(cam->sensor_client, cmd, arg);
-	else
+	if (c->driver->command) {
+		rc = c->driver->command(cam->sensor_client, cmd, arg);
+		/* The I2C driver returns -EPERM on non-supported controls */
+		return (rc < 0 && rc != -EPERM) ? rc : 0;
+	} else
 		return -ENODEV;
 }
 
 
 /*--------------------------------------------------------------------------
-  Change some settings of the CMOS sensor.
-  Returns: 0 for success, a negative number otherwise.
+  Update some settings of the CMOS sensor.
+  Returns: 0 on success, a negative number otherwise.
   --------------------------------------------------------------------------*/
-static int w9968cf_sensor_change_settings(struct w9968cf_device* cam)
+static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
 {
-	int rc;
+	int err = 0;
 
 	/* Auto brightness */
-	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, 
-	                                cam->auto_brt);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, 
+	                                 cam->auto_brt);
+	if (err)
+		return err;
 
 	/* Auto exposure */
-	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, 
-	                                cam->auto_exp);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, 
+	                                 cam->auto_exp);
+	if (err)
+		return err;
 
 	/* Banding filter */
-	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, 
-	                                cam->bandfilt);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, 
+	                                 cam->bandfilt);
+	if (err)
+		return err;
 
 	/* Light frequency */
-	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
-	                                cam->lightfreq);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
+	                                 cam->lightfreq);
+	if (err)
+		return err;
 
 	/* Back light */
-	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
-	                                cam->backlight);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
+	                                 cam->backlight);
+	if (err)
+		return err;
 
 	/* Mirror */
-	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
-	                                cam->mirror);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
+	                                 cam->mirror);
+	if (err)
+		return err;
 
 	return 0;
 }
 
 
 /*--------------------------------------------------------------------------
-  Get some current picture settings from the CMOS sensor.
-  Returns: 0 for success, a negative number otherwise.
+  Get some current picture settings from the CMOS sensor and update the
+  internal 'picture' structure of the camera.
+  Returns: 0 on success, a negative number otherwise.
   --------------------------------------------------------------------------*/
-static int
-w9968cf_sensor_get_picture(struct w9968cf_device* cam, 
-                           struct video_picture* pict)
+static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
 {
-	int rc, v;
+	int err, v;
 
-	/* Don't return error if a setting is unsupported, or rest of settings
-	   will not be performed */
+	err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
+	if (err)
+		return err;
+	cam->picture.contrast = v;
 
-	rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
-	pict->contrast = v;
-
-	rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
-	pict->brightness = v;
-
-	rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
-	pict->colour = v;
-
-	rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
-	pict->hue = v;
+	err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
+	if (err)
+		return err;
+	cam->picture.brightness = v;
 
-	pict->whiteness = W9968CF_WHITENESS; /* to do! */
+	err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
+	if (err)
+		return err;
+	cam->picture.colour = v;
+
+	err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
+	if (err)
+		return err;
+	cam->picture.hue = v;
 
 	DBG(5, "Got picture settings from the CMOS sensor.")
 
 	PDBGG("Brightness, contrast, hue, colour, whiteness are "
-	      "%d,%d,%d,%d,%d.", pict->brightness, pict->contrast,
-	      pict->hue, pict->colour, pict->whiteness)
+	      "%d,%d,%d,%d,%d.", cam->picture.brightness,cam->picture.contrast,
+	      cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
 
 	return 0;
 }
 
 
 /*--------------------------------------------------------------------------
-  Change picture settings of the CMOS sensor.
-  Returns: 0 for success, a negative number otherwise.
+  Update picture settings of the CMOS sensor.
+  Returns: 0 on success, a negative number otherwise.
   --------------------------------------------------------------------------*/
 static int
-w9968cf_sensor_set_picture(struct w9968cf_device* cam, 
-                           struct video_picture pict)
+w9968cf_sensor_update_picture(struct w9968cf_device* cam, 
+                              struct video_picture pict)
 {
-	int rc;
-
-	rc = w9968cf_sensor_set_control(cam,OVCAMCHIP_CID_CONT, pict.contrast);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	int err = 0;
 
-	if (!cam->auto_brt) {
-		rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, 
-	                                        pict.brightness);
-		if (SENSOR_FATAL_ERROR(rc))
-			return rc;
+	if ((!cam->sensor_initialized)
+	    || pict.contrast != cam->picture.contrast) {
+		err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
+		                                 pict.contrast);
+		if (err)
+			goto fail;
+		DBG(4, "Contrast changed from %d to %d.",
+		    cam->picture.contrast, pict.contrast)
+		cam->picture.contrast = pict.contrast;
 	}
 
-	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, pict.colour);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	if (((!cam->sensor_initialized) || 
+	    pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
+		err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, 
+		                                 pict.brightness);
+		if (err)
+			goto fail;
+		DBG(4, "Brightness changed from %d to %d.",
+		    cam->picture.brightness, pict.brightness)
+		cam->picture.brightness = pict.brightness;
+	}
 
-	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, pict.hue);
-	if (SENSOR_FATAL_ERROR(rc))
-		return rc;
+	if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
+		err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, 
+		                                 pict.colour);
+		if (err)
+			goto fail;
+		DBG(4, "Colour changed from %d to %d.",
+		    cam->picture.colour, pict.colour)
+		cam->picture.colour = pict.colour;
+	}
 
-	PDBGG("Brightness, contrast, hue, colour, whiteness are "
-	      "%d,%d,%d,%d,%d.", pict.brightness, pict.contrast,
-	      pict.hue, pict.colour, pict.whiteness)
+	if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
+		err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, 
+		                                 pict.hue);
+		if (err)
+			goto fail;
+		DBG(4, "Hue changed from %d to %d.",
+		    cam->picture.hue, pict.hue)
+		cam->picture.hue = pict.hue;
+	}
 
 	return 0;
+
+fail:
+	DBG(4, "Failed to change sensor picture setting.")
+	return err;
 }
 
 
@@ -2626,12 +2601,22 @@
  ****************************************************************************/
 
 /*--------------------------------------------------------------------------
-  This function is called when the CMOS sensor is detected.
+  This function is called when a supported CMOS sensor is detected.
+  Return 0 if the initialization succeeds, a negative number otherwise.
   --------------------------------------------------------------------------*/
-static void w9968cf_sensor_configure(struct w9968cf_device* cam)
+static int w9968cf_sensor_init(struct w9968cf_device* cam)
 {
-	/* NOTE: Make sure width and height are a multiple of 16 */
+	int err = 0;
+
+	if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, 
+	                              &cam->monochrome)))
+		goto error;
 
+	if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, 
+	                              &cam->sensor)))
+		goto error;
+
+	/* NOTE: Make sure width and height are a multiple of 16 */
 	switch (cam->sensor_client->addr) {
 		case OV6xx0_SID:
 			cam->maxwidth = 352;
@@ -2645,6 +2630,10 @@
 			cam->minwidth = 64;
 			cam->minheight = 48;
 			break;
+		default:
+			DBG(1, "Not supported CMOS sensor detected for %s.",
+			    symbolic(camlist, cam->id))
+			return -EINVAL;
 	}
 
 	/* These values depend on the ones in the ovxxx0.c sources */
@@ -2663,7 +2652,24 @@
 			cam->hs_polarity = 0;
 	}
 
-	DBG(5, "CMOS sensor %s configured.", symbolic(senlist, cam->sensor))
+	if ((err = w9968cf_sensor_update_settings(cam)))
+		goto error;
+
+	if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
+		goto error;
+
+	cam->sensor_initialized = 1;
+
+	DBG(2, "%s CMOS sensor initialized.", symbolic(senlist, cam->sensor))
+	return 0;
+
+error:
+	cam->sensor_initialized = 0;
+	cam->sensor = CC_UNKNOWN;
+	DBG(1, "CMOS sensor initialization failed for %s (/dev/video%d). "
+	       "Try to detach and attach this device again.",
+	    symbolic(camlist, cam->id), cam->v4ldev->minor)
+	return err;
 }
 
 
@@ -2678,7 +2684,7 @@
                          enum w9968cf_model_id mod_id,
                          const unsigned short dev_nr)
 {
-#if defined(CONFIG_VIDEO_PROC_FS)
+#ifdef CONFIG_VIDEO_PROC_FS
 	init_MUTEX(&cam->procfs_sem);
 #endif
 	init_MUTEX(&cam->fileop_sem);
@@ -2691,13 +2697,7 @@
 	cam->usbdev = udev;
 	cam->id = mod_id;
 	cam->sensor = CC_UNKNOWN;
-
-	strcpy(cam->v4ldev.name, symbolic(camlist, mod_id));
-	cam->v4ldev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-	cam->v4ldev.hardware = VID_HARDWARE_W9968CF;
-	cam->v4ldev.fops = &w9968cf_fops;
-	cam->v4ldev.priv = (void*)cam;
-	cam->v4ldev.minor = video_nr[dev_nr];
+	cam->sensor_initialized = 0;
 
 	/* Calculate the alternate setting number (from 1 to 16)
 	   according to the 'packet_size' module parameter */
@@ -2709,66 +2709,66 @@
 
 	cam->max_buffers = (max_buffers[dev_nr] < 2 || 
 	                    max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
-	                   ? W9968CF_BUFFERS : max_buffers[dev_nr];
+	                   ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
 
 	cam->double_buffer = (double_buffer[dev_nr] == 0 || 
 	                      double_buffer[dev_nr] == 1)
-	                     ? double_buffer[dev_nr] : W9968CF_DOUBLE_BUFFER;
+	                     ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
 
 	cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
-	                ? clamping[dev_nr] : W9968CF_CLAMPING;
+	                ? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
 	
 	cam->filter_type = (filter_type[dev_nr] == 0 ||
 	                    filter_type[dev_nr] == 1 ||
 	                    filter_type[dev_nr] == 2)
-	                   ? filter_type[dev_nr] : W9968CF_FILTER_TYPE;
+	                   ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
 
 	cam->capture = 1;
 
 	cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
-	                 ? largeview[dev_nr] : W9968CF_LARGEVIEW;
+	                 ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
 
 	cam->decompression = (decompression[dev_nr] == 0 || 
 	                      decompression[dev_nr] == 1 ||
 	                      decompression[dev_nr] == 2)
-	                     ? decompression[dev_nr] : W9968CF_DECOMPRESSION;
+	                     ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
 
 	cam->upscaling = (upscaling[dev_nr] == 0 || 
 	                  upscaling[dev_nr] == 1)
-	                 ? upscaling[dev_nr] : W9968CF_UPSCALING;
+	                 ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
 
 	cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
-	                ? autobright[dev_nr] : W9968CF_AUTOBRIGHT;
+	                ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
 
 	cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
-	                ? autoexp[dev_nr] : W9968CF_AUTOEXP;
+	                ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
 
 	cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
-	                 ? lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
+	                 ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
 
 	cam->bandfilt = (bandingfilter[dev_nr] == 0 || 
 	                 bandingfilter[dev_nr] == 1)
-	                ? bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
+	                ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
 
 	cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
-	                 ? backlight[dev_nr] : W9968CF_BACKLIGHT;
+	                 ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
 
 	cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
-	                ? clockdiv[dev_nr] : W9968CF_CLOCKDIV;
+	                ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
 
 	cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
-	              ? mirror[dev_nr] : W9968CF_MIRROR;
+	              ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
 
-	cam->sensor_mono = (sensor_mono[dev_nr]==0 || sensor_mono[dev_nr]==1)
-	                   ? sensor_mono[dev_nr] : W9968CF_SENSOR_MONO;
+	cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
+	                  ? monochrome[dev_nr] : W9968CF_MONOCHROME;
 
-	cam->picture.brightness = brightness[dev_nr];
-	cam->picture.hue = hue[dev_nr];
-	cam->picture.colour = colour[dev_nr];
-	cam->picture.contrast = contrast[dev_nr];
-	cam->picture.whiteness = whiteness[dev_nr];
-	if (w9968cf_valid_palette(force_palette[dev_nr])) {
-		cam->picture.palette = force_palette[dev_nr];
+	cam->picture.brightness = (u16)brightness[dev_nr];
+	cam->picture.hue = (u16)hue[dev_nr];
+	cam->picture.colour = (u16)colour[dev_nr];
+	cam->picture.contrast = (u16)contrast[dev_nr];
+	cam->picture.whiteness = (u16)whiteness[dev_nr];
+	if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
+		cam->picture.palette = (u16)force_palette[dev_nr];
 		cam->force_palette = 1;
 	} else {
 		cam->force_palette = 0;
@@ -2781,7 +2781,7 @@
 	}
 
 	cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
-	                 ? force_rgb[dev_nr] : W9968CF_FORCE_RGB;
+	                 ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
 
 	cam->window.x = 0;
 	cam->window.y = 0;
@@ -2886,7 +2886,7 @@
 	else
 		DBG(3, "- Clock divisor: %d", cam->clockdiv)
 
-	if (cam->sensor_mono)
+	if (cam->monochrome)
 		DBG(3, "- CMOS sensor used as monochrome.")
 	else
 		DBG(3, "- CMOS sensor not used as monochrome.")
@@ -2902,10 +2902,12 @@
 {
 	down(&w9968cf_devlist_sem);
 
-	DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev.minor)
+	DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
 
+#ifdef CONFIG_VIDEO_PROC_FS
 	w9968cf_proc_destroy_dev(cam);
-	video_unregister_device(&cam->v4ldev);
+#endif
+	video_unregister_device(cam->v4ldev);
 	list_del(&cam->v4llist);
 	i2c_del_adapter(&cam->i2c_adapter);
 	w9968cf_deallocate_memory(cam);
@@ -2925,24 +2927,25 @@
 
 static int w9968cf_open(struct inode* inode, struct file* filp)
 {
-	struct w9968cf_device* cam =
-	  (struct w9968cf_device*)video_devdata(filp)->priv;    
+	struct w9968cf_device* cam;
 	int err;
 
+	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
 	down(&cam->dev_sem);
 
 	if (cam->sensor == CC_UNKNOWN) {
 		DBG(2, "No supported CMOS sensor has been detected by the "
 		       "'ovcamchip' module for the %s (/dev/video%d). Make "
 		       "sure it is loaded *before* the 'w9968cf' module.", 
-		    symbolic(camlist, cam->id),cam->v4ldev.minor)
+		    symbolic(camlist, cam->id), cam->v4ldev->minor)
 		up(&cam->dev_sem);
 		return -ENODEV;
 	}
 
 	if (cam->users) {
 		DBG(2, "%s (/dev/video%d) has been already occupied by '%s'.",
-		    symbolic(camlist, cam->id),cam->v4ldev.minor, cam->command)
+		    symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
 		if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
 			up(&cam->dev_sem);
 			return -EWOULDBLOCK;
@@ -2958,7 +2961,7 @@
 	}
 
 	DBG(5, "Opening the %s, /dev/video%d ...",
-	    symbolic(camlist, cam->id), cam->v4ldev.minor)
+	    symbolic(camlist, cam->id), cam->v4ldev->minor)
 
 	cam->streaming = 0;
 	cam->misconfigured = 0;
@@ -2975,7 +2978,7 @@
 	if ((err = w9968cf_start_transfer(cam)))
 		goto deallocate_memory;
 
-	filp->private_data = (void*)cam;
+	filp->private_data = cam;
 
 	cam->users++;
 	strcpy(cam->command, current->comm);
@@ -2997,8 +3000,9 @@
 
 static int w9968cf_release(struct inode* inode, struct file* filp)
 {
-	struct w9968cf_device* cam = 
-	  (struct w9968cf_device*)video_devdata(filp)->priv;
+	struct w9968cf_device* cam;
+
+	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
 	down(&cam->dev_sem); /* prevent disconnect() to be called */
 
@@ -3026,11 +3030,12 @@
 static ssize_t
 w9968cf_read(struct file* filp, char* buf, size_t count, loff_t* f_pos)
 {
-	struct w9968cf_device* cam =
-	  (struct w9968cf_device*)video_devdata(filp)->priv;
+	struct w9968cf_device* cam;
 	struct w9968cf_frame_t* fr;
 	int err = 0;
 
+	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
 	if (filp->f_flags & O_NONBLOCK)
 		return -EWOULDBLOCK;
 
@@ -3094,9 +3099,8 @@
 
 static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
 {
-	struct w9968cf_device* cam =
-	  (struct w9968cf_device*)video_devdata(filp)->priv;
-
+	struct w9968cf_device* cam = (struct w9968cf_device*)
+	                             video_get_drvdata(video_devdata(filp));
 	unsigned long vsize = vma->vm_end - vma->vm_start,
 	              psize = cam->nbuffers * w9968cf_get_max_bufsize(cam),
 	              start = vma->vm_start,
@@ -3136,10 +3140,11 @@
 w9968cf_ioctl(struct inode* inode, struct file* filp,
               unsigned int cmd, unsigned long arg)
 {
-	struct w9968cf_device* cam =
-	  (struct w9968cf_device*)video_devdata(filp)->priv;
+	struct w9968cf_device* cam;
 	int err;
 
+	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
 	if (down_interruptible(&cam->fileop_sem))
 		return -ERESTARTSYS;
 
@@ -3155,7 +3160,7 @@
 		return -EIO;
 	}
 
-	err = w9968cf_do_ioctl(cam, cmd, (void*)arg);
+	err = w9968cf_v4l_ioctl(inode, filp, cmd, (void* )arg);
 
 	up(&cam->fileop_sem);
 	return err;
@@ -3163,8 +3168,10 @@
 
 
 static int 
-w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
+w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
+                  unsigned int cmd, void* arg)
 {
+	struct w9968cf_device* cam;
 	const char* v4l1_ioctls[] = {
 		"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", 
 		"GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
@@ -3176,7 +3183,9 @@
 
 	#define V4L1_IOCTL(cmd) \
 	        ((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \
-	        v4l1_ioctls[_IOC_NR((cmd))] : "???")
+	        v4l1_ioctls[_IOC_NR((cmd))] : "?")
+
+	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
 	switch (cmd) {
 
@@ -3190,7 +3199,7 @@
 			.minheight = cam->minheight,
 		};
 		sprintf(cap.name, "W996[87]CF USB Camera #%d", 
-		        cam->v4ldev.minor);
+		        cam->v4ldev->minor);
 		cap.maxwidth = (cam->upscaling && w9968cf_vppmod_present)
 		               ? W9968CF_MAX_WIDTH : cam->maxwidth;
 		cap.maxheight = (cam->upscaling && w9968cf_vppmod_present)
@@ -3241,15 +3250,10 @@
 
 	case VIDIOCGPICT: /* get image properties of the picture */
 	{
-		struct video_picture pict;
-
-		if (w9968cf_sensor_get_picture(cam, &pict))
+		if (w9968cf_sensor_get_picture(cam))
 			return -EIO;
 
-		pict.depth = cam->picture.depth;
-		pict.palette = cam->picture.palette;
-
-		if (copy_to_user(arg, &pict, sizeof(pict)))
+		if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
 			return -EFAULT;
 
 		DBG(5, "VIDIOCGPICT successfully called.")
@@ -3278,13 +3282,6 @@
 			return -EINVAL;
 		}
 
-		if (pict.depth != w9968cf_valid_depth(pict.palette)) {
-			DBG(4, "Depth %d bpp is not supported for %s palette. "
-			       "VIDIOCSPICT failed.", 
-			    pict.depth, symbolic(v4l1_plist, pict.palette))
-			return -EINVAL;
-		}
-
 		if (!cam->force_palette) {
 		   if (cam->decompression == 0) {
 		      if (w9968cf_need_decompression(pict.palette)) {
@@ -3303,9 +3300,15 @@
 		   }
 		}
 
-		if (pict.palette != cam->picture.palette ||
-		    pict.depth   != cam->picture.depth)
-		{
+		if (pict.depth != w9968cf_valid_depth(pict.palette)) {
+			DBG(4, "Requested depth %d bpp is not valid for %s "
+			       "palette: ignored and changed to %d bpp.", 
+			    pict.depth, symbolic(v4l1_plist, pict.palette),
+			    w9968cf_valid_depth(pict.palette))
+			pict.depth = w9968cf_valid_depth(pict.palette);
+		}
+
+		if (pict.palette != cam->picture.palette) {
 			if(*cam->requested_frame
 			   || cam->frame_current->queued) {
 				err = wait_event_interruptible
@@ -3328,15 +3331,9 @@
 			if (w9968cf_start_transfer(cam))
 				goto ioctl_fail;
 
-		} else if ( ((pict.brightness != cam->picture.brightness) &&
-		            (!cam->auto_brt)) ||
-		            pict.hue != cam->picture.hue ||
-		            pict.colour != cam->picture.colour ||
-		            pict.contrast != cam->picture.contrast ||
-		            pict.whiteness != cam->picture.whiteness ) {
-			if (w9968cf_sensor_set_picture(cam, pict))
-				return -EIO;
-		}
+		} else if (w9968cf_sensor_update_picture(cam, pict))
+			return -EIO;
+
 
 		DBG(5, "VIDIOCSPICT successfully called.")
 		return 0;
@@ -3368,7 +3365,6 @@
 		    win.y != cam->window.y ||
 		    win.width != cam->window.width ||
 		    win.height != cam->window.height) {
-
 			if(*cam->requested_frame
 			   || cam->frame_current->queued) {
 				err = wait_event_interruptible
@@ -3479,12 +3475,12 @@
 		   }
 		}
 
-		if (w9968cf_adjust_window_size(cam, (u16*)&mmap.width, 
-		                               (u16*)&mmap.height)) {
+		if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, 
+		                                      (u16*)&mmap.height))) {
 			DBG(4, "Resolution not supported (%dx%d). "
 			       "VIDIOCMCAPTURE failed.",
 			    mmap.width, mmap.height)
-			return -EINVAL;
+			return err;
 		}
 
 		fr = &cam->frame[mmap.frame];
@@ -3599,7 +3595,7 @@
 	case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
 	{
 		struct video_unit unit = {
-			.video = cam->v4ldev.minor,
+			.video = cam->v4ldev->minor,
 			.vbi = VIDEO_NO_UNIT,
 			.radio = VIDEO_NO_UNIT,
 			.audio = VIDEO_NO_UNIT,
@@ -3767,14 +3763,6 @@
 		return NULL;
 	}
 
-	err = usb_set_configuration(udev, 1);
-	err += usb_set_interface(udev, 0, 0);
-
-	if (err) {
-		DBG(1, "Device configuration failed.")
-		return NULL;
-	}
-
 	cam = (struct w9968cf_device*)
 	          kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
 
@@ -3806,10 +3794,24 @@
 	}
 	memset(cam->data_buffer, 0, 8);
 
-	/* Set some basic constants */
-	w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
+	/* Register the V4L device */
+	cam->v4ldev = video_device_alloc();
+	if (!cam->v4ldev) {
+		DBG(1, "Could not allocate memory for a V4L structure.")
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
+	cam->v4ldev->owner = THIS_MODULE;
+	cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+	cam->v4ldev->hardware = VID_HARDWARE_W9968CF;
+	cam->v4ldev->fops = &w9968cf_fops;
+	cam->v4ldev->minor = video_nr[dev_nr];
+	cam->v4ldev->release = video_device_release;
+	video_set_drvdata(cam->v4ldev, cam);
 
-	err = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER,
+	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
 	                            video_nr[dev_nr]);
 	if (err) {
 		DBG(1, "V4L device registration failed.")
@@ -3820,22 +3822,27 @@
 		goto fail;
 	}
 
-	DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev.minor)
+	DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor)
+
+	/* Set some basic constants */
+	w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
 
 	/* Ok, add a new entry into the list of V4L registered devices */
 	down(&w9968cf_devlist_sem);
 	list_add(&cam->v4llist, &w9968cf_dev_list);
 	up(&w9968cf_devlist_sem);
-
 	dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
 	w9968cf_turn_on_led(cam);
 
 	w9968cf_i2c_init(cam);
 
+#ifdef CONFIG_VIDEO_PROC_FS
 	w9968cf_proc_create_dev(cam);
+#endif
 
 	up(&cam->dev_sem);
+
 	return (void*)cam;
 
 fail: /* Free unused memory */
@@ -3844,6 +3851,8 @@
 			kfree(cam->control_buffer);
 		if (cam->data_buffer)
 			kfree(cam->data_buffer);
+		if (cam->v4ldev)
+			video_device_release(cam->v4ldev);
 		up(&cam->dev_sem);
 		kfree(cam);
 	}
@@ -3851,7 +3860,8 @@
 }
 
 
-static void w9968cf_usb_disconnect(struct usb_device* udev, void* drv_context)
+static void
+w9968cf_usb_disconnect(struct usb_device* udev, void* drv_context)
 {
 	struct w9968cf_device* cam = (struct w9968cf_device*)drv_context;
 
@@ -3871,7 +3881,7 @@
 			DBG(2, "The device is open (/dev/video%d)! "
 			       "Process name: %s. Deregistration and memory "
 			       "deallocation are deferred on close.",
-			    cam->v4ldev.minor, cam->command)
+			    cam->v4ldev->minor, cam->command)
 
 			cam->misconfigured = 1;
 
@@ -3956,14 +3966,18 @@
 
 	init_MUTEX(&w9968cf_devlist_sem);
 
+#ifdef CONFIG_VIDEO_PROC_FS
 	w9968cf_proc_create();
+#endif
 
 	w9968cf_vppmod_detect();
 
 	if ((err = usb_register(&w9968cf_usb_driver))) {
 		if (w9968cf_vppmod_present)
 			w9968cf_vppmod_release();
+#ifdef CONFIG_VIDEO_PROC_FS
 		w9968cf_proc_destroy();
+#endif
 		return err;
 	}
 
@@ -3976,7 +3990,9 @@
 	/* w9968cf_usb_disconnect() will be called */
 	usb_deregister(&w9968cf_usb_driver);
 
+#ifdef CONFIG_VIDEO_PROC_FS
 	w9968cf_proc_destroy();	
+#endif
 
 	if (w9968cf_vppmod_present)
 		w9968cf_vppmod_release();
@@ -3987,3 +4003,5 @@
 
 module_init(w9968cf_module_init);
 module_exit(w9968cf_module_exit);
+
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.23-bk11/drivers/usb/w9968cf.h linux-2.4.23-bk12/drivers/usb/w9968cf.h
--- linux-2.4.23-bk11/drivers/usb/w9968cf.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/w9968cf.h	2003-12-16 03:09:16.000000000 -0800
@@ -1,7 +1,7 @@
 /***************************************************************************
  * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
  *                                                                         *
- * Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it>            *
+ * Copyright (C) 2002 2003 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -24,11 +24,14 @@
 #include <linux/videodev.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/proc_fs.h>
+#ifdef CONFIG_VIDEO_PROC_FS
+#	include <linux/proc_fs.h>
+#endif
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/config.h>
+#include <linux/param.h>
 #include <asm/semaphore.h>
 #include <asm/types.h>
 
@@ -106,7 +109,7 @@
 #define W9968CF_LARGEVIEW      1 /* 0 disable, 1 enable */
 #define W9968CF_UPSCALING      0 /* 0 disable, 1 enable */
 
-#define W9968CF_SENSOR_MONO    0 /* 0 not monochrome, 1 monochrome sensor */
+#define W9968CF_MONOCHROME     0 /* 0 not monochrome, 1 monochrome sensor */
 #define W9968CF_BRIGHTNESS     31000 /* from 0 to 65535 */
 #define W9968CF_HUE            32768 /* from 0 to 65535 */
 #define W9968CF_COLOUR         32768 /* from 0 to 65535 */
@@ -130,9 +133,10 @@
 
 #define W9968CF_MODULE_NAME     "V4L driver for W996[87]CF JPEG USB " \
                                 "Dual Mode Camera Chip"
-#define W9968CF_MODULE_VERSION  "v1.22"
+#define W9968CF_MODULE_VERSION  "v1.24-basic"
 #define W9968CF_MODULE_AUTHOR   "(C) 2002 2003 Luca Risolia"
-#define W9968CF_AUTHOR_EMAIL    "<luca_ing@libero.it>"
+#define W9968CF_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
+#define W9968CF_MODULE_LICENSE  "GPL"
 
 static u8 w9968cf_vppmod_present; /* status flag: yes=1, no=0 */
 
@@ -172,6 +176,7 @@
 };
 
 struct w9968cf_frame_t {
+	#define W9968CF_HW_BUF_SIZE 640*480*2 /* buf.size of original frames */
 	void* buffer;
 	u32 length;
 	enum w9968cf_frame_status status;
@@ -195,8 +200,8 @@
 struct w9968cf_device {
 	enum w9968cf_model_id id;   /* private device identifier */
 
-	struct video_device v4ldev; /* V4L structure */
-	struct list_head v4llist;   /* entry of the list of V4L cameras */
+	struct video_device* v4ldev; /* -> V4L structure */
+	struct list_head v4llist;    /* entry of the list of V4L cameras */
 
 	struct usb_device* usbdev;           /* -> main USB structure */
 	struct urb* urb[W9968CF_URBS];       /* -> USB request block structs */
@@ -208,9 +213,9 @@
 	struct w9968cf_frame_t frame_tmp;  /* temporary frame */
 	struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
 	struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
-	void* vpp_buffer; /* -> helper buffer for post-processing routines */
+	void* vpp_buffer; /*-> helper buf.for video post-processing routines */
 
-	u8 max_buffers,   /* number of requested buffers */	   
+	u8 max_buffers,   /* number of requested buffers */
 	   force_palette, /* yes=1/no=0 */
 	   force_rgb,     /* read RGB instead of BGR, yes=1, no=0 */
 	   double_buffer, /* hardware double buffering yes=1/no=0 */
@@ -221,15 +226,17 @@
 	   decompression, /* 0=disabled, 1=forced, 2=allowed */
 	   upscaling;     /* software image scaling, 0=enabled, 1=disabled */
 
-	struct video_picture picture; /* current window settings */
-	struct video_window window;   /* current picture settings */
+	struct video_picture picture; /* current picture settings */
+	struct video_window window;   /* current window settings */
 
 	u16 hw_depth,    /* depth (used by the chip) */
 	    hw_palette,  /* palette (used by the chip) */
 	    hw_width,    /* width (used by the chip) */
 	    hw_height,   /* height (used by the chip) */
 	    hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-	    vs_polarity; /* 0=negative sync pulse, 1=positive sync pulse */
+	    vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
+	    start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
+	    start_cropy; /* pixels from VS incative edge to 1st cropped pixel*/
 
 	enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
 
@@ -240,16 +247,15 @@
 	   users,         /* flag: number of users holding the device */
 	   streaming;     /* flag: yes=1, no=0 */
 
-	int sensor; /* type of image CMOS sensor chip (CC_*) */
-
-	/* Determined by CMOS sensor type */
-	u16 maxwidth,
-	    maxheight,
-	    minwidth,
-	    minheight,
-	    start_cropx,
-	    start_cropy;
+	u8 sensor_initialized; /* flag: yes=1, no=0 */
 
+	/* Determined by CMOS sensor type: */
+	int sensor,       /* type of image sensor chip (CC_*) */
+	    monochrome;   /* CMOS sensor is (probably) monochrome */
+	u16 maxwidth,     /* maximum width supported by the CMOS sensor */
+	    maxheight,    /* maximum height supported by the CMOS sensor */
+	    minwidth,     /* minimum width supported by the CMOS sensor */
+	    minheight;    /* minimum height supported by the CMOS sensor */
 	u8  auto_brt,     /* auto brightness enabled flag */
 	    auto_exp,     /* auto exposure enabled flag */
 	    backlight,    /* backlight exposure algorithm flag */
@@ -257,21 +263,20 @@
 	    lightfreq,    /* power (lighting) frequency */
 	    bandfilt;     /* banding filter enabled flag */
 	s8  clockdiv;     /* clock divisor */
-	int sensor_mono;  /* CMOS sensor is (probably) monochrome */
 
 	/* I2C interface to kernel */
 	struct i2c_adapter i2c_adapter;
 	struct i2c_client* sensor_client;
 
-#if defined(CONFIG_VIDEO_PROC_FS)
+#ifdef CONFIG_VIDEO_PROC_FS
 	/* /proc entries, relative to /proc/video/w9968cf/ */
-	struct proc_dir_entry *proc_dev;   /* readable per-device entry */
+	struct proc_dir_entry *proc_dev;   /* rw per-device entry */
 #endif
 
 	/* Locks */
 	struct semaphore dev_sem,    /* for probe, disconnect,open and close */
 	                 fileop_sem; /* for read and ioctl */
-#if defined(CONFIG_VIDEO_PROC_FS)
+#ifdef CONFIG_VIDEO_PROC_FS
 	struct semaphore procfs_sem; /* for /proc read/write calls */
 #endif
 	spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
@@ -280,14 +285,9 @@
 	wait_queue_head_t open, wait_queue;
 };
 
-#define W9968CF_HW_BUF_SIZE 640*480*2 /* buf. size for original video frames */
-
-#define SENSOR_FORMAT          VIDEO_PALETTE_UYVY
-#define SENSOR_FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
-
 
 /****************************************************************************
- * Macros and other constants                                               *
+ * Macros for debugging                                                     *
  ****************************************************************************/
 
 #undef DBG
@@ -303,7 +303,7 @@
 	else if ((level) == 4) \
 		warn(fmt, ## args); \
 	else if ((level) >= 5) \
-		info("[%s,%d] " fmt, \
+		info("[%s:%d] " fmt, \
 		     __PRETTY_FUNCTION__, __LINE__ , ## args); \
 } \
 }
@@ -314,7 +314,7 @@
 
 #undef PDBG
 #undef PDBGG
-#define PDBG(fmt, args...) info("[%s, %d] "fmt, \
+#define PDBG(fmt, args...) info("[%s:%d] "fmt, \
 	                        __PRETTY_FUNCTION__, __LINE__ , ## args);
 #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
 
diff -urN linux-2.4.23-bk11/drivers/usb/w9968cf_decoder.h linux-2.4.23-bk12/drivers/usb/w9968cf_decoder.h
--- linux-2.4.23-bk11/drivers/usb/w9968cf_decoder.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/w9968cf_decoder.h	2003-12-16 03:09:16.000000000 -0800
@@ -1,7 +1,7 @@
 /***************************************************************************
  * Video decoder for the W996[87]CF driver for Linux.                      *
  *                                                                         *
- * Copyright (C) 2003 by Luca Risolia <luca_ing@libero.it>                 *
+ * Copyright (C) 2003 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
diff -urN linux-2.4.23-bk11/drivers/usb/w9968cf_externaldef.h linux-2.4.23-bk12/drivers/usb/w9968cf_externaldef.h
--- linux-2.4.23-bk11/drivers/usb/w9968cf_externaldef.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk12/drivers/usb/w9968cf_externaldef.h	2003-12-16 03:09:16.000000000 -0800
@@ -1,8 +1,9 @@
 /***************************************************************************
- * Various definitions for compatibility with external modules.            *
+ * Various definitions for compatibility with OVCAMCHIP external module.   *
  * This file is part of the W996[87]CF driver for Linux.                   *
  *                                                                         *
- * Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it>            *
+ * The definitions have been taken from the OVCAMCHIP module written by    *
+ * Mark McClelland.                                                        *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -27,10 +28,8 @@
 #include <asm/ioctl.h>
 #include <asm/types.h>
 
-/* The following values have been copied from the "ovcamchip" module. */
-
 #ifndef I2C_DRIVERID_OVCAMCHIP
-#	define I2C_DRIVERID_OVCAMCHIP	0xf00f
+#	define I2C_DRIVERID_OVCAMCHIP 0xf00f
 #endif
 
 /* Controls */
@@ -77,10 +76,10 @@
 	int width;
 	int height;
 	int format;
-	int quarter;		/* Scale width and height down 2x */
+	int quarter;  /* Scale width and height down 2x */
 
 	/* This stuff will be removed eventually */
-	int clockdiv;		/* Clock divisor setting */
+	int clockdiv; /* Clock divisor setting */
 };
 
 /* Commands. 
diff -urN linux-2.4.23-bk11/include/asm-ppc64/current.h linux-2.4.23-bk12/include/asm-ppc64/current.h
--- linux-2.4.23-bk11/include/asm-ppc64/current.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.23-bk12/include/asm-ppc64/current.h	2003-12-16 03:09:17.000000000 -0800
@@ -1,5 +1,6 @@
 #ifndef _PPC64_CURRENT_H
 #define _PPC64_CURRENT_H
+#include <asm/paca.h>
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -7,9 +8,11 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * Use r13 for current since the ppc64 ABI reserves it - Anton
+ * current is in the paca (processor data area), which is pointed
+ * to by r13.
  */
 
-register struct task_struct *current asm ("r13");
+#define get_current()   ((struct task_struct *)(get_paca()->xCurrent))
+#define current         get_current()
 
 #endif /* !(_PPC64_CURRENT_H) */
diff -urN linux-2.4.23-bk11/include/asm-ppc64/mmu.h linux-2.4.23-bk12/include/asm-ppc64/mmu.h
--- linux-2.4.23-bk11/include/asm-ppc64/mmu.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.23-bk12/include/asm-ppc64/mmu.h	2003-12-16 03:09:17.000000000 -0800
@@ -180,7 +180,7 @@
 extern HTAB htab_data;
 
 #include <linux/cache.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 typedef struct {
 	spinlock_t lock;
 } ____cacheline_aligned hash_table_lock_t;
@@ -191,6 +191,7 @@
 			unsigned long prpn, unsigned hash,
 			void * ptep, unsigned hpteflags,
 			unsigned bolted );
+unsigned long get_lock_slot(unsigned long vpn);
 
 #define PD_SHIFT (10+12)		/* Page directory */
 #define PD_MASK  0x02FF
diff -urN linux-2.4.23-bk11/include/asm-ppc64/paca.h linux-2.4.23-bk12/include/asm-ppc64/paca.h
--- linux-2.4.23-bk11/include/asm-ppc64/paca.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.23-bk12/include/asm-ppc64/paca.h	2003-12-16 03:09:17.000000000 -0800
@@ -45,7 +45,8 @@
 #define MAX_PACAS MAX_PROCESSORS * 2
 
 extern struct paca_struct paca[];
-#define get_paca() ((struct paca_struct *)mfspr(SPRG3))
+register struct paca_struct *local_paca asm("r13");
+#define get_paca()	local_paca
 
 /*============================================================================
  * Name_______:	paca
diff -urN linux-2.4.23-bk11/include/asm-ppc64/ppc32.h linux-2.4.23-bk12/include/asm-ppc64/ppc32.h
--- linux-2.4.23-bk11/include/asm-ppc64/ppc32.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.23-bk12/include/asm-ppc64/ppc32.h	2003-12-16 03:09:17.000000000 -0800
@@ -76,6 +76,13 @@
 	int f_spare[6];
 };
 
+struct ustat32 {
+	__kernel_daddr_t32      f_tfree;
+	__kernel_ino_t32        f_tinode;
+	char                    f_fname[6];
+	char                    f_fpack[6];
+};
+
 typedef union sigval32 {
 	int sival_int;
 	unsigned int sival_ptr;
diff -urN linux-2.4.23-bk11/include/asm-ppc64/ptrace.h linux-2.4.23-bk12/include/asm-ppc64/ptrace.h
--- linux-2.4.23-bk11/include/asm-ppc64/ptrace.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.23-bk12/include/asm-ppc64/ptrace.h	2003-12-16 03:09:17.000000000 -0800
@@ -66,7 +66,11 @@
 
 #define STACK_FRAME_OVERHEAD	112	/* size of minimum stack frame */
 
-/* Size of dummy stack frame allocated when calling signal handler. */
+/*
+ * Size of dummy stack frame allocated when calling signal handler.
+ * These *MUST* be multiples of 16 since the ABI requires stack frames
+ * be quadword aligned.
+ */
 #define __SIGNAL_FRAMESIZE	128
 #define __SIGNAL_FRAMESIZE32	64
 
diff -urN linux-2.4.23-bk11/include/asm-ppc64/serial.h linux-2.4.23-bk12/include/asm-ppc64/serial.h
--- linux-2.4.23-bk11/include/asm-ppc64/serial.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.23-bk12/include/asm-ppc64/serial.h	2003-12-16 03:09:17.000000000 -0800
@@ -26,11 +26,9 @@
 
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
 
 #ifdef CONFIG_SERIAL_MANY_PORTS
@@ -39,7 +37,7 @@
 #define BOCA_FLAGS 0
 #define HUB6_FLAGS 0
 #endif
-	
+
 /*
  * The following define the access methods for the HUB6 card. All
  * access is through two ports for all 24 possible chips. The card is
@@ -60,8 +58,8 @@
 	/* UART CLK   PORT IRQ     FLAGS        */			\
 	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
 	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
-	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
-	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
+	{ 0, BASE_BAUD, 0x898, 0xe, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0x890, 0xf, STD_COM_FLAGS },	/* ttyS3 */
 
 
 #ifdef CONFIG_SERIAL_MANY_PORTS
diff -urN linux-2.4.23-bk11/include/asm-sparc/openprom.h linux-2.4.23-bk12/include/asm-sparc/openprom.h
--- linux-2.4.23-bk11/include/asm-sparc/openprom.h	2000-06-19 17:59:39.000000000 -0700
+++ linux-2.4.23-bk12/include/asm-sparc/openprom.h	2003-12-16 03:09:17.000000000 -0800
@@ -169,6 +169,8 @@
 	int (*v3_cpuresume)(unsigned int whichcpu);
 };
 
+extern struct linux_romvec *romvec;
+
 /* Routines for traversing the prom device tree. */
 struct linux_nodeops {
 	int (*no_nextnode)(int node);
diff -urN linux-2.4.23-bk11/include/asm-sparc/oplib.h linux-2.4.23-bk12/include/asm-sparc/oplib.h
--- linux-2.4.23-bk11/include/asm-sparc/oplib.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.23-bk12/include/asm-sparc/oplib.h	2003-12-16 03:09:17.000000000 -0800
@@ -11,9 +11,6 @@
 #include <asm/openprom.h>
 #include <linux/spinlock.h>
 
-/* The master romvec pointer... */
-extern struct linux_romvec *romvec;
-
 /* Enumeration to describe the prom major version we have detected. */
 enum prom_major_version {
 	PROM_V0,      /* Original sun4c V0 prom */
diff -urN linux-2.4.23-bk11/include/asm-sparc/system.h linux-2.4.23-bk12/include/asm-sparc/system.h
--- linux-2.4.23-bk11/include/asm-sparc/system.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk12/include/asm-sparc/system.h	2003-12-16 03:09:17.000000000 -0800
@@ -10,7 +10,6 @@
 
 #ifdef __KERNEL__
 #include <asm/page.h>
-#include <asm/oplib.h>
 #include <asm/psr.h>
 #include <asm/ptrace.h>
 #include <asm/btfixup.h>
@@ -52,9 +51,6 @@
 extern unsigned long empty_bad_page_table;
 extern unsigned long empty_zero_page;
 
-extern struct linux_romvec *romvec;
-#define halt() romvec->pv_halt()
-
 /* When a context switch happens we must flush all user windows so that
  * the windows of the current process are flushed onto its stack. This
  * way the windows are all clean for the next process and the stack
diff -urN linux-2.4.23-bk11/mm/page_alloc.c linux-2.4.23-bk12/mm/page_alloc.c
--- linux-2.4.23-bk11/mm/page_alloc.c	2003-12-16 03:09:08.000000000 -0800
+++ linux-2.4.23-bk12/mm/page_alloc.c	2003-12-16 03:09:17.000000000 -0800
@@ -378,8 +378,8 @@
 
 	/* here we're in the low on memory slow path */
 
-	if (((current->flags & PF_MEMALLOC) && !in_interrupt()) || 
-			(current->flags & (PF_MEMALLOC | PF_MEMDIE))) {
+	if (((current->flags & PF_MEMALLOC) && 
+			(!in_interrupt() || (current->flags & PF_MEMDIE))) {
 		zone = zonelist->zones;
 		for (;;) {
 			zone_t *z = *(zone++);
