]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.35 2.3.35
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:29:38 +0000 (15:29 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:29:38 +0000 (15:29 -0500)
75 files changed:
CREDITS
Documentation/Configure.help
Documentation/filesystems/cramfs.txt [new file with mode: 0644]
Documentation/sound/Maestro [new file with mode: 0644]
MAINTAINERS
Makefile
arch/i386/defconfig
arch/ppc/config.in
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/gemini_setup.c
arch/ppc/kernel/irq.c
arch/ppc/kernel/local_irq.h
arch/ppc/kernel/m8xx_setup.c
arch/ppc/kernel/mbx_pci.c [deleted file]
arch/ppc/kernel/mbx_setup.c [deleted file]
arch/ppc/kernel/open_pic.c
arch/ppc/kernel/pmac_pic.c
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/prep_setup.c
drivers/pci/pci.c
drivers/pci/pci.ids
drivers/pcmcia/cardbus.c
drivers/pcmcia/yenta.c
drivers/sound/Config.in
drivers/sound/maestro.c
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/README.hp_scanner [deleted file]
drivers/usb/README.hp_scanner_sane [deleted file]
drivers/usb/README.scanner [new file with mode: 0644]
drivers/usb/README.scanner_hp_sane [new file with mode: 0644]
drivers/usb/acm.c
drivers/usb/audio.c
drivers/usb/hp_scanner.c [deleted file]
drivers/usb/hub.c
drivers/usb/inits.h
drivers/usb/keymap.c
drivers/usb/mouse.c
drivers/usb/printer.c
drivers/usb/scanner.c [new file with mode: 0644]
drivers/usb/uhci.c
drivers/usb/usb-core.c
drivers/usb/usb.c
drivers/usb/usb.h
fs/Config.in
fs/Makefile
fs/cramfs/Makefile [new file with mode: 0644]
fs/cramfs/cramfs.h [new file with mode: 0644]
fs/cramfs/inflate/Makefile [new file with mode: 0644]
fs/cramfs/inflate/adler32.c [new file with mode: 0644]
fs/cramfs/inflate/infblock.c [new file with mode: 0644]
fs/cramfs/inflate/infblock.h [new file with mode: 0644]
fs/cramfs/inflate/infcodes.c [new file with mode: 0644]
fs/cramfs/inflate/infcodes.h [new file with mode: 0644]
fs/cramfs/inflate/inffast.c [new file with mode: 0644]
fs/cramfs/inflate/inffast.h [new file with mode: 0644]
fs/cramfs/inflate/inffixed.h [new file with mode: 0644]
fs/cramfs/inflate/inflate.c [new file with mode: 0644]
fs/cramfs/inflate/inftrees.c [new file with mode: 0644]
fs/cramfs/inflate/inftrees.h [new file with mode: 0644]
fs/cramfs/inflate/infutil.c [new file with mode: 0644]
fs/cramfs/inflate/infutil.h [new file with mode: 0644]
fs/cramfs/inflate/uncompr.c [new file with mode: 0644]
fs/cramfs/inflate/zconf.h [new file with mode: 0644]
fs/cramfs/inflate/zlib.h [new file with mode: 0644]
fs/cramfs/inflate/zutil.h [new file with mode: 0644]
fs/cramfs/inode.c [new file with mode: 0644]
fs/cramfs/uncompress.c [new file with mode: 0644]
fs/ext2/super.c
fs/filesystems.c
include/asm-ppc/hw_irq.h [new file with mode: 0644]
include/asm-ppc/irq_control.h [deleted file]
include/asm-ppc/system.h
include/asm-ppc/unistd.h
scripts/cramfs/mkcramfs.c [new file with mode: 0644]

diff --git a/CREDITS b/CREDITS
index 70bbc827aa718a475b1f321b2c0f5e5bb4e96e70..15cc92ad9b45016d847dc6cb7a418d497849fccf 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -331,6 +331,10 @@ S: Bessemerstraat 21
 S: Amsterdam
 S: The Netherlands
 
+N: Zach Brown
+E: zab@zabbo.net
+D: maestro pci sound
+
 N: Ray Burr
 E: ryb@nightmare.com
 D: Original author of Amiga FFS filesystem
index 993d629ee4188f455a670d2b67acff65a1d5298b..76f0ead06d27f6319c64e1b8f9c3e5e0af6860af 100644 (file)
@@ -7912,11 +7912,11 @@ CONFIG_USB_MOUSE
   The module will be called mouse.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-USB HP scanner support
-CONFIG_USB_HP_SCANNER
-  Say Y here if you want to connect a USB HP scanner to your
-  computer's USB port. Please read drivers/usb/README.hp_scanner
-  for more information.
+USB scanner support
+CONFIG_USB_SCANNER
+  Say Y here if you want to connect a USB scanner to your
+  computer's USB port. Please read drivers/usb/README.scanner
+  and drivers/usb/README.scanner_hp_sane for more information.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -11179,6 +11179,12 @@ CONFIG_SOUND_NM256
 
   See Documentation/sound/NM256 for further information.
 
+ESS Maestro sound chipsets
+CONFIG_SOUND_MAESTRO
+  Say Y or M if you have a sound system driven by ESS's Maestro line
+  of PCI sound chips.  These include the Maestro 1, Maestro 2, and
+  Maestro 2E.  See Documentation/sound/Maestro for more details.
+
 Are you using a crosscompiler
 CONFIG_CROSSCOMPILE
   Say Y here if you are compiling the kernel on a different
diff --git a/Documentation/filesystems/cramfs.txt b/Documentation/filesystems/cramfs.txt
new file mode 100644 (file)
index 0000000..a408b88
--- /dev/null
@@ -0,0 +1,13 @@
+
+       Cramfs - cram a filesystem onto a small ROM
+
+cramfs is designed to be simple and small, and to compress things well. 
+
+It uses the zlib routines to compress a file one page at a time, and
+allows random page access.  The meta-data is not compressed, but is
+expressed in a very terse representation to make it use much less
+diskspace than traditional filesystems. 
+
+You can't write to a cramfs filesystem (making it compressible and
+compact also makes it _very_ hard to update on-the-fly), so you have to
+create the disk image with the "mkcramfs" utility in scripts/cramfs.
diff --git a/Documentation/sound/Maestro b/Documentation/sound/Maestro
new file mode 100644 (file)
index 0000000..f3cc4ab
--- /dev/null
@@ -0,0 +1,98 @@
+       An OSS/Lite Driver for the ESS Maestro family of sound cards
+
+                       Zach Brown, December 1999
+
+Driver Status and Availability
+------------------------------
+
+The most recent version of this driver will hopefully always be available at
+       http://people.redhat.com/zab/maestro/
+
+I will try and maintain the most recent stable version of the driver
+in both the stable and development kernel lines.
+
+ESS Maestro Chip Family
+-----------------------
+
+There are 3 main variants of the ESS Maestro PCI sound chip.  The first
+is the Maestro 1.  It was originally produced by Platform Tech as the
+'AGOGO'.  It can be recognized by Platform Tech's PCI ID 0x1285 with
+0x0100 as the device ID.  It was put on some sound boards and a few laptops.  
+ESS bought the design and cleaned it up as the Maestro 2.  This starts
+their marking with the ESS vendor ID 0x125D and the 'year' device IDs.
+The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978.
+
+The various families of Maestro are mostly identical as far as this 
+driver is concerned.  It doesn't touch the DSP parts that differ (though
+it could for FM synthesis)
+
+Driver OSS Behavior
+--------------------
+
+This OSS driver exports /dev/mixer and /dev/dsp to applications, which
+mostly adhere to the OSS spec.   This driver doesn't register itself
+with /dev/sndstat, so don't expect information to appear there.
+
+The /dev/dsp device exported behaves almost as expected.  Playback is
+supported in all the various lovely formats.  8/16bit stereo/mono from
+8khz to 48khz, and mmap()ing for playback behaves.  Capture/recording
+is limited due to oddities with the Maestro hardware.  One can only
+record in 16bit stereo.  For recording the maestro uses non interleaved
+stereo buffers so that mmap()ing the incoming data does not result in
+a ring buffer of LRLR data.  mmap()ing of the read buffers is therefore
+disallowed until this can be cleaned up.
+
+/dev/mixer is an interface to the AC'97 codec on the Maestro.  It is
+worth noting that there are a variety of AC'97s that can be wired to
+the Maestro.  Which is used is entirely up to the hardware implementor.
+This should only be visible to the user by the presence, or lack, of
+'Bass' and 'Treble' sliders in the mixer.  Not all AC'97s have them.
+
+The driver doesn't support MIDI or FM playback at the moment.  Typically
+the Maestro is wired to an MPU MIDI chip, but some hardware implementations
+don't.  We need to assemble a white list of hardware implementations that
+have MIDI wired properly before we can claim to support it safely.
+
+Compiling and Installing
+------------------------
+
+With the drivers inclusion into the kernel, compiling and installing
+is the same as most OSS/Lite modular sound drivers.  Compilation
+of the driver is enabled through the CONFIG_SOUND_MAESTRO variable
+in the config system.  
+
+It may be modular or statically linked.  If it is modular it should be
+installed with the rest of the modules for the kernel on the system.
+Typically this will be in /lib/modules/ somewhere.  'alias sound maestro'
+should also be added to your module configs (typically /etc/conf.modules)
+if you're using modular OSS/Lite sound and want to default to using a
+maestro chip.
+
+As this is a PCI device, the module does not need to be informed of
+any IO or IRQ resources it should use, it devines these from the
+system.  Somtimes, on sucky PCs, the BIOS fails to allocated resources
+for the maestro.  This will result in a message like:
+       maestro: PCI subsystem reports IRQ 0, this might not be correct.
+from the kernel.  Should this happen the sound chip most likely will
+not operate correctly.  To solve this one has to dig through their BIOS
+(typically entered by hitting a hot key at boot time) and figure out
+what magic needs to happen so that the BIOS will reward the maestro with
+an IRQ.  This operation is incredibly system specific, so you're on your
+own.  Sometimes the magic lies in 'PNP Capable Operating System' settings.
+
+There are very few options to the driver.  One is 'debug' which will 
+tell the driver to print minimal debugging information as it runs.  This
+can be collected with 'dmesg' or through the klogd daemon.
+
+The other, more interesting option, is 'dsps_order'.  Typically at
+install time the driver will only register one available /dev/dsp device
+for its use.  The 'dsps_order' module parameter allows for more devices
+to be allocated, as a power of two.  Up to 4 devices can be registered
+( dsps_order=2 ).  These devices act as fully distinct units and use
+separate channels in the maestro.
+
+.. more details ..
+-----------------
+
+drivers/sound/maestro.c contains comments that hopefully explain
+the maestro implementation.
index 42d30a0bb86375ce02fb8c45e631da31b0f2e51b..010550c720d2de4a3c52a118fb7e2bebeb303f8b 100644 (file)
@@ -529,6 +529,12 @@ W: http://www.linuxppc.org/
 L:     linuxppc-dev@lists.linuxppc.org
 S:     Maintained
 
+MAESTRO PCI SOUND DRIVER
+P:     Zach Brown
+M:     zab@redhat.com
+W:     http://people.redhat.com/zab/maestro/
+S:     Supported
+
 M68K
 P:     Jes Sorensen
 M:     Jes.Sorensen@cern.ch
index 0e283c5220ce1c4a6bc24c809a70f954fbd438b8..e2ef41653d40422e668f7a6d28beeb2d27ff1780 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -109,7 +109,6 @@ CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/
 #
 
 CORE_FILES     =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
-FILESYSTEMS    =fs/filesystems.a
 NETWORKS       =net/network.a
 DRIVERS                =drivers/block/block.a \
                 drivers/char/char.o \
@@ -256,7 +255,6 @@ vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
        $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
                --start-group \
                $(CORE_FILES) \
-               $(FILESYSTEMS) \
                $(NETWORKS) \
                $(DRIVERS) \
                $(LIBS) \
index c70efe4c6dfd1ea39120c244791a5d5684a20498..475c039b6cb5911442871797fdcb2a03a5fef695 100644 (file)
@@ -417,6 +417,7 @@ CONFIG_AUTOFS_FS=y
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
+# CONFIG_CRAMFS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
index 279d81438551d56cdecd358aff21943bd411554b..fa98b5fcf1f977cdf8fa0fefda1b3ba040e4a8ea 100644 (file)
@@ -85,12 +85,16 @@ comment 'General setup'
 
 if [ "$CONFIG_APUS" = "y" ]; then
   define_bool CONFIG_PCI n
-else if [ "$CONFIG_OAK" = "y" ]; then
+fi
+if [ "$CONFIG_OAK" = "y" ]; then
   define_bool CONFIG_PCI n
-else if [ "$CONFIG_8xx" = "y" ]; then
+fi
+if [ "$CONFIG_8xx" = "y" ]; then
     bool 'QSpan PCI' CONFIG_PCI
 else
+  if [ "$CONFIG_APUS" != "y" ]; then
     define_bool CONFIG_PCI y
+  fi
 fi
 
 bool 'Networking support' CONFIG_NET
index 938cea36dc5d291c047fc9f00a4e7e714af65da9..e76aa8dd97d61ab7e629a5bba4f95afc0f8476de 100644 (file)
@@ -249,7 +249,7 @@ chrp_setup_arch(void)
        else
 #endif
                ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
-       
+sprintf(cmd_line, "console=ttyS0,9600 console=tty0");
        printk("Boot arguments: %s\n", cmd_line);
        
        request_region(0x20,0x20,"pic1");
@@ -391,7 +391,7 @@ void chrp_post_irq(int irq)
         * openpic irq.  So we just check to make sure the controller
         * is an openpic and if it is then eoi
         *
-        * We do it this way since our irq_desc[irq].ctl can change
+        * We do it this way since our irq_desc[irq].handler can change
         * with RTL and no longer be open_pic -- Cort
         */
        if ( irq >= open_pic.irq_offset)
@@ -413,10 +413,10 @@ void __init chrp_init_IRQ(void)
        }
        open_pic.irq_offset = 16;
        for ( i = 16 ; i < NR_IRQS ; i++ )
-               irq_desc[i].ctl = &open_pic;
+               irq_desc[i].handler = &open_pic;
        openpic_init(1);
        for ( i = 0 ; i < 16  ; i++ )
-               irq_desc[i].ctl = &i8259_pic;
+               irq_desc[i].handler = &i8259_pic;
        i8259_init();
 #ifdef CONFIG_XMON
        request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
index f0b57a8b662221927f86a71250b2bc35fadddc22..fadddda8b671d4542c48515a14aeea1b711788b5 100644 (file)
@@ -332,7 +332,7 @@ void __init gemini_init_IRQ(void)
        /* gemini has no 8259 */
        open_pic.irq_offset = 0;
        for( i=0; i < NR_IRQS; i++ ) 
-               irq_desc[i].ctl = &open_pic;
+               irq_desc[i].handler = &open_pic;
        openpic_init(1);
 #ifdef __SMP__
        request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
@@ -512,7 +512,7 @@ void gemini_post_irq(int irq)
         * openpic irq.  So we just check to make sure the controller
         * is an openpic and if it is then eoi
         *
-        * We do it this way since our irq_desc[irq].ctl can change
+        * We do it this way since our irq_desc[irq].handler can change
         * with RTL and no longer be open_pic -- Cort
         */
        if ( irq >= open_pic.irq_offset)
index 4427e801f7d8d2db85214380ed8034238da79a9e..a09d6ad9830bf0d71a75364094d5094d0515008f 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/openpic.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/irq.h>
 
 #include <asm/bitops.h>
 #include <asm/hydra.h>
@@ -71,7 +72,7 @@ volatile unsigned char *chrp_int_ack_special;
 
 #define NR_MASK_WORDS  ((NR_IRQS + 31) / 32)
 
-struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
+irq_desc_t irq_desc[NR_IRQS];
 int ppc_spurious_interrupts = 0;
 unsigned int ppc_local_bh_count[NR_CPUS];
 unsigned int ppc_local_irq_count[NR_CPUS];
@@ -244,8 +245,8 @@ int get_irq_list(char *buf)
 #else          
                len += sprintf(buf+len, "%10u ", kstat_irqs(i));
 #endif /* __SMP__ */
-               if ( irq_desc[i].ctl )          
-                       len += sprintf(buf+len, " %s ", irq_desc[i].ctl->typename );
+               if ( irq_desc[i].handler )              
+                       len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
                else
                        len += sprintf(buf+len, "  None      ");
                len += sprintf(buf+len, "    %s",action->name);
index 8e9fe6df60983d07dcb09af1c5d0c631991f614d..60219201356c58f741414591de7e9a3cccca1cf5 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
-#include <asm/irq_control.h>
+#include <linux/irq.h>
 
 void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
 
index 4d510612bd1b2cfaeaa4506e473257cd0a196aad..36e886d0c451d755b6c96f4fe1c38f9a568636b6 100644 (file)
@@ -278,7 +278,7 @@ m8xx_init_IRQ(void)
 
         ppc8xx_pic.irq_offset = 0;
         for ( i = 0 ; i < NR_SIU_INTS ; i++ )
-                irq_desc[i].ctl = &ppc8xx_pic;
+                irq_desc[i].handler = &ppc8xx_pic;
        
        /* We could probably incorporate the CPM into the multilevel
         * interrupt structure.
@@ -288,7 +288,7 @@ m8xx_init_IRQ(void)
 
 #if defined(CONFIG_PCI)
         for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ )
-                irq_desc[i].ctl = &i8259_pic;
+                irq_desc[i].handler = &i8259_pic;
         i8259_pic.irq_offset = NR_SIU_INTS;
         i8259_init();
         request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
diff --git a/arch/ppc/kernel/mbx_pci.c b/arch/ppc/kernel/mbx_pci.c
deleted file mode 100644 (file)
index d7473e1..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * MBX pci routines.
- * The MBX uses the QSpan PCI bridge.  The config address register
- * is located 0x500 from the base of the bridge control/status registers.
- * The data register is located at 0x504.
- * This is a two step operation.  First, the address register is written,
- * then the data register is read/written as required.
- * I don't know what to do about interrupts (yet).
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/bios32.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/mbx.h>
-
-
-/*
- * This blows......The MBX uses the Tundra QSpan PCI bridge.  When
- * reading the configuration space, if something does not respond
- * the bus times out and we get a machine check interrupt.  So, the
- * good ol' exception tables come to mind to trap it and return some
- * value.
- *
- * On an error we just return a -1, since that is what the caller wants
- * returned if nothing is present.  I copied this from __get_user_asm,
- * with the only difference of returning -1 instead of EFAULT.
- * There is an associated hack in the machine check trap code.
- *
- * The QSPAN is also a big endian device, that is it makes the PCI
- * look big endian to us.  This presents a problem for the Linux PCI
- * functions, which assume little endian.  For example, we see the
- * first 32-bit word like this:
- *     ------------------------
- *     | Device ID | Vendor ID |
- *     ------------------------
- * If we read/write as a double word, that's OK.  But in our world,
- * when read as a word, device ID is at location 0, not location 2 as
- * the little endian PCI would believe.  We have to switch bits in
- * the PCI addresses given to us to get the data to/from the correct
- * byte lanes.
- *
- * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
- * It always forces the MS bit to zero.  Therefore, dev_fn values
- * greater than 128 are returned as "no device found" errors.
- *
- * The QSPAN can only perform long word (32-bit) configuration cycles.
- * The "offset" must have the two LS bits set to zero.  Read operations
- * require we read the entire word and then sort out what should be
- * returned.  Write operations other than long word require that we
- * read the long word, update the proper word or byte, then write the
- * entire long word back.
- *
- * PCI Bridge hack.  We assume (correctly) that bus 0 is the primary
- * PCI bus from the QSPAN.  If we are called with a bus number other
- * than zero, we create a Type 1 configuration access that a downstream
- * PCI bridge will interpret.
- */
-
-#define __get_mbx_pci_config(x, addr, op)              \
-       __asm__ __volatile__(                           \
-               "1:     "op" %0,0(%1)\n"                \
-               "       eieio\n"                        \
-               "2:\n"                                  \
-               ".section .fixup,\"ax\"\n"              \
-               "3:     li %0,-1\n"                     \
-               "       b 2b\n"                         \
-               ".section __ex_table,\"a\"\n"           \
-               "       .align 2\n"                     \
-               "       .long 1b,3b\n"                  \
-               ".text"                                 \
-               : "=r"(x) : "r"(addr))
-
-#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500))
-#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504))
-
-#define mk_config_addr(bus, dev, offset) \
-       (((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
-
-#define mk_config_type1(bus, dev, offset) \
-       mk_config_addr(bus, dev, offset) | 1;
-
-int mbx_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
-                                 unsigned char offset, unsigned char *val)
-{
-       uint    temp;
-       u_char  *cp;
-
-       if ((bus > 7) || (dev_fn > 127)) {
-               *val = 0xff;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       }
-
-       if (bus == 0)
-               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-       else
-               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-       __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz");
-
-       offset ^= 0x03;
-       cp = ((u_char *)&temp) + (offset & 0x03);
-       *val = *cp;
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
-                                 unsigned char offset, unsigned short *val)
-{
-       uint    temp;
-       ushort  *sp;
-
-       if ((bus > 7) || (dev_fn > 127)) {
-               *val = 0xffff;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       }
-
-       if (bus == 0)
-               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-       else
-               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-       __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz");
-       offset ^= 0x02;
-
-       sp = ((ushort *)&temp) + ((offset >> 1) & 1);
-       *val = *sp;
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
-                                  unsigned char offset, unsigned int *val)
-{
-       if ((bus > 7) || (dev_fn > 127)) {
-               *val = 0xffffffff;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       }
-       if (bus == 0)
-               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-       else
-               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-       __get_mbx_pci_config(*val, QS_CONFIG_DATA, "lwz");
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
-                                  unsigned char offset, unsigned char val)
-{
-       uint    temp;
-       u_char  *cp;
-
-       if ((bus > 7) || (dev_fn > 127))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
-
-       offset ^= 0x03;
-       cp = ((u_char *)&temp) + (offset & 0x03);
-       *cp = val;
-
-       if (bus == 0)
-               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-       else
-               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-       *QS_CONFIG_DATA = temp;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
-                                  unsigned char offset, unsigned short val)
-{
-       uint    temp;
-       ushort  *sp;
-
-       if ((bus > 7) || (dev_fn > 127))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
-
-       offset ^= 0x02;
-       sp = ((ushort *)&temp) + ((offset >> 1) & 1);
-       *sp = val;
-
-       if (bus == 0)
-               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-       else
-               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-       *QS_CONFIG_DATA = temp;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-                                   unsigned char offset, unsigned int val)
-{
-       if ((bus > 7) || (dev_fn > 127))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       if (bus == 0)
-               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-       else
-               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-       *(unsigned int *)QS_CONFIG_DATA = val;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
-                            unsigned short index, unsigned char *bus_ptr,
-                            unsigned char *dev_fn_ptr)
-{
-    int num, devfn;
-    unsigned int x, vendev;
-
-    if (vendor == 0xffff)
-       return PCIBIOS_BAD_VENDOR_ID;
-    vendev = (dev_id << 16) + vendor;
-    num = 0;
-    for (devfn = 0;  devfn < 32;  devfn++) {
-       mbx_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
-       if (x == vendev) {
-           if (index == num) {
-               *bus_ptr = 0;
-               *dev_fn_ptr = devfn<<3;
-               return PCIBIOS_SUCCESSFUL;
-           }
-           ++num;
-       }
-    }
-    return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int mbx_pcibios_find_class(unsigned int class_code, unsigned short index,
-                           unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
-{
-    int devnr, x, num;
-
-    num = 0;
-    for (devnr = 0;  devnr < 32;  devnr++) {
-       mbx_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
-       if ((x>>8) == class_code) {
-           if (index == num) {
-               *bus_ptr = 0;
-               *dev_fn_ptr = devnr<<3;
-               return PCIBIOS_SUCCESSFUL;
-           }
-           ++num;
-       }
-    }
-    return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-void __init
-mbx_pcibios_fixup(void)
-{
-   /* Nothing to do here? */
-}
-
-void __init
-mbx_setup_pci_ptrs(void)
-{
-       set_config_access_method(mbx);
-
-       ppc_md.pcibios_fixup = mbx_pcibios_fixup;
-}
-
diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c
deleted file mode 100644 (file)
index f648778..0000000
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * $Id: mbx_setup.c,v 1.12 1999/08/31 06:53:56 davem Exp $
- *
- *  linux/arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ide.h>
-#include <linux/ioport.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/mbx.h>
-#include <asm/machdep.h>
-
-#include "time.h"
-#include "local_irq.h"
-
-static int mbx_set_rtc_time(unsigned long time);
-unsigned long mbx_get_rtc_time(void);
-void mbx_calibrate_decr(void);
-
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
-                          char raw_mode);
-extern char mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void mackbd_init_hw(void);
-
-extern unsigned long loops_per_sec;
-
-unsigned long empty_zero_page[1024];
-
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;          /* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;          /* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start;     /* starting block # of image */
-#endif
-
-extern char saved_command_line[256];
-
-extern unsigned long find_available_memory(void);
-extern void m8xx_cpm_reset(uint);
-
-void __init adbdev_init(void)
-{
-}
-
-void __init
-mbx_setup_arch(void)
-{
-       int     cpm_page;
-       extern char cmd_line[];
-       
-       cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
-       
-       sprintf(cmd_line,
-"%s root=/dev/nfs nfsroot=/sys/mbxroot",
-               cmd_line);
-       printk("Boot arguments: %s\n", cmd_line);
-
-       /* Reset the Communication Processor Module.
-       */
-       m8xx_cpm_reset(cpm_page);
-
-#ifdef notdef
-       ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
-#endif
-       
-#ifdef CONFIG_BLK_DEV_INITRD
-#if 0
-       ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
-       rd_prompt = 1;
-       rd_doload = 1;
-       rd_image_start = 0;
-#endif
-#if 0  /* XXX this may need to be updated for the new bootmem stuff,
-          or possibly just deleted (see set_phys_avail() in init.c).
-          - paulus. */
-       /* initrd_start and size are setup by boot/head.S and kernel/head.S */
-       if ( initrd_start )
-       {
-               if (initrd_end > *memory_end_p)
-               {
-                       printk("initrd extends beyond end of memory "
-                              "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-                              initrd_end,*memory_end_p);
-                       initrd_start = 0;
-               }
-       }
-#endif
-#endif
-
-#ifdef notdef
-       request_region(0x20,0x20,"pic1");
-       request_region(0xa0,0x20,"pic2");
-       request_region(0x00,0x20,"dma1");
-       request_region(0x40,0x20,"timer");
-       request_region(0x80,0x10,"dma page reg");
-       request_region(0xc0,0x20,"dma2");
-#endif
-}
-
-void
-abort(void)
-{
-#ifdef CONFIG_XMON
-       extern void xmon(void *);
-       xmon(0);
-#endif
-       machine_restart(NULL);
-}
-
-/* The decrementer counts at the system (internal) clock frequency divided by
- * sixteen, or external oscillator divided by four.  Currently, we only
- * support the MBX, which is system clock divided by sixteen.
- */
-void __init mbx_calibrate_decr(void)
-{
-       bd_t    *binfo = (bd_t *)&res;
-       int freq, fp, divisor;
-
-       if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
-               printk("WARNING: Wrong decrementer source clock.\n");
-
-       /* The manual says the frequency is in Hz, but it is really
-        * as MHz.  The value 'fp' is the number of decrementer ticks
-        * per second.
-        */
-       fp = (binfo->bi_intfreq * 1000000) / 16;
-       freq = fp*60;   /* try to make freq/1e6 an integer */
-        divisor = 60;
-        printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
-        decrementer_count = freq / HZ / divisor;
-        count_period_num = divisor;
-        count_period_den = freq / 1000000;
-}
-
-/* A place holder for time base interrupts, if they are ever enabled.
-*/
-void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
-       printk("timebase_interrupt()\n");
-}
-
-/* The RTC on the MPC8xx is an internal register.
- * We want to protect this during power down, so we need to unlock,
- * modify, and re-lock.
- */
-static int
-mbx_set_rtc_time(unsigned long time)
-{
-       ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
-       ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
-       ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
-       return(0);
-}
-
-unsigned long __init mbx_get_rtc_time(void)
-{
-       /* First, unlock all of the registers we are going to modify.
-        * To protect them from corruption during power down, registers
-        * that are maintained by keep alive power are "locked".  To
-        * modify these registers we have to write the key value to
-        * the key location associated with the register.
-        */
-       ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
-       ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
-
-
-       /* Disable the RTC one second and alarm interrupts.
-       */
-       ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
-                                               ~(RTCSC_SIE | RTCSC_ALE);
-
-       /* Enabling the decrementer also enables the timebase interrupts
-        * (or from the other point of view, to get decrementer interrupts
-        * we have to enable the timebase).  The decrementer interrupt
-        * is wired into the vector table, nothing to do here for that.
-        */
-       ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
-                               ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
-                                        (TBSCR_TBF | TBSCR_TBE));
-       if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
-               panic("Could not allocate timer IRQ!");
-
-       /* Get time from the RTC.
-       */
-       return ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
-}
-
-void
-mbx_restart(char *cmd)
-{
-       extern void MBX_gorom(void);
-
-       MBX_gorom();
-}
-
-void
-mbx_power_off(void)
-{
-   mbx_restart(NULL);
-}
-
-void
-mbx_halt(void)
-{
-   mbx_restart(NULL)
-}
-
-
-int mbx_setup_residual(char *buffer)
-{
-        int     len = 0;
-       bd_t    *bp;
-       extern  RESIDUAL *res;
-                       
-       bp = (bd_t *)res;
-                       
-       len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
-                      "bus clock\t: %dMHz\n",
-                      bp->bi_intfreq /*/ 1000000*/,
-                      bp->bi_busfreq /*/ 1000000*/);
-
-       return len;
-}
-
-void
-mbx_do_IRQ(struct pt_regs *regs,
-          int            cpu,
-           int            isfake)
-{
-       int irq;
-        unsigned long bits = 0;
-
-        /* For MPC8xx, read the SIVEC register and shift the bits down
-         * to get the irq number.         */
-        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
-        irq = bits >> 26;
-        irq += ppc8xx_pic.irq_offset;
-        bits = 1UL << irq;
-
-       if (irq < 0) {
-               printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-                      irq, regs->nip);
-               spurious_interrupts++;
-       }
-       else {
-                ppc_irq_dispatch_handler( regs, irq );
-       }
-
-}
-
-static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-       int bits, irq;
-
-       /* A bug in the QSpan chip causes it to give us 0xff always
-        * when doing a character read.  So read 32 bits and shift.
-        * This doesn't seem to return useful values anyway, but
-        * read it to make sure things are acked.
-        * -- Cort
-        */
-       irq = (inl(0x508) >> 24)&0xff;
-       if ( irq != 0xff ) printk("iack %d\n", irq);
-       
-       outb(0x0C, 0x20);
-       irq = inb(0x20) & 7;
-       if (irq == 2)
-       {
-               outb(0x0C, 0xA0);
-               irq = inb(0xA0);
-               irq = (irq&7) + 8;
-       }
-       bits = 1UL << irq;
-       irq += i8259_pic.irq_offset;
-       ppc_irq_dispatch_handler( regs, irq );
-}
-
-
-/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug.  External
- * interrupts can be either edge or level triggered, but there is no
- * reason for us to change the EPPC-bug values (it would not work if we did).
- */
-void __init
-mbx_init_IRQ(void)
-{
-       int i;
-
-        ppc8xx_pic.irq_offset = 16;
-        for ( i = 16 ; i < 32 ; i++ )
-                irq_desc[i].ctl = &ppc8xx_pic;
-        unmask_irq(CPM_INTERRUPT);
-
-        for ( i = 0 ; i < 16 ; i++ )
-                irq_desc[i].ctl = &i8259_pic;
-        i8259_init();
-        request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
-        enable_irq(ISA_BRIDGE_INT);
-}
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-void
-mbx_ide_insw(ide_ioreg_t port, void *buf, int ns)
-{
-       ide_insw(port+_IO_BASE), buf, ns);
-}
-
-void
-mbx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
-{
-       ide_outsw(port+_IO_BASE, buf, ns);
-}
-
-int
-mbx_ide_default_irq(ide_ioreg_t base)
-{
-        return 14;
-}
-
-ide_ioreg_t
-mbx_ide_default_io_base(int index)
-{
-        return index;
-}
-
-int
-mbx_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-        return 0
-}
-
-void
-mbx_ide_request_region(ide_ioreg_t from,
-                       unsigned int extent,
-                       const char *name)
-{
-}
-
-void
-mbx_ide_release_region(ide_ioreg_t from,
-                       unsigned int extent)
-{
-}
-
-void
-mbx_ide_fix_driveid(struct hd_driveid *id)
-{
-        ppc_generic_ide_fix_driveid(id);
-}
-
-void
-mbx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-       ide_ioreg_t reg = data_port;
-       int i;
-
-       *irq = 0;
-
-       if (data_port != 0)     /* Only map the first ATA flash drive */
-               return;
-
-#ifdef ATA_FLASH
-
-       reg = (ide_ioreg_t) ioremap(PCMCIA_MEM_ADDR, 0x200);
-
-       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-               hw->io_ports[i] = reg;
-               reg += 1;
-       }
-
-       /* Does not matter */
-
-       if (ctrl_port) {
-               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-       } else {
-               hw->io_ports[IDE_CONTROL_OFFSET] = reg;
-       }
-       if (irq)
-               hw->irq = 13;
-#endif
-}
-#endif
-
-void __init
-mbx_init(unsigned long r3, unsigned long r4, unsigned long r5,
-        unsigned long r6, unsigned long r7)
-{
-
-       if ( r3 )
-               memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-       
-#ifdef CONFIG_PCI
-       mbx_setup_pci_ptrs();
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       /* take care of initrd if we have one */
-       if ( r4 )
-       {
-               initrd_start = r4 + KERNELBASE;
-               initrd_end = r5 + KERNELBASE;
-       }
-#endif /* CONFIG_BLK_DEV_INITRD */
-       /* take care of cmd line */
-       if ( r6 )
-       {
-               
-               *(char *)(r7+KERNELBASE) = 0;
-               strcpy(cmd_line, (char *)(r6+KERNELBASE));
-       }
-
-       ppc_md.setup_arch     = mbx_setup_arch;
-       ppc_md.setup_residual = mbx_setup_residual;
-       ppc_md.get_cpuinfo    = NULL;
-       ppc_md.irq_cannonicalize = NULL;
-       ppc_md.init_IRQ       = mbx_init_IRQ;
-       ppc_md.do_IRQ         = mbx_do_IRQ;
-       ppc_md.init           = NULL;
-
-       ppc_md.restart        = mbx_restart;
-       ppc_md.power_off      = mbx_power_off;
-       ppc_md.halt           = mbx_halt;
-
-       ppc_md.time_init      = NULL;
-       ppc_md.set_rtc_time   = mbx_set_rtc_time;
-       ppc_md.get_rtc_time   = mbx_get_rtc_time;
-       ppc_md.calibrate_decr = mbx_calibrate_decr;
-
-       ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-       ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-       ppc_md.kbd_translate     = pckbd_translate;
-       ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-       ppc_md.kbd_leds          = pckbd_leds;
-       ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-       ppc_md.kbd_sysrq_xlate   = pckbd_sysrq_xlate;
-#endif
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.insw = mbx_ide_insw;
-        ppc_ide_md.outsw = mbx_ide_outsw;
-        ppc_ide_md.default_irq = mbx_ide_default_irq;
-        ppc_ide_md.default_io_base = mbx_ide_default_io_base;
-        ppc_ide_md.ide_check_region = mbx_ide_check_region;
-        ppc_ide_md.ide_request_region = mbx_ide_request_region;
-        ppc_ide_md.ide_release_region = mbx_ide_release_region;
-        ppc_ide_md.fix_driveid = mbx_ide_fix_driveid;
-        ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports;
-
-        ppc_ide_md.io_base = _IO_BASE;
-#endif         
-}
index c278585d99601493e65c873421321b50a306922e..02e276729021ea37b9e2835d6cdc8e7ac89ae321 100644 (file)
@@ -416,13 +416,13 @@ void openpic_maptimer(u_int timer, u_int cpumask)
 void openpic_enable_irq(u_int irq)
 {
        check_arg_irq(irq);
-       openpic_clearfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK);
+       openpic_clearfield(&OpenPIC->Source[irq-irq_desc[irq].handler->irq_offset].Vector_Priority, OPENPIC_MASK);
 }
 
 void openpic_disable_irq(u_int irq)
 {
        check_arg_irq(irq);
-       openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK);
+       openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].handler->irq_offset].Vector_Priority, OPENPIC_MASK);
 }
 
 /*
index b44380e1c20f650103b9a2e311008675ea2814b4..385e233272ee3d849db3bacc9df01447e6fa5aec 100644 (file)
@@ -135,7 +135,7 @@ static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
         * don't.  Put this here to check for it.
         * -- Cort
         */
