v2.4.10.4 -> v2.4.10.5
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:21:01 +0000 (20:21 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:21:01 +0000 (20:21 -0800)
  - Keith Owens: module exporting error checking
  - Greg KH: USB update
  - Paul Mackerras: clean up wait_init_idle(), ppc prefetch macros
  - Jan Kara: quota fixes
  - Abraham vd Merwe: agpgart support for Intel 830M
  - Jakub Jelinek: ELF loader cleanups
  - Al Viro: more cleanups
  - David Miller: sparc64 fix, netfilter fixes
  - me: tweak resurrected oom handling

99 files changed:
CREDITS
Documentation/Configure.help
Documentation/DocBook/Makefile
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/kernel-hacking.tmpl
Documentation/DocBook/tulip-user.tmpl
Documentation/usb/CREDITS
MAINTAINERS
Makefile
README
arch/i386/kernel/entry.S
arch/i386/kernel/setup.c
arch/mips/au1000/common/serial.c
arch/mips/dec/wbflush.c
arch/parisc/hpux/entry_hpux.S
arch/s390/kernel/entry.S
arch/s390x/kernel/entry.S
arch/sparc64/kernel/head.S
drivers/block/paride/Makefile
drivers/block/paride/bpck6.c
drivers/char/Config.in
drivers/char/agp/agp.h
drivers/char/agp/agpgart_be.c
drivers/media/video/cpia.c
drivers/media/video/cpia_usb.c
drivers/mtd/Config.in
drivers/mtd/chips/Makefile
drivers/mtd/devices/blkmtd.c
drivers/scsi/aic7xxx/aic7xxx_linux.c
drivers/scsi/scsi.c
drivers/scsi/scsi_scan.c
drivers/usb/CDCEther.c
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/acm.c
drivers/usb/audio.c
drivers/usb/hpusbscsi.c [new file with mode: 0644]
drivers/usb/hpusbscsi.h [new file with mode: 0644]
drivers/usb/ibmcam.c
drivers/usb/microtek.c
drivers/usb/uhci.c
drivers/usb/ultracam.c [new file with mode: 0644]
drivers/usb/usb-uhci.c
drivers/usb/usbvideo.h
fs/attr.c
fs/binfmt_elf.c
fs/dquot.c
fs/ext2/balloc.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/namespace.c
fs/nfsd/vfs.c
fs/open.c
fs/super.c
fs/udf/balloc.c
fs/udf/ialloc.c
fs/udf/udfdecl.h
fs/ufs/balloc.c
fs/ufs/ialloc.c
include/asm-alpha/compiler.h
include/asm-alpha/page.h
include/asm-alpha/processor.h
include/asm-alpha/rwsem.h
include/asm-alpha/semaphore.h
include/asm-arm/processor.h
include/asm-cris/processor.h
include/asm-i386/processor.h
include/asm-i386/smp.h
include/asm-ia64/processor.h
include/asm-m68k/processor.h
include/asm-mips/processor.h
include/asm-mips64/processor.h
include/asm-parisc/processor.h
include/asm-ppc/processor.h
include/asm-s390/processor.h
include/asm-s390x/processor.h
include/asm-sh/processor.h
include/asm-sparc/processor.h
include/asm-sparc64/processor.h
include/linux/agp_backend.h
include/linux/dcache.h
include/linux/ext2_fs.h
include/linux/fs.h
include/linux/module.h
include/linux/mount.h
include/linux/pagemap.h
include/linux/quota.h
include/linux/quotaops.h
include/net/route.h
init/main.c
kernel/sched.c
kernel/sysctl.c
mm/oom_kill.c
mm/page_alloc.c
mm/vmscan.c
net/core/dev.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/ipt_mac.c
scripts/kernel-doc

diff --git a/CREDITS b/CREDITS
index e1239f2..4f5c1b0 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -844,7 +844,6 @@ S: Palo Alto, CA 94304
 S: USA
 
 N: Johannes Erdfelt
-E: jerdfelt@valinux.com
 E: johannes@erdfelt.com
 D: Linux/IA-64 bootloader and kernel goop, USB
 S: 6350 Stoneridge Mall Road
index cf019fe..99906c6 100644 (file)
@@ -2575,10 +2575,10 @@ CONFIG_AGP
   module, say M here and read Documentation/modules.txt. The module
   will be called agpgart.o.
 
-Intel 440LX/BX/GX/815/840/850 support
+Intel 440LX/BX/GX/815/830M/840/850 support
 CONFIG_AGP_INTEL
   This option gives you AGP support for the GLX component of the
-  XFree86 4.x on Intel 440LX/BX/GX, 815, 840 and 850 chipsets.
+  XFree86 4.x on Intel 440LX/BX/GX, 815, 830M, 840 and 850 chipsets.
 
   For the moment, you should probably say N, unless you want to test
   the GLX component for XFree86 3.3.6, which can be downloaded from
@@ -2586,9 +2586,9 @@ CONFIG_AGP_INTEL
 
 Intel I810/I810 DC100/I810e support
 CONFIG_AGP_I810
-  This option gives you AGP support for the Xserver on the Intel 810
-  and 815 chipset boards for their on-board integrated graphics. This
-  is required to do any useful video modes with these boards.
+  This option gives you AGP support for the Xserver on the Intel 810,
+  830M and 815 chipset boards for their on-board integrated graphics.
+  This is required to do any useful video modes with these boards.
 
 VIA chipset support
 CONFIG_AGP_VIA
index 1d5e079..f67e775 100644 (file)
@@ -141,17 +141,18 @@ LOG       :=      $(patsubst %.sgml, %.log, $(BOOKS))
 OUT    :=      $(patsubst %.sgml, %.out, $(BOOKS))
 
 clean:
-       -$(RM) core *~
-       -$(RM) $(BOOKS)
-       -$(RM) $(DVI) $(AUX) $(TEX) $(LOG) $(OUT)
-       -$(RM) $(JPG-parportbook) $(EPS-parportbook)
-       -$(RM) $(C-procfs-example)
+       rm -f core *~
+       rm -f $(BOOKS)
+       rm -f $(DVI) $(AUX) $(TEX) $(LOG) $(OUT)
+       rm -f $(JPG-parportbook) $(EPS-parportbook)
+       rm -f $(C-procfs-example)
 
 mrproper: clean
-       -$(RM) $(PS) $(PDF)
-       -$(RM) -r $(HTML)
-       -$(RM) .depend
-       -$(RM) $(TOPDIR)/scripts/mkdep-docbook
+       rm -f $(PS) $(PDF)
+       rm -f -r $(HTML)
+       rm -f .depend
+       rm -f $(TOPDIR)/scripts/mkdep-docbook
+       rm -rf DBTOHTML_OUTPUT*
 
 %.ps : %.sgml
        @(which db2ps > /dev/null 2>&1) || \
@@ -169,7 +170,7 @@ mrproper: clean
        @(which db2html > /dev/null 2>&1) || \
         (echo "*** You need to install DocBook stylesheets ***"; \
          exit 1)
-       -$(RM) -r $@
+       rm -rf $@
        db2html $<
        if [ ! -z "$(JPG-$@)" ]; then cp $(JPG-$@) $@; fi
 
index 26194fc..40bb76f 100644 (file)
 !Edrivers/block/ll_rw_blk.c
   </chapter>
 
-  <chapter id="part">
-     <title>Partition Handling</title>
-!Edrivers/block/genhd.c
-  </chapter>
-
   <chapter id="miscdev">
      <title>Miscellaneous Devices</title>
 !Edrivers/char/misc.c
index 275d784..2ecffd5 100644 (file)
@@ -976,17 +976,35 @@ foo_open (...)
    </para>
   </sect1>
 
-  <sect1 id="sym-exportsymtab">
-   <title><function>EXPORT_SYMTAB</function></title>
+  <sect1 id="sym-exportnosymbols">
+   <title><symbol>EXPORT_NO_SYMBOLS</symbol>
+    <filename class=headerfile>include/linux/module.h</filename></title>
 
    <para>
-    For convenience, a module usually exports all non-file-scope
-    symbols (ie. all those not declared <type>static</type>).  If this
-    is defined before
+    If a module exports no symbols then you can specify
+    <programlisting>
+EXPORT_NO_SYMBOLS;
+    </programlisting>
+    anywhere in the module.
+    In kernel 2.4 and earlier, if a module contains neither
+    <function>EXPORT_SYMBOL()</function> nor
+    <symbol>EXPORT_NO_SYMBOLS</symbol> then the module defaults to
+    exporting all non-static global symbols.
+    In kernel 2.5 onwards you must explicitly specify whether a module
+    exports symbols or not.
+   </para>
+  </sect1>
+
+  <sect1 id="sym-exportsymbols-gpl">
+   <title><function>EXPORT_SYMBOL_GPL()</function>
+    <filename class=headerfile>include/linux/module.h</filename></title>
 
-    <filename class=headerfile>include/linux/module.h</filename> is
-    included, then only symbols explicit exported with
-    <function>EXPORT_SYMBOL()</function> will be exported.
+   <para>
+    Similar to <function>EXPORT_SYMBOL()</function> except that the
+    symbols exported by <function>EXPORT_SYMBOL_GPL()</function> can
+    only be seen by modules with a
+    <function>MODULE_LICENCE()</function> that specifies a GPL
+    compatible license.
    </para>
   </sect1>
  </chapter>
@@ -1241,9 +1259,19 @@ static struct block_device_operations opt_fops = {
      Edit the <filename>Makefile</filename>: the CONFIG variables are
      exported here so you can conditionalize compilation with `ifeq'.
      If your file exports symbols then add the names to
-     <varname>MX_OBJS</varname> or <varname>OX_OBJS</varname> instead
-     of <varname>M_OBJS</varname> or <varname>O_OBJS</varname>, so
-     that genksyms will find them.
+     <varname>export-objs</varname> so that genksyms will find them.
+     <caution>
+      <para>
+       There is a restriction on the kernel build system that objects
+       which export symbols must have globally unique names.
+       If your object does not have a globally unique name then the
+       standard fix is to move the
+       <function>EXPORT_SYMBOL()</function> statements to their own
+       object with a unique name.
+       This is why several systems have separate exporting objects,
+       usually suffixed with ksyms.
+      </para>
+     </caution>
     </para>
    </listitem>
 
index 1109c55..bd7c5c0 100644 (file)
@@ -90,7 +90,7 @@ For 2.4.x and later kernels, the Linux Tulip driver is available at
 
   </chapter>
 
-  <chapter id="drvr_compat">
+  <chapter id="drvr-compat">
     <title>Driver Compatibility</title>
 
 <para>
@@ -111,7 +111,7 @@ increasing in the operational critical path length.
 </para>
   </chapter>
 
-  <chapter id="board_settings">
+  <chapter id="board-settings">
     <title>Board-specific Settings</title>
 
 <para>
@@ -129,7 +129,7 @@ autonegotiation.
 </para>
   </chapter>
 
-  <chapter id="driver_operation">
+  <chapter id="driver-operation">
     <title>Driver Operation</title>
 
 <sect1><title>Ring buffers</title>
index 5eb41a5..ba868a2 100644 (file)
@@ -8,7 +8,7 @@ difficult to maintain, add yourself with a patch if desired.
   David Brownell <dbrownell@users.sourceforge.net>
   Alan Cox <alan@lxorguk.ukuu.org.uk>
   Randy Dunlap <randy.dunlap@intel.com>
-  Johannes Erdfelt <jerdfelt@sventech.com>
+  Johannes Erdfelt <johannes@erdfelt.com>
   Deti Fliegl <deti@fliegl.de>
   ham <ham@unsuave.com>
   Bradley M Keryan <keryan@andrew.cmu.edu>
index 54d7052..f012fb9 100644 (file)
@@ -337,6 +337,12 @@ P: H. Peter Anvin
 M:     hpa@zytor.com
 S:     Maintained
 
+CRAMFS FILESYSTEM
+P:     Daniel Quinlan
+M:     quinlan@transmeta.com
+W:     http://sourceforge.net/projects/cramfs/
+S:     Maintained
+
 CREDITS FILE
 P:     John A. Martin
 M:     jam@acm.org
@@ -1481,7 +1487,6 @@ S:        Supported
 
 USB HUB
 P:     Johannes Erdfelt
-M:     jerdfelt@valinux.com
 M:     johannes@erdfelt.com
 L:     linux-usb-users@lists.sourceforge.net
 L:     linux-usb-devel@lists.sourceforge.net
@@ -1586,7 +1591,6 @@ W:        http://misc.nu/hugh/keyspan/
 
 USB SUBSYSTEM
 P:     Johannes Erdfelt
-M:     jerdfelt@valinux.com
 M:     johannes@erdfelt.com
 L:     linux-usb-users@lists.sourceforge.net
 L:     linux-usb-devel@lists.sourceforge.net
index 1c3dcf1..fb352eb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 11
-EXTRAVERSION =-pre4
+EXTRAVERSION =-pre5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff --git a/README b/README
index d965e46..6b62632 100644 (file)
--- a/README
+++ b/README
@@ -192,11 +192,7 @@ COMPILING the kernel:
    to the place where your regular bootable kernel is found. 
 
    For some, this is on a floppy disk, in which case you can copy the
-   kernel bzImage file to /dev/fd0 to make a bootable floppy. Please note
-   that you can not boot a kernel by directly dumping it to a 720k
-   double-density 3.5" floppy.  In this case, it is highly recommended
-   that you install LILO on your double-density boot floppy or switch to
-   high-density floppies.
+   kernel bzImage file to /dev/fd0 to make a bootable floppy.
 
    If you boot Linux from the hard drive, chances are you use LILO which
    uses the kernel image as specified in the file /etc/lilo.conf.  The
index 3369901..39b4380 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
-#define ASSEMBLY
 #include <asm/smp.h>
 
 EBX            = 0x00
index 63be313..4ffaa2f 100644 (file)
@@ -2416,17 +2416,16 @@ int get_cpuinfo(char * buffer)
        struct cpuinfo_x86 *c = cpu_data;
        int i, n;
 
-       /* 
-        * WARNING - nasty evil hack ... if we print > 8, it overflows the
-        * page buffer and corrupts memory - this needs fixing properly
-        */
-       for (n = 0; n < 8; n++, c++) {
-       /* for (n = 0; n < NR_CPUS; n++, c++) { */
+       for (n = 0; n < NR_CPUS; n++, c++) {
                int fpu_exception;
 #ifdef CONFIG_SMP
                if (!(cpu_online_map & (1<<n)))
                        continue;
 #endif
+               /* Stupid hack */
+               if (p - buffer > (3*PAGE_SIZE)/4)
+                       break;
+
                p += sprintf(p,"processor\t: %d\n"
                        "vendor_id\t: %s\n"
                        "cpu family\t: %d\n"
index cc4a327..439a332 100644 (file)
@@ -68,9 +68,6 @@ static char *serial_revdate = "2001-02-08";
  * End of serial driver configuration section.
  */
 
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
 
 #include <linux/types.h>
index b1f9d32..380aafa 100644 (file)
@@ -103,8 +103,6 @@ static void wbflush_kn03(void)
 {
 }
 
-#ifdef EXPORT_SYMTAB
 #include <linux/module.h>
 
 EXPORT_SYMBOL(__wbflush);
-#endif
index 165aeb6..828599c 100644 (file)
@@ -6,8 +6,6 @@
  */
 
 
-#define ASSEMBLY
-
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/unistd.h>
index 6ed023f..e97338a 100644 (file)
@@ -9,8 +9,6 @@
  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
  */
 
-#define ASSEMBLY
-
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/config.h>
index 740558d..8f4f238 100644 (file)
@@ -9,8 +9,6 @@
  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
  */
 
-#define ASSEMBLY
-
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/config.h>
index 692368e..9148fc8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.81 2001/09/07 23:00:15 kanoj Exp $
+/* $Id: head.S,v 1.82 2001/10/04 23:37:04 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -590,7 +590,8 @@ not_starfire:
 
        ldxa            [%g0] ASI_SAFARI_CONFIG, %g1
        srlx            %g1, 17, %g1
-       and             %g1, 0x3ff, %g1         ! 10bit Safari Agent ID
+       ba,pt           %xcc, set_worklist
+        and            %g1, 0x3ff, %g1         ! 10bit Safari Agent ID
 
 not_cheetah:
        ldxa    [%g0] ASI_UPA_CONFIG, %g1
index 9555263..2eb1f5b 100644 (file)
@@ -7,6 +7,8 @@
 
 L_TARGET := paride.a
 
+export-objs := bpck6.o
+
 obj-$(CONFIG_PARIDE)           += paride.o
 obj-$(CONFIG_PARIDE_PD)                += pd.o
 obj-$(CONFIG_PARIDE_PCD)       += pcd.o
index 8732563..f2febfc 100644 (file)
@@ -25,7 +25,6 @@ int verbose=0; /* set this to 1 to see debugging messages and whatnot */
 
 #define BACKPACK_VERSION "2.0.2"
 
-#define EXPORT_SYMTAB 
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
index eb84013..d4d3a19 100644 (file)
@@ -205,8 +205,8 @@ endmenu
 
 dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
 if [ "$CONFIG_AGP" != "n" ]; then
-   bool '  Intel 440LX/BX/GX and I815/I840/I850 support' CONFIG_AGP_INTEL
-   bool '  Intel I810/I815 (on-board) support' CONFIG_AGP_I810
+   bool '  Intel 440LX/BX/GX and I815/I830M/I840/I850 support' CONFIG_AGP_INTEL
+   bool '  Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
    bool '  VIA chipset support' CONFIG_AGP_VIA
    bool '  AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
    bool '  Generic SiS support' CONFIG_AGP_SIS
index 61e66d7..15c93d6 100644 (file)
@@ -133,6 +133,10 @@ struct agp_bridge_data {
 #define INREG16(mmap, addr)         __raw_readw((mmap)+(addr))
 #define INREG8(mmap, addr)         __raw_readb((mmap)+(addr))
 
+#define KB(x) ((x) * 1024)
+#define MB(x) (KB (KB (x)))
+#define GB(x) (MB (KB (x)))
+
 #define CACHE_FLUSH    agp_bridge.cache_flush
 #define A_SIZE_8(x)    ((aper_size_info_8 *) x)
 #define A_SIZE_16(x)   ((aper_size_info_16 *) x)
@@ -196,6 +200,12 @@ struct agp_bridge_data {
 #ifndef PCI_DEVICE_ID_INTEL_815_1
 #define PCI_DEVICE_ID_INTEL_815_1       0x1132
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_830_M_0
+#define PCI_DEVICE_ID_INTEL_830_M_0     0x3575
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_830_M_1
+#define PCI_DEVICE_ID_INTEL_830_M_1     0x3577
+#endif
 #ifndef PCI_DEVICE_ID_INTEL_82443GX_1
 #define PCI_DEVICE_ID_INTEL_82443GX_1   0x71a1
 #endif
@@ -267,6 +277,22 @@ struct agp_bridge_data {
 #define I810_DRAM_ROW_0        0x00000001
 #define I810_DRAM_ROW_0_SDRAM  0x00000001
 
+/* intel i830 registers */
+#define I830_GMCH_CTRL             0x52
+#define I830_GMCH_ENABLED          0x4
+#define I830_GMCH_MEM_MASK         0x1
+#define I830_GMCH_MEM_64M          0x1
+#define I830_GMCH_MEM_128M         0
+#define I830_GMCH_GMS_MASK         0x70
+#define I830_GMCH_GMS_DISABLED     0x00
+#define I830_GMCH_GMS_LOCAL        0x10
+#define I830_GMCH_GMS_STOLEN_512   0x20
+#define I830_GMCH_GMS_STOLEN_1024  0x30
+#define I830_GMCH_GMS_STOLEN_8192  0x40
+#define I830_RDRAM_CHANNEL_TYPE    0x03010
+#define I830_RDRAM_ND(x)           (((x) & 0x20) >> 5)
+#define I830_RDRAM_DDT(x)          (((x) & 0x18) >> 3)
+
 /* VIA register */
 #define VIA_APBASE      0x10
 #define VIA_GARTCTRL    0x80
index 641395c..7e0f53e 100644 (file)
@@ -1113,6 +1113,290 @@ static int __init intel_i810_setup(struct pci_dev *i810_dev)
        return 0;
 }
 
+static aper_size_info_fixed intel_i830_sizes[] =
+{
+       {128, 32768, 5},
+       /* The 64M mode still requires a 128k gatt */
+       {64, 16384, 5}
+};
+
+static struct _intel_i830_private {
+       struct pci_dev *i830_dev;   /* device one */
+       volatile u8 *registers;
+       int gtt_entries;
+} intel_i830_private;
+
+static void intel_i830_init_gtt_entries(void) {
+       u16 gmch_ctrl;
+       int gtt_entries;
+       u8 rdct;
+       static const int ddt[4] = { 0, 16, 32, 64 };
+
+       pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
+
+       switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+       case I830_GMCH_GMS_STOLEN_512:
+               gtt_entries = KB(512);
+               printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
+               break;
+       case I830_GMCH_GMS_STOLEN_1024:
+               gtt_entries = MB(1);
+               printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
+               break;
+       case I830_GMCH_GMS_STOLEN_8192:
+               gtt_entries = MB(8);
+               printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
+               break;
+       case I830_GMCH_GMS_LOCAL:
+               rdct = INREG8(intel_i830_private.registers,I830_RDRAM_CHANNEL_TYPE);
+               gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]);
+               printk(KERN_INFO PFX "detected %dK local memory.\n",gtt_entries / KB(1));
+               break;
+       default:
+               printk(KERN_INFO PFX "no video memory detected.\n");
+               gtt_entries = 0;
+               break;
+       }
+
+       gtt_entries /= KB(4);
+
+       intel_i830_private.gtt_entries = gtt_entries;
+}
+
+/* The intel i830 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i830_create_gatt_table(void)
+{
+       int page_order;
+       aper_size_info_fixed *size;
+       int num_entries;
+       u32 temp;
+
+       size = agp_bridge.current_size;
+       page_order = size->page_order;
+       num_entries = size->num_entries;
+       agp_bridge.gatt_table_real = 0;
+
+       pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp);
+       temp &= 0xfff80000;
+
+       intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096);
+       if (!intel_i830_private.registers) return (-ENOMEM);
+
+       temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000;
+       CACHE_FLUSH();
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_i830_init_gtt_entries();
+
+       agp_bridge.gatt_table = NULL;
+
+       agp_bridge.gatt_bus_addr = temp;
+
+       return(0);
+}
+
+/* Return the gatt table to a sane state. Use the top of stolen
+ * memory for the GTT.
+ */
+static int intel_i830_free_gatt_table(void)
+{
+       return(0);
+}
+
+static int intel_i830_fetch_size(void)
+{
+       u16 gmch_ctrl;
+       aper_size_info_fixed *values;
+
+       pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
+       values = A_SIZE_FIX(agp_bridge.aperture_sizes);
+
+       if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
+               agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
+               agp_bridge.aperture_size_idx = 0;
+               return(values[0].size);
+       } else {
+               agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
+               agp_bridge.aperture_size_idx = 1;
+               return(values[1].size);
+       }
+
+       return(0);
+}
+
+static int intel_i830_configure(void)
+{
+       aper_size_info_fixed *current_size;
+       u32 temp;
+       u16 gmch_ctrl;
+       int i;
+
+       current_size = A_SIZE_FIX(agp_bridge.current_size);
+
+       pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp);
+       agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+       pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
+       gmch_ctrl |= I830_GMCH_ENABLED;
+       pci_write_config_word(agp_bridge.dev,I830_GMCH_CTRL,gmch_ctrl);
+
+       OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
+       CACHE_FLUSH();
+
+       if (agp_bridge.needs_scratch_page == TRUE)
+               for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
+                       OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
+
+       return (0);
+}
+
+static void intel_i830_cleanup(void)
+{
+       iounmap((void *) intel_i830_private.registers);
+}
+
+static int intel_i830_insert_entries(agp_memory *mem,off_t pg_start,int type)
+{
+       int i,j,num_entries;
+       void *temp;
+
+       temp = agp_bridge.current_size;
+       num_entries = A_SIZE_FIX(temp)->num_entries;
+
+       if (pg_start < intel_i830_private.gtt_entries) {
+               printk (KERN_DEBUG "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n",
+                               pg_start,intel_i830_private.gtt_entries);
+
+               printk ("Trying to insert into local/stolen memory\n");
+               return (-EINVAL);
+       }
+
+       if ((pg_start + mem->page_count) > num_entries)
+               return (-EINVAL);
+
+       /* The i830 can't check the GTT for entries since its read only,
+        * depend on the caller to make the correct offset decisions.
+        */
+
+       if ((type != 0 && type != AGP_PHYS_MEMORY) ||
+               (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
+               return (-EINVAL);
+
+       CACHE_FLUSH();
+
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
+               OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
+
+       CACHE_FLUSH();
+
+       agp_bridge.tlb_flush(mem);
+
+       return(0);
+}
+
+static int intel_i830_remove_entries(agp_memory *mem,off_t pg_start,int type)
+{
+       int i;
+
+       CACHE_FLUSH ();
+
+       if (pg_start < intel_i830_private.gtt_entries) {
+               printk ("Trying to disable local/stolen memory\n");
+               return (-EINVAL);
+       }
+
+       for (i = pg_start; i < (mem->page_count + pg_start); i++)
+               OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
+
+       CACHE_FLUSH();
+
+       agp_bridge.tlb_flush(mem);
+
+       return (0);
+}
+
+static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
+{
+       agp_memory *nw;
+
+       /* always return NULL for now */
+       if (type == AGP_DCACHE_MEMORY) return(NULL);
+
+       if (type == AGP_PHYS_MEMORY) {
+               unsigned long physical;
+
+               /* The i830 requires a physical address to program
+                * it's mouse pointer into hardware. However the
+                * Xserver still writes to it through the agp
+                * aperture
+                */
+
+               if (pg_count != 1) return(NULL);
+
+               nw = agp_create_memory(1);
+
+               if (nw == NULL) return(NULL);
+
+               MOD_INC_USE_COUNT;
+               nw->memory[0] = agp_bridge.agp_alloc_page();
+               physical = nw->memory[0];
+               if (nw->memory[0] == 0) {
+                       /* free this structure */
+                       agp_free_memory(nw);
+                       return(NULL);
+               }
+
+               nw->memory[0] = agp_bridge.mask_memory(virt_to_phys((void *) nw->memory[0]),type);
+               nw->page_count = 1;
+               nw->num_scratch_pages = 1;
+               nw->type = AGP_PHYS_MEMORY;
+               nw->physical = virt_to_phys((void *) physical);
+               return(nw);
+       }
+
+       return(NULL);
+}
+
+static int __init intel_i830_setup(struct pci_dev *i830_dev)
+{
+       intel_i830_private.i830_dev = i830_dev;
+
+       agp_bridge.masks = intel_i810_masks;
+       agp_bridge.num_of_masks = 3;
+       agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
+       agp_bridge.size_type = FIXED_APER_SIZE;
+       agp_bridge.num_aperture_sizes = 2;
+
+       agp_bridge.dev_private_data = (void *) &intel_i830_private;
+       agp_bridge.needs_scratch_page = TRUE;
+
+       agp_bridge.configure = intel_i830_configure;
+       agp_bridge.fetch_size = intel_i830_fetch_size;
+       agp_bridge.cleanup = intel_i830_cleanup;
+       agp_bridge.tlb_flush = intel_i810_tlbflush;
+       agp_bridge.mask_memory = intel_i810_mask_memory;
+       agp_bridge.agp_enable = intel_i810_agp_enable;
+       agp_bridge.cache_flush = global_cache_flush;
+
+       agp_bridge.create_gatt_table = intel_i830_create_gatt_table;
+       agp_bridge.free_gatt_table = intel_i830_free_gatt_table;
+
+       agp_bridge.insert_memory = intel_i830_insert_entries;
+       agp_bridge.remove_memory = intel_i830_remove_entries;
+       agp_bridge.alloc_by_type = intel_i830_alloc_by_type;
+       agp_bridge.free_by_type = intel_i810_free_by_type;
+       agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+       agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
+       agp_bridge.cant_use_aperture = 0;
+
+       return(0);
+}
+
 #endif /* CONFIG_AGP_I810 */
 
 #ifdef CONFIG_AGP_INTEL
@@ -2976,6 +3260,12 @@ static struct {
                "Intel",
                "i815",
                intel_generic_setup },
+       { PCI_DEVICE_ID_INTEL_830_M_0,
+               PCI_VENDOR_ID_INTEL,
+               INTEL_I830_M,
+               "Intel",
+               "i830M",
+               intel_generic_setup },
        { PCI_DEVICE_ID_INTEL_840_0,
                PCI_VENDOR_ID_INTEL,
                INTEL_I840,
@@ -3240,17 +3530,38 @@ static int __init agp_find_supported_device(void)
                                                   PCI_DEVICE_ID_INTEL_815_1,
                                                   NULL);
                        if (i810_dev == NULL) {
-                               printk(KERN_ERR PFX "agpgart: Detected an "
+                               printk(KERN_ERR PFX "Detected an "
                                       "Intel i815, but could not find the"
                                       " secondary device. Assuming a "
                                       "non-integrated video card.\n");
                                break;
                        }
-                       printk(KERN_INFO PFX "agpgart: Detected an Intel i815 "
+                       printk(KERN_INFO PFX "Detected an Intel i815 "
                               "Chipset.\n");
                        agp_bridge.type = INTEL_I810;
                        return intel_i810_setup(i810_dev);
 
+               case PCI_DEVICE_ID_INTEL_830_M_0:
+                       i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+                                                                          PCI_DEVICE_ID_INTEL_830_M_1,
+                                                                          NULL);
+                       if(PCI_FUNC(i810_dev->devfn) != 0) {
+                               i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+                                                                                  PCI_DEVICE_ID_INTEL_830_M_1,
+                                                                                  i810_dev);
+                       }
+
+                       if (i810_dev == NULL) {
+                               printk(KERN_ERR PFX "Detected an "
+                                          "Intel 830M, but could not find the"
+                                          " secondary device.\n");
+                               agp_bridge.type = NOT_SUPPORTED;
+                               return -ENODEV;
+                       }
+                       printk(KERN_INFO PFX "Detected an Intel "
+                                  "830M Chipset.\n");
+                       agp_bridge.type = INTEL_I810;
+                       return intel_i830_setup(i810_dev);
                default:
                        break;
                }
index 92d3c48..e42e874 100644 (file)
@@ -3,9 +3,9 @@
  *
  * Supports CPiA based Video Camera's.
  *
- * (C) Copyright 1999-2000 Peter Pregler,
- * (C) Copyright 1999-2000 Scott J. Bertin,
- * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com
+ * (C) Copyright 1999-2000 Peter Pregler
+ * (C) Copyright 1999-2000 Scott J. Bertin
+ * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@ static int video_nr = -1;
 
 #ifdef MODULE
 MODULE_PARM(video_nr,"i");
-MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
+MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
 MODULE_SUPPORTED_DEVICE("video");
 #endif
index b871b0b..27cea97 100644 (file)
@@ -4,7 +4,7 @@
  * Supports CPiA based parallel port Video Camera's.
  *
  * Copyright (C) 1999        Jochen Scharrlach <Jochen.Scharrlach@schwaben.de>
- * Copyright (C) 1999, 2000  Johannes Erdfelt <jerdfelt@valinux.com>
+ * Copyright (C) 1999, 2000  Johannes Erdfelt <johannes@erdfelt.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index e187bfb..b1c7717 100644 (file)
@@ -1,5 +1,5 @@
 
-# $Id: Config.in,v 1.70 2001/08/11 16:13:38 dwmw2 Exp $
+# $Id: Config.in,v 1.71 2001/10/03 11:38:38 dwmw2 Exp $
 
 mainmenu_option next_comment
 comment 'Memory Technology Devices (MTD)'
@@ -13,8 +13,10 @@ if [ "$CONFIG_MTD" = "y" -o "$CONFIG_MTD" = "m" ]; then
    fi
    dep_tristate '  MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
    dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
+if [ "$CONFIG_ARM" = "y" ]; then
    dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
    dep_tristate '  ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
+fi
 
 comment 'User Modules And Translation Layers'
    dep_tristate '  Direct char device access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
index 8987c24..aea6798 100644 (file)
@@ -1,11 +1,11 @@
 #
 # linux/drivers/chips/Makefile
 #
-# $Id: Makefile,v 1.6 2001/09/02 18:57:01 dwmw2 Exp $
+# $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $
 
 O_TARGET       := chipslink.o
 
-export-objs    := chipreg.o
+export-objs    := chipreg.o gen_probe.o
 
 #                       *** BIG UGLY NOTE ***
 #
index c5b3db1..857753d 100644 (file)
 #include <linux/mtd/compatmac.h>
 #include <linux/mtd/mtd.h>
 
-#if CONFIG_MODVERSION==1
-#define MODVERSIONS
-#include <linux/modversions.h>
-#endif
-
 /* Default erase size in K, always make it a multiple of PAGE_SIZE */
 #define CONFIG_MTD_BLKDEV_ERASESIZE 128
 #define VERSION "1.1"
index 556d51d..e834e46 100644 (file)
@@ -1175,6 +1175,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
        host->irq = ahc->platform_data->irq;
        host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8;
        host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
+       host->max_lun = AHC_NUM_LUNS;
        ahc_set_unit(ahc, ahc_linux_next_unit());
        sprintf(buf, "scsi%d", host->host_no);
        new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
index 9f5de0a..59f04bc 100644 (file)
@@ -629,6 +629,7 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
        if (++serial_number == 0)
                serial_number = 1;
        SCpnt->serial_number = serial_number;
+       SCpnt->pid = scsi_pid++;
 
        /*
         * We will wait MIN_RESET_DELAY clock ticks after the last reset so
@@ -968,6 +969,7 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
 
        ASSERT_LOCK(&io_request_lock, 0);
 
+       SCpnt->pid = scsi_pid++;
        SCpnt->owner = SCSI_OWNER_MIDLEVEL;
 
        SCSI_LOG_MLQUEUE(4,
index c94e8f8..737ed73 100644 (file)
@@ -795,19 +795,7 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
         * other settings, and scan all of them.
         */
        if (bflags & BLIST_SPARSELUN) {
-               /*
-                * Scanning MAX_SCSI_LUNS units would be a bad idea.
-                * Any better idea?
-                * I think we need REPORT LUNS in future to avoid scanning
-                * of unused LUNs. But, that is another item.
-                *
-                * FIXME(eric) - perhaps this should be a kernel configurable?
-                */
-               if (*max_dev_lun < shpnt->max_lun)
-                       *max_dev_lun = shpnt->max_lun;
-               else    if ((max_scsi_luns >> 1) >= *max_dev_lun)
-                               *max_dev_lun += shpnt->max_lun;
-                       else    *max_dev_lun = max_scsi_luns;
+               *max_dev_lun = shpnt->max_lun;
                *sparse_lun = 1;
                return 1;
        }
index d3d75be..f00b3fc 100644 (file)
 
 static const char *version = __FILE__ ": v0.98.5 22 Sep 2001 Brad Hards and another";
 
-/* We need to be selective about what we try to match on, to avoiding loading for a CDC
- * ACM (ISDN or PSTN) modem */
+/* Take any CDC device, and sort it out in probe() */
 static struct usb_device_id CDCEther_ids[] = {
-        { match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
-          bInterfaceClass: USB_CLASS_COMM, bInterfaceSubClass: 6},
-        { } /* Terminating null entry */
+       { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
+       { } /* Terminating null entry */
 };
 
 /* 
index 23b4f53..2299f19 100644 (file)
@@ -59,6 +59,7 @@ comment 'USB Controllers'
    dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
    dep_tristate '  Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
+   dep_tristate '  HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
 
    comment 'USB Multimedia devices'
    dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
index d8ac33f..0d70c16 100644 (file)
@@ -59,7 +59,7 @@ obj-$(CONFIG_USB_SCANNER)     += scanner.o
 obj-$(CONFIG_USB_ACM)          += acm.o
 obj-$(CONFIG_USB_PRINTER)      += printer.o
 obj-$(CONFIG_USB_AUDIO)                += audio.o
-obj-$(CONFIG_USB_IBMCAM)       += ibmcam.o
+obj-$(CONFIG_USB_IBMCAM)       += ibmcam.o usbvideo.o ultracam.o
 obj-$(CONFIG_USB_PWC)          += pwc.o
 obj-$(CONFIG_USB_DC2XX)                += dc2xx.o
 obj-$(CONFIG_USB_MDC800)       += mdc800.o
@@ -74,6 +74,7 @@ obj-$(CONFIG_USB_CDCETHER)    += CDCEther.o
 obj-$(CONFIG_USB_RIO500)       += rio500.o
 obj-$(CONFIG_USB_DSBR)         += dsbr100.o
 obj-$(CONFIG_USB_MICROTEK)     += microtek.o
+obj-$(CONFIG_USB_HPUSBSCSI)    += hpusbscsi.o
 obj-$(CONFIG_USB_BLUETOOTH)    += bluetooth.o
 obj-$(CONFIG_USB_USBNET)       += usbnet.o
 
index b1455e1..882c53a 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * acm.c  Version 0.20
+ * acm.c  Version 0.21
  *
  * Copyright (c) 1999 Armin Fuerst     <fuerst@in.tum.de>
  * Copyright (c) 1999 Pavel Machek     <pavel@suse.cz>
- * Copyright (c) 1999 Johannes Erdfelt <jerdfelt@valinux.com>
+ * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com>
  * Copyright (c) 2000 Vojtech Pavlik   <vojtech@suse.cz>
  *
  * USB Abstract Control Model driver for USB modems and ISDN adapters
@@ -22,7 +22,8 @@
  *     v0.17 - added new style probing
  *     v0.18 - fixed new style probing for devices with more configurations
  *     v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
- *      v0.20 - switched to probing on interface (rather than device) class
+ *     v0.20 - switched to probing on interface (rather than device) class
+ *     v0.21 - revert to probing on device for devices with multiple configs
  */
 
 /*
@@ -60,7 +61,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.20"
+#define DRIVER_VERSION "v0.21"
 #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
 
@@ -648,8 +649,7 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
  */
 
 static struct usb_device_id acm_ids[] = {
-       {match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
-       bInterfaceClass: USB_CLASS_COMM, bInterfaceSubClass: 2},
+       { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
        { }
 };
 
index 114e011..2f9aa3c 100644 (file)
@@ -3,7 +3,7 @@
 /*
  *     audio.c  --  USB Audio Class driver
  *
- *     Copyright (C) 1999, 2000
+ *     Copyright (C) 1999, 2000, 2001
  *         Alan Cox (alan@lxorguk.ukuu.org.uk)
  *         Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
@@ -12,6 +12,8 @@
  *     the Free Software Foundation; either version 2 of the License, or
  *     (at your option) any later version.
  *
+ * Debugging:
+ *     Use the 'lsusb' utility to dump the descriptors.
  *
  * 1999-09-07:  Alan Cox
  *             Parsing Audio descriptor patch
  * 2000-11-26:  Thomas Sailer
  *              Workaround for Dallas DS4201. The DS4201 uses PCM8 as format tag for
  *              its 8 bit modes, but expects signed data (and should therefore have used PCM).
- * 2001-04-08:  gb
- *              Identify version on module load.
- *
+ * 2001-03-10:  Thomas Sailer
+ *              provide abs function, prevent picking up a bogus kernel macro
+ *              for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
+ * 2001-06-16:  Bryce Nesbitt <bryce@obviously.com>
+ *              Fix SNDCTL_DSP_STEREO API violation
  */
 
 /*
 
 #define dprintk(x)
 
+#undef abs
+extern int abs(int __x) __attribute__ ((__const__)); /* Shut up warning */
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -390,6 +397,17 @@ struct usb_audio_state {
 
 /* --------------------------------------------------------------------- */
 
+/* prevent picking up a bogus abs macro */
+#undef abs
+extern inline int abs(int x)
+{
+        if (x < 0)
+               return -x;
+       return x;
+}
+                                
+/* --------------------------------------------------------------------- */
+
 extern inline unsigned ld2(unsigned int x)
 {
        unsigned r = 0;
@@ -485,10 +503,10 @@ static int dmabuf_init(struct dmabuf *db)
        }
        db->bufsize = nr << PAGE_SHIFT;
        db->ready = 1;
-       dprintk((KERN_DEBUG "dmabuf_init: bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
-                "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x\n",
+       dprintk((KERN_DEBUG "usbaudio: dmabuf_init bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
+                "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x srate %d\n",
                 bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
-                db->numfrag, db->dmasize, db->bufsize, db->format));
+                db->numfrag, db->dmasize, db->bufsize, db->format, db->srate));
        return 0;
 }
 
@@ -860,9 +878,11 @@ static int usbin_retire_desc(struct usbin *u, purb_t urb)
                u->dma.count += cnt;
                if (u->format == u->dma.format) {
                        /* we do not need format conversion */
+                       dprintk((KERN_DEBUG "usbaudio: no sample format conversion\n"));
                        dmabuf_copyin(&u->dma, cp, cnt);
                } else {
                        /* we need sampling format conversion */
+                       dprintk((KERN_DEBUG "usbaudio: sample format conversion %x != %x\n", u->format, u->dma.format));
                        usbin_convert(u, cp, scnt);
                }
        }
@@ -1533,7 +1553,7 @@ static int set_format_in(struct usb_audiodev *as)
                d->srate = fmt->sratelo;
        if (d->srate > fmt->sratehi)
                d->srate = fmt->sratehi;
-       dprintk((KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting));
+       dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting));
        if (usb_set_interface(dev, alts->bInterfaceNumber, fmt->altsetting) < 0) {
                printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
                       dev->devnum, u->interface, fmt->altsetting);
@@ -1628,7 +1648,7 @@ static int set_format_out(struct usb_audiodev *as)
                d->srate = fmt->sratelo;
        if (d->srate > fmt->sratehi)
                d->srate = fmt->sratehi;
-       dprintk((KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting));
+       dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting));
        if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
                printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
                       dev->devnum, u->interface, fmt->altsetting);
@@ -1925,13 +1945,6 @@ extern inline int prog_dmabuf_out(struct usb_audiodev *as)
 
 /* --------------------------------------------------------------------- */
 
-static loff_t usb_audio_llseek(struct file *file, loff_t offset, int origin)
-{
-       return -ESPIPE;
-}
-
-/* --------------------------------------------------------------------- */
-
 static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
 {
        int minor = MINOR(inode->i_rdev);
@@ -2071,7 +2084,7 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
 
 static /*const*/ struct file_operations usb_mixer_fops = {
        owner:          THIS_MODULE,
-       llseek:         usb_audio_llseek,
+       llseek:         no_llseek,
        ioctl:          usb_audio_ioctl_mixdev,
        open:           usb_audio_open_mixdev,
        release:        usb_audio_release_mixdev,
@@ -2341,12 +2354,18 @@ static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int
        unsigned long flags;
        audio_buf_info abinfo;
        count_info cinfo;
-       int val, val2, mapped, ret;
+       int val = 0;
+       int val2, mapped, ret;
 
        if (!s->usbdev)
                return -EIO;
        mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) ||
                ((file->f_mode & FMODE_READ) && as->usbin.dma.mapped);
+#if 0
+       if (arg)
+               get_user(val, (int *)arg);
+       printk(KERN_DEBUG "usbaudio: usb_audio_ioctl cmd=%x arg=%lx *arg=%d\n", cmd, arg, val)
+#endif
        switch (cmd) {
        case OSS_GETVERSION:
                return put_user(SOUND_VERSION, (int *)arg);
@@ -2388,8 +2407,14 @@ static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int
                return put_user((file->f_mode & FMODE_READ) ? as->usbin.dma.srate : as->usbout.dma.srate, (int *)arg);
 
        case SNDCTL_DSP_STEREO:
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
                val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-               if (set_format(as, file->f_mode, val2 | AFMT_STEREO, 0))
+               if (val)
+                       val2 |= AFMT_STEREO;
+               else
+                       val2 &= ~AFMT_STEREO;
+               if (set_format(as, file->f_mode, val2, 0))
                        return -EIO;
                return 0;
 
@@ -2590,6 +2615,7 @@ static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int
        case SOUND_PCM_READ_FILTER:
                return -EINVAL;
        }
+       dprintk((KERN_DEBUG "usbaudio: usb_audio_ioctl - no command found\n"));
        return -ENOIOCTLCMD;
 }
 
@@ -2690,7 +2716,7 @@ static int usb_audio_release(struct inode *inode, struct file *file)
 
 static /*const*/ struct file_operations usb_audio_fops = {
        owner:          THIS_MODULE,
-       llseek:         usb_audio_llseek,
+       llseek:         no_llseek,
        read:           usb_audio_read,
        write:          usb_audio_write,
        poll:           usb_audio_poll,
@@ -2815,8 +2841,10 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b
                        if (alts->bInterfaceClass != USB_CLASS_AUDIO || alts->bInterfaceSubClass != 2)
                                continue;
                        if (alts->bNumEndpoints < 1) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
-                                      dev->devnum, asifin, i);
+                               if (i != 0) {  /* altsetting 0 has no endpoints (Section B.3.4.1) */
+                                       printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
+                                              dev->devnum, asifin, i);
+                               }
                                continue;
                        }
                        if ((alts->endpoint[0].bmAttributes & 0x03) != 0x01 ||
@@ -2871,8 +2899,10 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b
                        fp->format = format;
                        fp->altsetting = i;
                        fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
+                       printk(KERN_INFO "usbaudio: valid input sample rate %u\n", fp->sratelo);
                        for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
                                k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
+                               printk(KERN_INFO "usbaudio: valid input sample rate %u\n", k);
                                if (k > fp->sratehi)
                                        fp->sratehi = k;
                                if (k < fp->sratelo)
@@ -2902,6 +2932,7 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b
                                       dev->devnum, asifout, i);
                                continue;
                        }
+                       /* See USB audio formats manual, section 2 */
                        fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifout, i);
                        if (!fmt) {
                                printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
@@ -2951,8 +2982,10 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b
                        fp->format = format;
                        fp->altsetting = i;
                        fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
+                       printk(KERN_INFO "usbaudio: valid output sample rate %u\n", fp->sratelo);
                        for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
                                k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
+                               printk(KERN_INFO "usbaudio: valid output sample rate %u\n", k);
                                if (k > fp->sratehi)
                                        fp->sratehi = k;
                                if (k < fp->sratelo)
@@ -2972,6 +3005,7 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b
                kfree(as);
                return;
        }
+       printk(KERN_INFO "usbaudio: registered dsp 14,%d\n", as->dev_audio);
        /* everything successful */
        list_add_tail(&as->list, &s->audiolist);
 }
@@ -3318,6 +3352,8 @@ static void usb_audio_processingunit(struct consmixstate *state, unsigned char *
        state->chconfig = proc[8+proc[6]] | (proc[9+proc[6]] << 8);
 }
 
+
+/* See Audio Class Spec, section 4.3.2.5 */
 static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr)
 {
        struct mixerchannel *ch;
@@ -3335,7 +3371,7 @@ static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr
        if (state->nrchannels > 2)
                printk(KERN_WARNING "usbaudio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]);
        if (state->nrchannels == 1 && ftr[0] == 7+ftr[5]) {
-               printk(KERN_WARNING "usbaudio: workaround for broken Philips Camera Microphone descriptor enabled\n");
+               printk(KERN_DEBUG "usbaudio: workaround for Philips camera microphone descriptor enabled\n");
                mchftr = ftr[6];
                chftr = 0;
        } else {
@@ -3465,7 +3501,7 @@ static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unit
                usb_audio_selectorunit(state, p1);
                return;
 
-       case FEATURE_UNIT:
+       case FEATURE_UNIT: /* See USB Audio Class Spec 4.3.2.5 */
                if (p1[0] < 7 || p1[0] < 7+p1[5]) {
                        printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
                        return;
@@ -3517,7 +3553,7 @@ static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *b
        state.buflen = buflen;
        state.ctrlif = ctrlif;
        set_bit(oterm[3], &state.unitbitmap);  /* mark terminal ID as visited */
-       printk(KERN_INFO "usbaudio: constructing mixer for Terminal %u type 0x%04x\n",
+       printk(KERN_DEBUG "usbaudio: constructing mixer for Terminal %u type 0x%04x\n",
               oterm[3], oterm[4] | (oterm[5] << 8));
        usb_audio_recurseunit(&state, oterm[7]);
        if (!state.nrmixch) {
@@ -3536,6 +3572,7 @@ static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *b
                kfree(ms);
                return;
        }
+       printk(KERN_INFO "usbaudio: registered mixer 14,%d\n", ms->dev_mixer);
        list_add_tail(&ms->list, &s->mixerlist);
 }
 
@@ -3688,8 +3725,8 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
                return NULL;
        }
        ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8);
-       if (ret<0) {
-               printk(KERN_ERR "usbaudio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum);
+       if (ret < 0) {
+               printk(KERN_ERR "usbaudio: cannot get first 8 bytes of config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret);
                return NULL;
        }
        if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
@@ -3702,7 +3739,7 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
        ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen);
        if (ret < 0) {
                kfree(buffer);
-               printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d\n", i, dev->devnum);
+               printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret);
                return NULL;
        }
        return usb_audio_parsecontrol(dev, buffer, buflen, ifnum);
@@ -3720,11 +3757,11 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
 
        /* we get called with -1 for every audiostreaming interface registered */
        if (s == (struct usb_audio_state *)-1) {
-               dprintk((KERN_DEBUG "usb_audio_disconnect: called with -1\n"));
+               dprintk((KERN_DEBUG "usbaudio: note, usb_audio_disconnect called with -1\n"));
                return;
        }
        if (!s->usbdev) {
-               dprintk((KERN_DEBUG "usb_audio_disconnect: already called for %p!\n", s));
+               dprintk((KERN_DEBUG "usbaudio: error,  usb_audio_disconnect already called for %p!\n", s));
                return;
        }
        down(&open_sem);
@@ -3738,14 +3775,18 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
                usbout_disc(as);
                wake_up(&as->usbin.dma.wait);
                wake_up(&as->usbout.dma.wait);
-               if (as->dev_audio >= 0)
+               if (as->dev_audio >= 0) {
                        unregister_sound_dsp(as->dev_audio);
+                       printk(KERN_INFO "usbaudio: unregister dsp 14,%d\n", as->dev_audio);
+               }
                as->dev_audio = -1;
        }
        for(list = s->mixerlist.next; list != &s->mixerlist; list = list->next) {
                ms = list_entry(list, struct usb_mixerdev, list);
-               if (ms->dev_mixer >= 0)
+               if (ms->dev_mixer >= 0) {
                        unregister_sound_mixer(ms->dev_mixer);
+                       printk(KERN_INFO "usbaudio: unregister mixer 14,%d\n", ms->dev_mixer);
+               }
                ms->dev_mixer = -1;
        }
        release(s);
@@ -3770,4 +3811,5 @@ module_exit(usb_audio_cleanup);
 
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
 
diff --git a/drivers/usb/hpusbscsi.c b/drivers/usb/hpusbscsi.c
new file mode 100644 (file)
index 0000000..fa08c08
--- /dev/null
@@ -0,0 +1,517 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <asm/atomic.h>
+#include <linux/blk.h>
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+
+#include "hpusbscsi.h"
+
+#define DEBUG(x...) \
+       printk( KERN_DEBUG x )
+
+static char *states[]={"FREE", "BEGINNING", "WORKING", "ERROR", "WAIT", "PREMATURE"};
+
+#define TRACE_STATE printk(KERN_DEBUG"hpusbscsi->state = %s at line %d\n", states[hpusbscsi->state], __LINE__)
+
+/* global variables */
+
+struct list_head hpusbscsi_devices;
+//LIST_HEAD(hpusbscsi_devices);
+
+/* USB related parts */
+
+static void *
+hpusbscsi_usb_probe (struct usb_device *dev, unsigned int interface,
+                    const struct usb_device_id *id)
+{
+       struct hpusbscsi *new;
+       struct usb_interface_descriptor *altsetting =
+               &(dev->actconfig->interface[interface].altsetting[0]);
+
+       int i, result;
+
+       /* basic check */
+
+       if (altsetting->bNumEndpoints != 3) {
+               printk (KERN_ERR "Wrong number of endpoints\n");
+               return NULL;
+       }
+
+       /* descriptor allocation */
+
+       new =
+               (struct hpusbscsi *) kmalloc (sizeof (struct hpusbscsi),
+                                             GFP_KERNEL);
+       if (new == NULL)
+               return NULL;
+       DEBUG ("Allocated memory\n");
+       memset (new, 0, sizeof (struct hpusbscsi));
+       spin_lock_init (&new->dataurb.lock);
+       spin_lock_init (&new->controlurb.lock);
+       new->dev = dev;
+       init_waitqueue_head (&new->pending);
+       init_waitqueue_head (&new->deathrow);
+       INIT_LIST_HEAD (&new->lh);
+
+
+
+       /* finding endpoints */
+
+       for (i = 0; i < altsetting->bNumEndpoints; i++) {
+               if (
+                   (altsetting->endpoint[i].
+                    bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                   USB_ENDPOINT_XFER_BULK) {
+                       if (altsetting->endpoint[i].
+                           bEndpointAddress & USB_DIR_IN) {
+                               new->ep_in =
+                                       altsetting->endpoint[i].
+                                       bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                       } else {
+                               new->ep_out =
+                                       altsetting->endpoint[i].
+                                       bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                       }
+               } else {
+                       new->ep_int =
+                               altsetting->endpoint[i].
+                               bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+                       new->interrupt_interval= altsetting->endpoint[i].bInterval;
+               }
+       }
+
+       /* USB initialisation magic for the simple case */
+
+       result = usb_set_interface (dev, altsetting->bInterfaceNumber, 0);
+
+       switch (result) {
+       case 0:         /* no error */
+               break;
+
+       case -EPIPE:
+               usb_clear_halt (dev, usb_sndctrlpipe (dev, 0));
+               break;
+
+       default:
+               printk (KERN_ERR "unknown error %d from usb_set_interface\n",
+                        result);
+               goto err_out;
+       }
+
+       /* making a template for the scsi layer to fake detection of a scsi device */
+
+       memcpy (&(new->ctempl), &hpusbscsi_scsi_host_template,
+               sizeof (hpusbscsi_scsi_host_template));
+       (struct hpusbscsi *) new->ctempl.proc_dir = new;
+       new->ctempl.module = THIS_MODULE;
+
+       if (scsi_register_module (MODULE_SCSI_HA, &(new->ctempl)))
+               goto err_out;
+
+       /* adding to list for module unload */
+       list_add (&hpusbscsi_devices, &new->lh);
+
+       return new;
+
+      err_out:
+       kfree (new);
+       return NULL;
+}
+
+static void
+hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
+{
+                 usb_unlink_urb(&(((struct hpusbscsi *) ptr)->controlurb));
+       ((struct hpusbscsi *) ptr)->dev = NULL;
+}
+
+static struct usb_device_id hpusbscsi_usb_ids[] = {
+       {USB_DEVICE (0x03f0, 0x0701)},  /* HP 53xx */
+       {USB_DEVICE (0x03f0, 0x0801)},  /* HP 7400 */
+       {USB_DEVICE (0x0638, 0x026a)},  /*Scan Dual II */
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, hpusbscsi_usb_ids);
+
+static struct usb_driver hpusbscsi_usb_driver = {
+       name:"hpusbscsi",
+       probe:hpusbscsi_usb_probe,
+       disconnect:hpusbscsi_usb_disconnect,
+       id_table:hpusbscsi_usb_ids,
+};
+
+/* module initialisation */
+
+int __init
+hpusbscsi_init (void)
+{
+       int result;
+
+       INIT_LIST_HEAD (&hpusbscsi_devices);
+       DEBUG ("Driver loaded\n");
+
+       if ((result = usb_register (&hpusbscsi_usb_driver)) < 0) {
+               printk (KERN_ERR "hpusbscsi: driver registration failed\n");
+               return -1;
+       } else {
+               return 0;
+       }
+}
+
+void __exit
+hpusbscsi_exit (void)
+{
+       struct list_head *tmp;
+       struct list_head *old;
+       struct hpusbscsi * o;
+
+       for (tmp = hpusbscsi_devices.next; tmp != &hpusbscsi_devices;/*nothing */) {
+               old = tmp;
+               tmp = tmp->next;
+               o = (struct hpusbscsi *)old;
+               usb_unlink_urb(&o->controlurb);
+               scsi_unregister_module(MODULE_SCSI_HA,&o->ctempl);
+               kfree(old);
+       }
+
+       usb_deregister (&hpusbscsi_usb_driver);
+}
+
+module_init (hpusbscsi_init);
+module_exit (hpusbscsi_exit);
+
+/* interface to the scsi layer */
+
+static int
+hpusbscsi_scsi_detect (struct SHT *sht)
+{
+       /* Whole function stolen from usb-storage */
+
+       struct hpusbscsi *desc = (struct hpusbscsi *) sht->proc_dir;
+       /* What a hideous hack! */
+
+       char local_name[48];
+
+
+       /* set up the name of our subdirectory under /proc/scsi/ */
+       sprintf (local_name, "hpusbscsi-%d", desc->number);
+       sht->proc_name = kmalloc (strlen (local_name) + 1, GFP_KERNEL);
+       /* FIXME: where is this freed ? */
+
+       if (!sht->proc_name) {
+               return 0;
+       }
+
+       strcpy (sht->proc_name, local_name);
+
+       sht->proc_dir = NULL;
+
+       /* build and submit an interrupt URB for status byte handling */
+       FILL_INT_URB(&desc->controlurb,
+                       desc->dev,
+                       usb_rcvintpipe(desc->dev,desc->ep_int),
+                       &desc->scsi_state_byte,
+                       1,
+                       control_interrupt_callback,
+                       desc,
+                       desc->interrupt_interval
+       );
+
+       if ( 0  >  usb_submit_urb(&desc->controlurb)) {
+               kfree(sht->proc_name);
+               return 0;
+       }
+
+       /* In host->hostdata we store a pointer to desc */
+       desc->host = scsi_register (sht, sizeof (desc));
+       if (desc->host == NULL) {
+               kfree (sht->proc_name);
+               usb_unlink_urb(&desc->controlurb);
+               return 0;
+       }
+       desc->host->hostdata[0] = (unsigned long) desc;
+
+
+       return 1;
+}
+
+static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
+{
+       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
+       usb_urb_callback usb_callback;
+       int res;
+
+       hpusbscsi->use_count++;
+
+       /* we don't answer for anything but our single device on any faked host controller */
+       if ( srb->device->lun || srb->device->id || srb->device->channel ) {
+               if (callback) {
+                       srb->result = DID_BAD_TARGET;
+                       callback(srb);
+               }
+                       goto out;
+       }
+
+       /* Now we need to decide which callback to give to the urb we send the command with */
+
+       if (!srb->bufflen) {
+               usb_callback = simple_command_callback;
+       } else {
+               if (srb->use_sg) {
+                       usb_callback = scatter_gather_callback;
+                       hpusbscsi->fragment = 0;
+               } else {
+                       usb_callback = simple_payload_callback;
+               }
+               /* Now we find out which direction data is to be transfered in */
+               hpusbscsi->current_data_pipe = DIRECTION_IS_IN(srb->cmnd[0]) ?
+                       usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in)
+               :
+                       usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out)
+               ;
+       }
+
+
+       TRACE_STATE;
+       if (hpusbscsi->state != HP_STATE_FREE) {
+               printk(KERN_CRIT"hpusbscsi - Ouch: queueing violation!\n");
+               return 1; /* This must not happen */
+       }
+
+        /* We zero the sense buffer to avoid confusing user space */
+        memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+
+       hpusbscsi->state = HP_STATE_BEGINNING;
+       TRACE_STATE;
+
+       /* We prepare the urb for writing out the scsi command */
+       FILL_BULK_URB(
+               &hpusbscsi->dataurb,
+               hpusbscsi->dev,
+               usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
+               srb->cmnd,
+               srb->cmd_len,
+               usb_callback,
+               hpusbscsi
+       );
+       hpusbscsi->scallback = callback;
+       hpusbscsi->srb = srb;
+
+       res = usb_submit_urb(&hpusbscsi->dataurb);
+       if (res) {
+               hpusbscsi->state = HP_STATE_FREE;
+               TRACE_STATE;
+               if (callback) {
+                       srb->result = DID_ERROR;
+                       callback(srb);
+               }
+       }
+
+out:
+       hpusbscsi->use_count--;
+       return 0;
+}
+
+static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb)
+{
+       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
+
+       printk(KERN_DEBUG"SCSI reset requested.\n");
+       usb_reset_device(hpusbscsi->dev);
+       printk(KERN_DEBUG"SCSI reset completed.\n");
+       hpusbscsi->state = HP_STATE_FREE;
+
+       return 0;
+}
+
+static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
+{
+       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
+       printk(KERN_DEBUG"Requested is canceled.\n");
+
+       usb_unlink_urb(&hpusbscsi->dataurb);
+       usb_unlink_urb(&hpusbscsi->controlurb);
+       hpusbscsi->state = HP_STATE_FREE;
+
+       return SCSI_ABORT_PENDING;
+}
+
+/* usb interrupt handlers - they are all running IN INTERRUPT ! */
+
+static void handle_usb_error (struct hpusbscsi *hpusbscsi)
+{
+       if (hpusbscsi->scallback != NULL) {
+               hpusbscsi->srb->result = DID_ERROR;
+               hpusbscsi->scallback(hpusbscsi->srb);
+       }
+       hpusbscsi->state = HP_STATE_FREE;
+}
+
+static void  control_interrupt_callback (struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+
+DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
+       if(u->status < 0) {
+                if (hpusbscsi->state != HP_STATE_FREE)
+                        handle_usb_error(hpusbscsi);
+               return;
+       }
+       hpusbscsi->srb->result &= SCSI_ERR_MASK;
+       hpusbscsi->srb->result |= hpusbscsi->scsi_state_byte<<1;
+
+       if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT)
+               /* we do a callback to the scsi layer if and only if all data has been transfered */
+               hpusbscsi->scallback(hpusbscsi->srb);
+
+       TRACE_STATE;
+       switch (hpusbscsi->state) {
+       case HP_STATE_WAIT:
+               hpusbscsi->state = HP_STATE_FREE;
+       TRACE_STATE;
+               break;
+       case HP_STATE_WORKING:
+       case HP_STATE_BEGINNING:
+               hpusbscsi->state = HP_STATE_PREMATURE;
+       TRACE_STATE;
+               break;
+       default:
+               printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
+       TRACE_STATE;
+               hpusbscsi->state = HP_STATE_FREE;
+       TRACE_STATE;
+               break;
+       }
+}
+
+static void simple_command_callback(struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+       if (u->status<0) {
+               handle_usb_error(hpusbscsi);
+               return;
+        }
+       TRACE_STATE;
+       if (hpusbscsi->state != HP_STATE_PREMATURE) {
+               TRACE_STATE;
+               hpusbscsi->state = HP_STATE_WAIT;
+       } else {
+               if (hpusbscsi->scallback != NULL)
+                       hpusbscsi->scallback(hpusbscsi->srb);
+               hpusbscsi->state = HP_STATE_FREE;
+       TRACE_STATE;
+       }
+}
+
+static void scatter_gather_callback(struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+        struct scatterlist *sg = hpusbscsi->srb->buffer;
+        usb_urb_callback callback;
+        int res;
+
+        DEBUG("Going through scatter/gather\n");
+        if (u->status < 0) {
+                handle_usb_error(hpusbscsi);
+                return;
+        }
+
+        if (hpusbscsi->fragment + 1 != hpusbscsi->srb->use_sg)
+                callback = scatter_gather_callback;
+        else
+                callback = simple_done;
+
+       TRACE_STATE;
+        if (hpusbscsi->state != HP_STATE_PREMATURE)
+               hpusbscsi->state = HP_STATE_WORKING;
+       TRACE_STATE;
+
+        FILL_BULK_URB(
+                u,
+                hpusbscsi->dev,
+                hpusbscsi->current_data_pipe,
+                sg[hpusbscsi->fragment].address,
+                sg[hpusbscsi->fragment++].length,
+                callback,
+                hpusbscsi
+        );
+
+        res = usb_submit_urb(u);
+        if (res)
+                hpusbscsi->state = HP_STATE_ERROR;
+       TRACE_STATE;
+}
+
+static void simple_done (struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+
+        if (u->status < 0) {
+                handle_usb_error(hpusbscsi);
+                return;
+        }
+        DEBUG("Data transfer done\n");
+       TRACE_STATE;
+       if (hpusbscsi->state != HP_STATE_PREMATURE) {
+               if (u->status < 0)
+                       hpusbscsi->state = HP_STATE_ERROR;
+               else
+                       hpusbscsi->state = HP_STATE_WAIT;
+               TRACE_STATE;
+       } else {
+               if (hpusbscsi->scallback != NULL)
+                       hpusbscsi->scallback(hpusbscsi->srb);
+               hpusbscsi->state = HP_STATE_FREE;
+       }
+}
+
+static void simple_payload_callback (struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+       int res;
+
+       if (u->status<0) {
+                handle_usb_error(hpusbscsi);
+               return;
+        }
+
+       FILL_BULK_URB(
+               u,
+               hpusbscsi->dev,
+               hpusbscsi->current_data_pipe,
+               hpusbscsi->srb->buffer,
+               hpusbscsi->srb->bufflen,
+               simple_done,
+               hpusbscsi
+       );
+
+       res = usb_submit_urb(u);
+       if (res) {
+                handle_usb_error(hpusbscsi);
+               return;
+        }
+       TRACE_STATE;
+       if (hpusbscsi->state != HP_STATE_PREMATURE) {
+               hpusbscsi->state = HP_STATE_WORKING;
+       TRACE_STATE;
+       } else {
+               if (hpusbscsi->scallback != NULL)
+                       hpusbscsi->scallback(hpusbscsi->srb);
+               hpusbscsi->state = HP_STATE_FREE;
+       TRACE_STATE;
+       }
+}
+
diff --git a/drivers/usb/hpusbscsi.h b/drivers/usb/hpusbscsi.h
new file mode 100644 (file)
index 0000000..877e698
--- /dev/null
@@ -0,0 +1,88 @@
+/* Header file for the hpusbscsi driver */
+/* (C) Copyright 2001 Oliver Neukum */
+/* sponsored by the Linux Usb Project */
+/* large parts based on or taken from code by John Fremlin and Matt Dharm */
+/* this file is licensed under the GPL */
+
+typedef void (*usb_urb_callback) (struct urb *);
+typedef void (*scsi_callback)(Scsi_Cmnd *);
+
+struct hpusbscsi
+{
+        struct list_head lh;
+        struct usb_device *dev; /* NULL indicates unplugged device */
+        int ep_out;
+        int ep_in;
+        int ep_int;
+        int interrupt_interval;
+
+        struct Scsi_Host *host;
+        Scsi_Host_Template ctempl;
+        int number;
+       scsi_callback scallback;
+       Scsi_Cmnd *srb;
+
+        int use_count;
+        wait_queue_head_t pending;
+        wait_queue_head_t deathrow;
+
+        struct urb dataurb;
+        struct urb controlurb;
+        int fragment;
+
+        int state;
+        int current_data_pipe;
+
+        u8 scsi_state_byte;
+};
+
+#define SCSI_ERR_MASK ~0x3fu
+
+static const unsigned char scsi_command_direction[256/8] = {
+       0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+       0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define DIRECTION_IS_IN(x) ((scsi_command_direction[x>>3] >> (x & 7)) & 1)
+
+static int hpusbscsi_scsi_detect (struct SHT * sht);
+static void simple_command_callback(struct urb *u);
+static void scatter_gather_callback(struct urb *u);
+static void simple_payload_callback (struct urb *u);
+static void  control_interrupt_callback (struct urb *u);
+static void simple_done (struct urb *u);
+static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
+static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
+static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
+
+static Scsi_Host_Template hpusbscsi_scsi_host_template = {
+       name:           "hpusbscsi",
+       detect:         hpusbscsi_scsi_detect,
+//     release:        hpusbscsi_scsi_release,
+       queuecommand:   hpusbscsi_scsi_queuecommand,
+
+       eh_abort_handler:       hpusbscsi_scsi_abort,
+       eh_host_reset_handler:  hpusbscsi_scsi_host_reset,
+
+       sg_tablesize:           SG_ALL,
+       can_queue:              1,
+       this_id:                -1,
+       cmd_per_lun:            1,
+       present:                0,
+       unchecked_isa_dma:      FALSE,
+       use_clustering:         TRUE,
+       use_new_eh_code:        TRUE,
+       emulated:               TRUE
+};
+
+/* defines for internal driver state */
+#define HP_STATE_FREE                 0  /*ready for next request */
+#define HP_STATE_BEGINNING      1  /*command being transfered */
+#define HP_STATE_WORKING         2  /* data transfer stage */
+#define HP_STATE_ERROR             3  /* error has been reported */
+#define HP_STATE_WAIT                 4  /* waiting for status transfer */
+#define HP_STATE_PREMATURE              5 /* status prematurely reported */
+
+
index 822536e..c306115 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
 #include <linux/wrapper.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
 
-#include <asm/io.h>
+#include "usbvideo.h"
 
-#include "ibmcam.h"
+#define        IBMCAM_VENDOR_ID        0x0545
+#define        IBMCAM_PRODUCT_ID       0x8080
+#define NETCAM_PRODUCT_ID      0x8002  /* IBM NetCamera, close to model 2 */
+
+#define MAX_IBMCAM             4       /* How many devices we allow to connect */
+#define USES_IBMCAM_PUTPIXEL    0       /* 0=Fast/oops 1=Slow/secure */
+
+/* Header signatures */
+
+/* Model 1 header: 00 FF 00 xx */
+#define HDRSIG_MODEL1_128x96   0x06    /* U Y V Y ... */
+#define HDRSIG_MODEL1_176x144  0x0e    /* U Y V Y ... */
+#define HDRSIG_MODEL1_352x288  0x00    /* V Y U Y ... */
+
+#define        IBMCAM_MODEL_1  1       /* XVP-501, 3 interfaces, rev. 0.02 */
+#define IBMCAM_MODEL_2 2       /* KSX-X9903, 2 interfaces, rev. 3.0a */
+#define IBMCAM_MODEL_3 3       /* KSX-X9902, 2 interfaces, rev. 3.01 */
+#define        IBMCAM_MODEL_4  4       /* IBM NetCamera, 0545/8002/3.0a */
+
+/* Video sizes supported */
+#define        VIDEOSIZE_128x96        VIDEOSIZE(128, 96)
+#define        VIDEOSIZE_176x144       VIDEOSIZE(176,144)
+#define        VIDEOSIZE_352x288       VIDEOSIZE(352,288)
+#define        VIDEOSIZE_320x240       VIDEOSIZE(320,240)
+#define        VIDEOSIZE_352x240       VIDEOSIZE(352,240)
+#define        VIDEOSIZE_640x480       VIDEOSIZE(640,480)
+#define        VIDEOSIZE_160x120       VIDEOSIZE(160,120)
+
+/* Video sizes supported */
+enum {
+       SIZE_128x96 = 0,
+       SIZE_160x120,
+       SIZE_176x144,
+       SIZE_320x240,
+       SIZE_352x240,
+       SIZE_352x288,
+       SIZE_640x480,
+       /* Add/remove/rearrange items before this line */
+       SIZE_LastItem
+};
 
 /*
- * Version Information
+ * This structure lives in uvd_t->user field.
  */
-#define DRIVER_VERSION "v1.0.0"
-#define DRIVER_AUTHOR "http://www.linux-usb.org/ibmcam/"
-#define DRIVER_DESC "IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000"
+typedef struct {
+       int initialized;        /* Had we already sent init sequence? */
+       int camera_model;       /* What type of IBM camera we got? */
+       int has_hdr;
+} ibmcam_t;
+#define        IBMCAM_T(uvd)   ((ibmcam_t *)((uvd)->user_data))
 
-#define        ENABLE_HEXDUMP  0       /* Enable if you need it */
-static int debug = 0;
+usbvideo_t *cams = NULL;
 
-static int video_nr = -1;
-
-/* Completion states of the data parser */
-typedef enum {
-       scan_Continue,          /* Just parse next item */
-       scan_NextFrame,         /* Frame done, send it to V4L */
-       scan_Out,               /* Not enough data for frame */
-       scan_EndParse           /* End parsing */
-} scan_state_t;
-
-/* Bit flags (options) */
-#define FLAGS_RETRY_VIDIOCSYNC         (1 << 0)
-#define        FLAGS_MONOCHROME                (1 << 1)
-#define FLAGS_DISPLAY_HINTS            (1 << 2)
-#define FLAGS_OVERLAY_STATS            (1 << 3)
-#define FLAGS_FORCE_TESTPATTERN                (1 << 4)
-#define FLAGS_SEPARATE_FRAMES          (1 << 5)
-#define FLAGS_CLEAN_FRAMES             (1 << 6)
+static int debug = 0;
 
 static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
 
-/* This is the size of V4L frame that we provide */
-static const int imgwidth = V4L_FRAME_WIDTH_USED;
-static const int imgheight = V4L_FRAME_HEIGHT;
-static const int min_imgwidth  = 8;
-static const int min_imgheight = 4;
+static const int min_canvasWidth  = 8;
+static const int min_canvasHeight = 4;
 
 static int lighting = 1; /* Medium */
 
@@ -88,27 +101,9 @@ static int sharpness = 4; /* Low noise, good details */
 
 #define FRAMERATE_MIN  0
 #define FRAMERATE_MAX  6
-static int framerate = 2; /* Lower, reliable frame rate (8-12 fps) */
-
-enum {
-       VIDEOSIZE_128x96 = 0,
-       VIDEOSIZE_176x144,
-       VIDEOSIZE_352x288,
-       VIDEOSIZE_320x240,
-       VIDEOSIZE_352x240,
-};
-
-static int videosize = VIDEOSIZE_352x288;
+static int framerate = -1;
 
-/*
- * The value of 'scratchbufsize' affects quality of the picture
- * in many ways. Shorter buffers may cause loss of data when client
- * is too slow. Larger buffers are memory-consuming and take longer
- * to work with. This setting can be adjusted, but the default value
- * should be OK for most desktop users.
- */
-#define DEFAULT_SCRATCH_BUF_SIZE       (0x10000)       /* 64 KB */
-static const int scratchbufsize = DEFAULT_SCRATCH_BUF_SIZE;
+static int size = SIZE_352x288;
 
 /*
  * Here we define several initialization variables. They may
@@ -131,36 +126,37 @@ static int init_hue = 128;
 static int hue_correction = 128;
 
 /* Settings for camera model 2 */
-static int init_model2_rg = -1;
 static int init_model2_rg2 = -1;
 static int init_model2_sat = -1;
 static int init_model2_yb = -1;
 
+/* 01.01.08 - Added for RCA video in support -LO */
+/* Settings for camera model 3 */
+static int init_model3_input = 0;
+
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
 MODULE_PARM(flags, "i");
-MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=seperate frames, 6=clean frames");
+MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames");
 MODULE_PARM(framerate, "i");
 MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
 MODULE_PARM(lighting, "i");
 MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
 MODULE_PARM(sharpness, "i");
 MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
-MODULE_PARM(videosize, "i");
-MODULE_PARM_DESC(videosize, "Image size: 0=128x96, 1=176x144, 2=352x288, 3=320x240, 4=352x240 (default=1)");
+MODULE_PARM(size, "i");
+MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480  (default=5)");
 MODULE_PARM(init_brightness, "i");
 MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
 MODULE_PARM(init_contrast, "i");
 MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
 MODULE_PARM(init_color, "i");
-MODULE_PARM_DESC(init_color, "Dolor preconfiguration: 0-255 (default=128)");
+MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
 MODULE_PARM(init_hue, "i");
 MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
 MODULE_PARM(hue_correction, "i");
 MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
 
-MODULE_PARM(init_model2_rg, "i");
-MODULE_PARM_DESC(init_model2_rg, "Model2 preconfiguration: 0-255 (default=112)");
 MODULE_PARM(init_model2_rg2, "i");
 MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");
 MODULE_PARM(init_model2_sat, "i");
@@ -168,6 +164,14 @@ MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)")
 MODULE_PARM(init_model2_yb, "i");
 MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");
 
+/* 01.01.08 - Added for RCA video in support -LO */
+MODULE_PARM(init_model3_input, "i");
+MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA");
+
+MODULE_AUTHOR ("Dmitri");
+MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
+MODULE_LICENSE("GPL");
+
 /* Still mysterious i2c commands */
 static const unsigned short unknown_88 = 0x0088;
 static const unsigned short unknown_89 = 0x0089;
@@ -182,594 +186,326 @@ static const unsigned short mod2_set_framerate = 0x001c;        /* 0 (fast).. $1F (slow
 static const unsigned short mod2_color_balance_rg2 = 0x001e;   /* 0 (red) .. $7F (green) */
 static const unsigned short mod2_saturation = 0x0020;          /* 0 (b/w) - $7F (full color) */
 static const unsigned short mod2_color_balance_yb = 0x0022;    /* 0..$7F, $50 is about right */
-static const unsigned short mod2_color_balance_rg = 0x0024;    /* 0..$7F, $70 is about right */
+static const unsigned short mod2_hue = 0x0024;                 /* 0..$7F, $70 is about right */
 static const unsigned short mod2_sensitivity = 0x0028;         /* 0 (min) .. $1F (max) */
 
-#define MAX_IBMCAM     4
-
-struct usb_ibmcam cams[MAX_IBMCAM];
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-#define MDEBUG(x)      do { } while(0)         /* Debug memory management */
-
-static struct usb_driver ibmcam_driver;
-static void usb_ibmcam_release(struct usb_ibmcam *ibmcam);
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-       unsigned long ret = 0UL;
-       pmd_t *pmd;
-       pte_t *ptep, pte;
-
-       if (!pgd_none(*pgd)) {
-               pmd = pmd_offset(pgd, adr);
-               if (!pmd_none(*pmd)) {
-                       ptep = pte_offset(pmd, adr);
-                       pte = *ptep;
-                       if (pte_present(pte)) {
-                               ret = (unsigned long) page_address(pte_page(pte));
-                               ret |= (adr & (PAGE_SIZE - 1));
-                       }
-               }
-       }
-       MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-       return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
-       unsigned long kva, ret;
-
-       kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-       ret = virt_to_bus((void *)kva);
-       MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-       return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
-       unsigned long va, kva, ret;
-
-       va = VMALLOC_VMADDR(adr);
-       kva = uvirt_to_kva(pgd_offset_k(va), va);
-       ret = virt_to_bus((void *)kva);
-       MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
-       return ret;
-}
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
-       unsigned long va, kva, ret;
-
-       va = VMALLOC_VMADDR(adr);
-       kva = uvirt_to_kva(pgd_offset_k(va), va);
-       ret = __pa(kva);
-       MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
-       return ret;
-}
-
-static void *rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr, page;
-
-       /* Round it off to PAGE_SIZE */
-       size += (PAGE_SIZE - 1);
-       size &= ~(PAGE_SIZE - 1);
-
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               page = kvirt_to_pa(adr);
-               mem_map_reserve(virt_to_page(__va(page)));
-               adr += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr, page;
-
-       if (!mem)
-               return;
-
-       size += (PAGE_SIZE - 1);
-       size &= ~(PAGE_SIZE - 1);
-
-       adr=(unsigned long) mem;
-       while (size > 0) {
-               page = kvirt_to_pa(adr);
-               mem_map_unreserve(virt_to_page(__va(page)));
-               adr += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-       vfree(mem);
-}
-
-#if ENABLE_HEXDUMP
-static void ibmcam_hexdump(const unsigned char *data, int len)
-{
-       char tmp[80];
-       int i, k;
-
-       for (i=k=0; len > 0; i++, len--) {
-               if (i > 0 && (i%16 == 0)) {
-                       printk("%s\n", tmp);
-                       k=0;
-               }
-               k += sprintf(&tmp[k], "%02x ", data[i]);
-       }
-       if (k > 0)
-               printk("%s\n", tmp);
-}
-#endif
-
-/*
- * usb_ibmcam_overlaychar()
- *
- * History:
- * 1/2/00   Created.
- */
-void usb_ibmcam_overlaychar(
-       struct usb_ibmcam *ibmcam,
-       struct ibmcam_frame *frame,
-       int x, int y, int ch)
-{
-       static const unsigned short digits[16] = {
-               0xF6DE, /* 0 */
-               0x2492, /* 1 */
-               0xE7CE, /* 2 */
-               0xE79E, /* 3 */
-               0xB792, /* 4 */
-               0xF39E, /* 5 */
-               0xF3DE, /* 6 */
-               0xF492, /* 7 */
-               0xF7DE, /* 8 */
-               0xF79E, /* 9 */
-               0x77DA, /* a */
-               0xD75C, /* b */
-               0xF24E, /* c */
-               0xD6DC, /* d */
-               0xF34E, /* e */
-               0xF348  /* f */
-       };
-       unsigned short digit;
-       int ix, iy;
-
-       if ((ibmcam == NULL) || (frame == NULL))
-               return;
-
-       if (ch >= '0' && ch <= '9')
-               ch -= '0';
-       else if (ch >= 'A' && ch <= 'F')
-               ch = 10 + (ch - 'A');
-       else if (ch >= 'a' && ch <= 'f')
-               ch = 10 + (ch - 'a');
-       else
-               return;
-       digit = digits[ch];
-
-       for (iy=0; iy < 5; iy++) {
-               for (ix=0; ix < 3; ix++) {
-                       if (digit & 0x8000) {
-                               IBMCAM_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
-                       }
-                       digit = digit << 1;
-               }
-       }
-}
+struct struct_initData {
+       unsigned char req;
+       unsigned short value;
+       unsigned short index;
+};
 
 /*
- * usb_ibmcam_overlaystring()
+ * ibmcam_size_to_videosize()
  *
- * History:
- * 1/2/00   Created.
+ * This procedure converts module option 'size' into the actual
+ * videosize_t that defines the image size in pixels. We need
+ * simplified 'size' because user wants a simple enumerated list
+ * of choices, not an infinite set of possibilities.
  */
-void usb_ibmcam_overlaystring(
-       struct usb_ibmcam *ibmcam,
-       struct ibmcam_frame *frame,
-       int x, int y, const char *str)
+static videosize_t ibmcam_size_to_videosize(int size)
 {
-       while (*str) {
-               usb_ibmcam_overlaychar(ibmcam, frame, x, y, *str);
-               str++;
-               x += 4; /* 3 pixels character + 1 space */
+       videosize_t vs = VIDEOSIZE_352x288;
+       RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1));
+       switch (size) {
+       case SIZE_128x96:
+               vs = VIDEOSIZE_128x96;
+               break;
+       case SIZE_160x120:
+               vs = VIDEOSIZE_160x120;
+               break;
+       case SIZE_176x144:
+               vs = VIDEOSIZE_176x144;
+               break;
+       case SIZE_320x240:
+               vs = VIDEOSIZE_320x240;
+               break;
+       case SIZE_352x240:
+               vs = VIDEOSIZE_352x240;
+               break;
+       case SIZE_352x288:
+               vs = VIDEOSIZE_352x288;
+               break;
+       case SIZE_640x480:
+               vs = VIDEOSIZE_640x480;
+               break;
+       default:
+               err("size=%d. is not valid", size);
+               break;
        }
+       return vs;
 }
 
 /*
- * usb_ibmcam_overlaystats()
- *
- * Overlays important debugging information.
- *
- * History:
- * 1/2/00   Created.
- */
-void usb_ibmcam_overlaystats(struct usb_ibmcam *ibmcam, struct ibmcam_frame *frame)
-{
-       const int y_diff = 8;
-       char tmp[16];
-       int x = 10;
-       int y = 10;
-
-       sprintf(tmp, "%8x", ibmcam->frame_num);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", ibmcam->urb_count);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", ibmcam->urb_length);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", ibmcam->data_count);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", ibmcam->header_count);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", ibmcam->scratch_ovf_count);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", ibmcam->iso_skip_count);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", ibmcam->iso_err_count);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", ibmcam->vpic.colour);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", ibmcam->vpic.hue);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", ibmcam->vpic.brightness >> 8);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", ibmcam->vpic.contrast >> 12);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8d", ibmcam->vpic.whiteness >> 8);
-       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
-       y += y_diff;
-}
-
-/*
- * usb_ibmcam_testpattern()
+ * ibmcam_find_header()
  *
- * Procedure forms a test pattern (yellow grid on blue background).
- *
- * Parameters:
- * fullframe:   if TRUE then entire frame is filled, otherwise the procedure
- *           continues from the current scanline.
- * pmode       0: fill the frame with solid blue color (like on VCR or TV)
- *           1: Draw a colored grid
+ * Locate one of supported header markers in the queue.
+ * Once found, remove all preceding bytes AND the marker (4 bytes)
+ * from the data pump queue. Whatever follows must be video lines.
  *
  * History:
- * 1/2/00   Created.
+ * 1/21/00  Created.
  */
-void usb_ibmcam_testpattern(struct usb_ibmcam *ibmcam, int fullframe, int pmode)
+static ParseState_t ibmcam_find_header(uvd_t *uvd) /* FIXME: Add frame here */
 {
-       static const char proc[] = "usb_ibmcam_testpattern";
-       struct ibmcam_frame *frame;
-       unsigned char *f;
-       int num_cell = 0;
-       int scan_length = 0;
-       static int num_pass = 0;
-
-       if (ibmcam == NULL) {
-               printk(KERN_ERR "%s: ibmcam == NULL\n", proc);
-               return;
-       }
-       if ((ibmcam->curframe < 0) || (ibmcam->curframe >= IBMCAM_NUMFRAMES)) {
-               printk(KERN_ERR "%s: ibmcam->curframe=%d.\n", proc, ibmcam->curframe);
-               return;
-       }
+       usbvideo_frame_t *frame;
+       ibmcam_t *icam;
 
-       /* Grab the current frame */
-       frame = &ibmcam->frame[ibmcam->curframe];
-
-       /* Optionally start at the beginning */
-       if (fullframe) {
-               frame->curline = 0;
-               frame->scanlength = 0;
+       if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
+               err("ibmcam_find_header: Illegal frame %d.", uvd->curframe);
+               return scan_EndParse;
        }
-
-       /* Form every scan line */
-       for (; frame->curline < imgheight; frame->curline++) {
-               int i;
-
-               f = frame->data + (imgwidth * 3 * frame->curline);
-               for (i=0; i < imgwidth; i++) {
-                       unsigned char cb=0x80;
-                       unsigned char cg = 0;
-                       unsigned char cr = 0;
-
-                       if (pmode == 1) {
-                               if (frame->curline % 32 == 0)
-                                       cb = 0, cg = cr = 0xFF;
-                               else if (i % 32 == 0) {
-                                       if (frame->curline % 32 == 1)
-                                               num_cell++;
-                                       cb = 0, cg = cr = 0xFF;
-                               } else {
-                                       cb = ((num_cell*7) + num_pass) & 0xFF;
-                                       cg = ((num_cell*5) + num_pass*2) & 0xFF;
-                                       cr = ((num_cell*3) + num_pass*3) & 0xFF;
+       icam = IBMCAM_T(uvd);
+       assert(icam != NULL);
+       frame = &uvd->frame[uvd->curframe];
+       icam->has_hdr = 0;
+       switch (icam->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               const int marker_len = 4;
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
+                       {
+#if 0                          /* This code helps to detect new frame markers */
+                               info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3));
+#endif
+                               frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
+                               if ((frame->header == HDRSIG_MODEL1_128x96) ||
+                                   (frame->header == HDRSIG_MODEL1_176x144) ||
+                                   (frame->header == HDRSIG_MODEL1_352x288))
+                               {
+#if 0
+                                       info("Header found.");
+#endif
+                                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                                       icam->has_hdr = 1;
+                                       break;
                                }
-                       } else {
-                               /* Just the blue screen */
                        }
-                               
-                       *f++ = cb;
-                       *f++ = cg;
-                       *f++ = cr;
-                       scan_length += 3;
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
                }
+               break;
        }
-
-       frame->grabstate = FRAME_DONE;
-       frame->scanlength += scan_length;
-       ++num_pass;
-
-       /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
-       usb_ibmcam_overlaystats(ibmcam, frame);
-}
-
-static unsigned char *ibmcam_model1_find_header(unsigned char hdr_sig, unsigned char *data, int len)
-{
-       while (len >= 4)
+       case IBMCAM_MODEL_2:
+case IBMCAM_MODEL_4:
        {
-               if ((data[0] == 0x00) && (data[1] == 0xFF) && (data[2] == 0x00))
-               {
+               int marker_len = 0;
+               switch (uvd->videosize) {
+               case VIDEOSIZE_176x144:
+                       marker_len = 10;
+                       break;
+               default:
+                       marker_len = 2;
+                       break;
+               }
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
+                       {
 #if 0
-                       /* This code helps to detect new frame markers */
-                       printk(KERN_DEBUG "Header sig: 00 FF 00 %02X\n", data[3]);
+                               info("Header found.");
 #endif
-                       if (data[3] == hdr_sig) {
-                               if (debug > 2)
-                                       printk(KERN_DEBUG "Header found.\n");
-                               return data+4;
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                               icam->has_hdr = 1;
+                               frame->header = HDRSIG_MODEL1_176x144;
+                               break;
                        }
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
                }
-               ++data;
-               --len;
-       }
-       return NULL;
-}
-
-static unsigned char *ibmcam_model2_find_header(unsigned char hdr_sig, unsigned char *data, int len)
-{
-       int marker_len = 0;
-
-       switch (videosize) {
-       case VIDEOSIZE_176x144:
-               marker_len = 10;
-               break;
-       default:
-               marker_len = 2;
                break;
        }
-       while (len >= marker_len)
-       {
-               if ((data[0] == 0x00) && (data[1] == 0xFF))
-               {
+       case IBMCAM_MODEL_3:
+       {       /*
+                * Headers: (one precedes every frame). nc=no compression,
+                * bq=best quality bf=best frame rate.
+                *
+                * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf }
+                * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf }
+                * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf }
+                *
+                * Bytes '00 FF' seem to indicate header. Other two bytes
+                * encode the frame type. This is a set of bit fields that
+                * encode image size, compression type etc. These fields
+                * do NOT contain frame number because all frames carry
+                * the same header.
+                */
+               const int marker_len = 4;
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF))
+                       {
+                               /*
+                                * Combine 2 bytes of frame type into one
+                                * easy to use value
+                                */
+                               unsigned long byte3, byte4;
+
+                               byte3 = RING_QUEUE_PEEK(&uvd->dp, 2);
+                               byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
+                               frame->header = (byte3 << 8) | byte4;
 #if 0
-                       /* This code helps to detect new frame markers */
-                       static int pass = 0;
-                       if (pass++ == 0)
-                               ibmcam_hexdump(data, (len > 16) ? 16 : len);
+                               info("Header found.");
 #endif
-                       if (debug > 2)
-                               printk(KERN_DEBUG "Header found.\n");
-                       return data+marker_len;
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                               icam->has_hdr = 1;
+                               break;
+                       }
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
                }
-               ++data;
-               --len;
+               break;
        }
-       return NULL;
-}
-
-/* How much data is left in the scratch buf? */
-#define scratch_left(x)        (ibmcam->scratchlen - (int)((char *)x - (char *)ibmcam->scratch))
-
-/* Grab the remaining */
-static void usb_ibmcam_align_scratch(struct usb_ibmcam *ibmcam, unsigned char *data)
-{
-       unsigned long left;
-
-       left = scratch_left(data);
-       memmove(ibmcam->scratch, data, left);
-       ibmcam->scratchlen = left;
-}
-
-/*
- * usb_ibmcam_find_header()
- *
- * Locate one of supported header markers in the scratch buffer.
- * Once found, remove all preceding bytes AND the marker (4 bytes)
- * from the scratch buffer. Whatever follows must be video lines.
- *
- * History:
- * 1/21/00  Created.
- */
-static scan_state_t usb_ibmcam_find_header(struct usb_ibmcam *ibmcam)
-{
-       struct ibmcam_frame *frame;
-       unsigned char *data, *tmp;
-
-       data = ibmcam->scratch;
-       frame = &ibmcam->frame[ibmcam->curframe];
-
-       if (ibmcam->camera_model == IBMCAM_MODEL_1)
-               tmp = ibmcam_model1_find_header(frame->hdr_sig, data, scratch_left(data));
-       else if (ibmcam->camera_model == IBMCAM_MODEL_2)
-               tmp = ibmcam_model2_find_header(frame->hdr_sig, data, scratch_left(data));
-       else
-               tmp = NULL;
-
-       if (tmp == NULL) {
-               /* No header - entire scratch buffer is useless! */
-               if (debug > 2)
-                       printk(KERN_DEBUG "Skipping frame, no header\n");
-               ibmcam->scratchlen = 0;
+       default:
+               break;
+       }
+       if (!icam->has_hdr) {
+               if (uvd->debug > 2)
+                       info("Skipping frame, no header");
                return scan_EndParse;
        }
-       /* Header found */
-       data = tmp;
 
-       ibmcam->has_hdr = 1;
-       ibmcam->header_count++;
-       frame->scanstate = STATE_LINES;
+       /* Header found */
+       icam->has_hdr = 1;
+       uvd->stats.header_count++;
+       frame->scanstate = ScanState_Lines;
        frame->curline = 0;
 
        if (flags & FLAGS_FORCE_TESTPATTERN) {
-               usb_ibmcam_testpattern(ibmcam, 1, 1);
+               usbvideo_TestPattern(uvd, 1, 1);
                return scan_NextFrame;
        }
-       usb_ibmcam_align_scratch(ibmcam, data);
        return scan_Continue;
 }
 
 /*
- * usb_ibmcam_parse_lines()
+ * ibmcam_parse_lines()
  *
- * Parse one line (TODO: more than one!) from the scratch buffer, put
- * decoded RGB value into the current frame buffer and add the written
- * number of bytes (RGB) to the *pcopylen.
+ * Parse one line (interlaced) from the buffer, put
+ * decoded RGB value into the current frame buffer
+ * and add the written number of bytes (RGB) to
+ * the *pcopylen.
  *
  * History:
- * 1/21/00  Created.
+ * 21-Jan-2000 Created.
+ * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
  */
-static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcopylen)
+static ParseState_t ibmcam_parse_lines(
+       uvd_t *uvd,
+       usbvideo_frame_t *frame,
+       long *pcopylen)
 {
-       struct ibmcam_frame *frame;
-       unsigned char *data, *f, *chromaLine;
-       unsigned int len;
-       const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL;        /* V4L line offset */
-       const int hue_corr  = (ibmcam->vpic.hue - 0x8000) >> 10;        /* -32..+31 */
+       unsigned char *f;
+       ibmcam_t *icam;
+       unsigned int len, scanLength, scanHeight, order_uv, order_yc;
+       int v4l_linesize; /* V4L line offset */
+       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
        const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
        const int ccm = 128; /* Color correction median - see below */
-       int y, u, v, i, frame_done=0, mono_plane, color_corr;
-
-       color_corr = (ibmcam->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+       int y, u, v, i, frame_done=0, color_corr;
+       static unsigned char lineBuffer[640*3];
+       unsigned const char *chromaLine, *lumaLine;
+
+       assert(uvd != NULL);
+       assert(frame != NULL);
+       icam = IBMCAM_T(uvd);
+       assert(icam != NULL);
+       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
        RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-       data = ibmcam->scratch;
-       frame = &ibmcam->frame[ibmcam->curframe];
 
-       len = frame->frmwidth * 3; /* 1 line of mono + 1 line of color */
-       /*printk(KERN_DEBUG "len=%d. left=%d.\n",len,scratch_left(data));*/
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) {
+               /* Model 4 frame markers do not carry image size identification */
+               switch (uvd->videosize) {
+               case VIDEOSIZE_128x96:
+               case VIDEOSIZE_160x120:
+               case VIDEOSIZE_176x144:
+                       scanLength = VIDEOSIZE_X(uvd->videosize);
+                       scanHeight = VIDEOSIZE_Y(uvd->videosize);
+                       break;
+               default:
+                       err("ibmcam_parse_lines: Wrong mode.");
+                       return scan_Out;
+               }
+               order_yc = 1;   /* order_yc: true=Yc false=cY ('c'=either U or V) */
+               order_uv = 1;   /* Always true in this algorithm */
+       } else {
+               switch (frame->header) {
+               case HDRSIG_MODEL1_128x96:
+                       scanLength = 128;
+                       scanHeight = 96;
+                       order_uv = 1;   /* U Y V Y ... */
+                       break;
+               case HDRSIG_MODEL1_176x144:
+                       scanLength = 176;
+                       scanHeight = 144;
+                       order_uv = 1;   /* U Y V Y ... */
+                       break;
+               case HDRSIG_MODEL1_352x288:
+                       scanLength = 352;
+                       scanHeight = 288;
+                       order_uv = 0;   /* Y V Y V ... */
+                       break;
+               default:
+                       err("Unknown header signature 00 FF 00 %02lX", frame->header);
+                       return scan_NextFrame;
+               }
+               /* order_yc: true=Yc false=cY ('c'=either U or V) */
+               order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2);
+       }
 
-       mono_plane = ((frame->curline & 1) == 0);
+       len = scanLength * 3;
+       assert(len <= sizeof(lineBuffer));
 
        /*
-        * Lines are organized this way (or are they?)
+        * Lines are organized this way:
         *
         * I420:
         * ~~~~
+        * <scanLength->
         * ___________________________________
         * |-----Y-----|---UVUVUV...UVUV-----| \
         * |-----------+---------------------|  \
-        * |<-- 176 -->|<------ 176*2 ------>|  Total 72. pairs of lines
-        * |...    ...       ...|  /
-        * |___________|_____________________| /
-        *  - odd line- ------- even line ---
-        *
-        * another format:
-        * ~~~~~~~~~~~~~~
-        * ___________________________________
-        * |-----Y-----|---UVUVUV...UVUV-----| \
-        * |-----------+---------------------|  \
-        * |<-- 352 -->|<------ 352*2 ------>|  Total 144. pairs of lines
-        * |...    ...       ...|  /
+        * |<-- 176 -->|<------ 176*2 ------>|  Total 72. lines (interlaced)
+        * |...    ... |        ...          |  /
+        * |<-- 352 -->|<------ 352*2 ------>|  Total 144. lines (interlaced)
         * |___________|_____________________| /
-        *  - odd line- ------- even line ---
+        *  \           \
+        *   lumaLine    chromaLine
         */
 
        /* Make sure there's enough data for the entire line */
-       if (scratch_left(data) < (len+1024)) {
-               /*printk(KERN_DEBUG "out of data, need %u.\n", len);*/
+       if (RingQueue_GetLength(&uvd->dp) < len)
                return scan_Out;
-       }
 
-#if 0
-       {       /* This code prints beginning of the source frame */
-               static int pass = 0;
-               if ((pass++ % 3000) == 0)
-                       ibmcam_hexdump(data, 16);
-       }
-#endif
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
 
-#if 0
-       if (frame->curline == 10 || frame->curline == 11) {
-               /* This code prints beginning of 10th (mono), 11th (chroma) line */
-               static int pass = 0;
-               if ((pass % 100) == 0)
-                       ibmcam_hexdump(data, 16);
-               if (frame->curline == 11)
-                       pass++;
-       }
-#endif
        /*
         * Make sure that our writing into output buffer
         * will not exceed the buffer. Mind that we may write
         * not into current output scanline but in several after
         * it as well (if we enlarge image vertically.)
         */
-       if ((frame->curline + 1) >= V4L_FRAME_HEIGHT)
+       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
                return scan_NextFrame;
 
        /*
-        * Now we are sure that entire line (representing all 'frame->frmwidth'
-        * pixels from the camera) is available in the scratch buffer. We
-        * start copying the line left-aligned to the V4L buffer (which
-        * might be larger - not smaller, hopefully). If the camera
-        * line is shorter then we should pad the V4L buffer with something
-        * (black in this case) to complete the line.
+        * Now we are sure that entire line (representing all 'scanLength'
+        * pixels from the camera) is available in the buffer. We
+        * start copying the line left-aligned to the V4L buffer.
+        * If the camera line is shorter then we should pad the V4L
+        * buffer with something (black) to complete the line.
         */
+       assert(frame->data != NULL);
        f = frame->data + (v4l_linesize * frame->curline);
 
        /*
-        * chromaLine points to 1st pixel of the line with chrominance.
-        * If current line is monochrome then chromaLine points to next
-        * line after monochrome one. If current line has chrominance
-        * then chromaLine points to this very line. Such method allows
-        * to access chrominance data uniformly.
-        *
         * To obtain chrominance data from the 'chromaLine' use this:
         *   v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
         *   u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
@@ -778,40 +514,16 @@ static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcop
         * v_index = (i >> 1) << 2;
         * u_index = (i >> 1) << 2 + 2;
         *
-        * where 'i' is the column number [0..frame->frmwidth-1]
+        * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1]
         */
-       chromaLine = data;
-       if (mono_plane)
-               chromaLine += frame->frmwidth;
-
-       for (i = 0; i < frame->frmwidth; i++, data += (mono_plane ? 1 : 2))
+       lumaLine = lineBuffer;
+       chromaLine = lineBuffer + scanLength;
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++)
        {
                unsigned char rv, gv, bv;       /* RGB components */
 
-               /*
-                * Search for potential Start-Of-Frame marker. It should
-                * not be here, of course, but if your formats don't match
-                * you might exceed the frame. We must match the marker to
-                * each byte of multi-byte data element if it is multi-byte.
-                */
-#if 1
-               if ((ibmcam->camera_model == IBMCAM_MODEL_1) && (scratch_left(data) >= (4+2))) {
-                       unsigned char *dp;
-                       int j;
-
-                       for (j=0, dp=data; j < 2; j++, dp++) {
-                               if ((dp[0] == 0x00) && (dp[1] == 0xFF) &&
-                                   (dp[2] == 0x00) && (dp[3] == frame->hdr_sig)) {
-                                       ibmcam->has_hdr = 2;
-                                       frame_done++;
-                                       break;
-                               }
-                       }
-               }
-#endif
-
                /* Check for various visual debugging hints (colorized pixels) */
-               if ((flags & FLAGS_DISPLAY_HINTS) && (ibmcam->has_hdr)) {
+               if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) {
                        /*
                         * This is bad and should not happen. This means that
                         * we somehow overshoot the line and encountered new
@@ -819,7 +531,7 @@ static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcop
                         * of whack. This cyan dot will help you to figure
                         * out where exactly the new frame arrived.
                         */
-                       if (ibmcam->has_hdr == 1) {
+                       if (icam->has_hdr == 1) {
                                bv = 0; /* Yellow marker */
                                gv = 0xFF;
                                rv = 0xFF;
@@ -828,15 +540,27 @@ static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcop
                                gv = 0xFF;
                                rv = 0;
                        }
-                       ibmcam->has_hdr = 0;
+                       icam->has_hdr = 0;
                        goto make_pixel;
                }
 
-               if (mono_plane || frame->order_yc)
-                       y = data[0];
-               else
-                       y = data[1];
+               /*
+                * Check if we are still in range. We may be out of range if our
+                * V4L canvas is wider or taller than the camera "native" image.
+                * Then we quickly fill the remainder of the line with zeros to
+                * make black color and quit the horizontal scanning loop.
+                */
+               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
+                       const int j = i * V4L_BYTES_PER_PIXEL;
+#if USES_IBMCAM_PUTPIXEL
+                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
+                       f = frame->data + (v4l_linesize * frame->curline) + j;
+#endif
+                       memset(f, 0, v4l_linesize - j);
+                       break;
+               }
 
+               y = lumaLine[i];
                if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
                        rv = gv = bv = y;
                else {
@@ -845,11 +569,11 @@ static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcop
                        off_0 = (i >> 1) << 2;
                        off_2 = off_0 + 2;
 
-                       if (frame->order_yc) {
+                       if (order_yc) {
                                off_0++;
                                off_2++;
                        }
-                       if (!frame->order_uv) {
+                       if (!order_uv) {
                                off_0 += 2;
                                off_2 -= 2;
                        }
@@ -877,7 +601,7 @@ static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcop
                 * (in this order).
                 */
 #if USES_IBMCAM_PUTPIXEL
-               IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
 #else
                *f++ = bv;
                *f++ = gv;
@@ -899,18 +623,19 @@ static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcop
         * may fill more than one output scanline if we do vertical
         * enlargement.
         */
-       frame->curline++;
-       *pcopylen += v4l_linesize;
-       usb_ibmcam_align_scratch(ibmcam, data);
+       frame->curline += 2;
+       if (pcopylen != NULL)
+               *pcopylen += 2 * v4l_linesize;
+       frame->deinterlace = Deinterlace_FillOddLines;
 
-       if (frame_done || (frame->curline >= frame->frmheight))
+       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
                return scan_NextFrame;
        else
                return scan_Continue;
 }
 
 /*
- * usb_ibmcam_model2_parse_lines()
+ * ibmcam_model2_320x240_parse_lines()
  *
  * This procedure deals with a weird RGB format that is produced by IBM
  * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175,
@@ -918,15 +643,15 @@ static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcop
  *
  * <--- 160 or 176 pairs of RA,RB bytes ----->
  * *-----------------------------------------* \
- * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx |  \
- * |-----+-----+-----+-----+ ... +-----+-----|   *- This is pair of horizontal lines,
- * | B0  | G0  | B1  | G1  | ... | Bx  | Gx  |  /   total 240 or 288 lines (120 or 144
- * |=====+=====+=====+=====+ ... +=====+=====| /    such pairs).
+ * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx |  \   This is pair of horizontal lines,
+ * |-----+-----+-----+-----+ ... +-----+-----|   *- or one interlaced line, total
+ * | B0  | G0  | B1  | G1  | ... | Bx  | Gx  |  /   120 or 144 such pairs which yield
+ * |=====+=====+=====+=====+ ... +=====+=====| /    240 or 288 lines after deinterlacing.
  *
  * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1
  * defines ONE pixel. Therefore this format yields 176x144 "decoded"
  * resolution at best. I do not know why camera sends such format - the
- * previous model just used I420 and everyone was happy.
+ * previous model (1) just used interlaced I420 and everyone was happy.
  *
  * I do not know what is the difference between RAi and RBi bytes. Both
  * seemingly represent R component, but slightly vary in value (so that
@@ -934,29 +659,42 @@ static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcop
  * them both as R component in attempt to at least partially recover the
  * lost resolution.
  */
-static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, long *pcopylen)
+static ParseState_t ibmcam_model2_320x240_parse_lines(
+       uvd_t *uvd,
+       usbvideo_frame_t *frame,
+       long *pcopylen)
 {
-       struct ibmcam_frame *frame;
-       unsigned char *data, *f, *la, *lb;
+       unsigned char *f, *la, *lb;
        unsigned int len;
-       const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL;        /* V4L line offset */
+       int v4l_linesize; /* V4L line offset */
        int i, j, frame_done=0, color_corr;
+       int scanLength, scanHeight;
+       static unsigned char lineBuffer[352*2];
 
-       color_corr = (ibmcam->vpic.colour) >> 8; /* 0..+255 */
-
-       data = ibmcam->scratch;
-       frame = &ibmcam->frame[ibmcam->curframe];
+       switch (uvd->videosize) {
+       case VIDEOSIZE_320x240:
+       case VIDEOSIZE_352x240:
+       case VIDEOSIZE_352x288:
+               scanLength = VIDEOSIZE_X(uvd->videosize);
+               scanHeight = VIDEOSIZE_Y(uvd->videosize);
+               break;
+       default:
+               err("ibmcam_model2_320x240_parse_lines: Wrong mode.");
+               return scan_Out;
+       }
 
-       /* Here we deal with pairs of horizontal lines */
+       color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
 
-       len = frame->frmwidth * 2; /* 2 lines */
-       /*printk(KERN_DEBUG "len=%d. left=%d.\n",len,scratch_left(data));*/
+       len = scanLength * 2; /* See explanation above */
+       assert(len <= sizeof(lineBuffer));
 
        /* Make sure there's enough data for the entire line */
-       if (scratch_left(data) < (len+32)) {
-               /*printk(KERN_DEBUG "out of data, need %u.\n", len);*/
+       if (RingQueue_GetLength(&uvd->dp) < len)
                return scan_Out;
-       }
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
 
        /*
         * Make sure that our writing into output buffer
@@ -964,19 +702,15 @@ static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, lon
         * not into current output scanline but in several after
         * it as well (if we enlarge image vertically.)
         */
-       if ((frame->curline + 1) >= V4L_FRAME_HEIGHT)
+       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
                return scan_NextFrame;
 
-       if ((frame->curline & 1) == 0) {
-               la = data;
-               lb = data + frame->frmwidth;
-       } else {
-               la = data + frame->frmwidth;
-               lb = data;
-       }
+       la = lineBuffer;
+       lb = lineBuffer + scanLength;
 
        /*
-        * Now we are sure that entire line (representing all 'frame->frmwidth'
+        * Now we are sure that entire line (representing all
+        *         VIDEOSIZE_X(frame->request)
         * pixels from the camera) is available in the scratch buffer. We
         * start copying the line left-aligned to the V4L buffer (which
         * might be larger - not smaller, hopefully). If the camera
@@ -986,14 +720,14 @@ static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, lon
        f = frame->data + (v4l_linesize * frame->curline);
 
        /* Fill the 2-line strip */
-       for (i = 0; i < frame->frmwidth; i++) {
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
                int y, rv, gv, bv;      /* RGB components */
 
                j = i & (~1);
 
                /* Check for various visual debugging hints (colorized pixels) */
-               if ((flags & FLAGS_DISPLAY_HINTS) && (ibmcam->has_hdr)) {
-                       if (ibmcam->has_hdr == 1) {
+               if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) {
+                       if (IBMCAM_T(uvd)->has_hdr == 1) {
                                bv = 0; /* Yellow marker */
                                gv = 0xFF;
                                rv = 0xFF;
@@ -1002,14 +736,30 @@ static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, lon
                                gv = 0xFF;
                                rv = 0;
                        }
-                       ibmcam->has_hdr = 0;
+                       IBMCAM_T(uvd)->has_hdr = 0;
                        goto make_pixel;
                }
 
                /*
-                * Here I use RA and RB components, one per physical pixel.
-                * This causes fine vertical grid on the picture but may improve
-                * horizontal resolution. If you prefer replicating, use this:
+                * Check if we are still in range. We may be out of range if our
+                * V4L canvas is wider or taller than the camera "native" image.
+                * Then we quickly fill the remainder of the line with zeros to
+                * make black color and quit the horizontal scanning loop.
+                */
+               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
+                       const int j = i * V4L_BYTES_PER_PIXEL;
+#if USES_IBMCAM_PUTPIXEL
+                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
+                       f = frame->data + (v4l_linesize * frame->curline) + j;
+#endif
+                       memset(f, 0, v4l_linesize - j);
+                       break;
+               }
+
+               /*
+                * Here I use RA and RB components, one per physical pixel.
+                * This causes fine vertical grid on the picture but may improve
+                * horizontal resolution. If you prefer replicating, use this:
                 *   rv = la[j + 0];   ... or ... rv = la[j + 1];
                 * then the pixel will be replicated.
                 */
@@ -1045,8 +795,7 @@ static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, lon
                }
 
        make_pixel:
-               IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-               IBMCAM_PUTPIXEL(frame, i, frame->curline+1, rv, gv, bv);
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
        }
        /*
         * Account for number of bytes that we wrote into output V4L frame.
@@ -1056,257 +805,342 @@ static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, lon
         */
        frame->curline += 2;
        *pcopylen += v4l_linesize * 2;
-       data += frame->frmwidth * 2;
-       usb_ibmcam_align_scratch(ibmcam, data);
+       frame->deinterlace = Deinterlace_FillOddLines;
 
-       if (frame_done || (frame->curline >= frame->frmheight))
+       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
                return scan_NextFrame;
        else
                return scan_Continue;
 }
 
-/*
- * ibmcam_parse_data()
- *
- * Generic routine to parse the scratch buffer. It employs either
- * usb_ibmcam_find_header() or usb_ibmcam_parse_lines() to do most
- * of work.
- *
- * History:
- * 1/21/00  Created.
- */
-static void ibmcam_parse_data(struct usb_ibmcam *ibmcam)
+static ParseState_t ibmcam_model3_parse_lines(
+       uvd_t *uvd,
+       usbvideo_frame_t *frame,
+       long *pcopylen)
 {
-       struct ibmcam_frame *frame;
-       unsigned char *data = ibmcam->scratch;
-       scan_state_t newstate;
-       long copylen = 0;
+       unsigned char *data;
+       const unsigned char *color;
+       unsigned int len;
+       int v4l_linesize; /* V4L line offset */
+       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
+       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
+       const int ccm = 128; /* Color correction median - see below */
+       int i, u, v, rw, data_w=0, data_h=0, color_corr;
+       static unsigned char lineBuffer[640*3];
 
-       /* Grab the current frame and the previous frame */
-       frame = &ibmcam->frame[ibmcam->curframe];
+       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
 
-       /* printk(KERN_DEBUG "parsing %u.\n", ibmcam->scratchlen); */
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
 
-       while (1) {
+       /* The header tells us what sort of data is in this frame */
+       switch (frame->header) {
+               /*
+                * Uncompressed modes (that are easy to decode).
+                */
+       case 0x0308:
+               data_w = 640;
+               data_h = 480;
+               break;
+       case 0x0208:
+               data_w = 320;
+               data_h = 240;
+               break;
+       case 0x020A:
+               data_w = 160;
+               data_h = 120;
+               break;
+               /*
+                * Compressed modes (ViCE - that I don't know how to decode).
+                */
+       case 0x0328:    /* 640x480, best quality compression */
+       case 0x0368:    /* 640x480, best frame rate compression */
+       case 0x0228:    /* 320x240, best quality compression */
+       case 0x0268:    /* 320x240, best frame rate compression */
+       case 0x02CA:    /* 160x120, best quality compression */
+       case 0x02EA:    /* 160x120, best frame rate compression */
+               /* Do nothing with this - not supported */
+               err("Unsupported mode $%04lx", frame->header);
+               return scan_NextFrame;
+       default:
+               /* Catch unknown headers, may help in learning new headers */
+               err("Strange frame->header=$%08lx", frame->header);
+               return scan_NextFrame;
+       }
 
-               newstate = scan_Out;
-               if (scratch_left(data)) {
-                       if (frame->scanstate == STATE_SCANNING)
-                               newstate = usb_ibmcam_find_header(ibmcam);
-                       else if (frame->scanstate == STATE_LINES) {
-                               if ((ibmcam->camera_model == IBMCAM_MODEL_2) &&
-                                   (videosize >= VIDEOSIZE_352x288)) {
-                                       newstate = usb_ibmcam_model2_parse_lines(ibmcam, &copylen);
-                               }
-                               else {
-                                       newstate = usb_ibmcam_parse_lines(ibmcam, &copylen);
-                               }
-                       }
-               }
-               if (newstate == scan_Continue)
-                       continue;
-               else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
-                       break;
-               else
-                       return; /* scan_EndParse */
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Note that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 1) >= data_h) {
+               if (uvd->debug >= 3)
+                       info("Reached line %d. (frame is done)", frame->curline);
+               return scan_NextFrame;
        }
 
-       if (newstate == scan_NextFrame) {
-               frame->grabstate = FRAME_DONE;
-               ibmcam->curframe = -1;
-               ibmcam->frame_num++;
+       /* Make sure there's enough data for the entire line */
+       len = 3 * data_w; /* <y-data> <uv-data> */
+       assert(len <= sizeof(lineBuffer));
 
-               /* Optionally display statistics on the screen */
-               if (flags & FLAGS_OVERLAY_STATS)
-                       usb_ibmcam_overlaystats(ibmcam, frame);
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
 
-               /* This will cause the process to request another frame. */
-               if (waitqueue_active(&frame->wq))
-                       wake_up_interruptible(&frame->wq);
-       }
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
 
-       /* Update the frame's uncompressed length. */
-       frame->scanlength += copylen;
-}
+       data = lineBuffer;
+       color = data + data_w;          /* Point to where color planes begin */
 
-/*
- * Make all of the blocks of data contiguous
- */
-static int ibmcam_compress_isochronous(struct usb_ibmcam *ibmcam, urb_t *urb)
-{
-       unsigned char *cdata, *data, *data0;
-       int i, totlen = 0;
-
-       data = data0 = ibmcam->scratch + ibmcam->scratchlen;
-       for (i = 0; i < urb->number_of_packets; i++) {
-               int n = urb->iso_frame_desc[i].actual_length;
-               int st = urb->iso_frame_desc[i].status;
-               
-               cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-               /* Detect and ignore errored packets */
-               if (st < 0) {
-                       if (debug >= 1) {
-                               printk(KERN_ERR "ibmcam data error: [%d] len=%d, status=%X\n",
-                                      i, n, st);
-                       }
-                       ibmcam->iso_err_count++;
-                       continue;
-               }
+       /* Bottom-to-top scanning */
+       rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
+       RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
 
-               /* Detect and ignore empty packets */
-               if (n <= 0) {
-                       ibmcam->iso_skip_count++;
-                       continue;
-               }
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+               int y, rv, gv, bv;      /* RGB components */
 
-               /*
-                * If camera continues to feed us with data but there is no
-                * consumption (if, for example, V4L client fell asleep) we
-                * may overflow the buffer. We have to move old data over to
-                * free room for new data. This is bad for old data. If we
-                * just drop new data then it's bad for new data... choose
-                * your favorite evil here.
-                */
-               if ((ibmcam->scratchlen + n) > scratchbufsize) {
-#if 0
-                       ibmcam->scratch_ovf_count++;
-                       if (debug >= 3)
-                               printk(KERN_ERR "ibmcam: scratch buf overflow! "
-                                      "scr_len: %d, n: %d\n", ibmcam->scratchlen, n );
-                       return totlen;
-#else
-                       int mv;
+               if (i < data_w) {
+                       y = data[i];    /* Luminosity is the first line */
 
-                       ibmcam->scratch_ovf_count++;
-                       if (debug >= 3) {
-                               printk(KERN_ERR "ibmcam: scratch buf overflow! "
-                                      "scr_len: %d, n: %d\n", ibmcam->scratchlen, n );
-                       }
-                       mv  = (ibmcam->scratchlen + n) - scratchbufsize;
-                       if (ibmcam->scratchlen >= mv) {
-                               int newslen = ibmcam->scratchlen - mv;
-                               memmove(ibmcam->scratch, ibmcam->scratch + mv, newslen);
-                               ibmcam->scratchlen = newslen;
-                               data = data0 = ibmcam->scratch + ibmcam->scratchlen;
-                       } else {
-                               printk(KERN_ERR "ibmcam: scratch buf too small\n");
-                               return totlen;
+                       /* Apply static color correction */
+                       u = color[i*2] + hue_corr;
+                       v = color[i*2 + 1] + hue2_corr;
+
+                       /* Apply color correction */
+                       if (color_corr != 0) {
+                               /* Magnify up to 2 times, reduce down to zero saturation */
+                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
+                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
                        }
-#endif
-               }
+               } else
+                       y = 0, u = v = 128;
 
-               /* Now we know that there is enough room in scratch buffer */
-               memmove(data, cdata, n);
-               data += n;
-               totlen += n;
-               ibmcam->scratchlen += n;
+               YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+               RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */
        }
-#if 0
-       if (totlen > 0) {
-               static int foo=0;
-               if (foo < 1) {
-                       printk(KERN_DEBUG "+%d.\n", totlen);
-                       ibmcam_hexdump(data0, (totlen > 64) ? 64:totlen);
-                       ++foo;
+       frame->deinterlace = Deinterlace_FillEvenLines;
+
+       /*
+        * Account for number of bytes that we wrote into output V4L frame.
+        * We do it here, after we are done with the scanline, because we
+        * may fill more than one output scanline if we do vertical
+        * enlargement.
+        */
+       frame->curline += 2;
+       *pcopylen += 2 * v4l_linesize;
+
+       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
+               if (uvd->debug >= 3) {
+                       info("All requested lines (%ld.) done.",
+                            VIDEOSIZE_Y(frame->request));
                }
-       }
-#endif
-       return totlen;
+               return scan_NextFrame;
+       } else
+               return scan_Continue;
 }
 
-static void ibmcam_isoc_irq(struct urb *urb)
+/*
+ * ibmcam_model4_128x96_parse_lines()
+ *
+ * This decoder is for one strange data format that is produced by Model 4
+ * camera only in 128x96 mode. This is RGB format and here is its description.
+ * First of all, this is non-interlaced stream, meaning that all scan lines
+ * are present in the datastream. There are 96 consecutive blocks of data
+ * that describe all 96 lines of the image. Each block is 5*128 bytes long
+ * and carries R, G, B components. The format of the block is shown in the
+ * code below. First 128*2 bytes are interleaved R and G components. Then
+ * we have a gap (junk data) 64 bytes long. Then follow B and something
+ * else, also interleaved (this makes another 128*2 bytes). After that
+ * probably another 64 bytes of junk follow.
+ *
+ * History:
+ * 10-Feb-2001 Created.
+ */
+static ParseState_t ibmcam_model4_128x96_parse_lines(
+       uvd_t *uvd,
+       usbvideo_frame_t *frame,
+       long *pcopylen)
 {
-       int len;
-       struct usb_ibmcam *ibmcam = urb->context;
-       struct ibmcam_sbuf *sbuf;
-       int i;
+       const unsigned char *data_rv, *data_gv, *data_bv;
+       unsigned int len;
+       int i, v4l_linesize; /* V4L line offset */
+       const int data_w=128, data_h=96;
+       static unsigned char lineBuffer[128*5];
 
-       /* We don't want to do anything if we are about to be removed! */
-       if (!IBMCAM_IS_OPERATIONAL(ibmcam))
-               return;
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
 
-#if 0
-       if (urb->actual_length > 0) {
-               printk(KERN_DEBUG "ibmcam_isoc_irq: %p status %d, "
-                      " errcount = %d, length = %d\n", urb, urb->status,
-                      urb->error_count, urb->actual_length);
-       } else {
-               static int c = 0;
-               if (c++ % 100 == 0)
-                       printk(KERN_DEBUG "ibmcam_isoc_irq: no data\n");
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Note that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 1) >= data_h) {
+               if (uvd->debug >= 3)
+                       info("Reached line %d. (frame is done)", frame->curline);
+               return scan_NextFrame;
        }
-#endif
 
-       if (!ibmcam->streaming) {
-               if (debug >= 1)
-                       printk(KERN_DEBUG "ibmcam: oops, not streaming, but interrupt\n");
-               return;
-       }
-       
-       sbuf = &ibmcam->sbuf[ibmcam->cursbuf];
+       /*
+        * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________
+        * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 --->
+        */
 
-       /* Copy the data received into our scratch buffer */
-       len = ibmcam_compress_isochronous(ibmcam, urb);
+       /* Make sure there's enough data for the entire line */
+       len = 5 * data_w;
+       assert(len <= sizeof(lineBuffer));
 
-       ibmcam->urb_count++;
-       ibmcam->urb_length = len;
-       ibmcam->data_count += len;
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
 
-#if 0   /* This code prints few initial bytes of ISO data: used to decode markers */
-       if (ibmcam->urb_count % 64 == 1) {
-               if (ibmcam->urb_count == 1) {
-                       ibmcam_hexdump(ibmcam->scratch,
-                                      (ibmcam->scratchlen > 32) ? 32 : ibmcam->scratchlen);
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       data_rv = lineBuffer;
+       data_gv = lineBuffer + 1;
+       data_bv = lineBuffer + data_w*2 + data_w/2;
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+               int rv, gv, bv; /* RGB components */
+               if (i < data_w) {
+                       const int j = i * 2;
+                       gv = data_rv[j];
+                       rv = data_gv[j];
+                       bv = data_bv[j];
+                       if (flags & FLAGS_MONOCHROME) {
+                               unsigned long y;
+                               y = rv + gv + bv;
+                               y /= 3;
+                               if (y > 0xFF)
+                                       y = 0xFF;
+                               rv = gv = bv = (unsigned char) y;
+                       }
+               } else {
+                       rv = gv = bv = 0;
                }
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
        }
-#endif
+       frame->deinterlace = Deinterlace_None;
+       frame->curline++;
+       *pcopylen += v4l_linesize;
 
-       /* If we collected enough data let's parse! */
-       if (ibmcam->scratchlen) {
-               /* If we don't have a frame we're current working on, complain */
-               if (ibmcam->curframe >= 0)
-                       ibmcam_parse_data(ibmcam);
-               else {
-                       if (debug >= 1)
-                               printk(KERN_DEBUG "ibmcam: received data, but no frame available\n");
+       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
+               if (uvd->debug >= 3) {
+                       info("All requested lines (%ld.) done.",
+                            VIDEOSIZE_Y(frame->request));
+               }
+               return scan_NextFrame;
+       } else
+               return scan_Continue;
+}
+
+/*
+ * ibmcam_ProcessIsocData()
+ *
+ * Generic routine to parse the ring queue data. It employs either
+ * ibmcam_find_header() or ibmcam_parse_lines() to do most
+ * of work.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+void ibmcam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
+{
+       ParseState_t newstate;
+       long copylen = 0;
+       int mod = IBMCAM_T(uvd)->camera_model;
+
+       while (1) {
+               newstate = scan_Out;
+               if (RingQueue_GetLength(&uvd->dp) > 0) {
+                       if (frame->scanstate == ScanState_Scanning) {
+                               newstate = ibmcam_find_header(uvd);
+                       } else if (frame->scanstate == ScanState_Lines) {
+                               if ((mod == IBMCAM_MODEL_2) &&
+                                   ((uvd->videosize == VIDEOSIZE_352x288) ||
+                                    (uvd->videosize == VIDEOSIZE_320x240) ||
+                                    (uvd->videosize == VIDEOSIZE_352x240)))
+                               {
+                                       newstate = ibmcam_model2_320x240_parse_lines(
+                                               uvd, frame, &copylen);
+                               } else if (mod == IBMCAM_MODEL_4) {
+                                       /*
+                                        * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB)
+                                        * for 320x240 and above; 160x120 and 176x144 uses Model 1
+                                        * decoder (YUV), and 128x96 mode uses ???
+                                        */
+                                       if ((uvd->videosize == VIDEOSIZE_352x288) ||
+                                           (uvd->videosize == VIDEOSIZE_320x240) ||
+                                           (uvd->videosize == VIDEOSIZE_352x240))
+                                       {
+                                               newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, &copylen);
+                                       } else if (uvd->videosize == VIDEOSIZE_128x96) {
+                                               newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, &copylen);
+                                       } else {
+                                               newstate = ibmcam_parse_lines(uvd, frame, &copylen);
+                                       }
+                               } else if (mod == IBMCAM_MODEL_3) {
+                                       newstate = ibmcam_model3_parse_lines(uvd, frame, &copylen);
+                               } else {
+                                       newstate = ibmcam_parse_lines(uvd, frame, &copylen);
+                               }
+                       }
                }
+               if (newstate == scan_Continue)
+                       continue;
+               else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
+                       break;
+               else
+                       return; /* scan_EndParse */
        }
 
-       for (i = 0; i < FRAMES_PER_DESC; i++) {
-               sbuf->urb->iso_frame_desc[i].status = 0;
-               sbuf->urb->iso_frame_desc[i].actual_length = 0;
+       if (newstate == scan_NextFrame) {
+               frame->frameState = FrameState_Done;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+               if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) {
+                       /* Need software contrast adjustment for those cameras */
+                       frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST;
+               }
        }
 
-       /* Move to the next sbuf */
-       ibmcam->cursbuf = (ibmcam->cursbuf + 1) % IBMCAM_NUMSBUF;
+       /* Update the frame's uncompressed length. */
+       frame->seqRead_Length += copylen;
 
-       return;
+#if 0
+       {
+               static unsigned char j=0;
+               memset(frame->data, j++, uvd->max_frame_size);
+               frame->frameState = FrameState_Ready;
+       }
+#endif
 }
 
 /*
- * usb_ibmcam_veio()
+ * ibmcam_veio()
  *
  * History:
  * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
  */
-static int usb_ibmcam_veio(
-       struct usb_ibmcam *ibmcam,
+static int ibmcam_veio(
+       uvd_t *uvd,
        unsigned char req,
        unsigned short value,
        unsigned short index)
 {
-       static const char proc[] = "usb_ibmcam_veio";
+       static const char proc[] = "ibmcam_veio";
        unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
        int i;
 
-       if (!IBMCAM_IS_OPERATIONAL(ibmcam))
+       if (!CAMERA_IS_OPERATIONAL(uvd))
                return 0;
 
        if (req == 1) {
                i = usb_control_msg(
-                       ibmcam->dev,
-                       usb_rcvctrlpipe(ibmcam->dev, 0),
+                       uvd->dev,
+                       usb_rcvctrlpipe(uvd->dev, 0),
                        req,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
                        value,
@@ -1315,15 +1149,15 @@ static int usb_ibmcam_veio(
                        sizeof(cp),
                        HZ);
 #if 0
-               printk(KERN_DEBUG "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-                      "(req=$%02x val=$%04x ind=$%04x)\n",
+               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                      "(req=$%02x val=$%04x ind=$%04x)",
                       cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
                       req, value, index);
 #endif
        } else {
                i = usb_control_msg(
-                       ibmcam->dev,
-                       usb_sndctrlpipe(ibmcam->dev, 0),
+                       uvd->dev,
+                       usb_sndctrlpipe(uvd->dev, 0),
                        req,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
                        value,
@@ -1333,15 +1167,15 @@ static int usb_ibmcam_veio(
                        HZ);
        }
        if (i < 0) {
-               printk(KERN_ERR "%s: ERROR=%d. Camera stopped - "
-                      "reconnect or reload driver.\n", proc, i);
-               ibmcam->last_error = i;
+               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
+                   proc, i);
+               uvd->last_error = i;
        }
        return i;
 }
 
 /*
- * usb_ibmcam_calculate_fps()
+ * ibmcam_calculate_fps()
  *
  * This procedure roughly calculates the real frame rate based
  * on FPS code (framerate=NNN option). Actual FPS differs
@@ -1358,13 +1192,13 @@ static int usb_ibmcam_veio(
  * History:
  * 1/18/00  Created.
  */
-static int usb_ibmcam_calculate_fps(void)
+static int ibmcam_calculate_fps(uvd_t *uvd)
 {
        return 3 + framerate*4 + framerate/2;
 }
 
 /*
- * usb_ibmcam_send_FF_04_02()
+ * ibmcam_send_FF_04_02()
  *
  * This procedure sends magic 3-command prefix to the camera.
  * The purpose of this prefix is not known.
@@ -1372,108 +1206,140 @@ static int usb_ibmcam_calculate_fps(void)
  * History:
  * 1/2/00   Created.
  */
-static void usb_ibmcam_send_FF_04_02(struct usb_ibmcam *ibmcam)
+static void ibmcam_send_FF_04_02(uvd_t *uvd)
 {
-       usb_ibmcam_veio(ibmcam, 0, 0x00FF, 0x0127);
-       usb_ibmcam_veio(ibmcam, 0, 0x0004, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124);
+       ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
+       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
 }
 
-static void usb_ibmcam_send_00_04_06(struct usb_ibmcam *ibmcam)
+static void ibmcam_send_00_04_06(uvd_t *uvd)
 {
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0127);
-       usb_ibmcam_veio(ibmcam, 0, 0x0004, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0006, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0006, 0x0124);
 }
 
-static void usb_ibmcam_send_x_00(struct usb_ibmcam *ibmcam, unsigned short x)
+static void ibmcam_send_x_00(uvd_t *uvd, unsigned short x)
 {
-       usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
 }
 
-static void usb_ibmcam_send_x_00_05(struct usb_ibmcam *ibmcam, unsigned short x)
+static void ibmcam_send_x_00_05(uvd_t *uvd, unsigned short x)
 {
-       usb_ibmcam_send_x_00(ibmcam, x);
-       usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
+       ibmcam_send_x_00(uvd, x);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
 }
 
-static void usb_ibmcam_send_x_00_05_02(struct usb_ibmcam *ibmcam, unsigned short x)
+static void ibmcam_send_x_00_05_02(uvd_t *uvd, unsigned short x)
 {
-       usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124);
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
 }
 
-static void usb_ibmcam_send_x_01_00_05(struct usb_ibmcam *ibmcam, unsigned short x)
+static void ibmcam_send_x_01_00_05(uvd_t *uvd, unsigned short x)
 {
-       usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
-       usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
 }
 
-static void usb_ibmcam_send_x_00_05_02_01(struct usb_ibmcam *ibmcam, unsigned short x)
+static void ibmcam_send_x_00_05_02_01(uvd_t *uvd, unsigned short x)
 {
-       usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124);
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
 }
 
-static void usb_ibmcam_send_x_00_05_02_08_01(struct usb_ibmcam *ibmcam, unsigned short x)
+static void ibmcam_send_x_00_05_02_08_01(uvd_t *uvd, unsigned short x)
 {
-       usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0008, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124);
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0008, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
 }
 
-static void usb_ibmcam_Packet_Format1(struct usb_ibmcam *ibmcam, unsigned char fkey, unsigned char val)
+static void ibmcam_Packet_Format1(uvd_t *uvd, unsigned char fkey, unsigned char val)
 {
-       usb_ibmcam_send_x_01_00_05      (ibmcam, unknown_88);
-       usb_ibmcam_send_x_00_05         (ibmcam, fkey);
-       usb_ibmcam_send_x_00_05_02_08_01(ibmcam, val);
-       usb_ibmcam_send_x_00_05         (ibmcam, unknown_88);
-       usb_ibmcam_send_x_00_05_02_01   (ibmcam, fkey);
-       usb_ibmcam_send_x_00_05         (ibmcam, unknown_89);
-       usb_ibmcam_send_x_00            (ibmcam, fkey);
-       usb_ibmcam_send_00_04_06        (ibmcam);
-       usb_ibmcam_veio                 (ibmcam, 1, 0x0000, 0x0126);
-       usb_ibmcam_send_FF_04_02        (ibmcam);
+       ibmcam_send_x_01_00_05(uvd, unknown_88);
+       ibmcam_send_x_00_05(uvd, fkey);
+       ibmcam_send_x_00_05_02_08_01(uvd, val);
+       ibmcam_send_x_00_05(uvd, unknown_88);
+       ibmcam_send_x_00_05_02_01(uvd, fkey);
+       ibmcam_send_x_00_05(uvd, unknown_89);
+       ibmcam_send_x_00(uvd, fkey);
+       ibmcam_send_00_04_06(uvd);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0126);
+       ibmcam_send_FF_04_02(uvd);
 }
 
-static void usb_ibmcam_PacketFormat2(struct usb_ibmcam *ibmcam, unsigned char fkey, unsigned char val)
+static void ibmcam_PacketFormat2(uvd_t *uvd, unsigned char fkey, unsigned char val)
 {
-       usb_ibmcam_send_x_01_00_05      (ibmcam, unknown_88);
-       usb_ibmcam_send_x_00_05         (ibmcam, fkey);
-       usb_ibmcam_send_x_00_05_02      (ibmcam, val);
+       ibmcam_send_x_01_00_05  (uvd, unknown_88);
+       ibmcam_send_x_00_05     (uvd, fkey);
+       ibmcam_send_x_00_05_02  (uvd, val);
 }
 
-static void usb_ibmcam_model2_Packet2(struct usb_ibmcam *ibmcam)
+static void ibmcam_model2_Packet2(uvd_t *uvd)
 {
-       usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x012d);
-       usb_ibmcam_veio(ibmcam, 0, 0xfea3, 0x0124);
+       ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
+       ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
 }
 
-static void usb_ibmcam_model2_Packet1(struct usb_ibmcam *ibmcam, unsigned short v1, unsigned short v2)
+static void ibmcam_model2_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2)
 {
-       usb_ibmcam_veio(ibmcam, 0, 0x00aa, 0x012d);
-       usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x012e);
-       usb_ibmcam_veio(ibmcam, 0, v1,     0x012f);
-       usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x0130);
-       usb_ibmcam_veio(ibmcam, 0, 0xc719, 0x0124);
-       usb_ibmcam_veio(ibmcam, 0, v2,     0x0127);
-
-       usb_ibmcam_model2_Packet2(ibmcam);
+       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+       ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
+       ibmcam_veio(uvd, 0, v1,     0x012f);
+       ibmcam_veio(uvd, 0, 0x00ff, 0x0130);
+       ibmcam_veio(uvd, 0, 0xc719, 0x0124);
+       ibmcam_veio(uvd, 0, v2,     0x0127);
+
+       ibmcam_model2_Packet2(uvd);
 }
 
 /*
- * usb_ibmcam_adjust_contrast()
+ * ibmcam_model3_Packet1()
+ *
+ * 00_0078_012d        
+ * 00_0097_012f
+ * 00_d141_0124        
+ * 00_0096_0127
+ * 00_fea8_0124        
+*/
+static void ibmcam_model3_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2)
+{
+       ibmcam_veio(uvd, 0, 0x0078, 0x012d);
+       ibmcam_veio(uvd, 0, v1,     0x012f);
+       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+       ibmcam_veio(uvd, 0, v2,     0x0127);
+       ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+}
+
+static void ibmcam_model4_BrightnessPacket(uvd_t *uvd, int i)
+{
+       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+       ibmcam_veio(uvd, 0, 0x0026, 0x012f);
+       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+       ibmcam_veio(uvd, 0, i,      0x0127);
+       ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+       ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0038, 0x012d);
+       ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+       ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+       ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+}
+
+/*
+ * ibmcam_adjust_contrast()
  *
  * The contrast value changes from 0 (high contrast) to 15 (low contrast).
  * This is in reverse to usual order of things (such as TV controls), so
@@ -1484,30 +1350,65 @@ static void usb_ibmcam_model2_Packet1(struct usb_ibmcam *ibmcam, unsigned short
  * History:
  * 1/2/00   Created.
  */
-static void usb_ibmcam_adjust_contrast(struct usb_ibmcam *ibmcam)
+static void ibmcam_adjust_contrast(uvd_t *uvd)
 {
-       unsigned char new_contrast = ibmcam->vpic.contrast >> 12;
-       const int ntries = 5;
+       unsigned char a_contrast = uvd->vpic.contrast >> 12;
+       unsigned char new_contrast;
 
-       if (new_contrast >= 16)
-               new_contrast = 15;
-       new_contrast = 15 - new_contrast;
-       if (new_contrast != ibmcam->vpic_old.contrast) {
-               ibmcam->vpic_old.contrast = new_contrast;
-               if (ibmcam->camera_model == IBMCAM_MODEL_1) {
-                       int i;
-                       for (i=0; i < ntries; i++) {
-                               usb_ibmcam_Packet_Format1(ibmcam, contrast_14, new_contrast);
-                               usb_ibmcam_send_FF_04_02(ibmcam);
-                       }
-               } else {
-                       /* Camera model 2 does not have this control; implemented in software. */
+       if (a_contrast >= 16)
+               a_contrast = 15;
+       new_contrast = 15 - a_contrast;
+       if (new_contrast == uvd->vpic_old.contrast)
+               return;
+       uvd->vpic_old.contrast = new_contrast;
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               const int ntries = 5;
+               int i;
+               for (i=0; i < ntries; i++) {
+                       ibmcam_Packet_Format1(uvd, contrast_14, new_contrast);
+                       ibmcam_send_FF_04_02(uvd);
                }
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       case IBMCAM_MODEL_4:
+               /* Models 2, 4 do not have this control; implemented in software. */
+               break;
+       case IBMCAM_MODEL_3:
+       {       /* Preset hardware values */
+               static const struct {
+                       unsigned short cv1;
+                       unsigned short cv2;
+                       unsigned short cv3;
+               } cv[7] = {
+                       { 0x05, 0x05, 0x0f },   /* Minimum */
+                       { 0x04, 0x04, 0x16 },
+                       { 0x02, 0x03, 0x16 },
+                       { 0x02, 0x08, 0x16 },
+                       { 0x01, 0x0c, 0x16 },
+                       { 0x01, 0x0e, 0x16 },
+                       { 0x01, 0x10, 0x16 }    /* Maximum */
+               };
+               int i = a_contrast / 2;
+               RESTRICT_TO_RANGE(i, 0, 6);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1);
+               ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2);
+               ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               break;
+       }
+       default:
+               break;
        }
 }
 
 /*
- * usb_ibmcam_change_lighting_conditions()
+ * ibmcam_change_lighting_conditions()
  *
  * Camera model 1:
  * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
@@ -1524,19 +1425,24 @@ static void usb_ibmcam_adjust_contrast(struct usb_ibmcam *ibmcam)
  * 1/5/00   Created.
  * 2/20/00  Added support for Model 2 cameras.
  */
-static void usb_ibmcam_change_lighting_conditions(struct usb_ibmcam *ibmcam)
+static void ibmcam_change_lighting_conditions(uvd_t *uvd)
 {
-       static const char proc[] = "usb_ibmcam_change_lighting_conditions";
+       static const char proc[] = "ibmcam_change_lighting_conditions";
 
        if (debug > 0)
-               printk(KERN_INFO "%s: Set lighting to %hu.\n", proc, lighting);
+               info("%s: Set lighting to %hu.", proc, lighting);
 
-       if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
                const int ntries = 5;
                int i;
                for (i=0; i < ntries; i++)
-                       usb_ibmcam_Packet_Format1(ibmcam, light_27, (unsigned short) lighting);
-       } else {
+                       ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting);
+               break;
+       }
+       case IBMCAM_MODEL_2:
+#if 0
                /*
                 * This command apparently requires camera to be stopped. My
                 * experiments showed that it -is- possible to alter the lighting
@@ -1546,385 +1452,549 @@ static void usb_ibmcam_change_lighting_conditions(struct usb_ibmcam *ibmcam)
                 * is commented out because it does not work at -any- moment, so its
                 * presence makes no sense. You may use it for experiments.
                 */
-#if 0
-               usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x010c);     /* Stop camera */
-               usb_ibmcam_model2_Packet1(ibmcam, mod2_sensitivity, lighting);
-               usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c);     /* Start camera */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop camera */
+               ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Start camera */
 #endif
+               break;
+       case IBMCAM_MODEL_3:
+       case IBMCAM_MODEL_4:
+       default:
+               break;
        }
 }
 
 /*
- * usb_ibmcam_set_sharpness()
+ * ibmcam_set_sharpness()
  *
  * Cameras model 1 have internal smoothing feature. It is controlled by value in
  * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
  * Recommended value is 4. Cameras model 2 do not have this feature at all.
  */
-static void usb_ibmcam_set_sharpness(struct usb_ibmcam *ibmcam)
+static void ibmcam_set_sharpness(uvd_t *uvd)
 {
-       static const char proc[] = "usb_ibmcam_set_sharpness";
+       static const char proc[] = "ibmcam_set_sharpness";
 
-       if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
                static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
                unsigned short i, sv;
 
                RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
                if (debug > 0)
-                       printk(KERN_INFO "%s: Set sharpness to %hu.\n", proc, sharpness);
+                       info("%s: Set sharpness to %hu.", proc, sharpness);
 
                sv = sa[sharpness - SHARPNESS_MIN];
                for (i=0; i < 2; i++) {
-                       usb_ibmcam_send_x_01_00_05      (ibmcam, unknown_88);
-                       usb_ibmcam_send_x_00_05         (ibmcam, sharp_13);
-                       usb_ibmcam_send_x_00_05_02      (ibmcam, sv);
+                       ibmcam_send_x_01_00_05  (uvd, unknown_88);
+                       ibmcam_send_x_00_05             (uvd, sharp_13);
+                       ibmcam_send_x_00_05_02  (uvd, sv);
                }
-       } else {
-               /* Camera model 2 does not have this control */
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       case IBMCAM_MODEL_4:
+               /* Models 2, 4 do not have this control */
+               break;
+       case IBMCAM_MODEL_3:
+       {       /*
+                * "Use a table of magic numbers.
+                *  This setting doesn't really change much.
+                *  But that's how Windows does it."
+                */
+               static const struct {
+                       unsigned short sv1;
+                       unsigned short sv2;
+                       unsigned short sv3;
+                       unsigned short sv4;
+               } sv[7] = {
+                       { 0x00, 0x00, 0x05, 0x14 },     /* Smoothest */
+                       { 0x01, 0x04, 0x05, 0x14 },
+                       { 0x02, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x05, 0x05, 0x14 },
+                       { 0x03, 0x06, 0x05, 0x14 },
+                       { 0x03, 0x07, 0x05, 0x14 }      /* Sharpest */
+               };
+               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
+               RESTRICT_TO_RANGE(sharpness, 0, 6);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1);
+               ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2);
+               ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3);
+               ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+               break;
+       }
+       default:
+               break;
        }
 }
 
 /*
- * usb_ibmcam_set_brightness()
+ * ibmcam_set_brightness()
  *
  * This procedure changes brightness of the picture.
  */
-static void usb_ibmcam_set_brightness(struct usb_ibmcam *ibmcam)
+static void ibmcam_set_brightness(uvd_t *uvd)
 {
-       static const char proc[] = "usb_ibmcam_set_brightness";
+       static const char proc[] = "ibmcam_set_brightness";
        static const unsigned short n = 1;
-       unsigned short i, j, bv[3];
-
-       bv[0] = bv[1] = bv[2] = ibmcam->vpic.brightness >> 10;
-       if (bv[0] == (ibmcam->vpic_old.brightness >> 10))
-               return;
-       ibmcam->vpic_old.brightness = ibmcam->vpic.brightness;
 
        if (debug > 0)
-               printk(KERN_INFO "%s: Set brightness to (%hu,%hu,%hu)\n",
-                      proc, bv[0], bv[1], bv[2]);
+               info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness);
 
-       if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               unsigned short i, j, bv[3];
+               bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10;
+               if (bv[0] == (uvd->vpic_old.brightness >> 10))
+                       return;
+               uvd->vpic_old.brightness = bv[0];
                for (j=0; j < 3; j++)
                        for (i=0; i < n; i++)
-                               usb_ibmcam_Packet_Format1(ibmcam, bright_3x[j], bv[j]);
-       } else {
-               i = ibmcam->vpic.brightness >> 12;      /* 0 .. 15 */
+                               ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]);
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       {
+               unsigned short i, j;
+               i = uvd->vpic.brightness >> 12; /* 0 .. 15 */
                j = 0x60 + i * ((0xee - 0x60) / 16);    /* 0x60 .. 0xee or so */
-               usb_ibmcam_model2_Packet1(ibmcam, mod2_brightness, j);
+               if (uvd->vpic_old.brightness == j)
+                       break;
+               uvd->vpic_old.brightness = j;
+               ibmcam_model2_Packet1(uvd, mod2_brightness, j);
+               break;
+       }
+       case IBMCAM_MODEL_3:
+       {
+               /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
+               unsigned short i =
+                       0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1)));
+               RESTRICT_TO_RANGE(i, 0x0C, 0x3F);
+               if (uvd->vpic_old.brightness == i)
+                       break;
+               uvd->vpic_old.brightness = i;
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0036, i);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+               break;
+       }
+       case IBMCAM_MODEL_4:
+       {
+               /* Model 4: Brightness range 'i' in [0x04..0xb4] */
+               unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1)));
+               RESTRICT_TO_RANGE(i, 0x04, 0xb4);
+               if (uvd->vpic_old.brightness == i)
+                       break;
+               uvd->vpic_old.brightness = i;
+               ibmcam_model4_BrightnessPacket(uvd, i);
+               break;
+       }
+       default:
+               break;
        }
 }
 
-static void usb_ibmcam_model2_set_hue(struct usb_ibmcam *ibmcam)
+static void ibmcam_set_hue(uvd_t *uvd)
 {
-       unsigned short hue = ibmcam->vpic.hue >> 9; /* 0 .. 7F */
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_2:
+       {
+               unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */
+               if (uvd->vpic_old.hue == hue)
+                       return;
+               uvd->vpic_old.hue = hue;
+               ibmcam_model2_Packet1(uvd, mod2_hue, hue);
+               /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */
+               break;
+       }
+       case IBMCAM_MODEL_3:
+       {
+#if 0 /* This seems not to work. No problem, will fix programmatically */
+               unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1)));
+               RESTRICT_TO_RANGE(hue, 0x05, 0x37);
+               if (uvd->vpic_old.hue == hue)
+                       return;
+               uvd->vpic_old.hue = hue;
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x007e, hue);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+#endif
+               break;
+       }
+       case IBMCAM_MODEL_4:
+       {
+               unsigned short r_gain, g_gain, b_gain, hue;
 
-       usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg, hue);
-       /* usb_ibmcam_model2_Packet1(ibmcam, mod2_saturation, sat); */
+               /*
+                * I am not sure r/g/b_gain variables exactly control gain
+                * of those channels. Most likely they subtly change some
+                * very internal image processing settings in the camera.
+                * In any case, here is what they do, and feel free to tweak:
+                *
+                * r_gain: seriously affects red gain
+                * g_gain: seriously affects green gain
+                * b_gain: seriously affects blue gain
+                * hue: changes average color from violet (0) to red (0xFF)
+                *
+                * These settings are preset for a decent white balance in
+                * 320x240, 352x288 modes. Low-res modes exhibit higher contrast
+                * and therefore may need different values here.
+                */
+               hue = 20 + (uvd->vpic.hue >> 9);
+               switch (uvd->videosize) {
+               case VIDEOSIZE_128x96:
+                       r_gain = 90;
+                       g_gain = 166;
+                       b_gain = 175;
+                       break;
+               case VIDEOSIZE_160x120:
+                       r_gain = 70;
+                       g_gain = 166;
+                       b_gain = 185;
+                       break;
+               case VIDEOSIZE_176x144:
+                       r_gain = 160;
+                       g_gain = 175;
+                       b_gain = 185;
+                       break;
+               default:
+                       r_gain = 120;
+                       g_gain = 166;
+                       b_gain = 175;
+                       break;
+               }
+               RESTRICT_TO_RANGE(hue, 1, 0x7f);
+
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, g_gain, 0x0127);    /* Green gain */
+               ibmcam_veio(uvd, 0, r_gain, 0x012e);    /* Red gain */
+               ibmcam_veio(uvd, 0, b_gain, 0x0130);    /* Blue gain */
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, hue,    0x012d);    /* Hue */
+               ibmcam_veio(uvd, 0, 0xf545, 0x0124);
+               break;
+       }
+       default:
+               break;
+       }
 }
 
 /*
- * usb_ibmcam_adjust_picture()
+ * ibmcam_adjust_picture()
  *
  * This procedure gets called from V4L interface to update picture settings.
  * Here we change brightness and contrast.
  */
-static void usb_ibmcam_adjust_picture(struct usb_ibmcam *ibmcam)
+static void ibmcam_adjust_picture(uvd_t *uvd)
 {
-       usb_ibmcam_adjust_contrast(ibmcam);
-       usb_ibmcam_set_brightness(ibmcam);
-       if (ibmcam->camera_model == IBMCAM_MODEL_2) {
-               usb_ibmcam_model2_set_hue(ibmcam);
-       }
+       ibmcam_adjust_contrast(uvd);
+       ibmcam_set_brightness(uvd);
+       ibmcam_set_hue(uvd);
 }
 
-static int usb_ibmcam_model1_setup(struct usb_ibmcam *ibmcam)
+static int ibmcam_model1_setup(uvd_t *uvd)
 {
        const int ntries = 5;
        int i;
 
-       usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0128);
-       usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100);
-       usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100);       /* LED On  */
-       usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100);
-       usb_ibmcam_veio(ibmcam, 0, 0x81, 0x0100);       /* LED Off */
-       usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100);
-       usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100);       /* LED On  */
-       usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0108);
-
-       usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0112);
-       usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0115);
-       usb_ibmcam_veio(ibmcam, 0, 0x06, 0x0115);
-       usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0116);
-       usb_ibmcam_veio(ibmcam, 0, 0x44, 0x0116);
-       usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0116);
-       usb_ibmcam_veio(ibmcam, 0, 0x40, 0x0116);
-       usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0115);
-       usb_ibmcam_veio(ibmcam, 0, 0x0e, 0x0115);
-       usb_ibmcam_veio(ibmcam, 0, 0x19, 0x012c);
-
-       usb_ibmcam_Packet_Format1(ibmcam, 0x00, 0x1e);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x0d);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x09);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x3b, 0x00);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x28, 0x22);
-       usb_ibmcam_Packet_Format1(ibmcam, light_27, 0);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1f);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x08);
+       ibmcam_veio(uvd, 1, 0x00, 0x0128);
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 0, 0x01, 0x0108);
+
+       ibmcam_veio(uvd, 0, 0x03, 0x0112);
+       ibmcam_veio(uvd, 1, 0x00, 0x0115);
+       ibmcam_veio(uvd, 0, 0x06, 0x0115);
+       ibmcam_veio(uvd, 1, 0x00, 0x0116);
+       ibmcam_veio(uvd, 0, 0x44, 0x0116);
+       ibmcam_veio(uvd, 1, 0x00, 0x0116);
+       ibmcam_veio(uvd, 0, 0x40, 0x0116);
+       ibmcam_veio(uvd, 1, 0x00, 0x0115);
+       ibmcam_veio(uvd, 0, 0x0e, 0x0115);
+       ibmcam_veio(uvd, 0, 0x19, 0x012c);
+
+       ibmcam_Packet_Format1(uvd, 0x00, 0x1e);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x0d);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x09);
+       ibmcam_Packet_Format1(uvd, 0x3b, 0x00);
+       ibmcam_Packet_Format1(uvd, 0x28, 0x22);
+       ibmcam_Packet_Format1(uvd, light_27, 0);
+       ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
 
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x2c, 0x00);
+               ibmcam_Packet_Format1(uvd, 0x2c, 0x00);
 
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x30, 0x14);
-
-       usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x01, 0xe1);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x02, 0xcd);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x03, 0xcd);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x04, 0xfa);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00);
-
-       usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x0a, 0x37);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x0b, 0xb8);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x0c, 0xf3);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x0d, 0xe3);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x0e, 0x0d);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x0f, 0xf2);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x10, 0xd5);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x11, 0xba);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x12, 0x53);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00);
-
-       usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x16, 0x00);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x17, 0x28);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x18, 0x7d);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x19, 0xbe);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff);
-       usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00);
+               ibmcam_Packet_Format1(uvd, 0x30, 0x14);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x01, 0xe1);
+       ibmcam_PacketFormat2(uvd, 0x02, 0xcd);
+       ibmcam_PacketFormat2(uvd, 0x03, 0xcd);
+       ibmcam_PacketFormat2(uvd, 0x04, 0xfa);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x0a, 0x37);
+       ibmcam_PacketFormat2(uvd, 0x0b, 0xb8);
+       ibmcam_PacketFormat2(uvd, 0x0c, 0xf3);
+       ibmcam_PacketFormat2(uvd, 0x0d, 0xe3);
+       ibmcam_PacketFormat2(uvd, 0x0e, 0x0d);
+       ibmcam_PacketFormat2(uvd, 0x0f, 0xf2);
+       ibmcam_PacketFormat2(uvd, 0x10, 0xd5);
+       ibmcam_PacketFormat2(uvd, 0x11, 0xba);
+       ibmcam_PacketFormat2(uvd, 0x12, 0x53);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x16, 0x00);
+       ibmcam_PacketFormat2(uvd, 0x17, 0x28);
+       ibmcam_PacketFormat2(uvd, 0x18, 0x7d);
+       ibmcam_PacketFormat2(uvd, 0x19, 0xbe);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
 
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x00, 0x18);
+               ibmcam_Packet_Format1(uvd, 0x00, 0x18);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x13, 0x18);
+               ibmcam_Packet_Format1(uvd, 0x13, 0x18);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x14, 0x06);
+               ibmcam_Packet_Format1(uvd, 0x14, 0x06);
 
        /* This is default brightness */
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x31, 0x37);
+               ibmcam_Packet_Format1(uvd, 0x31, 0x37);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x32, 0x46);
+               ibmcam_Packet_Format1(uvd, 0x32, 0x46);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x33, 0x55);
+               ibmcam_Packet_Format1(uvd, 0x33, 0x55);
 
-       usb_ibmcam_Packet_Format1(ibmcam, 0x2e, 0x04);
+       ibmcam_Packet_Format1(uvd, 0x2e, 0x04);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x2d, 0x04);
+               ibmcam_Packet_Format1(uvd, 0x2d, 0x04);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x29, 0x80);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x2c, 0x01);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x30, 0x17);
-       usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x08);
+               ibmcam_Packet_Format1(uvd, 0x29, 0x80);
+       ibmcam_Packet_Format1(uvd, 0x2c, 0x01);
+       ibmcam_Packet_Format1(uvd, 0x30, 0x17);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x34, 0x00);
+               ibmcam_Packet_Format1(uvd, 0x34, 0x00);
 
-       usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0101);
-       usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010a);
+       ibmcam_veio(uvd, 0, 0x00, 0x0101);
+       ibmcam_veio(uvd, 0, 0x00, 0x010a);
 
-       switch (videosize) {
+       switch (uvd->videosize) {
        case VIDEOSIZE_128x96:
-               usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0103);
-               usb_ibmcam_veio(ibmcam, 0, 0x60, 0x0105);
-               usb_ibmcam_veio(ibmcam, 0, 0x0c, 0x010b);
-               usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x0b, 0x011d);
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0129);
+               ibmcam_veio(uvd, 0, 0x80, 0x0103);
+               ibmcam_veio(uvd, 0, 0x60, 0x0105);
+               ibmcam_veio(uvd, 0, 0x0c, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x0b, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x00, 0x0129);
                break;
        case VIDEOSIZE_176x144:
-               usb_ibmcam_veio(ibmcam, 0, 0xb0, 0x0103);
-               usb_ibmcam_veio(ibmcam, 0, 0x8f, 0x0105);
-               usb_ibmcam_veio(ibmcam, 0, 0x06, 0x010b);
-               usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x0d, 0x011d);
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0129);
+               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
+               ibmcam_veio(uvd, 0, 0x8f, 0x0105);
+               ibmcam_veio(uvd, 0, 0x06, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x0d, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x03, 0x0129);
                break;
        case VIDEOSIZE_352x288:
-               usb_ibmcam_veio(ibmcam, 0, 0xb0, 0x0103);
-               usb_ibmcam_veio(ibmcam, 0, 0x90, 0x0105);
-               usb_ibmcam_veio(ibmcam, 0, 0x02, 0x010b);
-               usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x05, 0x011d);
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0129);
+               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
+               ibmcam_veio(uvd, 0, 0x90, 0x0105);
+               ibmcam_veio(uvd, 0, 0x02, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x05, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x00, 0x0129);
                break;
        }
 
-       usb_ibmcam_veio(ibmcam, 0, 0xff, 0x012b);
+       ibmcam_veio(uvd, 0, 0xff, 0x012b);
 
        /* This is another brightness - don't know why */
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x31, 0xc3);
+               ibmcam_Packet_Format1(uvd, 0x31, 0xc3);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x32, 0xd2);
+               ibmcam_Packet_Format1(uvd, 0x32, 0xd2);
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, 0x33, 0xe1);
+               ibmcam_Packet_Format1(uvd, 0x33, 0xe1);
 
        /* Default contrast */
        for (i=0; i < ntries; i++)
-               usb_ibmcam_Packet_Format1(ibmcam, contrast_14, 0x0a);
+               ibmcam_Packet_Format1(uvd, contrast_14, 0x0a);
 
        /* Default sharpness */
        for (i=0; i < 2; i++)
-               usb_ibmcam_PacketFormat2(ibmcam, sharp_13, 0x1a);       /* Level 4 FIXME */
+               ibmcam_PacketFormat2(uvd, sharp_13, 0x1a);      /* Level 4 FIXME */
 
        /* Default lighting conditions */
-       usb_ibmcam_Packet_Format1(ibmcam, light_27, lighting); /* 0=Bright 2=Low */
+       ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */
 
        /* Assorted init */
 
-       switch (videosize) {
+       switch (uvd->videosize) {
        case VIDEOSIZE_128x96:
-               usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1e);
-               usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x36, 0x0102);
-               usb_ibmcam_veio(ibmcam, 0, 0x1a, 0x0104);
-               usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x2b, 0x011c);
-               usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a);       /* Same everywhere */
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x36, 0x0102);
+               ibmcam_veio(uvd, 0, 0x1a, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
 #if 0
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0106);
-               usb_ibmcam_veio(ibmcam, 0, 0x38, 0x0107);
+               ibmcam_veio(uvd, 0, 0x00, 0x0106);
+               ibmcam_veio(uvd, 0, 0x38, 0x0107);
 #else
-               usb_ibmcam_veio(ibmcam, 0, 0x02, 0x0106);
-               usb_ibmcam_veio(ibmcam, 0, 0x2a, 0x0107);
+               ibmcam_veio(uvd, 0, 0x02, 0x0106);
+               ibmcam_veio(uvd, 0, 0x2a, 0x0107);
 #endif
                break;
        case VIDEOSIZE_176x144:
-               usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1e);
-               usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x04, 0x0102);
-               usb_ibmcam_veio(ibmcam, 0, 0x02, 0x0104);
-               usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x2b, 0x011c);
-               usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0106);
-               usb_ibmcam_veio(ibmcam, 0, 0xca, 0x0107);
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x04, 0x0102);
+               ibmcam_veio(uvd, 0, 0x02, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x01, 0x0106);
+               ibmcam_veio(uvd, 0, 0xca, 0x0107);
                break;
        case VIDEOSIZE_352x288:
-               usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1f);
-               usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x08, 0x0102);
-               usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0104);
-               usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x2f, 0x011c);
-               usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a);       /* Same everywhere */
-               usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0106);
-               usb_ibmcam_veio(ibmcam, 0, 0xf6, 0x0107);
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x08, 0x0102);
+               ibmcam_veio(uvd, 0, 0x01, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2f, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x03, 0x0106);
+               ibmcam_veio(uvd, 0, 0xf6, 0x0107);
                break;
        }
-       return IBMCAM_IS_OPERATIONAL(ibmcam);
+       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
 }
 
-static int usb_ibmcam_model2_setup(struct usb_ibmcam *ibmcam)
+static int ibmcam_model2_setup(uvd_t *uvd)
 {
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0100);     /* LED on */
-       usb_ibmcam_veio(ibmcam, 1, 0x0000, 0x0116);
-       usb_ibmcam_veio(ibmcam, 0, 0x0060, 0x0116);
-       usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0112);
-       usb_ibmcam_veio(ibmcam, 0, 0x00bc, 0x012c);
-       usb_ibmcam_veio(ibmcam, 0, 0x0008, 0x012b);
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0108);
-       usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0133);
-       usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0102);
-       switch (videosize) {
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
+       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
+       ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+       ibmcam_veio(uvd, 0, 0x0008, 0x012b);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+       switch (uvd->videosize) {
        case VIDEOSIZE_176x144:
-               usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103);     /* All except 320x240 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104);     /* Same */
-               usb_ibmcam_veio(ibmcam, 0, 0x0024, 0x0105);     /* 176x144, 352x288 */
-               usb_ibmcam_veio(ibmcam, 0, 0x00b9, 0x010a);     /* Unique to this mode */
-               usb_ibmcam_veio(ibmcam, 0, 0x0038, 0x0119);     /* Unique to this mode */
-               usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106);     /* Same */
-               usb_ibmcam_veio(ibmcam, 0, 0x0090, 0x0107);     /* Unique to every mode*/
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0090, 0x0107);    /* Unique to every mode*/
                break;
        case VIDEOSIZE_320x240:
-               usb_ibmcam_veio(ibmcam, 0, 0x0028, 0x0103);     /* Unique to this mode */
-               usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104);     /* Same */
-               usb_ibmcam_veio(ibmcam, 0, 0x001e, 0x0105);     /* 320x240, 352x240 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a);     /* All except 176x144 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119);     /* All except 176x144 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106);     /* Same */
-               usb_ibmcam_veio(ibmcam, 0, 0x0098, 0x0107);     /* Unique to every mode*/
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0098, 0x0107);    /* Unique to every mode*/
                break;
        case VIDEOSIZE_352x240:
-               usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103);     /* All except 320x240 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104);     /* Same */
-               usb_ibmcam_veio(ibmcam, 0, 0x001e, 0x0105);     /* 320x240, 352x240 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a);     /* All except 176x144 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119);     /* All except 176x144 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106);     /* Same */
-               usb_ibmcam_veio(ibmcam, 0, 0x00da, 0x0107);     /* Unique to every mode*/
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x00da, 0x0107);    /* Unique to every mode*/
                break;
        case VIDEOSIZE_352x288:
-               usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103);     /* All except 320x240 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104);     /* Same */
-               usb_ibmcam_veio(ibmcam, 0, 0x0024, 0x0105);     /* 176x144, 352x288 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a);     /* All except 176x144 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119);     /* All except 176x144 */
-               usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106);     /* Same */
-               usb_ibmcam_veio(ibmcam, 0, 0x00fe, 0x0107);     /* Unique to every mode*/
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x00fe, 0x0107);    /* Unique to every mode*/
                break;
        }
-       return IBMCAM_IS_OPERATIONAL(ibmcam);
+       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
 }
 
 /*
- * usb_ibmcam_model1_setup_after_video_if()
+ * ibmcam_model1_setup_after_video_if()
  *
  * This code adds finishing touches to the video data interface.
  * Here we configure the frame rate and turn on the LED.
  */
-static void usb_ibmcam_model1_setup_after_video_if(struct usb_ibmcam *ibmcam)
+static void ibmcam_model1_setup_after_video_if(uvd_t *uvd)
 {
        unsigned short internal_frame_rate;
 
        RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
        internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
-       usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100);       /* LED On  */
-       usb_ibmcam_veio(ibmcam, 0, internal_frame_rate, 0x0111);
-       usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0114);
-       usb_ibmcam_veio(ibmcam, 0, 0xc0, 0x010c);
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111);
+       ibmcam_veio(uvd, 0, 0x01, 0x0114);
+       ibmcam_veio(uvd, 0, 0xc0, 0x010c);
 }
 
-static void usb_ibmcam_model2_setup_after_video_if(struct usb_ibmcam *ibmcam)
+static void ibmcam_model2_setup_after_video_if(uvd_t *uvd)
 {
-       unsigned short setup_model2_rg, setup_model2_rg2, setup_model2_sat, setup_model2_yb;
+       unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
 
-       usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0100);     /* LED on */
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
 
-       switch (videosize) {
+       switch (uvd->videosize) {
        case VIDEOSIZE_176x144:
-               usb_ibmcam_veio(ibmcam, 0, 0x0050, 0x0111);
-               usb_ibmcam_veio(ibmcam, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0050, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
                break;
        case VIDEOSIZE_320x240:
        case VIDEOSIZE_352x240:
        case VIDEOSIZE_352x288:
-               usb_ibmcam_veio(ibmcam, 0, 0x0040, 0x0111);
-               usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0040, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
                break;
        }
-       usb_ibmcam_veio(ibmcam, 0, 0x009b, 0x010f);
-       usb_ibmcam_veio(ibmcam, 0, 0x00bb, 0x010f);
+       ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+       ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
 
        /*
         * Hardware settings, may affect CMOS sensor; not user controls!
@@ -1939,52 +2009,52 @@ static void usb_ibmcam_model2_setup_after_video_if(struct usb_ibmcam *ibmcam)
         * 0x002c: hardware setting (related to scan lines)
         * 0x002e: stops video stream, probably important h/w setting
         */
-       usb_ibmcam_model2_Packet1(ibmcam, 0x000a, 0x005c);
-       usb_ibmcam_model2_Packet1(ibmcam, 0x0004, 0x0000);
-       usb_ibmcam_model2_Packet1(ibmcam, 0x0006, 0x00fb);
-       usb_ibmcam_model2_Packet1(ibmcam, 0x0008, 0x0000);
-       usb_ibmcam_model2_Packet1(ibmcam, 0x000c, 0x0009);
-       usb_ibmcam_model2_Packet1(ibmcam, 0x0012, 0x000a);
-       usb_ibmcam_model2_Packet1(ibmcam, 0x002a, 0x0000);
-       usb_ibmcam_model2_Packet1(ibmcam, 0x002c, 0x0000);
-       usb_ibmcam_model2_Packet1(ibmcam, 0x002e, 0x0008);
+       ibmcam_model2_Packet1(uvd, 0x000a, 0x005c);
+       ibmcam_model2_Packet1(uvd, 0x0004, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb);
+       ibmcam_model2_Packet1(uvd, 0x0008, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x000c, 0x0009);
+       ibmcam_model2_Packet1(uvd, 0x0012, 0x000a);
+       ibmcam_model2_Packet1(uvd, 0x002a, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x002c, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x002e, 0x0008);
 
        /*
         * Function 0x0030 pops up all over the place. Apparently
         * it is a hardware control register, with every bit assigned to
         * do something.
         */
-       usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x0030, 0x0000);
 
        /*
         * Magic control of CMOS sensor. Only lower values like
         * 0-3 work, and picture shifts left or right. Don't change.
         */
-       switch (videosize) {
+       switch (uvd->videosize) {
        case VIDEOSIZE_176x144:
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0002);
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0002); /* Horizontal shift */
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x004a); /* Another hardware setting */
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0002);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
                break;
        case VIDEOSIZE_320x240:
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0009);
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0005); /* Horizontal shift */
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x0044); /* Another hardware setting */
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */
                break;
        case VIDEOSIZE_352x240:
                /* This mode doesn't work as Windows programs it; changed to work */
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0009); /* Windows sets this to 8 */
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0003); /* Horizontal shift */
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
                break;
        case VIDEOSIZE_352x288:
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0003);
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0002); /* Horizontal shift */
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x004a); /* Another hardware setting */
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0003);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
                break;
        }
 
-       usb_ibmcam_model2_Packet1(ibmcam, mod2_brightness, 0x005a);
+       ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a);
 
        /*
         * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest).
@@ -2008,7 +2078,7 @@ static void usb_ibmcam_model2_setup_after_video_if(struct usb_ibmcam *ibmcam)
 
                RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
                i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN;
-               switch (videosize) {
+               switch (uvd->videosize) {
                case VIDEOSIZE_176x144:
                        hw_fps = 6 + i_framerate*4;
                        break;
@@ -2022,10 +2092,10 @@ static void usb_ibmcam_model2_setup_after_video_if(struct usb_ibmcam *ibmcam)
                        hw_fps = 28 + i_framerate/2;
                        break;
                }
-               if (debug > 0)
-                       printk(KERN_DEBUG "Framerate (hardware): %hd.\n", hw_fps);
+               if (uvd->debug > 0)
+                       info("Framerate (hardware): %hd.", hw_fps);
                RESTRICT_TO_RANGE(hw_fps, 0, 31);
-               usb_ibmcam_model2_Packet1(ibmcam, mod2_set_framerate, hw_fps);
+               ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
        }
 
        /*
@@ -2034,28 +2104,22 @@ static void usb_ibmcam_model2_setup_after_video_if(struct usb_ibmcam *ibmcam)
         * does not allow arbitrary values and apparently is a bit mask, to
         * be activated only at appropriate time. Don't change it randomly!
         */
-       switch (videosize) {
+       switch (uvd->videosize) {
        case VIDEOSIZE_176x144:
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x00c2);
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2);
                break;
        case VIDEOSIZE_320x240:
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0044);
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0044);
                break;
        case VIDEOSIZE_352x240:
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0046);
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0046);
                break;
        case VIDEOSIZE_352x288:
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0048);
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0048);
                break;
        }
 
-       usb_ibmcam_model2_Packet1(ibmcam, mod2_sensitivity, lighting);
-
-       if (init_model2_rg >= 0) {
-               RESTRICT_TO_RANGE(init_model2_rg, 0, 255);
-               setup_model2_rg = init_model2_rg;
-       } else
-               setup_model2_rg = 0x0070;
+       ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
 
        if (init_model2_rg2 >= 0) {
                RESTRICT_TO_RANGE(init_model2_rg2, 0, 255);
@@ -2075,806 +2139,1469 @@ static void usb_ibmcam_model2_setup_after_video_if(struct usb_ibmcam *ibmcam)
        } else
                setup_model2_yb = 0x00a0;
 
-       usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg2, setup_model2_rg2);
-       usb_ibmcam_model2_Packet1(ibmcam, mod2_saturation, setup_model2_sat);
-       usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_yb, setup_model2_yb);
-       usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg, setup_model2_rg);
+       ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2);
+       ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat);
+       ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb);
+       ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */;
 
        /* Hardware control command */
-       usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0004);
+       ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
 
-       usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c);     /* Go camera, go! */
-       usb_clear_halt(ibmcam->dev, ibmcam->video_endp);
+       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go camera, go! */
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
 }
 
-/*
- * usb_ibmcam_setup_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void usb_ibmcam_setup_video_stop(struct usb_ibmcam *ibmcam)
+static void ibmcam_model4_setup_after_video_if(uvd_t *uvd)
 {
-       if (ibmcam->camera_model == IBMCAM_MODEL_1) {
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c);
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c);
-               usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0114);
-               usb_ibmcam_veio(ibmcam, 0, 0xc0, 0x010c);
-               usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c);
-               usb_ibmcam_send_FF_04_02(ibmcam);
-               usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100);
-               usb_ibmcam_veio(ibmcam, 0, 0x81, 0x0100);       /* LED Off */
-       } else if (ibmcam->camera_model == IBMCAM_MODEL_2) {
-               usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x010c);     /* Stop the camera */
-
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0004);
-
-               usb_ibmcam_veio(ibmcam, 0, 0x0080, 0x0100);     /* LED Off */
-               usb_ibmcam_veio(ibmcam, 0, 0x0020, 0x0111);
-               usb_ibmcam_veio(ibmcam, 0, 0x00a0, 0x0111);
-
-               usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0002);
-
-               usb_ibmcam_veio(ibmcam, 0, 0x0020, 0x0111);
-               usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0112);
-       }
-}
-
-/*
- * usb_ibmcam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- *
- * History:
- * 1/2/00   Created.
- */
-static void usb_ibmcam_reinit_iso(struct usb_ibmcam *ibmcam, int do_stop)
-{
-       if (ibmcam->camera_model == IBMCAM_MODEL_1) {
-               if (do_stop)
-                       usb_ibmcam_setup_video_stop(ibmcam);
-               usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0114);
-               usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c);
-               usb_clear_halt(ibmcam->dev, ibmcam->video_endp);
-               usb_ibmcam_model1_setup_after_video_if(ibmcam);
-       } else if (ibmcam->camera_model == IBMCAM_MODEL_2) {
-               usb_ibmcam_model2_setup_after_video_if(ibmcam);
-       }
+       switch (uvd->videosize) {
+       case VIDEOSIZE_128x96:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d8, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000b, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0025, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0048, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0035, 0x012e);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0048, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0090, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d6, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0018, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0007, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0001, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x002a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
+               ibmcam_veio(uvd, 0, 0x006d, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00f2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x008c, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0006, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0002, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00cf, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0025, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0048, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break; 
+       }
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
 }
 
-/*
- * ibmcam_init_isoc()
- *
- * History:
- * 1/27/00  Used ibmcam->iface, ibmcam->ifaceAltActive instead of hardcoded values.
- *          Simplified by using for loop, allowed any number of URBs.
- */
-static int ibmcam_init_isoc(struct usb_ibmcam *ibmcam)
+static void ibmcam_model3_setup_after_video_if(uvd_t *uvd)
 {
-       struct usb_device *dev = ibmcam->dev;
-       int i, err;
-
-       if (!IBMCAM_IS_OPERATIONAL(ibmcam))
-               return -EFAULT;
-
-       ibmcam->compress = 0;
-       ibmcam->curframe = -1;
-       ibmcam->cursbuf = 0;
-       ibmcam->scratchlen = 0;
-
-       /* Alternate interface 1 is is the biggest frame size */
-       i = usb_set_interface(dev, ibmcam->iface, ibmcam->ifaceAltActive);
-       if (i < 0) {
-               printk(KERN_ERR "usb_set_interface error\n");
-               ibmcam->last_error = i;
-               return -EBUSY;
-       }
-       usb_ibmcam_change_lighting_conditions(ibmcam);
-       usb_ibmcam_set_sharpness(ibmcam);
-       usb_ibmcam_reinit_iso(ibmcam, 0);
-
-       /* We double buffer the Iso lists */
-
-       for (i=0; i < IBMCAM_NUMSBUF; i++) {
-               int j, k;
-               urb_t *urb;
-
-               urb = usb_alloc_urb(FRAMES_PER_DESC);
-               if (urb == NULL) {
-                       printk(KERN_ERR "ibmcam_init_isoc: usb_init_isoc() failed.\n");
-                       return -ENOMEM;
-               }
-               ibmcam->sbuf[i].urb = urb;
-               urb->dev = dev;
-               urb->context = ibmcam;
-               urb->pipe = usb_rcvisocpipe(dev, ibmcam->video_endp);
-               urb->transfer_flags = USB_ISO_ASAP;
-               urb->transfer_buffer = ibmcam->sbuf[i].data;
-               urb->complete = ibmcam_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = ibmcam->iso_packet_len * FRAMES_PER_DESC;
-               for (j=k=0; j < FRAMES_PER_DESC; j++, k += ibmcam->iso_packet_len) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length = ibmcam->iso_packet_len;
-               }
-       }
-
-       /* Link URBs into a ring so that they invoke each other infinitely */
-       for (i=0; i < IBMCAM_NUMSBUF; i++) {
-               if ((i+1) < IBMCAM_NUMSBUF)
-                       ibmcam->sbuf[i].urb->next = ibmcam->sbuf[i+1].urb;
-               else
-                       ibmcam->sbuf[i].urb->next = ibmcam->sbuf[0].urb;
-       }
-
-       /* Submit all URBs */
-       for (i=0; i < IBMCAM_NUMSBUF; i++) {
-               err = usb_submit_urb(ibmcam->sbuf[i].urb);
-               if (err)
-                       printk(KERN_ERR "ibmcam_init_isoc: usb_run_isoc(%d) ret %d\n",
-                              i, err);
-       }
-
-       ibmcam->streaming = 1;
-       /* printk(KERN_DEBUG "streaming=1 ibmcam->video_endp=$%02x\n", ibmcam->video_endp); */
-       return 0;
-}
+       int i;
+       /*
+        * 01.01.08 - Added for RCA video in support -LO
+        * This struct is used to init the Model3 cam to use the RCA video in port
+        * instead of the CCD sensor.
+        */
+       static const struct struct_initData initData[] = {
+               {0, 0x0000, 0x010c},
+               {0, 0x0006, 0x012c},
+               {0, 0x0078, 0x012d},
+               {0, 0x0046, 0x012f},
+               {0, 0xd141, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfea8, 0x0124},
+               {1, 0x0000, 0x0116},
+               {0, 0x0064, 0x0116},
+               {1, 0x0000, 0x0115},
+               {0, 0x0003, 0x0115},
+               {0, 0x0008, 0x0123},
+               {0, 0x0000, 0x0117},
+               {0, 0x0000, 0x0112},
+               {0, 0x0080, 0x0100},
+               {0, 0x0000, 0x0100},
+               {1, 0x0000, 0x0116},
+               {0, 0x0060, 0x0116},
+               {0, 0x0002, 0x0112},
+               {0, 0x0000, 0x0123},
+               {0, 0x0001, 0x0117},
+               {0, 0x0040, 0x0108},
+               {0, 0x0019, 0x012c},
+               {0, 0x0040, 0x0116},
+               {0, 0x000a, 0x0115},
+               {0, 0x000b, 0x0115},
+               {0, 0x0078, 0x012d},
+               {0, 0x0046, 0x012f},
+               {0, 0xd141, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfea8, 0x0124},
+               {0, 0x0064, 0x0116},
+               {0, 0x0000, 0x0115},
+               {0, 0x0001, 0x0115},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00aa, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f2, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x000f, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f8, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00fc, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f9, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x003c, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0027, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0019, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0021, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0006, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0045, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002a, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x000e, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002b, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f4, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002c, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0004, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002d, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0014, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002e, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0003, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002f, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0003, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0014, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0053, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0x0000, 0x0101},
+               {0, 0x00a0, 0x0103},
+               {0, 0x0078, 0x0105},
+               {0, 0x0000, 0x010a},
+               {0, 0x0024, 0x010b},
+               {0, 0x0028, 0x0119},
+               {0, 0x0088, 0x011b},
+               {0, 0x0002, 0x011d},
+               {0, 0x0003, 0x011e},
+               {0, 0x0000, 0x0129},
+               {0, 0x00fc, 0x012b},
+               {0, 0x0008, 0x0102},
+               {0, 0x0000, 0x0104},
+               {0, 0x0008, 0x011a},
+               {0, 0x0028, 0x011c},
+               {0, 0x0021, 0x012a},
+               {0, 0x0000, 0x0118},
+               {0, 0x0000, 0x0132},
+               {0, 0x0000, 0x0109},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0031, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00dc, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0032, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0020, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0030, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0008, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0x0003, 0x0106},
+               {0, 0x0062, 0x0107},
+               {0, 0x0003, 0x0111},
+       };
+#define NUM_INIT_DATA 
 
-/*
- * ibmcam_stop_isoc()
- *
- * This procedure stops streaming and deallocates URBs. Then it
- * activates zero-bandwidth alt. setting of the video interface.
- *
- * History:
- * 1/22/00  Corrected order of actions to work after surprise removal.
- * 1/27/00  Used ibmcam->iface, ibmcam->ifaceAltInactive instead of hardcoded values.
- */
-static void ibmcam_stop_isoc(struct usb_ibmcam *ibmcam)
-{
-       static const char proc[] = "ibmcam_stop_isoc";
-       int i, j;
+       unsigned short compression = 0; /* 0=none, 7=best frame rate  */
+       int f_rate; /* 0=Fastest 7=slowest */
 
-       if (!ibmcam->streaming || (ibmcam->dev == NULL))
+       if (IBMCAM_T(uvd)->initialized)
                return;
 
-       /* Unschedule all of the iso td's */
-       for (i=0; i < IBMCAM_NUMSBUF; i++) {
-               j = usb_unlink_urb(ibmcam->sbuf[i].urb);
-               if (j < 0)
-                       printk(KERN_ERR "%s: usb_unlink_urb() error %d.\n", proc, j);
-       }
-       /* printk(KERN_DEBUG "streaming=0\n"); */
-       ibmcam->streaming = 0;
-
-       /* Delete them all */
-       for (i=0; i < IBMCAM_NUMSBUF; i++)
-               usb_free_urb(ibmcam->sbuf[i].urb);
-
-       if (!ibmcam->remove_pending) {
-               usb_ibmcam_setup_video_stop(ibmcam);
-
-               /* Set packet size to 0 */
-               j = usb_set_interface(ibmcam->dev, ibmcam->iface, ibmcam->ifaceAltInactive);
-               if (j < 0) {
-                       printk(KERN_ERR "%s: usb_set_interface() error %d.\n", proc, j);
-                       ibmcam->last_error = j;
-               }
-       }
-}
-
-/*
- * ibmcam_new_frame()
- *
- * History:
- * 29-Mar-00 Added copying of previous frame into the current one.
- */
-static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
-{
-       struct ibmcam_frame *frame;
-       int n, width, height;
-
-       /* If we're not grabbing a frame right now and the other frame is */
-       /*  ready to be grabbed into, then use it instead */
-       if (ibmcam->curframe != -1)
-               return 0;
-
-       n = (framenum - 1 + IBMCAM_NUMFRAMES) % IBMCAM_NUMFRAMES;
-       if (ibmcam->frame[n].grabstate == FRAME_READY)
-               framenum = n;
-
-       frame = &ibmcam->frame[framenum];
-
-       frame->grabstate = FRAME_GRABBING;
-       frame->scanstate = STATE_SCANNING;
-       frame->scanlength = 0;          /* Accumulated in ibmcam_parse_data() */
-       ibmcam->curframe = framenum;
-
-       /*
-        * Normally we would want to copy previous frame into the current one
-        * before we even start filling it with data; this allows us to stop
-        * filling at any moment; top portion of the frame will be new and
-        * bottom portion will stay as it was in previous frame. If we don't
-        * do that then missing chunks of video stream will result in flickering
-        * portions of old data whatever it was before.
-        *
-        * If we choose not to copy previous frame (to, for example, save few
-        * bus cycles - the frame can be pretty large!) then we have an option
-        * to clear the frame before using. If we experience losses in this
-        * mode then missing picture will be black (no flickering).
-        *
-        * Finally, if user chooses not to clean the current frame before
-        * filling it with data then the old data will be visible if we fail
-        * to refill entire frame with new data.
-        */
-       if (!(flags & FLAGS_SEPARATE_FRAMES)) {
-               /* This copies previous frame into this one to mask losses */
-               memmove(frame->data, ibmcam->frame[1-framenum].data,  MAX_FRAME_SIZE);
-       } else {
-               if (flags & FLAGS_CLEAN_FRAMES) {
-                       /* This provides a "clean" frame but slows things down */
-                       memset(frame->data, 0, MAX_FRAME_SIZE);
-               }
-       }
-       switch (videosize) {
-       case VIDEOSIZE_128x96:
-               frame->frmwidth = 128;
-               frame->frmheight = 96;
-               frame->order_uv = 1;    /* U Y V Y ... */
-               frame->hdr_sig = 0x06;  /* 00 FF 00 06 */
+       /* Internal frame rate is controlled by f_rate value */
+       f_rate = 7 - framerate;
+       RESTRICT_TO_RANGE(f_rate, 0, 7);
+
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0123);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0117);
+       ibmcam_veio(uvd, 0, 0x0040, 0x0108);
+       ibmcam_veio(uvd, 0, 0x0019, 0x012c);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0115);
+       ibmcam_veio(uvd, 0, 0x0003, 0x0115);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0115);
+       ibmcam_veio(uvd, 0, 0x000b, 0x0115);
+       ibmcam_model3_Packet1(uvd, 0x000a, 0x0040);
+       ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6);
+       ibmcam_model3_Packet1(uvd, 0x000c, 0x0002);
+       ibmcam_model3_Packet1(uvd, 0x000d, 0x0020);
+       ibmcam_model3_Packet1(uvd, 0x000e, 0x0033);
+       ibmcam_model3_Packet1(uvd, 0x000f, 0x0007);
+       ibmcam_model3_Packet1(uvd, 0x0010, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0011, 0x0070);
+       ibmcam_model3_Packet1(uvd, 0x0012, 0x0030);
+       ibmcam_model3_Packet1(uvd, 0x0013, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0014, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0015, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0016, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0017, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0018, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3);
+       ibmcam_model3_Packet1(uvd, 0x0020, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0028, 0x0010);
+       ibmcam_model3_Packet1(uvd, 0x0029, 0x0054);
+       ibmcam_model3_Packet1(uvd, 0x002a, 0x0013);
+       ibmcam_model3_Packet1(uvd, 0x002b, 0x0007);
+       ibmcam_model3_Packet1(uvd, 0x002d, 0x0028);
+       ibmcam_model3_Packet1(uvd, 0x002e, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0031, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0032, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0033, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0034, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0035, 0x0038);
+       ibmcam_model3_Packet1(uvd, 0x003a, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x003c, 0x001e);
+       ibmcam_model3_Packet1(uvd, 0x003f, 0x000a);
+       ibmcam_model3_Packet1(uvd, 0x0041, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0046, 0x003f);
+       ibmcam_model3_Packet1(uvd, 0x0047, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0050, 0x0005);
+       ibmcam_model3_Packet1(uvd, 0x0052, 0x001a);
+       ibmcam_model3_Packet1(uvd, 0x0053, 0x0003);
+       ibmcam_model3_Packet1(uvd, 0x005a, 0x006b);
+       ibmcam_model3_Packet1(uvd, 0x005d, 0x001e);
+       ibmcam_model3_Packet1(uvd, 0x005e, 0x0030);
+       ibmcam_model3_Packet1(uvd, 0x005f, 0x0041);
+       ibmcam_model3_Packet1(uvd, 0x0064, 0x0008);
+       ibmcam_model3_Packet1(uvd, 0x0065, 0x0015);
+       ibmcam_model3_Packet1(uvd, 0x0068, 0x000f);
+       ibmcam_model3_Packet1(uvd, 0x0079, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x007a, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x007c, 0x003f);
+       ibmcam_model3_Packet1(uvd, 0x0082, 0x000f);
+       ibmcam_model3_Packet1(uvd, 0x0085, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0099, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x009b, 0x0023);
+       ibmcam_model3_Packet1(uvd, 0x009c, 0x0022);
+       ibmcam_model3_Packet1(uvd, 0x009d, 0x0096);
+       ibmcam_model3_Packet1(uvd, 0x009e, 0x0096);
+       ibmcam_model3_Packet1(uvd, 0x009f, 0x000a);
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x00a9, 0x0119);
+               ibmcam_veio(uvd, 0, 0x0016, 0x011b);
+               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               ibmcam_veio(uvd, 0, 0x0018, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
+               ibmcam_veio(uvd, 0, 0x0028, 0x011c);
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0118);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
                break;
-       case VIDEOSIZE_176x144:
-               frame->frmwidth = 176;
-               frame->frmheight = 144;
-               frame->order_uv = 1;    /* U Y V Y ... */
-               frame->hdr_sig = 0x0E;  /* 00 FF 00 0E */
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */
+               ibmcam_veio(uvd, 0, 0x0000, 0x011e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               /* 4 commands from 160x120 skipped */
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
+               ibmcam_veio(uvd, 0, 0x00d9, 0x0119);
+               ibmcam_veio(uvd, 0, 0x0006, 0x011b);
+               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0010, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
+               ibmcam_veio(uvd, 0, 0x003f, 0x011c);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0118);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
                break;
-       case VIDEOSIZE_320x240:         /* For model 2 only */
-               frame->frmwidth = 320;
-               frame->frmheight = 240;
+       case VIDEOSIZE_640x480:
+               ibmcam_veio(uvd, 0, 0x00f0, 0x0105);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */
+               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
+               ibmcam_veio(uvd, 0, 0x0040, 0x0101);
+               ibmcam_veio(uvd, 0, 0x0040, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
                break;
-       case VIDEOSIZE_352x240:         /* For model 2 only */
-               frame->frmwidth = 352;
-               frame->frmheight = 240;
+       }
+       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);     /* Hue */
+       ibmcam_model3_Packet1(uvd, 0x0036, 0x0011);     /* Brightness */
+       ibmcam_model3_Packet1(uvd, 0x0060, 0x0002);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0061, 0x0004);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0062, 0x0005);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0063, 0x0014);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
+       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
+       ibmcam_model3_Packet1(uvd, 0x0067, 0x0001);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x005b, 0x000c);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x005c, 0x0016);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x002c, 0x0003);     /* Was 1, broke 640x480 */
+       ibmcam_model3_Packet1(uvd, 0x002f, 0x002a);
+       ibmcam_model3_Packet1(uvd, 0x0030, 0x0029);
+       ibmcam_model3_Packet1(uvd, 0x0037, 0x0002);
+       ibmcam_model3_Packet1(uvd, 0x0038, 0x0059);
+       ibmcam_model3_Packet1(uvd, 0x003d, 0x002e);
+       ibmcam_model3_Packet1(uvd, 0x003e, 0x0028);
+       ibmcam_model3_Packet1(uvd, 0x0078, 0x0005);
+       ibmcam_model3_Packet1(uvd, 0x007b, 0x0011);
+       ibmcam_model3_Packet1(uvd, 0x007d, 0x004b);
+       ibmcam_model3_Packet1(uvd, 0x007f, 0x0022);
+       ibmcam_model3_Packet1(uvd, 0x0080, 0x000c);
+       ibmcam_model3_Packet1(uvd, 0x0081, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd);
+       ibmcam_model3_Packet1(uvd, 0x0086, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x0087, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);
+       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
+       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
+       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0107);
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x000a);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
                break;
-       case VIDEOSIZE_352x288:
-               frame->frmwidth = 352;
-               frame->frmheight = 288;
-               frame->order_uv = 0;    /* V Y U Y ... */
-               frame->hdr_sig = 0x00;  /* 00 FF 00 00 */
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0062, 0x0107);
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000b);
+               break;
+       case VIDEOSIZE_640x480:
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);    /* Adjustments */
+               ibmcam_veio(uvd, 0, 0x00b4, 0x0107);    /* Adjustments */
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
                break;
        }
-       frame->order_yc = (ibmcam->camera_model == IBMCAM_MODEL_2);
-
-       width = frame->width;
-       RESTRICT_TO_RANGE(width, min_imgwidth, imgwidth);
-       width &= ~7;            /* Multiple of 8 */
-
-       height = frame->height;
-       RESTRICT_TO_RANGE(height, min_imgheight, imgheight);
-       height &= ~3;           /* Multiple of 4 */
-
-       return 0;
-}
 
-/*
- * ibmcam_open()
- *
- * This is part of Video 4 Linux API. The driver can be opened by one
- * client only (checks internal counter 'ibmcam->user'). The procedure
- * then allocates buffers needed for video processing.
- *
- * History:
- * 1/22/00  Rewrote, moved scratch buffer allocation here. Now the
- *          camera is also initialized here (once per connect), at
- *          expense of V4L client (it waits on open() call).
- * 1/27/00  Used IBMCAM_NUMSBUF as number of URB buffers.
- * 5/24/00  Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- */
-static int ibmcam_open(struct video_device *dev, int flags)
-{
-       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
-       const int sb_size = FRAMES_PER_DESC * ibmcam->iso_packet_len;
-       int i, err = 0;
-
-       MOD_INC_USE_COUNT;
-       down(&ibmcam->lock);
-
-       if (ibmcam->user)
-               err = -EBUSY;
-       else {
-               /* Clean pointers so we know if we allocated something */
-               for (i=0; i < IBMCAM_NUMSBUF; i++)
-                       ibmcam->sbuf[i].data = NULL;
-
-               /* Allocate memory for the frame buffers */
-               ibmcam->fbuf_size = IBMCAM_NUMFRAMES * MAX_FRAME_SIZE;
-               ibmcam->fbuf = rvmalloc(ibmcam->fbuf_size);
-               ibmcam->scratch = kmalloc(scratchbufsize, GFP_KERNEL);
-               ibmcam->scratchlen = 0;
-               if ((ibmcam->fbuf == NULL) || (ibmcam->scratch == NULL))
-                       err = -ENOMEM;
-               else {
-                       /* Allocate all buffers */
-                       for (i=0; i < IBMCAM_NUMFRAMES; i++) {
-                               ibmcam->frame[i].grabstate = FRAME_UNUSED;
-                               ibmcam->frame[i].data = ibmcam->fbuf + i*MAX_FRAME_SIZE;
-                               /*
-                                * Set default sizes in case IOCTL (VIDIOCMCAPTURE)
-                                * is not used (using read() instead).
-                                */
-                               ibmcam->frame[i].width = imgwidth;
-                               ibmcam->frame[i].height = imgheight;
-                               ibmcam->frame[i].bytes_read = 0;
-                       }
-                       for (i=0; i < IBMCAM_NUMSBUF; i++) {
-                               ibmcam->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);
-                               if (ibmcam->sbuf[i].data == NULL) {
-                                       err = -ENOMEM;
-                                       break;
-                               }
-                       }
-               }
-               if (err) {
-                       /* Have to free all that memory */
-                       if (ibmcam->fbuf != NULL) {
-                               rvfree(ibmcam->fbuf, ibmcam->fbuf_size);
-                               ibmcam->fbuf = NULL;
-                       }
-                       if (ibmcam->scratch != NULL) {
-                               kfree(ibmcam->scratch);
-                               ibmcam->scratch = NULL;
-                       }
-                       for (i=0; i < IBMCAM_NUMSBUF; i++) {
-                               if (ibmcam->sbuf[i].data != NULL) {
-                                       kfree (ibmcam->sbuf[i].data);
-                                       ibmcam->sbuf[i].data = NULL;
-                               }
-                       }
+       /* 01.01.08 - Added for RCA video in support -LO */
+       if(init_model3_input) {
+               if (debug > 0)
+                       info("Setting input to RCA.");
+               for (i=0; i < (sizeof(initData)/sizeof(initData[0])); i++) {
+                       ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
                }
        }
 
-       /* If so far no errors then we shall start the camera */
-       if (!err) {
-               err = ibmcam_init_isoc(ibmcam);
-               if (!err) {
-                       /* Send init sequence only once, it's large! */
-                       if (!ibmcam->initialized) {
-                               int setup_ok = 0;
-                               if (ibmcam->camera_model == IBMCAM_MODEL_1)
-                                       setup_ok = usb_ibmcam_model1_setup(ibmcam);
-                               else if (ibmcam->camera_model == IBMCAM_MODEL_2)
-                                       setup_ok = usb_ibmcam_model2_setup(ibmcam);
-                               if (setup_ok)
-                                       ibmcam->initialized = 1;
-                               else
-                                       err = -EBUSY;
-                       }
-                       if (!err)
-                               ibmcam->user++;
-               }
-       }
-       up(&ibmcam->lock);
-       if (err)
-               MOD_DEC_USE_COUNT;
-       return err;
+       ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
 }
 
 /*
- * ibmcam_close()
- *
- * This is part of Video 4 Linux API. The procedure
- * stops streaming and deallocates all buffers that were earlier
- * allocated in ibmcam_open().
+ * ibmcam_video_stop()
  *
- * History:
- * 1/22/00  Moved scratch buffer deallocation here.
- * 1/27/00  Used IBMCAM_NUMSBUF as number of URB buffers.
- * 5/24/00  Moved MOD_DEC_USE_COUNT outside of code that can sleep.
+ * This code tells camera to stop streaming. The interface remains
+ * configured and bandwidth - claimed.
  */
-static void ibmcam_close(struct video_device *dev)
+static void ibmcam_video_stop(uvd_t *uvd)
 {
-       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
-       int i;
-
-       down(&ibmcam->lock);    
-
-       ibmcam_stop_isoc(ibmcam);
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_veio(uvd, 0, 0x01, 0x0114);
+               ibmcam_veio(uvd, 0, 0xc0, 0x010c);
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_send_FF_04_02(uvd);
+               ibmcam_veio(uvd, 1, 0x00, 0x0100);
+               ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
+               break;
+       case IBMCAM_MODEL_2:
+case IBMCAM_MODEL_4:
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop the camera */
 
-       rvfree(ibmcam->fbuf, ibmcam->fbuf_size);
-       kfree(ibmcam->scratch);
-       for (i=0; i < IBMCAM_NUMSBUF; i++)
-               kfree(ibmcam->sbuf[i].data);
+               ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
 
-       ibmcam->user--;
+               ibmcam_veio(uvd, 0, 0x0080, 0x0100);    /* LED Off */
+               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0111);
 
-       if (ibmcam->remove_pending) {
-               printk(KERN_INFO "ibmcam_close: Final disconnect.\n");
-               usb_ibmcam_release(ibmcam);
-       }
-       up(&ibmcam->lock);
-       MOD_DEC_USE_COUNT;
-}
+               ibmcam_model2_Packet1(uvd, 0x0030, 0x0002);
 
-static long ibmcam_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
-{
-       return -EINVAL;
+               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
+               break;
+       case IBMCAM_MODEL_3:
+#if 1
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);
+
+               /* Here we are supposed to select video interface alt. setting 0 */
+               ibmcam_veio(uvd, 0, 0x0006, 0x012c);
+
+               ibmcam_model3_Packet1(uvd, 0x0046, 0x0000);
+
+               ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+               ibmcam_veio(uvd, 0, 0x0064, 0x0116);
+               ibmcam_veio(uvd, 1, 0x0000, 0x0115);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0115);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0123);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0117);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
+               ibmcam_veio(uvd, 0, 0x0080, 0x0100);
+               IBMCAM_T(uvd)->initialized = 0;
+#endif
+               break;
+       } /* switch */
 }
 
 /*
- * ibmcam_ioctl()
+ * ibmcam_reinit_iso()
  *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ * This procedure sends couple of commands to the camera and then
+ * resets the video pipe. This sequence was observed to reinit the
+ * camera or, at least, to initiate ISO data stream.
  *
  * History:
- * 1/22/00  Corrected VIDIOCSPICT to reject unsupported settings.
+ * 1/2/00   Created.
  */
-static int ibmcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+static void ibmcam_reinit_iso(uvd_t *uvd, int do_stop)
 {
-       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
-
-       if (!IBMCAM_IS_OPERATIONAL(ibmcam))
-               return -EFAULT;
-
-       switch (cmd) {
-               case VIDIOCGCAP:
-               {
-                       if (copy_to_user(arg, &ibmcam->vcap, sizeof(ibmcam->vcap)))
-                               return -EFAULT;
-                       return 0;
-               }
-               case VIDIOCGCHAN:
-               {
-                       if (copy_to_user(arg, &ibmcam->vchan, sizeof(ibmcam->vchan)))
-                               return -EFAULT;
-                       return 0;
-               }
-               case VIDIOCSCHAN:
-               {
-                       int v;
-
-                       if (copy_from_user(&v, arg, sizeof(v)))
-                               return -EFAULT;
-                       if ((v < 0) || (v >= 3)) /* 3 grades of lighting conditions */
-                               return -EINVAL;
-                       if (v != ibmcam->vchan.channel) {
-                               ibmcam->vchan.channel = v;
-                               usb_ibmcam_change_lighting_conditions(ibmcam);
-                       }
-                       return 0;
-               }
-               case VIDIOCGPICT:
-               {
-                       if (copy_to_user(arg, &ibmcam->vpic, sizeof(ibmcam->vpic)))
-                               return -EFAULT;
-                       return 0;
-               }
-               case VIDIOCSPICT:
-               {
-                       struct video_picture tmp;
-                       /*
-                        * Use temporary 'video_picture' structure to preserve our
-                        * own settings (such as color depth, palette) that we
-                        * aren't allowing everyone (V4L client) to change.
-                        */
-                       if (copy_from_user(&tmp, arg, sizeof(tmp)))
-                               return -EFAULT;
-                       ibmcam->vpic.brightness = tmp.brightness;
-                       ibmcam->vpic.hue = tmp.hue;
-                       ibmcam->vpic.colour = tmp.colour;
-                       ibmcam->vpic.contrast = tmp.contrast;
-                       usb_ibmcam_adjust_picture(ibmcam);
-                       return 0;
-               }
-               case VIDIOCSWIN:
-               {
-                       struct video_window vw;
-
-                       if (copy_from_user(&vw, arg, sizeof(vw)))
-                               return -EFAULT;
-                       if (vw.flags)
-                               return -EINVAL;
-                       if (vw.clipcount)
-                               return -EINVAL;
-                       if (vw.height != imgheight)
-                               return -EINVAL;
-                       if (vw.width != imgwidth)
-                               return -EINVAL;
-
-                       ibmcam->compress = 0;
-
-                       return 0;
-               }
-               case VIDIOCGWIN:
-               {
-                       struct video_window vw;
-
-                       memset(&vw, 0, sizeof(vw));
-                       vw.x = 0;
-                       vw.y = 0;
-                       vw.width = imgwidth;
-                       vw.height = imgheight;
-                       vw.flags = usb_ibmcam_calculate_fps();
-
-                       if (copy_to_user(arg, &vw, sizeof(vw)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCGMBUF:
-               {
-                       struct video_mbuf vm;
-
-                       memset(&vm, 0, sizeof(vm));
-                       vm.size = MAX_FRAME_SIZE * 2;
-                       vm.frames = 2;
-                       vm.offsets[0] = 0;
-                       vm.offsets[1] = MAX_FRAME_SIZE;
-
-                       if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap vm;
-
-                       if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
-                               return -EFAULT;
-
-                       if (debug >= 1)
-                               printk(KERN_DEBUG "frame: %d, size: %dx%d, format: %d\n",
-                                       vm.frame, vm.width, vm.height, vm.format);
-
-                       if (vm.format != VIDEO_PALETTE_RGB24)
-                               return -EINVAL;
-
-                       if ((vm.frame != 0) && (vm.frame != 1))
-                               return -EINVAL;
-
-                       if (ibmcam->frame[vm.frame].grabstate == FRAME_GRABBING)
-                               return -EBUSY;
-
-                       /* Don't compress if the size changed */
-                       if ((ibmcam->frame[vm.frame].width != vm.width) ||
-                           (ibmcam->frame[vm.frame].height != vm.height))
-                               ibmcam->compress = 0;
-
-                       ibmcam->frame[vm.frame].width = vm.width;
-                       ibmcam->frame[vm.frame].height = vm.height;
-
-                       /* Mark it as ready */
-                       ibmcam->frame[vm.frame].grabstate = FRAME_READY;
-
-                       return ibmcam_new_frame(ibmcam, vm.frame);
-               }
-               case VIDIOCSYNC:
-               {
-                       int frame;
-
-                       if (copy_from_user((void *)&frame, arg, sizeof(int)))
-                               return -EFAULT;
-
-                       if ((unsigned)frame >= IBMCAM_NUMFRAMES) {
-                               err("VIDIOCSYNC: invalid frame %d.", frame);
-                               return -EINVAL;
-                       }
-
-                       if (debug >= 1)
-                               printk(KERN_DEBUG "ibmcam: syncing to frame %d\n", frame);
-
-                       switch (ibmcam->frame[frame].grabstate) {
-                       case FRAME_UNUSED:
-                               return -EINVAL;
-                       case FRAME_READY:
-                       case FRAME_GRABBING:
-                       case FRAME_ERROR:
-                       {
-                               int ntries;
-               redo:
-                               if (!IBMCAM_IS_OPERATIONAL(ibmcam))
-                                       return -EIO;
-                               ntries = 0; 
-                               do {
-                                       interruptible_sleep_on(&ibmcam->frame[frame].wq);
-                                       if (signal_pending(current)) {
-                                               if (flags & FLAGS_RETRY_VIDIOCSYNC) {
-                                                       /* Polling apps will destroy frames with that! */
-                                                       ibmcam_new_frame(ibmcam, frame);
-                                                       usb_ibmcam_testpattern(ibmcam, 1, 0);
-                                                       ibmcam->curframe = -1;
-                                                       ibmcam->frame_num++;
-
-                                                       /* This will request another frame. */
-                                                       if (waitqueue_active(&ibmcam->frame[frame].wq))
-                                                               wake_up_interruptible(&ibmcam->frame[frame].wq);
-                                                       return 0;
-                                               } else {
-                                                       /* Standard answer: not ready yet! */
-                                                       return -EINTR;
-                                               }
-                                       }
-                               } while (ibmcam->frame[frame].grabstate == FRAME_GRABBING);
-
-                               if (ibmcam->frame[frame].grabstate == FRAME_ERROR) {
-                                       int ret = ibmcam_new_frame(ibmcam, frame);
-                                       if (ret < 0)
-                                               return ret;
-                                       goto redo;
-                               }
-                       }
-                       case FRAME_DONE:
-                               ibmcam->frame[frame].grabstate = FRAME_UNUSED;
-                               break;
-                       }
-
-                       ibmcam->frame[frame].grabstate = FRAME_UNUSED;
-
-                       return 0;
-               }
-               case VIDIOCGFBUF:
-               {
-                       struct video_buffer vb;
-
-                       memset(&vb, 0, sizeof(vb));
-                       vb.base = NULL; /* frame buffer not supported, not used */
-
-                       if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCKEY:
-                       return 0;
-
-               case VIDIOCCAPTURE:
-                       return -EINVAL;
-
-               case VIDIOCSFBUF:
-
-               case VIDIOCGTUNER:
-               case VIDIOCSTUNER:
-
-               case VIDIOCGFREQ:
-               case VIDIOCSFREQ:
-
-               case VIDIOCGAUDIO:
-               case VIDIOCSAUDIO:
-                       return -EINVAL;
-
-               default:
-                       return -ENOIOCTLCMD;
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+               if (do_stop)
+                       ibmcam_video_stop(uvd);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_model1_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_2:
+               ibmcam_model2_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_3:
+               ibmcam_video_stop(uvd);
+               ibmcam_model3_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_4:
+               ibmcam_model4_setup_after_video_if(uvd);
+               break;
        }
-       return 0;
 }
 
-static long ibmcam_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
+static void ibmcam_video_start(uvd_t *uvd)
 {
-       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
-       int frmx = -1;
-       volatile struct ibmcam_frame *frame;
-
-       if (debug >= 1)
-               printk(KERN_DEBUG "ibmcam_read: %ld bytes, noblock=%d\n", count, noblock);
-
-       if (!IBMCAM_IS_OPERATIONAL(ibmcam) || (buf == NULL))
-               return -EFAULT;
-
-       /* See if a frame is completed, then use it. */
-       if (ibmcam->frame[0].grabstate >= FRAME_DONE)   /* _DONE or _ERROR */
-               frmx = 0;
-       else if (ibmcam->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
-               frmx = 1;
-
-       if (noblock && (frmx == -1))
-               return -EAGAIN;
-
-       /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
-       /* See if a frame is in process (grabbing), then use it. */
-       if (frmx == -1) {
-               if (ibmcam->frame[0].grabstate == FRAME_GRABBING)
-                       frmx = 0;
-               else if (ibmcam->frame[1].grabstate == FRAME_GRABBING)
-                       frmx = 1;
-       }
-
-       /* If no frame is active, start one. */
-       if (frmx == -1)
-               ibmcam_new_frame(ibmcam, frmx = 0);
-
-       frame = &ibmcam->frame[frmx];
-
-restart:
-       if (!IBMCAM_IS_OPERATIONAL(ibmcam))
-               return -EIO;
-       while (frame->grabstate == FRAME_GRABBING) {
-               interruptible_sleep_on((void *)&frame->wq);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       if (frame->grabstate == FRAME_ERROR) {
-               frame->bytes_read = 0;
-               if (ibmcam_new_frame(ibmcam, frmx))
-                       printk(KERN_ERR "ibmcam_read: ibmcam_new_frame error\n");
-               goto restart;
-       }
-
-       if (debug >= 1)
-               printk(KERN_DEBUG "ibmcam_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n",
-                       frmx, frame->bytes_read, frame->scanlength);
-
-       /* copy bytes to user space; we allow for partials reads */
-       if ((count + frame->bytes_read) > frame->scanlength)
-               count = frame->scanlength - frame->bytes_read;
-
-       if (copy_to_user(buf, frame->data + frame->bytes_read, count))
-               return -EFAULT;
-
-       frame->bytes_read += count;
-       if (debug >= 1)
-               printk(KERN_DEBUG "ibmcam_read: {copy} count used=%ld, new bytes_read=%ld\n",
-                       count, frame->bytes_read);
-
-       if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
-               frame->bytes_read = 0;
-
-               /* Mark it as available to be used again. */
-               ibmcam->frame[frmx].grabstate = FRAME_UNUSED;
-               if (ibmcam_new_frame(ibmcam, frmx ? 0 : 1))
-                       printk(KERN_ERR "ibmcam_read: ibmcam_new_frame returned error\n");
-       }
-
-       return count;
+       ibmcam_change_lighting_conditions(uvd);
+       ibmcam_set_sharpness(uvd);
+       ibmcam_reinit_iso(uvd, 0);
 }
 
-static int ibmcam_mmap(struct video_device *dev, const char *adr, unsigned long size)
+/*
+ * Return negative code on failure, 0 on success.
+ */
+static int ibmcam_setup_on_open(uvd_t *uvd)
 {
-       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
-       unsigned long start = (unsigned long)adr;
-       unsigned long page, pos;
-
-       if (!IBMCAM_IS_OPERATIONAL(ibmcam))
-               return -EFAULT;
-
-       if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
-               return -EINVAL;
-
-       pos = (unsigned long)ibmcam->fbuf;
-       while (size > 0) {
-               page = kvirt_to_pa(pos);
-               if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
+       int setup_ok = 0; /* Success by default */
+       /* Send init sequence only once, it's large! */
+       if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */
+               switch (IBMCAM_T(uvd)->camera_model) {
+               case IBMCAM_MODEL_1:
+                       setup_ok = ibmcam_model1_setup(uvd);
+                       break;
+               case IBMCAM_MODEL_2:
+                       setup_ok = ibmcam_model2_setup(uvd);
+                       break;
+               case IBMCAM_MODEL_3:
+               case IBMCAM_MODEL_4:
+                       /* We do all setup when Isoc stream is requested */
+                       break;
+               }
+               IBMCAM_T(uvd)->initialized = (setup_ok != 0);
        }
-
-       return 0;
+       return setup_ok;
 }
 
-static struct video_device ibmcam_template = {
-       name:           "CPiA USB Camera",
-       type:           VID_TYPE_CAPTURE,
-       hardware:       VID_HARDWARE_CPIA,
-       open:           ibmcam_open,
-       close:          ibmcam_close,
-       read:           ibmcam_read,
-       write:          ibmcam_write,
-       ioctl:          ibmcam_ioctl,
-       mmap:           ibmcam_mmap,
-};
-
-static void usb_ibmcam_configure_video(struct usb_ibmcam *ibmcam)
+static void ibmcam_configure_video(uvd_t *uvd)
 {
-       if (ibmcam == NULL)
+       if (uvd == NULL)
                return;
 
        RESTRICT_TO_RANGE(init_brightness, 0, 255);
@@ -2883,286 +3610,316 @@ static void usb_ibmcam_configure_video(struct usb_ibmcam *ibmcam)
        RESTRICT_TO_RANGE(init_hue, 0, 255);
        RESTRICT_TO_RANGE(hue_correction, 0, 255);
 
-       memset(&ibmcam->vpic, 0, sizeof(ibmcam->vpic));
-       memset(&ibmcam->vpic_old, 0x55, sizeof(ibmcam->vpic_old));
-
-       ibmcam->vpic.colour = init_color << 8;
-       ibmcam->vpic.hue = init_hue << 8;
-       ibmcam->vpic.brightness = init_brightness << 8;
-       ibmcam->vpic.contrast = init_contrast << 8;
-       ibmcam->vpic.whiteness = 105 << 8; /* This one isn't used */
-       ibmcam->vpic.depth = 24;
-       ibmcam->vpic.palette = VIDEO_PALETTE_RGB24;
-
-       memset(&ibmcam->vcap, 0, sizeof(ibmcam->vcap));
-       strcpy(ibmcam->vcap.name, "IBM USB Camera");
-       ibmcam->vcap.type = VID_TYPE_CAPTURE;
-       ibmcam->vcap.channels = 1;
-       ibmcam->vcap.audios = 0;
-       ibmcam->vcap.maxwidth = imgwidth;
-       ibmcam->vcap.maxheight = imgheight;
-       ibmcam->vcap.minwidth = min_imgwidth;
-       ibmcam->vcap.minheight = min_imgheight;
-
-       memset(&ibmcam->vchan, 0, sizeof(ibmcam->vchan));
-       ibmcam->vchan.flags = 0;
-       ibmcam->vchan.tuners = 0;
-       ibmcam->vchan.channel = 0;
-       ibmcam->vchan.type = VIDEO_TYPE_CAMERA;
-       strcpy(ibmcam->vchan.name, "Camera");
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       uvd->vpic.colour = init_color << 8;
+       uvd->vpic.hue = init_hue << 8;
+       uvd->vpic.brightness = init_brightness << 8;
+       uvd->vpic.contrast = init_contrast << 8;
+       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
+       uvd->vpic.depth = 24;
+       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "IBM USB Camera");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
+       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
+       uvd->vcap.minwidth = min_canvasWidth;
+       uvd->vcap.minheight = min_canvasHeight;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
 }
 
 /*
- * ibmcam_find_struct()
- *
- * This code searches the array of preallocated (static) structures
- * and returns index of the first one that isn't in use. Returns -1
- * if there are no free structures.
- *
- * History:
- * 1/27/00  Created.
- */
-static int ibmcam_find_struct(void)
-{
-       int i, u;
-
-       for (u = 0; u < MAX_IBMCAM; u++) {
-               struct usb_ibmcam *ibmcam = &cams[u];
-               if (!ibmcam->ibmcam_used) /* This one is free */
-               {
-                       ibmcam->ibmcam_used = 1;        /* In use now */
-                       for (i=0; i < IBMCAM_NUMFRAMES; i++)
-                               init_waitqueue_head(&ibmcam->frame[i].wq);
-                       init_MUTEX(&ibmcam->lock);      /* to 1 == available */
-                       ibmcam->dev = NULL;
-                       memcpy(&ibmcam->vdev, &ibmcam_template, sizeof(ibmcam_template));
-                       return u;
-               }
-       }
-       return -1;
-}
-
-/*
- * usb_ibmcam_probe()
+ * ibmcam_probe()
  *
  * This procedure queries device descriptor and accepts the interface
  * if it looks like IBM C-it camera.
  *
  * History:
- * 1/22/00  Moved camera init code to ibmcam_open()
- * 1/27/00  Changed to use static structures, added locking.
- * 5/24/00  Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 7/3/00   Fixed endianness bug.
+ * 22-Jan-2000 Moved camera init code to ibmcam_open()
+ * 27=Jan-2000 Changed to use static structures, added locking.
+ * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ * 03-Jul-2000 Fixed endianness bug.
+ * 12-Nov-2000 Reworked to comply with new probe() signature.
+ * 23-Jan-2001 Added compatibility with 2.2.x kernels.
  */
-static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum,
-                        const struct usb_device_id *id)
+static void *ibmcam_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
 {
-       struct usb_ibmcam *ibmcam = NULL;
-       const struct usb_interface_descriptor *interface;
-       const struct usb_endpoint_descriptor *endpoint;
-       int devnum, model=0;
+       uvd_t *uvd = NULL;
+       int i, nas, model=0, canvasX=0, canvasY=0;
+       int actInterface=-1, inactInterface=-1, maxPS=0;
+       unsigned char video_ep = 0;
 
        if (debug >= 1)
-               printk(KERN_DEBUG "ibmcam_probe(%p,%u.)\n", dev, ifnum);
+               info("ibmcam_probe(%p,%u.)", dev, ifnum);
 
        /* We don't handle multi-config cameras */
        if (dev->descriptor.bNumConfigurations != 1)
                return NULL;
 
+       /* Is it an IBM camera? */
+       if (dev->descriptor.idVendor != IBMCAM_VENDOR_ID)
+               return NULL;
+       if ((dev->descriptor.idProduct != IBMCAM_PRODUCT_ID) &&
+           (dev->descriptor.idProduct != NETCAM_PRODUCT_ID))
+               return NULL;
+
        /* Check the version/revision */
        switch (dev->descriptor.bcdDevice) {
        case 0x0002:
                if (ifnum != 2)
                        return NULL;
-               printk(KERN_INFO "IBM USB camera found (model 1, rev. 0x%04x).\n",
-                       dev->descriptor.bcdDevice);
                model = IBMCAM_MODEL_1;
                break;
        case 0x030A:
                if (ifnum != 0)
                        return NULL;
-               printk(KERN_INFO "IBM USB camera found (model 2, rev. 0x%04x).\n",
-                       dev->descriptor.bcdDevice);
-               model = IBMCAM_MODEL_2;
+               if (dev->descriptor.idProduct == NETCAM_PRODUCT_ID)
+                       model = IBMCAM_MODEL_4;
+               else
+                       model = IBMCAM_MODEL_2;
                break;
-
-       /* ibmcam_table contents prevents any other values from ever
-          being passed to us, so no need for "default" case. */
+       case 0x0301:
+               if (ifnum != 0)
+                       return NULL;
+               model = IBMCAM_MODEL_3;
+               break;
+       default:
+               err("IBM camera with revision 0x%04x is not supported.",
+                       dev->descriptor.bcdDevice);
+               return NULL;
        }
+       info("IBM USB camera found (model %d, rev. 0x%04x)",
+               model, dev->descriptor.bcdDevice);
 
        /* Validate found interface: must have one ISO endpoint */
-       interface = &dev->actconfig->interface[ifnum].altsetting[0];
-       if (interface->bNumEndpoints != 1) {
-               printk(KERN_ERR "IBM camera: interface %d. has %u. endpoints!\n",
-                      ifnum, (unsigned)(interface->bNumEndpoints));
+       nas = dev->actconfig->interface[ifnum].num_altsetting;
+       if (debug > 0)
+               info("Number of alternate settings=%d.", nas);
+       if (nas < 2) {
+               err("Too few alternate settings for this camera!");
                return NULL;
        }
-       endpoint = &interface->endpoint[0];
-       if ((endpoint->bmAttributes & 0x03) != 0x01) {
-               printk(KERN_ERR "IBM camera: interface %d. has non-ISO endpoint!\n", ifnum);
-               return NULL;
+       /* Validate all alternate settings */
+       for (i=0; i < nas; i++) {
+               const struct usb_interface_descriptor *interface;
+               const struct usb_endpoint_descriptor *endpoint;
+
+               interface = &dev->actconfig->interface[ifnum].altsetting[i];
+               if (interface->bNumEndpoints != 1) {
+                       err("Interface %d. has %u. endpoints!",
+                           ifnum, (unsigned)(interface->bNumEndpoints));
+                       return NULL;
+               }
+               endpoint = &interface->endpoint[0];
+               if (video_ep == 0)
+                       video_ep = endpoint->bEndpointAddress;
+               else if (video_ep != endpoint->bEndpointAddress) {
+                       err("Alternate settings have different endpoint addresses!");
+                       return NULL;
+               }
+               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+                       err("Interface %d. has non-ISO endpoint!", ifnum);
+                       return NULL;
+               }
+               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+                       err("Interface %d. has ISO OUT endpoint!", ifnum);
+                       return NULL;
+               }
+               if (endpoint->wMaxPacketSize == 0) {
+                       if (inactInterface < 0)
+                               inactInterface = i;
+                       else {
+                               err("More than one inactive alt. setting!");
+                               return NULL;
+                       }
+               } else {
+                       if (actInterface < 0) {
+                               actInterface = i;
+                               maxPS = endpoint->wMaxPacketSize;
+                               if (debug > 0)
+                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
+                       } else
+                               err("More than one active alt. setting! Ignoring #%d.", i);
+               }
        }
-       if ((endpoint->bEndpointAddress & 0x80) == 0) {
-               printk(KERN_ERR "IBM camera: interface %d. has ISO OUT endpoint!\n", ifnum);
+       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
+               err("Failed to recognize the camera!");
                return NULL;
        }
 
        /* Validate options */
-       if (model == IBMCAM_MODEL_1) {
+       switch (model) {
+       case IBMCAM_MODEL_1:
                RESTRICT_TO_RANGE(lighting, 0, 2);
-               RESTRICT_TO_RANGE(videosize, VIDEOSIZE_128x96, VIDEOSIZE_352x288);
-       } else {
+               RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288);
+               if (framerate < 0)
+                       framerate = 2;
+               canvasX = 352;
+               canvasY = 288;
+               break;
+       case IBMCAM_MODEL_2:
                RESTRICT_TO_RANGE(lighting, 0, 15);
-               RESTRICT_TO_RANGE(videosize, VIDEOSIZE_176x144, VIDEOSIZE_352x240);
+               RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240);
+               if (framerate < 0)
+                       framerate = 2;
+               canvasX = 352;
+               canvasY = 240;
+               break;
+       case IBMCAM_MODEL_3:
+               RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */
+               switch (size) {
+               case SIZE_160x120:
+                       canvasX = 160;
+                       canvasY = 120;
+                       if (framerate < 0)
+                               framerate = 2;
+                       RESTRICT_TO_RANGE(framerate, 0, 5);
+                       break;
+               default:
+                       info("IBM camera: using 320x240");
+                       size = SIZE_320x240;
+                       /* No break here */
+               case SIZE_320x240:
+                       canvasX = 320;
+                       canvasY = 240;
+                       if (framerate < 0)
+                               framerate = 3;
+                       RESTRICT_TO_RANGE(framerate, 0, 5);
+                       break;
+               case SIZE_640x480:
+                       canvasX = 640;
+                       canvasY = 480;
+                       framerate = 0;  /* Slowest, and maybe even that is too fast */
+                       break;
+               }
+               break;
+       case IBMCAM_MODEL_4:
+               RESTRICT_TO_RANGE(lighting, 0, 2);
+               switch (size) {
+               case SIZE_128x96:
+                       canvasX = 128;
+                       canvasY = 96;
+                       break;
+               case SIZE_160x120:
+                       canvasX = 160;
+                       canvasY = 120;
+                       break;
+               default:
+                       info("IBM NetCamera: using 176x144");
+                       size = SIZE_176x144;
+                       /* No break here */
+               case SIZE_176x144:
+                       canvasX = 176;
+                       canvasY = 144;
+                       break;
+               case SIZE_320x240:
+                       canvasX = 320;
+                       canvasY = 240;
+                       break;
+               case SIZE_352x288:
+                       canvasX = 352;
+                       canvasY = 288;
+                       break;
+               }
+               break;
+       default:
+               err("IBM camera: Model %d. not supported!", model);
+               return NULL;
        }
 
        /* Code below may sleep, need to lock module while we are here */
        MOD_INC_USE_COUNT;
-
-       devnum = ibmcam_find_struct();
-       if (devnum == -1) {
-               printk(KERN_INFO "IBM USB camera driver: Too many devices!\n");
-               ibmcam = NULL; /* Do not free, it's preallocated */
-               goto probe_done;
-       }
-       ibmcam = &cams[devnum];
-
-       down(&ibmcam->lock);
-       ibmcam->camera_model = model;
-       ibmcam->remove_pending = 0;
-       ibmcam->last_error = 0;
-       ibmcam->dev = dev;
-       ibmcam->iface = ifnum;
-       ibmcam->ifaceAltInactive = 0;
-       ibmcam->ifaceAltActive = 1;
-       ibmcam->video_endp = endpoint->bEndpointAddress;
-       ibmcam->iso_packet_len = 1014;
-       ibmcam->compress = 0;
-       ibmcam->user=0; 
-
-       usb_ibmcam_configure_video(ibmcam);
-       up (&ibmcam->lock);
-
-       if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-               printk(KERN_ERR "video_register_device failed\n");
-               ibmcam = NULL; /* Do not free, it's preallocated */
+       uvd = usbvideo_AllocateDevice(cams);
+       if (uvd != NULL) {
+               /* Here uvd is a fully allocated uvd_t object */
+               uvd->flags = flags;
+               uvd->debug = debug;
+               uvd->dev = dev;
+               uvd->iface = ifnum;
+               uvd->ifaceAltInactive = inactInterface;
+               uvd->ifaceAltActive = actInterface;
+               uvd->video_endp = video_ep;
+               uvd->iso_packet_len = maxPS;
+               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+               uvd->canvas = VIDEOSIZE(canvasX, canvasY);
+               uvd->videosize = ibmcam_size_to_videosize(size);
+
+               /* Initialize ibmcam-specific data */
+               assert(IBMCAM_T(uvd) != NULL);
+               IBMCAM_T(uvd)->camera_model = model;
+               IBMCAM_T(uvd)->initialized = 0;
+
+               ibmcam_configure_video(uvd);
+
+               i = usbvideo_RegisterVideoDevice(uvd);
+               if (i != 0) {
+                       err("usbvideo_RegisterVideoDevice() failed.");
+                       uvd = NULL;
+               }
        }
-       if (debug > 1)
-               printk(KERN_DEBUG "video_register_device() successful\n");
-probe_done:
        MOD_DEC_USE_COUNT;
-       return ibmcam;
+       return uvd;
 }
 
 /*
- * usb_ibmcam_release()
+ * ibmcam_init()
  *
- * This code does final release of struct usb_ibmcam. This happens
- * after the device is disconnected -and- all clients closed their files.
+ * This code is run to initialize the driver.
  *
  * History:
- * 1/27/00  Created.
+ * 1/27/00  Reworked to use statically allocated ibmcam structures.
+ * 21/10/00 Completely redesigned to use usbvideo services.
  */
-static void usb_ibmcam_release(struct usb_ibmcam *ibmcam)
+static int __init ibmcam_init(void)
 {
-       video_unregister_device(&ibmcam->vdev);
-       if (debug > 0)
-               printk(KERN_DEBUG "usb_ibmcam_release: Video unregistered.\n");
-       ibmcam->ibmcam_used = 0;
-       ibmcam->initialized = 0;
+       usbvideo_cb_t cbTbl;
+       memset(&cbTbl, 0, sizeof(cbTbl));
+       cbTbl.probe = ibmcam_probe;
+       cbTbl.setupOnOpen = ibmcam_setup_on_open;
+       cbTbl.videoStart = ibmcam_video_start;
+       cbTbl.videoStop = ibmcam_video_stop;
+       cbTbl.processData = ibmcam_ProcessIsocData;
+       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
+       cbTbl.adjustPicture = ibmcam_adjust_picture;
+       cbTbl.getFPS = ibmcam_calculate_fps;
+       return usbvideo_register(
+               &cams,
+               MAX_IBMCAM,
+               sizeof(ibmcam_t),
+               "ibmcam",
+               &cbTbl,
+               THIS_MODULE);
 }
 
-/*
- * usb_ibmcam_disconnect()
- *
- * This procedure stops all driver activity, deallocates interface-private
- * structure (pointed by 'ptr') and after that driver should be removable
- * with no ill consequences.
- *
- * This code handles surprise removal. The ibmcam->user is a counter which
- * increments on open() and decrements on close(). If we see here that
- * this counter is not 0 then we have a client who still has us opened.
- * We set ibmcam->remove_pending flag as early as possible, and after that
- * all access to the camera will gracefully fail. These failures should
- * prompt client to (eventually) close the video device, and then - in
- * ibmcam_close() - we decrement ibmcam->ibmcam_used and usage counter.
- *
- * History:
- * 1/22/00  Added polling of MOD_IN_USE to delay removal until all users gone.
- * 1/27/00  Reworked to allow pending disconnects; see ibmcam_close()
- * 5/24/00  Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- */
-static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr)
+static void __exit ibmcam_cleanup(void)
 {
-       static const char proc[] = "usb_ibmcam_disconnect";
-       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *) ptr;
-
-       MOD_INC_USE_COUNT;
-
-       if (debug > 0)
-               printk(KERN_DEBUG "%s(%p,%p.)\n", proc, dev, ptr);
-
-       down(&ibmcam->lock);
-       ibmcam->remove_pending = 1; /* Now all ISO data will be ignored */
-
-       /* At this time we ask to cancel outstanding URBs */
-       ibmcam_stop_isoc(ibmcam);
-
-       ibmcam->dev = NULL;         /* USB device is no more */
-
-       if (ibmcam->user)
-               printk(KERN_INFO "%s: In use, disconnect pending.\n", proc);
-       else
-               usb_ibmcam_release(ibmcam);
-       up(&ibmcam->lock);
-       printk(KERN_INFO "IBM USB camera disconnected.\n");
-
-       MOD_DEC_USE_COUNT;
+       usbvideo_Deregister(&cams);
 }
 
-static struct usb_device_id ibmcam_table [] = {
-       { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002) },
-       { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, ibmcam_table);
+#if defined(usb_device_id_ver)
 
-static struct usb_driver ibmcam_driver = {
-       name:           "ibmcam",
-       probe:          usb_ibmcam_probe,
-       disconnect:     usb_ibmcam_disconnect,
-       id_table:       ibmcam_table,
+static __devinitdata struct usb_device_id id_table[] = {
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },        /* Model 1 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 2 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },        /* Model 3 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 4 */
+       { }  /* Terminating entry */
 };
+MODULE_DEVICE_TABLE(usb, id_table);
 
-/*
- * usb_ibmcam_init()
- *
- * This code is run to initialize the driver.
- *
- * History:
- * 1/27/00  Reworked to use statically allocated usb_ibmcam structures.
- */
-static int __init usb_ibmcam_init(void)
-{
-       unsigned u;
-
-       /* Initialize struct */
-       for (u = 0; u < MAX_IBMCAM; u++) {
-               struct usb_ibmcam *ibmcam = &cams[u];
-               memset (ibmcam, 0, sizeof(struct usb_ibmcam));
-       }
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-       return usb_register(&ibmcam_driver);
-}
-
-static void __exit usb_ibmcam_cleanup(void)
-{
-       usb_deregister(&ibmcam_driver);
-}
-
-module_init(usb_ibmcam_init);
-module_exit(usb_ibmcam_cleanup);
+#endif /* defined(usb_device_id_ver) */
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+module_init(ibmcam_init);
+module_exit(ibmcam_cleanup);
index 4d300c1..249de20 100644 (file)
  *     20010320 check return value of scsi_register()
  *     20010320 Version 0.4.3
  *     20010408 Identify version on module load.
+ *     20011003 Fix multiple requests
  */
 
 #include <linux/module.h>
@@ -500,7 +501,6 @@ void mts_int_submit_urb (struct urb* transfer,
                      context
                );
 
-       transfer->transfer_flags = USB_ASYNC_UNLINK;
        transfer->status = 0;
 
        res = usb_submit_urb( transfer );
@@ -520,7 +520,6 @@ static void mts_transfer_cleanup( struct urb *transfer )
 
        if ( context->final_callback )
                context->final_callback(context->srb);
-       up( &context->instance->lock );
 
 }
 
@@ -710,7 +709,6 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
                goto out;
        }
 
-       down(&desc->lock);
        
        FILL_BULK_URB(&desc->urb,
                      desc->usb_dev,
@@ -733,7 +731,6 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
 
                if(callback)
                        callback(srb);
-               up(&desc->lock);
 
        }
 
index ce02371..867fd0e 100644 (file)
@@ -61,7 +61,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION ""
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
@@ -1258,21 +1258,38 @@ static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
                        return -ENOMEM;
 
                uhci_add_td_to_urb(urb, td);
-               uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) |
+               uhci_fill_td(td, status, destination |
+                       (((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
                        (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
                         usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
                        data);
 
                data += pktsze;
-               len -= maxsze;
-
-               if (len <= 0)
-                       td->status |= TD_CTRL_IOC;
+               len -= pktsze;
 
                usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
                        usb_pipeout(urb->pipe));
        } while (len > 0);
 
+       if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
+          urb->transfer_buffer_length) {
+               td = uhci_alloc_td(uhci, urb->dev);
+               if (!td)
+                       return -ENOMEM;
+
+               uhci_add_td_to_urb(urb, td);
+               uhci_fill_td(td, status, destination | UHCI_NULL_DATA_SIZE |
+                       (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                        usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
+                       data);
+
+               usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                       usb_pipeout(urb->pipe));
+       }
+
+       /* Set the flag on the last packet */
+       td->status |= TD_CTRL_IOC;
+
        qh = uhci_alloc_qh(uhci, urb->dev);
        if (!qh)
                return -ENOMEM;
@@ -2343,11 +2360,11 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
 
        if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
                if (status & USBSTS_HSE)
-                       printk(KERN_ERR "uhci: host system error, PCI problems?\n");
+                       err("%x: host system error, PCI problems?", io_addr);
                if (status & USBSTS_HCPE)
-                       printk(KERN_ERR "uhci: host controller process error. something bad happened\n");
+                       err("%x: host controller process error. something bad happened", io_addr);
                if ((status & USBSTS_HCH) && !uhci->is_suspended) {
-                       printk(KERN_ERR "uhci: host controller halted. very bad\n");
+                       err("%x: host controller halted. very bad", io_addr);
                        /* FIXME: Reset the controller, fix the offending TD */
                }
        }
@@ -2463,37 +2480,74 @@ static void start_hc(struct uhci *uhci)
        outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
 }
 
-static int uhci_alloc_root_hub(struct uhci *uhci)
+#ifdef CONFIG_PROC_FS
+static int uhci_num = 0;
+#endif
+
+static void free_uhci(struct uhci *uhci)
 {
-       struct usb_device *dev;
+       kfree(uhci);
+}
 
-       dev = usb_alloc_dev(NULL, uhci->bus);
-       if (!dev)
-               return -1;
+/*
+ * De-allocate all resources..
+ */
+static void release_uhci(struct uhci *uhci)
+{
+       int i;
+#ifdef CONFIG_PROC_FS
+       char buf[8];
+#endif
 
-       uhci->bus->root_hub = dev;
-       uhci->rh.dev = dev;
+       if (uhci->irq >= 0) {
+               free_irq(uhci->irq, uhci);
+               uhci->irq = -1;
+       }
 
-       return 0;
-}
+       for (i = 0; i < UHCI_NUM_SKELQH; i++)
+               if (uhci->skelqh[i]) {
+                       uhci_free_qh(uhci, uhci->skelqh[i]);
+                       uhci->skelqh[i] = NULL;
+               }
 
-static int uhci_start_root_hub(struct uhci *uhci)
-{
-       usb_connect(uhci->rh.dev);
+       for (i = 0; i < UHCI_NUM_SKELTD; i++)
+               if (uhci->skeltd[i]) {
+                       uhci_free_td(uhci, uhci->skeltd[i]);
+                       uhci->skeltd[i] = NULL;
+               }
 
-       if (usb_new_device(uhci->rh.dev) != 0) {
-               usb_free_dev(uhci->rh.dev);
+       if (uhci->qh_pool) {
+               pci_pool_destroy(uhci->qh_pool);
+               uhci->qh_pool = NULL;
+       }
 
-               return -1;
+       if (uhci->td_pool) {
+               pci_pool_destroy(uhci->td_pool);
+               uhci->td_pool = NULL;
        }
 
-       return 0;
-}
+       if (uhci->fl) {
+               pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+               uhci->fl = NULL;
+       }
+
+       if (uhci->bus) {
+               usb_free_bus(uhci->bus);
+               uhci->bus = NULL;
+       }
 
 #ifdef CONFIG_PROC_FS
-static int uhci_num = 0;
+       if (uhci->proc_entry) {
+               sprintf(buf, "hc%d", uhci->num);
+
+               remove_proc_entry(buf, uhci_proc_root);
+               uhci->proc_entry = NULL;
+       }
 #endif
 
+       free_uhci(uhci);
+}
+
 /*
  * Allocate a frame list, and then setup the skeleton
  *
@@ -2504,27 +2558,96 @@ static int uhci_num = 0;
  *  - any isochronous events handled before any
  *    of the queues. We don't do that here, because
  *    we'll create the actual TD entries on demand.
- *  - The first queue is the "interrupt queue".
- *  - The second queue is the "control queue", split into low and high speed
- *  - The third queue is "bulk data".
+ *  - The first queue is the interrupt queue.
+ *  - The second queue is the control queue, split into low and high speed
+ *  - The third queue is bulk queue.
+ *  - The fourth queue is the bandwidth reclamation queue, which loops back
+ *    to the high speed control queue.
  */
-static struct uhci *alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io_size)
+static int alloc_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
 {
-       int i, port;
        struct uhci *uhci;
+       int retval = -EBUSY;
+       char buf[8], *bufp = buf;
+       int i, port;
        struct usb_bus *bus;
        dma_addr_t dma_handle;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *ent;
+#endif
 
-       uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
-       if (!uhci)
-               return NULL;
+       if (!request_region(io_addr, io_size, "usb-uhci")) {
+               err("couldn't allocate I/O range %x - %x", io_addr,
+                       io_addr + io_size - 1);
+               goto err_request_region;
+       }
+
+       if (!dev->irq) {
+               err("found UHCI device with no IRQ assigned. check BIOS settings!");
+               retval = -EINVAL;
+               goto err_invalid_irq;
+       }
+
+       if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
+               err("PCI subsystem doesn't support 32 bit addressing?");
+               retval = -ENODEV;
+               goto err_pci_dma_supported;
+       }
+
+       if (pci_enable_device(dev) < 0) {
+               err("couldn't enable PCI device");
+               goto err_enable_device;
+       }
+
+       pci_set_master(dev);
+
+#ifndef __sparc__
+       sprintf(buf, "%d", irq);
+#else
+       bufp = __irq_itoa(irq);
+#endif
+       printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+               io_addr, bufp);
+
+       if (pci_set_dma_mask(dev, 0xFFFFFFFF)) {
+               err("couldn't set PCI dma mask");
+               retval = -ENODEV;
+               goto err_pci_set_dma_mask;
+       }
 
-       memset(uhci, 0, sizeof(*uhci));
+       uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
+       if (!uhci) {
+               err("couldn't allocate uhci structure");
+               retval = -ENOMEM;
+               goto err_alloc_uhci;
+       }
 
        uhci->dev = dev;
-       uhci->irq = -1;
        uhci->io_addr = io_addr;
        uhci->io_size = io_size;
+       dev->driver_data = uhci;
+
+#ifdef CONFIG_PROC_FS
+       uhci->num = uhci_num++;
+
+       sprintf(buf, "hc%d", uhci->num);
+
+       ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
+       if (!ent) {
+               err("couldn't create uhci proc entry");
+               retval = -ENOMEM;
+               goto err_create_proc_entry;
+       }
+
+       ent->data = uhci;
+       ent->proc_fops = &uhci_proc_operations;
+       ent->size = 0;
+       uhci->proc_entry = ent;
+#endif
+
+       /* Reset here so we don't get any interrupts from an old setup */
+       /*  or broken setup */
+       reset_hc(uhci);
 
        spin_lock_init(&uhci->qh_remove_list_lock);
        INIT_LIST_HEAD(&uhci->qh_remove_list);
@@ -2542,10 +2665,13 @@ static struct uhci *alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsign
 
        /* We need exactly one page (per UHCI specs), how convenient */
        /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
+#if PAGE_SIZE < (4 * 1024)
+#error PAGE_SIZE is not atleast 4k
+#endif
        uhci->fl = pci_alloc_consistent(uhci->dev, sizeof(*uhci->fl), &dma_handle);
        if (!uhci->fl) {
-               printk(KERN_ERR "Unable to allocate consistent memory for frame list\n");
-               goto free_uhci;
+               err("unable to allocate consistent memory for frame list");
+               goto err_alloc_fl;
        }
 
        memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
@@ -2555,34 +2681,38 @@ static struct uhci *alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsign
        uhci->td_pool = pci_pool_create("uhci_td", uhci->dev,
                sizeof(struct uhci_td), 16, 0, GFP_DMA | GFP_ATOMIC);
        if (!uhci->td_pool) {
-               printk(KERN_ERR "Unable to create td pci_pool\n");
-               goto free_fl;
+               err("unable to create td pci_pool");
+               goto err_create_td_pool;
        }
 
        uhci->qh_pool = pci_pool_create("uhci_qh", uhci->dev,
                sizeof(struct uhci_qh), 16, 0, GFP_DMA | GFP_ATOMIC);
        if (!uhci->qh_pool) {
-               printk(KERN_ERR "Unable to create qh pci_pool\n");
-               goto free_td_pool;
+               err("unable to create qh pci_pool");
+               goto err_create_qh_pool;
        }
 
        bus = usb_alloc_bus(&uhci_device_operations);
-       if (!bus)
-               goto free_qh_pool;
+       if (!bus) {
+               err("unable to allocate bus");
+               goto err_alloc_bus;
+       }
 
        uhci->bus = bus;
        bus->hcpriv = uhci;
 
+       usb_register_bus(uhci->bus);
+
        /* Initialize the root hub */
 
        /* UHCI specs says devices must have 2 ports, but goes on to say */
        /*  they may have more but give no way to determine how many they */
        /*  have. However, according to the UHCI spec, Bit 7 is always set */
        /*  to 1. So we try to use this to our advantage */
-       for (port = 0; port < (io_size - 0x10) / 2; port++) {
+       for (port = 0; port < (uhci->io_size - 0x10) / 2; port++) {
                unsigned int portstatus;
 
-               portstatus = inw(io_addr + 0x10 + (port * 2));
+               portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
                if (!(portstatus & 0x0080))
                        break;
        }
@@ -2598,15 +2728,16 @@ static struct uhci *alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsign
 
        uhci->rh.numports = port;
 
-       if (uhci_alloc_root_hub(uhci)) {
+       uhci->bus->root_hub = uhci->rh.dev = usb_alloc_dev(NULL, uhci->bus);
+       if (!uhci->rh.dev) {
                err("unable to allocate root hub");
-               goto free_fl;
+               goto err_alloc_root_hub;
        }
 
        uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh.dev);
        if (!uhci->skeltd[0]) {
                err("unable to allocate TD 0");
-               goto free_fl;
+               goto err_alloc_skeltd;
        }
 
        /*
@@ -2619,7 +2750,7 @@ static struct uhci *alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsign
                td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh.dev);
                if (!td) {
                        err("unable to allocate TD %d", i);
-                       goto free_tds;
+                       goto err_alloc_skeltd;
                }
 
                uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
@@ -2628,15 +2759,15 @@ static struct uhci *alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsign
 
        uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh.dev);
        if (!uhci->skel_term_td) {
-               err("unable to allocate TD 0");
-               goto free_fl;
+               err("unable to allocate skel TD term");
+               goto err_alloc_skeltd;
        }
 
        for (i = 0; i < UHCI_NUM_SKELQH; i++) {
                uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh.dev);
                if (!uhci->skelqh[i]) {
                        err("unable to allocate QH %d", i);
-                       goto free_qhs;
+                       goto err_alloc_skelqh;
                }
        }
 
@@ -2695,157 +2826,88 @@ static struct uhci *alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsign
                uhci->fl->frame[i] =  uhci->skeltd[irq]->dma_handle;
        }
 
-       return uhci;
-
-/*
- * error exits:
- */
-free_qhs:
-       for (i = 0; i < UHCI_NUM_SKELQH; i++)
-               if (uhci->skelqh[i]) {
-                       uhci_free_qh(uhci, uhci->skelqh[i]);
-                       uhci->skelqh[i] = NULL;
-               }
+       start_hc(uhci);
 
-free_tds:
-       for (i = 0; i < UHCI_NUM_SKELTD; i++)
-               if (uhci->skeltd[i]) {
-                       uhci_free_td(uhci, uhci->skeltd[i]);
-                       uhci->skeltd[i] = NULL;
-               }
+       if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci))
+               goto err_request_irq;
 
-free_qh_pool:
-       pci_pool_destroy(uhci->qh_pool);
+       uhci->irq = irq;
 
-free_td_pool:
-       pci_pool_destroy(uhci->td_pool);
+       /* disable legacy emulation */
+       pci_write_config_word(uhci->dev, USBLEGSUP, 0);
 
-free_fl:
-       pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+       usb_connect(uhci->rh.dev);
 
-free_uhci:
-       kfree(uhci);
+       if (usb_new_device(uhci->rh.dev) != 0) {
+               err("unable to start root hub");
+               retval = -ENOMEM;
+               goto err_start_root_hub;
+       }
 
-       return NULL;
-}
+       return 0;
 
 /*
- * De-allocate all resources..
+ * error exits:
  */
-static void release_uhci(struct uhci *uhci)
-{
-       int i;
-#ifdef CONFIG_PROC_FS
-       char buf[8];
-#endif
-
-       if (uhci->irq >= 0) {
-               free_irq(uhci->irq, uhci);
-               uhci->irq = -1;
-       }
+err_start_root_hub:
+       free_irq(uhci->irq, uhci);
+       uhci->irq = -1;
 
+err_request_irq:
        for (i = 0; i < UHCI_NUM_SKELQH; i++)
                if (uhci->skelqh[i]) {
                        uhci_free_qh(uhci, uhci->skelqh[i]);
                        uhci->skelqh[i] = NULL;
                }
 
+err_alloc_skelqh:
        for (i = 0; i < UHCI_NUM_SKELTD; i++)
                if (uhci->skeltd[i]) {
                        uhci_free_td(uhci, uhci->skeltd[i]);
                        uhci->skeltd[i] = NULL;
                }
 
-       if (uhci->qh_pool) {
-               pci_pool_destroy(uhci->qh_pool);
-               uhci->qh_pool = NULL;
-       }
-
-       if (uhci->td_pool) {
-               pci_pool_destroy(uhci->td_pool);
-               uhci->td_pool = NULL;
-       }
-
-       if (uhci->fl) {
-               pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
-               uhci->fl = NULL;
-       }
+err_alloc_skeltd:
+       usb_free_dev(uhci->rh.dev);
+       uhci->rh.dev = NULL;
 
+err_alloc_root_hub:
        usb_free_bus(uhci->bus);
+       uhci->bus = NULL;
 
-#ifdef CONFIG_PROC_FS
-       sprintf(buf, "hc%d", uhci->num);
-
-       remove_proc_entry(buf, uhci_proc_root);
-       uhci->proc_entry = NULL;
-#endif
-
-       kfree(uhci);
-}
-
-/*
- * If we've successfully found a UHCI, now is the time to return success..
- */
-static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
-{
-       int retval;
-       struct uhci *uhci;
-       char buf[8], *bufp = buf;
-#ifdef CONFIG_PROC_FS
-       struct proc_dir_entry *ent;
-#endif
-
-#ifndef __sparc__
-       sprintf(buf, "%d", irq);
-#else
-       bufp = __irq_itoa(irq);
-#endif
-       printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
-               io_addr, bufp);
+err_alloc_bus:
+       pci_pool_destroy(uhci->qh_pool);
+       uhci->qh_pool = NULL;
 
-       uhci = alloc_uhci(dev, io_addr, io_size);
-       if (!uhci)
-               return -ENOMEM;
+err_create_qh_pool:
+       pci_pool_destroy(uhci->td_pool);
+       uhci->td_pool = NULL;
 
-       dev->driver_data = uhci;
+err_create_td_pool:
+       pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+       uhci->fl = NULL;
 
+err_alloc_fl:
 #ifdef CONFIG_PROC_FS
-       uhci->num = uhci_num++;
-
-       sprintf(buf, "hc%d", uhci->num);
-
-       ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
-       if (!ent)
-               return -ENOMEM;
+       remove_proc_entry(buf, uhci_proc_root);
+       uhci->proc_entry = NULL;
 
-       ent->data = uhci;
-       ent->proc_fops = &uhci_proc_operations;
-       ent->size = 0;
-       uhci->proc_entry = ent;
+err_create_proc_entry:
+       free_uhci(uhci);
 #endif
 
-       request_region(uhci->io_addr, io_size, "usb-uhci");
-
-       reset_hc(uhci);
-
-       usb_register_bus(uhci->bus);
-       start_hc(uhci);
+err_alloc_uhci:
 
-       retval = -EBUSY;
-       if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) {
-               uhci->irq = irq;
+err_pci_set_dma_mask:
 
-               pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+err_enable_device:
 
-               if (!uhci_start_root_hub(uhci))
-                       return 0;
-       }
+err_pci_dma_supported:
+       release_region(io_addr, io_size);
 
-       /* Couldn't allocate IRQ if we got here */
+err_invalid_irq:
 
-       reset_hc(uhci);
-       release_region(uhci->io_addr, uhci->io_size);
-       release_uhci(uhci);
+err_request_region:
 
        return retval;
 }
@@ -2854,23 +2916,6 @@ static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device
 {
        int i;
 
-       if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
-               err("PCI subsystem doesn't support 32 bit addressing?");
-               return -ENODEV;
-       }
-       dev->dma_mask = 0xFFFFFFFF;
-
-       /* disable legacy emulation */
-       pci_write_config_word(dev, USBLEGSUP, 0);
-
-       if (pci_enable_device(dev) < 0)
-               return -ENODEV;
-
-       if (!dev->irq) {
-               err("found UHCI device with no IRQ assigned. check BIOS settings!");
-               return -ENODEV;
-       }
-
        /* Search for the IO base address.. */
        for (i = 0; i < 6; i++) {
                unsigned int io_addr = pci_resource_start(dev, i);
@@ -2880,12 +2925,7 @@ static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device
                if (!(pci_resource_flags(dev, i) & IORESOURCE_IO))
                        continue;
 
-               /* Is it already in use? */
-               if (check_region(io_addr, io_size))
-                       break;
-
-               pci_set_master(dev);
-               return setup_uhci(dev, dev->irq, io_addr, io_size);
+               return alloc_uhci(dev, dev->irq, io_addr, io_size);
        }
 
        return -ENODEV;
@@ -2945,11 +2985,11 @@ static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
        }, { /* end: all zeroes */ }
 };
 
-MODULE_DEVICE_TABLE (pci, uhci_pci_ids);
+MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
 
 static struct pci_driver uhci_pci_driver = {
        name:           "usb-uhci",
-       id_table:       &uhci_pci_ids [0],
+       id_table:       uhci_pci_ids,
 
        probe:          uhci_pci_probe,
        remove:         uhci_pci_remove,
@@ -2965,6 +3005,8 @@ static int __init uhci_hcd_init(void)
 {
        int retval = -ENOMEM;
 
+       info(DRIVER_DESC " " DRIVER_VERSION);
+
        if (debug) {
                errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
                if (!errbuf)
@@ -2986,8 +3028,6 @@ static int __init uhci_hcd_init(void)
        if (retval)
                goto init_failed;
 
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-
        return 0;
 
 init_failed:
@@ -3009,7 +3049,7 @@ errbuf_failed:
        return retval;
 }
 
-static void __exit uhci_hcd_cleanup (void) 
+static void __exit uhci_hcd_cleanup(void) 
 {
        pci_unregister_driver(&uhci_pci_driver);
        
@@ -3027,6 +3067,6 @@ static void __exit uhci_hcd_cleanup (void)
 module_init(uhci_hcd_init);
 module_exit(uhci_hcd_cleanup);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/ultracam.c b/drivers/usb/ultracam.c
new file mode 100644 (file)
index 0000000..815ae20
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * USB NB Camera driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/wrapper.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "usbvideo.h"
+
+#define        ULTRACAM_VENDOR_ID      0x0461
+#define        ULTRACAM_PRODUCT_ID     0x0813
+
+#define MAX_CAMERAS            4       /* How many devices we allow to connect */
+
+/*
+ * This structure lives in uvd_t->user field.
+ */
+typedef struct {
+       int initialized;        /* Had we already sent init sequence? */
+       int camera_model;       /* What type of IBM camera we got? */
+        int has_hdr;
+} ultracam_t;
+#define        ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data))
+
+static usbvideo_t *cams = NULL;
+
+static int debug = 0;
+
+static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+
+static const int min_canvasWidth  = 8;
+static const int min_canvasHeight = 4;
+
+//static int lighting = 1; /* Medium */
+
+#define SHARPNESS_MIN  0
+#define SHARPNESS_MAX  6
+//static int sharpness = 4; /* Low noise, good details */
+
+#define FRAMERATE_MIN  0
+#define FRAMERATE_MAX  6
+static int framerate = -1;
+
+/*
+ * Here we define several initialization variables. They may
+ * be used to automatically set color, hue, brightness and
+ * contrast to desired values. This is particularly useful in
+ * case of webcams (which have no controls and no on-screen
+ * output) and also when a client V4L software is used that
+ * does not have some of those controls. In any case it's
+ * good to have startup values as options.
+ *
+ * These values are all in [0..255] range. This simplifies
+ * operation. Note that actual values of V4L variables may
+ * be scaled up (as much as << 8). User can see that only
+ * on overlay output, however, or through a V4L client.
+ */
+static int init_brightness = 128;
+static int init_contrast = 192;
+static int init_color = 128;
+static int init_hue = 128;
+static int hue_correction = 128;
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+MODULE_PARM(flags, "i");
+MODULE_PARM_DESC(flags,
+               "Bitfield: 0=VIDIOCSYNC, "
+               "1=B/W, "
+               "2=show hints, "
+               "3=show stats, "
+               "4=test pattern, "
+               "5=separate frames, "
+               "6=clean frames");
+MODULE_PARM(framerate, "i");
+MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
+MODULE_PARM(lighting, "i");
+MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
+MODULE_PARM(sharpness, "i");
+MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
+
+MODULE_PARM(init_brightness, "i");
+MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
+MODULE_PARM(init_contrast, "i");
+MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
+MODULE_PARM(init_color, "i");
+MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
+MODULE_PARM(init_hue, "i");
+MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
+MODULE_PARM(hue_correction, "i");
+MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
+
+/*
+ * ultracam_ProcessIsocData()
+ *
+ * Generic routine to parse the ring queue data. It employs either
+ * ultracam_find_header() or ultracam_parse_lines() to do most
+ * of work.
+ *
+ * 02-Nov-2000 First (mostly dummy) version.
+ * 06-Nov-2000 Rewrote to dump all data into frame.
+ */
+void ultracam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
+{
+       int n;
+
+       assert(uvd != NULL);
+       assert(frame != NULL);
+
+       /* Try to move data from queue into frame buffer */
+       n = RingQueue_GetLength(&uvd->dp);
+       if (n > 0) {
+               int m;
+               /* See how much spare we have left */
+               m = uvd->max_frame_size - frame->seqRead_Length;
+               if (n > m)
+                       n = m;
+               /* Now move that much data into frame buffer */
+               RingQueue_Dequeue(
+                       &uvd->dp,
+                       frame->data + frame->seqRead_Length,
+                       m);
+               frame->seqRead_Length += m;
+       }
+       /* See if we filled the frame */
+       if (frame->seqRead_Length >= uvd->max_frame_size) {
+               frame->frameState = FrameState_Done;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+       }
+}
+
+/*
+ * ultracam_veio()
+ *
+ * History:
+ * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
+ */
+static int ultracam_veio(
+       uvd_t *uvd,
+       unsigned char req,
+       unsigned short value,
+       unsigned short index,
+       int is_out)
+{
+       static const char proc[] = "ultracam_veio";
+       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
+       int i;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return 0;
+
+       if (!is_out) {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_rcvctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       cp,
+                       sizeof(cp),
+                       HZ);
+#if 1
+               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                      "(req=$%02x val=$%04x ind=$%04x)",
+                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+                      req, value, index);
+#endif
+       } else {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_sndctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       NULL,
+                       0,
+                       HZ);
+       }
+       if (i < 0) {
+               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
+                   proc, i);
+               uvd->last_error = i;
+       }
+       return i;
+}
+
+/*
+ * ultracam_calculate_fps()
+ */
+static int ultracam_calculate_fps(uvd_t *uvd)
+{
+       return 3 + framerate*4 + framerate/2;
+}
+
+/*
+ * ultracam_adjust_contrast()
+ */
+static void ultracam_adjust_contrast(uvd_t *uvd)
+{
+}
+
+/*
+ * ultracam_change_lighting_conditions()
+ */
+static void ultracam_change_lighting_conditions(uvd_t *uvd)
+{
+}
+
+/*
+ * ultracam_set_sharpness()
+ *
+ * Cameras model 1 have internal smoothing feature. It is controlled by value in
+ * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
+ * Recommended value is 4. Cameras model 2 do not have this feature at all.
+ */
+static void ultracam_set_sharpness(uvd_t *uvd)
+{
+}
+
+/*
+ * ultracam_set_brightness()
+ *
+ * This procedure changes brightness of the picture.
+ */
+static void ultracam_set_brightness(uvd_t *uvd)
+{
+}
+
+static void ultracam_set_hue(uvd_t *uvd)
+{
+}
+
+/*
+ * ultracam_adjust_picture()
+ *
+ * This procedure gets called from V4L interface to update picture settings.
+ * Here we change brightness and contrast.
+ */
+static void ultracam_adjust_picture(uvd_t *uvd)
+{
+       ultracam_adjust_contrast(uvd);
+       ultracam_set_brightness(uvd);
+       ultracam_set_hue(uvd);
+}
+
+/*
+ * ultracam_video_stop()
+ *
+ * This code tells camera to stop streaming. The interface remains
+ * configured and bandwidth - claimed.
+ */
+static void ultracam_video_stop(uvd_t *uvd)
+{
+}
+
+/*
+ * ultracam_reinit_iso()
+ *
+ * This procedure sends couple of commands to the camera and then
+ * resets the video pipe. This sequence was observed to reinit the
+ * camera or, at least, to initiate ISO data stream.
+ */
+static void ultracam_reinit_iso(uvd_t *uvd, int do_stop)
+{
+}
+
+static void ultracam_video_start(uvd_t *uvd)
+{
+       ultracam_change_lighting_conditions(uvd);
+       ultracam_set_sharpness(uvd);
+       ultracam_reinit_iso(uvd, 0);
+}
+
+static int ultracam_resetPipe(uvd_t *uvd)
+{
+       usb_clear_halt(uvd->dev, uvd->video_endp);
+       return 0;
+}
+
+static int ultracam_alternateSetting(uvd_t *uvd, int setting)
+{
+       static const char proc[] = "ultracam_alternateSetting";
+       int i;
+       i = usb_set_interface(uvd->dev, uvd->iface, setting);
+       if (i < 0) {
+               err("%s: usb_set_interface error", proc);
+               uvd->last_error = i;
+               return -EBUSY;
+       }
+       return 0;
+}
+
+/*
+ * Return negative code on failure, 0 on success.
+ */
+static int ultracam_setup_on_open(uvd_t *uvd)
+{
+       int setup_ok = 0; /* Success by default */
+       /* Send init sequence only once, it's large! */
+       if (!ULTRACAM_T(uvd)->initialized) {
+               ultracam_alternateSetting(uvd, 0x04);
+               ultracam_alternateSetting(uvd, 0x00);
+               ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1);
+               ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1);
+               ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1);
+               ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1);
+               ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1);
+               ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1);
+               ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1);
+               ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1);
+               ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1);
+               ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1);
+               ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1);
+               ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1);
+               ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
+               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
+               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
+               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
+               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
+               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
+               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
+               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1);
+               ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1);
+               ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1);
+               ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1);
+               ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1);
+               ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1);
+               ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1);
+               ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1);
+               ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1);
+               ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1);
+               ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1);
+               ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1);
+               ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1);
+               ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1);
+               ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1);
+               ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1);
+               ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1);
+               ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1);
+               ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1);
+               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
+               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
+               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
+               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
+               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
+               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
+               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
+               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0);
+               ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1);
+               ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1);
+               ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1);
+               ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1);
+               ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1);
+               ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1);
+               ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_alternateSetting(uvd, 0x04);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1);
+               ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1);
+               ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0);
+               ultracam_resetPipe(uvd);
+               ULTRACAM_T(uvd)->initialized = (setup_ok != 0);
+       }
+       return setup_ok;
+}
+
+static void ultracam_configure_video(uvd_t *uvd)
+{
+       if (uvd == NULL)
+               return;
+
+       RESTRICT_TO_RANGE(init_brightness, 0, 255);
+       RESTRICT_TO_RANGE(init_contrast, 0, 255);
+       RESTRICT_TO_RANGE(init_color, 0, 255);
+       RESTRICT_TO_RANGE(init_hue, 0, 255);
+       RESTRICT_TO_RANGE(hue_correction, 0, 255);
+
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       uvd->vpic.colour = init_color << 8;
+       uvd->vpic.hue = init_hue << 8;
+       uvd->vpic.brightness = init_brightness << 8;
+       uvd->vpic.contrast = init_contrast << 8;
+       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
+       uvd->vpic.depth = 24;
+       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "IBM Ultra Camera");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
+       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
+       uvd->vcap.minwidth = min_canvasWidth;
+       uvd->vcap.minheight = min_canvasHeight;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
+}
+
+/*
+ * ultracam_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like our camera.
+ *
+ * History:
+ * 12-Nov-2000 Reworked to comply with new probe() signature.
+ * 23-Jan-2001 Added compatibility with 2.2.x kernels.
+ */
+static void *ultracam_probe(struct usb_device *dev, unsigned int ifnum
+#if defined(usb_device_id_ver)
+       ,const struct usb_device_id *devid
+#endif
+       )
+{
+       uvd_t *uvd = NULL;
+       int i, nas;
+       int actInterface=-1, inactInterface=-1, maxPS=0;
+       unsigned char video_ep = 0;
+
+       if (debug >= 1)
+               info("ultracam_probe(%p,%u.)", dev, ifnum);
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return NULL;
+
+       /* Is it an IBM camera? */
+       if ((dev->descriptor.idVendor != ULTRACAM_VENDOR_ID) ||
+           (dev->descriptor.idProduct != ULTRACAM_PRODUCT_ID))
+               return NULL;
+
+       info("IBM Ultra camera found (rev. 0x%04x)", dev->descriptor.bcdDevice);
+
+       /* Validate found interface: must have one ISO endpoint */
+       nas = dev->actconfig->interface[ifnum].num_altsetting;
+       if (debug > 0)
+               info("Number of alternate settings=%d.", nas);
+       if (nas < 8) {
+               err("Too few alternate settings for this camera!");
+               return NULL;
+       }
+       /* Validate all alternate settings */
+       for (i=0; i < nas; i++) {
+               const struct usb_interface_descriptor *interface;
+               const struct usb_endpoint_descriptor *endpoint;
+
+               interface = &dev->actconfig->interface[ifnum].altsetting[i];
+               if (interface->bNumEndpoints != 1) {
+                       err("Interface %d. has %u. endpoints!",
+                           ifnum, (unsigned)(interface->bNumEndpoints));
+                       return NULL;
+               }
+               endpoint = &interface->endpoint[0];
+               if (video_ep == 0)
+                       video_ep = endpoint->bEndpointAddress;
+               else if (video_ep != endpoint->bEndpointAddress) {
+                       err("Alternate settings have different endpoint addresses!");
+                       return NULL;
+               }
+               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+                       err("Interface %d. has non-ISO endpoint!", ifnum);
+                       return NULL;
+               }
+               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+                       err("Interface %d. has ISO OUT endpoint!", ifnum);
+                       return NULL;
+               }
+               if (endpoint->wMaxPacketSize == 0) {
+                       if (inactInterface < 0)
+                               inactInterface = i;
+                       else {
+                               err("More than one inactive alt. setting!");
+                               return NULL;
+                       }
+               } else {
+                       if (actInterface < 0) {
+                               actInterface = i;
+                               maxPS = endpoint->wMaxPacketSize;
+                               if (debug > 0)
+                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
+                       } else {
+                               /* Got another active alt. setting */
+                               if (maxPS < endpoint->wMaxPacketSize) {
+                                       /* This one is better! */
+                                       actInterface = i;
+                                       maxPS = endpoint->wMaxPacketSize;
+                                       if (debug > 0) {
+                                               info("Even better ctive setting=%d. maxPS=%d.",
+                                                    i, maxPS);
+                                       }
+                               }
+                       }
+               }
+       }
+       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
+               err("Failed to recognize the camera!");
+               return NULL;
+       }
+
+       /* Code below may sleep, need to lock module while we are here */
+       MOD_INC_USE_COUNT;
+       uvd = usbvideo_AllocateDevice(cams);
+       if (uvd != NULL) {
+               /* Here uvd is a fully allocated uvd_t object */
+               uvd->flags = flags;
+               uvd->debug = debug;
+               uvd->dev = dev;
+               uvd->iface = ifnum;
+               uvd->ifaceAltInactive = inactInterface;
+               uvd->ifaceAltActive = actInterface;
+               uvd->video_endp = video_ep;
+               uvd->iso_packet_len = maxPS;
+               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+               uvd->canvas = VIDEOSIZE(640, 480);      /* FIXME */
+               uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/
+
+               /* Initialize ibmcam-specific data */
+               assert(ULTRACAM_T(uvd) != NULL);
+               ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */
+               ULTRACAM_T(uvd)->initialized = 0;
+
+               ultracam_configure_video(uvd);
+
+               i = usbvideo_RegisterVideoDevice(uvd);
+               if (i != 0) {
+                       err("usbvideo_RegisterVideoDevice() failed.");
+                       uvd = NULL;
+               }
+       }
+       MOD_DEC_USE_COUNT;
+       return uvd;
+}
+
+/*
+ * ultracam_init()
+ *
+ * This code is run to initialize the driver.
+ */
+static int __init ultracam_init(void)
+{
+       usbvideo_cb_t cbTbl;
+       memset(&cbTbl, 0, sizeof(cbTbl));
+       cbTbl.probe = ultracam_probe;
+       cbTbl.setupOnOpen = ultracam_setup_on_open;
+       cbTbl.videoStart = ultracam_video_start;
+       cbTbl.videoStop = ultracam_video_stop;
+       cbTbl.processData = ultracam_ProcessIsocData;
+       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
+       cbTbl.adjustPicture = ultracam_adjust_picture;
+       cbTbl.getFPS = ultracam_calculate_fps;
+       return usbvideo_register(
+               &cams,
+               MAX_CAMERAS,
+               sizeof(ultracam_t),
+               "ultracam",
+               &cbTbl,
+               THIS_MODULE);
+}
+
+static void __exit ultracam_cleanup(void)
+{
+       usbvideo_Deregister(&cams);
+}
+
+#if defined(usb_device_id_ver)
+
+static __devinitdata struct usb_device_id id_table[] = {
+       { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
+       { }  /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+
+#endif /* defined(usb_device_id_ver) */
+MODULE_LICENSE("GPL");
+
+module_init(ultracam_init);
+module_exit(ultracam_cleanup);
index 65929d2..e8a8d9e 100644 (file)
@@ -71,9 +71,6 @@
 #define DEBUG_SYMBOLS
 #ifdef DEBUG_SYMBOLS
        #define _static
-       #ifndef EXPORT_SYMTAB
-               #define EXPORT_SYMTAB
-       #endif
 #else
        #define _static static
 #endif
index 0942fc9..cca31f5 100644 (file)
@@ -255,13 +255,7 @@ typedef struct {
  * that default to usbvideo-provided methods.
  */
 typedef struct {
-#if defined(usb_device_id_ver)
-       /* New style probe (for 2.4.x kernels with hotplugging) */
        void *(*probe)(struct usb_device *, unsigned int,const struct usb_device_id *);
-#else
-       /* Old style probe (for 2.2.x kernels) */
-       void *(*probe)(struct usb_device *, unsigned int);
-#endif
        void (*userFree)(uvd_t *);
        void (*disconnect)(struct usb_device *, void *);
        int (*setupOnOpen)(uvd_t *);
index d6a4889..624f232 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -11,6 +11,7 @@
 #include <linux/smp_lock.h>
 #include <linux/dnotify.h>
 #include <linux/fcntl.h>
+#include <linux/quotaops.h>
 
 /* Taken over from the old code... */
 
@@ -131,8 +132,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
                error = inode->i_op->setattr(dentry, attr);
        else {
                error = inode_change_ok(inode, attr);
-               if (!error)
-                       inode_setattr(inode, attr);
+               if (!error) {
+                       if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+                           (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
+                               error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
+                       if (!error)
+                               inode_setattr(inode, attr);
+               }
        }
        unlock_kernel();
        if (!error) {
index ee93f1f..fc59634 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/highuid.h>
 #include <linux/smp_lock.h>
 #include <linux/compiler.h>
+#include <linux/limits.h>
 
 #include <asm/uaccess.h>
 #include <asm/param.h>
@@ -444,9 +445,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        /* Now read in all of the header information */
 
        retval = -ENOMEM;
-       size = ((unsigned int)elf_ex.e_phentsize) * elf_ex.e_phnum;
-       if (size > 65536)
+       if (elf_ex.e_phentsize != sizeof(struct elf_phdr))
                goto out;
+       if (elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
+               goto out;
+       size = elf_ex.e_phnum * sizeof(struct elf_phdr);
        elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
        if (!elf_phdata)
                goto out;
@@ -472,16 +475,14 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 
        for (i = 0; i < elf_ex.e_phnum; i++) {
                if (elf_ppnt->p_type == PT_INTERP) {
-                       retval = -EINVAL;
-                       if (elf_interpreter)
-                               goto out_free_dentry;
-
                        /* This is the program interpreter used for
                         * shared libraries - for now assume that this
                         * is an a.out format binary
                         */
 
                        retval = -ENOMEM;
+                       if (elf_ppnt->p_filesz > PATH_MAX)
+                               goto out_free_file;
                        elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
                                                           GFP_KERNEL);
                        if (!elf_interpreter)
@@ -536,6 +537,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                        /* Get the exec headers */
                        interp_ex = *((struct exec *) bprm->buf);
                        interp_elf_ex = *((struct elfhdr *) bprm->buf);
+                       break;
                }
                elf_ppnt++;
        }
@@ -805,7 +807,7 @@ out_free_ph:
 static int load_elf_library(struct file *file)
 {
        struct elf_phdr *elf_phdata;
-       unsigned long elf_bss = 0, bss, len, k;
+       unsigned long elf_bss, bss, len;
        int retval, error, i, j;
        struct elfhdr elf_ex;
 
@@ -825,19 +827,18 @@ static int load_elf_library(struct file *file)
        /* Now read in all of the header information */
 
        j = sizeof(struct elf_phdr) * elf_ex.e_phnum;
-       if (j > ELF_MIN_ALIGN)
-               goto out;
+       /* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */
 
        error = -ENOMEM;
        elf_phdata = (struct elf_phdr *) kmalloc(j, GFP_KERNEL);
        if (!elf_phdata)
                goto out;
 
-       /* N.B. check for error return?? */
-       retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata,
-                          sizeof(struct elf_phdr) * elf_ex.e_phnum);
-
        error = -ENOEXEC;
+       retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata, j);
+       if (retval != j)
+               goto out_free_ph;
+
        for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
                if ((elf_phdata + i)->p_type == PT_LOAD) j++;
        if (j != 1)
@@ -859,9 +860,7 @@ static int load_elf_library(struct file *file)
        if (error != ELF_PAGESTART(elf_phdata->p_vaddr))
                goto out_free_ph;
 
-       k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
-       if (k > elf_bss)
-               elf_bss = k;
+       elf_bss = elf_phdata->p_vaddr + elf_phdata->p_filesz;
        padzero(elf_bss);
 
        len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
index 41d6cda..8e3ec28 100644 (file)
@@ -26,7 +26,7 @@
  *             dquot_incr_...() to calling functions.
  *             invalidate_dquots() now writes modified dquots.
  *             Serialized quota_off() and quota_on() for mount point.
- *             Fixed a few bugs in grow_dquots.
+ *             Fixed a few bugs in grow_dquots().
  *             Fixed deadlock in write_dquot() - we no longer account quotas on
  *             quota files
  *             remove_dquot_ref() moved to inode.c - it now traverses through inodes
  *             Added check for bogus uid and fixed check for group in quotactl.
  *             Jan Kara, <jack@suse.cz>, sponsored by SuSE CR, 10-11/99
  *
+ *             Used struct list_head instead of own list struct
+ *             Invalidation of dquots with dq_count > 0 no longer possible
+ *             Improved free_dquots list management
+ *             Quota and i_blocks are now updated in one place to avoid races
+ *             Warnings are now delayed so we won't block in critical section
+ *             Write updated not to require dquot lock
+ *             Jan Kara, <jack@suse.cz>, 9/2000
+ *
+ *             Added dynamic quota structure allocation
+ *             Jan Kara <jack@suse.cz> 12/2000
+ *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/fs.h>
 #include <linux/sched.h>
-
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
@@ -48,8 +59,6 @@
 #include <linux/tty.h>
 #include <linux/file.h>
 #include <linux/slab.h>
-#include <linux/mount.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
@@ -58,9 +67,7 @@
 #define __DQUOT_VERSION__      "dquot_6.4.0"
 
 int nr_dquots, nr_free_dquots;
-int max_dquots = NR_DQUOTS;
 
-static char quotamessage[MAX_QUOTA_MESSAGE];
 static char *quotatypes[] = INITQFNAMES;
 
 static inline struct quota_mount_options *sb_dqopt(struct super_block *sb)
@@ -74,28 +81,41 @@ static inline struct quota_mount_options *sb_dqopt(struct super_block *sb)
  * free_dquots, and dquot_hash[] array. A single dquot structure may be
  * on all three lists, depending on its current state.
  *
- * All dquots are placed on the inuse_list when first created, and this
+ * All dquots are placed to the end of inuse_list when first created, and this
  * list is used for the sync and invalidate operations, which must look
  * at every dquot.
  *
  * Unused dquots (dq_count == 0) are added to the free_dquots list when
  * freed, and this list is searched whenever we need an available dquot.
  * Dquots are removed from the list as soon as they are used again, and
- * nr_free_dquots gives the number of dquots on the list.
+ * nr_free_dquots gives the number of dquots on the list. When dquot is
+ * invalidated it's completely released from memory.
  *
  * Dquots with a specific identity (device, type and id) are placed on
  * one of the dquot_hash[] hash chains. The provides an efficient search
- * mechanism to lcoate a specific dquot.
+ * mechanism to locate a specific dquot.
+ */
+
+/*
+ * Note that any operation which operates on dquot data (ie. dq_dqb) mustn't
+ * block while it's updating/reading it. Otherwise races would occur.
+ *
+ * Locked dquots might not be referenced in inodes - operations like
+ * add_dquot_space() does dqduplicate() and would complain. Currently
+ * dquot it locked only once in its existence - when it's being read
+ * to memory on first dqget() and at that time it can't be referenced
+ * from inode. Write operations on dquots don't hold dquot lock as they
+ * copy data to internal buffers before writing anyway and copying as well
+ * as any data update should be atomic. Also nobody can change used
+ * entries in dquot structure as this is done only when quota is destroyed
+ * and invalidate_dquots() waits for dquot to have dq_count == 0.
  */
 
-static struct dquot *inuse_list;
+static LIST_HEAD(inuse_list);
 static LIST_HEAD(free_dquots);
-static struct dquot *dquot_hash[NR_DQHASH];
-static int dquot_updating[NR_DQHASH];
+static struct list_head dquot_hash[NR_DQHASH];
 
 static struct dqstats dqstats;
-static DECLARE_WAIT_QUEUE_HEAD(dquot_wait);
-static DECLARE_WAIT_QUEUE_HEAD(update_wait);
 
 static void dqput(struct dquot *);
 static struct dquot *dqduplicate(struct dquot *);
@@ -123,38 +143,27 @@ static inline int const hashfn(kdev_t dev, unsigned int id, short type)
 
 static inline void insert_dquot_hash(struct dquot *dquot)
 {
-       struct dquot **htable;
-
-       htable = &dquot_hash[hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type)];
-       if ((dquot->dq_hash_next = *htable) != NULL)
-               (*htable)->dq_hash_pprev = &dquot->dq_hash_next;
-       *htable = dquot;
-       dquot->dq_hash_pprev = htable;
-}
-
-static inline void hash_dquot(struct dquot *dquot)
-{
-       insert_dquot_hash(dquot);
+       struct list_head *head = dquot_hash + hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type);
+       list_add(&dquot->dq_hash, head);
 }
 
-static inline void unhash_dquot(struct dquot *dquot)
+static inline void remove_dquot_hash(struct dquot *dquot)
 {
-       if (dquot->dq_hash_pprev) {
-               if (dquot->dq_hash_next)
-                       dquot->dq_hash_next->dq_hash_pprev = dquot->dq_hash_pprev;
-               *(dquot->dq_hash_pprev) = dquot->dq_hash_next;
-               dquot->dq_hash_pprev = NULL;
-       }
+       list_del(&dquot->dq_hash);
+       INIT_LIST_HEAD(&dquot->dq_hash);
 }
 
 static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigned int id, short type)
 {
+       struct list_head *head;
        struct dquot *dquot;
 
-       for (dquot = dquot_hash[hashent]; dquot; dquot = dquot->dq_hash_next)
+       for (head = dquot_hash[hashent].next; head != dquot_hash+hashent; head = head->next) {
+               dquot = list_entry(head, struct dquot, dq_hash);
                if (dquot->dq_dev == dev && dquot->dq_id == id && dquot->dq_type == type)
-                       break;
-       return dquot;
+                       return dquot;
+       }
+       return NODQUOT;
 }
 
 /* Add a dquot to the head of the free list */
@@ -171,6 +180,13 @@ static inline void put_dquot_last(struct dquot *dquot)
        nr_free_dquots++;
 }
 
+/* Move dquot to the head of free list (it must be already on it) */
+static inline void move_dquot_head(struct dquot *dquot)
+{
+       list_del(&dquot->dq_free);
+       list_add(&dquot->dq_free, &free_dquots);
+}
+
 static inline void remove_free_dquot(struct dquot *dquot)
 {
        /* sanity check */
@@ -185,36 +201,30 @@ static inline void remove_free_dquot(struct dquot *dquot)
 
 static inline void put_inuse(struct dquot *dquot)
 {
-       if ((dquot->dq_next = inuse_list) != NULL)
-               inuse_list->dq_pprev = &dquot->dq_next;
-       inuse_list = dquot;
-       dquot->dq_pprev = &inuse_list;
+       /* We add to the back of inuse list so we don't have to restart
+        * when traversing this list and we block */
+       list_add(&dquot->dq_inuse, inuse_list.prev);
+       nr_dquots++;
 }
 
-#if 0  /* currently not needed */
 static inline void remove_inuse(struct dquot *dquot)
 {
-       if (dquot->dq_pprev) {
-               if (dquot->dq_next)
-                       dquot->dq_next->dq_pprev = dquot->dq_pprev;
-               *dquot->dq_pprev = dquot->dq_next;
-               dquot->dq_pprev = NULL;
-       }
+       nr_dquots--;
+       list_del(&dquot->dq_inuse);
 }
-#endif
 
 static void __wait_on_dquot(struct dquot *dquot)
 {
        DECLARE_WAITQUEUE(wait, current);
 
-       add_wait_queue(&dquot->dq_wait, &wait);
+       add_wait_queue(&dquot->dq_wait_lock, &wait);
 repeat:
        set_current_state(TASK_UNINTERRUPTIBLE);
        if (dquot->dq_flags & DQ_LOCKED) {
                schedule();
                goto repeat;
        }
-       remove_wait_queue(&dquot->dq_wait, &wait);
+       remove_wait_queue(&dquot->dq_wait_lock, &wait);
        current->state = TASK_RUNNING;
 }
 
@@ -233,7 +243,22 @@ static inline void lock_dquot(struct dquot *dquot)
 static inline void unlock_dquot(struct dquot *dquot)
 {
        dquot->dq_flags &= ~DQ_LOCKED;
-       wake_up(&dquot->dq_wait);
+       wake_up(&dquot->dq_wait_lock);
+}
+
+static void __wait_dquot_unused(struct dquot *dquot)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(&dquot->dq_wait_free, &wait);
+repeat:
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       if (dquot->dq_count) {
+               schedule();
+               goto repeat;
+       }
+       remove_wait_queue(&dquot->dq_wait_free, &wait);
+       current->state = TASK_RUNNING;
 }
 
 /*
@@ -247,12 +272,8 @@ static void write_dquot(struct dquot *dquot)
        loff_t offset;
        ssize_t ret;
        struct semaphore *sem = &dquot->dq_sb->s_dquot.dqio_sem;
+       struct dqblk dqbuf;
 
-       lock_dquot(dquot);
-       if (!dquot->dq_sb) {    /* Invalidated quota? */
-               unlock_dquot(dquot);
-               return;
-       }
        down(sem);
        filp = dquot->dq_sb->s_dquot.files[type];
        offset = dqoff(dquot->dq_id);
@@ -263,10 +284,11 @@ static void write_dquot(struct dquot *dquot)
         * Note: clear the DQ_MOD flag unconditionally,
         * so we don't loop forever on failure.
         */
+       memcpy(&dqbuf, &dquot->dq_dqb, sizeof(struct dqblk));
        dquot->dq_flags &= ~DQ_MOD;
        ret = 0;
        if (filp)
-               ret = filp->f_op->write(filp, (char *)&dquot->dq_dqb, 
+               ret = filp->f_op->write(filp, (char *)&dqbuf, 
                                        sizeof(struct dqblk), &offset);
        if (ret != sizeof(struct dqblk))
                printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
@@ -274,8 +296,6 @@ static void write_dquot(struct dquot *dquot)
 
        set_fs(fs);
        up(sem);
-       unlock_dquot(dquot);
-
        dqstats.writes++;
 }
 
@@ -318,96 +338,99 @@ out_lock:
 void clear_dquot(struct dquot *dquot)
 {
        /* unhash it first */
-        unhash_dquot(dquot);
-        dquot->dq_sb = NULL;
-        dquot->dq_flags = 0;
-        dquot->dq_referenced = 0;
-        memset(&dquot->dq_dqb, 0, sizeof(struct dqblk));
+       remove_dquot_hash(dquot);
+       dquot->dq_sb = NULL;
+       dquot->dq_id = 0;
+       dquot->dq_dev = NODEV;
+       dquot->dq_type = -1;
+       dquot->dq_flags = 0;
+       dquot->dq_referenced = 0;
+       memset(&dquot->dq_dqb, 0, sizeof(struct dqblk));
 }
 
+/* Invalidate all dquots on the list, wait for all users. Note that this function is called
+ * after quota is disabled so no new quota might be created. As we only insert to the end of
+ * inuse list, we don't have to restart searching... */
 static void invalidate_dquots(struct super_block *sb, short type)
 {
-       struct dquot *dquot, *next;
-       int need_restart;
+       struct dquot *dquot;
+       struct list_head *head;
 
 restart:
-       next = inuse_list;      /* Here it is better. Otherwise the restart doesn't have any sense ;-) */
-       need_restart = 0;
-       while ((dquot = next) != NULL) {
-               next = dquot->dq_next;
+       for (head = inuse_list.next; head != &inuse_list; head = head->next) {
+               dquot = list_entry(head, struct dquot, dq_inuse);
                if (dquot->dq_sb != sb)
                        continue;
                if (dquot->dq_type != type)
                        continue;
-               if (dquot->dq_flags & DQ_LOCKED) {
-                       __wait_on_dquot(dquot);
-
-                       /* Set the flag for another pass. */
-                       need_restart = 1;
+               if (dquot->dq_count)
                        /*
-                        * Make sure it's still the same dquot.
+                        *  Wait for any users of quota. As we have already cleared the flags in
+                        *  superblock and cleared all pointers from inodes we are assured
+                        *  that there will be no new users of this quota.
                         */
-                       if (dquot->dq_sb != sb)
-                               continue;
-                       if (dquot->dq_type != type)
-                               continue;
-               }
-               /*
-                *  Because inodes needn't to be the only holders of dquot
-                *  the quota needn't to be written to disk. So we write it
-                *  ourselves before discarding the data just for sure...
-                */
-               if (dquot->dq_flags & DQ_MOD && dquot->dq_sb)
-               {
-                       write_dquot(dquot);
-                       need_restart = 1;       /* We slept on IO */
-               }
-               clear_dquot(dquot);
-       }
-       /*
-        * If anything blocked, restart the operation
-        * to ensure we don't miss any dquots.
-        */ 
-       if (need_restart)
+                       __wait_dquot_unused(dquot);
+               /* Quota now have no users and it has been written on last dqput() */
+               remove_dquot_hash(dquot);
+               remove_free_dquot(dquot);
+               remove_inuse(dquot);
+               kmem_cache_free(dquot_cachep, dquot);
                goto restart;
+       }
 }
 
 int sync_dquots(kdev_t dev, short type)
 {
-       struct dquot *dquot, *next, *ddquot;
-       int need_restart;
+       struct list_head *head;
+       struct dquot *dquot;
 
 restart:
-       next = inuse_list;
-       need_restart = 0;
-       while ((dquot = next) != NULL) {
-               next = dquot->dq_next;
+       for (head = inuse_list.next; head != &inuse_list; head = head->next) {
+               dquot = list_entry(head, struct dquot, dq_inuse);
                if (dev && dquot->dq_dev != dev)
                        continue;
                 if (type != -1 && dquot->dq_type != type)
                        continue;
                if (!dquot->dq_sb)      /* Invalidated? */
                        continue;
-               if (!(dquot->dq_flags & (DQ_LOCKED | DQ_MOD)))
+               if (!(dquot->dq_flags & (DQ_MOD | DQ_LOCKED)))
                        continue;
+               /* Raise use count so quota won't be invalidated. We can't use dqduplicate() as it does too many tests */
+               dquot->dq_count++;
+               if (dquot->dq_flags & DQ_LOCKED)
+                       wait_on_dquot(dquot);
+               if (dquot->dq_flags & DQ_MOD)
+                       write_dquot(dquot);
+               dqput(dquot);
+               goto restart;
+       }
+       dqstats.syncs++;
+       return 0;
+}
 
-               if ((ddquot = dqduplicate(dquot)) == NODQUOT)
-                       continue;
-               if (ddquot->dq_flags & DQ_MOD)
-                       write_dquot(ddquot);
-               dqput(ddquot);
-               /* Set the flag for another pass. */
-               need_restart = 1;
+/* Free unused dquots from cache */
+static void prune_dqcache(int count)
+{
+       struct list_head *head;
+       struct dquot *dquot;
+
+       head = free_dquots.prev;
+       while (head != &free_dquots && count) {
+               dquot = list_entry(head, struct dquot, dq_free);
+               remove_dquot_hash(dquot);
+               remove_free_dquot(dquot);
+               remove_inuse(dquot);
+               kmem_cache_free(dquot_cachep, dquot);
+               count--;
+               head = free_dquots.prev;
        }
-       /*
-        * If anything blocked, restart the operation
-        * to ensure we don't miss any dquots.
-        */ 
-       if (need_restart)
-               goto restart;
+}
 
-       dqstats.syncs++;
-       return(0);
+int shrink_dqcache_memory(int priority, unsigned int gfp_mask)
+{
+       prune_dqcache(nr_free_dquots / (priority + 1));
+       kmem_cache_shrink(dquot_cachep);
+       return 0;
 }
 
 /* NOTE: If you change this function please check whether dqput_blocks() works right... */
@@ -423,24 +446,14 @@ static void dqput(struct dquot *dquot)
                return;
        }
 
-       /*
-        * If the dq_sb pointer isn't initialized this entry needs no
-        * checking and doesn't need to be written. It's just an empty
-        * dquot that is put back on to the freelist.
-        */
-       if (dquot->dq_sb)
-               dqstats.drops++;
+       dqstats.drops++;
 we_slept:
        if (dquot->dq_count > 1) {
                /* We have more than one user... We can simply decrement use count */
                dquot->dq_count--;
                return;
        }
-       if (dquot->dq_flags & DQ_LOCKED) {
-               printk(KERN_ERR "VFS: Locked quota to be put on the free list.\n");
-               dquot->dq_flags &= ~DQ_LOCKED;
-       }
-       if (dquot->dq_sb && dquot->dq_flags & DQ_MOD) {
+       if (dquot->dq_flags & DQ_MOD) {
                write_dquot(dquot);
                goto we_slept;
        }
@@ -452,130 +465,49 @@ we_slept:
                return;
        }
        dquot->dq_count--;
-       dquot->dq_flags &= ~DQ_MOD;     /* Modified flag has no sense on free list */
        /* Place at end of LRU free queue */
        put_dquot_last(dquot);
-       wake_up(&dquot_wait);
-}
-
-static int grow_dquots(void)
-{
-       struct dquot *dquot;
-       int cnt = 0;
-
-       while (cnt < 32) {
-               dquot = kmem_cache_alloc(dquot_cachep, SLAB_KERNEL);
-               if(!dquot)
-                       return cnt;
-
-               nr_dquots++;
-               memset((caddr_t)dquot, 0, sizeof(struct dquot));
-               init_waitqueue_head(&dquot->dq_wait);
-               /* all dquots go on the inuse_list */
-               put_inuse(dquot);
-               put_dquot_head(dquot);
-               cnt++;
-       }
-       return cnt;
-}
-
-static struct dquot *find_best_candidate_weighted(void)
-{
-       struct list_head *tmp = &free_dquots;
-       struct dquot *dquot, *best = NULL;
-       unsigned long myscore, bestscore = ~0U;
-       int limit = (nr_free_dquots > 128) ? nr_free_dquots >> 2 : 32;
-
-       while ((tmp = tmp->next) != &free_dquots && --limit) {
-               dquot = list_entry(tmp, struct dquot, dq_free);
-               /* This should never happen... */
-               if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD))
-                       continue;
-               myscore = dquot->dq_referenced;
-               if (myscore < bestscore) {
-                       bestscore = myscore;
-                       best = dquot;
-               }
-       }
-       return best;
-}
-
-static inline struct dquot *find_best_free(void)
-{
-       struct list_head *tmp = &free_dquots;
-       struct dquot *dquot;
-       int limit = (nr_free_dquots > 1024) ? nr_free_dquots >> 5 : 32;
-
-       while ((tmp = tmp->next) != &free_dquots && --limit) {
-               dquot = list_entry(tmp, struct dquot, dq_free);
-               if (dquot->dq_referenced == 0)
-                       return dquot;
-       }
-       return NULL;
+       wake_up(&dquot->dq_wait_free);
 }
 
 struct dquot *get_empty_dquot(void)
 {
        struct dquot *dquot;
-       int shrink = 8; /* Number of times we should try to shrink dcache and icache */
 
-repeat:
-       dquot = find_best_free();
-       if (!dquot)
-               goto pressure;
-got_it:
-       /* Sanity checks */
-       if (dquot->dq_flags & DQ_LOCKED)
-               printk(KERN_ERR "VFS: Locked dquot on the free list\n");
-       if (dquot->dq_count != 0)
-               printk(KERN_ERR "VFS: free dquot count=%d\n", dquot->dq_count);
+       dquot = kmem_cache_alloc(dquot_cachep, SLAB_KERNEL);
+       if(!dquot)
+               return NODQUOT;
 
-       remove_free_dquot(dquot);
+       memset((caddr_t)dquot, 0, sizeof(struct dquot));
+       init_waitqueue_head(&dquot->dq_wait_free);
+       init_waitqueue_head(&dquot->dq_wait_lock);
+       INIT_LIST_HEAD(&dquot->dq_free);
+       INIT_LIST_HEAD(&dquot->dq_inuse);
+       INIT_LIST_HEAD(&dquot->dq_hash);
        dquot->dq_count = 1;
-       /* unhash and selectively clear the structure */
-       clear_dquot(dquot);
-       return dquot;
-
-pressure:
-       if (nr_dquots < max_dquots)
-               if (grow_dquots())
-                       goto repeat;
+       /* all dquots go on the inuse_list */
+       put_inuse(dquot);
 
-       dquot = find_best_candidate_weighted();
-       if (dquot)
-               goto got_it;
-       /*
-        * Try pruning the dcache to free up some dquots ...
-        */
-       if (shrink) {
-               printk(KERN_DEBUG "get_empty_dquot: pruning dcache and icache\n");
-               prune_dcache(128);
-               prune_icache(128);
-               shrink--;
-               goto repeat;
-       }
-
-       printk("VFS: No free dquots, contact mvw@planets.elm.net\n");
-       sleep_on(&dquot_wait);
-       goto repeat;
+       return dquot;
 }
 
 static struct dquot *dqget(struct super_block *sb, unsigned int id, short type)
 {
        unsigned int hashent = hashfn(sb->s_dev, id, type);
-       struct dquot *dquot, *empty = NULL;
+       struct dquot *dquot, *empty = NODQUOT;
        struct quota_mount_options *dqopt = sb_dqopt(sb);
 
-        if (!is_enabled(dqopt, type))
-                return(NODQUOT);
-
 we_slept:
-       if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NULL) {
-               if (empty == NULL) {
-                       dquot_updating[hashent]++;
-                       empty = get_empty_dquot();
-                       if (!--dquot_updating[hashent])
-                               wake_up(&update_wait);
+        if (!is_enabled(dqopt, type)) {
+               if (empty)
+                       dqput(empty);
+                return NODQUOT;
+       }
+
+       if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NODQUOT) {
+               if (empty == NODQUOT) {
+                       if ((empty = get_empty_dquot()) == NODQUOT)
+                               schedule();     /* Try to wait for a moment... */
                        goto we_slept;
                }
                dquot = empty;
@@ -584,25 +516,19 @@ we_slept:
                dquot->dq_dev = sb->s_dev;
                dquot->dq_sb = sb;
                /* hash it first so it can be found */
-               hash_dquot(dquot);
+               insert_dquot_hash(dquot);
                read_dquot(dquot);
        } else {
-               if (!dquot->dq_count++) {
+               if (!dquot->dq_count++)
                        remove_free_dquot(dquot);
-               } else
-                       dqstats.cache_hits++;
+               dqstats.cache_hits++;
                wait_on_dquot(dquot);
                if (empty)
                        dqput(empty);
        }
 
-       while (dquot_updating[hashent])
-               sleep_on(&update_wait);
-
        if (!dquot->dq_sb) {    /* Has somebody invalidated entry under us? */
-               /*
-                *  Do it as if the quota was invalidated before we started
-                */
+               printk(KERN_ERR "VFS: dqget(): Quota invalidated in dqget()!\n");
                dqput(dquot);
                return NODQUOT;
        }
@@ -614,14 +540,16 @@ we_slept:
 
 static struct dquot *dqduplicate(struct dquot *dquot)
 {
-       if (dquot == NODQUOT || !dquot->dq_sb)
+       if (dquot == NODQUOT)
                return NODQUOT;
        dquot->dq_count++;
-       wait_on_dquot(dquot);
        if (!dquot->dq_sb) {
+               printk(KERN_ERR "VFS: dqduplicate(): Invalidated quota to be duplicated!\n");
                dquot->dq_count--;
                return NODQUOT;
        }
+       if (dquot->dq_flags & DQ_LOCKED)
+               printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n");
        dquot->dq_referenced++;
        dqstats.lookups++;
        return dquot;
@@ -695,9 +623,9 @@ put_it:
                                printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", dquot->dq_count);
                        list_add(&dquot->dq_free, tofree_head); /* As dquot must have currently users it can't be on the free list... */
                        return 1;
-               } else {
-                       dqput(dquot);   /* We have guaranteed we won't block */
                }
+               else
+                       dqput(dquot);   /* We have guaranteed we won't block */
        }
        return 0;
 }
@@ -765,14 +693,61 @@ static inline int need_print_warning(struct dquot *dquot, int flag)
        return 0;
 }
 
-static void print_warning(struct dquot *dquot, int flag, const char *fmtstr)
+/* Values of warnings */
+#define NOWARN 0
+#define IHARDWARN 1
+#define ISOFTLONGWARN 2
+#define ISOFTWARN 3
+#define BHARDWARN 4
+#define BSOFTLONGWARN 5
+#define BSOFTWARN 6
+
+/* Print warning to user which exceeded quota */
+static void print_warning(struct dquot *dquot, const char warntype)
 {
+       char *msg = NULL;
+       int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS :
+         ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES : 0);
+
        if (!need_print_warning(dquot, flag))
                return;
-       sprintf(quotamessage, fmtstr,
-               bdevname(dquot->dq_sb->s_dev), quotatypes[dquot->dq_type]);
-       tty_write_message(current->tty, quotamessage);
        dquot->dq_flags |= flag;
+       tty_write_message(current->tty, (char *)bdevname(dquot->dq_sb->s_dev));
+       if (warntype == ISOFTWARN || warntype == BSOFTWARN)
+               tty_write_message(current->tty, ": warning, ");
+       else
+               tty_write_message(current->tty, ": write failed, ");
+       tty_write_message(current->tty, quotatypes[dquot->dq_type]);
+       switch (warntype) {
+               case IHARDWARN:
+                       msg = " file limit reached.\n";
+                       break;
+               case ISOFTLONGWARN:
+                       msg = " file quota exceeded too long.\n";
+                       break;
+               case ISOFTWARN:
+                       msg = " file quota exceeded.\n";
+                       break;
+               case BHARDWARN:
+                       msg = " block limit reached.\n";
+                       break;
+               case BSOFTLONGWARN:
+                       msg = " block quota exceeded too long.\n";
+                       break;
+               case BSOFTWARN:
+                       msg = " block quota exceeded.\n";
+                       break;
+       }
+       tty_write_message(current->tty, msg);
+}
+
+static inline void flush_warnings(struct dquot **dquots, char *warntype)
+{
+       int i;
+
+       for (i = 0; i < MAXQUOTAS; i++)
+               if (dquots[i] != NODQUOT && warntype[i] != NOWARN)
+                       print_warning(dquots[i], warntype[i]);
 }
 
 static inline char ignore_hardlimit(struct dquot *dquot)
@@ -780,15 +755,16 @@ static inline char ignore_hardlimit(struct dquot *dquot)
        return capable(CAP_SYS_RESOURCE) && !dquot->dq_sb->s_dquot.rsquash[dquot->dq_type];
 }
 
-static int check_idq(struct dquot *dquot, u_long inodes)
+static int check_idq(struct dquot *dquot, ulong inodes, char *warntype)
 {
+       *warntype = NOWARN;
        if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
                return QUOTA_OK;
 
        if (dquot->dq_ihardlimit &&
           (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit &&
             !ignore_hardlimit(dquot)) {
-               print_warning(dquot, DQ_INODES, "%s: write failed, %s file limit reached\n");
+               *warntype = IHARDWARN;
                return NO_QUOTA;
        }
 
@@ -796,22 +772,23 @@ static int check_idq(struct dquot *dquot, u_long inodes)
           (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
            dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime &&
             !ignore_hardlimit(dquot)) {
-               print_warning(dquot, DQ_INODES, "%s: warning, %s file quota exceeded too long.\n");
+               *warntype = ISOFTLONGWARN;
                return NO_QUOTA;
        }
 
        if (dquot->dq_isoftlimit &&
           (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
            dquot->dq_itime == 0) {
-               print_warning(dquot, 0, "%s: warning, %s file quota exceeded\n");
+               *warntype = ISOFTWARN;
                dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[dquot->dq_type];
        }
 
        return QUOTA_OK;
 }
 
-static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc)
+static int check_bdq(struct dquot *dquot, ulong blocks, char prealloc, char *warntype)
 {
+       *warntype = 0;
        if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)
                return QUOTA_OK;
 
@@ -819,7 +796,7 @@ static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc)
           (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit &&
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
-                       print_warning(dquot, DQ_BLKS, "%s: write failed, %s disk limit reached.\n");
+                       *warntype = BHARDWARN;
                return NO_QUOTA;
        }
 
@@ -828,7 +805,7 @@ static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc)
            dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime &&
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
-                       print_warning(dquot, DQ_BLKS, "%s: write failed, %s disk quota exceeded too long.\n");
+                       *warntype = BSOFTLONGWARN;
                return NO_QUOTA;
        }
 
@@ -836,7 +813,7 @@ static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc)
           (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
            dquot->dq_btime == 0) {
                if (!prealloc) {
-                       print_warning(dquot, 0, "%s: warning, %s disk quota exceeded\n");
+                       *warntype = BSOFTWARN;
                        dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[dquot->dq_type];
                }
                else
@@ -860,18 +837,11 @@ static int set_dqblk(struct super_block *sb, int id, short type, int flags, stru
        int error = -EFAULT;
        struct dqblk dq_dqblk;
 
-       if (dqblk == (struct dqblk *)NULL)
+       if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk)))
                return error;
 
-       if (flags & QUOTA_SYSCALL) {
-               if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk)))
-                       return(error);
-       } else
-               memcpy((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk));
-
        if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) {
-               lock_dquot(dquot);
-
+               /* We can't block while changing quota structure... */
                if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) {
                        dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit;
                        dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit;
@@ -908,15 +878,15 @@ static int set_dqblk(struct super_block *sb, int id, short type, int flags, stru
                        dquot->dq_flags &= ~DQ_FAKE;
 
                dquot->dq_flags |= DQ_MOD;
-               unlock_dquot(dquot);
                dqput(dquot);
        }
-       return(0);
+       return 0;
 }
 
 static int get_quota(struct super_block *sb, int id, short type, struct dqblk *dqblk)
 {
        struct dquot *dquot;
+       struct dqblk data;
        int error = -ESRCH;
 
        if (!sb || !sb_has_quota_enabled(sb, type))
@@ -925,12 +895,11 @@ static int get_quota(struct super_block *sb, int id, short type, struct dqblk *d
        if (dquot == NODQUOT)
                goto out;
 
-       lock_dquot(dquot);      /* We must protect against invalidating the quota */
+       memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk));        /* We copy data to preserve them from changing */
+       dqput(dquot);
        error = -EFAULT;
-       if (dqblk && !copy_to_user(dqblk, &dquot->dq_dqb, sizeof(struct dqblk)))
+       if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct dqblk)))
                error = 0;
-       unlock_dquot(dquot);
-       dqput(dquot);
 out:
        return error;
 }
@@ -965,6 +934,7 @@ static int quota_root_squash(struct super_block *sb, short type, int *addr)
        return error;
 }
 
+#if 0  /* We are not going to support filesystems without i_blocks... */
 /*
  * This is a simple algorithm that calculates the size of a file in blocks.
  * This is only used on filesystems that do not have an i_blocks count.
@@ -988,6 +958,7 @@ static u_long isize_to_blocks(loff_t isize, size_t blksize_bits)
        }
        return blocks;
 }
+#endif
 
 /*
  * Externally referenced functions through dquot_operations in inode.
@@ -996,22 +967,19 @@ static u_long isize_to_blocks(loff_t isize, size_t blksize_bits)
  */
 void dquot_initialize(struct inode *inode, short type)
 {
-       struct dquot *dquot;
+       struct dquot *dquot[MAXQUOTAS];
        unsigned int id = 0;
        short cnt;
 
-       lock_kernel();
-       if (IS_NOQUOTA(inode)) {
-               unlock_kernel();
+       if (IS_NOQUOTA(inode))
                return;
-       }
+       /* Build list of quotas to initialize... We can block here */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               dquot[cnt] = NODQUOT;
                if (type != -1 && cnt != type)
                        continue;
-
                if (!sb_has_quota_enabled(inode->i_sb, cnt))
                        continue;
-
                if (inode->i_dquot[cnt] == NODQUOT) {
                        switch (cnt) {
                                case USRQUOTA:
@@ -1021,18 +989,22 @@ void dquot_initialize(struct inode *inode, short type)
                                        id = inode->i_gid;
                                        break;
                        }
-                       dquot = dqget(inode->i_sb, id, cnt);
-                       if (dquot == NODQUOT)
-                               continue;
-                       if (inode->i_dquot[cnt] != NODQUOT) {
-                               dqput(dquot);
-                               continue;
-                       } 
-                       inode->i_dquot[cnt] = dquot;
-                       inode->i_flags |= S_QUOTA;
+                       dquot[cnt] = dqget(inode->i_sb, id, cnt);
                }
        }
-       unlock_kernel();
+       /* NOBLOCK START: Here we shouldn't block */
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               if (dquot[cnt] == NODQUOT || !sb_has_quota_enabled(inode->i_sb, cnt) || inode->i_dquot[cnt] != NODQUOT)
+                       continue;
+               inode->i_dquot[cnt] = dquot[cnt];
+               dquot[cnt] = NODQUOT;
+               inode->i_flags |= S_QUOTA;
+       }
+       /* NOBLOCK END */
+       /* Put quotas which we didn't use */
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+               if (dquot[cnt] != NODQUOT)
+                       dqput(dquot[cnt]);
 }
 
 /*
@@ -1045,7 +1017,6 @@ void dquot_drop(struct inode *inode)
        struct dquot *dquot;
        short cnt;
 
-       lock_kernel();
        inode->i_flags &= ~S_QUOTA;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (inode->i_dquot[cnt] == NODQUOT)
@@ -1054,229 +1025,180 @@ void dquot_drop(struct inode *inode)
                inode->i_dquot[cnt] = NODQUOT;
                dqput(dquot);
        }
-       unlock_kernel();
 }
 
 /*
- * Note: this is a blocking operation.
+ * This operation can block, but only after everything is updated
  */
-int dquot_alloc_block(const struct inode *inode, unsigned long number, char warn)
+int dquot_alloc_block(struct inode *inode, unsigned long number, char warn)
 {
-       int cnt;
+       int cnt, ret = NO_QUOTA;
        struct dquot *dquot[MAXQUOTAS];
+       char warntype[MAXQUOTAS];
 
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               dquot[cnt] = NODQUOT;
+               warntype[cnt] = NOWARN;
+       }
+       /* NOBLOCK Start */
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                dquot[cnt] = dqduplicate(inode->i_dquot[cnt]);
                if (dquot[cnt] == NODQUOT)
                        continue;
-               lock_dquot(dquot[cnt]);
-               if (check_bdq(dquot[cnt], number, warn))
-                       goto put_all;
+               if (check_bdq(dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA)
+                       goto warn_put_all;
        }
-
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (dquot[cnt] == NODQUOT)
                        continue;
                dquot_incr_blocks(dquot[cnt], number);
-               unlock_dquot(dquot[cnt]);
-               dqput(dquot[cnt]);
        }
-
-       return QUOTA_OK;
-put_all:
-       for (; cnt >= 0; cnt--) {
-               if (dquot[cnt] == NODQUOT)
-                       continue;
-               unlock_dquot(dquot[cnt]);
-               dqput(dquot[cnt]);
-       }
-       return NO_QUOTA;
+       inode->i_blocks += number << (BLOCK_SIZE_BITS - 9);
+       /* NOBLOCK End */
+       ret = QUOTA_OK;
+warn_put_all:
+       flush_warnings(dquot, warntype);
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+               if (dquot[cnt] != NODQUOT)
+                       dqput(dquot[cnt]);
+       return ret;
 }
 
 /*
- * Note: this is a blocking operation.
+ * This operation can block, but only after everything is updated
  */
 int dquot_alloc_inode(const struct inode *inode, unsigned long number)
 {
-       int cnt;
+       int cnt, ret = NO_QUOTA;
        struct dquot *dquot[MAXQUOTAS];
+       char warntype[MAXQUOTAS];
 
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               dquot[cnt] = NODQUOT;
+               warntype[cnt] = NOWARN;
+       }
+       /* NOBLOCK Start */
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                dquot[cnt] = dqduplicate(inode -> i_dquot[cnt]);
                if (dquot[cnt] == NODQUOT)
                        continue;
-               lock_dquot(dquot[cnt]);
-               if (check_idq(dquot[cnt], number))
-                       goto put_all;
+               if (check_idq(dquot[cnt], number, warntype+cnt) == NO_QUOTA)
+                       goto warn_put_all;
        }
 
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (dquot[cnt] == NODQUOT)
                        continue;
                dquot_incr_inodes(dquot[cnt], number);
-               unlock_dquot(dquot[cnt]);
-               dqput(dquot[cnt]);
-       }
-
-       return QUOTA_OK;
-put_all:
-       for (; cnt >= 0; cnt--) {
-               if (dquot[cnt] == NODQUOT)
-                       continue;
-               unlock_dquot(dquot[cnt]);
-               dqput(dquot[cnt]);
        }
-       return NO_QUOTA;
+       /* NOBLOCK End */
+       ret = QUOTA_OK;
+warn_put_all:
+       flush_warnings(dquot, warntype);
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+               if (dquot[cnt] != NODQUOT)
+                       dqput(dquot[cnt]);
+       return ret;
 }
 
 /*
- * Note: this is a blocking operation.
+ * This is a non-blocking operation.
  */
-void dquot_free_block(const struct inode *inode, unsigned long number)
+void dquot_free_block(struct inode *inode, unsigned long number)
 {
        unsigned short cnt;
        struct dquot *dquot;
 
+       /* NOBLOCK Start */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               dquot = inode->i_dquot[cnt];
+               dquot = dqduplicate(inode->i_dquot[cnt]);
                if (dquot == NODQUOT)
                        continue;
-               wait_on_dquot(dquot);
                dquot_decr_blocks(dquot, number);
+               dqput(dquot);
        }
+       inode->i_blocks -= number << (BLOCK_SIZE_BITS - 9);
+       /* NOBLOCK End */
 }
 
 /*
- * Note: this is a blocking operation.
+ * This is a non-blocking operation.
  */
 void dquot_free_inode(const struct inode *inode, unsigned long number)
 {
        unsigned short cnt;
        struct dquot *dquot;
 
+       /* NOBLOCK Start */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               dquot = inode->i_dquot[cnt];
+               dquot = dqduplicate(inode->i_dquot[cnt]);
                if (dquot == NODQUOT)
                        continue;
-               wait_on_dquot(dquot);
                dquot_decr_inodes(dquot, number);
+               dqput(dquot);
        }
+       /* NOBLOCK End */
 }
 
 /*
  * Transfer the number of inode and blocks from one diskquota to an other.
  *
- * Note: this is a blocking operation.
+ * This operation can block, but only after everything is updated
  */
-int dquot_transfer(struct dentry *dentry, struct iattr *iattr)
+int dquot_transfer(struct inode *inode, struct iattr *iattr)
 {
-       struct inode *inode = dentry -> d_inode;
        unsigned long blocks;
        struct dquot *transfer_from[MAXQUOTAS];
        struct dquot *transfer_to[MAXQUOTAS];
-       short cnt, disc;
-       int error = -EDQUOT;
-
-       if (!inode)
-               return -ENOENT;
-       /* Arguably we could consider that as error, but... no fs - no quota */
-       if (!inode->i_sb)
-               return 0;
+       int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid,
+           chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid;
+       char warntype[MAXQUOTAS];
 
-       lock_kernel();
-       /*
-        * Build the transfer_from and transfer_to lists and check quotas to see
-        * if operation is permitted.
-        */
+       /* Clear the arrays */
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               transfer_to[cnt] = transfer_from[cnt] = NODQUOT;
+               warntype[cnt] = NOWARN;
+       }
+       /* First build the transfer_to list - here we can block on reading of dquots... */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               transfer_from[cnt] = NODQUOT;
-               transfer_to[cnt] = NODQUOT;
-
                if (!sb_has_quota_enabled(inode->i_sb, cnt))
                        continue;
-
                switch (cnt) {
                        case USRQUOTA:
-                               if (inode->i_uid == iattr->ia_uid)
+                               if (!chuid)
                                        continue;
-                               /* We can get transfer_from from inode, can't we? */
-                               transfer_from[cnt] = dqget(inode->i_sb, inode->i_uid, cnt);
                                transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_uid, cnt);
                                break;
                        case GRPQUOTA:
-                               if (inode->i_gid == iattr->ia_gid)
+                               if (!chgid)
                                        continue;
-                               transfer_from[cnt] = dqget(inode->i_sb, inode->i_gid, cnt);
                                transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_gid, cnt);
                                break;
                }
-
-               /* Something bad (eg. quotaoff) happened while we were sleeping? */
-               if (transfer_from[cnt] == NODQUOT || transfer_to[cnt] == NODQUOT)
-               {
-                       if (transfer_from[cnt] != NODQUOT) {
-                               dqput(transfer_from[cnt]);
-                               transfer_from[cnt] = NODQUOT;
-                       }
-                       if (transfer_to[cnt] != NODQUOT) {
-                               dqput(transfer_to[cnt]);
-                               transfer_to[cnt] = NODQUOT;
-                       }
-                       continue;
-               }
-               /*
-                *  We have to lock the quotas to prevent races...
-                */
-               if (transfer_from[cnt] < transfer_to[cnt])
-               {
-                       lock_dquot(transfer_from[cnt]);
-                       lock_dquot(transfer_to[cnt]);
-               }
-               else
-               {
-                       lock_dquot(transfer_to[cnt]);
-                       lock_dquot(transfer_from[cnt]);
-               }
-
-               /*
-                * The entries might got invalidated while locking. The second
-                * dqget() could block and so the first structure might got
-                * invalidated or locked...
-                */
-               if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb) {
-                       cnt++;
-                       goto put_all;
-               }
        }
-
-       /*
-        * Find out if this filesystem uses i_blocks.
-        */
-       if (!inode->i_sb->s_blocksize)
-               blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS);
-       else
-               blocks = (inode->i_blocks >> 1);
+       /* NOBLOCK START: From now on we shouldn't block */
+       blocks = (inode->i_blocks >> 1);
+       /* Build the transfer_from list and check the limits */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (!transfer_to[cnt])
+               /* The second test can fail when quotaoff is in progress... */
+               if (transfer_to[cnt] == NODQUOT || !sb_has_quota_enabled(inode->i_sb, cnt))
                        continue;
-               if (check_idq(transfer_to[cnt], 1) == NO_QUOTA ||
-                   check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) {
-                       cnt = MAXQUOTAS;
-                       goto put_all;
-               }
+               transfer_from[cnt] = dqduplicate(inode->i_dquot[cnt]);
+               if (transfer_from[cnt] == NODQUOT)      /* Can happen on quotafiles (quota isn't initialized on them)... */
+                       continue;
+               if (check_idq(transfer_to[cnt], 1, warntype+cnt) == NO_QUOTA ||
+                   check_bdq(transfer_to[cnt], blocks, 0, warntype+cnt) == NO_QUOTA)
+                       goto warn_put_all;
        }
 
-       if ((error = notify_change(dentry, iattr)))
-               goto put_all; 
        /*
-        * Finally perform the needed transfer from transfer_from to transfer_to,
-        * and release any pointers to dquots not needed anymore.
+        * Finally perform the needed transfer from transfer_from to transfer_to
         */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                /*
                 * Skip changes for same uid or gid or for non-existing quota-type.
                 */
-               if (transfer_from[cnt] == NODQUOT && transfer_to[cnt] == NODQUOT)
+               if (transfer_from[cnt] == NODQUOT || transfer_to[cnt] == NODQUOT)
                        continue;
 
                dquot_decr_inodes(transfer_from[cnt], 1);
@@ -1285,40 +1207,34 @@ int dquot_transfer(struct dentry *dentry, struct iattr *iattr)
                dquot_incr_inodes(transfer_to[cnt], 1);
                dquot_incr_blocks(transfer_to[cnt], blocks);
 
-               unlock_dquot(transfer_from[cnt]);
-               dqput(transfer_from[cnt]);
-               if (inode->i_dquot[cnt] != NODQUOT) {
-                       struct dquot *temp = inode->i_dquot[cnt];
-                       inode->i_dquot[cnt] = transfer_to[cnt];
-                       unlock_dquot(transfer_to[cnt]);
-                       dqput(temp);
-               } else {
-                       unlock_dquot(transfer_to[cnt]);
-                       dqput(transfer_to[cnt]);
-               }
+               if (inode->i_dquot[cnt] == NODQUOT)
+                       BUG();
+               inode->i_dquot[cnt] = transfer_to[cnt];
+               /*
+                * We've got to release transfer_from[] twice - once for dquot_transfer() and
+                * once for inode. We don't want to release transfer_to[] as it's now placed in inode
+                */
+               transfer_to[cnt] = transfer_from[cnt];
        }
-
-       unlock_kernel();
-       return 0;
-put_all:
-       for (disc = 0; disc < cnt; disc++) {
-               /* There should be none or both pointers set but... */
-               if (transfer_to[disc] != NODQUOT) {
-                       unlock_dquot(transfer_to[disc]);
-                       dqput(transfer_to[disc]);
-               }
-               if (transfer_from[disc] != NODQUOT) {
-                       unlock_dquot(transfer_from[disc]);
-                       dqput(transfer_from[disc]);
-               }
+       /* NOBLOCK END. From now on we can block as we wish */
+       ret = QUOTA_OK;
+warn_put_all:
+       flush_warnings(transfer_to, warntype);
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               if (transfer_to[cnt] != NODQUOT)
+                       dqput(transfer_to[cnt]);
+               if (transfer_from[cnt] != NODQUOT)
+                       dqput(transfer_from[cnt]);
        }
-       unlock_kernel();
-       return error;
+       return ret;
 }
 
-
 static int __init dquot_init(void)
 {
+       int i;
+
+       for (i = 0; i < NR_DQHASH; i++)
+               INIT_LIST_HEAD(dquot_hash + i);
        printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__);
        return 0;
 }
@@ -1371,7 +1287,6 @@ int quota_off(struct super_block *sb, short type)
 {
        struct file *filp;
        short cnt;
-       int enabled = 0;
        struct quota_mount_options *dqopt = sb_dqopt(sb);
 
        if (!sb)
@@ -1390,27 +1305,15 @@ int quota_off(struct super_block *sb, short type)
                remove_dquot_ref(sb, cnt);
                invalidate_dquots(sb, cnt);
 
-               /* Wait for any pending IO - remove me as soon as invalidate is more polite */
-               down(&dqopt->dqio_sem);
                filp = dqopt->files[cnt];
                dqopt->files[cnt] = (struct file *)NULL;
                dqopt->inode_expire[cnt] = 0;
                dqopt->block_expire[cnt] = 0;
-               up(&dqopt->dqio_sem);
                fput(filp);
        }       
-
-       /*
-        * Check whether any quota is still enabled,
-        * and if not clear the dq_op pointer.
-        */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               enabled |= is_enabled(dqopt, cnt);
-       if (!enabled)
-               sb->dq_op = NULL;
        up(&dqopt->dqoff_sem);
 out:
-       return(0);
+       return 0;
 }
 
 static inline int check_quotafile_size(loff_t size)
@@ -1459,8 +1362,8 @@ static int quota_on(struct super_block *sb, short type, char *path)
        dquot_drop(inode);
        inode->i_flags |= S_NOQUOTA;
 
-       set_enable_flags(dqopt, type);
        dqopt->files[type] = f;
+       set_enable_flags(dqopt, type);
 
        dquot = dqget(sb, 0, type);
        dqopt->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME;
@@ -1511,11 +1414,11 @@ asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
                case Q_GETQUOTA:
                        if (((type == USRQUOTA && current->euid != id) ||
                             (type == GRPQUOTA && !in_egroup_p(id))) &&
-                           !capable(CAP_SYS_RESOURCE))
+                           !capable(CAP_SYS_ADMIN))
                                goto out;
                        break;
                default:
-                       if (!capable(CAP_SYS_RESOURCE))
+                       if (!capable(CAP_SYS_ADMIN))
                                goto out;
        }
 
@@ -1536,13 +1439,16 @@ asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
                ret = -ENOTBLK;
                if (!S_ISBLK(mode))
                        goto out;
+               ret = -ENODEV;
                sb = get_super(dev);
+               if (!sb)
+                       goto out;
        }
 
        ret = -EINVAL;
        switch (cmds) {
                case Q_QUOTAON:
-                       ret = sb ? quota_on(sb, type, (char *) addr) : -ENODEV;
+                       ret = quota_on(sb, type, (char *) addr);
                        goto out;
                case Q_QUOTAOFF:
                        ret = quota_off(sb, type);
@@ -1572,9 +1478,7 @@ asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
                        goto out;
        }
 
-       flags |= QUOTA_SYSCALL;
-
-       ret = -ESRCH;
+       ret = -NODEV;
        if (sb && sb_has_quota_enabled(sb, type))
                ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr);
 out:
index 28cd69a..3d799f7 100644 (file)
@@ -247,7 +247,8 @@ static inline int load_block_bitmap (struct super_block * sb,
        return slot;
 }
 
-void ext2_free_blocks (const struct inode * inode, unsigned long block,
+/* Free given blocks, update quota and i_blocks field */
+void ext2_free_blocks (struct inode * inode, unsigned long block,
                       unsigned long count)
 {
        struct buffer_head * bh;
@@ -318,7 +319,7 @@ do_more:
                                      "bit already cleared for block %lu",
                                      block + i);
                else {
-                       DQUOT_FREE_BLOCK(sb, inode, 1);
+                       DQUOT_FREE_BLOCK(inode, 1);
                        gdp->bg_free_blocks_count =
                                cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1);
                        es->s_free_blocks_count =
@@ -351,8 +352,9 @@ error_return:
  * is allocated.  Otherwise a forward search is made for a free block; within 
  * each block group the search first looks for an entire free byte in the block
  * bitmap, and then for any free bit if that fails.
+ * This function also updates quota and i_blocks field.
  */
-int ext2_new_block (const struct inode * inode, unsigned long goal,
+int ext2_new_block (struct inode * inode, unsigned long goal,
     u32 * prealloc_count, u32 * prealloc_block, int * err)
 {
        struct buffer_head * bh;
@@ -508,7 +510,7 @@ got_block:
        /*
         * Check quota for allocation of this block.
         */
-       if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) {
+       if(DQUOT_ALLOC_BLOCK(inode, 1)) {
                *err = -EDQUOT;
                goto out;
        }
@@ -526,7 +528,7 @@ got_block:
        if (ext2_set_bit (j, bh->b_data)) {
                ext2_warning (sb, "ext2_new_block",
                              "bit already set for block %d", j);
-               DQUOT_FREE_BLOCK(sb, inode, 1);
+               DQUOT_FREE_BLOCK(inode, 1);
                goto repeat;
        }
 
@@ -549,13 +551,13 @@ got_block:
                for (k = 1;
                     k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb);
                     k++, next_block++) {
-                       if (DQUOT_PREALLOC_BLOCK(sb, inode, 1))
+                       if (DQUOT_PREALLOC_BLOCK(inode, 1))
                                break;
                        /* Writer: ->i_prealloc* */
                        if (*prealloc_block + *prealloc_count != next_block ||
                            ext2_set_bit (j + k, bh->b_data)) {
                                /* Writer: end */
-                               DQUOT_FREE_BLOCK(sb, inode, 1);
+                               DQUOT_FREE_BLOCK(inode, 1);
                                break;
                        }
                        (*prealloc_count)++;
index 0efef5c..c42ea9f 100644 (file)
@@ -196,7 +196,7 @@ void ext2_free_inode (struct inode * inode)
         */
        if (!is_bad_inode(inode)) {
                /* Quota is already initialized in iput() */
-               DQUOT_FREE_INODE(sb, inode);
+               DQUOT_FREE_INODE(inode);
                DQUOT_DROP(inode);
        }
 
@@ -454,7 +454,7 @@ repeat:
        mark_inode_dirty(inode);
 
        unlock_super (sb);
-       if(DQUOT_ALLOC_INODE(sb, inode)) {
+       if(DQUOT_ALLOC_INODE(inode)) {
                DQUOT_DROP(inode);
                inode->i_flags |= S_NOQUOTA;
                inode->i_nlink = 0;
index 1ff30e5..eb01965 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/highuid.h>
+#include <linux/quotaops.h>
 
 static int ext2_update_inode(struct inode * inode, int do_sync);
 
@@ -445,7 +446,7 @@ static inline int ext2_splice_branch(struct inode *inode,
 
        /* Verify that place we are splicing to is still there and vacant */
 
-       /* Writer: pointers, ->i_next_alloc*, ->i_blocks */
+       /* Writer: pointers, ->i_next_alloc* */
        if (!verify_chain(chain, where-1) || *where->p)
                /* Writer: end */
                goto changed;
@@ -455,7 +456,6 @@ static inline int ext2_splice_branch(struct inode *inode,
        *where->p = where->key;
        inode->u.ext2_i.i_next_alloc_block = block;
        inode->u.ext2_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key);
-       inode->i_blocks += num * inode->i_sb->s_blocksize/512;
 
        /* Writer: end */
 
@@ -702,7 +702,6 @@ no_top:
  */
 static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q)
 {
-       int blocks = inode->i_sb->s_blocksize / 512;
        unsigned long block_to_free = 0, count = 0;
        unsigned long nr;
 
@@ -716,9 +715,6 @@ static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q)
                        else if (block_to_free == nr - count)
                                count++;
                        else {
-                               /* Writer: ->i_blocks */
-                               inode->i_blocks -= blocks * count;
-                               /* Writer: end */
                                mark_inode_dirty(inode);
                                ext2_free_blocks (inode, block_to_free, count);
                        free_this:
@@ -728,9 +724,6 @@ static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q)
                }
        }
        if (count > 0) {
-               /* Writer: ->i_blocks */
-               inode->i_blocks -= blocks * count;
-               /* Writer: end */
                mark_inode_dirty(inode);
                ext2_free_blocks (inode, block_to_free, count);
        }
@@ -775,9 +768,6 @@ static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth)
                                           (u32*)bh->b_data + addr_per_block,
                                           depth);
                        bforget(bh);
-                       /* Writer: ->i_blocks */
-                       inode->i_blocks -= inode->i_sb->s_blocksize / 512;
-                       /* Writer: end */
                        ext2_free_blocks(inode, nr, 1);
                        mark_inode_dirty(inode);
                }
@@ -1177,7 +1167,9 @@ int ext2_notify_change(struct dentry *dentry, struct iattr *iattr)
                goto out;
 
        retval = inode_change_ok(inode, iattr);
-       if (retval != 0)
+       if (retval != 0 || (((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
+           (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) &&
+           DQUOT_TRANSFER(inode, iattr)))
                goto out;
 
        inode_setattr(inode, iattr);
index bd128f2..1f51ca0 100644 (file)
@@ -24,7 +24,8 @@
 #include <linux/nfs_mount.h>
 
 struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data);
-int do_remount_sb(struct super_block *sb, int flags, char * data);
+int do_remount_sb(struct super_block *sb, int flags, void * data);
+void kill_super(struct super_block *sb);
 
 static struct list_head *mount_hashtable;
 static int hash_mask, hash_bits;
@@ -54,7 +55,6 @@ struct vfsmount *alloc_vfsmnt(void)
                INIT_LIST_HEAD(&mnt->mnt_child);
                INIT_LIST_HEAD(&mnt->mnt_mounts);
                INIT_LIST_HEAD(&mnt->mnt_list);
-               mnt->mnt_owner = current->uid;
        }
        return mnt;
 }
@@ -66,6 +66,18 @@ void free_vfsmnt(struct vfsmount *mnt)
        kmem_cache_free(mnt_cache, mnt);
 }
 
+void set_devname(struct vfsmount *mnt, const char *name)
+{
+       if (name) {
+               int size = strlen(name)+1;
+               char * newname = kmalloc(size, GFP_KERNEL);
+               if (newname) {
+                       memcpy(newname, name, size);
+                       mnt->mnt_devname = newname;
+               }
+       }
+}
+
 struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
 {
        struct list_head * head = mount_hashtable + hash(mnt, dentry);
@@ -129,6 +141,30 @@ static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)
        return list_entry(next, struct vfsmount, mnt_child);
 }
 
+static struct vfsmount *
+clone_mnt(struct vfsmount *old, struct dentry *root)
+{
+       struct super_block *sb = old->mnt_sb;
+       struct vfsmount *mnt = alloc_vfsmnt();
+
+       if (mnt) {
+               mnt->mnt_flags = old->mnt_flags;
+               set_devname(mnt, old->mnt_devname);
+               atomic_inc(&sb->s_active);
+               mnt->mnt_sb = sb;
+               mnt->mnt_root = dget(root);
+       }
+       return mnt;
+}
+
+void __mntput(struct vfsmount *mnt)
+{
+       struct super_block *sb = mnt->mnt_sb;
+       dput(mnt->mnt_root);
+       free_vfsmnt(mnt);
+       kill_super(sb);
+}
+
 /* Use octal escapes, like mount does, for embedded spaces etc. */
 static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
 
@@ -189,31 +225,6 @@ static struct proc_nfs_info {
        { 0, NULL, NULL }
 };
 
-static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root)
-{
-       char *name = old->mnt_devname;
-       struct vfsmount *mnt = alloc_vfsmnt();
-       struct super_block *sb = old->mnt_sb;
-
-       if (!mnt)
-               goto out;
-
-       if (name) {
-               mnt->mnt_devname = kmalloc(strlen(name)+1, GFP_KERNEL);
-               if (mnt->mnt_devname)
-                       strcpy(mnt->mnt_devname, name);
-       }
-       mnt->mnt_sb = sb;
-       mnt->mnt_root = dget(root);
-       mnt->mnt_mountpoint = mnt->mnt_root;
-       mnt->mnt_parent = mnt;
-       mnt->mnt_flags = old->mnt_flags;
-
-       atomic_inc(&sb->s_active);
-out:
-       return mnt;
-}
-
 int get_filesystem_info( char *buf )
 {
        struct list_head *p;
@@ -374,24 +385,22 @@ static int do_umount(struct vfsmount *mnt, int flags)
         * somewhat bogus. Suggestions for better replacement?
         * Ho-hum... In principle, we might treat that as umount + switch
         * to rootfs. GC would eventually take care of the old vfsmount.
-        * The problem being: we have to implement rootfs and GC for that ;-)
         * Actually it makes sense, especially if rootfs would contain a
         * /reboot - static binary that would close all descriptors and
         * call reboot(9). Then init(8) could umount root and exec /reboot.
         */
        if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) {
-               int retval = 0;
                /*
                 * Special case for "unmounting" root ...
                 * we just try to remount it readonly.
                 */
+               down_write(&sb->s_umount);
                if (!(sb->s_flags & MS_RDONLY)) {
-                       down_write(&sb->s_umount);
                        lock_kernel();
                        retval = do_remount_sb(sb, MS_RDONLY, 0);
                        unlock_kernel();
-                       up_write(&sb->s_umount);
                }
+               up_write(&sb->s_umount);
                return retval;
        }
 
@@ -448,12 +457,10 @@ asmlinkage long sys_umount(char * name, int flags)
                goto dput_and_out;
 
        retval = -EPERM;
-       if (!capable(CAP_SYS_ADMIN) && current->uid!=nd.mnt->mnt_owner)
+       if (!capable(CAP_SYS_ADMIN))
                goto dput_and_out;
 
        retval = do_umount(nd.mnt, flags);
-       path_release(&nd);
-       goto out;
 dput_and_out:
        path_release(&nd);
 out:
@@ -487,9 +494,48 @@ static int mount_is_safe(struct nameidata *nd)
 #endif
 }
 
+static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry)
+{
+       struct vfsmount *p, *next, *q, *res;
+       struct nameidata nd;
+
+       p = mnt;
+       res = nd.mnt = q = clone_mnt(p, dentry);
+       if (!q)
+               goto Enomem;
+       q->mnt_parent = q;
+       q->mnt_mountpoint = p->mnt_mountpoint;
+
+       while ( (next = next_mnt(p, mnt)) != NULL) {
+               while (p != next->mnt_parent) {
+                       p = p->mnt_parent;
+                       q = q->mnt_parent;
+               }
+               p = next;
+               nd.mnt = q;
+               nd.dentry = p->mnt_mountpoint;
+               q = clone_mnt(p, p->mnt_root);
+               if (!q)
+                       goto Enomem;
+               spin_lock(&dcache_lock);
+               list_add_tail(&q->mnt_list, &res->mnt_list);
+               attach_mnt(q, &nd);
+               spin_unlock(&dcache_lock);
+       }
+       return res;
+Enomem:
+       if (res) {
+               spin_lock(&dcache_lock);
+               umount_tree(res);
+               spin_unlock(&dcache_lock);
+       }
+       return NULL;
+}
+
 /* Will become static */
 int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
 {
+       int err;
        if (mnt->mnt_sb->s_flags & MS_NOUSER)
                return -EINVAL;
 
@@ -497,43 +543,38 @@ int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
              S_ISDIR(mnt->mnt_root->d_inode->i_mode))
                return -ENOTDIR;
 
+       err = -ENOENT;
        down(&nd->dentry->d_inode->i_zombie);
        if (IS_DEADDIR(nd->dentry->d_inode))
-               goto fail1;
+               goto out_unlock;
 
        spin_lock(&dcache_lock);
-       if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry))
-               goto fail;
-
-       attach_mnt(mnt, nd);
-       list_add(&mnt->mnt_list, vfsmntlist.prev);
-       spin_unlock(&dcache_lock);
-       up(&nd->dentry->d_inode->i_zombie);
-       mntget(mnt);
-       return 0;
-fail:
+       if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) {
+               struct list_head head;
+               attach_mnt(mnt, nd);
+               list_add_tail(&head, &mnt->mnt_list);
+               list_splice(&head, vfsmntlist.prev);
+               mntget(mnt);
+               err = 0;
+       }
        spin_unlock(&dcache_lock);
-fail1:
+out_unlock:
        up(&nd->dentry->d_inode->i_zombie);
-       return -ENOENT;
+       return err;
 }
 
 /*
  * do loopback mount.
  */
-static int do_loopback(struct nameidata *nd, char *old_name)
+static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
 {
        struct nameidata old_nd;
        struct vfsmount *mnt = NULL;
-       int err;
-
-       err = mount_is_safe(nd);
+       int err = mount_is_safe(nd);
        if (err)
                return err;
-
        if (!old_name || !*old_name)
                return -EINVAL;
-
        if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
                err = path_walk(old_name, &old_nd);
        if (err)
@@ -541,12 +582,18 @@ static int do_loopback(struct nameidata *nd, char *old_name)
 
        down(&mount_sem);
        err = -EINVAL;
-       if (check_mnt(nd->mnt)) {
+       if (check_mnt(nd->mnt) && (!recurse || check_mnt(old_nd.mnt))) {
                err = -ENOMEM;
-               mnt = clone_mnt(old_nd.mnt, old_nd.dentry);
+               if (recurse)
+                       mnt = copy_tree(old_nd.mnt, old_nd.dentry);
+               else
+                       mnt = clone_mnt(old_nd.mnt, old_nd.dentry);
        }
+
        if (mnt) {
                err = graft_tree(mnt, nd);
+               if (err && recurse)
+                       umount_tree(mnt);
                mntput(mnt);
        }
 
@@ -557,10 +604,11 @@ static int do_loopback(struct nameidata *nd, char *old_name)
 
 /*
  * change filesystem flags. dir should be a physical root of filesystem.
+ * If you've mounted a non-root directory somewhere and want to do remount
  * on it - tough luck.
  */
 
-static int do_remount(struct nameidata *nd,int flags,int mnt_flags,char *data)
+static int do_remount(struct nameidata *nd,int flags,int mnt_flags,void *data)
 {
        int err;
        struct super_block * sb = nd->mnt->mnt_sb;
@@ -694,10 +742,10 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
                return retval;
 
        if (flags & MS_REMOUNT)
-               retval = do_remount(&nd, flags&~MS_REMOUNT, mnt_flags,
-                                 (char *)data_page);
+               retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
+                                   data_page);
        else if (flags & MS_BIND)
-               retval = do_loopback(&nd, dev_name);
+               retval = do_loopback(&nd, dev_name, flags & MS_REC);
        else
                retval = do_add_mount(&nd, type_page, flags, mnt_flags,
                                      dev_name, data_page);
index 015ef90..7d00745 100644 (file)
@@ -296,16 +296,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
 
 
        iap->ia_valid |= ATTR_CTIME;
-#ifdef CONFIG_QUOTA
-       /* DQUOT_TRANSFER needs both ia_uid and ia_gid defined */
-       if (iap->ia_valid & (ATTR_UID|ATTR_GID)) {
-               if (! (iap->ia_valid & ATTR_UID))
-                       iap->ia_uid = inode->i_uid;
-               if (! (iap->ia_valid & ATTR_GID))
-                       iap->ia_gid = inode->i_gid;
-               iap->ia_valid |= ATTR_UID|ATTR_GID;
-       }
-#endif /* CONFIG_QUOTA */
 
        if (iap->ia_valid & ATTR_SIZE) {
                fh_lock(fhp);
@@ -313,12 +303,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        }
        err = nfserr_notsync;
        if (!check_guard || guardtime == inode->i_ctime) {
-#ifdef CONFIG_QUOTA
-               if (iap->ia_valid & (ATTR_UID|ATTR_GID)) 
-                       err = DQUOT_TRANSFER(dentry, iap);
-               else
-#endif
-                       err = notify_change(dentry, iap);
+               err = notify_change(dentry, iap);
                err = nfserrno(err);
        }
        if (size_change) {
index 30c4833..658c1c5 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -554,7 +554,7 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
                newattrs.ia_mode &= ~S_ISGID;
                newattrs.ia_valid |= ATTR_MODE;
        }
-       error = DQUOT_TRANSFER(dentry, &newattrs);
+       error = notify_change(dentry, &newattrs);
 out:
        return error;
 }
index a2886f5..d6b12cf 100644 (file)
@@ -46,7 +46,7 @@ extern void wait_for_keypress(void);
 
 extern int root_mountflags;
 
-int do_remount_sb(struct super_block *sb, int flags, char * data);
+int do_remount_sb(struct super_block *sb, int flags, void * data);
 
 /* this is initialized in init/main.c */
 kdev_t ROOT_DEV;
@@ -273,23 +273,12 @@ struct file_system_type *get_fs_type(const char *name)
 
 struct vfsmount *alloc_vfsmnt(void);
 void free_vfsmnt(struct vfsmount *mnt);
-void umount_tree(struct vfsmount *mnt);
+void set_devname(struct vfsmount *mnt, const char *name);
 
 /* Will go away */
 extern struct vfsmount *root_vfsmnt;
 extern int graft_tree(struct vfsmount *mnt, struct nameidata *nd);
 
-static void kill_super(struct super_block *);
-
-void __mntput(struct vfsmount *mnt)
-{
-       struct super_block *sb = mnt->mnt_sb;
-
-       dput(mnt->mnt_root);
-       free_vfsmnt(mnt);
-       kill_super(sb);
-}
-
 static inline void __put_super(struct super_block *sb)
 {
        spin_lock(&sb_lock);
@@ -404,9 +393,7 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf)
         struct statfs sbuf;
        int err = -EINVAL;
 
-       lock_kernel();
         s = get_super(to_kdev_t(dev));
-       unlock_kernel();
         if (s == NULL)
                 goto out;
        err = vfs_statfs(s, &sbuf);
@@ -727,7 +714,7 @@ retry:
        }
 }
 
-static void kill_super(struct super_block *sb)
+void kill_super(struct super_block *sb)
 {
        struct block_device *bdev;
        kdev_t dev;
@@ -789,7 +776,7 @@ static void kill_super(struct super_block *sb)
  * is used as a reference - file system type and the device are ignored.
  */
 
-int do_remount_sb(struct super_block *sb, int flags, char *data)
+int do_remount_sb(struct super_block *sb, int flags, void *data)
 {
        int retval;
        
@@ -846,12 +833,7 @@ struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data)
                mnt = ERR_PTR(-ENOMEM);
                goto fs_out;
        }
-       if (name) {
-               mnt->mnt_devname = kmalloc(strlen(name)+1, GFP_KERNEL);
-               if (mnt->mnt_devname)
-                       strcpy(mnt->mnt_devname, name);
-       }
-
+       set_devname(mnt, name);
        /* get locked superblock */
        if (fstype->fs_flags & FS_REQUIRES_DEV)
                sb = get_sb_bdev(fstype, name, flags, data);
@@ -1042,9 +1024,7 @@ mount_it:
        if (!vfsmnt)
                panic("VFS: alloc_vfsmnt failed for root fs");
 
-       vfsmnt->mnt_devname = kmalloc(strlen(name)+1, GFP_KERNEL);
-       if (vfsmnt->mnt_devname)
-               strcpy(vfsmnt->mnt_devname, name);
+       set_devname(vfsmnt, name);
        vfsmnt->mnt_sb = sb;
        vfsmnt->mnt_root = dget(sb->s_root);
 
index 0aa448b..0d82b45 100644 (file)
@@ -142,7 +142,7 @@ static inline int load_block_bitmap(struct super_block *sb,
        return slot;
 }
 
-static void udf_bitmap_free_blocks(const struct inode * inode,
+static void udf_bitmap_free_blocks(struct inode * inode,
        struct udf_bitmap *bitmap, lb_addr bloc, Uint32 offset, Uint32 count)
 {
        struct buffer_head * bh = NULL;
@@ -200,7 +200,7 @@ do_more:
                }
                else
                {
-                       DQUOT_FREE_BLOCK(sb, inode, 1);
+                       DQUOT_FREE_BLOCK(inode, 1);
                        if (UDF_SB_LVIDBH(sb))
                        {
                                UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
@@ -223,7 +223,7 @@ error_return:
        return;
 }
 
-static int udf_bitmap_prealloc_blocks(const struct inode * inode,
+static int udf_bitmap_prealloc_blocks(struct inode * inode,
        struct udf_bitmap *bitmap, Uint16 partition, Uint32 first_block,
        Uint32 block_count)
 {
@@ -265,12 +265,12 @@ repeat:
        {
                if (!udf_test_bit(bit, bh->b_data))
                        goto out;
-               else if (DQUOT_PREALLOC_BLOCK(sb, inode, 1))
+               else if (DQUOT_PREALLOC_BLOCK(inode, 1))
                        goto out;
                else if (!udf_clear_bit(bit, bh->b_data))
                {
                        udf_debug("bit already cleared for block %d\n", bit);
-                       DQUOT_FREE_BLOCK(sb, inode, 1);
+                       DQUOT_FREE_BLOCK(inode, 1);
                        goto out;
                }
                block_count --;
@@ -293,7 +293,7 @@ out:
        return alloc_count;
 }
 
-static int udf_bitmap_new_block(const struct inode * inode,
+static int udf_bitmap_new_block(struct inode * inode,
        struct udf_bitmap *bitmap, Uint16 partition, Uint32 goal, int *err)
 {
        int newbit, bit=0, block, block_group, group_start;
@@ -404,7 +404,7 @@ got_block:
        /*
         * Check quota for allocation of this block.
         */
-       if (DQUOT_ALLOC_BLOCK(sb, inode, 1))
+       if (DQUOT_ALLOC_BLOCK(inode, 1))
        {
                unlock_super(sb);
                *err = -EDQUOT;
@@ -439,7 +439,7 @@ error_return:
        return 0;
 }
 
-static void udf_table_free_blocks(const struct inode * inode,
+static void udf_table_free_blocks(struct inode * inode,
        struct inode * table, lb_addr bloc, Uint32 offset, Uint32 count)
 {
        struct super_block * sb;
@@ -475,7 +475,7 @@ static void udf_table_free_blocks(const struct inode * inode,
 
        /* We do this up front - There are some error conditions that could occure,
           but.. oh well */
-       DQUOT_FREE_BLOCK(sb, inode, count);
+       DQUOT_FREE_BLOCK(inode, count);
        if (UDF_SB_LVIDBH(sb))
        {
                UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
@@ -690,7 +690,7 @@ error_return:
        return;
 }
 
-static int udf_table_prealloc_blocks(const struct inode * inode,
+static int udf_table_prealloc_blocks(struct inode * inode,
        struct inode *table, Uint16 partition, Uint32 first_block,
        Uint32 block_count)
 {
@@ -887,7 +887,7 @@ static int udf_table_new_block(const struct inode * inode,
        return newblock;
 }
 
-inline void udf_free_blocks(const struct inode * inode, lb_addr bloc,
+inline void udf_free_blocks(struct inode * inode, lb_addr bloc,
        Uint32 offset, Uint32 count)
 {
        if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_UNALLOC_BITMAP)
@@ -918,7 +918,7 @@ inline void udf_free_blocks(const struct inode * inode, lb_addr bloc,
                return;
 }
 
-inline int udf_prealloc_blocks(const struct inode * inode, Uint16 partition,
+inline int udf_prealloc_blocks(struct inode * inode, Uint16 partition,
        Uint32 first_block, Uint32 block_count)
 {
        if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
@@ -949,7 +949,7 @@ inline int udf_prealloc_blocks(const struct inode * inode, Uint16 partition,
                return 0;
 }
 
-inline int udf_new_block(const struct inode * inode, Uint16 partition,
+inline int udf_new_block(struct inode * inode, Uint16 partition,
        Uint32 goal, int *err)
 {
        if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
index bd2c3ae..8755390 100644 (file)
@@ -44,7 +44,7 @@ void udf_free_inode(struct inode * inode)
         * Note: we must free any quota before locking the superblock,
         * as writing the quota to disk may need the lock as well.
         */
-       DQUOT_FREE_INODE(sb, inode);
+       DQUOT_FREE_INODE(inode);
        DQUOT_DROP(inode);
 
        lock_super(sb);
@@ -70,7 +70,7 @@ void udf_free_inode(struct inode * inode)
        udf_free_blocks(inode, UDF_I_LOCATION(inode), 0, 1);
 }
 
-struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
+struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
 {
        struct super_block *sb;
        struct inode * inode;
@@ -153,9 +153,10 @@ struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
        mark_inode_dirty(inode);
 
        unlock_super(sb);
-       if (DQUOT_ALLOC_INODE(sb, inode))
+       if (DQUOT_ALLOC_INODE(inode))
        {
-               sb->dq_op->drop(inode);
+               DQUOT_DROP(inode);
+               inode->i_flags |= S_NOQUOTA;
                inode->i_nlink = 0;
                iput(inode);
                *err = -EDQUOT;
index 2159aad..d13911a 100644 (file)
@@ -165,15 +165,15 @@ extern int udf_get_filename(struct super_block *, Uint8 *, Uint8 *, int);
 
 /* ialloc.c */
 extern void udf_free_inode(struct inode *);
-extern struct inode * udf_new_inode (const struct inode *, int, int *);
+extern struct inode * udf_new_inode (struct inode *, int, int *);
 
 /* truncate.c */
 extern void udf_truncate_extents(struct inode *);
 
 /* balloc.c */
-extern void udf_free_blocks(const struct inode *, lb_addr, Uint32, Uint32);
-extern int udf_prealloc_blocks(const struct inode *, Uint16, Uint32, Uint32);
-extern int udf_new_block(const struct inode *, Uint16, Uint32, int *);
+extern void udf_free_blocks(struct inode *, lb_addr, Uint32, Uint32);
+extern int udf_prealloc_blocks(struct inode *, Uint16, Uint32, Uint32);
+extern int udf_new_block(struct inode *, Uint16, Uint32, int *);
 
 /* fsync.c */
 extern int udf_fsync_file(struct file *, struct dentry *, int);
index 0b299d5..e3f906c 100644 (file)
@@ -85,7 +85,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
                        "bit already cleared for fragment %u", i);
        }
        
-       DQUOT_FREE_BLOCK (sb, inode, count);
+       DQUOT_FREE_BLOCK (inode, count);
        ADD_SWAB32(ucg->cg_cs.cs_nffree, count);
        ADD_SWAB32(usb1->fs_cstotal.cs_nffree, count);
        ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
@@ -187,7 +187,7 @@ do_more:
                ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno);
                if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                        ufs_clusteracct (sb, ucpi, blkno, 1);
-               DQUOT_FREE_BLOCK(sb, inode, uspi->s_fpb);
+               DQUOT_FREE_BLOCK(inode, uspi->s_fpb);
                INC_SWAB32(ucg->cg_cs.cs_nbfree);
                INC_SWAB32(usb1->fs_cstotal.cs_nbfree);
                INC_SWAB32(sb->fs_cs(cgno).cs_nbfree);
@@ -451,7 +451,7 @@ unsigned ufs_add_fragments (struct inode * inode, unsigned fragment,
                INC_SWAB32(ucg->cg_frsum[fragsize - count]);
        for (i = oldcount; i < newcount; i++)
                ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i);
-       if(DQUOT_ALLOC_BLOCK(sb, inode, count)) {
+       if(DQUOT_ALLOC_BLOCK(inode, count)) {
                *err = -EDQUOT;
                return 0;
        }
@@ -558,7 +558,7 @@ cg_found:
                for (i = count; i < uspi->s_fpb; i++)
                        ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i);
                i = uspi->s_fpb - count;
-               DQUOT_FREE_BLOCK(sb, inode, i);
+               DQUOT_FREE_BLOCK(inode, i);
                ADD_SWAB32(ucg->cg_cs.cs_nffree, i);
                ADD_SWAB32(usb1->fs_cstotal.cs_nffree, i);
                ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, i);
@@ -569,7 +569,7 @@ cg_found:
        result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
        if (result == (unsigned)-1)
                return 0;
-       if(DQUOT_ALLOC_BLOCK(sb, inode, count)) {
+       if(DQUOT_ALLOC_BLOCK(inode, count)) {
                *err = -EDQUOT;
                return 0;
        }
@@ -639,7 +639,7 @@ gotit:
        ubh_clrblock (UCPI_UBH, ucpi->c_freeoff, blkno);
        if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                ufs_clusteracct (sb, ucpi, blkno, -1);
-       if(DQUOT_ALLOC_BLOCK(sb, inode, uspi->s_fpb)) {
+       if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) {
                *err = -EDQUOT;
                return (unsigned)-1;
        }
index d7fef19..b1e331d 100644 (file)
@@ -100,7 +100,7 @@ void ufs_free_inode (struct inode * inode)
 
        is_directory = S_ISDIR(inode->i_mode);
 
-       DQUOT_FREE_INODE(sb, inode);
+       DQUOT_FREE_INODE(inode);
        DQUOT_DROP(inode);
 
        clear_inode (inode);
@@ -278,8 +278,9 @@ cg_found:
 
        unlock_super (sb);
 
-       if(DQUOT_ALLOC_INODE(sb, inode)) {
-               sb->dq_op->drop(inode);
+       if (DQUOT_ALLOC_INODE(inode)) {
+               DQUOT_DROP(inode);
+               inode->i_flags |= S_NOQUOTA;
                inode->i_nlink = 0;
                iput(inode);
                *err = -EDQUOT;
@@ -293,6 +294,7 @@ cg_found:
 
 failed:
        unlock_super (sb);
+       make_bad_inode(inode);
        iput (inode);
        UFSD(("EXIT (FAILED)\n"))
        return NULL;
index 7714bf2..70d6ce7 100644 (file)
   __asm__("stw %1,%0" : "=m"(mem) : "r"(val))
 #endif
 
-/* Somewhere in the middle of the GCC 2.96 development cycle, we implemented
-   a mechanism by which the user can annotate likely branch directions and
-   expect the blocks to be reordered appropriately.  Define __builtin_expect
-   to nothing for earlier compilers.  */
-
-#if __GNUC__ == 2 && __GNUC_MINOR__ < 96
-#define __builtin_expect(x, expected_value) (x)
-#endif
-
 #endif /* __ALPHA_COMPILER_H */
index f403fa8..e4e6bd3 100644 (file)
@@ -80,7 +80,7 @@ extern __inline__ int get_order(unsigned long size)
        return order;
 }
 
-#endif /* !ASSEMBLY */
+#endif /* !__ASSEMBLY__ */
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
index 005af29..1c41ecc 100644 (file)
@@ -148,6 +148,8 @@ unsigned long get_wchan(struct task_struct *p);
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
 #define ARCH_HAS_SPINLOCK_PREFETCH
index 6812299..0eafe88 100644 (file)
@@ -12,7 +12,7 @@
 
 #ifdef __KERNEL__
 
-#include <asm/compiler.h>
+#include <linux/compiler.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
index fa101aa..b5d6082 100644 (file)
@@ -11,7 +11,7 @@
 #include <asm/current.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <asm/compiler.h>
+#include <linux/compiler.h>
 #include <linux/wait.h>
 #include <linux/rwsem.h>
 
index be44c2d..cd4a06d 100644 (file)
@@ -112,6 +112,8 @@ extern void __free_task_struct(struct task_struct *);
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 /*
  * Create a new kernel thread
  */
index 5bc95fa..dec7e2c 100644 (file)
@@ -141,4 +141,6 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t)
 #define init_task       (init_task_union.task)
 #define init_stack      (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 #endif /* __ASM_CRIS_PROCESSOR_H */
index 4445df1..ee4167b 100644 (file)
@@ -476,6 +476,8 @@ static inline void rep_nop(void)
        __asm__ __volatile__("rep;nop");
 }
 
+#define cpu_relax()    rep_nop()
+
 /* Prefetch instructions for Pentium III and AMD Athlon */
 #ifdef         CONFIG_MPENTIUMIII
 
index 362397e..f841e42 100644 (file)
@@ -4,14 +4,14 @@
 /*
  * We need the APIC definitions automatically as part of 'smp.h'
  */
-#ifndef ASSEMBLY
+#ifndef __ASSEMBLY__
 #include <linux/config.h>
 #include <linux/threads.h>
 #include <linux/ptrace.h>
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
-#ifndef ASSEMBLY
+#ifndef __ASSEMBLY__
 #include <asm/fixmap.h>
 #include <asm/bitops.h>
 #include <asm/mpspec.h>
@@ -22,7 +22,7 @@
 #endif
 #endif
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 # ifdef CONFIG_MULTIQUAD
 #  define TARGET_CPUS 0xf     /* all CPUs in *THIS* quad */
 #  define INT_DELIVERY_MODE 0     /* physical delivery on LOCAL quad */
 #  define INT_DELIVERY_MODE 1     /* logical delivery broadcast to all procs */
 # endif
 #else
+# define INT_DELIVERY_MODE 0     /* physical delivery on LOCAL quad */
 # define TARGET_CPUS 0x01
 #endif
 
+#ifndef clustered_apic_mode
+ #ifdef CONFIG_MULTIQUAD
+  #define clustered_apic_mode (1)
+  #define esr_disable (1)
+ #else /* !CONFIG_MULTIQUAD */
+  #define clustered_apic_mode (0)
+  #define esr_disable (0)
+ #endif /* CONFIG_MULTIQUAD */
+#endif 
+
 #ifdef CONFIG_SMP
-#ifndef ASSEMBLY
+#ifndef __ASSEMBLY__
 
 /*
  * Private routines/data
@@ -77,16 +88,6 @@ extern volatile int physical_apicid_to_cpu[MAX_APICID];
 extern volatile int cpu_to_logical_apicid[NR_CPUS];
 extern volatile int logical_apicid_to_cpu[MAX_APICID];
 
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
-  #define clustered_apic_mode (1)
-  #define esr_disable (1)
- #else /* !CONFIG_MULTIQUAD */
-  #define clustered_apic_mode (0)
-  #define esr_disable (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif 
-
 /*
  * General functions that each host system must provide.
  */
@@ -114,7 +115,7 @@ extern __inline int logical_smp_processor_id(void)
        return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
 }
 
-#endif /* !ASSEMBLY */
+#endif /* !__ASSEMBLY__ */
 
 #define NO_PROC_ID             0xFF            /* No processor magic marker */
 
index bef8ac6..dda22a4 100644 (file)
@@ -969,6 +969,8 @@ ia64_thash (__u64 addr)
        return result;
 }
 
+#define cpu_relax()    do { } while (0)
+
 
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
index cbe657e..8d976bf 100644 (file)
@@ -155,4 +155,6 @@ unsigned long get_wchan(struct task_struct *p);
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 #endif
index 90c0b6c..06d85fc 100644 (file)
@@ -259,6 +259,8 @@ unsigned long get_wchan(struct task_struct *p);
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 #endif /* __KERNEL__ */
 
index 8798431..1572cc5 100644 (file)
@@ -290,6 +290,8 @@ unsigned long get_wchan(struct task_struct *p);
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 #endif /* __KERNEL__ */
 
index c612fa8..3929c52 100644 (file)
@@ -333,5 +333,7 @@ extern inline unsigned long get_wchan(struct task_struct *p)
 #define init_task (init_task_union.task) 
 #define init_stack (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 
 #endif /* __ASM_PARISC_PROCESSOR_H */
index 633becd..f5b55b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.processor.h 1.28 08/17/01 15:23:17 paulus
+ * BK Id: SCCS/s.processor.h 1.31 10/05/01 16:26:22 paulus
  */
 #ifdef __KERNEL__
 #ifndef __ASM_PPC_PROCESSOR_H
@@ -655,6 +655,27 @@ void ll_puts(const char *);
 /* In misc.c */
 void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
 
+#define cpu_relax()    do { } while (0)
+
+/*
+ * Prefetch macros.
+ */
+#define ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCHW
+#define ARCH_HAS_SPINLOCK_PREFETCH
+
+extern inline void prefetch(const void *x)
+{
+        __asm__ __volatile__ ("dcbt 0,%0" : : "r" (x));
+}
+
+extern inline void prefetchw(const void *x)
+{
+        __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x));
+}
+
+#define spin_lock_prefetch(x)  prefetchw(x)
+
 #endif /* !__ASSEMBLY__ */
 
 #define have_of (_machine == _MACH_chrp || _machine == _MACH_Pmac)
index c1822da..539d1df 100644 (file)
@@ -149,6 +149,8 @@ unsigned long get_wchan(struct task_struct *p);
 #define init_task       (init_task_union.task)
 #define init_stack      (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 /*
  * Set of msr bits that gdb can change on behalf of a process.
  */
index b33891a..c0351e2 100644 (file)
@@ -159,6 +159,8 @@ unsigned long get_wchan(struct task_struct *p);
 #define init_task       (init_task_union.task)
 #define init_stack      (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 /*
  * Set of msr bits that gdb can change on behalf of a process.
  */
index d628309..9268300 100644 (file)
@@ -218,4 +218,6 @@ extern void free_task_struct(struct task_struct *);
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 #endif /* __ASM_SH_PROCESSOR_H */
index 0b19b15..f33f834 100644 (file)
@@ -201,6 +201,8 @@ BTFIXUPDEF_CALL(void, get_task_struct, struct task_struct *)
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 #endif
 
 #endif /* __ASM_SPARC_PROCESSOR_H */
index 6c7a93f..a75aecf 100644 (file)
@@ -276,6 +276,8 @@ __out:      __ret; \
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
 
+#define cpu_relax()    do { } while (0)
+
 #endif /* __KERNEL__ */
 
 #endif /* !(__ASSEMBLY__) */
index eadb9e6..c8e54a3 100644 (file)
@@ -46,6 +46,7 @@ enum chipset_type {
        INTEL_GX,
        INTEL_I810,
        INTEL_I815,
+       INTEL_I830_M,
        INTEL_I840,
        INTEL_I850,
        VIA_GENERIC,
index f11118f..a4cb2b8 100644 (file)
@@ -178,6 +178,9 @@ extern void prune_dcache(int);
 extern int shrink_icache_memory(int, int);
 extern void prune_icache(int);
 
+/* quota cache memory management (defined in linux/fs/dquot.c) */
+extern int shrink_dqcache_memory(int, unsigned int);
+
 /* only used at mount-time */
 extern struct dentry * d_alloc_root(struct inode *);
 
index 75923c8..3351936 100644 (file)
@@ -551,9 +551,9 @@ extern int ext2_permission (struct inode *, int);
 /* balloc.c */
 extern int ext2_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
-extern int ext2_new_block (const struct inode *, unsigned long,
+extern int ext2_new_block (struct inode *, unsigned long,
                           __u32 *, __u32 *, int *);
-extern void ext2_free_blocks (const struct inode *, unsigned long,
+extern void ext2_free_blocks (struct inode *, unsigned long,
                              unsigned long);
 extern unsigned long ext2_count_free_blocks (struct super_block *);
 extern void ext2_check_blocks_bitmap (struct super_block *);
index 9d31405..b058b67 100644 (file)
@@ -108,6 +108,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time;
 #define MS_NOATIME     1024    /* Do not update access times. */
 #define MS_NODIRATIME  2048    /* Do not update directory access times */
 #define MS_BIND                4096
+#define MS_REC         16384
 #define MS_NOUSER      (1<<31)
 
 /*
@@ -919,11 +920,11 @@ static inline void mark_inode_dirty_pages(struct inode *inode)
 struct dquot_operations {
        void (*initialize) (struct inode *, short);
        void (*drop) (struct inode *);
-       int (*alloc_block) (const struct inode *, unsigned long, char);
+       int (*alloc_block) (struct inode *, unsigned long, char);
        int (*alloc_inode) (const struct inode *, unsigned long);
-       void (*free_block) (const struct inode *, unsigned long);
+       void (*free_block) (struct inode *, unsigned long);
        void (*free_inode) (const struct inode *, unsigned long);
-       int (*transfer) (struct dentry *, struct iattr *);
+       int (*transfer) (struct inode *, struct iattr *);
 };
 
 struct file_system_type {
index becc3a0..018e766 100644 (file)
@@ -348,6 +348,13 @@ extern struct module *module_list;
 #define EXPORT_SYMBOL_NOVERS(var)  error config_must_be_included_before_module
 #define EXPORT_SYMBOL_GPL(var)  error config_must_be_included_before_module
 
+#elif !defined(EXPORT_SYMTAB)
+
+#define __EXPORT_SYMBOL(sym,str)   error this_object_must_be_defined_as_export_objs_in_the_Makefile
+#define EXPORT_SYMBOL(var)        error this_object_must_be_defined_as_export_objs_in_the_Makefile
+#define EXPORT_SYMBOL_NOVERS(var)  error this_object_must_be_defined_as_export_objs_in_the_Makefile
+#define EXPORT_SYMBOL_GPL(var)  error this_object_must_be_defined_as_export_objs_in_the_Makefile
+
 #elif !defined(CONFIG_MODULES)
 
 #define __EXPORT_SYMBOL(sym,str)
index 2d4fd33..f13b458 100644 (file)
@@ -29,7 +29,6 @@ struct vfsmount
        int mnt_flags;
        char *mnt_devname;              /* Name of device e.g. /dev/dsk/hda1 */
        struct list_head mnt_list;
-       uid_t mnt_owner;
 };
 
 static inline struct vfsmount *mntget(struct vfsmount *mnt)
index ce6d07e..5007df9 100644 (file)
@@ -83,8 +83,6 @@ extern void lock_page(struct page *page);
 #define find_lock_page(mapping, index) \
        __find_lock_page(mapping, index, page_hash(mapping, index))
 
-extern void __add_page_to_hash_queue(struct page * page, struct page **p);
-
 extern void add_to_page_cache(struct page * page, struct address_space *mapping, unsigned long index);
 extern void add_to_page_cache_locked(struct page * page, struct address_space *mapping, unsigned long index);
 extern int add_to_page_cache_unique(struct page * page, struct address_space *mapping, unsigned long index, struct page **hash);
index 9324b9a..3f69eb9 100644 (file)
 #define QUOTAFILENAME "quota"
 #define QUOTAGROUP "staff"
 
-extern int nr_dquots, nr_free_dquots;
-extern int max_dquots;
-extern int dquot_root_squash;
-
-#define NR_DQHASH 43            /* Just an arbitrary number */
-#define NR_DQUOTS 1024          /* Maximum number of quotas active at one time (Configurable from /proc/sys/fs) */
-
 /*
  * Command definitions for the 'quotactl' system call.
  * The commands are broken into a main command defined below
@@ -151,26 +144,23 @@ struct dqstats {
 
 #ifdef __KERNEL__
 
-/*
- * Maximum length of a message generated in the quota system,
- * that needs to be kicked onto the tty.
- */
-#define MAX_QUOTA_MESSAGE 75
+extern int nr_dquots, nr_free_dquots;
+extern int dquot_root_squash;
+
+#define NR_DQHASH 43            /* Just an arbitrary number */
 
-#define DQ_LOCKED     0x01     /* locked for update */
-#define DQ_WANT       0x02     /* wanted for update */
-#define DQ_MOD        0x04     /* dquot modified since read */
+#define DQ_LOCKED     0x01     /* dquot under IO */
+#define DQ_MOD        0x02     /* dquot modified since read */
 #define DQ_BLKS       0x10     /* uid/gid has been warned about blk limit */
 #define DQ_INODES     0x20     /* uid/gid has been warned about inode limit */
 #define DQ_FAKE       0x40     /* no limits only usage */
 
 struct dquot {
-       struct dquot *dq_next;          /* Pointer to next dquot */
-       struct dquot **dq_pprev;
-       struct list_head dq_free;       /* free list element */
-       struct dquot *dq_hash_next;     /* Pointer to next in dquot_hash */
-       struct dquot **dq_hash_pprev;   /* Pointer to previous in dquot_hash */
-       wait_queue_head_t dq_wait;      /* Pointer to waitqueue */
+       struct list_head dq_hash;       /* Hash list in memory */
+       struct list_head dq_inuse;      /* List of all quotas */
+       struct list_head dq_free;       /* Free list element */
+       wait_queue_head_t dq_wait_lock; /* Pointer to waitqueue on dquot lock */
+       wait_queue_head_t dq_wait_free; /* Pointer to waitqueue for quota to be unused */
        int dq_count;                   /* Reference count */
 
        /* fields after this point are cleared when invalidating */
@@ -189,7 +179,6 @@ struct dquot {
 /*
  * Flags used for set_dqblk.
  */
-#define QUOTA_SYSCALL     0x01
 #define SET_QUOTA         0x02
 #define SET_USE           0x04
 #define SET_QLIMIT        0x08
index a97d3f4..485639f 100644 (file)
 #define _LINUX_QUOTAOPS_
 
 #include <linux/config.h>
+#include <linux/smp_lock.h>
 
 #if defined(CONFIG_QUOTA)
 
-#include <linux/smp_lock.h>
+#include <linux/fs.h>
 
 /*
  * declaration of quota_function calls in kernel.
@@ -24,85 +25,138 @@ extern void dquot_drop(struct inode *inode);
 extern int  quota_off(struct super_block *sb, short type);
 extern int  sync_dquots(kdev_t dev, short type);
 
-extern int  dquot_alloc_block(const struct inode *inode, unsigned long number, char prealloc);
+extern int  dquot_alloc_block(struct inode *inode, unsigned long number, char prealloc);
 extern int  dquot_alloc_inode(const struct inode *inode, unsigned long number);
 
-extern void dquot_free_block(const struct inode *inode, unsigned long number);
+extern void dquot_free_block(struct inode *inode, unsigned long number);
 extern void dquot_free_inode(const struct inode *inode, unsigned long number);
 
-extern int  dquot_transfer(struct dentry *dentry, struct iattr *iattr);
+extern int  dquot_transfer(struct inode *inode, struct iattr *iattr);
 
 /*
  * Operations supported for diskquotas.
  */
+#define sb_any_quota_enabled(sb) ((sb)->s_dquot.flags & (DQUOT_USR_ENABLED | DQUOT_GRP_ENABLED))
+
 static __inline__ void DQUOT_INIT(struct inode *inode)
 {
-       if (!IS_NOQUOTA(inode)) {
-               if (inode->i_sb && inode->i_sb->dq_op)
-                       inode->i_sb->dq_op->initialize(inode, -1);
-       }
+       if (!inode->i_sb)
+               BUG();
+       lock_kernel();
+       if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode))
+               inode->i_sb->dq_op->initialize(inode, -1);
+       unlock_kernel();
 }
 
 static __inline__ void DQUOT_DROP(struct inode *inode)
 {
+       lock_kernel();
        if (IS_QUOTAINIT(inode)) {
-               if (inode->i_sb && inode->i_sb->dq_op)
-                       inode->i_sb->dq_op->drop(inode);
+               if (!inode->i_sb)
+                       BUG();
+               inode->i_sb->dq_op->drop(inode);        /* Ops must be set when there's any quota... */
        }
+       unlock_kernel();
 }
 
-static __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
 {
-       if (sb->dq_op) {
-               if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 1) == NO_QUOTA)
+       lock_kernel();
+       if (sb_any_quota_enabled(inode->i_sb)) {
+               /* Number of used blocks is updated in alloc_block() */
+               if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 1) == NO_QUOTA) {
+                       unlock_kernel();
                        return 1;
+               }
        }
+       else
+               inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+       unlock_kernel();
        return 0;
 }
 
-static __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr)
 {
-       if (sb->dq_op) {
-               if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 0) == NO_QUOTA)
+       int ret;
+        if (!(ret =  DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr)))
+               mark_inode_dirty(inode);
+       return ret;
+}
+
+static __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+{
+       lock_kernel();
+       if (sb_any_quota_enabled(inode->i_sb)) {
+               /* Number of used blocks is updated in alloc_block() */
+               if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 0) == NO_QUOTA) {
+                       unlock_kernel();
                        return 1;
+               }
        }
+       else
+               inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+       unlock_kernel();
        return 0;
 }
 
-static __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
+static __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr)
+{
+       int ret;
+       if (!(ret = DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr)))
+               mark_inode_dirty(inode);
+       return ret;
+}
+
+static __inline__ int DQUOT_ALLOC_INODE(struct inode *inode)
 {
-       if (sb->dq_op) {
+       lock_kernel();
+       if (sb_any_quota_enabled(inode->i_sb)) {
                DQUOT_INIT(inode);
-               if (sb->dq_op->alloc_inode (inode, 1))
+               if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) {
+                       unlock_kernel();
                        return 1;
+               }
        }
-       inode->i_flags |= S_QUOTA;
+       unlock_kernel();
        return 0;
 }
 
-static __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr)
 {
-       if (sb->dq_op)
-               sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize));
+       lock_kernel();
+       if (sb_any_quota_enabled(inode->i_sb))
+               inode->i_sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize));
+       else
+               inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9);
+       unlock_kernel();
 }
 
-static __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode)
+static __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr)
 {
-       if (sb->dq_op)
-               sb->dq_op->free_inode(inode, 1);
+       DQUOT_FREE_BLOCK_NODIRTY(inode, nr);
+       mark_inode_dirty(inode);
 }
 
-static __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
+static __inline__ void DQUOT_FREE_INODE(struct inode *inode)
 {
-       int error = -EDQUOT;
+       lock_kernel();
+       if (sb_any_quota_enabled(inode->i_sb))
+               inode->i_sb->dq_op->free_inode(inode, 1);
+       unlock_kernel();
+}
 
-       if (dentry->d_inode->i_sb->dq_op && !IS_NOQUOTA(dentry->d_inode)) {
-               DQUOT_INIT(dentry->d_inode);
-               error = dentry->d_inode->i_sb->dq_op->transfer(dentry, iattr);
-       } else {
-               error = notify_change(dentry, iattr);
+static __inline__ int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr)
+{
+       lock_kernel();
+       if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) {
+               DQUOT_INIT(inode);
+               if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) {
+                       unlock_kernel();
+                       return 1;
+               }
        }
-       return error;
+       unlock_kernel();
+       return 0;
 }
 
 #define DQUOT_SYNC(dev)        sync_dquots(dev, -1)
@@ -115,18 +169,53 @@ static __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
  */
 #define DQUOT_INIT(inode)                      do { } while(0)
 #define DQUOT_DROP(inode)                      do { } while(0)
-#define DQUOT_PREALLOC_BLOCK(sb, inode, nr)    (0)
-#define DQUOT_ALLOC_BLOCK(sb, inode, nr)       (0)
-#define DQUOT_ALLOC_INODE(sb, inode)           (0)
-#define DQUOT_FREE_BLOCK(sb, inode, nr)                do { } while(0)
-#define DQUOT_FREE_INODE(sb, inode)            do { } while(0)
+#define DQUOT_ALLOC_INODE(inode)               (0)
+#define DQUOT_FREE_INODE(inode)                        do { } while(0)
 #define DQUOT_SYNC(dev)                                do { } while(0)
 #define DQUOT_OFF(sb)                          do { } while(0)
+#define DQUOT_TRANSFER(inode, iattr)           (0)
+extern __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+{
+       lock_kernel();
+       inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+       unlock_kernel();
+       return 0;
+}
 
-/*
- * Special case expands to a simple notify_change.
- */
-#define DQUOT_TRANSFER(dentry, iattr) notify_change(dentry, iattr)
+extern __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr)
+{
+       DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr);
+       mark_inode_dirty(inode);
+       return 0;
+}
+
+extern __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+{
+       lock_kernel();
+       inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+       unlock_kernel();
+       return 0;
+}
+
+extern __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr)
+{
+       DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr);
+       mark_inode_dirty(inode);
+       return 0;
+}
+
+extern __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr)
+{
+       lock_kernel();
+       inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9);
+       unlock_kernel();
+}
+
+extern __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr)
+{
+       DQUOT_FREE_BLOCK_NODIRTY(inode, nr);
+       mark_inode_dirty(inode);
+}      
 
 #endif /* CONFIG_QUOTA */
 #endif /* _LINUX_QUOTAOPS_ */
index 2f942d7..887237f 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/route.h>
+#include <linux/cache.h>
 
 #ifndef __KERNEL__
 #warning This file is not supposed to be used outside of kernel.
@@ -105,7 +106,7 @@ struct rt_cache_stat
         unsigned int out_hit;
         unsigned int out_slow_tot;
         unsigned int out_slow_mc;
-};
+} ____cacheline_aligned_in_smp;
 
 extern struct ip_rt_acct *ip_rt_acct;
 
index 8278bfc..cb65330 100644 (file)
@@ -482,7 +482,7 @@ static void __init parse_options(char *line)
 extern void setup_arch(char **);
 extern void cpu_idle(void);
 
-volatile unsigned long wait_init_idle = 0UL;
+unsigned long wait_init_idle;
 
 #ifndef CONFIG_SMP
 
@@ -505,18 +505,18 @@ static void __init smp_init(void)
        smp_boot_cpus();
        wait_init_idle = cpu_online_map;
        clear_bit(current->processor, &wait_init_idle); /* Don't wait on me! */
-       printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle);
+
        smp_threads_ready=1;
        smp_commence();
 
        /* Wait for the other cpus to set up their idle processes */
-        while (1) {
-                if (!wait_init_idle)
-                        break;
-                rep_nop();
-        }
+       printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle);
+       while (wait_init_idle) {
+               cpu_relax();
+               barrier();
+       }
        printk("All processors have done init_idle\n");
-}              
+}
 
 #endif
 
index 60505f2..e35da10 100644 (file)
@@ -1309,7 +1309,7 @@ void daemonize(void)
        atomic_inc(&current->files->count);
 }
 
-extern volatile unsigned long wait_init_idle;
+extern unsigned long wait_init_idle;
 
 void __init init_idle(void)
 {
index 1e9c81d..446bb8b 100644 (file)
@@ -288,8 +288,6 @@ static ctl_table fs_table[] = {
         0644, NULL, &proc_dointvec},
        {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
         0444, NULL, &proc_dointvec},
-       {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
-        0644, NULL, &proc_dointvec},
        {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
         0444, NULL, &proc_dointvec},
        {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
index d7f035c..2d63550 100644 (file)
@@ -241,13 +241,12 @@ int out_of_memory(void)
                return 0;
 
        /*
-        * If the buffer and page cache (excluding swap cache) are over
+        * If the buffer and page cache (including swap cache) are over
         * their (/proc tunable) minimum, we're still not OOM.  We test
         * this to make sure we don't return OOM when the system simply
         * has a hard time with the cache.
         */
        cache_mem = atomic_read(&page_cache_size);
-       cache_mem -= swapper_space.nrpages;
        limit = 2;
        limit *= num_physpages / 100;
 
index a6c56b2..2679810 100644 (file)
@@ -357,6 +357,7 @@ struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_
 
        /* here we're in the low on memory slow path */
 
+rebalance:
        if (current->flags & PF_MEMALLOC) {
                zone = zonelist->zones;
                for (;;) {
@@ -371,48 +372,28 @@ struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_
                return NULL;
        }
 
- rebalance:
        page = balance_classzone(classzone, gfp_mask, order, &freed);
        if (page)
                return page;
 
        zone = zonelist->zones;
-       if (likely(freed)) {
-               for (;;) {
-                       zone_t *z = *(zone++);
-                       if (!z)
-                               break;
-
-                       if (zone_free_pages(z, order) > z->pages_min) {
-                               page = rmqueue(z, order);
-                               if (page)
-                                       return page;
-                       }
-               }
-               goto rebalance;
-       } else {
-               /* 
-                * Check that no other task is been killed meanwhile,
-                * in such a case we can succeed the allocation.
-                */
-               for (;;) {
-                       zone_t *z = *(zone++);
-                       if (!z)
-                               break;
+       for (;;) {
+               zone_t *z = *(zone++);
+               if (!z)
+                       break;
 
-                       if (zone_free_pages(z, order) > z->pages_min) {
-                               page = rmqueue(z, order);
-                               if (page)
-                                       return page;
-                       }
+               if (zone_free_pages(z, order) > z->pages_min) {
+                       page = rmqueue(z, order);
+                       if (page)
+                               return page;
                }
-               
-               goto rebalance;
        }
 
-       printk(KERN_NOTICE "__alloc_pages: %u-order allocation failed (gfp=0x%x/%i) from %p\n",
-              order, gfp_mask, !!(current->flags & PF_MEMALLOC), __builtin_return_address(0));
-       return NULL;
+       /* Yield for kswapd, and try again */
+       current->policy |= SCHED_YIELD;
+       __set_current_state(TASK_RUNNING);
+       schedule();
+       goto rebalance;
 }
 
 /*
index 6e5644b..29fecaf 100644 (file)
@@ -546,6 +546,9 @@ static int shrink_caches(int priority, zone_t * classzone, unsigned int gfp_mask
 
        shrink_dcache_memory(priority, gfp_mask);
        shrink_icache_memory(priority, gfp_mask);
+#ifdef CONFIG_QUOTA
+       shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
+#endif
 
        return nr_pages;
 }
@@ -553,14 +556,16 @@ static int shrink_caches(int priority, zone_t * classzone, unsigned int gfp_mask
 int try_to_free_pages(zone_t * classzone, unsigned int gfp_mask, unsigned int order)
 {
        int ret = 0;
+       int priority = DEF_PRIORITY;
        int nr_pages = SWAP_CLUSTER_MAX;
 
-       nr_pages = shrink_caches(DEF_PRIORITY, classzone, gfp_mask, nr_pages);
-
-       if (nr_pages < SWAP_CLUSTER_MAX)
-               ret |= 1;
+       do {
+               nr_pages = shrink_caches(priority, classzone, gfp_mask, nr_pages);
+               if (nr_pages <= 0)
+                       return 1;
 
-       ret |= swap_out(DEF_PRIORITY, classzone, gfp_mask, SWAP_CLUSTER_MAX << 2);
+               ret |= swap_out(priority, classzone, gfp_mask, SWAP_CLUSTER_MAX << 2);
+       } while (--priority);
 
        return ret;
 }
index 4ab2966..23b5f8d 100644 (file)
@@ -552,35 +552,22 @@ int dev_alloc_name(struct net_device *dev, const char *name)
 {
        int i;
        char buf[32];
-       char *p, c;
+       char *p;
 
        /*
         * Verify the string as this thing may have come from
         * the user.  There must be one "%d" and no other "%"
         * characters.
         */
-       p = name;
-       while ((c = *p++) != 0) {
-               if (c == '%') {
-                       c = *p++;
-                       if (c != 'd')
-                               return -EINVAL;
-
-                       while ((c = *p++) != 0) {
-                               if (c == '%')
-                                       return -EINVAL;
-                       }
-                       goto name_ok;
-               }
-       }
-       return -EINVAL;
+       p = strchr(name, '%');
+       if (!p || p[1] != 'd' || strchr(p+2, '%'))
+               return -EINVAL;
 
- name_ok:
        /*
         * If you need over 100 please also fix the algorithm...
         */
        for (i = 0; i < 100; i++) {
-               sprintf(buf,name,i);
+               snprintf(buf,sizeof(buf),name,i);
                if (__dev_get_by_name(buf) == NULL) {
                        strcpy(dev->name, buf);
                        return i;
index 787be9b..04caebc 100644 (file)
@@ -325,7 +325,7 @@ static int check(const char *tablename,
 {
        const struct ipt_reject_info *rejinfo = targinfo;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_icmp))) {
+       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
                DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
                return 0;
        }
index b18270a..b320e29 100644 (file)
@@ -20,7 +20,7 @@ match(const struct sk_buff *skb,
 
     /* Is mac pointer valid? */
     return (skb->mac.raw >= skb->head
-           && skb->mac.raw < skb->head + skb->len - ETH_HLEN
+           && (skb->mac.raw + ETH_HLEN) <= skb->data
            /* If so, compare... */
            && ((memcmp(skb->mac.ethernet->h_source, info->srcaddr, ETH_ALEN)
                == 0) ^ info->invert));
index 62bdaca..028e5a3 100644 (file)
@@ -588,7 +588,7 @@ sub output_function_sgml(%) {
     } else {
        print "  <void>\n";
     }
-    print "  </funcsynopsis>\n";
+    print "  </funcprototype></funcsynopsis>\n";
     print "</refsynopsisdiv>\n";
 
     # print parameters