-       if ( irq_desc[irq].ctl != &gatwick_pic )
+       if ( irq_desc[irq].handler != &gatwick_pic )
                printk("gatwick irq not from gatwick pic\n");
        else
                ppc_irq_dispatch_handler( regs, irq );
@@ -361,7 +361,7 @@ pmac_pic_init(void)
                        max_irqs = 64;
        }
        for ( i = 0; i < max_real_irqs ; i++ )
-               irq_desc[i].ctl = &pmac_pic;
+               irq_desc[i].handler = &pmac_pic;
 
        /* get addresses of first controller */
        if (irqctrler) {
@@ -401,7 +401,7 @@ pmac_pic_init(void)
                if (device_is_compatible(irqctrler, "gatwick"))
                        pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
                for ( i = max_real_irqs ; i < max_irqs ; i++ )
-                       irq_desc[i].ctl = &gatwick_pic;
+                       irq_desc[i].handler = &gatwick_pic;
                request_irq( second_irq, gatwick_action, SA_INTERRUPT,
                             "gatwick cascade", 0 );
        }
index 5cf5295213008a9facdbadfbedba68c4b95e9c63..397685d431cb2da5a598a6e4aae28383fc261953 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/nvram.h>
 #include <linux/spinlock.h>
 #include <linux/console.h>
+#include <linux/irq.h>
 
 #include <asm/page.h>
 #include <asm/semaphore.h>
index e7f62c42947ef66b5dcb72b6a3886dedae409f68..19ae61450d7e16865761c9e2fa55ad40602de919 100644 (file)
@@ -617,12 +617,12 @@ prep_init_IRQ(void)
 
        if (OpenPIC != NULL) {
                for ( i = 16 ; i < 36 ; i++ )
-                       irq_desc[i].ctl = &open_pic;
+                       irq_desc[i].handler = &open_pic;
                openpic_init(1);
        }
        
         for ( i = 0 ; i < 16  ; i++ )
-                irq_desc[i].ctl = &i8259_pic;
+                irq_desc[i].handler = &i8259_pic;
         i8259_init();
 #ifdef __SMP__
        request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
index bcec975153c6ff10717157cf2b1409822f025a9a..4babbcfd3574697522343f1cbec13db0286e4fb5 100644 (file)
@@ -412,7 +412,7 @@ void __init pci_read_bridge_bases(struct pci_bus *child)
        }
 }
 
-static __init struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
 {
        struct pci_bus *child;
 
@@ -445,7 +445,7 @@ static __init struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci
  * A CardBus bridge is basically the same as a regular PCI bridge,
  * except we don't scan behind it because it will be changing.
  */
-static __init int pci_scan_cardbus(struct pci_bus *bus, struct pci_dev *dev, int busnr)
+static int __init pci_scan_cardbus(struct pci_bus *bus, struct pci_dev *dev, int busnr)
 {
        unsigned short cr;
        unsigned int buses;
@@ -500,7 +500,7 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus);
 /*
  * If it's a bridge, scan the bus behind it.
  */
-static __init int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max)
+static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max)
 {
        unsigned int buses;
        unsigned short cr;
@@ -566,7 +566,7 @@ static __init int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int
  * Read interrupt line and base address registers.
  * The architecture-dependent code can tweak these, of course.
  */
-static __init void pci_read_irq(struct pci_dev *dev)
+static void __init pci_read_irq(struct pci_dev *dev)
 {
        unsigned char irq;
 
index baeafc542622c5aca475945d99777fb98a639acd..6b3e025faedae5dd34d1c58644e031b7d7309af8 100644 (file)
        1948  Solo?
        1968  ES1968 Maestro 2
        1969  ES1969 Solo-1 Audiodrive
-       1978  ES1978 Maestro Audiodrive
+       1978  ES1978 Maestro 2E
        2808  ES336H Fax Modem (Later Model)
        2898  ES2898 Modem
 125e  Specialvideo Engineering SRL
        e886  IT8330G
 1284  Sahara Networks, Inc.
 1285  Platform Technologies, Inc.
-       0100  PT-201C-O-P AGOGO-XP sound chip
+       0100  AGOGO sound chip (aka ESS Maestro 1)
 1286  Mazet GmbH
 1287  M-Pact, Inc.
        001e  LS220D DVD Decoder
index a27827644c3008502b86462d45846267b2313f4e..7c0f54412c6d7021892e8b9a16d29d81eae16ca1 100644 (file)
@@ -340,10 +340,13 @@ void cb_free(socket_info_t *s)
     if (c) {
        struct pci_dev **p;
        /* Unlink from PCI device chain */
-       for (p = &pci_devices; *p; p = &((*p)->next)) {
+       p = &pci_devices;
+       while (*p) {
            struct pci_dev * dev = *p;
-           if (dev->bus != s->cap.cb_bus)
+           if (dev->bus != s->cap.cb_bus) {
+               p = &dev->next;
                continue;
+           }
            *p = dev->next;
 #ifdef CONFIG_PROC_FS
            pci_proc_detach_device(dev);
index a8826f5231ad414c823e37fdcb338c77b4e67dac..28f73d6b862de14b81c5b7ed38b0b1fbde0f8580 100644 (file)
@@ -304,6 +304,8 @@ printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start);
                exca_writeb(socket, I365_ADDRWIN, addr);
        }
 
+       exca_writeb(socket, CB_MEM_PAGE(map), start >> 24);
+
        word = (start >> 12) & 0x0fff;
        if (mem->flags & MAP_16BIT)
                word |= I365_MEM_16BIT;
@@ -327,8 +329,6 @@ printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start);
                word |= I365_MEM_REG;
        exca_writew(socket, I365_MEM(map) + I365_W_OFF, word);
 
-       exca_writeb(socket, CB_MEM_PAGE(map), start >> 24);
-
        if (mem->flags & MAP_ACTIVE)
                exca_writeb(socket, I365_ADDRWIN, addr | enable);
        return 0;
index 14d630a2192c194e5ea1024d81bba5311c699b81..4859685c63f5266d6474f0f13755d1fd3eb8e791 100644 (file)
@@ -20,9 +20,7 @@ fi
 dep_tristate '  Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
 dep_tristate '  Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
 dep_tristate '  ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    dep_tristate '  ESS Maestro, Maestro2, Maestro2E driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
-fi
+dep_tristate '  ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
 dep_tristate '  S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
 if [ "$CONFIG_VISWS" = "y" ]; then
     dep_tristate '  SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
index c44b31ef3ffbffe9d50e61904321cc248920fe7d..6a316d56e0291d6adcc20bac8f83c871f39bb092 100644 (file)
@@ -1,6 +1,6 @@
 /*****************************************************************************
  *
- *      ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.2.x
+ *      ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x
  *
  *      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
  *     proprietors of Hack Central for fine lodging.
  *
  *  Supported devices:
- *  /dev/dsp0-7    standard /dev/dsp device, (mostly) OSS compatible
+ *  /dev/dsp0-3    standard /dev/dsp device, (mostly) OSS compatible
  *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
  *
  *  Hardware Description
  *
  *     A working Maestro setup contains the Maestro chip wired to a 
- *     codec or 2.  In the Maestro we have the APUs, the ASP, and the
+ *     codec or 2.  In the Maestro we have the APUs, the ASSP, and the
  *     Wavecache.  The APUs can be though of as virtual audio routing
  *     channels.  They can take data from a number of sources and perform
  *     basic encodings of the data.  The wavecache is a storehouse for
  *     PCM data.  Typically it deals with PCI and interracts with the
- *     APUs.  The ASP is a wacky DSP like device that ESS is loth
+ *     APUs.  The ASSP is a wacky DSP like device that ESS is loth
  *     to release docs on.  Thankfully it isn't required on the Maestro
  *     until you start doing insane things like FM emulation and surround
  *     encoding.  The codecs are almost always AC-97 compliant codecs, 
  *     but it appears that early Maestros may have had PT101 (an ESS
  *     part?) wired to them.  The only real difference in the Maestro
  *     families is external goop like docking capability, memory for
- *     the ASP, and initialization differences.
+ *     the ASSP, and initialization differences.
  *
  *  Driver Operation
  *
  *     /dev/dsp? device.  2 channels for output, and 4 channels for
  *     input.
  *
- *     For output we maintain a ring buffer of data that we are DMAing
- *     to the card.  In mono operation this is nice and easy.  When
- *     we receive data we tack it onto the ring buffer and make sure
- *     the APU assigned to it is playing over the data.  When we fill
- *     the ring buffer we put the client to sleep until there is
- *     room again.  Easy.
+ *     Each APU can do a number of things, but we only really use
+ *     3 basic functions.  For playback we use them to convert PCM
+ *     data fetched over PCI by the wavecahche into analog data that
+ *     is handed to the codec.  One APU for mono, and a pair for stereo.
+ *     When in stereo, the combination of smarts in the APU and Wavecache
+ *     decide which wavecache gets the left or right channel.
  *
- *     However, this starts to stink when we use stereo.  The APUs
- *     supposedly can decode LRLR packed stereo data, but it
- *     doesn't work.  So we're forced to use dual mono APUs walking over
- *     mono encoded data.  This requires us to split the input from
- *     the client and complicates the buffer maths tremendously.  Ick.
- *
- *     This also pollutes the recording paths as well.  We have to use
- *     2 L/R incoming APUs that are fixed at 16bit/48khz.  We then pipe
- *     these through 2 rate converion apus that mix them down to the
- *     requested frequency and write them to memory through the wavecache.
- *     We also apparently need a 512byte region thats used as temp space 
- *     between the incoming APUs and the rate converters.
+ *     For record we still use the old overly mono system.  For each in
+ *     coming channel the data comes in from the codec, through a 'input'
+ *     APU, through another rate converter APU, and then into memory via
+ *     the wavecache and PCI.  If its stereo, we mash it back into LRLR in
+ *     software.  The pass between the 2 APUs is supposedly what requires us
+ *     to have a 512 byte buffer sitting around in wavecache/memory.
  *
  *     The wavecache makes our life even more fun.  First off, it can
  *     only address the first 28 bits of PCI address space, making it
  *     similar.
  *     
  * History
+ *  v0.13 - Nov 18 1999 - Zach Brown <zab@redhat.com>
+ *     fix nec Versas?  man would that be cool.
+ *  v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
+ *     brown bag volume max fix..
+ *  v0.11 - Nov 11 1999 - Zach Brown <zab@redhat.com>
+ *     use proper stereo apu decoding, mmap/write should work.
+ *     make volume sliders more useful, tweak rate calculation.
+ *     fix lame 8bit format reporting bug.  duh. apm apu saving buglet also
+ *     fix maestro 1 clock freq "bug", remove pt101 support
  *  v0.10 - Oct 28 1999 - Zach Brown <zab@redhat.com>
  *     aha, so, sometimes the WP writes a status word to offset 0
  *       from one of the PCMBARs.  rearrange allocation accordingly..
+ *       cheers again to Eric for being a good hacker in investigating this.
  *     Jeroen Hoogervorst submits 7500 fix out of nowhere.  yay.  :)
  *  v0.09 - Oct 23 1999 - Zach Brown <zab@redhat.com>
  *     added APM support.
  *
  * TODO
  *     some people get indir reg timeouts?
- *     anyone have a pt101 codec?
- *     mmap(), but beware stereo encoding nastiness.
- *     actually post pci writes
  *     fix bob frequency
+ *     endianness
  *     do smart things with ac97 2.0 bits.
- *     ugh.. non aligned writes in the middle of a data stream.. ugh
- *     sort out 0x34->0x36 crap in init
  *     docking and dual codecs and 978?
- *     pcm_sync?
- *     actually use LRLR
+ *     leave 54->61 open
+ *     resolve 2.3/2.2 stuff
  *
  *     it also would be fun to have a mode that would not use pci dma at all
  *     but would copy into the wavecache on board memory and use that 
  #define SILLY_INIT_SEM(SEM) SEM=MUTEX;
  #define init_waitqueue_head init_waitqueue
  #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC)
+ #define SILLY_OFFSET(VMA) ((VMA)->vm_offset)
 
 #else
 
  #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->resource[0].start)
  #define SILLY_INIT_SEM(SEM) init_MUTEX(&SEM)
  #define SILLY_MAKE_INIT(FUNC) __init FUNC
+ #define SILLY_OFFSET(VMA) ((VMA)->vm_pgoff)
 
 #endif
 
@@ -241,7 +243,7 @@ static int dsps_order=0;
 #endif
 
 /* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.10"
+#define DRIVER_VERSION "0.13"
 
 #ifndef PCI_VENDOR_ESS
 #define PCI_VENDOR_ESS                 0x125D
@@ -256,6 +258,10 @@ static int dsps_order=0;
 
 #define ESS_CHAN_HARD          0x100
 
+/* NEC Versas ? */
+#define NEC_VERSA_SUBID1       0x80581033
+#define NEC_VERSA_SUBID2       0x803c1033
+
 
 /* changed so that I could actually find all the
        references and fix them up.  its a little more readable now. */
@@ -271,8 +277,8 @@ static int dsps_order=0;
 #define DAC_RUNNING            1
 #define ADC_RUNNING            2
 
-#define MAX_DSP_ORDER  3
-#define MAX_DSPS       (1<<3)
+#define MAX_DSP_ORDER  2
+#define MAX_DSPS       (1<<MAX_DSP_ORDER)
 #define NR_DSPS                (1<<dsps_order)
 #define NR_IDRS                32
 
@@ -296,6 +302,11 @@ static const char *card_names[]={
        [TYPE_MAESTRO2E] = "ESS Maestro 2E"
 };
 
+static int clock_freq[]={
+       [TYPE_MAESTRO] = (49152000L / 1024L),
+       [TYPE_MAESTRO2] = (50000000L / 1024L),
+       [TYPE_MAESTRO2E] = (50000000L / 1024L)
+};
 
 /* --------------------------------------------------------------------- */
 
@@ -521,7 +532,7 @@ static u16 maestro_ac97_get(int io, u8 cmd)
        [SOUND_MIXER_BASS] =            0x3232,
        [SOUND_MIXER_TREBLE] =          0x3232,
        [SOUND_MIXER_SPEAKER] =         0x3232,
-       [SOUND_MIXER_MIC] =     0x3232,
+       [SOUND_MIXER_MIC] =     0x8000, /* annoying */
        [SOUND_MIXER_LINE] =    0x3232,
        [SOUND_MIXER_CD] =      0x3232,
        [SOUND_MIXER_VIDEO] =   0x3232,
@@ -599,6 +610,23 @@ static int ac97_read_mixer(struct ess_card *card, int mixer)
 /* write the OSS encoded volume to the given OSS encoded mixer,
        again caller's job to make sure all is well in arg land,
        call with spinlock held */
+       
+/* linear scale -> log */
+unsigned char lin2log[101] = 
+{
+0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
+50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
+63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 ,
+72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 ,
+78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 ,
+83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 ,
+87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 ,
+90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 ,
+93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 ,
+95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 ,
+97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99 
+};
+
 static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right)
 {
        u16 val=0;
@@ -614,12 +642,13 @@ static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left,
                        right = (right * mh->scale) / 100;
                        left = (left * mh->scale) / 100;
                        if ((left == 0) && (right == 0))
-                               val |= 0x8000; 
-               } else {
-                       right = ((100 - right) * mh->scale) / 100;
-                       left = ((100 - left) * mh->scale) / 100;
-                       if((left == mh->scale) && (right == mh->scale))
                                val |= 0x8000;
+               } else {
+                       /* log conversion for the stereo controls */
+                       if((left == 0) && (right == 0))
+                               val = 0x8000;
+                       right = ((100 - lin2log[right]) * mh->scale) / 100;
+                       left = ((100 - lin2log[left]) * mh->scale) / 100;
                }
 
                val |= (left << 8) | right;
@@ -772,6 +801,8 @@ static u16 maestro_ac97_init(struct ess_card *card, int iobase)
        return 0;
 }
 
+#if 0  /* there has been 1 person on the planet with a pt101 that we
+       know of.  If they care, they can put this back in :) */
 static u16 maestro_pt101_init(struct ess_card *card,int iobase)
 {
        printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
@@ -792,6 +823,7 @@ static u16 maestro_pt101_init(struct ess_card *card,int iobase)
        maestro_ac97_set(iobase, 0x0E, 0x801F);
        return 0;
 }
+#endif
 
 /* this is very magic, and very slow.. */
 static void 
@@ -799,6 +831,7 @@ maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev)
 {
        u16 save_68;
        u16 w;
+       u32 vend;
 
        outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
        outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
@@ -808,6 +841,7 @@ maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev)
        outw(0x0000,  ioaddr+0x36);
        save_68 = inw(ioaddr+0x68);
        pci_read_config_word(pcidev, 0x58, &w); /* something magical with gpio and bus arb. */
+       pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend);
        if( w & 0x1)
                save_68 |= 0x10;
        outw(0xfffe, ioaddr + 0x64);    /* tickly gpio 0.. */
@@ -861,6 +895,12 @@ maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev)
                }
        }
 #endif
+       if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {
+               /* turn on external amp? */
+               outw(0xf9ff, ioaddr + 0x64);
+               outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
+               outw(0x0209, ioaddr + 0x60);
+       }
 }
 /*
  *     Indirect register access. Not all registers are readable so we
@@ -1065,13 +1105,12 @@ static void sound_reset(int ioaddr)
 /* sets the play formats of these apus, should be passed the already shifted format */
 static void set_apu_fmt(struct ess_state *s, int apu, int mode)
 {
-       if(mode&ESS_FMT_16BIT) { 
-               s->apu_mode[apu] = 0x10;
-               s->apu_mode[apu+1] = 0x10;
-       } else {
-               s->apu_mode[apu] = 0x30;
-               s->apu_mode[apu+1] = 0x30;
-       }
+       int apu_fmt = 0x10;
+
+       if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20; 
+       if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10; 
+       s->apu_mode[apu]   = apu_fmt;
+       s->apu_mode[apu+1] = apu_fmt;
 }
 
 /* this only fixes the output apu mode to be later set by start_dac and
@@ -1082,18 +1121,21 @@ static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
        set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);
 }
 
-static u16 compute_rate(u32 freq)
+/* this is off by a little bit.. */
+static u32 compute_rate(struct ess_state *s, u32 freq)
 {
-       if(freq==48000)
-               return 0xFFFF;
-       freq<<=16;
-       freq/=48000;
-       return freq;
+       u32 clock = clock_freq[s->card->card_type];     
+
+       if (freq == 48000) return 0x10000;
+
+       return ((freq / clock) <<16 )+  
+               (((freq % clock) << 16) / clock);
 }
 
-static void set_dac_rate(struct ess_state *s, unsigned rate)
+static void set_dac_rate(struct ess_state *s, unsigned int rate)
 {
        u32 freq;
+       int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
 
        if (rate > 48000)
                rate = 48000;
@@ -1102,12 +1144,12 @@ static void set_dac_rate(struct ess_state *s, unsigned rate)
 
        s->ratedac = rate;
 
-       if(!((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT))
-               rate >>= 1; /* who knows */
+       if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))
+               rate >>= 1;
 
 /*     M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/
 
-       freq = compute_rate(rate);
+       freq = compute_rate(s, rate);
        
        /* Load the frequency, turn on 6dB */
        apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|
@@ -1122,14 +1164,15 @@ static void set_adc_rate(struct ess_state *s, unsigned rate)
 {
        u32 freq;
 
-       if (rate > 48000)
-               rate = 48000;
+       /* Sample Rate conversion APUs don't like 0x10000 for their rate */
+       if (rate > 47999)
+               rate = 47999;
        if (rate < 4000)
                rate = 4000;
 
        s->rateadc = rate;
 
-       freq = compute_rate(rate);
+       freq = compute_rate(s, rate);
        
        /* Load the frequency, turn on 6dB */
        apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|
@@ -1234,27 +1277,21 @@ ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size
        /* all maestro sizes are in 16bit words */
        size >>=1;
 
-       /* we're given the full size of the buffer, but
-       in stereo each channel will only play its half */
        if(mode&ESS_FMT_STEREO) {
-               size >>=1; 
                high_apu++;
+               /* only 16/stereo gets size divided */
+               if(mode&ESS_FMT_16BIT)
+                       size>>=1;
        }
        
        for(channel=0; channel <= high_apu; channel++)
        {
-               int i;
-               
-               if(!channel) 
-                       pa = virt_to_bus(buffer);
-               else
-               /* right channel plays its split half.
-                       *2 accomodates for rampant shifting earlier */
-                       pa = virt_to_bus(buffer + size*2);
+               pa = virt_to_bus(buffer);
 
                /* set the wavecache control reg */
                tmpval = (pa - 0x10) & 0xFFF8;
-               if(!(mode & 2)) tmpval |= 4; /* 8bit */ 
+               if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;
+               if(mode & ESS_FMT_STEREO) tmpval |= 2;
                ess->apu_base[channel]=tmpval;
                wave_set_register(ess, ess->apu[channel]<<3, tmpval);
                
@@ -1262,14 +1299,17 @@ ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size
                pa>>=1; /* words */
                
                /* base offset of dma calcs when reading the pointer
-                       on this left one */
+                       on the left one */
                if(!channel) ess->dma_dac.base = pa&0xFFFF;
                
                pa|=0x00400000;                 /* System RAM */
-               
-               /* Begin loading the APU */             
-               for(i=0;i<15;i++)               /* clear all PBRs */
-                       apu_set_register(ess, channel, i, 0x0000);
+
+               /* XXX the 16bit here might not be needed.. */
+               if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {
+                       if(channel) 
+                               pa|=0x00800000;                 /* Stereo */
+                       pa>>=1;
+               }
                        
 /* XXX think about endianess when writing these registers */
                M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
@@ -1290,16 +1330,17 @@ ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size
                /* dma on, no envelopes, filter to all 1s) */
                apu_set_register(ess, channel, 0, 0x400F);
                
-               if(mode&ESS_FMT_STEREO)
-                       /* set panning: left or right */
-                       apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
-               else
-                       apu_set_register(ess, channel, 10, 0x8F08);
-
                if(mode&ESS_FMT_16BIT)
                        ess->apu_mode[channel]=0x10;
                else
                        ess->apu_mode[channel]=0x30;
+
+               if(mode&ESS_FMT_STEREO) {
+                       /* set panning: left or right */
+                       apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
+                       ess->apu_mode[channel] += 0x10;
+               } else
+                       apu_set_register(ess, channel, 10, 0x8F08);
        }
        
        /* clear WP interupts */
@@ -1660,29 +1701,20 @@ static __inline__ void
 clear_advance(struct ess_state *s)
 {
        unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
+       
        unsigned char *buf = s->dma_dac.rawbuf;
        unsigned bsize = s->dma_dac.dmasize;
-       /* swptr is always in bytes as read from an apu.. */
        unsigned bptr = s->dma_dac.swptr;
        unsigned len = s->dma_dac.fragsize;
-       int i=1;
-
-       if((s->fmt >> ESS_DAC_SHIFT)  & ESS_FMT_STEREO) {
-               i++;
-               bsize >>=1;
-       }
-               
-       for ( ;i; i-- , buf += bsize) {
-
-               if (bptr + len > bsize) {
-                       unsigned x = bsize - bptr;
-                       memset(buf + bptr, c, x);
-                       /* account for wrapping? */
-                       bptr = 0;
-                       len -= x;
-               }
-               memset(buf + bptr, c, len);
+       
+       if (bptr + len > bsize) {
+               unsigned x = bsize - bptr;
+               memset(buf + bptr, c, x);
+               /* account for wrapping? */
+               bptr = 0;
+               len -= x;
        }
+       memset(buf + bptr, c, len);
 }
 
 /* call with spinlock held! */
@@ -1725,8 +1757,13 @@ ess_update_ptr(struct ess_state *s)
        }
        /* update DAC pointer */
        if (s->dma_dac.ready) {
-               /* this is so gross.  */
-               hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize; 
+               hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
+               /* the apu only reports the length it has seen, not the
+                       length of the memory that has been used (the WP
+                       knows that */
+               if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
+                       hwptr<<=1;
+
                diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
 /*             M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
                s->dma_dac.hwptr = hwptr;
@@ -2190,42 +2227,6 @@ rec_return_free:
        return ret;
 }
 
-/* god this is gross..*/
-/* again, the mode passed is shifted/masked */
-static int 
-split_stereo(unsigned char *real_buffer,unsigned char  *tmp_buffer, int offset, 
-       int count, int bufsize, int mode)
-{  
-       /* oh, bother.  stereo decoding APU's don't work in 16bit so we
-       use dual linear decoders.  which means we have to hack up stereo
-       buffer's we're given.  yuck.  */
-
-       unsigned char *so,*left,*right;
-       int i;
-
-       so = tmp_buffer;
-       left = real_buffer + offset;
-       right = real_buffer + bufsize/2 + offset;
-
-       if(mode & ESS_FMT_16BIT) {
-               for(i=count/4; i ; i--) {
-                       *(right++) = (*(so+2));
-                       *(right++) = (*(so+3));
-                       *(left++) = (*so);
-                       *(left++) = (*(so+1));
-                       so+=4;
-               }
-       } else {
-               for(i=count/2; i ; i--) {
-                       *(right++) = (*(so+1));
-                       *(left++) = (*so);
-                       so+=2;
-               }
-       }
-
-       return 0;
-}
-
 static ssize_t 
 ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
@@ -2233,9 +2234,7 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
        ssize_t ret;
        unsigned long flags;
        unsigned swptr;
-       unsigned char *splitbuf = NULL;
        int cnt;
-       int mode = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
        
        VALIDATE_STATE(s);
        if (ppos != &file->f_pos)
@@ -2246,9 +2245,6 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                return ret;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
-       /* XXX be more clever than this.. */
-       if (!(splitbuf = kmalloc(count,GFP_KERNEL)))
-               return -ENOMEM; 
        ret = 0;
 
        calc_bob_rate(s);
@@ -2262,12 +2258,8 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                }
                swptr = s->dma_dac.swptr;
 
-               if(mode & ESS_FMT_STEREO) {
-                       /* in stereo we have the 'dual' buffers.. */
-                       cnt = ((s->dma_dac.dmasize/2)-swptr)*2;
-               } else {
-                       cnt = s->dma_dac.dmasize-swptr;
-               }
+               cnt = s->dma_dac.dmasize-swptr;
+
                if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
                        cnt = s->dma_dac.dmasize - s->dma_dac.count;
 
@@ -2276,10 +2268,6 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                if (cnt > count)
                        cnt = count;
 
-               /* our goofball stereo splitter can only deal in mults of 4 */
-               if (cnt > 0) 
-                       cnt &= ~3;
-
                if (cnt <= 0) {
                        start_dac(s);
                        if (file->f_flags & O_NONBLOCK) {
@@ -2309,26 +2297,13 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                        }
                        continue;
                }
-               if(mode & ESS_FMT_STEREO) {
-                       if (copy_from_user(splitbuf, buffer, cnt)) {
-                               if (!ret) ret = -EFAULT;
-                               goto return_free;
-                       }
-                       split_stereo(s->dma_dac.rawbuf,splitbuf,swptr,cnt,s->dma_dac.dmasize,
-                               mode);
-               } else {
-                       if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
-                               if (!ret) ret = -EFAULT;
-                               goto return_free;
-                       }
+               if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+                       if (!ret) ret = -EFAULT;
+                       goto return_free;
                }
 
-               if(mode & ESS_FMT_STEREO) {
-                       /* again with the weird pointer magic */
-                       swptr = (swptr + (cnt/2)) % (s->dma_dac.dmasize/2);
-               } else {
-                       swptr = (swptr + cnt) % s->dma_dac.dmasize;
-               }
+               swptr = (swptr + cnt) % s->dma_dac.dmasize;
+
                spin_lock_irqsave(&s->lock, flags);
                s->dma_dac.swptr = swptr;
                s->dma_dac.count += cnt;
@@ -2340,7 +2315,6 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                start_dac(s);
        }
 return_free:
-       if (splitbuf) kfree(splitbuf);
        return ret;
 }
 
@@ -2374,8 +2348,6 @@ static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
        return mask;
 }
 
-/* this needs to be fixed to deal with the dual apus/buffers */
-#if 0
 static int ess_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct ess_state *s = (struct ess_state *)file->private_data;
@@ -2388,13 +2360,18 @@ static int ess_mmap(struct file *file, struct vm_area_struct *vma)
                if ((ret = prog_dmabuf(s, 1)) != 0)
                        return ret;
                db = &s->dma_dac;
-       } else if (vma->vm_flags & VM_READ) {
+       } else 
+#if 0
+       /* if we can have the wp/wc do the combining
+               we can turn this back on.  */
+             if (vma->vm_flags & VM_READ) {
                if ((ret = prog_dmabuf(s, 0)) != 0)
                        return ret;
                db = &s->dma_adc;
-       } else 
+       } else  
+#endif
                return -EINVAL;
-       if (vma->vm_pgofft != 0)
+       if (SILLY_OFFSET(vma) != 0)
                return -EINVAL;
        size = vma->vm_end - vma->vm_start;
        if (size > (PAGE_SIZE << db->buforder))
@@ -2404,7 +2381,6 @@ static int ess_mmap(struct file *file, struct vm_area_struct *vma)
        db->mapped = 1;
        return 0;
 }
-#endif
 
 static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -2434,7 +2410,7 @@ static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                return 0;
 
        case SNDCTL_DSP_GETCAPS:
-               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER /*| DSP_CAP_MMAP*/, (int *)arg);
+               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
                
         case SNDCTL_DSP_RESET:
                if (file->f_mode & FMODE_WRITE) {
@@ -2515,7 +2491,7 @@ static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                                           : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
                
        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+                return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg);
                
        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
                get_user_ret(val, (int *)arg, -EFAULT);
@@ -2548,7 +2524,7 @@ static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                        (ESS_FMT_16BIT << ESS_ADC_SHIFT) 
                        : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 
                                AFMT_S16_LE : 
-                               AFMT_S8, 
+                               AFMT_U8, 
                        (int *)arg);
                
        case SNDCTL_DSP_POST:
@@ -2938,7 +2914,7 @@ static struct file_operations ess_audio_fops = {
        NULL,  /* readdir */
        &ess_poll,
        &ess_ioctl,
-       NULL,   /* XXX &ess_mmap, */
+       &ess_mmap,
        &ess_open,
        NULL,   /* flush */
        &ess_release,
@@ -3000,7 +2976,7 @@ maestro_config(struct ess_card *card)
        w&=~(1<<7);             /* HWV off */
        w&=~(1<<6);             /* Debounce off */
        w&=~(1<<5);             /* GPIO 4:5 */
-       w|= (1<<4);             /* Disconnect from the CHI.  Enabling this in made a dell 7500 work. */
+       w|= (1<<4);             /* Disconnect from the CHI.  Enabling this made a dell 7500 work. */
        w&=~(1<<3);             /* IDMA off (undocumented) */
        w&=~(1<<2);             /* MIDI fix off (undoc) */
        w&=~(1<<1);             /* reserved, always write 0 */
@@ -3303,7 +3279,8 @@ maestro_install(struct pci_dev *pcidev, int card_type)
        maestro_config(card);
 
        if(maestro_ac97_get(iobase, 0x00)==0x0080) {
-               maestro_pt101_init(card,iobase);
+               printk(KERN_ERR "maestro: my goodness!  you seem to have a pt101 codec, which is quite rare.\n"
+                               "\tyou should tell someone about this.\n");
        } else {
                maestro_ac97_init(card,iobase);
        }
@@ -3451,7 +3428,7 @@ check_suspend(void)
 }
 
 static int 
-maestro_apm_suspend(void)
+maestro_suspend(void)
 {
        struct ess_card *card;
        unsigned long flags;
@@ -3474,7 +3451,7 @@ maestro_apm_suspend(void)
                        stop_dac(s);
                        stop_adc(s);
                        for(j=0;j<6;j++) 
-                               card->apu_map[s->apu[i]][5]=apu_get_register(s,i,5);
+                               card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5);
 
                }
 
@@ -3491,7 +3468,7 @@ maestro_apm_suspend(void)
        return 0;
 }
 static int 
-maestro_apm_resume(void)
+maestro_resume(void)
 {
        struct ess_card *card;
        unsigned long flags;
@@ -3565,11 +3542,11 @@ maestro_apm_callback(apm_event_t ae) {
        case APM_SYS_SUSPEND: 
        case APM_CRITICAL_SUSPEND: 
        case APM_USER_SUSPEND: 
-               maestro_apm_suspend();break;
+               maestro_suspend();break;
        case APM_NORMAL_RESUME: 
        case APM_CRITICAL_RESUME: 
        case APM_STANDBY_RESUME: 
-               maestro_apm_resume();break;
+               maestro_resume();break;
        default: break;
        }
 
index 64c0bb089022c1062b43a6deaad7d330b7cb55c7..3ae79866bab2b9fd46f2aacbd55557b824a6e86f 100644 (file)
@@ -22,7 +22,7 @@ comment 'USB Devices'
    dep_tristate '  USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
    dep_tristate '  USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
    dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
-   dep_tristate '  USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB
+   dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
    dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB
    dep_tristate '  USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
    dep_tristate '  USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
index 68fe3b07b25422dd6daf7d63cee14193ba4b11d0..03f3a56a655d47080a103689dea0c5b9d23c7394 100644 (file)
@@ -53,15 +53,13 @@ ifeq ($(CONFIG_USB_MOUSE),y)
 endif
 ifeq ($(CONFIG_USB_MOUSE),m)
   M_OBJS += mouse.o    
-  MI_OBJS += mouse.o
 endif
 
-ifeq ($(CONFIG_USB_HP_SCANNER),y)
-  L_OBJS += hp_scanner.o
+ifeq ($(CONFIG_USB_SCANNER),y)
+  L_OBJS += scanner.o
 endif
-ifeq ($(CONFIG_USB_HP_SCANNER),m)
-  M_OBJS  +=hp_scanner.o
-  MI_OBJS +=hp_scanner.o
+ifeq ($(CONFIG_USB_SCANNER),m)
+  M_OBJS  +=scanner.o
 endif
 
 ifeq ($(CONFIG_USB_ACM),y)
@@ -69,7 +67,6 @@ ifeq ($(CONFIG_USB_ACM),y)
 endif
 ifeq ($(CONFIG_USB_ACM),m)
   M_OBJS += acm.o
-  MI_OBJS += acm.o
 endif
 
 ifeq ($(CONFIG_USB_PRINTER),y)
@@ -78,7 +75,6 @@ endif
 
 ifeq ($(CONFIG_USB_PRINTER),m)
   M_OBJS += printer.o
-  MI_OBJS += printer.o  
 endif
 
 ifeq ($(CONFIG_USB_SERIAL),y)
@@ -87,7 +83,6 @@ endif
 
 ifeq ($(CONFIG_USB_SERIAL),m)
   M_OBJS += usb-serial.o
-  MI_OBJS += usb-serial.o  
 endif
 
 ifneq ($(CONFIG_ADB_KEYBOARD),y)
@@ -111,7 +106,6 @@ endif
 
 ifeq ($(CONFIG_USB_AUDIO),m)
   M_OBJS += audio.o
-  MI_OBJS += audio.o
 endif
 
 ifeq ($(CONFIG_USB_CPIA),y)
@@ -120,7 +114,6 @@ endif
 
 ifeq ($(CONFIG_USB_CPIA),m)
   M_OBJS += cpia.o
-  MI_OBJS += cpia.o
 endif
 
 ifeq ($(CONFIG_USB_DC2XX),y)
@@ -128,7 +121,6 @@ ifeq ($(CONFIG_USB_DC2XX),y)
 endif
 ifeq ($(CONFIG_USB_DC2XX),m)
   M_OBJS += dc2xx.o
-  MI_OBJS += dc2xx.o
 endif
 
 ifeq ($(CONFIG_USB_SCSI),y)
@@ -152,7 +144,6 @@ endif
 
 ifeq ($(CONFIG_USB_EZUSB),m)
   M_OBJS += ezusb.o
-  MI_OBJS += ezusb.o
 endif
 
 ifeq ($(CONFIG_USB_USS720),y)
@@ -161,7 +152,6 @@ endif
 
 ifeq ($(CONFIG_USB_USS720),m)
   M_OBJS += uss720.o
-  MI_OBJS += uss720.o
 endif
 
 ifeq ($(CONFIG_USB_DABUSB),y)
@@ -170,7 +160,6 @@ endif
 
 ifeq ($(CONFIG_USB_DABUSB),m)
   M_OBJS += dabusb.o
-  MI_OBJS += dabusb.o
 endif
 
 include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/README.hp_scanner b/drivers/usb/README.hp_scanner
deleted file mode 100644 (file)
index ce8c2e5..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-August 30, 1999
-
-
-Overview
-
-This README will address issues regarding how to configure the kernel
-to access a USB HP Scanner.  The scanner should support the Scanner
-Control Language (SCL) so that applications such as SANE can access it
-properly.  Refer to the document README.hp_scanner_sane for guidance
-on how to configure SANE to use the USB HP Scanner.
-
-
-Requirements
-
-A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
-(Compaq and others) hardware port should work.  However, I've only
-been able to really use an OHCI controller.  I did have access to a
-system with a UHCI controller but some very limited testing did not
-produce satisfactory results.
-
-A Linux kernel with USB support (preferably 2.3.15+).
-
-A Linux kernel with USB HP Scanner support.
-
-
-Configuration
-
-Add both USB controller support and USB HP Scanner support using `make
-menuconfig`.  If you decide to use the ohci-hcd driver, don't forget
-to add HUB support.  Compile and install the modules.  Testing was
-performed only as modules, YMMV.
-
-Add a device for the USB scanner: `mknod /dev/usbscanner c 16 1`
-
-Set appropriate permissions for /dev/usbscanner.  Both read and write
-permissions are needed for proper operation.
-
-Load the appropriate modules:
-
-  OHCI:
-
-    modprobe usb-ohci
-    modprobe hp_scanner
-
-  OHCI-HCD:
-    modprobe usb-ohci-hcd
-    modprobe hub
-    modprobe hp_scanner
-
-That's it.  SANE should now be able to access the device.  
-
-There is a small test program (hp_scan.c) that can be used to test the
-scanner device.  It's purpose is to test the driver(s) without having
-to retrieve/configure SANE.  Hp_scan.c will scan the entire bed and
-put the output into a file called out.dat in the current directory.
-The data in the file is raw data.
-
-David /\/elson
-dnelson@jump.net
diff --git a/drivers/usb/README.hp_scanner_sane b/drivers/usb/README.hp_scanner_sane
deleted file mode 100644 (file)
index 1cbc8b9..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-August 30, 1999
-
-NOTE: This is all VERY alpha.  Use at your own risk.  There is no
-warranty expressed nor implied.
-
-
-Introduction
-
-This document will hopefully provide enough info on how to get SANE
-working with a Hewlett Packard USB capable scanner using the USB
-interface.  The majority of HP Scanners support the Scanner Control
-Language (SCL) which is both published by HP and supported by SANE.
-The only HP Scanner that I'm aware of that does not support SCL is the
-4200C.  All other HP scanners with USB interfaces should work (4100C,
-5200C, 6200C).  Of course as HP releases new scanners this information
-may change.
-
-
-Requirements
-
-In order to get this running you'll need USB support in your kernel in
-addition to USB HP Scanner support.  Please refer to README.hp_scanner
-for issues pertaining to Linux USB and USB HP Scanner support.
-
-An installed version of SANE which is available from
-http://www.mostang.com/sane/.  Testing has been performed using
-version SANE-1.0.1.  For instructions on building and installing SANE,
-refer to the various README files within the distribution.
-
-
-Ok, so what do I do?
-
-NOTE: $INSTALL_DIR is the location where SANE was installed.  It may
-be /usr/local, /usr, /opt or somewhere else.  If you don't know, ask
-your system administrator.
-
-1) Make sure that you have the libsane-hp.* libraries under the
-$INSTALL_DIR/lib/sane/ directory.
-
-2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
-files: dll.conf, hp.conf.
-
-  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
-
-  hp.conf: This should contain two lines:
-
-    option connect-device
-    /dev/usbscanner
-
-3) You should now be able to use SANE (xscanimage or scanimage).
-
-Don't forget to read any relevant man pages regarding the usage of
-SANE.  If you have other entries uncommented in dll.conf, you my have
-to specify the device to (x)scanimage.  The xscanimage (1) man page
-has info on how to get 'The Gimp' to work with xscanimage.  Note that
-Gimp support must be compiled into SANE for it work.  If you are
-dealing with a RedHat system, you'll also need to install the
-gimp-devel rpm package.
-
-NOTE: Most of the time xscanimage will run without incident, then on
-the next invocation it'll core dump at different locations.  I don't
-know why yet and I don't have a work around either other than to try
-again.  But once you get it started, it'll scan without any problems
-(or at least it does for me).
-
-David /\/elson
-dnelson@jump.net
diff --git a/drivers/usb/README.scanner b/drivers/usb/README.scanner
new file mode 100644 (file)
index 0000000..4b5de2b
--- /dev/null
@@ -0,0 +1,231 @@
+Oct 19, 1999
+
+CHANGES
+
+- Ammended for linux-2.3.22+
+- Appended hp_scan.c to end of this README
+- Removed most references to HP
+
+
+OVERVIEW
+
+This README will address issues regarding how to configure the kernel
+to access a USB scanner.  Although the driver was originally conceived
+for USB HP scanners, it's general enough so that it can be used with
+other scanners.  Also, one can now pass the USB Vendor and
+Product ID's using module parameters for unknown scanners.  Refer to
+the document README.scanner_hp_sane for guidance on how to configure
+SANE to use a USB HP Scanner.
+
+
+ADDITIONAL INFORMATION
+
+http://www.linux-usb.org/
+http://www.dynamine.net/linux-usb/HOWTO/
+
+
+REQUIREMENTS
+
+A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
+(Compaq and others) hardware port should work.  However, I've only
+been able to really use an OHCI controller.  I did have access to a
+system with a UHCI controller but some very limited testing did not
+produce satisfactory results.  Luke Ordelmans
+<postbus@ordelmans.demon.nl> has reported success using the UHCI host
+controller with kernel 2.3.18 and a ChainTech motherboard.  Here
+lately I've been having better success with the ohci-hcd driver.  But
+since Linux USB support is still in a state of constant development
+that may change at a later date.  I am confident that eventually all
+the host contollers will perform without incident.
+
+A Linux kernel with USB support (preferably linux-2.3.18+)
+
+A Linux kernel with USB Scanner support.
+
+
+CONFIGURATION
+
+Using `make menuconfig` or your prefered method for configuring the
+kernel, select 'Support for USB', 'OHCI/OHCI-HCD/UHCI' depending on
+your hardware, 'USB hub support', and 'USB Scanner support'.  Compile
+and install the modules (you may need to execute `depmod -a` to update
+the module dependencies).  Testing was performed only as modules,
+YMMV.
+
+Add a device for the USB scanner:
+  linux-2.3.22 and above: `mknod /dev/usbscanner c 180 48`
+  linux-2.3.21 and below: `mknod /dev/usbscanner c 16 1`
+
+Set appropriate permissions for /dev/usbscanner (don't forget about
+group and world permissions).  Both read and write permissions are
+required for proper operation.
+
+Load the appropriate modules (if compiled as modules):
+
+  OHCI:
+    modprobe usb-ohci
+    modprobe scanner
+
+  OHCI-HCD:
+    modprobe usb-ohci-hcd
+    modprobe hub
+    modprobe scanner
+
+  UHCI:
+    modprobe usb-uhci
+    modprobe hub (don't know if this is required or not)
+    modprobe scanner
+
+That's it.  SANE should now be able to access the device.  
+
+There is a small test program (hp_scan.c -- appended below) that can
+be used to test the scanner device if it's an HP scanner that supports
+SCL.  Its purpose is to test the driver without having to
+retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
+the output into a file called 'out.dat' in the current directory.  The
+data in the file is raw data so it's not very useful for imaging.
+
+
+MODULE PARAMETERS
+
+If you have a device that wish to experiment with or try using this
+driver with, but the Vendor and Product ID's are not coded in, don't
+despair.  If the driver was compiled as a module, you can pass options
+to the driver.  Simply add 'options scanner vendor=0x####
+product=0x****' to the conf.modules/modules.conf file replacing the
+#'s and the *'s with the correct ID's.  The ID's can be retrieved from
+the messages file or using `cat /proc/bus/usb/devices` if USB /proc
+support was selected during kernel configuration.
+
+
+BUGS
+
+If you encounter any problems feel free to drop me an email.
+
+David /\/elson
+dnelson@jump.net
+http://www.jump.net/~dnelson
+
+--------------- snip -- hp_scan.c -- snip ---------------
+/*
+
+This is a really crude attempt at writing a short test program.  It's
+mostly only to be used to test connectivity with USB HP scanners that
+understand SCL.  Currently, the supported models are 4100C, 5200C,
+6200C, and the 6300C.  Note that the 4200C is *NOT* acceptable.
+
+Copyright (C) David E. Nelson <dnelson@jump.net>, 1999
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <error.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/*
+   Gray Output produces about a 8945400 byte file.
+   Color Output produces a 26836200 byte file. 
+   
+   To compile: gcc -o hp_scan hp_scan.c
+*/
+
+// #define COLOR /* Undef to scan GrayScale */
+
+int send_cmd(int, const char *, int);
+int read_cmd(int, char *, int);
+
+int
+main(void) {
+
+       ssize_t cnt = 0, total_cnt = 0;
+
+       FILE *fpout;
+
+       int fp;
+       int data_size = 32768;
+
+       char *data;
+
+       static char reset_cmd[] = {'\x1b','E'};
+
+#ifdef COLOR
+       static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
+       static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
+#else
+       static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
+       static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
+#endif
+
+       static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
+       static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
+       
+       if(!(data=malloc(data_size))) {
+               perror("malloc failed");
+               exit (1);
+       }
+       
+       if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
+               perror("Unable to open scanner device");
+               exit (1);
+       }
+
+       if((fpout=fopen("out.dat", "w+")) == NULL) {
+               perror("Unable to open ouput file");
+               exit(1);
+       }
+
+       send_cmd(fp, reset_cmd, sizeof(reset_cmd));
+       send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
+       send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
+       send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));
+
+       while ((cnt = read(fp, data, data_size)) > 0) {
+               printf("Read: %u\n", cnt); 
+               if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
+                       perror("Write to output file failed");
+                       exit (1);
+               }
+               total_cnt += cnt;
+       }
+       if (cnt < 0) {
+               perror("Read from scanner failed");
+               exit (1);
+       }
+
+       printf("\nRead %lu bytes.\n", total_cnt);
+
+       send_cmd(fp, reset_cmd, sizeof(reset_cmd));
+
+       close(fp);
+       fclose(fpout);
+       return (0);
+}
+
+int
+send_cmd(int fp, const char * cmd, int length) {
+
+       int result;
+       int x;
+
+       if((result = write(fp, cmd, length)) != length) {
+               printf ("Write warning: %d bytes requested, %d written\n");
+       } else if (result < 0) {
+               perror ("send_cmd failure");
+               exit (1);
+       }
+       return (result);
+}
+       
+int
+read_cmd(int fp, char * response, int length) {
+
+       return read(fp, response, length);
+
+}
diff --git a/drivers/usb/README.scanner_hp_sane b/drivers/usb/README.scanner_hp_sane
new file mode 100644 (file)
index 0000000..220bbb2
--- /dev/null
@@ -0,0 +1,69 @@
+Oct. 19, 1999
+
+CHANGES
+
+- Ammended for Linux-2.3.22+
+
+
+INTRODUCTION
+
+This document will hopefully provide enough info on how to get SANE
+working with a Hewlett Packard USB capable scanner using the USB
+interface.  The majority of HP Scanners support the Scanner Control
+Language (SCL) which is both published by HP and supported by SANE.
+The only HP Scanner that I'm aware of that does not support SCL is the
+4200C.  All other HP scanners with USB interfaces should work (4100C,
+5200C, 6200C, and 6300C).  Of course as HP releases new scanners this
+information may change.
+
+
+REQUIREMENTS
+
+In order to get this running you'll need USB support in your kernel in
+addition to USB Scanner support.  Please refer to README.scanner
+for issues pertaining to Linux USB and USB Scanner support.
+
+An installed version of SANE which is available from
+http://www.mostang.com/sane/.  Testing has been performed using
+version SANE-1.0.1.  For instructions on building and installing SANE,
+refer to the various README files within the SANE distribution.
+
+
+OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
+
+NOTE: $INSTALL_DIR is the location where SANE was installed.  It may
+be /usr/local, /usr, /opt or somewhere else.  If you don't know, ask
+your system administrator.
+
+1) Make sure that you have the libsane-hp.* libraries under the
+$INSTALL_DIR/lib/sane/ directory.  If you don't, then the HP backend
+was either not compiled or installed properly.
+
+2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
+files: dll.conf, hp.conf.
+
+  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
+
+  hp.conf: This should contain two lines:
+
+    /dev/usbscanner
+    option connect-device
+
+3) You should now be able to use SANE (xscanimage or scanimage).
+
+Don't forget to read any relevant man pages regarding the usage of
+SANE.  If you have other entries uncommented in dll.conf, you may have
+to specify the device to (x)scanimage.  Again, `man` is your friend.
+The xscanimage (1) man page has info on how to get 'The Gimp' to work
+with xscanimage.  Note that Gimp support must be compiled into SANE
+for it work.  If you are dealing with a RedHat system, this means that
+you'll also need to install the gimp-devel rpm package.
+
+NOTE: The issues regarding core dumping by (x)scanimage have (or seem
+to be thus far) been resolved with version 0.2+ of the USB scanner
+driver which should be available in linux-2.3.23.  If you notice
+otherwise, please contact me.
+
+David /\/elson
+dnelson@jump.net
+http://www.jump.net/~dnelson
index 1115ef0058043c89db37e6f47c1d0bc100c784cc..fb3f8e1e9bd5190af547e947a0f073a3dbfa308c 100644 (file)
@@ -1,55 +1,34 @@
 /*
- * USB Abstract Control Model based on Brad Keryan's USB busmouse driver
+ * acm.c  Version 0.10
  *
- * (C) Copyright 1999 Armin Fuerst <fuerst@in.tum.de>
- * (C) Copyright 1999 Pavel Machek <pavel@suse.cz>
- * (C) Copyright 1999 Johannes Erdfelt <jerdfelt@valinux.com>
+ * 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 Vojtech Pavlik   <vojtech@suse.cz>
  *
- * version 0.9: Johanness Erdfelt converted this to urb interface.
+ * USB Abstract Control Model driver for USB modems and ISDN adapters
  *
- * version 0.8: Fixed endianity bug, some cleanups. I really hate to have
- * half of driver in form if (...) { info("x"); return y; }
- *                                             Pavel Machek <pavel@suse.cz>
+ * Sponsored by SuSE
  *
- * version 0.7: Added usb flow control. Fixed bug in uhci.c (what idiot
- * wrote this code? ...Oops that was me). Fixed module cleanup. Did some
- * testing at 3Com => zmodem uload+download works, pppd had trouble but
- * seems to work now. Changed Menuconfig texts "Communications Device
- * Class (ACM)" might be a bit more intuitive. Ported to 2.3.13-1 prepatch.
- * (2/8/99)
- *
- * version 0.6: Modularized driver, added disconnect code, improved
- * assignment of device to tty minor number.
- * (21/7/99)
- *
- * version 0.5: Driver now generates a tty instead of a simple character
- * device. Moved async bulk transfer to 2.3.10 kernel version. fixed a bug
- * in uhci_td_allocate. Commenetd out getstringtable which causes crash.
- * (13/7/99)
- *
- * version 0.4: Small fixes in the FIFO, cleanup. Updated Bulk transfer in
- * uhci.c. Should have the correct interface now.
- * (6/6/99)
- *
- * version 0.3: Major changes. Changed Bulk transfer to interrupt based
- * transfer. Using FIFO Buffers now. Consistent handling of open/close
- * file state and detected/nondetected device. File operations behave
- * according to this. Driver is able to send+receive now! Heureka!
- * (27/5/99)
- *
- * version 0.2: Improved Bulk transfer. TX led now flashes every time data is
- * sent. Send Encapsulated Data is not needed, nor does it do anything.
- * Why's that ?!? Thanks to Thomas Sailer for his close look at the bulk code.
- * He told me about some importand bugs. (5/21/99)
+ * ChangeLog:
+ *     v0.9  Vojtech Pavlik - thorough cleaning, URBification, almost a rewrite
+ *      v0.10 Vojtech Pavlik - some more cleanups
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * version 0.1: Bulk transfer for uhci seems to work now, no dangling tds any
- * more. TX led of the ISDN TA flashed the first time. Does this mean it works?
- * The interrupt of the ctrl endpoint crashes the kernel => no read possible
- * (5/19/99)
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * version 0.0: Driver sets up configuration, sets up data pipes, opens misc
- * device. No actual data transfer is done, since we don't have bulk transfer,
- * yet. Purely skeleton for now. (5/8/99)
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #include <linux/kernel.h>
 #include <linux/tty_flip.h>
 #include <linux/tty.h>
 #include <linux/module.h>
+#include <linux/config.h>
 
 #include "usb.h"
 
-#define NR_PORTS 3
-#define ACM_MAJOR 166  /* Wow, major is now officially allocated */
+#ifdef CONFIG_USB_ACM_DEBUG
+#define acm_debug(fmt,arg...)  printk(KERN_DEBUG "acm: " fmt "\n" , ##arg)
+#else
+#define acm_debug(fmt,arg...)  do {} while(0)
+#endif
 
-//#define info(message...) printk(KERN_DEBUG message)
-#define info(message...)
+/*
+ * Major and minor numbers.
+ */
 
-#define CTRL_STAT_DTR  1
-#define CTRL_STAT_RTS  2
+#define ACM_TTY_MAJOR          166
+#define ACM_TTY_MINORS         8
 
-static struct usb_driver acm_driver;
+/*
+ * Output control lines.
+ */
 
-static int acm_refcount;
-
-static struct tty_driver acm_tty_driver;
-static struct tty_struct *acm_tty[NR_PORTS];
-static struct termios *acm_termios[NR_PORTS];
-static struct termios *acm_termios_locked[NR_PORTS];
-static struct acm_state acm_state_table[NR_PORTS];
-
-struct acm_state {
-       struct usb_device *dev;                         //the coresponding usb device
-       int cfgnum;                                     //configuration number on this device
-       struct tty_struct *tty;                         //the coresponding tty
-       char present;                                   //a device for this struct was detected => this tty is used
-       char active;                                    //someone has this acm's device open
-       unsigned int ctrlstate;                         //Status of the serial control lines  (handshake,...)
-       unsigned int linecoding;                        //Status of the line coding (Bits, Stop, Parity)
-       int writesize, readsize, ctrlsize;              //size of the usb buffers
-       char *writebuffer, *readbuffer, *ctrlbuffer;    //the usb buffers
-       char writing, reading;                          //flag if transfer is running
-       unsigned int readendp,writeendp,ctrlendp;       //endpoints and
-       unsigned int readpipe,writepipe,ctrlpipe;       //pipes (are one of these obsolete?)
-       urb_t *readurb, *writeurb, *ctrlurb;
-       unsigned ctrlinterval;                          //interval to poll from device
-};
+#define ACM_CTRL_DTR           0x01
+#define ACM_CTRL_RTS           0x02
 
-#define ACM_READY (acm->present && acm->active)
+/*
+ * Input control lines and line errors.
+ */
 
-//functions for various ACM requests
+#define ACM_CTRL_DCD           0x01
+#define ACM_CTRL_DSR           0x02
+#define ACM_CTRL_BRK           0x04
+#define ACM_CTRL_RI            0x08
 
-void Set_Control_Line_Status(unsigned int status, struct acm_state *acm)
-{
-       struct usb_device *dev = acm->dev;
-       int ret;
+#define ACM_CTRL_FRAMING       0x10
+#define ACM_CTRL_PARITY                0x20
+#define ACM_CTRL_OVERRUN       0x40
 
-       info("Set_control_Line_Status\n");
+/*
+ * Line speed and caracter encoding.
+ */
 
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x22, 0x22,
-               status, 0, NULL, 0, HZ);
-       if (ret < 0)
-               printk(KERN_ERR "acm: Set_Control_Line_Status failed\n");
+struct acm_coding {
+       __u32 speed;
+       __u8 stopbits;
+       __u8 parity;
+       __u8 databits;
+} __attribute__ ((packed));
 
-       acm->ctrlstate = status;
-}
+/*
+ * Internal driver structures.
+ */
 
-void Set_Line_Coding(unsigned int coding, struct acm_state *acm)
-{
-       struct usb_device *dev = acm->dev;
-       int ret;
+struct acm {
+       struct usb_device *dev;                         /* the coresponding usb device */
+       struct usb_config_descriptor *cfg;              /* configuration number on this device */
+       struct tty_struct *tty;                         /* the coresponding tty */
+       unsigned int ctrlin;                            /* input control lines (DCD, DSR, RI, break, overruns) */
+       unsigned int ctrlout;                           /* output control lines (DTR, RTS) */
+       struct acm_coding linecoding;                   /* line coding (bits, stop, parity) */
+       unsigned int writesize;                         /* max packet size for the output bulk endpoint */
+       struct urb ctrlurb, readurb, writeurb;          /* urbs */
+       unsigned char present;                          /* this device is connected to the usb bus */
+       unsigned char used;                             /* someone has this acm's device open */
+};
 
-       info("Set_Line_Coding\n");
+static struct usb_driver acm_driver;
+static struct acm acm_table[ACM_TTY_MINORS];
 
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x30, 0x22,
-               coding, 0, NULL, 0, HZ);
+#define ACM_READY(acm) (acm->present && acm->used)
 
-       acm->linecoding = coding;
+/*
+ * Functions for ACM control messages.
+ */
+
+static void acm_set_control(unsigned int status, struct acm *acm)
+{
+       if (usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), 0x22, 0x22, status, 0, NULL, 0, HZ) < 0)
+               acm_debug("acm_set_control() failed");
+
+       acm_debug("output control lines: dtr%c rts%c",
+               acm->ctrlout & ACM_CTRL_DTR ? '+' : '-', acm->ctrlout & ACM_CTRL_RTS ? '+' : '-');
 }
 
-//Interrupt handler for various usb events
-static void acm_irq(urb_t *urb)
+#if 0
+static void acm_set_coding(struct acm_coding *coding, struct acm *acm)
 {
-       struct acm_state *acm = (struct acm_state *)urb->context;
-       unsigned char *data = urb->transfer_buffer;
-        devrequest *dr;
+       if (usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), 0x30, 0x22, 0, 0, coding, sizeof(struct acm_coding), HZ) < 0)
+               acm_debug("acm_set_coding() failed");
+}
+
+static void acm_send_break(int ms, struct acm *acm)
+{
+       if (usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), 0x30, 0x33, ms, 0, NULL, 0, HZ) < 0)
+               acm_debug("acm_send_break() failed");
+}
+#endif
 
-       info("ACM_USB_IRQ\n");
+/*
+ * Interrupt handler for various ACM control events
+ */
+
+static void acm_ctrl_irq(struct urb *urb)
+{
+       struct acm *acm = urb->context;
+       devrequest *dr = urb->transfer_buffer;
+       unsigned char *data = (unsigned char *)(dr + 1);
 
        if (urb->status < 0) {
-               printk(KERN_DEBUG "acm_irq: strange status received: %d\n", urb->status);
+               acm_debug("nonzero ctrl irq status received: %d", urb->status);
                return;
        }
 
-       if (!acm->present)
-               return;
-       if (!acm->active)
-               return;
+       if (!ACM_READY(acm)) return;
 
-        dr = (devrequest *)data;
-       data += sizeof(dr);
-#if 0
-        printk("reqtype: %02X\n",dr->requesttype);
-        printk("request: %02X\n",dr->request);
-       printk("wValue: %02X\n",dr->value);
-       printk("wIndex: %02X\n",dr->index);
-       printk("wLength: %02X\n",dr->length);
-#endif
+       switch (dr->request) {
 
-       switch(dr->request) {
-       case 0x00: /* Network connection */
-               printk(KERN_DEBUG "Network connection: ");
-               if (dr->request==0) printk(KERN_DEBUG "disconnected\n");
-               if (dr->request==1) printk(KERN_DEBUG "connected\n");
-               break;
-
-       case 0x01: /* Response available */
-               printk(KERN_DEBUG "Response available\n");
-               break;
-
-       case 0x20: /* Set serial line state */
-               printk(KERN_DEBUG "acm.c: Set serial control line state\n");
-               if ((dr->index==1) && (dr->length==2)) {
-                       acm->ctrlstate = data[0] || (data[1] << 16);
-                       printk(KERN_DEBUG "Serstate: %02X\n", acm->ctrlstate);
-               }
-               break;
+               case 0x20: /* Set serial line state */
+
+                       if ((dr->index != 1) || (dr->length != 2)) {
+                               acm_debug("unknown set serial line request: index %d len %d", dr->index, dr->length);
+                               return;
+                       }
+
+                       acm->ctrlin = data[0] | (((unsigned int) data[1]) << 8);
+
+                       acm_debug("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
+                               acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
+                               acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI  ? '+' : '-',
+                               acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',     acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
+                               acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
+
+                       return;
+
+               default:
+                       acm_debug("unknown control event received: request %d index %d len %d data0 %d data1 %d",
+                               dr->request, dr->index, dr->length, data[0], data[1]);
+                       return;
        }
 
        return;
 }
 
-static void acm_read_irq(urb_t *urb)
+static void acm_read_bulk(struct urb *urb)
 {
-       struct acm_state *acm = (struct acm_state *)urb->context; 
-               struct tty_struct *tty = acm->tty; 
-               unsigned char *data = acm->readbuffer;
+       struct acm *acm = urb->context;
+       struct tty_struct *tty = acm->tty;
+       unsigned char *data = urb->transfer_buffer;
        int i;
 
-       info("ACM_READ_IRQ: state %d, %d bytes\n", urb->status, urb->actual_length);
        if (urb->status) {
-               printk("acm_read_irq: strange state received: %d\n", urb->status);
+               acm_debug("nonzero read bulk status received: %d", urb->status);
                return;
        }
-       
-       if (!ACM_READY)
-               return;
 
-       for (i=0;i<urb->actual_length;i++)
-               tty_insert_flip_char(tty,data[i],0);
-       tty_flip_buffer_push(tty);
+       if (!ACM_READY(acm)) return;
 
-       usb_submit_urb(urb);
+       for (i = 0; i < urb->actual_length; i++)
+               tty_insert_flip_char(tty, data[i], 0);
+
+       tty_flip_buffer_push(tty);
+
+       if (usb_submit_urb(urb))
+               acm_debug("failed resubmitting read urb");
 
        return;
 }
 
-static void acm_write_irq(urb_t *urb)
+static void acm_write_bulk(struct urb *urb)
 {
-       struct acm_state *acm = (struct acm_state *)urb->context;
-               struct tty_struct *tty = acm->tty;
-
-       info("ACM_WRITE_IRQ\n");
+       struct acm *acm = (struct acm *)urb->context;
+       struct tty_struct *tty = acm->tty;
 
-       if (!ACM_READY)
+       if (urb->status) {
+               acm_debug("nonzero write bulk status received: %d", urb->status);
                return;
+       }
+
+       if (!ACM_READY(acm)) return;
 
-       acm->writing = 0;
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
                (tty->ldisc.write_wakeup)(tty);
+
        wake_up_interruptible(&tty->write_wait);
 
        return;
 }
 
-/*TTY STUFF*/
-static int rs_open(struct tty_struct *tty, struct file *filp)
-{
-       struct acm_state *acm;
-       int ret;
+/*
+ * TTY handlers
+ */
 
-       info("USB_FILE_OPEN\n");
+static int acm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+       struct acm *acm = &acm_table[MINOR(tty->device)];
 
-       tty->driver_data = acm =
-               &acm_state_table[MINOR(tty->device) - tty->driver.minor_start];
+       tty->driver_data = acm;
        acm->tty = tty;
-        
-       if (!acm->present)
-               return -EINVAL;
 
-       if (acm->active++)
+       if (!acm->present) return -EINVAL;
+
+       if (acm->used++) {
+               MOD_INC_USE_COUNT;
                return 0;
+       }
+
        MOD_INC_USE_COUNT;
 
-       /* Start reading from the device */
-       FILL_INT_URB(acm->ctrlurb, acm->dev, acm->ctrlpipe,
-               acm->ctrlbuffer, acm->ctrlsize,
-               acm_irq, acm, acm->ctrlinterval);
-       ret = usb_submit_urb(acm->ctrlurb);
-       if (ret)
-               printk(KERN_ERR "acm: usb_submit_urb(INT) failed (%d)\n", ret);
-       acm->reading = 1;
-
-       FILL_BULK_URB(acm->readurb, acm->dev, acm->readpipe, acm->readbuffer,
-               acm->readsize, acm_read_irq, acm);
-       ret = usb_submit_urb(acm->readurb);
-               
-       if (ret)
-               printk(KERN_ERR "acm: usb_submit_urb(READ) failed (%d)\n", ret);
-       acm->reading = 1;
-
-       Set_Control_Line_Status(CTRL_STAT_DTR | CTRL_STAT_RTS, acm);
+       if (usb_submit_urb(&acm->ctrlurb))
+               acm_debug("usb_submit_urb(ctrl irq) failed");
+
+       if (usb_submit_urb(&acm->readurb))
+               acm_debug("usb_submit_urb(read bulk) failed");
+
+       acm_set_control(acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS, acm);
 
        return 0;
 }
 
-static void rs_close(struct tty_struct *tty, struct file *filp)
+static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 {
-       struct acm_state *acm = (struct acm_state *)tty->driver_data;
+       struct acm *acm = tty->driver_data;
 
-       info("rs_close\n");
+       if (!ACM_READY(acm)) return;
 
-       if (!acm->present)
+       if (--acm->used) {
+               MOD_DEC_USE_COUNT;
                return;
-
-       if (--acm->active)
-               goto early;
-
-       Set_Control_Line_Status(0, acm);
-
-       if (acm->writing) {
-               if (acm->writeurb)
-                       usb_unlink_urb(acm->writeurb);
-               acm->writing = 0;
-       }
-       if (acm->reading) {
-               if (acm->readurb)
-                       usb_unlink_urb(acm->readurb);
-               acm->reading = 0;
        }
 
-early:
+       acm_set_control(acm->ctrlout = 0, acm);
+       usb_unlink_urb(&acm->writeurb);
+       usb_unlink_urb(&acm->readurb);
+
        MOD_DEC_USE_COUNT;
 }
 
-static int rs_write(struct tty_struct *tty, int from_user,
-                   const unsigned char *buf, int count)
+static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
 {
-       struct acm_state *acm = (struct acm_state *)tty->driver_data;
-       int written, ret;
+       struct acm *acm = tty->driver_data;
 
-       info("rs_write\n");
+       if (!ACM_READY(acm)) return -EINVAL;
+       if (acm->writeurb.status == -EINPROGRESS) return 0;
 
-       if (!ACM_READY)
-               return -EINVAL;
-
-       if (acm->writing) {
-               info("already writing\n");
-               return 0;
-       }
-
-       written = (count>acm->writesize) ? acm->writesize : count;
+       count = (count > acm->writesize) ? acm->writesize : count;
 
        if (from_user)
-               copy_from_user(acm->writebuffer, buf, written);
+               copy_from_user(acm->writeurb.transfer_buffer, buf, count);
        else
-               memcpy(acm->writebuffer, buf, written);
-
-       //start the transfer
-       acm->writing = 1;
+               memcpy(acm->writeurb.transfer_buffer, buf, count);
 
-       FILL_BULK_URB(acm->writeurb, acm->dev, acm->writepipe, acm->writebuffer,
-               written, acm_write_irq, acm);
-       ret = usb_submit_urb(acm->writeurb);
-       if (ret)
-               printk("acm: usb_submit_urb(WRITE) failed: %d\n", ret);
+       acm->writeurb.transfer_buffer_length = count;
 
-       return written;
-} 
+       if (usb_submit_urb(&acm->writeurb))
+               acm_debug("usb_submit_urb(write bulk) failed");
 
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       printk(KERN_DEBUG "acm: rs_put_char: Who called this unsupported routine?\n");
-       BUG();
+       return count;
 }
 
-static int rs_write_room(struct tty_struct *tty)
+static int acm_tty_write_room(struct tty_struct *tty)
 {
-       struct acm_state *acm = (struct acm_state *)tty->driver_data;
-
-       info("rs_write_room\n");
-
-       if (!ACM_READY)
-               return -EINVAL;
-
-       return acm->writing ? 0 : acm->writesize;
+       struct acm *acm = tty->driver_data;
+       if (!ACM_READY(acm)) return -EINVAL;
+       return acm->writeurb.status == -EINPROGRESS ? 0 : acm->writesize;
 }
 
-static int rs_chars_in_buffer(struct tty_struct *tty)
+static int acm_tty_chars_in_buffer(struct tty_struct *tty)
 {
-       struct acm_state *acm = (struct acm_state *)tty->driver_data;
-
-//     info("rs_chars_in_buffer\n");
-
-       if (!ACM_READY)
-               return -EINVAL;
-
-       return acm->writing ? acm->writesize : 0;
+       struct acm *acm = tty->driver_data;
+       if (!ACM_READY(acm)) return -EINVAL;
+       return acm->writeurb.status == -EINPROGRESS ? acm->writesize : 0;
 }
 
-static void rs_throttle(struct tty_struct *tty)
+static void acm_tty_throttle(struct tty_struct *tty)
 {
-       struct acm_state *acm = (struct acm_state *)tty->driver_data;
-
-       info("rs_throttle\n");
-
-       if (!ACM_READY)
-               return;
-/*
-       if (I_IXOFF(tty))
-               rs_send_xchar(tty, STOP_CHAR(tty));
-*/
+       struct acm *acm = tty->driver_data;
+       if (!ACM_READY(acm)) return;
        if (tty->termios->c_cflag & CRTSCTS)
-               Set_Control_Line_Status(acm->ctrlstate & ~CTRL_STAT_RTS, acm);
+               acm_set_control(acm->ctrlout &= ~ACM_CTRL_RTS, acm);
 }
 
-static void rs_unthrottle(struct tty_struct *tty)
+static void acm_tty_unthrottle(struct tty_struct *tty)
 {
-       struct acm_state *acm = (struct acm_state *) tty->driver_data;
-
-       info("rs_unthrottle\n");
-
-       if (!ACM_READY)
-               return;
-/*
-       if (I_IXOFF(tty))
-               rs_send_xchar(tty, STOP_CHAR(tty));
-*/
+       struct acm *acm = tty->driver_data;
+       if (!ACM_READY(acm)) return;
        if (tty->termios->c_cflag & CRTSCTS)
-               Set_Control_Line_Status(acm->ctrlstate | CTRL_STAT_RTS, acm);
+               acm_set_control(acm->ctrlout |= ACM_CTRL_RTS, acm);
 }
 
-static int get_free_acm(void)
+static void acm_tty_set_termios(struct tty_struct *tty, struct termios *old)
 {
-       int i;
-       for (i = 0; i < NR_PORTS; i++) {
-               if (!acm_state_table[i].present)
-                       return i;
-       }
-       return -1;
+       acm_debug("set_termios called, but not there yet");
+       return;
 }
 
-static void * acm_probe(struct usb_device *dev, unsigned int ifnum)
+/*
+ * USB probe and disconnect routines.
+ */
+
+static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
 {
-       struct acm_state *acm;
-       struct usb_interface_descriptor *interface;
-       struct usb_endpoint_descriptor *endpoint;
-       int cfgnum,acmno;
-       int swapped=0;
-       
-       info("acm_probe\n");
-       
-       if (0>(acmno=get_free_acm())) {
-               info("Too many acm devices connected\n");
+       struct acm *acm;
+       struct usb_interface_descriptor *ifcom, *ifdata;
+       struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
+       int readsize, ctrlsize, minor, i;
+       unsigned char *buf;
+       char *s = NULL;
+
+       for (minor = 0; minor < ACM_TTY_MINORS &&
+               (acm_table[minor].present || acm_table[minor].used); minor++);
+       if (acm_table[minor].present || acm_table[minor].used) {
+               acm_debug("no more free acm devices");
                return NULL;
        }
-       acm = &acm_state_table[acmno];
+       acm = acm_table + minor;
+       memset(acm, 0, sizeof(struct acm));
 
-       /* Only use CDC */
-       if (dev->descriptor.bDeviceClass != 2 ||
-           dev->descriptor.bDeviceSubClass != 0 ||
-            dev->descriptor.bDeviceProtocol != 0)
-               return NULL;
+       acm->dev = dev;
 
-#define IFCLASS(if) ((if->bInterfaceClass << 24) | (if->bInterfaceSubClass << 16) | (if->bInterfaceProtocol << 8) | (if->bNumEndpoints))
+       if (dev->descriptor.bDeviceClass != 2 || dev->descriptor.bDeviceSubClass != 0
+               || dev->descriptor.bDeviceProtocol != 0) {
+               return NULL;
+       }
 
-       /* FIXME: should the driver really be doing the configuration
-        * selecting or should the usbcore?  [different configurations
-        * can have different bandwidth requirements] -greg */
+       for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 
-       printk("Acm: found device with right class...\n" );
+               acm_debug("probing config %d", i);
+               acm->cfg = dev->config + i;
 
-       /* Now scan all configs for a ACM configuration */
-       for (cfgnum=0;cfgnum<dev->descriptor.bNumConfigurations;cfgnum++) {
-               /* The first one should be Communications interface? */
-               interface = &dev->config[cfgnum].interface[0].altsetting[0];
-               if (IFCLASS(interface) != 0x02020101)
+               ifcom = acm->cfg->interface[0].altsetting + 0;
+               if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+                   ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
                        continue;
 
-               /* Which uses an interrupt input */
-               endpoint = &interface->endpoint[0];
-               if ((endpoint->bEndpointAddress & 0x80) != 0x80 ||
-                   (endpoint->bmAttributes & 3) != 3)
+               epctrl = ifcom->endpoint + 0;
+               if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3)
                        continue;
-                       
-               /* The second one should be a Data interface? */
-               interface = &dev->config[cfgnum].interface[1].altsetting[0];
-               if (interface->bInterfaceClass != 10 ||
-                   interface->bNumEndpoints != 2)
+
+               ifdata = acm->cfg->interface[1].altsetting + 0;
+               if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
                        continue;
 
-               /* make sure both interfaces are available for our use */
-               if (usb_interface_claimed(&dev->config[cfgnum].interface[0]) ||
-                   usb_interface_claimed(&dev->config[cfgnum].interface[1])) {
-                       printk("usb-acm: required interface already has a driver\n");
+               if (usb_interface_claimed(acm->cfg->interface + 0) ||
+                   usb_interface_claimed(acm->cfg->interface + 1))
                        continue;
-               }
 
-               endpoint = &interface->endpoint[0];
-               if ((endpoint->bEndpointAddress & 0x80) != 0x80)
-                       swapped = 1;
+               epread = ifdata->endpoint + 0;
+               epwrite = ifdata->endpoint + 1;
 
-               /*With a bulk input */
-               endpoint = &interface->endpoint[0^swapped];
-               if ((endpoint->bEndpointAddress & 0x80) != 0x80 ||
-                   (endpoint->bmAttributes & 3) != 2)
-                       continue;
-                       
-               /*And a bulk output */
-               endpoint = &interface->endpoint[1^swapped];
-               if ((endpoint->bEndpointAddress & 0x80) == 0x80 ||
-                   (endpoint->bmAttributes & 3) != 2)
+               if ((epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+                  ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
                        continue;
 
-               printk("USB ACM %d found on config %d\n", acmno, cfgnum);
-               usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
+               if ((epread->bEndpointAddress & 0x80) != 0x80) {
+                       epread = ifdata->endpoint + 1;
+                       epwrite = ifdata->endpoint + 0;
+               }
 
-               acm->dev=dev;
+               usb_set_configuration(dev, acm->cfg->bConfigurationValue);
 
-               acm->readendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0^swapped].bEndpointAddress;
-               acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp);
-               acm->readbuffer=kmalloc(acm->readsize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0^swapped].wMaxPacketSize,GFP_KERNEL);
-               acm->reading=0;
-               if (!acm->readbuffer) {
-                       printk("ACM: Couldn't allocate readbuffer\n");
-                       return NULL;
-               }
-               acm->readurb = usb_alloc_urb(0);
-               if (!acm->readurb) {
-                       printk("acm: couldn't allocate read urb\n");
-                       return NULL;
-               }
+               ctrlsize = epctrl->wMaxPacketSize;
+               readsize = epread->wMaxPacketSize;
+               acm->writesize = epwrite->wMaxPacketSize;
 
-               acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1^swapped].bEndpointAddress;
-               acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp);
-               acm->writebuffer=kmalloc(acm->writesize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1^swapped].wMaxPacketSize, GFP_KERNEL);
-               acm->writing=0;
-               if (!acm->writebuffer) {
-                       printk("ACM: Couldn't allocate writebuffer\n");
-                       kfree(acm->readbuffer);
+               if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL)))
                        return NULL;
-               }
-               acm->writeurb = usb_alloc_urb(0);
-               if (!acm->writeurb) {
-                       printk("acm: couldn't allocate write urb\n");
-                       return NULL;
-               }
 
-               acm->ctrlbuffer=kmalloc(acm->ctrlsize=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].wMaxPacketSize, GFP_KERNEL);
-               acm->ctrlendp=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bEndpointAddress;
-               acm->ctrlpipe=usb_rcvintpipe(acm->dev,acm->ctrlendp);
-               acm->ctrlinterval=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bInterval;
-               if (!acm->ctrlbuffer) {
-                       printk("acm: couldn't allocate ctrlbuffer\n");
-                       return NULL;
-               }
-               acm->ctrlurb = usb_alloc_urb(0);
-               if (!acm->ctrlurb) {
-                       printk("acm: couldn't allocate write urb\n");
-                       return NULL;
-               }
+               FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
+                       buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
 
-               acm->cfgnum = cfgnum;
-               acm->present=1;                         
-               MOD_INC_USE_COUNT;
+               FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+                       buf += ctrlsize, readsize, acm_read_bulk, acm);
+
+               FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+                       buf += readsize , acm->writesize, acm_write_bulk, acm);
+
+               printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+
+               usb_driver_claim_interface(&acm_driver, acm->cfg->interface + 0, acm);
+               usb_driver_claim_interface(&acm_driver, acm->cfg->interface + 1, acm);
+
+               acm->present = 1;
 
-               usb_driver_claim_interface(&acm_driver,
-                               &dev->config[cfgnum].interface[0], acm);
-               usb_driver_claim_interface(&acm_driver,
-                               &dev->config[cfgnum].interface[1], acm);
                return acm;
        }
+
        return NULL;
 }
 
 static void acm_disconnect(struct usb_device *dev, void *ptr)
 {
-       struct acm_state *acm = ptr;
+       struct acm *acm = ptr;
 
-       info("acm_disconnect\n");
-       
-       if (!acm->present)
+       if (!acm->present) {
+               acm_debug("disconnect on nonexisting interface");
                return;
-
-       acm->active=0;
-       acm->present=0;
-       if (acm->writing)
-               acm->writing=0;
-       if (acm->reading)
-               acm->reading=0;
-
-       if (acm->ctrlurb) {
-               usb_unlink_urb(acm->ctrlurb);
-               usb_free_urb(acm->ctrlurb);
-               acm->ctrlurb = NULL;
-       }
-       if (acm->readurb) {
-               usb_unlink_urb(acm->readurb);
-               usb_free_urb(acm->readurb);
-               acm->readurb = NULL;
-       }
-       if (acm->writeurb) {
-               usb_unlink_urb(acm->writeurb);
-               usb_free_urb(acm->writeurb);
-               acm->writeurb = NULL;
        }
-       //BUG: What to do if a device is open?? Notify process or not allow cleanup?
-       kfree(acm->writebuffer);
-       kfree(acm->readbuffer);
-       kfree(acm->ctrlbuffer);
 
-       /* release the interfaces so that other drivers can have at them */
-       usb_driver_release_interface(&acm_driver,
-                               &dev->config[acm->cfgnum].interface[0]);
-       usb_driver_release_interface(&acm_driver,
-                               &dev->config[acm->cfgnum].interface[1]);
+       acm->present = 0;
 
-       MOD_DEC_USE_COUNT;
+       usb_unlink_urb(&acm->ctrlurb);
+       usb_unlink_urb(&acm->readurb);
+       usb_unlink_urb(&acm->writeurb);
+
+       kfree(acm->ctrlurb.transfer_buffer);
+
+       usb_driver_release_interface(&acm_driver, acm->cfg->interface + 0);
+       usb_driver_release_interface(&acm_driver, acm->cfg->interface + 1);
 }
 
-/*USB DRIVER STUFF*/
+/*
+ * USB driver structure.
+ */
+
 static struct usb_driver acm_driver = {
-       "acm",
-       acm_probe,
-       acm_disconnect,
-       { NULL, NULL }
+       name:           "acm",
+       probe:          acm_probe,
+       disconnect:     acm_disconnect
 };
 
-int usb_acm_init(void)
-{
-       int cnt;
-
-       info("usb_acm_init\n");
-
-       //INITIALIZE GLOBAL DATA STRUCTURES
-       for (cnt = 0; cnt < NR_PORTS; cnt++)
-               memset(&acm_state_table[cnt], 0, sizeof(struct acm_state));
-
-       //REGISTER TTY DRIVER
-       memset(&acm_tty_driver, 0, sizeof(struct tty_driver));
-       acm_tty_driver.magic = TTY_DRIVER_MAGIC;
-       acm_tty_driver.driver_name = "usb";
-       acm_tty_driver.name = "ttyACM";
-       acm_tty_driver.major = ACM_MAJOR;
-       acm_tty_driver.minor_start = 0;
-       acm_tty_driver.num = NR_PORTS;
-       acm_tty_driver.type = TTY_DRIVER_TYPE_SERIAL;
-       acm_tty_driver.subtype = SERIAL_TYPE_NORMAL;
-       acm_tty_driver.init_termios = tty_std_termios;
-       acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       acm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
-       acm_tty_driver.refcount = &acm_refcount;
-       acm_tty_driver.table = acm_tty;
-       acm_tty_driver.termios = acm_termios;
-       acm_tty_driver.termios_locked = acm_termios_locked;
-
-       acm_tty_driver.open = rs_open;
-       acm_tty_driver.close = rs_close;
-       acm_tty_driver.write = rs_write;
-       acm_tty_driver.put_char = rs_put_char;
-       acm_tty_driver.flush_chars = NULL; //rs_flush_chars;
-       acm_tty_driver.write_room = rs_write_room;
-       acm_tty_driver.ioctl = NULL; //rs_ioctl
-       acm_tty_driver.set_termios = NULL; //rs_set_termios;
-       acm_tty_driver.set_ldisc = NULL;
-       acm_tty_driver.throttle = rs_throttle;
-       acm_tty_driver.unthrottle = rs_unthrottle;
-       acm_tty_driver.stop = NULL; //rs_stop;
-       acm_tty_driver.start = NULL; //rs_start;
-       acm_tty_driver.hangup = NULL; //rs_hangup;
-       acm_tty_driver.break_ctl = NULL; //rs_break;
-       acm_tty_driver.wait_until_sent = NULL; //rs_wait_until_sent;
-       acm_tty_driver.send_xchar = NULL; //rs_send_xchar;
-       acm_tty_driver.read_proc = NULL; //rs_read_proc;
-       acm_tty_driver.chars_in_buffer = rs_chars_in_buffer;
-       acm_tty_driver.flush_buffer = NULL; //rs_flush_buffer;
-       if (tty_register_driver(&acm_tty_driver)) {
-               printk(KERN_ERR "acm: failed to register tty driver\n");
-               return -EPERM;
-       }
+/*
+ * TTY driver structures.
+ */
 
-       if (usb_register(&acm_driver) < 0) {
-               tty_unregister_driver(&acm_tty_driver);
-               return -1;
-       }
+static int acm_tty_refcount;
+
+static struct tty_struct *acm_tty_table[ACM_TTY_MINORS];
+static struct termios *acm_tty_termios[ACM_TTY_MINORS];
+static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
+
+static struct tty_driver acm_tty_driver = {
+       magic:                  TTY_DRIVER_MAGIC,
+       driver_name:            "usb",
+       name:                   "ttyACM",
+       major:                  ACM_TTY_MAJOR,
+       minor_start:            0,
+       num:                    ACM_TTY_MINORS,
+       type:                   TTY_DRIVER_TYPE_SERIAL,
+       subtype:                SERIAL_TYPE_NORMAL,
+       flags:                  TTY_DRIVER_REAL_RAW,
+
+       refcount:               &acm_tty_refcount,
+
+       table:                  acm_tty_table,
+       termios:                acm_tty_termios,
+       termios_locked:         acm_tty_termios_locked,
+
+       open:                   acm_tty_open,
+       close:                  acm_tty_close,
+       write:                  acm_tty_write,
+       write_room:             acm_tty_write_room,
+       set_termios:            acm_tty_set_termios,
+       throttle:               acm_tty_throttle,
+       unthrottle:             acm_tty_unthrottle,
+       chars_in_buffer:        acm_tty_chars_in_buffer
+};
 
-       printk(KERN_INFO "USB ACM registered.\n");
-       return 0;
-}
+/*
+ * Init / cleanup.
+ */
 
-void usb_acm_cleanup(void)
+#ifdef MODULE
+void cleanup_module(void)
 {
-       int i;
-       struct acm_state *acm;
-
-       info("usb_acm_cleanup\n");
-               
-       for (i=0;i<NR_PORTS;i++) {
-               acm=&acm_state_table[i];
-               if (acm->present) {
-                       printk("disconnecting %d\n",i);
-                       acm_disconnect(acm->dev, acm);
-               }  
-       }
-       tty_unregister_driver(&acm_tty_driver);
-       
        usb_deregister(&acm_driver);
-       
+       tty_unregister_driver(&acm_tty_driver);
 }
 
-#ifdef MODULE
 int init_module(void)
+#else
+int usb_acm_init(void)
+#endif
 {
-       return usb_acm_init();
-}
+       memset(acm_table, 0, sizeof(struct acm) * ACM_TTY_MINORS);
 
-void cleanup_module(void)
-{
-       usb_acm_cleanup();
+       acm_tty_driver.init_termios =           tty_std_termios;
+       acm_tty_driver.init_termios.c_cflag =   B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+       if (tty_register_driver(&acm_tty_driver))
+               return -1;
+
+       if (usb_register(&acm_driver) < 0) {
+               tty_unregister_driver(&acm_tty_driver);
+               return -1;
+       }
+
+       return 0;
 }
-#endif
+
index 6471b0db50f41c573c8d2f90e7394f150ebc6024..9d8c0d03e3d8f4c2f9610928856b14af73185e84 100644 (file)
@@ -56,6 +56,9 @@
  *             that means they won't play short sounds. Should probably maintain
  *             the ISO datastream even if there's nothing to play.
  *             Fix counting the total_bytes counter, RealPlayer G2 depends on it.
+ * 1999-12-20:  Fix bad bug in conversion to per interface probing.
+ *             disconnect was called multiple times for the audio device,
+ *             leading to a premature freeing of the audio structures
  *
  */
 
  */
 
 /*****************************************************************************/
+
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <linux/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-//#include <linux/spinlock.h>
 
 #include "usb.h"
 #include "audio.h"
@@ -621,137 +624,145 @@ static void usbin_disc(struct usb_audiodev *as)
        usbin_stop(as);
 }
 
-static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
+static void conversion(const void *ibuf, unsigned int ifmt, void *obuf, unsigned int ofmt, void *tmp, unsigned int scnt)
 {
-       union {
-               __s16 s[64];
-               unsigned char b[0];
-       } tmp;
-       unsigned int scnt, maxs, ufmtsh, dfmtsh, cnt, i;
+       unsigned int cnt, i;
        __s16 *sp, *sp2, s;
        unsigned char *bp;
 
-       ufmtsh = AFMT_BYTESSHIFT(u->format);
-       dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-       maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
-       while (samples > 0) {
-               scnt = samples;
-               if (scnt > maxs)
-                       scnt = maxs;
-               cnt = scnt;
-               if (AFMT_ISSTEREO(u->format))
-                       cnt <<= 1;
-               sp = tmp.s + cnt;
-               switch (u->format & ~AFMT_STEREO) {
-               case AFMT_U8:
-                       for (bp = buffer+cnt, i = 0; i < cnt; i++) {
-                               bp--;
-                               sp--;
-                               *sp = (*bp ^ 0x80) << 8;
-                       }
-                       break;
+       cnt = scnt;
+       if (AFMT_ISSTEREO(ifmt))
+               cnt <<= 1;
+       sp = ((__s16 *)tmp) + cnt;
+       switch (ifmt & ~AFMT_STEREO) {
+       case AFMT_U8:
+               for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
+                       bp--;
+                       sp--;
+                       *sp = (*bp ^ 0x80) << 8;
+               }
+               break;
+                       
+       case AFMT_S8:
+               for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
+                       bp--;
+                       sp--;
+                       *sp = *bp << 8;
+               }
+               break;
+               
+       case AFMT_U16_LE:
+               for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
+                       bp -= 2;
+                       sp--;
+                       *sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
+               }
+               break;
 
-               case AFMT_S8:
-                       for (bp = buffer+cnt, i = 0; i < cnt; i++) {
-                               bp--;
-                               sp--;
-                               *sp = *bp << 8;
-                       }
-                       break;
+       case AFMT_U16_BE:
+               for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
+                       bp -= 2;
+                       sp--;
+                       *sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
+               }
+               break;
 
-               case AFMT_U16_LE:
-                       for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
-                               bp -= 2;
-                               sp--;
-                               *sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
-                       }
-                       break;
+       case AFMT_S16_LE:
+               for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
+                       bp -= 2;
+                       sp--;
+                       *sp = bp[0] | (bp[1] << 8);
+               }
+               break;
 
-               case AFMT_U16_BE:
-                       for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
-                               bp -= 2;
-                               sp--;
-                               *sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
-                       }
-                       break;
+       case AFMT_S16_BE:
+               for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
+                       bp -= 2;
+                       sp--;
+                       *sp = bp[1] | (bp[0] << 8);
+               }
+               break;
+       }
+       if (!AFMT_ISSTEREO(ifmt) && AFMT_ISSTEREO(ofmt)) {
+               /* expand from mono to stereo */
+               for (sp = ((__s16 *)tmp)+scnt, sp2 = ((__s16 *)tmp)+2*scnt, i = 0; i < scnt; i++) {
+                       sp--;
+                       sp2 -= 2;
+                       sp2[0] = sp2[1] = sp[0];
+               }
+       }
+       if (AFMT_ISSTEREO(ifmt) && !AFMT_ISSTEREO(ofmt)) {
+               /* contract from stereo to mono */
+               for (sp = sp2 = ((__s16 *)tmp), i = 0; i < scnt; i++, sp++, sp2 += 2)
+                       sp[0] = (sp2[0] + sp2[1]) >> 1;
+       }
+       cnt = scnt;
+       if (AFMT_ISSTEREO(ofmt))
+               cnt <<= 1;
+       sp = ((__s16 *)tmp);
+       bp = ((unsigned char *)obuf);
+       switch (ofmt & ~AFMT_STEREO) {
+       case AFMT_U8:
+               for (i = 0; i < cnt; i++, sp++, bp++)
+                       *bp = (*sp >> 8) ^ 0x80;
+               break;
 
-               case AFMT_S16_LE:
-                       for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
-                               bp -= 2;
-                               sp--;
-                               *sp = bp[0] | (bp[1] << 8);
-                       }
-                       break;
+       case AFMT_S8:
+               for (i = 0; i < cnt; i++, sp++, bp++)
+                       *bp = *sp >> 8;
+               break;
 
-               case AFMT_S16_BE:
-                       for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
-                               bp -= 2;
-                               sp--;
-                               *sp = bp[1] | (bp[0] << 8);
-                       }
-                       break;
+       case AFMT_U16_LE:
+               for (i = 0; i < cnt; i++, sp++, bp += 2) {
+                       s = *sp;
+                       bp[0] = s;
+                       bp[1] = (s >> 8) ^ 0x80;
                }
-               if (!AFMT_ISSTEREO(u->format) && AFMT_ISSTEREO(u->dma.format)) {
-                       /* expand from mono to stereo */
-                       for (sp = tmp.s+scnt, sp2 = tmp.s+2*scnt, i = 0; i < scnt; i++) {
-                               sp--;
-                               sp2 -= 2;
-                               sp2[0] = sp2[1] = sp[0];
-                       }
-               }
-               if (AFMT_ISSTEREO(u->format) && !AFMT_ISSTEREO(u->dma.format)) {
-                       /* contract from stereo to mono */
-                       for (sp = sp2 = tmp.s, i = 0; i < scnt; i++, sp++, sp2 += 2)
-                               sp[0] = (sp2[0] + sp2[1]) >> 1;
-               }
-               cnt = scnt;
-               if (AFMT_ISSTEREO(u->dma.format))
-                       cnt <<= 1;
-               sp = tmp.s;
-               bp = tmp.b;
-               switch (u->dma.format & ~AFMT_STEREO) {
-               case AFMT_U8:
-                       for (i = 0; i < cnt; i++, sp++, bp++)
-                               *bp = (*sp >> 8) ^ 0x80;
-                       break;
+               break;
 
-               case AFMT_S8:
-                       for (i = 0; i < cnt; i++, sp++, bp++)
-                               *bp = *sp >> 8;
-                       break;
+       case AFMT_U16_BE:
+               for (i = 0; i < cnt; i++, sp++, bp += 2) {
+                       s = *sp;
+                       bp[1] = s;
+                       bp[0] = (s >> 8) ^ 0x80;
+               }
+               break;
 
-               case AFMT_U16_LE:
-                       for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                               s = *sp;
-                               bp[0] = s;
-                               bp[1] = (s >> 8) ^ 0x80;
-                       }
-                       break;
+       case AFMT_S16_LE:
+               for (i = 0; i < cnt; i++, sp++, bp += 2) {
+                       s = *sp;
+                       bp[0] = s;
+                       bp[1] = s >> 8;
+               }
+               break;
 
-               case AFMT_U16_BE:
-                       for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                               s = *sp;
-                               bp[1] = s;
-                               bp[0] = (s >> 8) ^ 0x80;
-                       }
-                       break;
+       case AFMT_S16_BE:
+               for (i = 0; i < cnt; i++, sp++, bp += 2) {
+                       s = *sp;
+                       bp[1] = s;
+                       bp[0] = s >> 8;
+               }
+               break;
+       }
+       
+}
 
-               case AFMT_S16_LE:
-                       for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                               s = *sp;
-                               bp[0] = s;
-                               bp[1] = s >> 8;
-                       }
-                       break;
+static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
+{
+       union {
+               __s16 s[64];
+               unsigned char b[0];
+       } tmp;
+       unsigned int scnt, maxs, ufmtsh, dfmtsh;
 
-               case AFMT_S16_BE:
-                       for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                               s = *sp;
-                               bp[1] = s;
-                               bp[0] = s >> 8;
-                       }
-                       break;
-               }
+       ufmtsh = AFMT_BYTESSHIFT(u->format);
+       dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+       maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+       while (samples > 0) {
+               scnt = samples;
+               if (scnt > maxs)
+                       scnt = maxs;
+               conversion(buffer, u->format, tmp.b, u->dma.format, tmp.b, scnt);
                dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
                buffer += scnt << ufmtsh;
                samples -= scnt;
@@ -1040,7 +1051,7 @@ static void usbout_stop(struct usb_audiodev *as)
        i = u->flags;
        spin_unlock_irqrestore(&as->lock, flags);
        while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-               set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+               set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
                spin_lock_irqsave(&as->lock, flags);
                i = u->flags;
@@ -1078,7 +1089,6 @@ static inline void usbout_release(struct usb_audiodev *as)
 static void usbout_disc(struct usb_audiodev *as)
 {
        struct usbout *u = &as->usbout;
-
        unsigned long flags;
 
        spin_lock_irqsave(&as->lock, flags);
@@ -1093,9 +1103,7 @@ static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int
                __s16 s[64];
                unsigned char b[0];
        } tmp;
-       unsigned int scnt, maxs, ufmtsh, dfmtsh, cnt, i;
-       __s16 *sp, *sp2, s;
-       unsigned char *bp;
+       unsigned int scnt, maxs, ufmtsh, dfmtsh;
 
        ufmtsh = AFMT_BYTESSHIFT(u->format);
        dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
@@ -1104,121 +1112,8 @@ static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int
                scnt = samples;
                if (scnt > maxs)
                        scnt = maxs;
-               cnt = scnt;
-               if (AFMT_ISSTEREO(u->dma.format))
-                       cnt <<= 1;
                dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
-               sp = tmp.s + cnt;
-               switch (u->dma.format & ~AFMT_STEREO) {
-               case AFMT_U8:
-                       for (bp = tmp.b+cnt, i = 0; i < cnt; i++) {
-                               bp--;
-                               sp--;
-                               *sp = (*bp ^ 0x80) << 8;
-                       }
-                       break;
-
-               case AFMT_S8:
-                       for (bp = tmp.b+cnt, i = 0; i < cnt; i++) {
-                               bp--;
-                               sp--;
-                               *sp = *bp << 8;
-                       }
-                       break;
-
-               case AFMT_U16_LE:
-                       for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
-                               bp -= 2;
-                               sp--;
-                               *sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
-                       }
-                       break;
-
-               case AFMT_U16_BE:
-                       for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
-                               bp -= 2;
-                               sp--;
-                               *sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
-                       }
-                       break;
-
-               case AFMT_S16_LE:
-                       for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
-                               bp -= 2;
-                               sp--;
-                               *sp = bp[0] | (bp[1] << 8);
-                       }
-                       break;
-
-               case AFMT_S16_BE:
-                       for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
-                               bp -= 2;
-                               sp--;
-                               *sp = bp[1] | (bp[0] << 8);
-                       }
-                       break;
-               }
-               if (!AFMT_ISSTEREO(u->dma.format) && AFMT_ISSTEREO(u->format)) {
-                       /* expand from mono to stereo */
-                       for (sp = tmp.s+scnt, sp2 = tmp.s+2*scnt, i = 0; i < scnt; i++) {
-                               sp--;
-                               sp2 -= 2;
-                               sp2[0] = sp2[1] = sp[0];
-                       }
-               }
-               if (AFMT_ISSTEREO(u->dma.format) && !AFMT_ISSTEREO(u->format)) {
-                       /* contract from stereo to mono */
-                       for (sp = sp2 = tmp.s, i = 0; i < scnt; i++, sp++, sp2 += 2)
-                               sp[0] = (sp2[0] + sp2[1]) >> 1;
-               }
-               cnt = scnt;
-               if (AFMT_ISSTEREO(u->format))
-                       cnt <<= 1;
-               sp = tmp.s;
-               bp = buffer;
-               switch (u->format & ~AFMT_STEREO) {
-               case AFMT_U8:
-                       for (i = 0; i < cnt; i++, sp++, bp++)
-                               *bp = (*sp >> 8) ^ 0x80;
-                       break;
-
-               case AFMT_S8:
-                       for (i = 0; i < cnt; i++, sp++, bp++)
-                               *bp = *sp >> 8;
-                       break;
-
-               case AFMT_U16_LE:
-                       for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                               s = *sp;
-                               bp[0] = s;
-                               bp[1] = (s >> 8) ^ 0x80;
-                       }
-                       break;
-
-               case AFMT_U16_BE:
-                       for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                               s = *sp;
-                               bp[1] = s;
-                               bp[0] = (s >> 8) ^ 0x80;
-                       }
-                       break;
-
-               case AFMT_S16_LE:
-                       for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                               s = *sp;
-                               bp[0] = s;
-                               bp[1] = s >> 8;
-                       }
-                       break;
-
-               case AFMT_S16_BE:
-                       for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                               s = *sp;
-                               bp[1] = s;
-                               bp[0] = s >> 8;
-                       }
-                       break;
-               }
+               conversion(tmp.b, u->dma.format, buffer, u->format, tmp.b, scnt);
                buffer += scnt << ufmtsh;
                samples -= scnt;
        }
@@ -1534,7 +1429,7 @@ static int set_format_in(struct usb_audiodev *as)
        struct usb_device *dev = as->state->usbdev;
        struct usb_config_descriptor *config = dev->actconfig;
        struct usb_interface_descriptor *alts;
-       struct usb_interface *iface;    
+       struct usb_interface *iface;
        struct usbin *u = &as->usbin;
        struct dmabuf *d = &u->dma;
        struct audioformat *fmt;
@@ -1793,7 +1688,7 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
                                    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
                        goto err;
                return 0;
-               
+                
        case BASS_CONTROL:
        case MID_CONTROL:
        case TREBLE_CONTROL:
@@ -1808,7 +1703,7 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
                                    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
                        goto err;
                return 0;
-              
+
        default:
                return -1;
        }
@@ -1816,7 +1711,7 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
 
  err:
        printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
-              dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
+               dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
        return -1;
 }
 
@@ -1842,7 +1737,6 @@ static void release(struct usb_audio_state *s)
        while (!list_empty(&s->audiolist)) {
                as = list_entry(s->audiolist.next, struct usb_audiodev, list);
                list_del(&as->list);
-               
                usbin_release(as);
                usbout_release(as);
                dmabuf_release(&as->usbin.dma);
@@ -1851,7 +1745,6 @@ static void release(struct usb_audio_state *s)
        }
        while (!list_empty(&s->mixerlist)) {
                ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list);
-               
                list_del(&ms->list);
                kfree(ms);
        }
@@ -1956,7 +1849,7 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
                case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
                        /* don't know how to handle this yet */
                        return put_user(0, (int *)arg);
-                       
+
                case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
                        for (val = i = 0; i < ms->numch; i++)
                                val |= 1 << ms->ch[i].osschannel;
@@ -1965,7 +1858,7 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
                        /* don't know how to handle this yet */
                        return put_user(0, (int *)arg);
-                       
+                        
                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
                        for (val = i = 0; i < ms->numch; i++)
                                if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
@@ -3240,10 +3133,10 @@ static void usb_audio_processingunit(struct consmixstate *state, unsigned char *
 
 static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr)
 {
-//     struct usb_device *dev = state->s->usbdev;
+       struct usb_device *dev = state->s->usbdev;
        struct mixerchannel *ch;
        unsigned short chftr, mchftr;
-//     unsigned char data[1];
+       unsigned char data[1];
 
        usb_audio_recurseunit(state, ftr[4]);
        if (state->nrchannels == 0) {
@@ -3521,12 +3414,12 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
                if (iface->altsetting[1].endpoint[0].bEndpointAddress & USB_DIR_IN) {
                        if (numifin < USB_MAXINTERFACES) {
                                ifin[numifin++] = j;
-                               usb_driver_claim_interface(&usb_audio_driver, iface, s);
+                               usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
                        }
                } else {
                        if (numifout < USB_MAXINTERFACES) {
                                ifout[numifout++] = j;
-                               usb_driver_claim_interface(&usb_audio_driver, iface, s);
+                               usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
                        }
                }
        }
@@ -3555,6 +3448,7 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
        down(&open_sem);
        list_add_tail(&s->audiodev, &audiodevs);
        up(&open_sem);
+       printk(KERN_DEBUG "usb_audio_parsecontrol: usb_audio_state at %p\n", s);
        return s;
 }
 
@@ -3607,7 +3501,7 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum)
        if (!(buffer = kmalloc(buflen, GFP_KERNEL)))
                return NULL;
        ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen);
-       if (ret<0) {
+       if (ret < 0) {
                kfree(buffer);
                printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d\n", i, dev->devnum);
                return NULL;
@@ -3624,7 +3518,16 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
        struct list_head *list;
        struct usb_audiodev *as;
        struct usb_mixerdev *ms;
-       
+
+       /* we get called with -1 for every audiostreaming interface registered */
+       if (s == (struct usb_audio_state *)-1) {
+               printk(KERN_DEBUG "usb_audio_disconnect: called with -1\n");
+               return;
+       }
+       if (!s->usbdev) {
+               printk(KERN_DEBUG "usb_audio_disconnect: already called for %p!\n", s);
+               return;
+       }
        down(&open_sem);
        list_del(&s->audiodev);
        INIT_LIST_HEAD(&s->audiodev);
diff --git a/drivers/usb/hp_scanner.c b/drivers/usb/hp_scanner.c
deleted file mode 100644 (file)
index f61311b..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/* -*- linux-c -*- */
-
-/* 
- * Driver for USB HP Scanners
- *
- * David E. Nelson (dnelson@jump.net)
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
- *
- * History
- *  0.1  8/31/1999
- *
- *    Developed/tested using linux-2.3.15 with minor ohci.c changes to
- *    support short packes during bulk xfer mode.  Some testing was
- *    done with ohci-hcd but the performace was low.  Very limited
- *    testing was performed with uhci but I was unable to get it to
- *    work.  Initial relase to the linux-usb development effort.
- *
- * */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-#include <linux/spinlock.h>
-
-#include "usb.h"
-
-/* stall/wait timeout for scanner */
-#define NAK_TIMEOUT (HZ)
-
-/* For some reason, an IBUF_SIZE of 8192 causes REALLY big problems
- * with linux-2.3.15.  Anything more than 4k seems to not have an
- * effect on increasing performance. Anything smaller than 4k hurts
- * it.  */
-#define IBUF_SIZE 4096
-
-/* This is a scanner, so not much data is sent to it.  The largest
- * stuff may be some kind of maps and stuff but that's kinda rare.  */
-#define OBUF_SIZE 128
-
-struct hpscan_usb_data {
-       struct usb_device       *hpscan_dev;            /* init: probe_scanner */
-       __u8                    isopen;                 /* nz if open */
-
-       __u8                    present;                /* Device is present on the bus */
-       char                    *obuf;                  /* transfer buffers */
-       char                    *ibuf;          
-       wait_queue_head_t       wait_q;                 /* for timeouts */
-};
-
-static struct hpscan_usb_data hpscan;
-
-static int
-open_scanner(struct inode * inode, struct file * file)
-{
-       struct hpscan_usb_data *hps = &hpscan;
-
-       if (hps->isopen) {
-               return -EBUSY;
-       }
-       hps->isopen = 1;
-
-       init_waitqueue_head(&hps->wait_q);
-
-       MOD_INC_USE_COUNT;
-
-       return 0;
-}
-
-static int
-close_scanner(struct inode * inode, struct file * file)
-{
-       struct hpscan_usb_data *hps = &hpscan;
-
-       hps->isopen = 0;
-
-       MOD_DEC_USE_COUNT;
-
-       return 0;
-}
-
-static ssize_t
-write_scanner(struct file * file, const char * buffer,
-              size_t count, loff_t *ppos)
-{
-       struct hpscan_usb_data *hps = &hpscan;
-
-       unsigned long copy_size;
-       unsigned long bytes_written = 0;
-       unsigned long partial;
-
-       int result = 0;
-       int maxretry;
-       
-       do {
-               unsigned long thistime;
-               char *obuf = hps->obuf;
-
-               thistime = copy_size = (count > OBUF_SIZE) ?  OBUF_SIZE : count;
-               if (copy_from_user(hps->obuf, buffer, copy_size))
-                       return -EFAULT;
-               maxretry = 5;
-               while (thistime) {
-                       if (!hps->hpscan_dev)
-                               return -ENODEV;
-                       if (signal_pending(current)) {
-                               return bytes_written ? bytes_written : -EINTR;
-                       }
-
-                       result = usb_bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial, HZ*10);
-                       
-                       //printk(KERN_DEBUG "write stats: result:%d thistime:%lu partial:%lu\n", result, thistime, partial);
-
-                       if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */
-                               if(!maxretry--) {
-                                       return -ETIME;
-                               }
-                               interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT);
-                               continue;
-                       } else if (!result & partial) {
-                               obuf += partial;
-                               thistime -= partial;
-                       } else
-                               break;
-               };
-               if (result) {
-                       printk("Write Whoops - %x\n", result);
-                       return -EIO;
-               }
-               bytes_written += copy_size;
-               count -= copy_size;
-               buffer += copy_size;
-       } while ( count > 0 );
-       
-       return bytes_written ? bytes_written : -EIO;
-}
-
-static ssize_t
-read_scanner(struct file * file, char * buffer,
-             size_t count, loff_t *ppos)
-{
-       struct hpscan_usb_data *hps = &hpscan;
-
-       ssize_t read_count;
-
-       unsigned long partial;
-
-       int this_read;
-       int result;
-
-/* Wait for the scanner to get it's act together.  This may involve
- * resetting the head, warming up the lamp, etc.  maxretry is number
- * of seconds.  */
-       int maxretry = 30; 
-
-       char *ibuf = hps->ibuf;
-
-       read_count = 0;
-
-       while (count) {
-               if (signal_pending(current)) {
-                       return read_count ? read_count : -EINTR;
-               }
-               if (!hps->hpscan_dev)
-                       return -ENODEV;
-               this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;
-               
-               result = usb_bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial, HZ*10);
-
-               printk(KERN_DEBUG "read stats: result:%d this_read:%u partial:%lu\n", result, this_read, partial);
-               
-               if (partial) {
-                       count = this_read = partial;
-               } else if (result == USB_ST_TIMEOUT || result == 15) {  /* FIXME: 15 ??? */
-                       if(!maxretry--) {
-                               printk(KERN_DEBUG "read_scanner: maxretry timeout\n");
-                               return -ETIME;
-                       }
-                       interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT);
-                       continue;
-               } else if (result != USB_ST_DATAUNDERRUN) {
-                       printk("Read Whoops - result:%u partial:%lu this_read:%u\n", result, partial, this_read);
-                       return -EIO;
-               } else {
-                       return (0);
-               }
-               
-               if (this_read) {
-                       if (copy_to_user(buffer, ibuf, this_read))
-                               return -EFAULT;
-                       count -= this_read;
-                       read_count += this_read;
-                       buffer += this_read;
-               }
-       }
-       return read_count;
-}
-
-static void *
-probe_scanner(struct usb_device *dev, unsigned int ifnum)
-{
-       struct hpscan_usb_data *hps = &hpscan;
-
-       /*
-        * Don't bother using an HP 4200C since it does NOT understand
-        * SCL and HP isn't going to be releasing the specs any time
-        * soon.  */
-       if (dev->descriptor.idVendor != 0x3f0 ) {
-               printk(KERN_INFO "Scanner is not an HP Scanner.\n");
-               return NULL;
-       }
-
-       if (dev->descriptor.idProduct != 0x101 && /* HP 4100C */
-           dev->descriptor.idProduct != 0x202 && /* HP 5100C */
-            dev->descriptor.idProduct != 0x601) { /* HP 6300C */
-               printk(KERN_INFO "Scanner model not supported/tested.\n");
-               return NULL;
-       }
-       
-       printk(KERN_DEBUG "USB Scanner found at address %d\n", dev->devnum);
-       
-       hps->present = 1;
-       hps->hpscan_dev = dev;
-
-       if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
-               return NULL;
-       }
-
-       if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
-               return NULL;
-       }
-  
-       return hps;
-}
-
-static void
-disconnect_scanner(struct usb_device *dev, void *ptr)
-{
-       struct hpscan_usb_data *hps = (struct hpscan_usb_data *) ptr;
-
-       if (hps->isopen) {
-               /* better let it finish - the release will do whats needed */
-               hps->hpscan_dev = NULL;
-               return;
-       }
-       kfree(hps->ibuf);
-       kfree(hps->obuf);
-
-       hps->present = 0;
-}
-
-static struct
-file_operations usb_scanner_fops = {
-       NULL,           /* seek */
-       read_scanner,
-       write_scanner,
-       NULL,           /* readdir */
-       NULL,           /* poll */
-       NULL,           /* ioctl */
-       NULL,           /* mmap */
-       open_scanner,
-       NULL,           /* flush */
-       close_scanner,
-       NULL,         
-       NULL,         /* fasync */
-};
-
-static struct
-usb_driver scanner_driver = {
-       "usbscanner",
-       probe_scanner,
-       disconnect_scanner,
-       { NULL, NULL },
-       &usb_scanner_fops,
-       48
-};
-
-int
-usb_hp_scanner_init(void)
-{
-       if (usb_register(&scanner_driver) < 0)
-               return -1;
-
-       printk(KERN_DEBUG "USB Scanner support registered.\n");
-       return 0;
-}
-
-
-void
-usb_hp_scanner_cleanup(void)
-{
-       struct hpscan_usb_data *hps = &hpscan;
-
-       hps->present = 0;
-       usb_deregister(&scanner_driver);
-}
-
-#ifdef MODULE
-
-int
-init_module(void)
-{
-       return usb_hp_scanner_init();
-}
-
-void
-cleanup_module(void)
-{
-       usb_hp_scanner_cleanup();
-}
-#endif
-
index a238a6abd54d44b6788f1f6bff008e520d95e00b..25b4991dcd067bc208d89dec810ab8b4bb16914c 100644 (file)
@@ -4,6 +4,8 @@
  * (C) Copyright 1999 Linus Torvalds
  * (C) Copyright 1999 Johannes Erdfelt
  * (C) Copyright 1999 Gregory P. Smith
+ *
+ * $Id: hub.c,v 1.15 1999/12/27 15:17:45 acher Exp $
  */
 
 #include <linux/kernel.h>
@@ -45,6 +47,12 @@ static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
                USB_DT_HUB << 8, 0, data, size, HZ);
 }
 
+static int usb_clear_hub_feature(struct usb_device *dev,  int feature)
+{
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0 , NULL, 0, HZ);
+}
+
 static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
 {
        return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -190,7 +198,6 @@ static int usb_hub_configure(struct usb_hub *hub)
        printk(KERN_INFO "hub: enabling power on all ports\n");
        for (i = 0; i < hub->nports; i++)
                usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
-
        return 0;
 }
 
@@ -305,7 +312,9 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
        struct usb_device *usb;
        struct usb_port_status portsts;
        unsigned short portstatus, portchange;
+       int tries;
 
+       wait_ms(100);
        /* Check status */
        if (usb_get_port_status(hub, port + 1, &portsts)<0) {
                printk(KERN_ERR "get_port_status failed\n");
@@ -314,7 +323,8 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
 
        portstatus = le16_to_cpu(portsts.wPortStatus);
        portchange = le16_to_cpu(portsts.wPortChange);
-       printk("hub.c: portstatus %x, change %x\n",portstatus,portchange);
+       printk("hub.c: portstatus %x, change %x, %s\n",portstatus,portchange,
+       (portstatus&(1<<USB_PORT_FEAT_LOWSPEED)?"Low Speed":"High Speed"));
        /* If it's not in CONNECT and ENABLE state, we're done */
        if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
            (!(portstatus & USB_PORT_STAT_ENABLE))) {
@@ -324,10 +334,37 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
                return;
        }
        wait_ms(400);   
+
        /* Reset the port */
-       usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
-       wait_ms(100);   
+
+#define MAX_TRIES 5
+       
+       for(tries=0;tries<MAX_TRIES;tries++) {
+               
+               usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
+               wait_ms(200);   
+               
+               if (usb_get_port_status(hub, port + 1, &portsts)<0) {
+                       printk(KERN_ERR "get_port_status failed\n");
+                       return;
+               }
+               portstatus = le16_to_cpu(portsts.wPortStatus);
+               portchange = le16_to_cpu(portsts.wPortChange);
+               printk("hub.c: portstatus %x, change %x, %s\n",portstatus,portchange,
+               (portstatus&(1<<USB_PORT_FEAT_LOWSPEED)?"Low Speed":"High Speed"));
+
+               if ((portstatus&(1<<USB_PORT_FEAT_ENABLE))) 
+                       break;
+
+               wait_ms(200);
+       }
+
+       if (tries==MAX_TRIES) {
+               printk("hub.c: Can not enable port %i after %i retries, disabling port\n",port+1,MAX_TRIES);
+               return;
+       }
        /* Allocate a new device struct for it */
+
        usb = usb_alloc_dev(hub, hub->bus);
        if (!usb) {
                printk(KERN_ERR "couldn't allocate usb_device\n");
index 4a788be452ecc6fed012ce3eae9cca5c72612ff4..151ecf901a62cc2534b13f2b7326c80741f64f5d 100644 (file)
@@ -13,8 +13,8 @@ void usb_major_init(void);
 void usb_major_cleanup(void);
 int usb_mouse_init(void);
 void usb_mouse_cleanup(void);
-int usb_hp_scanner_init(void);
-void usb_hp_scanner_cleanup(void);
+int usb_scanner_init(void);
+void usb_scanner_cleanup(void);
 int usb_printer_init(void);
 int usb_scsi_init(void);
 int usb_serial_init(void);
index 82e2f14544cb7237d1166454e3791c609c891264..39f085cbdad104627b8cf3c0e810bb1bcfcabb24 100644 (file)
@@ -9,7 +9,7 @@ unsigned char usb_kbd_map[256] =
     0x04,  0x05,  0x06,  0x07,  0x08,  0x09,  0x0a,  0x0b,
     0x1c,  0x01,  0x0e,  0x0f,  0x39,  0x0c,  0x0d,  0x1a,
 
-    0x1b,  0x2b,  0x00,  0x27,  0x28,  0x29,  0x33,  0x34,
+    0x1b,  0x2b,  0x2b,  0x27,  0x28,  0x29,  0x33,  0x34,
     0x35,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,  0x40,
 
     0x41,  0x42,  0x43,  0x44,  0x57,  0x58,  0xb7,  0x46,
@@ -18,7 +18,7 @@ unsigned char usb_kbd_map[256] =
     0xcb,  0xd0,  0xc8,  0x45,  0xb5,  0x37,  0x4a,  0x4e,
     0x9c,  0x4f,  0x50,  0x51,  0x4b,  0x4c,  0x4d,  0x47,
 
-    0x48,  0x49,  0x52,  0x53,  0x00,  0x6d,  0x00,  0x00,
+    0x48,  0x49,  0x52,  0x53,  0x56,  0x6d,  0x00,  0x00,
     0xbd,  0xbe,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
 
     0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
index 676537763abef90cbcacd3be33cc2e0ff55d12e1..e1760b25ca35479c31a4e6b9244853d5fadc19ed 100644 (file)
@@ -236,22 +236,38 @@ static ssize_t write_mouse(struct file * file,
 
 /*
  * Look like a PS/2 mouse, please..
- *
+ * In XFree86 (3.3.5 tested) you must select Protocol "NetMousePS/2",
+ * then use your wheel as Button 4 and 5 via ZAxisMapping 4 5.
  * The PS/2 protocol is fairly strange, but
  * oh, well, it's at least common..
  */
 static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_t *ppos)
 {
+       DECLARE_WAITQUEUE(wait, current);
        int retval = 0;
        static int state = 0;
        struct mouse_state *mouse = &static_mouse_state;
 
        if (!mouse->present)
                return 0;
-       /*
-        * FIXME - Other mouse drivers handle blocking and nonblocking reads
-        * differently here...
-        */
+
+       if (!mouse->ready) {
+               if (file->f_flags & O_NONBLOCK) return -EAGAIN;
+
+               add_wait_queue(&mouse->wait, &wait);
+repeat:
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!mouse->ready && !signal_pending(current)) {
+                       schedule();
+               goto repeat;
+               }
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&mouse->wait, &wait);
+       }
+       if (signal_pending(current)) return -ERESTARTSYS;
+
+       if (!mouse->present)
+               return 0;
        if (count) {
                mouse->ready = 0;
                switch (state) {
@@ -389,7 +405,7 @@ struct file_operations usb_mouse_fops = {
        {
                printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__);
                /* restart the usb controller's polling of the mouse */
-               
+
                pipe = usb_rcvintpipe(mouse->dev, mouse->bEndpointAddress);
                FILL_INT_URB(mouse->urb,mouse->dev,pipe,
                             mouse->buffer,
@@ -411,10 +427,11 @@ struct file_operations usb_mouse_fops = {
 static void mouse_disconnect(struct usb_device *dev, void *priv)
 {
        struct mouse_state *mouse = priv;
-
+       
        /* stop the usb interrupt transfer */
        if (mouse->present) {
-         usb_unlink_urb(mouse->urb);
+               usb_unlink_urb(mouse->urb);
+               wake_up(&mouse->wait);
        }
 
        /* this might need work */
index 5b7d5f045aec8f6b1ee53999b028f81ff823894b..6fb7df722f51e773f4f8b2c97f6a0aa7d59101ba 100644 (file)
@@ -1,4 +1,3 @@
-
 /* Driver for USB Printers
  * 
  * Copyright 1999 Michael Gee (michael@linuxspecific.com)
 
 #include "usb.h"
 
+/* Define IEEE_DEVICE_ID if you want to see the IEEE-1284 Device ID string.
+ * This may include the printer's serial number.
+ * An example from an HP 970C DeskJet printer is (this is one long string,
+ * with the serial number changed):
+MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ:                    ;
+ */
+#define IEEE_DEVICE_ID
+
 #define NAK_TIMEOUT (HZ)                               /* stall wait for printer */
 #define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT)       /* should not take 1 minute a page! */
 
@@ -62,12 +69,16 @@ static struct pp_usb_data *minor_data[MAX_PRINTERS];
 static unsigned char printer_read_status(struct pp_usb_data *p)
 {
        __u8 status;
+       int err;
        struct usb_device *dev = p->pusb_dev;
 
-       if (usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
+       err = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
                USB_PRINTER_REQ_GET_PORT_STATUS,
                USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN,
-               0, 0, &status, sizeof(status), HZ)) {
+               0, 0, &status, sizeof(status), HZ);
+       if (err < 0) {
+               printk(KERN_ERR "usblp%d: read_status control_msg error = %d\n",
+                       p->minor, err);
                return 0;
        }
        return status;
@@ -105,11 +116,15 @@ static int printer_check_status(struct pp_usb_data *p)
 static void printer_reset(struct pp_usb_data *p)
 {
        struct usb_device *dev = p->pusb_dev;
+       int err;
 
-       usb_control_msg(dev, usb_sndctrlpipe(dev,0),
+       err = usb_control_msg(dev, usb_sndctrlpipe(dev,0),
                USB_PRINTER_REQ_SOFT_RESET,
                USB_TYPE_CLASS | USB_RECIP_OTHER,
                0, 0, NULL, 0, HZ);
+       if (err < 0)
+               printk(KERN_ERR "usblp%d: reset control_msg error = %d\n",
+                       p->minor, err);
 }
 
 static int open_printer(struct inode *inode, struct file *file)
@@ -125,10 +140,14 @@ static int open_printer(struct inode *inode, struct file *file)
        p->minor = MINOR(inode->i_rdev);
 
        if (p->isopen++) {
+               printk(KERN_ERR "usblp%d: printer is already open\n",
+                       p->minor);
                return -EBUSY;
        }
        if (!(p->obuf = (char *)__get_free_page(GFP_KERNEL))) {
                p->isopen = 0;
+               printk(KERN_ERR "usblp%d: cannot allocate memory\n",
+                       p->minor);
                return -ENOMEM;
        }
 
@@ -176,6 +195,7 @@ static ssize_t write_printer(struct file *file,
                if (copy_from_user(p->obuf, buffer, copy_size))
                        return -EFAULT;
                maxretry = MAX_RETRY_COUNT;
+
                while (thistime) {
                        if (!p->pusb_dev)
                                return -ENODEV;
@@ -238,6 +258,9 @@ static ssize_t read_printer(struct file *file,
                result = usb_bulk_msg(p->pusb_dev,
                          usb_rcvbulkpipe(p->pusb_dev, p->bulk_in_ep),
                          buf, this_read, &partial, HZ*20);
+               if (result < 0)
+                       printk(KERN_ERR "usblp%d read_printer bulk_msg error = %d\n",
+                               p->minor, result);
 
                /* unlike writes, we don't retry a NAK, just stop now */
                if (!result & partial)
@@ -253,6 +276,7 @@ static ssize_t read_printer(struct file *file,
                        buffer += this_read;
                }
        }
+
        return read_count;
 }
 
@@ -261,6 +285,7 @@ static void *printer_probe(struct usb_device *dev, unsigned int ifnum)
        struct usb_interface_descriptor *interface;
        struct pp_usb_data *pp;
        int i;
+       __u8 status;
 
        /*
         * FIXME - this will not cope with combined printer/scanners
@@ -311,19 +336,20 @@ static void *printer_probe(struct usb_device *dev, unsigned int ifnum)
                        break;
        }
        if (i >= MAX_PRINTERS) {
-               printk(KERN_ERR "No minor table space available for USB Printer\n");
+               printk(KERN_ERR "No minor table space available for new USB printer\n");
                return NULL;
        }
 
-       printk(KERN_INFO "USB Printer found at address %d\n", dev->devnum);
+       printk(KERN_INFO "USB printer found at address %d\n", dev->devnum);
 
        if (!(pp = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) {
-               printk(KERN_DEBUG "usb_printer: no memory!\n");
+               printk(KERN_DEBUG "USB printer: no memory!\n");
                return NULL;
        }
 
        memset(pp, 0, sizeof(struct pp_usb_data));
        minor_data[i] = PPDATA(pp);
+
        pp->minor = i;
        pp->pusb_dev = dev;
        pp->maxout = (BIG_BUF_SIZE > PAGE_SIZE) ? PAGE_SIZE : BIG_BUF_SIZE;
@@ -355,37 +381,44 @@ static void *printer_probe(struct usb_device *dev, unsigned int ifnum)
                pp->bulk_out_index,
                pp->bulk_out_ep);
 
-#if 1
+#ifdef IEEE_DEVICE_ID
        {
-               __u8 status;
-               __u8 ieee_id[64];       /* first 2 bytes are (big-endian) length */
-               int length = be16_to_cpup((__u16 *)ieee_id);
+               __u8 ieee_id[64]; /* first 2 bytes are (big-endian) length */
+                               /* This string space may be too short. */
+               int length = (ieee_id[0] << 8) + ieee_id[1]; /* high-low */
+                               /* This calc. or be16_to_cpu() both get
+                                * some weird results for <length>. */
+               int err;
 
                /* Let's get the device id if possible. */
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
+               err = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
                    USB_PRINTER_REQ_GET_DEVICE_ID,
                    USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN,
                    0, 0, ieee_id,
-                   sizeof(ieee_id)-1, HZ) == 0) {
+                   sizeof(ieee_id)-1, HZ);
+               if (err >= 0) {
                        if (ieee_id[1] < sizeof(ieee_id) - 1)
                                ieee_id[ieee_id[1]+2] = '\0';
                        else
                                ieee_id[sizeof(ieee_id)-1] = '\0';
-                       printk(KERN_INFO "  usblp%d Device ID length=%d, string=%s\n",
-                               pp->minor, length, &ieee_id[2]);
+                       printk(KERN_INFO "usblp%d Device ID length=%d [%x:%x]\n",
+                               pp->minor, length, ieee_id[0], ieee_id[1]);
+                       printk(KERN_INFO "usblp%d Device ID=%s\n",
+                               pp->minor, &ieee_id[2]);
                }
                else
-                       printk(KERN_INFO "  usblp%d: error reading IEEE-1284 Device ID\n",
-                               pp->minor);
-
-               status = printer_read_status(PPDATA(pp));
-               printk(KERN_INFO "  usblp%d Probe Status is %x: %s,%s,%s\n",
-                       pp->minor, status,
-                       (status & LP_PSELECD) ? "Selected" : "Not Selected",
-                       (status & LP_POUTPA)  ? "No Paper" : "Paper",
-                       (status & LP_PERRORP) ? "No Error" : "Error");
+                       printk(KERN_INFO "usblp%d: error = %d reading IEEE-1284 Device ID\n",
+                               pp->minor, err);
        }
 #endif
+
+       status = printer_read_status(PPDATA(pp));
+       printk(KERN_INFO "usblp%d probe status is %x: %s,%s,%s\n",
+               pp->minor, status,
+               (status & LP_PSELECD) ? "Selected" : "Not Selected",
+               (status & LP_POUTPA)  ? "No Paper" : "Paper",
+               (status & LP_PERRORP) ? "No Error" : "Error");
+
        return pp;
 }
 
@@ -431,7 +464,7 @@ int usb_printer_init(void)
        if (usb_register(&printer_driver))
                return -1;
 
-       printk(KERN_INFO "USB Printer support registered.\n");
+       printk(KERN_INFO "USB Printer driver registered.\n");
        return 0;
 }
 
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
new file mode 100644 (file)
index 0000000..ac36743
--- /dev/null
@@ -0,0 +1,516 @@
+/* -*- linux-c -*- */
+
+/* 
+ * Driver for USB Scanners (linux-2.3.33)
+ *
+ * David E. Nelson (dnelson@jump.net)
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
+ *
+ * History
+ *  0.1  8/31/1999
+ *
+ *    Developed/tested using linux-2.3.15 with minor ohci.c changes to
+ *    support short packes during bulk xfer mode.  Some testing was
+ *    done with ohci-hcd but the performace was low.  Very limited
+ *    testing was performed with uhci but I was unable to get it to
+ *    work.  Initial relase to the linux-usb development effort.
+ *
+ *  0.2  10/16/1999
+ *
+ *    FIXED:
+ *    - Device can't be opened unless a scanner is plugged into the USB.
+ *    - Finally settled on a reasonable value for the I/O buffer's.
+ *    - Cleaned up write_scanner()
+ *    - Disabled read/write stats
+ *    - A little more code cleanup
+ *
+ *  0.3  10/18/1999
+ *
+ *    FIXED:
+ *    - Device registration changed to reflect new device
+ *      allocation/registration for linux-2.3.22+.
+ *    - Adopted David Brownell's <david-b@pacbell.net> technique for 
+ *      assigning bulk endpoints.
+ *    - Removed unnessesary #include's
+ *    - Scanner model now reported via syslog INFO after being detected 
+ *      *and* configured.
+ *    - Added user specified verdor:product USB ID's which can be passed 
+ *      as module parameters.
+ *
+ *  0.3.1
+ *    FIXED:
+ *    - Applied patches for linux-2.3.25.
+ *    - Error number reporting changed to reflect negative return codes.
+ *
+ *  0.3.2
+ *    FIXED:
+ *    - Applied patches for linux-2.3.26 to scanner_init().
+ *    - Debug read/write stats now report values as signed decimal.
+ *
+ *
+ *  0.3.3
+ *    FIXED:
+ *    - Updated the bulk_msg() calls to usb usb_bulk_msg().
+ *    - Added a small delay in the write_scanner() method to aid in
+ *      avoiding NULL data reads on HP scanners.  We'll see how this works.
+ *    - Return values from usb_bulk_msg() now ignore positive values for
+ *      use with the ohci driver.
+ *    - Added conditional debugging instead of commenting/uncommenting
+ *      all over the place.
+ *    - kfree()'d the pointer after using usb_string() as documented in
+ *      linux-usb-api.txt.
+ *    - Added usb_set_configuration().  It got lost in version 0.3 -- ack!
+ *    - Added the HP 5200C USB Vendor/Product ID's
+ *
+ *  TODO
+ *    - Simultaneous multiple device attachment
+ *    - ioctl()'s ?
+ *
+ *  Thanks to:
+ *    - All the folks on the linux-usb list who put up with me. :)  This 
+ *      has been a great learning experience for me.
+ *    - To Linus Torvalds for this great OS.
+ *    - The GNU folks.
+ *    - The folks that forwarded Vendor:Product ID's to me.
+ *    - And anybody else who chimed in with reports and suggestions.
+ *
+ *  Performance:
+ *    System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner
+ *            300 dpi scan of the entire bed
+ *      24 Bit Color ~ 70 secs - 3.6 Mbit/sec
+ *       8 Bit Gray  ~ 17 secs - 4.2 Mbit/sec
+ * */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+
+#include "usb.h"
+
+// #define SCN_DBG /* Enable to print results of read/write_scanner() calls */
+// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
+// #define WR_DATA_DUMP
+
+#ifdef SCN_DBG
+#define SCN_DEBUG(X) X
+#else
+#define SCN_DEBUG(X)
+#endif
+
+#define IBUF_SIZE 32768
+#define OBUF_SIZE 4096
+
+struct hpscan_usb_data {
+       struct usb_device *hpscan_dev;
+        int isopen;            /* Not zero if the device is open */
+       int present;            /* Device is present on the bus */
+       char *obuf, *ibuf;      /* transfer buffers */
+       char iep, oep;          /* I/O Endpoints */
+};
+
+static struct hpscan_usb_data hpscan;
+
+MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
+MODULE_DESCRIPTION("USB Scanner Driver");
+
+static __u16 vendor=0, product=0;
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+static int
+open_scanner(struct inode * inode, struct file * file)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       if (!hps->present) {
+               return -ENODEV;
+       }
+
+       if (!hps->hpscan_dev) {
+               return -ENODEV;
+       }
+
+       if (hps->isopen) {
+               return -EBUSY;
+       }
+
+       hps->isopen = 1;
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+static int
+close_scanner(struct inode * inode, struct file * file)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       hps->isopen = 0;
+
+       MOD_DEC_USE_COUNT;
+
+       return 0;
+}
+
+static ssize_t
+write_scanner(struct file * file, const char * buffer,
+              size_t count, loff_t *ppos)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       unsigned long copy_size;
+       unsigned long bytes_written = 0;
+       unsigned long partial;
+
+       ssize_t ret = 0;
+
+       int result = 0;
+       
+       char *obuf = hps->obuf;
+
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       while (count > 0) {
+
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               copy_size = (count > OBUF_SIZE) ? OBUF_SIZE : count;
+               
+               if (copy_from_user(hps->obuf, buffer, copy_size)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               result = usb_bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, hps->oep), obuf, copy_size, &partial, 30*HZ);
+               SCN_DEBUG(printk(KERN_DEBUG "write stats: result:%d copy_size:%lu partial:%lu\n", (int)result, copy_size, partial);)
+
+               if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
+                       printk(KERN_WARNING "write_scanner: NAK recieved.\n");
+                       ret = -ETIME;
+                       break;
+               } else if (result < 0) { /* We should not get any I/O errors */
+                       printk(KERN_WARNING "write_scanner: funky result: %d. Please notify the maintainer.\n", result);
+                       ret = -EIO;
+                       break;
+               } 
+
+#ifdef WR_DATA_DUMP
+               if (partial) {
+                       unsigned char cnt, cnt_max;
+                       cnt_max = (partial > 24) ? 24 : partial;
+                       printk(KERN_DEBUG "dump: ");
+                       for (cnt=0; cnt < cnt_max; cnt++) {
+                               printk("%X ", obuf[cnt]);
+                       }
+                       printk("\n");
+               }
+#endif
+               if (partial != copy_size) { /* Unable to write complete amount */
+                       ret = -EIO;
+                       break;
+               }
+
+               if (partial) { /* Data written */
+                       obuf += partial;
+                       count -= partial;
+                       bytes_written += partial;
+               } else { /* No data written */
+                       ret = 0;
+                       bytes_written = 0;
+                       break;
+               }
+       }
+//     mdelay(5);
+       set_current_state(TASK_RUNNING);
+       return ret ? ret : bytes_written;
+}
+
+static ssize_t
+read_scanner(struct file * file, char * buffer,
+             size_t count, loff_t *ppos)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       ssize_t read_count, ret = 0;
+
+       unsigned long partial;
+
+       int this_read;
+       int result;
+
+       char *ibuf = hps->ibuf;
+
+       read_count = 0;
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       while (count) {
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;
+               
+               result = usb_bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, hps->iep), ibuf, this_read, &partial, 60*HZ);
+               SCN_DEBUG(printk(KERN_DEBUG "read stats: result:%d this_read:%u partial:%lu\n", (int)result, this_read, partial);)
+
+               if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
+                       printk(KERN_WARNING "read_scanner: NAK received\n");
+                       ret = -ETIME;
+                       break;
+               } else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
+                       printk(KERN_WARNING "read_scanner: funky result: %d. Please notify the maintainer.\n", (int)result);
+                       ret = -EIO;
+                       break;
+               }
+
+#ifdef RD_DATA_DUMP
+               if (partial) {
+                       unsigned char cnt, cnt_max;
+                       cnt_max = (partial > 24) ? 24 : partial;
+                       printk(KERN_DEBUG "dump: ");
+                       for (cnt=0; cnt < cnt_max; cnt++) {
+                               printk("%X ", ibuf[cnt]);
+                       }
+                       printk("\n");
+               }
+#endif
+
+               if (partial) { /* Data returned */
+                       count = this_read = partial;
+               } else {
+                       ret = 0;
+                       read_count = 0;
+                       break;
+               }
+
+               if (this_read) {
+                       if (copy_to_user(buffer, ibuf, this_read)) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       count -= this_read;
+                       read_count += this_read;
+                       buffer += this_read;
+               }
+       }
+       set_current_state(TASK_RUNNING);
+       return ret ? ret : read_count;
+}
+
+static void *
+probe_scanner(struct usb_device *dev, unsigned int ifnum)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+       struct usb_endpoint_descriptor *endpoint;
+
+       char *ident;
+
+       hps->present = 0;
+
+       if (vendor != 0 || product != 0) {
+               printk(KERN_INFO "USB Scanner Vendor:Product - %x:%x\n", vendor, product);
+       }
+
+/* There doesn't seem to be an imaging class defined in the USB
+ * Spec. (yet).  If there is, HP isn't following it and it doesn't
+ * look like anybody else is either.  Therefore, we have to test the
+ * Vendor and Product ID's to see what we have.  This makes this
+ * driver a high maintenance driver since it has to be updated with
+ * each release of a product.  Also, other scanners may be able to use
+ * this driver but again, their Vendor and Product ID's must be added.
+ *
+ * NOTE: Just because a product is supported here does not mean that
+ * applications exist that support the product.  It's in the hopes
+ * that this will allow developers a means to produce applications
+ * that will support USB products.
+ *
+ * Until we detect a device which is pleasing, we silently punt.
+ * */
+
+       if (dev->descriptor.idVendor != 0x03f0 && /* Hewlett Packard */
+           dev->descriptor.idVendor != 0x06bd && /* AGFA */
+           dev->descriptor.idVendor != 0x1606 && /* UMAX */
+           dev->descriptor.idVendor != vendor ) { /* User specified */
+               return NULL;
+       }
+
+       if (dev->descriptor.idProduct != 0x0101 && /* HP 4100C */
+           dev->descriptor.idProduct != 0x0102 && /* HP 4200C & PhotoSmart S20? */
+           dev->descriptor.idProduct != 0x0202 && /* HP 5100C */
+           dev->descriptor.idProduct != 0x0401 && /* HP 5200C */
+           dev->descriptor.idProduct != 0x0201 && /* HP 6200C */
+           dev->descriptor.idProduct != 0x0601 && /* HP 6300C */
+           dev->descriptor.idProduct != 0x0001 && /* AGFA SnapScan 1212U */
+           dev->descriptor.idProduct != 0x0030 && /* Umax 2000U */
+           dev->descriptor.idProduct != product) { /* User specified */
+               return NULL;
+       }
+
+/* After this point we can be a little noisy about what we are trying to
+ *  configure. */
+
+       if (dev->descriptor.bNumConfigurations != 1 || 
+           dev->config[0].bNumInterfaces != 1) {
+               printk(KERN_INFO "probe_scanner: only simple configurations supported\n");
+               return NULL;
+       }
+
+       endpoint = dev->config[0].interface[0].altsetting[0].endpoint;
+
+       if (endpoint[0].bmAttributes != USB_ENDPOINT_XFER_BULK
+           || endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK) {
+               printk(KERN_INFO "probe_scanner: invalid bulk endpoints\n");
+               return NULL;
+       }
+
+       if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+                printk (KERN_INFO "probe_scanner: failed usb_set_configuration\n");
+               hps->hpscan_dev = NULL;
+                return NULL;
+        }
+
+/* By the time we get here, we should be dealing with a fairly simple
+ * device that supports at least two bulk endpoints on endpoints 1 and
+ * 2.
+ *
+ * We determine the bulk endpoints so that the read_*() and write_*()
+ * procedures can recv/send data to the correct endpoint.
+ * */
+
+       hps->iep = hps->oep = 0;
+
+       if ((endpoint[0].bEndpointAddress & 0x80) == 0x80) {
+               hps->iep = endpoint[0].bEndpointAddress & 0x7f;
+       } else {
+               hps->oep = endpoint[0].bEndpointAddress;
+       }
+
+       if ((endpoint[1].bEndpointAddress & 0x80) == 0x80) {
+               hps->iep = endpoint[1].bEndpointAddress & 0x7f;
+       } else {
+               hps->oep = endpoint[1].bEndpointAddress;
+       }
+
+       ident = usb_string(dev, dev->descriptor.iProduct); /* usb_string allocates memory using kmalloc() so kfree() needs to be called afterwards when the pointer is no longer needed. */
+       printk(KERN_INFO "USB Scanner (%s) found at address %d\n", ident, dev->devnum);
+       kfree(ident);
+
+       SCN_DEBUG(printk(KERN_DEBUG "probe_scanner: using bulk endpoints - In: %x  Out: %x\n", hps->iep, hps->oep);)
+
+       hps->present = 1;
+       hps->hpscan_dev = dev;
+
+       if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+               return NULL;
+       }
+
+       if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+               return NULL;
+       }
+
+       return hps;
+}
+
+static void
+disconnect_scanner(struct usb_device *dev, void *ptr)
+{
+       struct hpscan_usb_data *hps = (struct hpscan_usb_data *) ptr;
+
+       if (hps->isopen) {
+               /* better let it finish - the release will do whats needed */
+               hps->hpscan_dev = NULL;
+               return;
+       }
+       kfree(hps->ibuf);
+       kfree(hps->obuf);
+
+       hps->present = 0;
+}
+
+static struct
+file_operations usb_scanner_fops = {
+       NULL,           /* seek */
+       read_scanner,
+       write_scanner,
+       NULL,           /* readdir */
+       NULL,           /* poll */
+       NULL,           /* ioctl */
+       NULL,           /* mmap */
+       open_scanner,
+       NULL,           /* flush */
+       close_scanner,
+       NULL,         
+       NULL,         /* fasync */
+};
+
+static struct
+usb_driver scanner_driver = {
+       "usbscanner",
+       probe_scanner,
+       disconnect_scanner,
+       { NULL, NULL },
+       &usb_scanner_fops,
+       48
+};
+
+int
+usb_scanner_init(void)
+{
+        if (usb_register(&scanner_driver) < 0)
+                return -1;
+
+       printk(KERN_INFO "USB Scanner support registered.\n");
+       return 0;
+}
+
+
+void
+usb_scanner_cleanup(void)
+{
+       struct hpscan_usb_data *hps = &hpscan;
+
+       hps->present = 0;
+       usb_deregister(&scanner_driver);
+}
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+       return usb_scanner_init();
+}
+
+void
+cleanup_module(void)
+{
+       usb_scanner_cleanup();
+}
+#endif
+
index 2ca02e3d0af7e76145f45eb488f61425f9af4e10..9b990fd2e4c5306cb1f177bf61942d4e641a6e2f 100644 (file)
@@ -12,7 +12,7 @@
  * (C) Copyright 1999 Johannes Erdfelt
  * (C) Copyright 1999 Randy Dunlap
  *
- * $Id: uhci.c,v 1.139 1999/12/17 17:50:59 fliegl Exp $
+ * $Id: uhci.c,v 1.149 1999/12/26 20:57:14 acher Exp $
  */
 
 
@@ -646,7 +646,7 @@ _static int uhci_submit_bulk_urb (purb_t purb)
        /* Build the TDs for the bulk request */
        len = purb->transfer_buffer_length;
        data = purb->transfer_buffer;
-       dbg (KERN_DEBUG MODSTR "uhci_submit_bulk_urb: len %d\n", len);
+       dbg (KERN_DEBUG MODSTR "uhci_submit_bulk_urb: pipe %x, len %d\n", pipe, len);
        
        while (len > 0) {
                int pktsze = len;
@@ -675,7 +675,7 @@ _static int uhci_submit_bulk_urb (purb_t purb)
                //dbg("insert td %p, len %i\n",td,pktsze);
 
                insert_td (s, qh, td, UHCI_PTR_DEPTH);
-
+               
                /* Alternate Data0/1 (start with Data0) */
                usb_dotoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
        }
@@ -701,8 +701,7 @@ _static int uhci_unlink_urb (purb_t purb)
        unsigned long flags=0;
        struct list_head *p;
 
-       if (!purb)              // you never know... 
-
+       if (!purb)              // you never know...
                return -1;
 
        s = (puhci_t) purb->dev->bus->hcpriv;   // get pointer to uhci struct
@@ -720,6 +719,8 @@ _static int uhci_unlink_urb (purb_t purb)
                // URB probably still in work
                purb_priv = purb->hcpriv;
                dequeue_urb (s, &purb->urb_list,1);
+               purb->status = USB_ST_URB_KILLED;       // mark urb as killed
+               
                if(!in_interrupt()) {
                        spin_unlock_irqrestore (&s->unlink_urb_lock, flags);    // allow interrupts from here
                }
@@ -757,8 +758,7 @@ _static int uhci_unlink_urb (purb_t purb)
                        delete_qh (s, qh);              // remove it physically
 
                }
-               purb->status = USB_ST_URB_KILLED;       // mark urb as killed
-
+               
 #ifdef _UHCI_SLAB
                kmem_cache_free(urb_priv_kmem, purb->hcpriv);
 #else
@@ -872,11 +872,13 @@ _static int iso_find_start (purb_t purb)
                                        now, purb->start_frame, purb->number_of_packets, purb->pipe);
                                {
                                        puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
-                                       struct list_head *p = s->urb_list.next;
+                                       struct list_head *p;
                                        purb_t u;
                                        int a = -1, b = -1;
                                        unsigned long flags;
+
                                        spin_lock_irqsave (&s->urb_list_lock, flags);
+                                       p=s->urb_list.next;
 
                                        for (; p != &s->urb_list; p = p->next) {
                                                u = list_entry (p, urb_t, urb_list);
@@ -1093,9 +1095,10 @@ _static int search_dev_ep (puhci_t s, purb_t purb)
                // we can accept this urb if it is not queued at this time 
                // or if non-iso transfer requests should be scheduled for the same device and pipe
                if ((usb_pipetype (purb->pipe) != PIPE_ISOCHRONOUS &&
-                    tmp->dev == purb->dev && tmp->pipe == purb->pipe) || (purb == tmp))
+                    tmp->dev == purb->dev && tmp->pipe == purb->pipe) || (purb == tmp)) {
+                       spin_unlock_irqrestore (&s->urb_list_lock, flags);
                        return 1;       // found another urb already queued for processing
-
+               }
        }
 
        spin_unlock_irqrestore (&s->urb_list_lock, flags);
@@ -1122,7 +1125,7 @@ _static int uhci_submit_urb (purb_t purb)
 
        if (search_dev_ep (s, purb)) {
                usb_dec_dev_use (purb->dev);
-               return -ENXIO;  // no such address
+               return -ENXIO;  // urb already queued
 
        }
 
@@ -1379,7 +1382,7 @@ _static int rh_submit_urb (purb_t purb)
        for (i = 0; i < 8; i++)
                uhci->rh.c_p_r[i] = 0;
 
-       dbg (KERN_DEBUG MODSTR "Root-Hub: adr: %2x cmd(%1x): %04 %04 %04 %04\n",
+       dbg(KERN_DEBUG MODSTR "Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x\n",
             uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
 
        switch (bmRType_bReq) {
@@ -1519,7 +1522,7 @@ _static int rh_submit_urb (purb_t purb)
        }
 
 
-       dbg (KERN_DEBUG MODSTR "Root-Hub stat port1: %x port2: %x \n",
+       printk (KERN_DEBUG MODSTR "Root-Hub stat port1: %x port2: %x \n",
             inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
 
        purb->actual_length = len;
@@ -1681,27 +1684,32 @@ _static int process_transfer (puhci_t s, purb_t purb)
                        uhci_show_td (desc);    // show first TD of each transfer
 #endif
 
-               // go into error condition to keep data_toggle unchanged if short packet occurs
-               if ((purb->transfer_flags & USB_DISABLE_SPD) && (actual_length < maxlength)) {
-                       ret = USB_ST_SHORT_PACKET;
-                       printk (KERN_DEBUG MODSTR "process_transfer: SPD!!\n");
-                       break;  // exit after this TD because SP was detected
+               // got less data than requested
+               if ( (actual_length < maxlength)) {
+                       if (purb->transfer_flags & USB_DISABLE_SPD) {
+                               ret = USB_ST_SHORT_PACKET;      // treat as real error
+                               printk (KERN_DEBUG MODSTR "process_transfer: SPD!!\n");
+                               break;  // exit after this TD because SP was detected
+                       }
 
+                       // short read during control-IN: re-start status stage
+                       if ((usb_pipetype (purb->pipe) == PIPE_CONTROL)) {
+                               if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) {
+                                       uhci_show_td (last_desc);
+                                       qh->hw.qh.element = virt_to_bus (last_desc);  // re-trigger status stage
+                                       printk("uhci: short packet during control transfer, retrigger status stage @ %p\n",last_desc);
+                                       purb_priv->short_control_packet=1;
+                                       return 0;
+                               }
+                       }
+                       // all other cases: short read is OK
+                       data_toggle = uhci_toggle (desc->hw.td.info);
+                       break;
                }
 
                data_toggle = uhci_toggle (desc->hw.td.info);
                //printk(KERN_DEBUG MODSTR"process_transfer: len:%d status:%x mapped:%x toggle:%d\n", actual_length, desc->hw.td.status,status, data_toggle);      
-#if 1
-               if ((usb_pipetype (purb->pipe) == PIPE_CONTROL) && (actual_length < maxlength)) {
-                       if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) {
-                               uhci_show_td (last_desc);
-                               qh->hw.qh.element = virt_to_bus (last_desc);  // re-trigger status stage
-                               printk("uhci: short packet during control transfer, retrigger status stage\n");
-                               purb_priv->short_control_packet=1;
-                               return 0;
-                       }
-               }
-#endif
+
        }
        usb_settoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe), !data_toggle);
        transfer_finished:
@@ -1714,15 +1722,14 @@ _static int process_transfer (puhci_t s, purb_t purb)
                status & TD_CTRL_NAK )
        {
                ret=0;
-               purb->status=0;
+               status=0;
        }
 
        unlink_qh (s, qh);
        delete_qh (s, qh);
 
        purb->status = status;
-       
-                                                                               
+                                                               
        dbg(KERN_DEBUG MODSTR"process_transfer: urb %p, wanted len %d, len %d status %x err %d\n",
                purb,purb->transfer_buffer_length,purb->actual_length, purb->status, purb->error_count);
        //dbg(KERN_DEBUG MODSTR"process_transfer: exit\n");
@@ -1748,21 +1755,15 @@ _static int process_interrupt (puhci_t s, purb_t purb)
        {
                desc = list_entry (p, uhci_desc_t, desc_list);
 
-               if (desc->hw.td.status & TD_CTRL_NAK) {
-                       // NAKed transfer
-                       //printk("TD NAK Status @%p %08x\n",desc,desc->hw.td.status);
-                       goto err;
-               }
-
                if (desc->hw.td.status & TD_CTRL_ACTIVE) {
                        // do not process active TDs
                        //printk("TD ACT Status @%p %08x\n",desc,desc->hw.td.status);
-                       goto err;
+                       break;
                }
 
                if (!desc->hw.td.status & TD_CTRL_IOC) {
-                       // do not process one-shot TDs
-                       goto err;
+                       // do not process one-shot TDs, no recycling
+                       break;
                }
                // extract transfer parameters from TD
 
@@ -1778,7 +1779,7 @@ _static int process_interrupt (puhci_t s, purb_t purb)
                // if any error occured: ignore this td, and continue
                if (status != USB_ST_NOERROR) {
                        purb->error_count++;
-                       goto err;
+                       goto recycle;
                }
                else
                        purb->actual_length = actual_length;
@@ -1794,7 +1795,7 @@ _static int process_interrupt (puhci_t s, purb_t purb)
                        purb->complete ((struct urb *) purb);
                        purb->status = USB_ST_URB_PENDING;
                }
-
+       recycle:
                // Recycle INT-TD if interval!=0, else mark TD as one-shot
                if (purb->interval) {
                        desc->hw.td.status |= TD_CTRL_ACTIVE;
@@ -1804,10 +1805,9 @@ _static int process_interrupt (puhci_t s, purb_t purb)
                        usb_dotoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));
                }
                else {
-                       desc->hw.td.status &= ~TD_CTRL_IOC;
+                       desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
                }
-
-             err:
+       err:
        }
 
        return ret;
@@ -1882,10 +1882,12 @@ _static int process_iso (puhci_t s, purb_t purb)
 _static int process_urb (puhci_t s, struct list_head *p)
 {
        int ret = USB_ST_NOERROR;
-       purb_t purb = list_entry (p, urb_t, urb_list);
-       spin_lock(&s->urb_list_lock);
+       purb_t purb;
 
+       spin_lock(&s->urb_list_lock);
+       purb=list_entry (p, urb_t, urb_list);
        dbg ( /*KERN_DEBUG */ MODSTR "found queued urb: %p\n", purb);
+
        switch (usb_pipetype (purb->pipe)) {
        case PIPE_CONTROL:
        case PIPE_BULK:
@@ -1933,7 +1935,7 @@ _static int process_urb (puhci_t s, struct list_head *p)
                        if (purb->complete && (!proceed || (purb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
                                dbg (KERN_DEBUG MODSTR "process_transfer: calling early completion\n");
                                purb->complete ((struct urb *) purb);
-                               if (!proceed && is_ring)
+                               if (!proceed && is_ring && (purb->status != USB_ST_URB_KILLED))
                                        uhci_submit_urb (purb);
                        }
 
@@ -1942,7 +1944,7 @@ _static int process_urb (puhci_t s, struct list_head *p)
                                tmp = purb->next;       // pointer to first urb
 
                                do {
-                                       if ((tmp->status != USB_ST_URB_PENDING) && uhci_submit_urb (tmp) != USB_ST_NOERROR)
+                                       if ((tmp->status != USB_ST_URB_PENDING) && (tmp->status != USB_ST_URB_KILLED) && uhci_submit_urb (tmp) != USB_ST_NOERROR)
                                                break;
                                        tmp = tmp->next;
                                }
@@ -2160,6 +2162,7 @@ _static int __init alloc_uhci (int irq, unsigned int io_addr, unsigned int io_si
        start_hc (s);
 
        if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
+               printk(MODSTR KERN_ERR"request_irq %d failed!\n",irq);
                usb_free_bus (bus);
                reset_hc (s);
                release_region (s->io_addr, s->io_size);
@@ -2204,9 +2207,6 @@ _static int __init start_uhci (struct pci_dev *dev)
                /* Is it already in use? */
                if (check_region (io_addr, io_size))
                        break;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
-               pci_enable_device (dev);
-#endif
                /* disable legacy emulation */
                pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
 
@@ -2297,10 +2297,21 @@ int __init uhci_init (void)
                if (type != 0)
                        continue;
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
+               pci_enable_device (dev);
+#endif
+               if(!dev->irq)
+               {
+                       printk(KERN_ERR MODSTR"Found UHCI device with no IRQ assigned. Check BIOS settings!\n");
+                       continue;
+               }
+
                /* Ok set it up */
                retval = start_uhci (dev);
+       
                if (!retval)
                        i++;
+
        }
 
 #ifdef CONFIG_APM
index 1c87124f74221f2ecb9f9f9ecdaf907d3efe55ea..f6ab99776d6a8e678496bc0e93e59df90fe27182 100644 (file)
@@ -43,8 +43,8 @@ int usb_init(void)
 #      ifdef CONFIG_USB_MOUSE
                usb_mouse_init();
 #      endif
-#       ifdef CONFIG_USB_HP_SCANNER
-                usb_hp_scanner_init();
+#       ifdef CONFIG_USB_SCANNER
+                usb_scanner_init();
 #       endif
 #      ifdef CONFIG_USB_KBD
                usb_kbd_init();
@@ -92,8 +92,8 @@ void cleanup_drivers(void)
 #      ifdef CONFIG_USB_MOUSE
                usb_mouse_cleanup();
 #      endif
-#       ifdef CONFIG_USB_HP_SCANNER
-                usb_hp_scanner_cleanup();
+#       ifdef CONFIG_USB_SCANNER
+                usb_scanner_cleanup();
 #       endif
 #      ifdef CONFIG_USB_DABUSB
                dabusb_cleanup();
index b076e82e65e2dc869563d5f63ea39c07017b5e44..fae15aa479dcd45f6fc1cf2f6e172af507b8da23 100644 (file)
@@ -15,7 +15,7 @@
  * It should be considered a slave, with no callbacks. Callbacks
  * are evil.
  *
- * $Id: usb.c,v 1.37 1999/12/17 10:48:08 fliegl Exp $
+ * $Id: usb.c,v 1.39 1999/12/27 15:17:47 acher Exp $
  */
 
 #ifndef EXPORT_SYMTAB
 #define MODSTR "usbcore: "
 
 #ifdef USB_DEBUG
-       #define dbg printk
+       #define dbg(format, arg...) printk(format, ## arg)
 #else
-       #define dbg nix
-static void nix(const char *format, ...)
-{
-}
+       #define dbg(format, arg...)
 #endif
 
 /*
index e544298e4d22a670331ebed1f035570499f7f0a2..5b4d46f6e0cbeb7337bf49f5fda7103d164b2d16 100644 (file)
@@ -179,6 +179,16 @@ struct usb_proc_setinterface {
 
 #define USB_MAJOR 180
 
+extern int usb_hub_init(void);
+extern int usb_kbd_init(void);
+extern int usb_cpia_init(void);
+extern int usb_dc2xx_init(void);
+extern int usb_mouse_init(void);
+extern int usb_printer_init(void);
+
+extern void usb_hub_cleanup(void);
+extern void usb_mouse_cleanup(void);
+
 /* for 2.2-kernels */
  
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
@@ -217,8 +227,8 @@ typedef struct wait_queue *wait_queue_head_t;
 
 static __inline__ void wait_ms(unsigned int ms)
 {
-        current->state = TASK_UNINTERRUPTIBLE;
-        schedule_timeout(1 + ms * HZ / 1000);
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout(1 + ms * HZ / 1000);
 }
 
 typedef struct {
@@ -361,7 +371,7 @@ struct usb_interface {
        int num_altsetting;             /* number of alternate settings */
        int max_altsetting;             /* total memory allocated */
  
-        struct usb_driver *driver;     /* driver */
+       struct usb_driver *driver;      /* driver */
        void *private_data;
 };
 
@@ -465,35 +475,35 @@ typedef struct urb
 
 #define FILL_CONTROL_URB(a,aa,b,c,d,e,f,g) \
     do {\
-       a->dev=aa;\
-       a->pipe=b;\
-       a->setup_packet=c;\
-       a->transfer_buffer=d;\
-       a->transfer_buffer_length=e;\
-       a->complete=f;\
-       a->context=g;\
+       (a)->dev=aa;\
+       (a)->pipe=b;\
+       (a)->setup_packet=c;\
+       (a)->transfer_buffer=d;\
+       (a)->transfer_buffer_length=e;\
+       (a)->complete=f;\
+       (a)->context=g;\
     } while (0)
 
 #define FILL_BULK_URB(a,aa,b,c,d,e,f) \
     do {\
-       a->dev=aa;\
-       a->pipe=b;\
-       a->transfer_buffer=c;\
-       a->transfer_buffer_length=d;\
-       a->complete=e;\
-       a->context=f;\
+       (a)->dev=aa;\
+       (a)->pipe=b;\
+       (a)->transfer_buffer=c;\
+       (a)->transfer_buffer_length=d;\
+       (a)->complete=e;\
+       (a)->context=f;\
     } while (0)
     
 #define FILL_INT_URB(a,aa,b,c,d,e,f,g) \
     do {\
-       a->dev=aa;\
-       a->pipe=b;\
-       a->transfer_buffer=c;\
-       a->transfer_buffer_length=d;\
-       a->complete=e;\
-       a->context=f;\
-       a->interval=g;\
-       a->start_frame=-1;\
+       (a)->dev=aa;\
+       (a)->pipe=b;\
+       (a)->transfer_buffer=c;\
+       (a)->transfer_buffer_length=d;\
+       (a)->complete=e;\
+       (a)->context=f;\
+       (a)->interval=g;\
+       (a)->start_frame=-1;\
     } while (0)
 
 purb_t usb_alloc_urb(int iso_packets);
@@ -551,7 +561,6 @@ struct usb_bus {
        int bandwidth_isoc_reqs;        /* number of Isoc. requesters */
 
        /* procfs entry */
-       int proc_busnum;
        struct proc_dir_entry *proc_entry;
 };
 
index 150e1c95b044b1ba7bfd8bfa694df9db401ab42e..5919ef6f382425c8a66a94e1dace987916692959 100644 (file)
@@ -29,6 +29,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'EFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS
 fi
 
+tristate 'Compressed ROM filessytem support' CONFIG_CRAMFS
 tristate 'ISO 9660 CDROM filesystem support' CONFIG_ISO9660_FS
 if [ "$CONFIG_ISO9660_FS" != "n" ]; then
    bool '  Microsoft Joliet CDROM extensions' CONFIG_JOLIET
index 9f085aa21fc5a180d05d916832a2a98a5176b37e..eadd9e16c38329cc041a9f7efa26c35f7df1d92d 100644 (file)
@@ -7,18 +7,18 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile.
 
-L_TARGET := filesystems.a
-L_OBJS    = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
+FILESYSTEMS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
 O_TARGET := fs.o
 O_OBJS    = open.o read_write.o devices.o file_table.o buffer.o \
                super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
                ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
-               dcache.o inode.o attr.o bad_inode.o file.o iobuf.o $(BINFMTS) 
+               dcache.o inode.o attr.o bad_inode.o file.o iobuf.o \
+               $(BINFMTS) $(FILESYSTEMS)
 
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
                hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
-               nfsd nls devpts adfs partitions qnx4 udf bfs openpromfs
+               nfsd nls devpts adfs partitions qnx4 udf bfs cramfs openpromfs
 
 SUB_DIRS := partitions
 
@@ -28,6 +28,22 @@ else
 O_OBJS += noquot.o
 endif
 
+ifeq ($(CONFIG_EXT2_FS),y)
+SUB_DIRS += ext2
+else
+  ifeq ($(CONFIG_EXT2_FS),m)
+  MOD_SUB_DIRS += ext2
+  endif
+endif
+
+ifeq ($(CONFIG_CRAMFS),y)
+SUB_DIRS += cramfs
+else
+  ifeq ($(CONFIG_CRAMFS),m)
+  MOD_SUB_DIRS += cramfs
+  endif
+endif
+
 ifeq ($(CONFIG_CODA_FS),y)
 SUB_DIRS += coda
 else
@@ -44,14 +60,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_EXT2_FS),y)
-SUB_DIRS += ext2
-else
-  ifeq ($(CONFIG_EXT2_FS),m)
-  MOD_SUB_DIRS += ext2
-  endif
-endif
-
 ifeq ($(CONFIG_FAT_FS),y)
 SUB_DIRS += fat
 else
diff --git a/fs/cramfs/Makefile b/fs/cramfs/Makefile
new file mode 100644 (file)
index 0000000..64ae14b
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux cramfs routines.
+#
+
+O_TARGET := cramfs.o
+
+O_OBJS := inode.o uncompress.o inflate/zlib.o
+
+include $(TOPDIR)/Rules.make
+
+inflate/zlib.o:
+       make -C inflate
diff --git a/fs/cramfs/cramfs.h b/fs/cramfs/cramfs.h
new file mode 100644 (file)
index 0000000..e98cd73
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __CRAMFS_H
+#define __CRAMFS_H
+
+#define CRAMFS_MAGIC           0x28cd3d45      /* some random number */
+#define CRAMFS_SIGNATURE       "Compressed ROMFS"
+
+/*
+ * Reasonably terse representation of the inode
+ * data.. When the mode of the inode indicates
+ * a special device node, the "offset" bits will
+ * encode i_rdev. In other cases, "offset" points
+ * to the ROM image for the actual file data
+ * (whether that data be directory or compressed
+ * file data depends on the inode type again)
+ */
+struct cramfs_inode {
+       u32 mode:16, uid:16;
+       u32 size:24, gid:8;
+       u32 namelen:6, offset:26;
+};
+
+/*
+ * Superblock information at the beginning of the FS.
+ */
+struct cramfs_super {
+       u32 magic;              /* 0x28cd3d45 - random number */
+       u32 size;               /* > offset, < 2**26 */
+       u32 flags;              /* 0 */
+       u32 future;             /* 0 */
+       u8 signature[16];       /* "Compressed ROMFS" */
+       u8 fsid[16];            /* random number */
+       u8 name[16];            /* user-defined name */
+       struct cramfs_inode root;       /* Root inode data */
+};
+
+/* Uncompression interfaces to the underlying zlib */
+int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen);
+int cramfs_uncompress_init(void);
+int cramfs_uncompress_exit(void);
+
+#endif
diff --git a/fs/cramfs/inflate/Makefile b/fs/cramfs/inflate/Makefile
new file mode 100644 (file)
index 0000000..294c36c
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# inflate/Makefile
+#
+#
+# NOTE NOTE NOTE!
+#
+# This code is basically a bastardized version of the zlib
+# library uncompression. It avoids dynamic allocations at
+# all cost, and is cut down in other ways too, to make it
+# simpler and more specialized. If you want to get the real
+# thing, don't look here.
+#
+# The simplifications mean that this version of the library
+# (unlike the real lib) is completely single-threaded, and
+# you cannot do multiple uncompressions at a time. You can
+# ONLY use it to uncompress a single block, with both the
+# source and the destination completely in memory. In SMP
+# environments, the uncompression has to be protected by
+# some lock to guarantee single-threaded access to the static
+# data structures used for inflation.
+#
+# You have been warned.
+#
+# (The upsides of the simplification is that you can't get in
+# any nasty situations wrt memory management, and that the
+# uncompression can be done without blocking on allocation).
+#
+
+OBJECTFILES=adler32.o infblock.o infcodes.o inffast.o inflate.o inftrees.o infutil.o uncompr.o
+
+zlib.o: $(OBJECTFILES)
+       ld -r -o zlib.o $(OBJECTFILES)
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/cramfs/inflate/adler32.c b/fs/cramfs/inflate/adler32.c
new file mode 100644 (file)
index 0000000..16cf9a7
--- /dev/null
@@ -0,0 +1,48 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+           buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+           s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
diff --git a/fs/cramfs/inflate/infblock.c b/fs/cramfs/inflate/infblock.c
new file mode 100644 (file)
index 0000000..1266f90
--- /dev/null
@@ -0,0 +1,379 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (c != Z_NULL)
+    *c = s->check;
+  if (s->mode == CODES)
+    inflate_codes_free(s->sub.decode.codes, z);
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+  Tracev((stderr, "inflate:   blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+  static struct inflate_blocks_state working_blocks_state;
+  static inflate_huft working_hufts[MANY];
+  static unsigned char working_window[1 << MAX_WBITS];
+
+  s = &working_blocks_state;
+  s->hufts = working_hufts;
+  s->window = working_window;
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Tracev((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, Z_NULL);
+  return s;
+}
+
+
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Tracev((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Tracev((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BAD;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = BAD;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      memcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BAD;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      {
+       static unsigned int working_blens [258 + 0x1f + 0x1f];
+       s->sub.trees.blens = working_blens;
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, s->hufts, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BAD;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->bits;
+        c = h->base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            s->mode = BAD;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td,
+                                  s->hufts, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BAD;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        s->sub.decode.codes = c;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONE;
+    case DONE:
+      r = Z_STREAM_END;
+      LEAVE
+    case BAD:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_blocks_reset(s, z, Z_NULL);
+  Tracev((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  memcpy(s->window, d, n);
+  s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
+ * IN assertion: s != Z_NULL
+ */
+int inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+  return s->mode == LENS;
+}
diff --git a/fs/cramfs/inflate/infblock.h b/fs/cramfs/inflate/infblock.h
new file mode 100644 (file)
index 0000000..bd25c80
--- /dev/null
@@ -0,0 +1,39 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+extern int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+extern void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+extern void inflate_set_dictionary OF((
+    inflate_blocks_statef *s,
+    const Bytef *d,  /* dictionary */
+    uInt  n));       /* dictionary length */
+
+extern int inflate_blocks_sync_point OF((
+    inflate_blocks_statef *s));
diff --git a/fs/cramfs/inflate/infcodes.c b/fs/cramfs/inflate/infcodes.c
new file mode 100644 (file)
index 0000000..c6aea52
--- /dev/null
@@ -0,0 +1,256 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  inflate_codes_mode mode;      /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+  static inflate_codes_statef memory_allocation;
+
+  c = &memory_allocation;
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      if (k > 7)        /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;            /* can always return one */
+      }
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+  Tracev((stderr, "inflate:       codes free\n"));
+}
diff --git a/fs/cramfs/inflate/infcodes.h b/fs/cramfs/inflate/infcodes.h
new file mode 100644 (file)
index 0000000..6c750d8
--- /dev/null
@@ -0,0 +1,27 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+extern int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+extern void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
diff --git a/fs/cramfs/inflate/inffast.c b/fs/cramfs/inflate/inffast.c
new file mode 100644 (file)
index 0000000..61a78ee
--- /dev/null
@@ -0,0 +1,170 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (uInt)(q - s->window); /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+          {
+            t += t->base;
+            e = (t += ((uInt)b & inflate_mask[e]))->exop;
+          }
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        t += t->base;
+        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
diff --git a/fs/cramfs/inflate/inffast.h b/fs/cramfs/inflate/inffast.h
new file mode 100644 (file)
index 0000000..8facec5
--- /dev/null
@@ -0,0 +1,17 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+extern int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_streamp ));
diff --git a/fs/cramfs/inflate/inffixed.h b/fs/cramfs/inflate/inffixed.h
new file mode 100644 (file)
index 0000000..77f7e76
--- /dev/null
@@ -0,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+  };
+local inflate_huft fixed_td[] = {
+    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+  };
diff --git a/fs/cramfs/inflate/inflate.c b/fs/cramfs/inflate/inflate.c
new file mode 100644 (file)
index 0000000..2a16085
--- /dev/null
@@ -0,0 +1,335 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+
+typedef enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  inflate_mode  mode;   /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+  Tracev((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z);
+  z->state = Z_NULL;
+  Tracev((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  static struct internal_state internal_state;
+
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream))
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+  z->state = &internal_state;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Tracev((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+  return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Tracev((stderr, "inflate: zlib header ok\n"));
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+        break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r == Z_OK)
+        r = f;
+      if (r != Z_STREAM_END)
+        return r;
+      r = f;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Tracev((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+int ZEXPORT inflateSync(z)
+z_streamp z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    static const Byte mark[4] = {0, 0, 0xff, 0xff};
+    if (*p == mark[m])
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+    return Z_STREAM_ERROR;
+  return inflate_blocks_sync_point(z->state->blocks);
+}
diff --git a/fs/cramfs/inflate/inftrees.c b/fs/cramfs/inflate/inftrees.c
new file mode 100644 (file)
index 0000000..250c883
--- /dev/null
@@ -0,0 +1,392 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+const char inflate_copyright[] =
+   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+struct internal_state  {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    inflate_huft *,     /* space for trees */
+    uInt *,             /* hufts used in space */
+    uIntf * ));         /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 288) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+inflate_huft *hp;       /* space for trees */
+uInt *hn;               /* hufts used in space */
+uIntf *v;               /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+   lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                     /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = g - w;
+        z = z > (uInt)l ? l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate new table */
+        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
+          return Z_MEM_ERROR;   /* not enough memory */
+        u[h] = q = hp + *hn;
+        *hn += z;
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          j = i >> (w - l);
+          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+        else
+          *t = q;               /* first table is returned result */
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
+      while ((i & mask) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+        mask = (1 << w) - 1;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+  static unsigned int work_area[19];
+
+  v = work_area;
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+                 tb, bb, hp, &hn, v);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+  static unsigned int work_area[288];
+
+  /* allocate work area */
+  v = work_area;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#include "inffixed.h"
+
+
+int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+z_streamp z;             /* for memory allocation */
+{
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
diff --git a/fs/cramfs/inflate/inftrees.h b/fs/cramfs/inflate/inftrees.h
new file mode 100644 (file)
index 0000000..85853e0
--- /dev/null
@@ -0,0 +1,58 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
+  uInt base;            /* literal, length base, distance base,
+                           or table offset */
+};
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1004 huft structures (850 for length/literals
+   and 154 for distances, the latter actually the result of an
+   exhaustive search).  The actual maximum is not known, but the
+   value below is more than safe. */
+#define MANY 1440
+
+extern int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_streamp));                /* for memory allocation */
diff --git a/fs/cramfs/inflate/infutil.c b/fs/cramfs/inflate/infutil.c
new file mode 100644 (file)
index 0000000..23b6d96
--- /dev/null
@@ -0,0 +1,87 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  memcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    memcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
diff --git a/fs/cramfs/inflate/infutil.h b/fs/cramfs/inflate/infutil.h
new file mode 100644 (file)
index 0000000..99d1135
--- /dev/null
@@ -0,0 +1,98 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONE,     /* finished last block, done */
+      BAD}      /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  mode;     /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  inflate_huft *hufts;  /* single malloc for tree space */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+struct internal_state      {int dummy;}; /* for buggy compilers */
+
+#endif
diff --git a/fs/cramfs/inflate/uncompr.c b/fs/cramfs/inflate/uncompr.c
new file mode 100644 (file)
index 0000000..45eb47b
--- /dev/null
@@ -0,0 +1,55 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/fs/cramfs/inflate/zconf.h b/fs/cramfs/inflate/zconf.h
new file mode 100644 (file)
index 0000000..adc70c2
--- /dev/null
@@ -0,0 +1,90 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+#if defined(__GNUC__) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+
+#if defined(__STDC__) || defined(__cplusplus)
+#  ifndef STDC
+#    define STDC
+#  endif
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  define MAX_MEM_LEVEL 9
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef FAR
+#   define FAR
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+typedef Byte  FAR Bytef;
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+typedef void FAR *voidpf;
+typedef void     *voidp;
+
+#include <sys/types.h> /* for off_t */
+#include <unistd.h>    /* for SEEK_* and off_t */
+#define z_off_t  off_t
+
+#endif /* _ZCONF_H */
diff --git a/fs/cramfs/inflate/zlib.h b/fs/cramfs/inflate/zlib.h
new file mode 100644 (file)
index 0000000..f359379
--- /dev/null
@@ -0,0 +1,893 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.3, July 9th, 1998
+
+  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.3"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func nozalloc;  /* used to allocate the internal state */
+    free_func  nozfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/* 
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/* 
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may some
+  introduce some output latency (reading input without producing any output)
+  except when forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+  output as possible to the output buffer. The flushing behavior of inflate is
+  not specified for values of the flush parameter other than Z_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
+  it sets strm->adler to the adler32 checksum of all output produced
+  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+  an error code as described below. At the end of the stream, inflate()
+  checks that its computed adler32 checksum is equal to that saved by the
+  compressor and returns Z_STREAM_END only if the checksum is correct.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect
+  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+  case, the application may then call inflateSync to look for a good
+  compression block.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+                            
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                     int level,
+                                     int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+/*   
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. If a compressed stream with a larger window size is given as
+   input, inflate() will return with the error code Z_DATA_ERROR instead of
+   trying to allocate a larger window.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least 0.1% larger than
+   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h". (See the description
+   of deflateInit2 for more information about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file, 
+                                  const voidp buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                     z_off_t offset, int whence));
+/* 
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running crc with the bytes buf[0..len-1] and return the updated
+   crc. If buf is NULL, this function returns the required initial value
+   for the crc. Pre- and post-conditioning (one's complement) is performed
+   within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int err));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/fs/cramfs/inflate/zutil.h b/fs/cramfs/inflate/zutil.h
new file mode 100644 (file)
index 0000000..4816d01
--- /dev/null
@@ -0,0 +1,120 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#  include <stddef.h>
+#  include <stdlib.h>
+
+#ifdef __KERNEL__
+#  include <linux/string.h>
+#  include <linux/errno.h>
+#else
+#  include <string.h>
+#  include <errno.h>
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int z_verbose;
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+                                      uInt len));
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) ({ \
+       printf("alloc %d %d at %s:%d\n", items, size, __FILE__, __LINE__); \
+       calloc((items), (size)); })
+#define ZFREE(strm, addr)  free(addr)
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
new file mode 100644 (file)
index 0000000..0331082
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * Compressed rom filesystem for Linux.
+ *
+ * Copyright (C) 1999 Linus Torvalds.
+ *
+ * This file is released under the GPL.
+ */
+
+/*
+ * These are the VFS interfaces to the compressed rom filesystem.
+ * The actual compression is based on zlib, see the other files.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/uaccess.h>
+
+#include "cramfs.h"
+
+static struct super_operations cramfs_ops;
+static struct inode_operations cramfs_file_inode_operations;
+static struct inode_operations cramfs_dir_inode_operations;
+static struct inode_operations cramfs_symlink_inode_operations;
+
+#define CRAMINO(x)     ((x)->offset?(x)->offset<<2:1)
+
+static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
+{
+       struct inode * inode = get_empty_inode();
+
+       if (inode) {
+               inode->i_mode = cramfs_inode->mode;
+               inode->i_uid = cramfs_inode->uid;
+               inode->i_size = cramfs_inode->size;
+               inode->i_gid = cramfs_inode->gid;
+               inode->i_ino = CRAMINO(cramfs_inode);
+               inode->i_sb = sb;
+               inode->i_dev = sb->s_dev;
+               insert_inode_hash(inode);
+               if (S_ISREG(inode->i_mode))
+                       inode->i_op = &cramfs_file_inode_operations;
+               else if (S_ISDIR(inode->i_mode))
+                       inode->i_op = &cramfs_dir_inode_operations;
+               else if (S_ISLNK(inode->i_mode))
+                       inode->i_op = &cramfs_symlink_inode_operations;
+               else {
+                       inode->i_size = 0;
+                       init_special_inode(inode, inode->i_mode, cramfs_inode->size);
+               }
+       }
+       return inode;
+}
+
+/*
+ * We have our own block cache: don't fill up the buffer cache
+ * with the rom-image, because the way the filesystem is set
+ * up the accesses should be fairly regular and cached in the
+ * page cache and dentry tree anyway..
+ *
+ * This also acts as a way to guarantee contiguous areas of
+ * up to 2*PAGE_CACHE_SIZE, so that the caller doesn't need
+ * to worry about end-of-buffer issues even when decompressing
+ * a full page cache.
+ */
+#define READ_BUFFERS (2)
+static unsigned char read_buffers[READ_BUFFERS][PAGE_CACHE_SIZE*4];
+static int buffer_blocknr[READ_BUFFERS];
+static int last_buffer = 0;
+
+static void *cramfs_read(struct super_block *sb, unsigned int offset)
+{
+       struct buffer_head * bh_array[4];
+       int i, blocknr, buffer;
+
+       blocknr = offset >> PAGE_CACHE_SHIFT;
+       offset &= PAGE_CACHE_SIZE-1;
+       for (i = 0; i < READ_BUFFERS; i++) {
+               if (blocknr == buffer_blocknr[i])
+                       return read_buffers[i] + offset;
+       }
+
+       /* Ok, read in four buffers completely first */
+       for (i = 0; i < 4; i++)
+               bh_array[i] = bread(sb->s_dev, blocknr + i, PAGE_CACHE_SIZE);
+
+       /* Ok, copy them to the staging area without sleeping.. */
+       buffer = last_buffer;
+       last_buffer = buffer ^ 1;
+       buffer_blocknr[buffer] = blocknr;
+       for (i = 0; i < 4; i++) {
+               struct buffer_head * bh = bh_array[i];
+               if (bh) {
+                       memcpy(read_buffers[buffer] + i*PAGE_CACHE_SIZE, bh->b_data, PAGE_CACHE_SIZE);
+                       bforget(bh);
+               }
+               blocknr++;
+       }
+       return read_buffers[buffer] + offset;
+}
+                       
+
+static struct super_block * cramfs_read_super(struct super_block *sb, void *data, int silent)
+{
+       int i;
+       struct cramfs_super super;
+       unsigned long root_offset;
+       struct super_block * retval = NULL;
+
+       lock_super(sb);
+       set_blocksize(sb->s_dev, PAGE_CACHE_SIZE);
+       sb->s_blocksize = PAGE_CACHE_SIZE;
+       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+
+       /* Invalidate the read buffers on mount: think disk change.. */
+       for (i = 0; i < READ_BUFFERS; i++)
+               buffer_blocknr[i] = -1;
+
+       /* Read the first block and get the superblock from it */
+       memcpy(&super, cramfs_read(sb, 0), sizeof(super));
+
+       /* Do sanity checks on the superblock */
+       if (super.magic != CRAMFS_MAGIC) {
+               printk("wrong magic\n");
+               goto out;
+       }
+       if (memcmp(super.signature, CRAMFS_SIGNATURE, sizeof(super.signature))) {
+               printk("wrong signature\n");
+               goto out;
+       }
+
+       /* Check that the root inode is in a sane state */
+       root_offset = super.root.offset << 2;
+       if (root_offset < sizeof(struct cramfs_super)) {
+               printk("root offset too small\n");
+               goto out;
+       }
+       if (root_offset >= super.size) {
+               printk("root offset too large (%lu %u)\n", root_offset, super.size);
+               goto out;
+       }
+       if (!S_ISDIR(super.root.mode)) {
+               printk("root is not a directory\n");
+               goto out;
+       }
+
+       /* Set it all up.. */
+       sb->s_op        = &cramfs_ops;
+       sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root));
+       retval = sb;
+
+out:
+       unlock_super(sb);
+       return retval;
+}
+
+/* Nothing to do.. */
+static void cramfs_put_super(struct super_block *sb)
+{
+       return;
+}
+
+static int cramfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+{
+       struct statfs tmp;
+
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.f_type = CRAMFS_MAGIC;
+       tmp.f_bsize = PAGE_CACHE_SIZE;
+       tmp.f_blocks = 0;
+       tmp.f_namelen = 255;
+       return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
+}
+
+/*
+ * Read a cramfs directory entry..
+ *
+ * Remember: the inode number is the byte offset of the start
+ * of the directory..
+ */
+static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       unsigned int offset;
+       int copied;
+
+       /* Offset within the thing.. */
+       offset = filp->f_pos;
+       if (offset >= inode->i_size)
+               return 0;
+       /* Directory entries are always 4-byte aligned */
+       if (offset & 3)
+               return -EINVAL;
+
+       copied = 0;
+       while (offset < inode->i_size) {
+               struct cramfs_inode *de;
+               unsigned long nextoffset;
+               char *name;
+               int namelen, error;
+
+               de = cramfs_read(sb, offset + inode->i_ino);
+               name = (char *)(de+1);
+
+               /*
+                * Namelengths on disk are shifted by two
+                * and the name padded out to 4-byte boundaries
+                * with zeroes.
+                */
+               namelen = de->namelen << 2;
+               nextoffset = offset + sizeof(*de) + namelen;
+               for (;;) {
+                       if (!namelen)
+                               return -EIO;
+                       if (name[namelen-1])
+                               break;
+                       namelen--;
+               }
+               error = filldir(dirent, name, namelen, offset, CRAMINO(de));
+               if (error)
+                       break;
+
+               offset = nextoffset;
+               filp->f_pos = offset;
+               copied++;
+       }
+       return 0;
+}
+
+/*
+ * Lookup and fill in the inode data..
+ */
+static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry)
+{
+       unsigned int offset = 0;
+
+       while (offset < dir->i_size) {
+               struct cramfs_inode *de;
+               char *name;
+               int namelen;
+
+               de = cramfs_read(dir->i_sb, offset + dir->i_ino);
+               name = (char *)(de+1);
+               namelen = de->namelen << 2;
+               offset += sizeof(*de) + namelen;
+
+               /* Quick check that the name is roughly the right length */
+               if (((dentry->d_name.len + 3) & ~3) != namelen)
+                       continue;
+
+               for (;;) {
+                       if (!namelen)
+                               return ERR_PTR(-EIO);
+                       if (name[namelen-1])
+                               break;
+                       namelen--;
+               }
+               if (namelen != dentry->d_name.len)
+                       continue;
+               if (memcmp(dentry->d_name.name, name, namelen))
+                       continue;
+               d_add(dentry, get_cramfs_inode(dir->i_sb, de));
+               return NULL;
+       }
+       d_add(dentry, NULL);
+       return NULL;
+}
+
+static int cramfs_readpage(struct dentry *dentry, struct page * page)
+{
+       struct inode *inode = dentry->d_inode;
+       unsigned long maxblock, bytes;
+
+       maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       bytes = 0;
+       if (page->index < maxblock) {
+               struct super_block *sb = inode->i_sb;
+               unsigned long block_offset = inode->i_ino + page->index*4;
+               unsigned long start_offset = inode->i_ino + maxblock*4;
+               unsigned long end_offset;
+
+               end_offset = *(u32 *) cramfs_read(sb, block_offset);
+               if (page->index)
+                       start_offset = *(u32 *) cramfs_read(sb, block_offset-4);
+
+               bytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
+               if (page->index < maxblock)
+                       bytes = PAGE_CACHE_SIZE;
+
+               cramfs_uncompress_block((void *) page_address(page), PAGE_CACHE_SIZE, cramfs_read(sb, start_offset), end_offset - start_offset);
+       }
+       memset((void *) (page_address(page) + bytes), 0, PAGE_CACHE_SIZE - bytes);
+       SetPageUptodate(page);
+       UnlockPage(page);
+       return 0;
+}
+
+static struct page *get_symlink_page(struct dentry *dentry)
+{
+       return read_cache_page(&dentry->d_inode->i_data, 0, (filler_t *)cramfs_readpage, dentry);
+}
+
+static int cramfs_readlink(struct dentry *dentry, char *buffer, int len)
+{
+       struct inode *inode = dentry->d_inode;
+       int retval;
+
+       if (!inode || !S_ISLNK(inode->i_mode))
+               return -EBADF;
+
+       retval = inode->i_size;
+       if (retval) {
+               int len;
+               struct page *page = get_symlink_page(dentry);
+
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+               wait_on_page(page);
+               len = retval;
+               retval = -EIO;
+               if (Page_Uptodate(page)) {
+                       retval = -EFAULT;
+                       if (!copy_to_user(buffer, (void *) page_address(page), len))
+                               retval = len;
+               }
+               page_cache_release(page);
+       }
+       return retval;
+}
+
+static struct dentry *cramfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
+{
+       struct page *page = get_symlink_page(dentry);
+       struct dentry *result;
+
+       if (IS_ERR(page)) {
+               dput(base);
+               return ERR_PTR(PTR_ERR(page));
+       }
+
+       result = lookup_dentry((void *) page_address(page), base, follow);
+       page_cache_release(page);
+       return result;
+}
+
+/*
+ * Our operations:
+ *
+ * A regular file can be read and mmap'ed.
+ */
+static struct file_operations cramfs_file_operations = {
+       NULL,                   /* lseek - default */
+       generic_file_read,      /* read */
+       NULL,                   /* write - bad */
+       NULL,                   /* readdir */
+       NULL,                   /* poll - default */
+       NULL,                   /* ioctl */
+       generic_file_mmap,      /* mmap */
+       NULL,                   /* open */
+       NULL,                   /* flush */
+       NULL,                   /* release */
+       NULL,                   /* fsync */
+       NULL,                   /* fasync */
+       NULL,                   /* check_media_change */
+       NULL                    /* revalidate */
+};
+
+/*
+ * A directory can only readdir
+ */
+static struct file_operations cramfs_directory_operations = {
+       NULL,                   /* lseek - default */
+       NULL,                   /* read */
+       NULL,                   /* write - bad */
+       cramfs_readdir,         /* readdir */
+       NULL,                   /* poll - default */
+       NULL,                   /* ioctl */
+       NULL,                   /* mmap */
+       NULL,                   /* open */
+       NULL,                   /* flush */
+       NULL,                   /* release */
+       NULL,                   /* fsync */
+       NULL,                   /* fasync */
+       NULL,                   /* check_media_change */
+       NULL                    /* revalidate */
+};
+
+static struct inode_operations cramfs_file_inode_operations = {
+       &cramfs_file_operations,
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* get_block */
+       cramfs_readpage,        /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* truncate */
+       NULL,                   /* permission */
+       NULL                    /* revalidate */
+};
+
+static struct inode_operations cramfs_dir_inode_operations = {
+       &cramfs_directory_operations,
+       NULL,                   /* create */
+       cramfs_lookup,          /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* get_block */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* truncate */
+       NULL,                   /* permission */
+       NULL                    /* revalidate */
+};
+
+static struct inode_operations cramfs_symlink_inode_operations = {
+       NULL,                   /* symlinks do not have files */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       cramfs_readlink,                /* readlink */
+       cramfs_follow_link,     /* follow_link */
+       NULL,                   /* get_block */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* truncate */
+       NULL,                   /* permission */
+       NULL                    /* revalidate */
+};
+
+static struct super_operations cramfs_ops = {
+       NULL,                   /* read inode */
+       NULL,                   /* write inode */
+       NULL,                   /* put inode */
+       NULL,                   /* delete inode */
+       NULL,                   /* notify change */
+       cramfs_put_super,               /* put super */
+       NULL,                   /* write super */
+       cramfs_statfs,          /* statfs */
+       NULL                    /* remount */
+};
+
+static struct file_system_type cramfs_fs_type = {
+       "cramfs",
+       FS_REQUIRES_DEV,
+       cramfs_read_super,
+       NULL
+};
+
+static int __init init_cramfs_fs(void)
+{
+       cramfs_uncompress_init();
+       return register_filesystem(&cramfs_fs_type);
+}
+
+static void __exit exit_cramfs_fs(void)
+{
+       cramfs_uncompress_exit();
+       unregister_filesystem(&cramfs_fs_type);
+}
+
+module_init(init_cramfs_fs)
+module_exit(exit_cramfs_fs)
diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c
new file mode 100644 (file)
index 0000000..8e92eb1
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * uncompress.c
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * cramfs interfaces to the uncompression library. There's really just
+ * three entrypoints:
+ *
+ *  - cramfs_uncompress_init() - called to initialize the thing.
+ *  - cramfs_uncompress_exit() - tell me when you're done
+ *  - cramfs_uncompress_block() - uncompress a block.
+ *
+ * NOTE NOTE NOTE! The uncompression is entirely single-threaded. We
+ * only have one stream, and we'll initialize it only once even if it
+ * then is used by multiple filesystems.
+ */
+
+#include <linux/kernel.h>
+
+#include "inflate/zlib.h"
+
+static z_stream stream;
+static int initialized = 0;
+
+int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen)
+{
+       int err;
+
+       stream.next_in = src;
+       stream.avail_in = srclen;
+
+       stream.next_out = dst;
+       stream.avail_out = dstlen;
+
+       inflateReset(&stream);
+
+       err = inflate(&stream, Z_FINISH);
+       if (err != Z_STREAM_END) {
+               printk("Error %d while decompressing!\n", err);
+               printk("%p(%d)->%p(%d)\n", src, srclen, dst, dstlen);
+       }
+       return stream.total_out;
+}
+
+int cramfs_uncompress_init(void)
+{
+       if (!initialized++) {
+               stream.next_in = NULL;
+               stream.avail_in = 0;
+               inflateInit(&stream);
+       }
+       return 0;
+}
+
+int cramfs_uncompress_exit(void)
+{
+       if (!--initialized)
+               inflateEnd(&stream);
+       return 0;
+}
index dadd3c67efb5e616c8193184c582ce47aa2b1cd8..11f99b4dc2917012229fb76ce69abce8cfbea482 100644 (file)
@@ -723,33 +723,6 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
        return 0;
 }
 
-static struct file_system_type ext2_fs_type = {
-       "ext2", 
-       FS_REQUIRES_DEV /* | FS_IBASKET */,     /* ibaskets have unresolved bugs */
-        ext2_read_super, 
-       NULL
-};
-
-int __init init_ext2_fs(void)
-{
-        return register_filesystem(&ext2_fs_type);
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-int init_module(void)
-{
-       return init_ext2_fs();
-}
-
-void cleanup_module(void)
-{
-        unregister_filesystem(&ext2_fs_type);
-}
-
-#endif
-
 int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
 {
        unsigned long overhead;
@@ -805,3 +778,25 @@ int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
        tmp.f_namelen = EXT2_NAME_LEN;
        return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
+
+static struct file_system_type ext2_fs_type = {
+       "ext2", 
+       FS_REQUIRES_DEV /* | FS_IBASKET */,     /* ibaskets have unresolved bugs */
+        ext2_read_super, 
+       NULL
+};
+
+static int __init init_ext2_fs(void)
+{
+        return register_filesystem(&ext2_fs_type);
+}
+
+static int __exit exit_ext2_fs(void)
+{
+       unregister_filesystem(&ext2_fs_type);
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_ext2_fs)
+module_exit(exit_ext2_fs)
index 9470aae3b9a3cbf927c5f245517886ebbc80c90b..42056c7b96f5a3a93747c0a5fb7da4f7e4df1fa1 100644 (file)
@@ -54,10 +54,6 @@ extern int init_devpts_fs(void);
 
 void __init filesystem_setup(void)
 {
-#ifdef CONFIG_EXT2_FS
-       init_ext2_fs();
-#endif
-
 #ifdef CONFIG_MINIX_FS
        init_minix_fs();
 #endif
diff --git a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h
new file mode 100644 (file)
index 0000000..a0deca1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * $Id: irq_control.h,v 1.8 1999/09/15 23:58:48 cort Exp $
+ *
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ */
+#ifndef _PPC_HW_IRQ_H
+#define _PPC_HW_IRQ_H
+
+#if 0
+/* Structure describing interrupts */
+struct hw_interrupt_type {
+       const char * typename;
+       void (*startup)(unsigned int irq);
+       void (*shutdown)(unsigned int irq);
+       void (*enable)(unsigned int irq);
+       void (*disable)(unsigned int irq);
+       void (*mask_and_ack)(unsigned int irq);
+       int irq_offset;
+};
+
+struct irqdesc {
+       struct irqaction *action;
+       struct hw_interrupt_type *ctl;
+};
+#endif
+
+struct int_control_struct
+{
+       void (*int_cli)(void);
+       void (*int_sti)(void);
+       void (*int_restore_flags)(unsigned long);
+       void (*int_save_flags)(unsigned long *);
+};
+extern struct int_control_struct int_control;
+extern unsigned long timer_interrupt_intercept;
+extern unsigned long do_IRQ_intercept;
+void timer_interrupt(struct pt_regs *);
+
+extern void __no_use_sti(void);
+extern void __no_use_cli(void);
+extern void __no_use_restore_flags(unsigned long);
+extern void __no_use_save_flags(unsigned long *);
+
+#define __cli() int_control.int_cli()
+#define __sti() int_control.int_sti()
+#define __save_flags(flags) int_control.int_save_flags(&flags)
+#define __restore_flags(flags) int_control.int_restore_flags(flags)
+#define __save_and_cli(flags) ({__save_flags(flags);__cli();})
+
+extern void do_lost_interrupts(unsigned long);
+extern atomic_t ppc_n_lost_interrupts;
+
+#define mask_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->disable) irq_desc[irq].handler->disable(irq);})
+#define unmask_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->enable) irq_desc[irq].handler->enable(irq);})
+#define mask_and_ack_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->ack) irq_desc[irq].handler->ack(irq);})
+
+#endif /* _PPC_HW_IRQ_H */
diff --git a/include/asm-ppc/irq_control.h b/include/asm-ppc/irq_control.h
deleted file mode 100644 (file)
index 5a79e3e..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * $Id: irq_control.h,v 1.8 1999/09/15 23:58:48 cort Exp $
- *
- * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
- */
-#ifndef _PPC_IRQ_CONTROL_H
-#define _PPC_IRQ_CONTROL_H
-
-#include <asm/irq.h>
-#include <asm/atomic.h>
-
-/* Structure describing interrupts */
-struct hw_interrupt_type {
-       const char * typename;
-       void (*startup)(unsigned int irq);
-       void (*shutdown)(unsigned int irq);
-       void (*enable)(unsigned int irq);
-       void (*disable)(unsigned int irq);
-       void (*mask_and_ack)(unsigned int irq);
-       int irq_offset;
-};
-
-struct irqdesc {
-       struct irqaction *action;
-       struct hw_interrupt_type *ctl;
-};
-
-extern struct irqdesc irq_desc[NR_IRQS];
-
-struct int_control_struct
-{
-       void (*int_cli)(void);
-       void (*int_sti)(void);
-       void (*int_restore_flags)(unsigned long);
-       void (*int_save_flags)(unsigned long *);
-};
-extern struct int_control_struct int_control;
-extern unsigned long timer_interrupt_intercept;
-extern unsigned long do_IRQ_intercept;
-void timer_interrupt(struct pt_regs *);
-
-extern void __no_use_sti(void);
-extern void __no_use_cli(void);
-extern void __no_use_restore_flags(unsigned long);
-extern void __no_use_save_flags(unsigned long *);
-
-#define __cli() int_control.int_cli()
-#define __sti() int_control.int_sti()
-#define __save_flags(flags) int_control.int_save_flags(&flags)
-#define __restore_flags(flags) int_control.int_restore_flags(flags)
-#define __save_and_cli(flags) ({__save_flags(flags);__cli();})
-
-extern void do_lost_interrupts(unsigned long);
-extern atomic_t ppc_n_lost_interrupts;
-
-#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
-#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
-#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
-
-#endif /* _PPC_IRQ_CONTROL_H */
index f6b2013ad6387569d0077d2a947689c78a04c914..d567a997502923226eb59c2eafced05cb7bd0ba5 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <asm/processor.h>
 #include <asm/atomic.h>
-#include <asm/irq_control.h>
+#include <asm/hw_irq.h>
 
 /*
  * Memory barrier.
index 6b2e724f669c99b25cf58f7974ae839acfee1b8b..d4609a9a8a201d635a896e9ffceded235704aea6 100644 (file)
 #define __NR_putpmsg           188     /* some people actually want streams */
 #define __NR_vfork             189
 #define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
+#define __NR_mmap2             192
+#define __NR_truncate64                193
+#define __NR_ftruncate64       194
+#define __NR_stat64            195
+#define __NR_lstat64           196
+#define __NR_fstat64           197
 
 #define __NR(n)        #n
 
diff --git a/scripts/cramfs/mkcramfs.c b/scripts/cramfs/mkcramfs.c
new file mode 100644 (file)
index 0000000..af4ce30
--- /dev/null
@@ -0,0 +1,349 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* zlib required.. */
+#include <zlib.h>
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+#include "cramfs.h"
+
+#define PAGE_CACHE_SIZE (4096)
+
+static const char *progname = "mkcramfs";
+
+void usage(void)
+{
+       fprintf(stderr, "Usage: '%s dirname outfile'\n"
+               " where <dirname> is the root of the\n"
+               " filesystem to be compressed.\n", progname);
+       exit(1);
+}
+
+struct entry {
+       /* stats */
+       char *name;
+       unsigned int mode, size, uid, gid;
+
+       /* FS data */
+       void *uncompressed;
+       unsigned int dir_offset;        /* Where in the archive is the directory entry? */
+       unsigned int data_offset;       /* Where in the archive is the start of the data? */
+
+       /* organization */
+       struct entry *child;
+       struct entry *next;
+};
+
+/*
+ * We should mind about memory leaks and
+ * checking for out-of-memory.
+ *
+ * We don't.
+ */
+static unsigned int parse_directory(const char *name, struct entry **prev)
+{
+       DIR *dir;
+       int count = 0, totalsize = 0;
+       struct dirent *dirent;
+       char *path, *endpath;
+       int len = strlen(name);
+
+       dir = opendir(name);
+       if (!dir) {
+               perror(name);
+               exit(2);
+       }
+       /* Set up the path.. */
+       path = malloc(4096);
+       memcpy(path, name, len);
+       endpath = path + len;
+       *endpath = '/';
+       endpath++;
+
+       while ((dirent = readdir(dir)) != NULL) {
+               struct entry *entry;
+               struct stat st;
+               int fd, size;
+
+               /* Ignore "." and ".." - we won't be adding them to the archive */
+               if (dirent->d_name[0] == '.') {
+                       if (dirent->d_name[1] == '\0')
+                               continue;
+                       if (dirent->d_name[1] == '.') {
+                               if (dirent->d_name[2] == '\0')
+                                       continue;
+                       }
+               }
+               strcpy(endpath, dirent->d_name);
+
+               if (lstat(path, &st) < 0) {
+                       perror(endpath);
+                       continue;
+               }
+               entry = calloc(1, sizeof(struct entry));
+               entry->name = strdup(dirent->d_name);
+               entry->mode = st.st_mode;
+               entry->size = st.st_size;
+               entry->uid = st.st_uid;
+               entry->gid = st.st_gid;
+               size = sizeof(struct cramfs_inode) + (~3 & (strlen(entry->name) + 3));
+               if (S_ISDIR(st.st_mode)) {
+                       entry->size = parse_directory(path, &entry->child);
+               } else if (S_ISREG(st.st_mode)) {
+                       int fd = open(path, O_RDONLY);
+                       if (fd < 0) {
+                               perror(path);
+                               continue;
+                       }
+                       if (entry->size)
+                               entry->uncompressed = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+                       if (-1 == (int) (long) entry->uncompressed) {
+                               perror("mmap");
+                               exit(5);
+                       }
+                       close(fd);
+               } else if (S_ISLNK(st.st_mode)) {
+                       entry->uncompressed = malloc(st.st_size);
+                       if (readlink(path, entry->uncompressed, st.st_size) < 0) {
+                               perror(path);
+                               continue;
+                       }
+               } else {
+                       entry->size = st.st_rdev;
+               }
+
+               /* Link it into the list */
+               *prev = entry;
+               prev = &entry->next;
+               count++;
+               totalsize += size;
+       }
+       closedir(dir);
+       free(path);
+       return totalsize;
+}
+
+static void set_random(void *area, int size)
+{
+       int fd = open("/dev/random", O_RDONLY);
+
+       if (fd >= 0) {
+               if (read(fd, area, size) == size)
+                       return;
+       }
+       memset(area, 0x00, size);
+}
+
+static unsigned int write_superblock(struct entry *root, char *base)
+{
+       struct cramfs_super *super = (struct cramfs_super *) base;
+       unsigned int offset = sizeof(struct cramfs_super);
+
+       super->magic = CRAMFS_MAGIC;
+       super->flags = 0;
+       super->size = 0x10000;
+       memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
+       set_random(super->fsid, sizeof(super->fsid));
+       strncpy(super->name, "Compressed", sizeof(super->name));
+
+       super->root.mode = root->mode;
+       super->root.uid = root->uid;
+       super->root.gid = root->gid;
+       super->root.size = root->size;
+       super->root.offset = offset >> 2;
+
+       return offset;
+}
+
+static void set_data_offset(struct entry *entry, char *base, unsigned long offset)
+{
+       struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
+       inode->offset = (offset >> 2);
+}
+
+
+/*
+ * We do a width-first printout of the directory
+ * entries, using a stack to remember the directories
+ * we've seen.
+ */
+#define MAXENTRIES (100)
+static int stack_entries = 0;
+static struct entry *entry_stack[MAXENTRIES];
+
+static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset)
+{
+       for (;;) {
+               while (entry) {
+                       struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset);
+                       int len = strlen(entry->name);
+
+                       entry->dir_offset = offset;
+                       offset += sizeof(struct cramfs_inode);
+
+                       inode->mode = entry->mode;
+                       inode->uid = entry->uid;
+                       inode->gid = entry->gid;
+                       inode->size = entry->size;
+                       inode->offset = 0;      /* Fill in later */
+
+                       memcpy(base + offset, entry->name, len);
+                       /* Pad up the name to a 4-byte boundary */
+                       while (len & 3) {
+                               *(base + offset + len) = '\0';
+                               len++;
+                       }
+                       inode->namelen = len >> 2;
+                       offset += len;
+
+                       printf("  %s\n", entry->name);
+
+                       if (entry->child) {
+                               entry_stack[stack_entries] = entry;
+                               stack_entries++;
+                       }
+                       entry = entry->next;
+               }
+               if (!stack_entries)
+                       break;
+               stack_entries--;
+               entry = entry_stack[stack_entries];
+
+               set_data_offset(entry, base, offset);
+               printf("'%s':\n", entry->name);
+               entry = entry->child;
+       }
+       return offset;
+}
+
+/*
+ * One 4-byte pointer per block and then the actual blocked
+ * output. The first block does not need an offset pointer,
+ * as it will start immediately after the pointer block.
+ *
+ * Note that size > 0, as a zero-sized file wouldn't ever
+ * have gotten here in the first place.
+ */
+static unsigned int do_compress(char *base, unsigned int offset, char *uncompressed, unsigned int size)
+{
+       unsigned long original_size = size;
+       unsigned long original_offset = offset;
+       unsigned long new_size;
+       unsigned long blocks = (size - 1) / PAGE_CACHE_SIZE + 1;
+       unsigned long curr = offset + 4 * blocks;
+       int change;
+
+       do {
+               unsigned int input = size;
+               unsigned long len = 8192;
+               if (input > PAGE_CACHE_SIZE)
+                       input = PAGE_CACHE_SIZE;
+               compress(base + curr, &len, uncompressed, input);
+               uncompressed += input;
+               size -= input;
+               curr += len;
+
+               if (len > PAGE_CACHE_SIZE*2) {
+                       printf("AIEEE: block expanded to > 2*blocklength (%d)\n", len);
+                       exit(1);
+               }
+
+               *(u32 *) (base + offset) = curr;
+               offset += 4;
+       } while (size);
+
+       new_size = curr - original_offset;
+       change = new_size - original_size;
+       printf("%4.2f %% (%d bytes)\n", (change * 100) / (double) original_size, change);
+
+       return (curr + 3) & ~3;
+}
+
+static unsigned int write_data(struct entry *entry, char *base, unsigned int offset)
+{
+       do {
+               if (entry->uncompressed) {
+                       set_data_offset(entry, base, offset);
+                       offset = do_compress(base, offset, entry->uncompressed, entry->size);
+               }
+               if (entry->child)
+                       offset = write_data(entry->child, base, offset);
+               entry = entry->next;
+       } while (entry);
+       return offset;
+}
+
+/* This is the maximum rom-image you can create */
+#define MAXROM (64*1024*1024)
+
+/*
+ * Usage:
+ *
+ *      mkcramfs directory-name
+ *
+ * where "directory-name" is simply the root of the directory
+ * tree that we want to generate a compressed filesystem out
+ * of..
+ */
+int main(int argc, char **argv)
+{
+       struct stat st;
+       struct entry *root_entry;
+       char *rom_image;
+       unsigned int offset, written;
+       int fd;
+
+       if (argc)
+               progname = argv[0];
+       if (argc != 3)
+               usage();
+
+       if (stat(argv[1], &st) < 0) {
+               perror(argv[1]);
+               exit(1);
+       }
+       fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+       root_entry = calloc(1, sizeof(struct entry));
+       root_entry->mode = st.st_mode;
+       root_entry->uid = st.st_uid;
+       root_entry->gid = st.st_gid;
+       root_entry->name = "";
+
+       root_entry->size = parse_directory(argv[1], &root_entry->child);
+
+       rom_image = mmap(NULL, MAXROM, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+       if (-1 == (int) (long) rom_image) {
+               perror("ROM image map");
+               exit(1);
+       }
+       offset = write_superblock(root_entry, rom_image);
+       printf("Super block: %d bytes\n", offset);
+
+       offset = write_directory_structure(root_entry->child, rom_image, offset);
+       printf("Directory data: %d bytes\n", offset);
+
+       offset = write_data(root_entry, rom_image, offset);
+       printf("Everything: %d bytes\n", offset);
+
+       written = write(fd, rom_image, offset);
+       if (written < 0) {
+               perror("rom image");
+               exit(1);
+       }
+       if (offset != written) {
+               fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset);
+               exit(1);
+       }
+       return 0;
+}