- Revert TCP delayed ACK fix, and fix correctly.2.1.90pre3
authorLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:55 +0000 (23 15:14 -0500)
committerLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:55 +0000 (23 15:14 -0500)
  We should not send an ack if we don't have any pending
  (in which case the DACK timer will be set)     (Dave Miller)

101 files changed:
Documentation/Changes
Documentation/Configure.help
Documentation/sysctl/vm.txt
arch/i386/kernel/head.S
arch/i386/kernel/io_apic.c
arch/i386/kernel/ioport.c
arch/i386/kernel/irq.h
arch/i386/kernel/process.c
arch/i386/kernel/trampoline.S
arch/sparc/mm/init.c
arch/sparc64/kernel/traps.c
arch/sparc64/mm/init.c
drivers/block/raid5.c
drivers/char/Config.in
drivers/char/ftape/zftape/zftape-read.c
drivers/char/ftape/zftape/zftape-write.c
drivers/char/rtc.c
drivers/net/ipddp.c
drivers/net/ipddp.h
drivers/net/ppp.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_obsolete.c
drivers/scsi/scsi_queue.c
drivers/sound/Config.in
drivers/sound/Makefile
drivers/sound/ad1848.c
drivers/sound/bin2hex.c
drivers/sound/cs4232.c
drivers/sound/dmabuf.c
drivers/sound/dmabuf.c.old[deleted file]
drivers/sound/gus_card.c
drivers/sound/hex2hex.c
drivers/sound/maui.c
drivers/sound/mpu401.c
drivers/sound/opl3.c
drivers/sound/pas2_card.c
drivers/sound/pss.c
drivers/sound/sb_audio.c
drivers/sound/sb_card.c
drivers/sound/sb_common.c
drivers/sound/sound_calls.h
drivers/sound/sound_timer.c
drivers/sound/soundcard.c
drivers/sound/uart401.c
drivers/sound/uart6850.c
drivers/sound/v_midi.c
fs/buffer.c
fs/exec.c
fs/hfs/ChangeLog
fs/hfs/Makefile
fs/hfs/catalog.c
fs/hfs/dir.c
fs/hfs/dir_cap.c
fs/hfs/dir_dbl.c
fs/hfs/dir_nat.c
fs/hfs/file.c
fs/hfs/file_cap.c
fs/hfs/file_hdr.c
fs/hfs/hfs.h
fs/hfs/inode.c
fs/hfs/string.c
fs/hfs/super.c
fs/hfs/sysdep.c
fs/hfs/version.c
include/asm-i386/page.h
include/linux/hfs_fs.h
include/linux/hfs_fs_i.h
include/linux/hfs_sysdep.h
include/linux/swap.h
include/linux/swapctl.h
include/linux/sysctl.h
include/net/sock.h
include/net/tcp.h
init/main.c
ipc/msg.c
kernel/fork.c
kernel/sysctl.c
mm/swap.c
mm/vmscan.c
net/802/sysctl_net_802.c
net/802/tr.c
net/appletalk/ddp.c
net/ax25/af_ax25.c
net/core/iovec.c
net/ipv4/proc.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/timer.c
net/ipv4/udp.c
net/ipv6/proc.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/netrom/af_netrom.c
net/netsyms.c
net/packet/af_packet.c
net/rose/af_rose.c
net/unix/af_unix.c

index 6f778a2..29dc474 100644 (file)
@@ -148,7+148,7 @@ in some standard tools.  Check in /proc/net/rt_local to verify their
 presence.
 
    To turn on IP forwarding, issue the following command:   echo 1 >
-/proc/sys/net/ipv4/ip_forwarding
+/proc/sys/net/ipv4/ip_forward
 
    To run bootpd, you'll need to issue the following command:   echo 1
 >/proc/sys/net/ipv4/ip_boot_agent
index efe2dc3..edf25b0 100644 (file)
@@ -6571,12+6571,6 @@ CONFIG_JOYSTICK
   be called joystick.o. If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-ARC console time
-CONFIG_RTC_ARC
-  If you boot your Alpha using the ARC firmware, say Y here. This option
-  adjusts the RTC clock to take into account the different starting epoch
-  used by ARC.
-
 Sound card support
 CONFIG_SOUND
   If you have a Sound Card in your Computer, i.e. if it can say more
@@ -6612,6+6606,16 @@ CONFIG_SB
   an unknown card you may answer Y if the card claims to be
   SoundBlaster compatible.
 
+Are you using the IBM Mwave "emulation" of SB ?
+CONFIG_SB_MWAVE
+  The IBM Mwave can do whats loosely describable as emulation of an 8bit
+  soundblaster if you load the right firmware from DOS warm boot and pray
+  and your machine happens to like you. Say Y if you are doing this as the
+  IRQ test normally fails on the mwave emulation. If you'd like real MWAVE
+  support phone IBM (425-556-8822) and ask them why they still haven't 
+  released any documentation.
+  [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html]
+
 Generic OPL2/OPL3 FM synthesizer support
 CONFIG_ADLIB
   Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
index a9f5d90..818d00f 100644 (file)
@@ -16,6+16,7 @@ usage.
 
 Currently, these files are in /proc/sys/vm:
 - bdflush
+- buffermem
 - freepages
 - overcommit_memory
 - swapctl
@@ -88,11+89,27 @@ number of jiffies per second is 100, except on Alpha machines
 age_super is for filesystem metadata.
 
 ==============================================================
+buffermem:
+
+The three values in this file correspond to the values in
+the struct buffer_mem. It controls how much memory should
+be used for buffer and cache memory. Note that memorymapped
+files are also counted as cache memory...
+
+The values are:
+min_percent    -- this is the minumum percentage of memory
+                  that should be spent on buffer + page cache
+borrow_percent  -- when Linux is short on memory, and buffer
+                   and cache use more than this percentage of
+                   memory, free pages are stolen from them
+max_percent     -- this is the maximum amount of memory that
+                   can be used for buffer and cache memory 
 
+==============================================================
 freepages:
 
-This file contains three values: min_free_pages, free_pages_low
-and free_pages_high in order.
+This file contains the values in the struct freepages. That
+struct contains three members: min, low and high.
 
 These numbers are used by the VM subsystem to keep a reasonable
 number of pages on the free page list, so that programs can
@@ -100,25+117,23 @@ allocate new pages without having to wait for the system to
 free used pages first. The actual freeing of pages is done
 by kswapd, a kernel daemon.
 
-min_free_pages  -- when the number of free pages reaches this
-                   level, only the kernel can allocate memory
-                   for _critical_ tasks only
-free_pages_low  -- when the number of free pages drops below
-                   this level, kswapd is woken up immediately
-free_pages_high -- this is kswapd's target, when more than
-                   free_pages_high pages are free, kswapd will
-                   stop swapping.
+min  -- when the number of free pages reaches this
+        level, only the kernel can allocate memory
+        for _critical_ tasks only
+low  -- when the number of free pages drops below
+        this level, kswapd is woken up immediately
+high -- this is kswapd's target, when more than <high>
+        pages are free, kswapd will stop swapping.
 
-When the number of free pages is between free_pages_low and
-free_pages_high, and kswapd hasn't run for swapout_interval
-jiffies, then kswapd is woken up too. See swapout_interval
-for more info.
+When the number of free pages is between low and high,
+and kswapd hasn't run for swapout_interval jiffies, then
+kswapd is woken up too. See swapout_interval for more info.
 
 When free memory is always low on your system, and kswapd has
 trouble keeping up with allocations, you might want to
-increase these values, especially free_pages_high and perhaps
-free_pages_low. I've found that a 1:2:4 relation for these
-values tend to work rather well in a heavily loaded system.
+increase these values, especially high and perhaps low.
+I've found that a 1:2:4 relation for these values tend to work
+rather well in a heavily loaded system.
 
 ==============================================================
 
@@ -163,9+178,7 @@ static inline int vm_enough_memory(long pages)
 
 swapctl:
 
-This file contains no less than 16 variables, of which about
-half is actually used :-) In the listing below, the unused
-variables are marked as such.
+This file contains no less than 8 variables.
 All of these values are used by kswapd, and the usage can be
 found in linux/mm/vmscan.c.
 
@@ -177,18+190,10 @@ typedef struct swap_control_v5
     unsigned int    sc_page_advance;
     unsigned int    sc_page_decline;
     unsigned int    sc_page_initial_age;
-    unsigned int    sc_max_buff_age;      /* unused */
-    unsigned int    sc_buff_advance;      /* unused */
-    unsigned int    sc_buff_decline;      /* unused */
-    unsigned int    sc_buff_initial_age;  /* unused */
     unsigned int    sc_age_cluster_fract;
     unsigned int    sc_age_cluster_min;
     unsigned int    sc_pageout_weight;
     unsigned int    sc_bufferout_weight;
-    unsigned int    sc_buffer_grace;      /* unused */
-    unsigned int    sc_nr_buffs_to_free;  /* unused */
-    unsigned int    sc_nr_pages_to_free;  /* unused */
-    enum RCL_POLICY sc_policy;            /* RCL_PERSIST hardcoded */
 } swap_control_v5;
 --------------------------------------------------------------
 
@@ -207,9+212,8 @@ is adjusted according to the following scheme:
   (default 1)
 And when a page reaches age 0, it's ready to be swapped out.
 
-The variables sc_age_cluster_fract till sc_bufferout_weight
-have to do with the amount of scanning kswapd is doing on
-each call to try_to_swap_out().
+The next four variables can be used to control kswapd's
+agressiveness in swapping out pages.
 
 sc_age_cluster_fract is used to calculate how many pages from
 a process are to be scanned by kswapd. The formula used is
@@ -221,9+225,12 @@ also scan small processes.
 
 The values of sc_pageout_weight and sc_bufferout_weight are
 used to control the how many tries kswapd will do in order
-to swapout one page / buffer. As with sc_age_cluster_fract,
-the actual value is calculated by several more or less complex
-formulae and the default value is good for every purpose.
+to swapout one page / buffer. These values can be used to
+finetune the ratio between user pages and buffer/cache memory.
+When you find that your Linux system is swapping out too much
+process pages in order to satisfy buffer memory demands, you
+might want to either increase sc_bufferout_weight, or decrease
+the value of sc_pageout_weight.
 
 ==============================================================
 
index 8e9f4e1..0489218 100644 (file)
@@ -8,7+8,6 @@
  */
 
 .text
-#include <linux/config.h>
 #include <linux/tasks.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
index 799561b..219e7f8 100644 (file)
@@ -513,7+513,7 @@ void print_IO_APIC (void)
        return;
 }
 
-void init_sym_mode (void)
+static void init_sym_mode (void)
 {
        printk("enabling Symmetric IO mode ... ");
                outb (0x70, 0x22);
@@ -521,6+521,14 @@ void init_sym_mode (void)
        printk("...done.\n");
 }
 
+void init_pic_mode (void)
+{
+       printk("disabling Symmetric IO mode ... ");
+               outb (0x70, 0x22);
+               outb (0x00, 0x23);
+       printk("...done.\n");
+}
+
 char ioapic_OEM_ID [16];
 char ioapic_Product_ID [16];
 
index 9bb1500..44fd265 100644 (file)
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/stddef.h>
 
 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
 static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
@@ -53,12+54,25 @@ static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_
  */
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
+       struct thread_struct * t = &current->tss;
+
        if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
                return -EINVAL;
        if (!suser())
                return -EPERM;
+       /*
+        * If it's the first ioperm() call in this thread's lifetime, set the
+        * IO bitmap up. ioperm() is much less timing critical than clone(),
+        * this is why we delay this operation until now:
+        */
+#define IO_BITMAP_OFFSET offsetof(struct thread_struct,io_bitmap)
+
+       if (t->bitmap != IO_BITMAP_OFFSET) {
+               t->bitmap = IO_BITMAP_OFFSET;
+               memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4);
+       }
                
-       set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
+       set_bitmap((unsigned long *)t->io_bitmap, from, num, !turn_on);
        return 0;
 }
 
index d77474e..9824026 100644 (file)
@@ -1,10+1,9 @@
 #ifndef __irq_h
 #define __irq_h
 
-#include <linux/config.h>
-
 /*
- * Various low-level irq details needed by irq.c and smp.c
+ * Various low-level irq details needed by irq.c, process.c,
+ * time.c, io_apic.c and smp.c
  *
  * Interrupt entry/exit code at both C and assembly level
  */
@@ -20,6+19,7 @@ void init_IO_APIC_traps(void);
 int IO_APIC_get_PCI_irq_vector (int bus, int slot, int fn);
 void make_8259A_irq (unsigned int irq);
 void send_IPI (int dest, int vector);
+void init_pic_mode (void);
 
 extern unsigned int io_apic_irqs;
 
index 27702c8..e7aa2f4 100644 (file)
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
+#include "irq.h"
 
 #ifdef __SMP__
 asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork");
@@ -280,6+281,12 @@ static inline void kb_wait(void)
 
 void machine_restart(char * __unused)
 {
+#if __SMP__
+       /*
+        * turn off the IO-APIC, so we can do a clean reboot
+        */
+       init_pic_mode();
+#endif
 
        if(!reboot_thru_bios) {
                /* rebooting needs to touch the page at absolute addr 0 */
@@ -510,9+517,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
                set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512);
        else
                set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1);
-       p->tss.bitmap = offsetof(struct thread_struct,io_bitmap);
-       for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
-               p->tss.io_bitmap[i] = ~0;
+       /*
+        * a bitmap offset pointing outside of the TSS limit causes a nicely
+        * controllable SIGSEGV. The first sys_ioperm() call sets up the
+        * bitmap properly.
+        */
+       p->tss.bitmap = sizeof(struct thread_struct);
+
        if (last_task_used_math == current)
                __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
 
index 9b32202..1f5303a 100644 (file)
  *     entries except for the gdt one..
  */
 
-#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page.h>
index 868fc21..aa85666 100644 (file)
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/swapctl.h>
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>
 #endif
@@ -172,9+173,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
 
 struct cache_palias *sparc_aliases;
 
-extern int min_free_pages;
-extern int free_pages_low;
-extern int free_pages_high;
 extern void srmmu_frob_mem_map(unsigned long);
 
 int physmem_mapped_contig = 1;
@@ -265,11+263,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
               initpages << (PAGE_SHIFT-10),
               PAGE_OFFSET, end_mem);
 
-       min_free_pages = nr_free_pages >> 7;
-       if(min_free_pages < 16)
-               min_free_pages = 16;
-       free_pages_low = min_free_pages + (min_free_pages >> 1);
-       free_pages_high = min_free_pages + min_free_pages;
+       freepages.min = nr_free_pages >> 7;
+       if(freepages.min < 16)
+               freepages.min = 16;
+       freepages.low = freepages.min + (freepages.min >> 1);
+       freepages.high = freepages.min + freepages.min;
 }
 
 void free_initmem (void)
index cde799d..6e1d309 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/fpumacro.h>
 #include <asm/lsu.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
 #endif
 
 /* #define SYSCALL_TRACING */
@@ -327,7+327,7 @@ void do_fpother(struct pt_regs *regs)
        case (2 << 14): /* unfinished_FPop */
        case (3 << 14): /* unimplemented_FPop */
 #ifdef CONFIG_MATHEMU_MODULE
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
                if (!handle_mathemu)
                        request_module("math-emu");
 #endif
index 54dc8f2..b564dc0 100644 (file)
 #include <linux/init.h>
 #include <linux/blk.h>
 #include <linux/swap.h>
+#include <linux/swapctl.h>
 
 #include <asm/head.h>
 #include <asm/system.h>
@@ -864,10+865,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        return device_scan (PAGE_ALIGN (start_mem));
 }
 
-extern int min_free_pages;
-extern int free_pages_low;
-extern int free_pages_high;
-
 __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
 {
        unsigned long addr, tmp2 = 0;
@@ -946,11+943,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
               initpages << (PAGE_SHIFT-10), 
               PAGE_OFFSET, end_mem);
 
-       min_free_pages = nr_free_pages >> 7;
-       if(min_free_pages < 16)
-               min_free_pages = 16;
-       free_pages_low = min_free_pages + (min_free_pages >> 1);
-       free_pages_high = min_free_pages + min_free_pages;
+       freepages.low = nr_free_pages >> 7;
+       if(freepages.low < 16)
+               freepages.low = 16;
+       freepages.low = freepages.low + (freepages.low >> 1);
+       freepages.high = freepages.low + freepages.low;
 }
 
 void free_initmem (void)
index bf0f2de..2b0e974 100644 (file)
@@ -840,7+840,7 @@ static void add_stripe_bh (struct stripe_head *sh, struct buffer_head *bh, int d
        if (sh->bh_new[dd_idx]) {
                printk("raid5: bug: stripe->bh_new[%d], sector %lu exists\n", dd_idx, sh->sector);
                printk("forcing oops.\n");
-               *(int*)=0;
+               *(int*)0=0;
        }
 
        set_bit(BH_Lock, &bh->b_state);
index 89faab3..de922c7 100644 (file)
@@ -106,11+106,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
   tristate '   Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
 fi
 bool 'Enhanced Real Time Clock Support' CONFIG_RTC
-if [ "$CONFIG_RTC" = "y" ]; then
-  if [ "$ARCH" = "alpha" ]; then
-    bool '  ARC console time' CONFIG_RTC_ARC y
-  fi
-fi
 if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
   bool 'Tadpole ANA H8 Support'  CONFIG_H8
 fi
index d0e756e..91ed514 100644 (file)
  *      for the QIC-117 floppy-tape driver for Linux.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
 
index 05e5239..03b126f 100644 (file)
  *      for the QIC-117 floppy-tape driver for Linux.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
 
index 26d15d1..846b858 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-/* Adjust starting epoch if ARC console time is being used */
-#ifdef CONFIG_RTC_ARC
-#define ARCFUDGE 20 
-#else
-#define ARCFUDGE 0
-#endif
-
 /*
  *     We sponge a minor off of the misc major. No need slurping
  *     up another valuable major dev number for this. If you add
@@ -126,12+119,8 @@ unsigned char days_in_mo[] =
  *     so that there is no possibility of conflicting with the
  *     set_rtc_mmss() call that happens during some timer interrupts.
  *     (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
- *
- *     On Alpha we won't get any interrupts anyway, as they all end up
- *     in the system timer code.
  */
 
-#ifndef __alpha__
 static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        /*
@@ -152,11+141,9 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                add_timer(&rtc_irq_timer);
        }
 }
-#endif
 
 /*
  *     Now all the various file operations that we export.
- *      They are all useless on Alpha...  *sigh*.
  */
 
 static long long rtc_llseek(struct file *file, loff_t offset, int origin)
@@ -167,9+154,6 @@ static long long rtc_llseek(struct file *file, loff_t offset, int origin)
 static ssize_t rtc_read(struct file *file, char *buf,
                        size_t count, loff_t *ppos)
 {
-#ifdef __alpha__
-       return -EIO;
-#else
        struct wait_queue wait = { current, NULL };
        unsigned long data;
        ssize_t retval;
@@ -201,7+185,6 @@ static ssize_t rtc_read(struct file *file, char *buf,
        remove_wait_queue(&rtc_wait, &wait);
 
        return retval;
-#endif
 }
 
 static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -212,7+195,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        struct rtc_time wtime; 
 
        switch (cmd) {
-#ifndef __alpha__
        case RTC_AIE_OFF:       /* Mask alarm int. enab. bit    */
        {
                mask_rtc_irq_bit(RTC_AIE);
@@ -260,7+242,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                set_rtc_irq_bit(RTC_UIE);
                return 0;
        }
-#endif
        case RTC_ALM_READ:      /* Read the present alarm time */
        {
                /*
@@ -335,7+316,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                                   sizeof(struct rtc_time)))
                        return -EFAULT;
 
-               yrs = rtc_tm.tm_year + 1900 + ARCFUDGE;
+               yrs = rtc_tm.tm_year + 1900;
                mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
                day = rtc_tm.tm_mday;
                hrs = rtc_tm.tm_hour;
@@ -400,7+381,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        {
                return put_user(rtc_freq, (unsigned long *)arg);
        }
-#ifndef __alpha__
        case RTC_IRQP_SET:      /* Set periodic IRQ rate.       */
        {
                int tmp = 0;
@@ -437,7+417,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                restore_flags(flags);
                return 0;
        }
-#else /* __alpha__ */
+#ifdef __alpha__
        case RTC_EPOCH_READ:    /* Read the epoch.      */
        {
                return put_user (epoch, (unsigned long *)arg);
@@ -467,18+447,15 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
  *     We enforce only one user at a time here with the open/close.
  *     Also clear the previous interrupt data on an open, and clean
  *     up things on a close.
- *     On Alpha we just open, for we don't mess with interrups anyway.
  */
 
 static int rtc_open(struct inode *inode, struct file *file)
 {
-#ifndef __alpha__
        if(rtc_status & RTC_IS_OPEN)
                return -EBUSY;
 
        rtc_status |= RTC_IS_OPEN;
        rtc_irq_data = 0;
-#endif
        return 0;
 }
 
@@ -489,7+466,6 @@ static int rtc_release(struct inode *inode, struct file *file)
         * in use, and clear the data.
         */
 
-#ifndef __alpha__
        unsigned char tmp;
        unsigned long flags;
 
@@ -510,11+486,9 @@ static int rtc_release(struct inode *inode, struct file *file)
 
        rtc_irq_data = 0;
        rtc_status &= ~RTC_IS_OPEN;
-#endif
        return 0;
 }
 
-#ifndef __alpha__
 static unsigned int rtc_poll(struct file *file, poll_table *wait)
 {
        poll_wait(file, &rtc_wait, wait);
@@ -522,7+496,6 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
                return POLLIN | POLLRDNORM;
        return 0;
 }
-#endif
 
 /*
  *     The various file operations we support.
@@ -533,11+506,7 @@ static struct file_operations rtc_fops = {
        rtc_read,
        NULL,           /* No write */
        NULL,           /* No readdir */
-#ifdef __alpha__
-       NULL,           /* No select on Alpha */
-#else
        rtc_poll,
-#endif
        rtc_ioctl,
        NULL,           /* No mmap */
        rtc_open,
@@ -560,14+529,12 @@ __initfunc(int rtc_init(void))
        char *guess = NULL;
 #endif
        printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
-#ifndef __alpha__
        if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
        {
                /* Yeah right, seeing as irq 8 doesn't even hit the bus. */
                printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
                return -EIO;
        }
-#endif
        misc_register(&rtc_dev);
        /* Check region? Naaah! Just snarf it up. */
        request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
@@ -599,8+566,8 @@ __initfunc(int rtc_init(void))
                guess = "Digital UNIX";
        }
        if (guess)
-               printk("rtc: %s epoch (%ld) detected\n", guess, epoch);
-#else
+               printk("rtc: %s epoch (%lu) detected\n", guess, epoch);
+#endif
        init_timer(&rtc_irq_timer);
        rtc_irq_timer.function = rtc_dropped_irq;
        rtc_wait = NULL;
@@ -610,7+577,6 @@ __initfunc(int rtc_init(void))
        CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
        restore_flags(flags);
        rtc_freq = 1024;
-#endif
        return 0;
 }
 
@@ -626,7+592,6 @@ __initfunc(int rtc_init(void))
  *     for something that requires a steady > 1KHz signal anyways.)
  */
 
-#ifndef __alpha__
 void rtc_dropped_irq(unsigned long data)
 {
        unsigned long flags;
@@ -643,7+608,6 @@ void rtc_dropped_irq(unsigned long data)
        rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);     /* restart */
        restore_flags(flags);
 }
-#endif
 
 /*
  *     Info exported via "/proc/rtc".
@@ -672,9+636,10 @@ int get_rtc_status(char *buf)
         */
        p += sprintf(p,
                     "rtc_time\t: %02d:%02d:%02d\n"
-                    "rtc_date\t: %04d-%02d-%02d\n",
+                    "rtc_date\t: %04d-%02d-%02d\n"
+                    "rtc_epoch\t: %04lu\n",
                     tm.tm_hour, tm.tm_min, tm.tm_sec,
-                    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+                    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
 
        get_rtc_alm_time(&tm);
 
@@ -788,12+753,9 @@ void get_rtc_time(struct rtc_time *rtc_tm)
         * Account for differences between how the RTC uses the values
         * and how they are defined in a struct rtc_time;
         */
-       if ((rtc_tm->tm_year += epoch - 1900) <= 69)
+       if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)
                rtc_tm->tm_year += 100;
 
-       /* if ARCFUDGE == 0, the optimizer should do away with this */
-       rtc_tm->tm_year -= ARCFUDGE;
-
        rtc_tm->tm_mon--;
 }
 
@@ -832,7+794,6 @@ void get_rtc_alm_time(struct rtc_time *alm_tm)
  * meddles with the interrupt enable/disable bits.
  */
 
-#ifndef __alpha__
 void mask_rtc_irq_bit(unsigned char bit)
 {
        unsigned char val;
@@ -862,4+823,3 @@ void set_rtc_irq_bit(unsigned char bit)
        rtc_irq_data = 0;
        restore_flags(flags);
 }
-#endif
index 1413495..16e52bd 100644 (file)
@@ -83,9+83,6 @@ static unsigned int ipddp_debug = IPDDP_DEBUG;
 /* Index to functions, as function prototypes. */
 static int ipddp_xmit(struct sk_buff *skb, struct device *dev);
 static struct net_device_stats *ipddp_get_stats(struct device *dev);
-static int ipddp_rebuild_header(struct sk_buff *skb);
-static int ipddp_hard_header(struct sk_buff *skb, struct device *dev,
-                unsigned short type, void *daddr, void *saddr, unsigned len);
 static int ipddp_create(struct ipddp_route *new_rt);
 static int ipddp_delete(struct ipddp_route *rt);
 static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
@@ -119,10+116,10 @@ int ipddp_init(struct device *dev)
 
        /* Let the user now what mode we are in */
        if(ipddp_mode == IPDDP_ENCAP)
-               printk("%s: Appletalk-IP Encapsulation mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
+               printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
                        dev->name);
        if(ipddp_mode == IPDDP_DECAP)
-               printk("%s: Appletalk-IP Decapsulation mode by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n", 
+               printk("%s: Appletalk-IP Decap. mode by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n", 
                        dev->name);
 
        /* Fill in the device structure with ethernet-generic values. */
@@ -140,8+137,6 @@ int ipddp_init(struct device *dev)
         dev->stop          = ipddp_close;
         dev->get_stats      = ipddp_get_stats;
         dev->do_ioctl       = ipddp_ioctl;
-       dev->hard_header    = ipddp_hard_header;        /* see ip_output.c */
-       dev->rebuild_header = ipddp_rebuild_header;
 
         dev->type = ARPHRD_IPDDP;              /* IP over DDP tunnel */
         dev->mtu = 585;
@@ -158,24+153,6 @@ int ipddp_init(struct device *dev)
 }
 
 /*
- * Transmit LLAP/ELAP frame using aarp_send_ddp.
- */
-static int ipddp_xmit(struct sk_buff *skb, struct device *dev)
-{
-        /* Retrieve the saved address hint */
-        struct at_addr *at = (struct at_addr *)skb->data;
-        skb_pull(skb,4);
-
-        ((struct net_device_stats *) dev->priv)->tx_packets++;
-        ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
-
-        if(aarp_send_ddp(skb->dev, skb, at, NULL) < 0)
-                dev_kfree_skb(skb);
-
-        return 0;
-}
-
-/*
  * Get the current statistics. This may be called with the card open or closed.
  */
 static struct net_device_stats *ipddp_get_stats(struct device *dev)
@@ -184,19+161,15 @@ static struct net_device_stats *ipddp_get_stats(struct device *dev)
 }
 
 /*
- * Now the packet really wants to go out. On entry skb->data points to the
- * ddpehdr we reserved earlier. skb->h.raw will be the higher level header.
+ * Transmit LLAP/ELAP frame using aarp_send_ddp.
  */
-static int ipddp_rebuild_header(struct sk_buff *skb)
+static int ipddp_xmit(struct sk_buff *skb, struct device *dev)
 {
        u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
         struct ddpehdr *ddp;
-        struct at_addr at;
         struct ipddp_route *rt;
         struct at_addr *our_addr;
 
-       /* Wow! I'll eat my hat if this routine is really called. --ANK */
-
        /*
          * Find appropriate route to use, based only on IP number.
          */
@@ -205,25+178,21 @@ static int ipddp_rebuild_header(struct sk_buff *skb)
                 if(rt->ip == paddr)
                         break;
         }
-
         if(rt == NULL)
-        {
-                printk("%s: unreachable dst %s\n", cardname, in_ntoa(paddr));
-                return -ENETUNREACH;
-        }
+                return 0;
 
         our_addr = atalk_find_dev_addr(rt->dev);
 
        if(ipddp_mode == IPDDP_DECAP)
                /* 
                 * Pull off the excess room that should not be there.
-                * This is the case for Localtalk, this may not hold
-                * true for Ethertalk, etc. 
+                * This is due to a hard-header problem. This is the
+                * quick fix for now though, till it breaks.
                 */
-               skb_pull(skb, 31-(sizeof(struct ddpehdr)+1));
+               skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
 
        /* Create the Extended DDP header */
-       ddp = (struct ddpehdr *) (skb->data+4);
+       ddp = (struct ddpehdr *)skb->data;
         ddp->deh_len = skb->len;
         ddp->deh_hops = 1;
         ddp->deh_pad = 0;
@@ -231,7+200,7 @@ static int ipddp_rebuild_header(struct sk_buff *skb)
 
        /*
          * For Localtalk we need aarp_send_ddp to strip the
-         * Ext DDP header and place a Shrt DDP header on it.
+         * long DDP header and place a shot DDP header on it.
          */
         if(rt->dev->type == ARPHRD_LOCALTLK)
         {
@@ -248,24+217,16 @@ static int ipddp_rebuild_header(struct sk_buff *skb)
         ddp->deh_dport = 72;
         ddp->deh_sport = 72;
 
-        *((__u8 *)(ddp+1)) = 22;                       /* ddp type = IP */
-        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));                /* fix up length field */
+        *((__u8 *)(ddp+1)) = 22;               /* ddp type = IP */
+        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));        /* fix up length field */
 
-       /* Hide it at the start of the buffer, we pull it out in ipddp_xmit */
-        at = rt->at;
-        memcpy(skb->data,(void *)&at,sizeof(at));
-
-       skb->dev = rt->dev;     /* set skb->dev to appropriate device */
         skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
 
-        return 0;
-}
+       ((struct net_device_stats *) dev->priv)->tx_packets++;
+        ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
 
-static int ipddp_hard_header(struct sk_buff *skb, struct device *dev, 
-               unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-        /* Push down the header space and the type byte */
-        skb_push(skb, sizeof(struct ddpehdr)+1+4);
+        if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
+                dev_kfree_skb(skb);
 
         return 0;
 }
index 3117893..076373b 100644 (file)
 #define SIOCADDIPDDPRT   (SIOCDEVPRIVATE)
 #define SIOCDELIPDDPRT   (SIOCDEVPRIVATE+1)
 #define SIOCFINDIPDDPRT  (SIOCDEVPRIVATE+2)
-#define SIOCPRINTIPDDPRT (SIOCDEVPRIVATE+3)
 
 struct ipddp_route
 {
index 829f79d..de70cd0 100644 (file)
 
 /* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */
 
-#include <linux/config.h> /* for CONFIG_KERNELD */
+#include <linux/config.h> /* for CONFIG_KMOD */
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index cc259fd..70adb00 100644 (file)
@@ -8,7+8,6 @@
  *
  */
 
-#include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
index a49bf38..daede4a 100644 (file)
  * driver uses the new code this *ENTIRE* file will be nuked.
  */
 
-#include <linux/config.h> /* for CONFIG_KERNELD */
 #define __NO_VERSION__
 #include <linux/module.h>
 
index 46d3ea7..3c29353 100644 (file)
  *  we attempt to remove commands from the queue and retry them.
  */
 
-#include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
index 7ef5f8d..d4678da 100644 (file)
@@ -6,6+6,8 @@ fi
 
 dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND
 if [ "$CONFIG_SB" = "y" ]; then
+    bool 'Is the card a Soundman Games ?' CONFIG_SM_GAMES
+    bool 'Are you using the IBM Mwave "emulation" of SB ?' CONFIG_SB_MWAVE
     hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220
     int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7
     int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1
index e8ec0b1..6b09e33 100644 (file)
@@ -117,22+117,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_MPU401),y)
-LX_OBJS += mpu401.o
-else
-  ifeq ($(CONFIG_MPU401),m)
-  MX_OBJS += mpu401.o
-  else
-    ifeq ($(CONFIG_MPU_EMU),y)
-    LX_OBJS += mpu401.o
-    else
-      ifeq ($(CONFIG_MPU_EMU),m)
-      MX_OBJS += mpu401.o
-      endif
-    endif
-  endif
-endif
-
 ifeq ($(CONFIG_UART401),y)
 LX_OBJS += uart401.o
 else
@@ -159,9+143,31 @@ endif
 
 ifeq ($(CONFIG_SSCAPE),y)
 L_OBJS += sscape.o
+LX_OBJS += ad1848.o
+CONFIG_MPU401 = y
 else
   ifeq ($(CONFIG_SSCAPE),m)
   M_OBJS += sscape.o
+  MX_OBJS += ad1848.o
+  ifneq ($(CONFIG_MPU401),y)
+    CONFIG_MPU401 = m
+  endif
+  endif
+endif
+
+ifeq ($(CONFIG_MPU401),y)
+LX_OBJS += mpu401.o
+else
+  ifeq ($(CONFIG_MPU401),m)
+  MX_OBJS += mpu401.o
+  else
+    ifeq ($(CONFIG_MPU_EMU),y)
+    LX_OBJS += mpu401.o
+    else
+      ifeq ($(CONFIG_MPU_EMU),m)
+      MX_OBJS += mpu401.o
+      endif
+    endif
   endif
 endif
 
@@ -265,7+271,7 @@ CONFIG_MAUI_BOOT_FILE := $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE))
 maui.o: maui_boot.h
 
 maui_boot.h: $(CONFIG_MAUI_BOOT_FILE) bin2hex
-       bin2hex maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@
+       bin2hex -i maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@
        @ ( \
            echo 'ifeq ($(strip $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_BOOT_FILE)))'; \
            echo 'FILES_BOOT_UP_TO_DATE += $@'; \
@@ -297,7+303,7 @@ CONFIG_TRIX_BOOT_FILE := $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE))
 trix.o: trix_boot.h
 
 trix_boot.h: $(CONFIG_TRIX_BOOT_FILE) hex2hex
-       hex2hex trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@
+       hex2hex -i trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@
        @ ( \
            echo 'ifeq ($(strip $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_BOOT_FILE)))'; \
            echo 'FILES_BOOT_UP_TO_DATE += $@'; \
index 6fdec35..d839ed2 100644 (file)
  */
 /*
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ *                  general sleep/wakeup clean up.
+ * Alan Cox       : reformatted. Fixed SMP bugs. Moved to kernel alloc/free
+ *                  of irqs. Use dev_id.
+ *
+ * Status:
+ *             Tested. Believed fully functional.
  */
 
 #include <linux/config.h>
@@ -144,9+150,9 @@ static void ad1848_tmr_reprogram(int dev);
 
 static int ad_read(ad1848_info * devc, int reg)
 {
-       unsigned long   flags;
-       int             x;
-       int             timeout = 900000;
+       unsigned long flags;
+       int x;
+       int timeout = 900000;
 
        while (timeout > 0 && inb(devc->base) == 0x80)  /*Are we initializing */
                timeout--;
@@ -163,11+169,10 @@ static int ad_read(ad1848_info * devc, int reg)
 
 static void ad_write(ad1848_info * devc, int reg, int data)
 {
-       unsigned long   flags;
-       int             timeout = 900000;
+       unsigned long flags;
+       int timeout = 900000;
 
-       while (timeout > 0 &&
-              inb(devc->base) == 0x80)         /*Are we initializing */
+       while (timeout > 0 && inb(devc->base) == 0x80)  /* Are we initializing */
                timeout--;
 
        save_flags(flags);
@@ -180,7+185,7 @@ static void ad_write(ad1848_info * devc, int reg, int data)
 
 static void wait_for_calibration(ad1848_info * devc)
 {
-       int             timeout = 0;
+       int timeout = 0;
 
        /*
         * Wait until the auto calibration process has finished.
@@ -1751,7+1756,11 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
                else
                        devc->audio_flags |= DMA_DUPLEX;
        }
-       
+
+       portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL);
+       if(portc==NULL)
+               return -1;
+               
        if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
                                             dev_name,
                                             &ad1848_audio_driver,
@@ -1762,12+1771,11 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
                                             dma_playback,
                                             dma_capture)) < 0)
        {
+               kfree(portc);
+               portc=NULL;
                return -1;
        }
-       portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(ad1848_port_info)));
-       sound_mem_sizes[sound_nblocks] = sizeof(ad1848_port_info);
-       if (sound_nblocks < 1024)
-               sound_nblocks++;;
+       
        audio_devs[my_dev]->portc = portc;
        memset((char *) portc, 0, sizeof(*portc));
 
@@ -1777,23+1785,21 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
 
        if (irq > 0)
        {
-               irq2dev[irq] = devc->dev_no = my_dev;
-               if (snd_set_irq_handler(devc->irq, adintr,
-                                         devc->name,
-                                         NULL) < 0)
+               devc->dev_no = my_dev;
+               if (request_irq(devc->irq, adintr, 0, devc->name, (void *)my_dev) < 0)
                {
-                       printk(KERN_WARNING "ad1848: IRQ in use\n");
+                       printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n");
                }
                if (devc->model != MD_1848 && devc->model != MD_C930)
                {
-                       int             x;
-                       unsigned char   tmp = ad_read(devc, 16);
+                       int x;
+                       unsigned char tmp = ad_read(devc, 16);
 
                        devc->timer_ticks = 0;
 
                        ad_write(devc, 21, 0x00);       /* Timer MSB */
                        ad_write(devc, 20, 0x10);       /* Timer LSB */
-
+#ifndef __SMP__
                        ad_write(devc, 16, tmp | 0x40); /* Enable timer */
                        for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
                        ad_write(devc, 16, tmp & ~0x40);        /* Disable timer */
@@ -1805,6+1811,9 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
                                DDB(printk("Interrupt test OK\n"));
                                devc->irq_ok = 1;
                        }
+#else
+                       devc->irq_ok=1;
+#endif                 
                }
                else
                        devc->irq_ok = 1;       /* Couldn't test. assume it's OK */
@@ -1840,7+1849,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
 
 void ad1848_control(int cmd, int arg)
 {
-       ad1848_info    *devc;
+       ad1848_info *devc;
 
        if (nr_ad1848_devs < 1)
                return;
@@ -1850,7+1859,7 @@ void ad1848_control(int cmd, int arg)
        switch (cmd)
        {
                case AD1848_SET_XTAL:   /* Change clock frequency of AD1845 (only ) */
-               if (devc->model != MD_1845)
+                       if (devc->model != MD_1845)
                                return;
                        ad_enter_MCE(devc);
                        ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5));
@@ -1859,8+1868,8 @@ void ad1848_control(int cmd, int arg)
 
                case AD1848_MIXER_REROUTE:
                {
-                       int             o = (arg >> 8) & 0xff;
-                       int             n = arg & 0xff;
+                       int o = (arg >> 8) & 0xff;
+                       int n = arg & 0xff;
 
                        if (n == SOUND_MIXER_NONE)
                        {       /* Just hide this control */
@@ -1906,12+1915,14 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
                
        if (devc != NULL)
        {
+               if(audio_devs[dev]->portc!=NULL)
+                       kfree(audio_devs[dev]->portc);
                release_region(devc->base, 4);
 
                if (!share_dma)
                {
                        if (irq > 0)
-                               snd_release_irq(devc->irq);
+                               free_irq(devc->irq, NULL);
 
                        sound_free_dma(audio_devs[dev]->dmap_out->dma);
 
@@ -1926,35+1937,15 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
 
 void adintr(int irq, void *dev_id, struct pt_regs *dummy)
 {
-       unsigned char   status;
-       ad1848_info    *devc;
-       int             dev;
-       int             alt_stat = 0xff;
-       unsigned char   c930_stat = 0;
-       int             cnt = 0;
-
-       if (irq < 0 || irq > 15)
-       {
-               dev = -1;
-       }
-       else
-               dev = irq2dev[irq];
-
-       if (dev < 0 || dev >= num_audiodevs)
-       {
-               for (irq = 0; irq < 17; irq++)
-                       if (irq2dev[irq] != -1)
-                               break;
-
-               if (irq > 15)
-               {
-                       /* printk("ad1848.c: Bogus interrupt %d\n", irq); */
-                       return;
-               }
-               dev = irq2dev[irq];
-               devc = (ad1848_info *) audio_devs[dev]->devc;
-       } else
-               devc = (ad1848_info *) audio_devs[dev]->devc;
+       unsigned char status;
+       ad1848_info *devc;
+       int dev;
+       int alt_stat = 0xff;
+       unsigned char c930_stat = 0;
+       int cnt = 0;
+
+       dev = (int)dev_id;
+       devc = (ad1848_info *) audio_devs[dev]->devc;
 
 interrupt_again:               /* Jump back here if int status doesn't reset */
 
@@ -2542,12+2533,12 @@ EXPORT_SYMBOL(unload_ms_sound);
 
 #ifdef MODULE
 
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(dma, "i");
-MODULE_PARM(dma2, "i");
-MODULE_PARM(type, "i");
-MODULE_PARM(deskpro_xl, "i");
+MODULE_PARM(io, "i");                  /* I/O for a raw AD1848 card */
+MODULE_PARM(irq, "i");                 /* IRQ to use */
+MODULE_PARM(dma, "i");                 /* First DMA channel */
+MODULE_PARM(dma2, "i");                        /* Second DMA channel */
+MODULE_PARM(type, "i");                        /* Card type */
+MODULE_PARM(deskpro_xl, "i");          /* Special magic for Deskpro XL boxen */
 
 int io = -1;
 int irq = -1;
index 351dd24..fc49c99 100644 (file)
 
 int main( int argc, const char * argv [] )
 {
-    const char * varname = argv[1];
+    const char * varname;
     int i = 0;
     int c;
+    int id = 0;
 
+    if(argv[1] && strcmp(argv[1],"-i")==0)
+    {
+       argv++;
+       argc--;
+       id=1;
+    }
+       
+    if(argc==1)
+    {
+       fprintf(stderr, "bin2hex: [-i] firmware\n");
+       exit(1);
+    }
+    
+    varname = argv[1];
     printf( "/* automatically generated by bin2hex */\n" );
-    printf( "static unsigned char %s [] =\n{\n", varname );
+    printf( "static unsigned char %s [] %s =\n{\n", varname , id?"__initdata":"");
 
     while ( ( c = getchar( ) ) != EOF )
     {
index c8732df..fdb5b73 100644 (file)
  *      CS4232
  *      CS4236
  *      CS4236B
+ *
+ * Note: You will need a PnP config setup to initialise some CS4232 boards
+ * anyway.
+ *
+ * Changes
+ *     Alan Cox        Modularisation, Basic cleanups.
  */
+
 /*
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -99,6+107,8 @@ int probe_cs4232(struct address_info *hw_config)
         * just one CS4232 compatible device can exist on the system. Also this
         * method conflicts with possible PnP support in the OS. For this reason 
         * driver is just a temporary kludge.
+        *
+        * Also the Cirrus/Crystal method doesnt always work. Try ISAPnP first ;)
         */
 
        /*
@@ -106,8+116,8 @@ int probe_cs4232(struct address_info *hw_config)
         * first time.
         */
 
-       for (n = 0; n < 4; n++) {
-               
+       for (n = 0; n < 4; n++)
+       {       
                /*
                 *      Wake up the card by sending a 32 byte Crystal key to the key port.
                 */
@@ -298,8+308,7 @@ struct address_info cfg;
  *     loaded ready.
  */
 
-int
-init_module(void)
+int init_module(void)
 {
        if (io == -1 || irq == -1 || dma == -1 || dma2 == -1)
        {
index a9d4f4a..db6a02d 100644 (file)
@@ -125,6+125,7 @@ static void sound_free_dmap(struct dma_buffparms *dmap)
 
        free_pages((unsigned long) dmap->raw_buf, sz);
        dmap->raw_buf = NULL;
+       /* Remember the buffer is deleted so we dont Oops later */
        dmap->fragment_size = 0;
 }
 
@@ -832,12+833,12 @@ int DMAbuf_move_wrpointer(int dev, int l)
        dmap->user_counter += l;
        dmap->flags |= DMA_DIRTY;
 
-       if (dmap->user_counter >= dmap->max_byte_counter) {
+       if (dmap->byte_counter >= dmap->max_byte_counter) {
                /* Wrap the byte counters */
-               long decr = dmap->user_counter;
-               dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
-               decr -= dmap->user_counter;
-               dmap->byte_counter -= decr;
+               long decr = dmap->byte_counter;
+               dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use);
+               decr -= dmap->byte_counter;
+               dmap->user_counter -= decr;
        }
        end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size;
 
@@ -928,7+929,7 @@ static void do_outputintr(int dev, int dummy)
                        dmap->byte_counter += dmap->bytes_in_use;
                        if (dmap->byte_counter >= dmap->max_byte_counter) {     /* Overflow */
                                long decr = dmap->byte_counter;
-                               dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
+                               dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use);
                                decr -= dmap->byte_counter;
                                dmap->user_counter -= decr;
                        }
@@ -952,7+953,7 @@ static void do_outputintr(int dev, int dummy)
                dmap->byte_counter += dmap->bytes_in_use;
                if (dmap->byte_counter >= dmap->max_byte_counter) {     /* Overflow */
                        long decr = dmap->byte_counter;
-                       dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
+                       dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use);
                        decr -= dmap->byte_counter;
                        dmap->user_counter -= decr;
                }
diff --git a/drivers/sound/dmabuf.c.old b/drivers/sound/dmabuf.c.old
deleted file mode 100644 (file)
index ebbd0ea..0000000
+++ /dev/null
@@ -1,1599 +0,0 @@
-/*
- * sound/dmabuf.c
- *
- * The DMA buffer manager for digitized voice applications
- */
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-#include <linux/config.h>
-
-#define BE_CONSERVATIVE
-
-#include "sound_config.h"
-
-#if defined(CONFIG_AUDIO) || defined(CONFIG_GUSHW)
-
-static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] =
-{NULL};
-static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] =
-{
-  {0}};
-static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] =
-{NULL};
-static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] =
-{
-  {0}};
-
-static int      ndmaps = 0;
-
-#define MAX_DMAP (MAX_AUDIO_DEV*2)
-
-static struct dma_buffparms dmaps[MAX_DMAP] =
-{
-  {0}};
-
-static void     dma_reset_output (int dev);
-static void     dma_reset_input (int dev);
-static int      local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
-
-static void
-dma_init_buffers (int dev, struct dma_buffparms *dmap)
-{
-
-  dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
-  dmap->byte_counter = 0;
-  dmap->max_byte_counter = 8000 * 60 * 60;
-  dmap->bytes_in_use = dmap->buffsize;
-
-  dmap->dma_mode = DMODE_NONE;
-  dmap->mapping_flags = 0;
-  dmap->neutral_byte = 0x80;
-  dmap->data_rate = 8000;
-  dmap->cfrag = -1;
-  dmap->closing = 0;
-  dmap->nbufs = 1;
-  dmap->flags = DMA_BUSY;      /* Other flags off */
-}
-
-static int
-open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan)
-{
-  if (dmap->flags & DMA_BUSY)
-    return -EBUSY;
-
-  {
-    int             err;
-
-    if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0)
-      return err;
-  }
-
-  if (dmap->raw_buf == NULL)
-    {
-      printk ("Sound: DMA buffers not available\n");
-      return -ENOSPC;          /* Memory allocation failed during boot */
-    }
-
-  if (sound_open_dma (chan, audio_devs[dev]->name))
-    {
-      printk ("Unable to grab(2) DMA%d for the audio driver\n", chan);
-      return -EBUSY;
-    }
-
-  dma_init_buffers (dev, dmap);
-  dmap->open_mode = mode;
-  dmap->subdivision = dmap->underrun_count = 0;
-  dmap->fragment_size = 0;
-  dmap->max_fragments = 65536; /* Just a large value */
-  dmap->byte_counter = 0;
-  dmap->max_byte_counter = 8000 * 60 * 60;
-  dmap->applic_profile = APF_NORMAL;
-  dmap->needs_reorg = 1;
-  dmap->audio_callback = NULL;
-  dmap->callback_parm = 0;
-
-
-  if (dmap->dma_mode & DMODE_OUTPUT)
-    {
-      out_sleep_flag[dev].opts = WK_NONE;
-    }
-  else
-    {
-      in_sleep_flag[dev].opts = WK_NONE;
-    }
-
-  return 0;
-}
-
-static void
-close_dmap (int dev, struct dma_buffparms *dmap, int chan)
-{
-  sound_close_dma (chan);
-
-  if (dmap->flags & DMA_BUSY)
-    dmap->dma_mode = DMODE_NONE;
-  dmap->flags &= ~DMA_BUSY;
-
-  disable_dma (dmap->dma);
-}
-
-
-static unsigned int
-default_set_bits (int dev, unsigned int bits)
-{
-  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits);
-}
-
-static int
-default_set_speed (int dev, int speed)
-{
-  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) & speed);
-}
-
-static short
-default_set_channels (int dev, short channels)
-{
-  int             c = channels;
-
-  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c);
-}
-
-static void
-check_driver (struct audio_driver *d)
-{
-  if (d->set_speed == NULL)
-    d->set_speed = default_set_speed;
-  if (d->set_bits == NULL)
-    d->set_bits = default_set_bits;
-  if (d->set_channels == NULL)
-    d->set_channels = default_set_channels;
-}
-
-int
-DMAbuf_open (int dev, int mode)
-{
-  int             retval;
-  struct dma_buffparms *dmap_in = NULL;
-  struct dma_buffparms *dmap_out = NULL;
-
-  if (dev >= num_audiodevs)
-    {
-      return -ENXIO;
-    }
-
-  if (!audio_devs[dev])
-    {
-      return -ENXIO;
-    }
-
-  if (!(audio_devs[dev]->flags & DMA_DUPLEX))
-    {
-      audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
-      audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma;
-    }
-
-  check_driver (audio_devs[dev]->d);
-
-  if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0)
-    return retval;
-
-  dmap_out = audio_devs[dev]->dmap_out;
-  dmap_in = audio_devs[dev]->dmap_in;
-
-  if (dmap_in == dmap_out)
-    audio_devs[dev]->flags &= ~DMA_DUPLEX;
-
-  if (mode & OPEN_WRITE)
-    {
-      if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0)
-       {
-         audio_devs[dev]->d->close (dev);
-         return retval;
-       }
-    }
-
-  audio_devs[dev]->enable_bits = mode;
-
-  if (mode == OPEN_READ || (mode != OPEN_WRITE &&
-                           audio_devs[dev]->flags & DMA_DUPLEX))
-    {
-      if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0)
-       {
-         audio_devs[dev]->d->close (dev);
-
-         if (mode & OPEN_WRITE)
-           {
-             close_dmap (dev, dmap_out, audio_devs[dev]->dmap_out->dma);
-           }
-
-         return retval;
-       }
-    }
-
-  audio_devs[dev]->open_mode = mode;
-  audio_devs[dev]->go = 1;
-
-  if (mode & OPEN_READ)
-    in_sleep_flag[dev].opts = WK_NONE;
-
-  if (mode & OPEN_WRITE)
-    out_sleep_flag[dev].opts = WK_NONE;
-
-  audio_devs[dev]->d->set_bits (dev, 8);
-  audio_devs[dev]->d->set_channels (dev, 1);
-  audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED);
-
-  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
-    {
-      memset (audio_devs[dev]->dmap_out->raw_buf,
-             audio_devs[dev]->dmap_out->neutral_byte,
-             audio_devs[dev]->dmap_out->bytes_in_use);
-    }
-
-  return 0;
-}
-
-void
-DMAbuf_reset (int dev)
-{
-  if (audio_devs[dev]->open_mode & OPEN_WRITE)
-    dma_reset_output (dev);
-
-  if (audio_devs[dev]->open_mode & OPEN_READ)
-    dma_reset_input (dev);
-}
-
-static void
-dma_reset_output (int dev)
-{
-  unsigned long   flags;
-  int             tmout;
-
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-
-  if (!(dmap->flags & DMA_STARTED))    /* DMA is not active */
-    return;
-
-/*
- * First wait until the current fragment has been played completely
- */
-  save_flags (flags);
-  cli ();
-
-  tmout =
-    (dmap->fragment_size * HZ) / dmap->data_rate;
-
-  tmout += HZ / 5;             /* Some safety distance */
-
-  if (tmout < (HZ / 2))
-    tmout = HZ / 2;
-  if (tmout > 20 * HZ)
-    tmout = 20 * HZ;
-
-  audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
-
-  audio_devs[dev]->dmap_out->underrun_count = 0;
-  if (!signal_pending(current)
-      && audio_devs[dev]->dmap_out->qlen
-      && audio_devs[dev]->dmap_out->underrun_count == 0)
-    {
-
-      {
-       unsigned long   tlimit;
-
-       if (tmout)
-         current->timeout = tlimit = jiffies + (tmout);
-       else
-         tlimit = (unsigned long) -1;
-       out_sleep_flag[dev].opts = WK_SLEEP;
-       interruptible_sleep_on (&out_sleeper[dev]);
-       if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
-         {
-           if (jiffies >= tlimit)
-             out_sleep_flag[dev].opts |= WK_TIMEOUT;
-         }
-       out_sleep_flag[dev].opts &= ~WK_SLEEP;
-      };
-    }
-  audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
-
-/*
- * Finally shut the device off
- */
-
-  if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
-      !audio_devs[dev]->d->halt_output)
-    audio_devs[dev]->d->halt_io (dev);
-  else
-    audio_devs[dev]->d->halt_output (dev);
-  audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED;
-  restore_flags (flags);
-
-  clear_dma_ff (dmap->dma);
-  disable_dma (dmap->dma);
-  dmap->byte_counter = 0;
-  reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0);
-  dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
-}
-
-static void
-dma_reset_input (int dev)
-{
-  unsigned long   flags;
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
-
-  save_flags (flags);
-  cli ();
-  if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
-      !audio_devs[dev]->d->halt_input)
-    audio_devs[dev]->d->halt_io (dev);
-  else
-    audio_devs[dev]->d->halt_input (dev);
-  audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED;
-  restore_flags (flags);
-
-  dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
-  dmap->byte_counter = 0;
-  reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1);
-}
-
-void
-DMAbuf_launch_output (int dev, struct dma_buffparms *dmap)
-{
-  if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT))
-    return;                    /* Don't start DMA yet */
-
-  dmap->dma_mode = DMODE_OUTPUT;
-
-  if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA)
-    {
-      if (!(dmap->flags & DMA_STARTED))
-       {
-         reorganize_buffers (dev, dmap, 0);
-
-         if (audio_devs[dev]->d->prepare_for_output (dev,
-                                         dmap->fragment_size, dmap->nbufs))
-           return;
-
-         if (!(dmap->flags & DMA_NODMA))
-           {
-             local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use,
-                              DMA_MODE_WRITE);
-           }
-         dmap->flags |= DMA_STARTED;
-       }
-      if (dmap->counts[dmap->qhead] == 0)
-       dmap->counts[dmap->qhead] = dmap->fragment_size;
-
-      dmap->dma_mode = DMODE_OUTPUT;
-      audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
-                                       dmap->qhead * dmap->fragment_size,
-                                       dmap->counts[dmap->qhead], 1);
-      if (audio_devs[dev]->d->trigger)
-       audio_devs[dev]->d->trigger (dev,
-                       audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-    }
-  dmap->flags |= DMA_ACTIVE;
-}
-
-int
-DMAbuf_sync (int dev)
-{
-  unsigned long   flags;
-  int             tmout, n = 0;
-
-  if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
-    return 0;
-
-  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
-    {
-
-      struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-      save_flags (flags);
-      cli ();
-
-      tmout =
-       (dmap->fragment_size * HZ) / dmap->data_rate;
-
-      tmout += HZ / 5;         /* Some safety distance */
-
-      if (tmout < (HZ / 2))
-       tmout = HZ / 2;
-      if (tmout > 20 * HZ)
-       tmout = 20 * HZ;
-
-      ;
-      if (dmap->qlen > 0)
-       if (!(dmap->flags & DMA_ACTIVE))
-         DMAbuf_launch_output (dev, dmap);
-      ;
-
-      audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
-
-      audio_devs[dev]->dmap_out->underrun_count = 0;
-      while (!signal_pending(current)
-            && n++ <= audio_devs[dev]->dmap_out->nbufs
-            && audio_devs[dev]->dmap_out->qlen
-            && audio_devs[dev]->dmap_out->underrun_count == 0)
-       {
-
-         {
-           unsigned long   tlimit;
-
-           if (tmout)
-             current->timeout = tlimit = jiffies + (tmout);
-           else
-             tlimit = (unsigned long) -1;
-           out_sleep_flag[dev].opts = WK_SLEEP;
-           interruptible_sleep_on (&out_sleeper[dev]);
-           if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
-             {
-               if (jiffies >= tlimit)
-                 out_sleep_flag[dev].opts |= WK_TIMEOUT;
-             }
-           out_sleep_flag[dev].opts &= ~WK_SLEEP;
-         };
-         if ((out_sleep_flag[dev].opts & WK_TIMEOUT))
-           {
-             audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
-             restore_flags (flags);
-             return audio_devs[dev]->dmap_out->qlen;
-           }
-       }
-      audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
-      restore_flags (flags);
-      /*
-       * Some devices such as GUS have huge amount of on board RAM for the
-       * audio data. We have to wait until the device has finished playing.
-       */
-
-      save_flags (flags);
-      cli ();
-      if (audio_devs[dev]->d->local_qlen)      /* Device has hidden buffers */
-       {
-         while (!signal_pending(current)
-                && audio_devs[dev]->d->local_qlen (dev))
-           {
-
-             {
-               unsigned long   tlimit;
-
-               if (tmout)
-                 current->timeout = tlimit = jiffies + (tmout);
-               else
-                 tlimit = (unsigned long) -1;
-               out_sleep_flag[dev].opts = WK_SLEEP;
-               interruptible_sleep_on (&out_sleeper[dev]);
-               if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
-                 {
-                   if (jiffies >= tlimit)
-                     out_sleep_flag[dev].opts |= WK_TIMEOUT;
-                 }
-               out_sleep_flag[dev].opts &= ~WK_SLEEP;
-             };
-           }
-       }
-      restore_flags (flags);
-    }
-  audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE;
-  return audio_devs[dev]->dmap_out->qlen;
-}
-
-int
-DMAbuf_release (int dev, int mode)
-{
-  unsigned long   flags;
-
-  if (audio_devs[dev]->open_mode & OPEN_WRITE)
-    audio_devs[dev]->dmap_out->closing = 1;
-  if (audio_devs[dev]->open_mode & OPEN_READ)
-    audio_devs[dev]->dmap_in->closing = 1;
-
-  if (audio_devs[dev]->open_mode & OPEN_WRITE)
-    if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED))
-      if (!signal_pending(current)
-         && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
-       {
-         DMAbuf_sync (dev);
-       }
-
-  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
-    {
-      memset (audio_devs[dev]->dmap_out->raw_buf,
-             audio_devs[dev]->dmap_out->neutral_byte,
-             audio_devs[dev]->dmap_out->bytes_in_use);
-    }
-
-  save_flags (flags);
-  cli ();
-
-  DMAbuf_reset (dev);
-  audio_devs[dev]->d->close (dev);
-
-  if (audio_devs[dev]->open_mode & OPEN_WRITE)
-    close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma);
-
-  if (audio_devs[dev]->open_mode == OPEN_READ ||
-      (audio_devs[dev]->open_mode != OPEN_WRITE &&
-       audio_devs[dev]->flags & DMA_DUPLEX))
-    close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma);
-  audio_devs[dev]->open_mode = 0;
-
-  restore_flags (flags);
-
-  return 0;
-}
-
-int
-DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap)
-{
-  if (!(audio_devs[dev]->open_mode & OPEN_READ))
-    return 0;
-
-  if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
-    return 0;
-
-  if (dmap->dma_mode == DMODE_OUTPUT)  /* Direction change */
-    {
-      DMAbuf_sync (dev);
-      DMAbuf_reset (dev);
-      dmap->dma_mode = DMODE_NONE;
-    }
-
-  if (!dmap->dma_mode)
-    {
-      int             err;
-
-      reorganize_buffers (dev, dmap, 1);
-      if ((err = audio_devs[dev]->d->prepare_for_input (dev,
-                                    dmap->fragment_size, dmap->nbufs)) < 0)
-       {
-         return err;
-       }
-      dmap->dma_mode = DMODE_INPUT;
-    }
-
-  if (!(dmap->flags & DMA_ACTIVE))
-    {
-      if (dmap->needs_reorg)
-       reorganize_buffers (dev, dmap, 0);
-      local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use,
-                      DMA_MODE_READ);
-      audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
-                                      dmap->qtail * dmap->fragment_size,
-                                      dmap->fragment_size, 0);
-      dmap->flags |= DMA_ACTIVE;
-      if (audio_devs[dev]->d->trigger)
-       audio_devs[dev]->d->trigger (dev,
-                       audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-    }
-  return 0;
-}
-
-int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
-{
-  unsigned long   flags;
-  int             err = 0, n = 0;
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
-
-  if (!(audio_devs[dev]->open_mode & OPEN_READ))
-    return -EIO;
-  if (dmap->needs_reorg)
-    reorganize_buffers (dev, dmap, 0);
-
-  save_flags (flags);
-  cli ();
-  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
-    {
-      printk ("Sound: Can't read from mmapped device (1)\n");
-      restore_flags (flags);
-      return -EINVAL;
-    }
-  else
-    while (dmap->qlen <= 0 && n++ < 10)
-      {
-       int             tmout;
-
-       if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) ||
-           !audio_devs[dev]->go)
-         {
-           restore_flags (flags);
-           return -EAGAIN;
-         }
-
-       if ((err = DMAbuf_activate_recording (dev, dmap)) < 0)
-         {
-           restore_flags (flags);
-           return err;
-         }
-
-       /* Wait for the next block */
-
-       if (dontblock)
-         {
-           restore_flags (flags);
-           return -EAGAIN;
-         }
-
-       if (!audio_devs[dev]->go)
-         tmout = 0;
-       else
-         {
-           tmout =
-             (dmap->fragment_size * HZ) / dmap->data_rate;
-
-           tmout += HZ / 5;    /* Some safety distance */
-
-           if (tmout < (HZ / 2))
-             tmout = HZ / 2;
-           if (tmout > 20 * HZ)
-             tmout = 20 * HZ;
-         }
-
-
-       {
-         unsigned long   tlimit;
-
-         if (tmout)
-           current->timeout = tlimit = jiffies + (tmout);
-         else
-           tlimit = (unsigned long) -1;
-         in_sleep_flag[dev].opts = WK_SLEEP;
-         interruptible_sleep_on (&in_sleeper[dev]);
-         if (!(in_sleep_flag[dev].opts & WK_WAKEUP))
-           {
-             if (jiffies >= tlimit)
-               in_sleep_flag[dev].opts |= WK_TIMEOUT;
-           }
-         in_sleep_flag[dev].opts &= ~WK_SLEEP;
-       };
-       if ((in_sleep_flag[dev].opts & WK_TIMEOUT))
-         {
-           err = -EIO;
-           printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
-           dma_reset_input (dev);
-           ;
-         }
-       else
-         err = -EINTR;
-      }
-  restore_flags (flags);
-
-  if (dmap->qlen <= 0)
-    {
-      if (err == 0)
-       err = -EINTR;
-      return err;
-    }
-
-  *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]];
-  *len = dmap->fragment_size - dmap->counts[dmap->qhead];
-
-  return dmap->qhead;
-}
-
-int
-DMAbuf_rmchars (int dev, int buff_no, int c)
-{
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
-
-  int             p = dmap->counts[dmap->qhead] + c;
-
-  if (dmap->mapping_flags & DMA_MAP_MAPPED)
-    {
-      printk ("Sound: Can't read from mmapped device (2)\n");
-      return -EINVAL;
-    }
-  else if (dmap->qlen <= 0)
-    return -EIO;
-  else if (p >= dmap->fragment_size)
-    {                          /* This buffer is completely empty */
-      dmap->counts[dmap->qhead] = 0;
-      dmap->qlen--;
-      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
-    }
-  else
-    dmap->counts[dmap->qhead] = p;
-
-  return 0;
-}
-
-int
-DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction)
-{
-/*
- * Try to approximate the active byte position of the DMA pointer within the
- * buffer area as well as possible.
- */
-  int             pos;
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-  if (!(dmap->flags & DMA_ACTIVE))
-    pos = 0;
-  else
-    {
-      int             chan = dmap->dma;
-
-      clear_dma_ff (chan);
-      disable_dma (dmap->dma);
-      pos = get_dma_residue (chan);
-      pos = dmap->bytes_in_use - pos;
-
-      if (!(dmap->mapping_flags & DMA_MAP_MAPPED))
-       if (direction == DMODE_OUTPUT)
-         {
-           if (dmap->qhead == 0)
-             if (pos > dmap->fragment_size)
-               pos = 0;
-         }
-       else
-         {
-           if (dmap->qtail == 0)
-             if (pos > dmap->fragment_size)
-               pos = 0;
-         }
-
-      if (pos < 0)
-       pos = 0;
-      if (pos >= dmap->bytes_in_use)
-       pos = 0;
-      enable_dma (dmap->dma);
-    }
-  restore_flags (flags);
-  /* printk( "%04x ",  pos); */
-
-  return pos;
-}
-
-/*
- * DMAbuf_start_devices() is called by the /dev/music driver to start
- * one or more audio devices at desired moment.
- */
-static void
-DMAbuf_start_device (int dev)
-{
-  if (audio_devs[dev]->open_mode != 0)
-    if (!audio_devs[dev]->go)
-      {
-       /* OK to start the device */
-       audio_devs[dev]->go = 1;
-
-       if (audio_devs[dev]->d->trigger)
-         audio_devs[dev]->d->trigger (dev,
-                       audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-      }
-}
-
-void
-DMAbuf_start_devices (unsigned int devmask)
-{
-  int             dev;
-
-  for (dev = 0; dev < num_audiodevs; dev++)
-    if (devmask & (1 << dev))
-      DMAbuf_start_device (dev);
-}
-
-int
-DMAbuf_space_in_queue (int dev)
-{
-  int             len, max, tmp;
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-  int             lim = dmap->nbufs;
-
-
-  if (lim < 2)
-    lim = 2;
-
-  if (dmap->qlen >= lim)       /* No space at all */
-    return 0;
-
-  /*
-   * Verify that there are no more pending buffers than the limit
-   * defined by the process.
-   */
-
-  max = dmap->max_fragments;
-  if (max > lim)
-    max = lim;
-  len = dmap->qlen;
-
-  if (audio_devs[dev]->d->local_qlen)
-    {
-      tmp = audio_devs[dev]->d->local_qlen (dev);
-      if (tmp && len)
-       tmp--;                  /*
-                                * This buffer has been counted twice
-                                */
-      len += tmp;
-    }
-  if (dmap->byte_counter % dmap->fragment_size)                /* There is a partial fragment */
-    len = len + 1;
-
-  if (len >= max)
-    return 0;
-  return max - len;
-}
-
-static int
-output_sleep (int dev, int dontblock)
-{
-  int             tmout;
-  int             err = 0;
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-  if (dontblock)
-    {
-      return -EAGAIN;
-    }
-
-  if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
-    {
-      return -EAGAIN;
-    }
-
-  /*
-   * Wait for free space
-   */
-  if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT)
-    tmout = 0;
-  else
-    {
-      tmout =
-       (dmap->fragment_size * HZ) / dmap->data_rate;
-
-      tmout += HZ / 5;         /* Some safety distance */
-
-      if (tmout < (HZ / 2))
-       tmout = HZ / 2;
-      if (tmout > 20 * HZ)
-       tmout = 20 * HZ;
-    }
-
-  if (signal_pending(current))
-    return -EIO;
-
-
-  {
-    unsigned long   tlimit;
-
-    if (tmout)
-      current->timeout = tlimit = jiffies + (tmout);
-    else
-      tlimit = (unsigned long) -1;
-    out_sleep_flag[dev].opts = WK_SLEEP;
-    interruptible_sleep_on (&out_sleeper[dev]);
-    if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
-      {
-       if (jiffies >= tlimit)
-         out_sleep_flag[dev].opts |= WK_TIMEOUT;
-      }
-    out_sleep_flag[dev].opts &= ~WK_SLEEP;
-  };
-  if ((out_sleep_flag[dev].opts & WK_TIMEOUT))
-    {
-      printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
-      ;
-      dma_reset_output (dev);
-    }
-  else if (signal_pending(current))
-    {
-      err = -EINTR;
-    }
-
-  return err;
-}
-
-static int
-find_output_space (int dev, char **buf, int *size)
-{
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-  unsigned long   flags;
-  unsigned long   active_offs;
-  long            len, offs;
-  int             maxfrags;
-  int             occupied_bytes = (dmap->user_counter % dmap->fragment_size);
-
-  *buf = dmap->raw_buf;
-
-  if (!(maxfrags = DMAbuf_space_in_queue (dev)) && !occupied_bytes)
-    {
-      return 0;
-    }
-
-  save_flags (flags);
-  cli ();
-
-#ifdef BE_CONSERVATIVE
-  active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size;
-#else
-  active_offs = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
-  /* Check for pointer wrapping situation */
-  if (active_offs < 0 || active_offs >= dmap->bytes_in_use)
-    active_offs = 0;
-  active_offs += dmap->byte_counter;
-#endif
-
-  offs = (dmap->user_counter % dmap->bytes_in_use) & ~3;
-  if (offs < 0 || offs >= dmap->bytes_in_use)
-    {
-      printk ("OSS: Got unexpected offs %ld. Giving up.\n", offs);
-      printk ("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use);
-      return 0;
-    }
-  *buf = dmap->raw_buf + offs;
-
-  len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */
-
-  if ((offs + len) > dmap->bytes_in_use)
-    {
-      len = dmap->bytes_in_use - offs;
-    }
-
-  if (len < 0)
-    {
-      restore_flags (flags);
-      return 0;
-    }
-
-  if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes))
-    {
-      len = (maxfrags * dmap->fragment_size) - occupied_bytes;
-    }
-
-  *size = len & ~3;
-
-  restore_flags (flags);
-  return (len > 0);
-}
-
-int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
-{
-  unsigned long   flags;
-  int             err = -EIO;
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-  if (dmap->needs_reorg)
-    reorganize_buffers (dev, dmap, 0);
-
-  if (dmap->mapping_flags & DMA_MAP_MAPPED)
-    {
-      printk ("Sound: Can't write to mmapped device (3)\n");
-      return -EINVAL;
-    }
-
-  if (dmap->dma_mode == DMODE_INPUT)   /* Direction change */
-    {
-      DMAbuf_reset (dev);
-      dmap->dma_mode = DMODE_NONE;
-    }
-
-  dmap->dma_mode = DMODE_OUTPUT;
-
-  save_flags (flags);
-  cli ();
-
-  while (find_output_space (dev, buf, size) <= 0)
-    {
-      if ((err = output_sleep (dev, dontblock)) < 0)
-       {
-         restore_flags (flags);
-         return err;
-       }
-    }
-
-  restore_flags (flags);
-
-  return 0;
-}
-
-int
-DMAbuf_move_wrpointer (int dev, int l)
-{
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-  unsigned long   ptr = (dmap->user_counter / dmap->fragment_size)
-  * dmap->fragment_size;
-
-  unsigned long   end_ptr, p;
-  int             post = (dmap->flags & DMA_POST);
-
-  ;
-
-  dmap->flags &= ~DMA_POST;
-
-  dmap->cfrag = -1;
-
-  dmap->user_counter += l;
-  dmap->flags |= DMA_DIRTY;
-
-  if (dmap->user_counter >= dmap->max_byte_counter)
-    {                          /* Wrap the byte counters */
-      long            decr = dmap->user_counter;
-
-      dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
-      decr -= dmap->user_counter;
-      dmap->byte_counter -= decr;
-    }
-
-  end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size;
-
-  p = (dmap->user_counter - 1) % dmap->bytes_in_use;
-  dmap->neutral_byte = dmap->raw_buf[p];
-
-  /* Update the fragment based bookkeeping too */
-  while (ptr < end_ptr)
-    {
-      dmap->counts[dmap->qtail] = dmap->fragment_size;
-      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-      dmap->qlen++;
-      ptr += dmap->fragment_size;
-    }
-
-  dmap->counts[dmap->qtail] = dmap->user_counter - ptr;
-
-/*
- * Let the low level driver to perform some postprocessing to
- * the written data.
- */
-  if (audio_devs[dev]->d->postprocess_write)
-    audio_devs[dev]->d->postprocess_write (dev);
-
-  if (!(dmap->flags & DMA_ACTIVE))
-    if (dmap->qlen > 1 ||
-       (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1)))
-      {
-       DMAbuf_launch_output (dev, dmap);
-      }
-
-  ;
-  return 0;
-}
-
-int
-DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
-{
-  int             chan;
-  struct dma_buffparms *dmap;
-
-  if (dma_mode == DMA_MODE_WRITE)
-    {
-      chan = audio_devs[dev]->dmap_out->dma;
-      dmap = audio_devs[dev]->dmap_out;
-    }
-  else
-    {
-      chan = audio_devs[dev]->dmap_in->dma;
-      dmap = audio_devs[dev]->dmap_in;
-    }
-
-  if (dmap->raw_buf == NULL)
-    {
-      printk ("sound: DMA buffer(1) == NULL\n");
-      printk ("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in");
-      return 0;
-    }
-
-  if (chan < 0)
-    return 0;
-
-  sound_start_dma (dev, dmap, chan, physaddr, count, dma_mode, 0);
-
-  return count;
-}
-
-static int
-local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
-{
-  int             chan;
-  struct dma_buffparms *dmap;
-
-  if (dma_mode == DMA_MODE_WRITE)
-    {
-      chan = audio_devs[dev]->dmap_out->dma;
-      dmap = audio_devs[dev]->dmap_out;
-    }
-  else
-    {
-      chan = audio_devs[dev]->dmap_in->dma;
-      dmap = audio_devs[dev]->dmap_in;
-    }
-
-  if (dmap->raw_buf == NULL)
-    {
-      printk ("sound: DMA buffer(2) == NULL\n");
-      printk ("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in");
-      return 0;
-    }
-
-  if (dmap->flags & DMA_NODMA)
-    {
-      return 1;
-    }
-
-  if (chan < 0)
-    return 0;
-
-  sound_start_dma (dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1);
-  dmap->flags |= DMA_STARTED;
-
-  return count;
-}
-
-static void
-finish_output_interrupt (int dev, struct dma_buffparms *dmap)
-{
-  unsigned long   flags;
-
-  if (dmap->audio_callback != NULL)
-    dmap->audio_callback (dev, dmap->callback_parm);
-
-  save_flags (flags);
-  cli ();
-  if ((out_sleep_flag[dev].opts & WK_SLEEP))
-    {
-      {
-       out_sleep_flag[dev].opts = WK_WAKEUP;
-       wake_up (&out_sleeper[dev]);
-      };
-    }
-  restore_flags (flags);
-}
-
-static void
-do_outputintr (int dev, int dummy)
-{
-  unsigned long   flags;
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-  int             this_fragment;
-
-#ifdef OS_DMA_INTR
-  if (audio_devs[dev]->dmap_out->dma >= 0)
-    sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma);
-#endif
-
-  if (dmap->raw_buf == NULL)
-    {
-      printk ("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev);
-      return;
-    }
-
-  if (dmap->mapping_flags & DMA_MAP_MAPPED)    /* Virtual memory mapped access */
-    {
-      /* mmapped access */
-      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
-      if (dmap->qhead == 0)    /* Wrapped */
-       {
-         dmap->byte_counter += dmap->bytes_in_use;
-         if (dmap->byte_counter >= dmap->max_byte_counter)     /* Overflow */
-           {
-             long            decr = dmap->byte_counter;
-
-             dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
-             decr -= dmap->byte_counter;
-             dmap->user_counter -= decr;
-           }
-       }
-
-      dmap->qlen++;            /* Yes increment it (don't decrement) */
-      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
-       dmap->flags &= ~DMA_ACTIVE;
-      dmap->counts[dmap->qhead] = dmap->fragment_size;
-
-      DMAbuf_launch_output (dev, dmap);
-      finish_output_interrupt (dev, dmap);
-      return;
-    }
-
-  save_flags (flags);
-  cli ();
-
-  dmap->qlen--;
-  this_fragment = dmap->qhead;
-  dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
-
-  if (dmap->qhead == 0)                /* Wrapped */
-    {
-      dmap->byte_counter += dmap->bytes_in_use;
-      if (dmap->byte_counter >= dmap->max_byte_counter)                /* Overflow */
-       {
-         long            decr = dmap->byte_counter;
-
-         dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
-         decr -= dmap->byte_counter;
-         dmap->user_counter -= decr;
-       }
-    }
-
-  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
-    dmap->flags &= ~DMA_ACTIVE;
-
-  while (dmap->qlen < 0)
-    {
-      dmap->underrun_count++;
-
-      dmap->qlen++;
-      if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS)
-       {
-         dmap->flags &= ~DMA_DIRTY;
-         memset (audio_devs[dev]->dmap_out->raw_buf,
-                 audio_devs[dev]->dmap_out->neutral_byte,
-                 audio_devs[dev]->dmap_out->buffsize);
-       }
-      dmap->user_counter += dmap->fragment_size;
-      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-    }
-
-  if (dmap->qlen > 0)
-    DMAbuf_launch_output (dev, dmap);
-
-  restore_flags (flags);
-  finish_output_interrupt (dev, dmap);
-}
-
-void
-DMAbuf_outputintr (int dev, int notify_only)
-{
-  unsigned long   flags;
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-  save_flags (flags);
-  cli ();
-
-  if (!(dmap->flags & DMA_NODMA))
-    {
-      int             chan = dmap->dma, pos, n;
-
-      clear_dma_ff (chan);
-      disable_dma (dmap->dma);
-      pos = dmap->bytes_in_use - get_dma_residue (chan);
-      enable_dma (dmap->dma);
-
-      pos = pos / dmap->fragment_size; /* Actual qhead */
-      if (pos < 0 || pos >= dmap->nbufs)
-       pos = 0;
-
-      n = 0;
-      while (dmap->qhead != pos && n++ < dmap->nbufs)
-       {
-         do_outputintr (dev, notify_only);
-       }
-    }
-  else
-    do_outputintr (dev, notify_only);
-  restore_flags (flags);
-}
-
-static void
-do_inputintr (int dev)
-{
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
-  unsigned long   flags;
-
-#ifdef OS_DMA_INTR
-  if (audio_devs[dev]->dmap_in->dma >= 0)
-    sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma);
-#endif
-
-  if (dmap->raw_buf == NULL)
-    {
-      printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n");
-      return;
-    }
-
-  if (dmap->mapping_flags & DMA_MAP_MAPPED)
-    {
-      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-      if (dmap->qtail == 0)    /* Wrapped */
-       {
-         dmap->byte_counter += dmap->bytes_in_use;
-         if (dmap->byte_counter >= dmap->max_byte_counter)     /* Overflow */
-           {
-             long            decr = dmap->byte_counter;
-
-             dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
-             decr -= dmap->byte_counter;
-             dmap->user_counter -= decr;
-           }
-       }
-      dmap->qlen++;
-
-      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
-       {
-         if (dmap->needs_reorg)
-           reorganize_buffers (dev, dmap, 0);
-         local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use,
-                          DMA_MODE_READ);
-         audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
-                                          dmap->qtail * dmap->fragment_size,
-                                          dmap->fragment_size, 1);
-         if (audio_devs[dev]->d->trigger)
-           audio_devs[dev]->d->trigger (dev,
-                       audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-       }
-
-      dmap->flags |= DMA_ACTIVE;
-    }
-  else if (dmap->qlen >= (dmap->nbufs - 1))
-    {
-      printk ("Sound: Recording overrun\n");
-      dmap->underrun_count++;
-
-      /* Just throw away the oldest fragment but keep the engine running */
-      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
-      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-    }
-  else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs)
-    {
-      dmap->qlen++;
-      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-      if (dmap->qtail == 0)    /* Wrapped */
-       {
-         dmap->byte_counter += dmap->bytes_in_use;
-         if (dmap->byte_counter >= dmap->max_byte_counter)     /* Overflow */
-           {
-             long            decr = dmap->byte_counter;
-
-             dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
-             decr -= dmap->byte_counter;
-             dmap->user_counter -= decr;
-           }
-       }
-    }
-
-  if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA)
-    {
-      local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use,
-                      DMA_MODE_READ);
-      audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
-                                      dmap->qtail * dmap->fragment_size,
-                                      dmap->fragment_size, 1);
-      if (audio_devs[dev]->d->trigger)
-       audio_devs[dev]->d->trigger (dev,
-                       audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-    }
-
-  dmap->flags |= DMA_ACTIVE;
-
-  save_flags (flags);
-  cli ();
-  if (dmap->qlen > 0)
-    if ((in_sleep_flag[dev].opts & WK_SLEEP))
-      {
-       {
-         in_sleep_flag[dev].opts = WK_WAKEUP;
-         wake_up (&in_sleeper[dev]);
-       };
-      }
-  restore_flags (flags);
-}
-
-void
-DMAbuf_inputintr (int dev)
-{
-  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-
-  if (!(dmap->flags & DMA_NODMA))
-    {
-      int             chan = dmap->dma, pos, n;
-
-      clear_dma_ff (chan);
-      disable_dma (dmap->dma);
-      pos = dmap->bytes_in_use - get_dma_residue (chan);
-      enable_dma (dmap->dma);
-
-      pos = pos / dmap->fragment_size; /* Actual qhead */
-      if (pos < 0 || pos >= dmap->nbufs)
-       pos = 0;
-
-      n = 0;
-      while (dmap->qtail != pos && ++n < dmap->nbufs)
-       {
-         do_inputintr (dev);
-       }
-    }
-  else
-    do_inputintr (dev);
-  restore_flags (flags);
-}
-
-int
-DMAbuf_open_dma (int dev)
-{
-/*
- *    NOTE!  This routine opens only the primary DMA channel (output).
- */
-
-  int             chan = audio_devs[dev]->dmap_out->dma;
-  int             err;
-
-  if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0)
-    {
-      return -EBUSY;
-    }
-  dma_init_buffers (dev, audio_devs[dev]->dmap_out);
-  out_sleep_flag[dev].opts = WK_NONE;
-  audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE;
-  audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize;
-
-  if (chan >= 0)
-    {
-      unsigned long   flags;
-
-      save_flags (flags);
-      cli ();
-      disable_dma (audio_devs[dev]->dmap_out->dma);
-      clear_dma_ff (chan);
-      restore_flags (flags);
-    }
-
-  return 0;
-}
-
-void
-DMAbuf_close_dma (int dev)
-{
-  close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma);
-}
-
-void
-DMAbuf_init (int dev, int dma1, int dma2)
-{
-  /*
-     * NOTE! This routine could be called several times.
-   */
-
-  if (audio_devs[dev]->dmap_out == NULL)
-    {
-      if (audio_devs[dev]->d == NULL)
-       panic ("OSS: audio_devs[%d]->d == NULL\n", dev);
-
-      if (audio_devs[dev]->parent_dev)
-       {                       /* Use DMA map of the parent dev */
-         int             parent = audio_devs[dev]->parent_dev - 1;
-
-         audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out;
-         audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in;
-       }
-      else
-       {
-         audio_devs[dev]->dmap_out =
-           audio_devs[dev]->dmap_in =
-           &dmaps[ndmaps++];
-         audio_devs[dev]->dmap_out->dma = dma1;
-
-         if (audio_devs[dev]->flags & DMA_DUPLEX)
-           {
-             audio_devs[dev]->dmap_in =
-               &dmaps[ndmaps++];
-             audio_devs[dev]->dmap_in->dma = dma2;
-           }
-       }
-    }
-}
-
-int
-DMAbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait)
-{
-  struct dma_buffparms *dmap;
-  unsigned long   flags;
-
-  switch (sel_type)
-    {
-    case SEL_IN:
-      if (!(audio_devs[dev]->open_mode & OPEN_READ))
-       return 0;
-
-      dmap = audio_devs[dev]->dmap_in;
-
-      if (dmap->mapping_flags & DMA_MAP_MAPPED)
-       {
-         if (dmap->qlen)
-           return 1;
-
-         save_flags (flags);
-         cli ();
-
-         in_sleep_flag[dev].opts = WK_SLEEP;
-         poll_wait (&in_sleeper[dev], wait);
-         restore_flags (flags);
-         return 0;
-       }
-
-      if (dmap->dma_mode != DMODE_INPUT)
-       {
-         if (dmap->dma_mode == DMODE_NONE &&
-             audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
-             !dmap->qlen &&
-             audio_devs[dev]->go)
-           {
-             unsigned long   flags;
-
-             save_flags (flags);
-             cli ();
-             DMAbuf_activate_recording (dev, dmap);
-             restore_flags (flags);
-           }
-         return 0;
-       }
-
-      if (!dmap->qlen)
-       {
-         save_flags (flags);
-         cli ();
-
-         in_sleep_flag[dev].opts = WK_SLEEP;
-         poll_wait (&in_sleeper[dev], wait);
-         restore_flags (flags);
-         return 0;
-       }
-      return 1;
-      break;
-
-    case SEL_OUT:
-      dmap = audio_devs[dev]->dmap_out;
-
-      if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-       return 0;
-
-      if (dmap->mapping_flags & DMA_MAP_MAPPED)
-       {
-         if (dmap->qlen)
-           return 1;
-
-         save_flags (flags);
-         cli ();
-
-         out_sleep_flag[dev].opts = WK_SLEEP;
-         poll_wait (&out_sleeper[dev], wait);
-         restore_flags (flags);
-         return 0;
-       }
-
-      if (dmap->dma_mode == DMODE_INPUT)
-       {
-         return 0;
-       }
-
-      if (dmap->dma_mode == DMODE_NONE)
-       {
-         return 1;
-       }
-
-      if (!DMAbuf_space_in_queue (dev))
-       {
-         save_flags (flags);
-         cli ();
-
-         out_sleep_flag[dev].opts = WK_SLEEP;
-         poll_wait (&out_sleeper[dev], wait);
-         restore_flags (flags);
-         return 0;
-       }
-      return 1;
-      break;
-
-    case SEL_EX:
-      return 0;
-    }
-
-  return 0;
-}
-
-
-#endif
index 0f4f769..92e6dba 100644 (file)
@@ -30,7+30,7 @@ int             gus_pnp_flag = 0;
 
 void attach_gus_card(struct address_info *hw_config)
 {
-       snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp);
+       snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp, hw_config);
 
        gus_wave_init(hw_config);
 
@@ -101,7+101,7 @@ void unload_gus(struct address_info *hw_config)
 
        release_region(hw_config->io_base, 16);
        release_region(hw_config->io_base + 0x100, 12);         /* 0x10c-> is MAX */
-       snd_release_irq(hw_config->irq);
+       snd_release_irq(hw_config->irq, hw_config);
 
        sound_free_dma(hw_config->dma);
 
@@ -111,14+111,15 @@ void unload_gus(struct address_info *hw_config)
 
 void gusintr(int irq, void *dev_id, struct pt_regs *dummy)
 {
-       unsigned char   src;
-       extern int      gus_timer_enabled;
+       unsigned char src;
+       extern int gus_timer_enabled;
+       struct address_info *hw_config=dev_id;
 
        sti();
 
 #ifdef CONFIG_GUSMAX
        if (have_gus_max)
-               adintr(irq, NULL, NULL);
+               adintr(irq, (void *)hw_config->slots[3], NULL);
 #endif
 
        while (1)
index 19753bf..4b18262 100644 (file)
@@ -66,14+66,27 @@ int loadhex(FILE *inf, unsigned char *buf)
 
 int main( int argc, const char * argv [] )
 {
-       const char * varline = argv[1];
+       const char * varline;
        int i,l;
+       int id=0;
 
+       if(argv[1] && strcmp(argv[1], "-i")==0)
+       {
+               argv++;
+               argc--;
+               id=1;
+       }
+       if(argv[1]==NULL)
+       {
+               fprintf(stderr,"hex2hex: [-i] filename\n");
+               exit(1);
+       }
+       varline = argv[1\x1d;
        l = loadhex(stdin, buf);
 
        printf("/*\n *\t Computer generated file. Do not edit.\n */\n");
         printf("static int %s_len = %d;\n", varline, l);
-       printf("static unsigned char %s[] = {\n", varline);
+       printf("static unsigned char %s[] %s = {\n", varline, id?"__initdata":"");
 
        for (i=0;i<l;i++)
        {
index 5cd620d..a7d3703 100644 (file)
@@ -9,7+9,15 @@
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
+ *
+ *     Changes:
+ *             Alan Cox                General clean up, use kernel IRQ 
+ *                                     system
+ *
+ *     Status:
+ *             Untested
  */
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -327,7+335,7 @@ int probe_maui(struct address_info *hw_config)
        maui_base = hw_config->io_base;
        maui_osp = hw_config->osp;
 
-       if (snd_set_irq_handler(hw_config->irq, mauiintr, "Maui", maui_osp) < 0)
+       if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
                return 0;
 
        /*
@@ -342,26+350,26 @@ int probe_maui(struct address_info *hw_config)
                        maui_read() == -1 || maui_read() == -1)
                        if (!maui_init(hw_config->irq))
                        {
-                               snd_release_irq(hw_config->irq);
+                               free_irq(hw_config->irq, NULL);
                                return 0;
                        }
        }
        if (!maui_write(0xCF))  /* Report hardware version */
        {
                printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
-               snd_release_irq(hw_config->irq);
+               free_irq(hw_config->irq, NULL);
                return 0;
        }
        if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
        {
                printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
-               snd_release_irq(hw_config->irq);
+               free_irq(hw_config->irq, NULL);
                return 0;
        }
        if (tmp1 == 0xff || tmp2 == 0xff)
        {
-                 snd_release_irq(hw_config->irq);
-                 return 0;
+               free_irq(hw_config->irq, NULL);
+               return 0;
        }
        if (trace_init)
                printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
@@ -439,7+447,7 @@ void unload_maui(struct address_info *hw_config)
        if (irq < 0)
                irq = -irq;
        if (irq > 0)
-               snd_release_irq(irq);
+               free_irq(irq, NULL);
 }
 
 #ifdef MODULE
@@ -452,8+460,7 @@ static int fw_load = 0;
 struct address_info cfg;
 
 /*
- *     Install a CS4232 based card. Need to have ad1848 and mpu401
- *     loaded ready.
+ *     Install a Maui card. Needs mpu401 loaded already.
  */
 
 int init_module(void)
index 9ae5974..ce92010 100644 (file)
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
+ *
+ *
+ * Thomas Sailer       ioctl code reworked (vmalloc/vfree removed)
+ * Alan Cox            modularisation, use normal request_irq, use dev_id
  */
-/*
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
- */
+
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -32,30+34,30 @@ static int      timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
 #endif
 
 struct mpu_config
-  {
-         int             base; /*
+{
+       int             base;   /*
                                 * I/O base
                                 */
-         int             irq;
-         int             opened;       /*
-                                        * Open mode
-                                        */
-         int             devno;
-         int             synthno;
-         int             uart_mode;
-         int             initialized;
-         int             mode;
+       int             irq;
+       int             opened; /*
+                                * Open mode
+                                */
+       int             devno;
+       int             synthno;
+       int             uart_mode;
+       int             initialized;
+       int             mode;
 #define MODE_MIDI      1
 #define MODE_SYNTH     2
-         unsigned char   version, revision;
-         unsigned int    capabilities;
+       unsigned char   version, revision;
+       unsigned int    capabilities;
 #define MPU_CAP_INTLG  0x10000000
 #define MPU_CAP_SYNC   0x00000010
 #define MPU_CAP_FSK    0x00000020
 #define MPU_CAP_CLS    0x00000040
 #define MPU_CAP_SMPTE  0x00000080
 #define MPU_CAP_2PORT  0x00000001
-         int             timer_flag;
+       int             timer_flag;
 
 #define MBUF_MAX       10
 #define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \
@@ -75,28+77,27 @@ struct mpu_config
 #define        COMDPORT(base)   (base+1)
 #define        STATPORT(base)   (base+1)
 
-static int
-mpu401_status(struct mpu_config *devc)
+static int mpu401_status(struct mpu_config *devc)
 {
        return inb(STATPORT(devc->base));
 }
+
 #define input_avail(devc)              (!(mpu401_status(devc)&INPUT_AVAIL))
 #define output_ready(devc)             (!(mpu401_status(devc)&OUTPUT_READY))
-static void
-write_command(struct mpu_config *devc, unsigned char cmd)
+
+static void write_command(struct mpu_config *devc, unsigned char cmd)
 {
-       outb((cmd), COMDPORT(devc->base));
+       outb(cmd, COMDPORT(devc->base));
 }
-static int
-read_data(struct mpu_config *devc)
+
+static int read_data(struct mpu_config *devc)
 {
        return inb(DATAPORT(devc->base));
 }
 
-static void
-write_data(struct mpu_config *devc, unsigned char byte)
+static void write_data(struct mpu_config *devc, unsigned char byte)
 {
-       outb((byte), DATAPORT(devc->base));
+       outb(byte, DATAPORT(devc->base));
 }
 
 #define        OUTPUT_READY    0x40
@@ -107,22+108,27 @@ write_data(struct mpu_config *devc, unsigned char byte)
 
 static struct mpu_config dev_conf[MAX_MIDI_DEV] =
 {
-       {0}};
+       {0}
+};
 
-static int      n_mpu_devs = 0;
-static volatile int irq2dev[17] =
-{-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1};
+static int n_mpu_devs = 0;
 
-static int      reset_mpu401(struct mpu_config *devc);
-static void     set_uart_mode(int dev, struct mpu_config *devc, int arg);
+static int reset_mpu401(struct mpu_config *devc);
+static void set_uart_mode(int dev, struct mpu_config *devc, int arg);
 
-static int      mpu_timer_init(int midi_dev);
-static void     mpu_timer_interrupt(void);
-static void     timer_ext_event(struct mpu_config *devc, int event, int parm);
+static int mpu_timer_init(int midi_dev);
+static void mpu_timer_interrupt(void);
+static void timer_ext_event(struct mpu_config *devc, int event, int parm);
 
-static struct synth_info mpu_synth_info_proto =
-{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+static struct synth_info mpu_synth_info_proto = {
+       "MPU-401 MIDI interface", 
+       0, 
+       SYNTH_TYPE_MIDI, 
+       MIDI_TYPE_MPU401, 
+       0, 128, 
+       0, 128, 
+       SYNTH_CAP_INPUT
+};
 
 static struct synth_info mpu_synth_info[MAX_MIDI_DEV];
 
@@ -158,10+164,10 @@ static unsigned char len_tab[] =  /* # of data bytes following a status
 #else
 #define STORE(cmd) \
 { \
-  int len; \
-  unsigned char obuf[8]; \
-  cmd; \
-  seq_input_event(obuf, len); \
+       int len; \
+       unsigned char obuf[8]; \
+       cmd; \
+       seq_input_event(obuf, len); \
 }
 #endif
 
@@ -169,242+175,242 @@ static unsigned char len_tab[] =        /* # of data bytes following a status
 #define _seqbufptr 0
 #define _SEQ_ADVBUF(x) len=x
 
-static int
-mpu_input_scanner(struct mpu_config *devc, unsigned char midic)
+static int mpu_input_scanner(struct mpu_config *devc, unsigned char midic)
 {
 
        switch (devc->m_state)
-         {
-         case ST_INIT:
-                 switch (midic)
-                   {
-                   case 0xf8:
-                           /* Timer overflow */
-                           break;
-
-                   case 0xfc:
-                           printk("<all end>");
-                           break;
-
-                   case 0xfd:
-                           if (devc->timer_flag)
-                                   mpu_timer_interrupt();
-                           break;
-
-                   case 0xfe:
-                           return MPU_ACK;
-                           break;
-
-                   case 0xf0:
-                   case 0xf1:
-                   case 0xf2:
-                   case 0xf3:
-                   case 0xf4:
-                   case 0xf5:
-                   case 0xf6:
-                   case 0xf7:
-                           printk("<Trk data rq #%d>", midic & 0x0f);
-                           break;
-
-                   case 0xf9:
-                           printk("<conductor rq>");
-                           break;
-
-                   case 0xff:
-                           devc->m_state = ST_SYSMSG;
-                           break;
-
-                   default:
-                           if (midic <= 0xef)
-                             {
-                                     /* printk( "mpu time: %d ",  midic); */
-                                     devc->m_state = ST_TIMED;
-                           } else
-                                   printk("<MPU: Unknown event %02x> ", midic);
-                   }
-                 break;
-
-         case ST_TIMED:
-                 {
-                         int             msg = ((int) (midic & 0xf0) >> 4);
-
-                         devc->m_state = ST_DATABYTE;
-
-                         if (msg < 8)  /* Data byte */
-                           {
-                                   /* printk( "midi msg (running status) "); */
-                                   msg = ((int) (devc->last_status & 0xf0) >> 4);
-                                   msg -= 8;
-                                   devc->m_left = len_tab[msg] - 1;
-
-                                   devc->m_ptr = 2;
-                                   devc->m_buf[0] = devc->last_status;
-                                   devc->m_buf[1] = midic;
-
-                                   if (devc->m_left <= 0)
-                                     {
-                                             devc->m_state = ST_INIT;
-                                             do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
-                                             devc->m_ptr = 0;
-                                     }
-                         } else if (msg == 0xf)        /* MPU MARK */
-                           {
-                                   devc->m_state = ST_INIT;
-
-                                   switch (midic)
-                                     {
-                                     case 0xf8:
-                                             /* printk( "NOP "); */
-                                             break;
-
-                                     case 0xf9:
-                                             /* printk( "meas end "); */
-                                             break;
-
-                                     case 0xfc:
-                                             /* printk( "data end "); */
-                                             break;
-
-                                     default:
-                                             printk("Unknown MPU mark %02x\n", midic);
-                                     }
-                         } else
-                           {
-                                   devc->last_status = midic;
-                                   /* printk( "midi msg "); */
-                                   msg -= 8;
-                                   devc->m_left = len_tab[msg];
-
-                                   devc->m_ptr = 1;
-                                   devc->m_buf[0] = midic;
-
-                                   if (devc->m_left <= 0)
-                                     {
-                                             devc->m_state = ST_INIT;
-                                             do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
-                                             devc->m_ptr = 0;
-                                     }
-                           }
-                 }
-                 break;
-
-         case ST_SYSMSG:
-                 switch (midic)
-                   {
-                   case 0xf0:
-                           printk("<SYX>");
-                           devc->m_state = ST_SYSEX;
-                           break;
-
-                   case 0xf1:
-                           devc->m_state = ST_MTC;
-                           break;
-
-                   case 0xf2:
-                           devc->m_state = ST_SONGPOS;
-                           devc->m_ptr = 0;
-                           break;
-
-                   case 0xf3:
-                           devc->m_state = ST_SONGSEL;
-                           break;
-
-                   case 0xf6:
-                           /* printk( "tune_request\n"); */
-                           devc->m_state = ST_INIT;
-
-                           /*
-                              *    Real time messages
-                            */
-                   case 0xf8:
-                           /* midi clock */
-                           devc->m_state = ST_INIT;
-                           timer_ext_event(devc, TMR_CLOCK, 0);
-                           break;
-
-                   case 0xfA:
-                           devc->m_state = ST_INIT;
-                           timer_ext_event(devc, TMR_START, 0);
-                           break;
-
-                   case 0xFB:
-                           devc->m_state = ST_INIT;
-                           timer_ext_event(devc, TMR_CONTINUE, 0);
-                           break;
-
-                   case 0xFC:
-                           devc->m_state = ST_INIT;
-                           timer_ext_event(devc, TMR_STOP, 0);
-                           break;
-
-                   case 0xFE:
-                           /* active sensing */
-                           devc->m_state = ST_INIT;
-                           break;
-
-                   case 0xff:
-                           /* printk( "midi hard reset"); */
-                           devc->m_state = ST_INIT;
-                           break;
-
-                   default:
-                           printk("unknown MIDI sysmsg %0x\n", midic);
-                           devc->m_state = ST_INIT;
-                   }
-                 break;
-
-         case ST_MTC:
-                 devc->m_state = ST_INIT;
-                 printk("MTC frame %x02\n", midic);
-                 break;
-
-         case ST_SYSEX:
-                 if (midic == 0xf7)
-                   {
-                           printk("<EOX>");
-                           devc->m_state = ST_INIT;
-                 } else
-                         printk("%02x ", midic);
-                 break;
-
-         case ST_SONGPOS:
-                 BUFTEST(devc);
-                 devc->m_buf[devc->m_ptr++] = midic;
-                 if (devc->m_ptr == 2)
-                   {
-                           devc->m_state = ST_INIT;
-                           devc->m_ptr = 0;
-                           timer_ext_event(devc, TMR_SPP,
-                                        ((devc->m_buf[1] & 0x7f) << 7) |
-                                           (devc->m_buf[0] & 0x7f));
-                   }
-                 break;
-
-         case ST_DATABYTE:
-                 BUFTEST(devc);
-                 devc->m_buf[devc->m_ptr++] = midic;
-                 if ((--devc->m_left) <= 0)
-                   {
-                           devc->m_state = ST_INIT;
-                           do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
-                           devc->m_ptr = 0;
-                   }
-                 break;
-
-         default:
-                 printk("Bad state %d ", devc->m_state);
-                 devc->m_state = ST_INIT;
-         }
+       {
+               case ST_INIT:
+                       switch (midic)
+                       {
+                               case 0xf8:
+                               /* Timer overflow */
+                                       break;
+
+                               case 0xfc:
+                                       printk("<all end>");
+                                       break;
+
+                               case 0xfd:
+                                       if (devc->timer_flag)
+                                               mpu_timer_interrupt();
+                                       break;
+
+                               case 0xfe:
+                                       return MPU_ACK;
+
+                               case 0xf0:
+                               case 0xf1:
+                               case 0xf2:
+                               case 0xf3:
+                               case 0xf4:
+                               case 0xf5:
+                               case 0xf6:
+                               case 0xf7:
+                                       printk("<Trk data rq #%d>", midic & 0x0f);
+                                       break;
+
+                               case 0xf9:
+                                       printk("<conductor rq>");
+                                       break;
+
+                               case 0xff:
+                                       devc->m_state = ST_SYSMSG;
+                                       break;
+
+                               default:
+                                       if (midic <= 0xef)
+                                       {
+                                               /* printk( "mpu time: %d ",  midic); */
+                                               devc->m_state = ST_TIMED;
+                                       }
+                                       else
+                                               printk("<MPU: Unknown event %02x> ", midic);
+                       }
+                       break;
+
+               case ST_TIMED:
+                       {
+                               int msg = ((int) (midic & 0xf0) >> 4);
+
+                               devc->m_state = ST_DATABYTE;
+
+                               if (msg < 8)    /* Data byte */
+                               {
+                                       /* printk( "midi msg (running status) "); */
+                                       msg = ((int) (devc->last_status & 0xf0) >> 4);
+                                       msg -= 8;
+                                       devc->m_left = len_tab[msg] - 1;
+
+                                       devc->m_ptr = 2;
+                                       devc->m_buf[0] = devc->last_status;
+                                       devc->m_buf[1] = midic;
+
+                                       if (devc->m_left <= 0)
+                                       {
+                                               devc->m_state = ST_INIT;
+                                               do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+                                               devc->m_ptr = 0;
+                                       }
+                               }
+                               else if (msg == 0xf)    /* MPU MARK */
+                               {
+                                       devc->m_state = ST_INIT;
+
+                                       switch (midic)
+                                       {
+                                               case 0xf8:
+                                                       /* printk( "NOP "); */
+                                                       break;
+
+                                               case 0xf9:
+                                                       /* printk( "meas end "); */
+                                                       break;
+
+                                               case 0xfc:
+                                                       /* printk( "data end "); */
+                                                       break;
+
+                                               default:
+                                                       printk("Unknown MPU mark %02x\n", midic);
+                                       }
+                               }
+                               else
+                               {
+                                       devc->last_status = midic;
+                                       /* printk( "midi msg "); */
+                                       msg -= 8;
+                                       devc->m_left = len_tab[msg];
+
+                                       devc->m_ptr = 1;
+                                       devc->m_buf[0] = midic;
+
+                                       if (devc->m_left <= 0)
+                                       {
+                                               devc->m_state = ST_INIT;
+                                               do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+                                               devc->m_ptr = 0;
+                                       }
+                               }
+                       }
+                       break;
+
+               case ST_SYSMSG:
+                       switch (midic)
+                       {
+                               case 0xf0:
+                                       printk("<SYX>");
+                                       devc->m_state = ST_SYSEX;
+                                       break;
+
+                               case 0xf1:
+                                       devc->m_state = ST_MTC;
+                                       break;
+
+                               case 0xf2:
+                                       devc->m_state = ST_SONGPOS;
+                                       devc->m_ptr = 0;
+                                       break;
+
+                               case 0xf3:
+                                       devc->m_state = ST_SONGSEL;
+                                       break;
+
+                               case 0xf6:
+                                       /* printk( "tune_request\n"); */
+                                       devc->m_state = ST_INIT;
+
+                                       /*
+                                        *    Real time messages
+                                        */
+                               case 0xf8:
+                                       /* midi clock */
+                                       devc->m_state = ST_INIT;
+                                       timer_ext_event(devc, TMR_CLOCK, 0);
+                                       break;
+
+                               case 0xfA:
+                                       devc->m_state = ST_INIT;
+                                       timer_ext_event(devc, TMR_START, 0);
+                                       break;
+
+                               case 0xFB:
+                                       devc->m_state = ST_INIT;
+                                       timer_ext_event(devc, TMR_CONTINUE, 0);
+                                       break;
+
+                               case 0xFC:
+                                       devc->m_state = ST_INIT;
+                                       timer_ext_event(devc, TMR_STOP, 0);
+                                       break;
+
+                               case 0xFE:
+                                       /* active sensing */
+                                       devc->m_state = ST_INIT;
+                                       break;
+
+                               case 0xff:
+                                       /* printk( "midi hard reset"); */
+                                       devc->m_state = ST_INIT;
+                                       break;
+
+                               default:
+                                       printk("unknown MIDI sysmsg %0x\n", midic);
+                                       devc->m_state = ST_INIT;
+                       }
+                       break;
+
+               case ST_MTC:
+                       devc->m_state = ST_INIT;
+                       printk("MTC frame %x02\n", midic);
+                       break;
+
+               case ST_SYSEX:
+                       if (midic == 0xf7)
+                       {
+                               printk("<EOX>");
+                               devc->m_state = ST_INIT;
+                       }
+                       else
+                               printk("%02x ", midic);
+                       break;
+
+               case ST_SONGPOS:
+                       BUFTEST(devc);
+                       devc->m_buf[devc->m_ptr++] = midic;
+                       if (devc->m_ptr == 2)
+                       {
+                               devc->m_state = ST_INIT;
+                               devc->m_ptr = 0;
+                               timer_ext_event(devc, TMR_SPP,
+                                       ((devc->m_buf[1] & 0x7f) << 7) |
+                                       (devc->m_buf[0] & 0x7f));
+                       }
+                       break;
 
+               case ST_DATABYTE:
+                       BUFTEST(devc);
+                       devc->m_buf[devc->m_ptr++] = midic;
+                       if ((--devc->m_left) <= 0)
+                       {
+                               devc->m_state = ST_INIT;
+                               do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+                               devc->m_ptr = 0;
+                       }
+                       break;
+
+               default:
+                       printk("Bad state %d ", devc->m_state);
+                       devc->m_state = ST_INIT;
+       }
        return 1;
 }
 
-static void
-mpu401_input_loop(struct mpu_config *devc)
+static void mpu401_input_loop(struct mpu_config *devc)
 {
-       unsigned long   flags;
-       int             busy;
-       int             n;
+       unsigned long flags;
+       int busy;
+       int n;
 
        save_flags(flags);
        cli();
@@ -418,72+424,45 @@ mpu401_input_loop(struct mpu_config *devc)
        n = 50;
 
        while (input_avail(devc) && n-- > 0)
-         {
-                 unsigned char   c = read_data(devc);
-
-                 if (devc->mode == MODE_SYNTH)
-                   {
-                           mpu_input_scanner(devc, c);
-                 } else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
-                         devc->inputintr(devc->devno, c);
-         }
+       {
+               unsigned char c = read_data(devc);
 
+               if (devc->mode == MODE_SYNTH)
+               {
+                       mpu_input_scanner(devc, c);
+               }
+               else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
+                       devc->inputintr(devc->devno, c);
+       }
        devc->m_busy = 0;
 }
 
-void
-mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
+void mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
 {
        struct mpu_config *devc;
-       int             dev;
+       int dev = (int) dev_id;
 
        sti();
-
-/*
- * FreeBSD (and some others) pass unit number to the interrupt handler.
- * In this case we have to scan the table for first handler.
- */
-
-       if (irq < 1 || irq > 15)
-         {
-                 dev = -1;
-       } else
-               dev = irq2dev[irq];
-
-       if (dev == -1)
-         {
-                 int             origirq = irq;
-
-                 for (irq = 0; irq <= 16; irq++)
-                         if (irq2dev[irq] != -1)
-                                 break;
-                 if (irq > 15)
-                   {
-                           printk("MPU-401: Bogus interrupt #%d?\n", origirq);
-                           return;
-                   }
-                 dev = irq2dev[irq];
-                 devc = &dev_conf[dev];
-       } else
-               devc = &dev_conf[dev];
+       devc = &dev_conf[dev];
 
        if (input_avail(devc))
+       {
                if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
                        mpu401_input_loop(devc);
                else
-                 {
-                         /* Dummy read (just to acknowledge the interrupt) */
-                         read_data(devc);
-                 }
+               {
+                       /* Dummy read (just to acknowledge the interrupt) */
+                       read_data(devc);
+               }
+       }
 }
 
-static int
-mpu401_open(int dev, int mode,
+static int mpu401_open(int dev, int mode,
            void            (*input) (int dev, unsigned char data),
            void            (*output) (int dev)
 )
 {
-       int             err;
+       int err;
        struct mpu_config *devc;
 
        if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
@@ -492,36+471,34 @@ mpu401_open(int dev, int mode,
        devc = &dev_conf[dev];
 
        if (devc->opened)
-         {
-                 printk("MPU-401: Midi busy\n");
                  return -EBUSY;
-         }
        /*
-          *  Verify that the device is really running.
-          *  Some devices (such as Ensoniq SoundScape don't
-          *  work before the on board processor (OBP) is initialized
-          *  by downloading its microcode.
+        *  Verify that the device is really running.
+        *  Some devices (such as Ensoniq SoundScape don't
+        *  work before the on board processor (OBP) is initialized
+        *  by downloading its microcode.
         */
 
        if (!devc->initialized)
-         {
-                 if (mpu401_status(devc) == 0xff)      /* Bus float */
-                   {
-                           printk("MPU-401: Device not initialized properly\n");
-                           return -EIO;
-                   }
-                 reset_mpu401(devc);
-         }
-       irq2dev[devc->irq] = dev;
+       {
+               if (mpu401_status(devc) == 0xff)        /* Bus float */
+               {
+                       printk(KERN_ERR "mpu401: Device not initialized properly\n");
+                       return -EIO;
+               }
+               reset_mpu401(devc);
+       }
 
        if (midi_devs[dev]->coproc)
+       {
                if ((err = midi_devs[dev]->coproc->
                     open(midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0)
-                 {
-                         printk("MPU-401: Can't access coprocessor device\n");
-
-                         return err;
-                 }
+               {
+                       printk("MPU-401: Can't access coprocessor device\n");
+                       return err;
+               }
+       }
+       
        set_uart_mode(dev, devc, 1);
        devc->mode = MODE_MIDI;
        devc->synthno = 0;
@@ -534,19+511,16 @@ mpu401_open(int dev, int mode,
        return 0;
 }
 
-static void
-mpu401_close(int dev)
+static void mpu401_close(int dev)
 {
        struct mpu_config *devc;
 
        devc = &dev_conf[dev];
-
        if (devc->uart_mode)
                reset_mpu401(devc);     /*
                                         * This disables the UART mode
                                         */
        devc->mode = 0;
-
        devc->inputintr = NULL;
 
        if (midi_devs[dev]->coproc)
@@ -554,11+528,10 @@ mpu401_close(int dev)
        devc->opened = 0;
 }
 
-static int
-mpu401_out(int dev, unsigned char midi_byte)
+static int mpu401_out(int dev, unsigned char midi_byte)
 {
-       int             timeout;
-       unsigned long   flags;
+       int timeout;
+       unsigned long flags;
 
        struct mpu_config *devc;
 
@@ -574,21+547,20 @@ mpu401_out(int dev, unsigned char midi_byte)
        save_flags(flags);
        cli();
        if (!output_ready(devc))
-         {
-                 printk("MPU-401: Send data timeout\n");
-                 restore_flags(flags);
-                 return 0;
-         }
+       {
+               printk(KERN_WARNING "mpu401: Send data timeout\n");
+               restore_flags(flags);
+               return 0;
+       }
        write_data(devc, midi_byte);
        restore_flags(flags);
        return 1;
 }
 
-static int
-mpu401_command(int dev, mpu_command_rec * cmd)
+static int mpu401_command(int dev, mpu_command_rec * cmd)
 {
-       int             i, timeout, ok;
-       int             ret = 0;
+       int i, timeout, ok;
+       int ret = 0;
        unsigned long   flags;
        struct mpu_config *devc;
 
@@ -597,10+569,10 @@ mpu401_command(int dev, mpu_command_rec * cmd)
        if (devc->uart_mode)    /*
                                 * Not possible in UART mode
                                 */
-         {
-                 printk("MPU-401 commands not possible in the UART mode\n");
-                 return -EINVAL;
-         }
+       {
+               printk(KERN_WARNING "mpu401: commands not possible in the UART mode\n");
+               return -EINVAL;
+       }
        /*
         * Test for input since pending input seems to block the output.
         */
@@ -613,83+585,87 @@ mpu401_command(int dev, mpu_command_rec * cmd)
         */
 
        timeout = 50000;
-      retry:
+retry:
        if (timeout-- <= 0)
-         {
-                 printk("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
-                 return -EIO;
-         }
+       {
+               printk(KERN_WARNING "mpu401: Command (0x%x) timeout\n", (int) cmd->cmd);
+               return -EIO;
+       }
        save_flags(flags);
        cli();
 
        if (!output_ready(devc))
-         {
+       {
                  restore_flags(flags);
                  goto retry;
-         }
+       }
        write_command(devc, cmd->cmd);
 
        ok = 0;
        for (timeout = 50000; timeout > 0 && !ok; timeout--)
+       {
                if (input_avail(devc))
-                 {
-                         if (devc->opened && devc->mode == MODE_SYNTH)
-                           {
-                                   if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK)
-                                           ok = 1;
-                         } else
-                           {   /* Device is not currently open. Use simpler method */
-                                   if (read_data(devc) == MPU_ACK)
-                                           ok = 1;
-                           }
-                 }
+               {
+                       if (devc->opened && devc->mode == MODE_SYNTH)
+                       {
+                               if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK)
+                                       ok = 1;
+                       }
+                       else
+                       {
+                               /* Device is not currently open. Use simpler method */
+                               if (read_data(devc) == MPU_ACK)
+                                       ok = 1;
+                       }
+               }
+       }
        if (!ok)
-         {
-                 restore_flags(flags);
-                 /*       printk( "MPU: No ACK to command (0x%x)\n",  (int) cmd->cmd); */
-                 return -EIO;
-         }
+       {
+               restore_flags(flags);
+               return -EIO;
+       }
        if (cmd->nr_args)
+       {
                for (i = 0; i < cmd->nr_args; i++)
-                 {
-                         for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--);
-
-                         if (!mpu401_out(dev, cmd->data[i]))
-                           {
-                                   restore_flags(flags);
-                                   printk("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
-                                   return -EIO;
-                           }
-                 }
+               {
+                       for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--);
+
+                       if (!mpu401_out(dev, cmd->data[i]))
+                       {
+                               restore_flags(flags);
+                               printk(KERN_WARNING "mpu401: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
+                               return -EIO;
+                       }
+               }
+       }
        ret = 0;
        cmd->data[0] = 0;
 
        if (cmd->nr_returns)
+       {
                for (i = 0; i < cmd->nr_returns; i++)
-                 {
-                         ok = 0;
-                         for (timeout = 5000; timeout > 0 && !ok; timeout--)
-                                 if (input_avail(devc))
-                                   {
-                                           cmd->data[i] = read_data(devc);
-                                           ok = 1;
-                                   }
-                         if (!ok)
-                           {
-                                   restore_flags(flags);
-                                   /* printk( "MPU: No response(%d) to command (0x%x)\n",  i,  (int) cmd->cmd);  */
-                                   return -EIO;
-                           }
-                 }
+               {
+                       ok = 0;
+                       for (timeout = 5000; timeout > 0 && !ok; timeout--)
+                               if (input_avail(devc))
+                               {
+                                       cmd->data[i] = read_data(devc);
+                                       ok = 1;
+                               }
+                       if (!ok)
+                       {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+               }
+       }
        restore_flags(flags);
-
        return ret;
 }
 
-static int
-mpu_cmd(int dev, int cmd, int data)
+static int mpu_cmd(int dev, int cmd, int data)
 {
-       int             ret;
+       int ret;
 
        static mpu_command_rec rec;
 
@@ -699,14+675,11 @@ mpu_cmd(int dev, int cmd, int data)
        rec.data[0] = data & 0xff;
 
        if ((ret = mpu401_command(dev, &rec)) < 0)
-         {
-                 return ret;
-         }
+               return ret;
        return (unsigned char) rec.data[0];
 }
 
-static int
-mpu401_prefix_cmd(int dev, unsigned char status)
+static int mpu401_prefix_cmd(int dev, unsigned char status)
 {
        struct mpu_config *devc = &dev_conf[dev];
 
@@ -714,37+687,29 @@ mpu401_prefix_cmd(int dev, unsigned char status)
                return 1;
 
        if (status < 0xf0)
-         {
-                 if (mpu_cmd(dev, 0xD0, 0) < 0)
-                   {
-                           return 0;
-                   }
-                 return 1;
-         }
+       {
+               if (mpu_cmd(dev, 0xD0, 0) < 0)
+                       return 0;
+               return 1;
+       }
        switch (status)
-         {
-         case 0xF0:
-                 if (mpu_cmd(dev, 0xDF, 0) < 0)
-                   {
-                           return 0;
-                   }
-                 return 1;
-                 break;
-
-         default:
-                 return 0;
-         }
+       {
+               case 0xF0:
+                       if (mpu_cmd(dev, 0xDF, 0) < 0)
+                               return 0;
+                       return 1;
 
+               default:
+                       return 0;
+       }
 }
 
-static int
-mpu401_start_read(int dev)
+static int mpu401_start_read(int dev)
 {
        return 0;
 }
 
-static int
-mpu401_end_read(int dev)
+static int mpu401_end_read(int dev)
 {
        return 0;
 }
@@ -756,49+721,47 @@ static int mpu401_ioctl(int dev, unsigned cmd, caddr_t arg)
        int val, ret;
 
        devc = &dev_conf[dev];
-       switch (cmd) {
-       case SNDCTL_MIDI_MPUMODE:
-               if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */
-                       printk("MPU-401: Intelligent mode not supported by the HW\n");
+       switch (cmd) 
+       {
+               case SNDCTL_MIDI_MPUMODE:
+                       if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */
+                               printk(KERN_WARNING "mpu401: Intelligent mode not supported by the HW\n");
+                               return -EINVAL;
+                       }
+                       if (get_user(val, (int *)arg))
+                               return -EFAULT;
+                       set_uart_mode(dev, devc, !val);
+                       return 0;
+
+               case SNDCTL_MIDI_MPUCMD:
+                       if (copy_from_user(&rec, arg, sizeof(rec)))
+                               return -EFAULT;
+                       if ((ret = mpu401_command(dev, &rec)) < 0)
+                               return ret;
+                       if (copy_to_user(arg, &rec, sizeof(rec)))
+                               return -EFAULT;
+                       return 0;
+
+               default:
                        return -EINVAL;
-               }
-               if (__get_user(val, (int *)arg))
-                       return -EFAULT;
-               set_uart_mode(dev, devc, !val);
-               return 0;
-
-       case SNDCTL_MIDI_MPUCMD:
-               if (__copy_from_user(&rec, arg, sizeof(rec)))
-                       return -EFAULT;
-               if ((ret = mpu401_command(dev, &rec)) < 0)
-                       return ret;
-               if (__copy_to_user(arg, &rec, sizeof(rec)))
-                       return -EFAULT;
-               return 0;
-
-       default:
-               return -EINVAL;
        }
 }
 
-static void
-mpu401_kick(int dev)
+static void mpu401_kick(int dev)
 {
 }
 
-static int
-mpu401_buffer_status(int dev)
+static int mpu401_buffer_status(int dev)
 {
        return 0;               /*
                                 * No data in buffers
                                 */
 }
 
-static int
-mpu_synth_ioctl(int dev,
+static int mpu_synth_ioctl(int dev,
                unsigned int cmd, caddr_t arg)
 {
-       int             midi_dev;
+       int midi_dev;
        struct mpu_config *devc;
 
        midi_dev = synth_devs[dev]->midi_dev;
@@ -809,88+772,77 @@ mpu_synth_ioctl(int dev,
        devc = &dev_conf[midi_dev];
 
        switch (cmd)
-         {
-
-         case SNDCTL_SYNTH_INFO:
-                 memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info));
+       {
 
-                 return 0;
-                 break;
+               case SNDCTL_SYNTH_INFO:
+                       memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info));
+                       return 0;
 
-         case SNDCTL_SYNTH_MEMAVL:
-                 return 0x7fffffff;
-                 break;
+               case SNDCTL_SYNTH_MEMAVL:
+                       return 0x7fffffff;
 
-         default:
-                 return -EINVAL;
-         }
+               default:
+                       return -EINVAL;
+       }
 }
 
-static int
-mpu_synth_open(int dev, int mode)
+static int mpu_synth_open(int dev, int mode)
 {
-       int             midi_dev, err;
+       int midi_dev, err;
        struct mpu_config *devc;
 
        midi_dev = synth_devs[dev]->midi_dev;
 
        if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL)
-         {
-                 return -ENXIO;
-         }
+               return -ENXIO;
+
        devc = &dev_conf[midi_dev];
 
        /*
-          *  Verify that the device is really running.
-          *  Some devices (such as Ensoniq SoundScape don't
-          *  work before the on board processor (OBP) is initialized
-          *  by downloading its microcode.
+        *  Verify that the device is really running.
+        *  Some devices (such as Ensoniq SoundScape don't
+        *  work before the on board processor (OBP) is initialized
+        *  by downloading its microcode.
         */
 
        if (!devc->initialized)
-         {
-                 if (mpu401_status(devc) == 0xff)      /* Bus float */
-                   {
-                           printk("MPU-401: Device not initialized properly\n");
-                           return -EIO;
-                   }
-                 reset_mpu401(devc);
-         }
+       {
+               if (mpu401_status(devc) == 0xff)        /* Bus float */
+               {
+                       printk(KERN_ERR "mpu401: Device not initialized properly\n");
+                       return -EIO;
+               }
+               reset_mpu401(devc);
+       }
        if (devc->opened)
-         {
-                 printk("MPU-401: Midi busy\n");
-                 return -EBUSY;
-         }
+               return -EBUSY;
        devc->mode = MODE_SYNTH;
        devc->synthno = dev;
 
        devc->inputintr = NULL;
-       irq2dev[devc->irq] = midi_dev;
 
        if (midi_devs[midi_dev]->coproc)
                if ((err = midi_devs[midi_dev]->coproc->
                 open(midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0)
-                 {
-                         printk("MPU-401: Can't access coprocessor device\n");
-
-                         return err;
-                 }
+               {
+                       printk(KERN_WARNING "mpu401: Can't access coprocessor device\n");
+                       return err;
+               }
        devc->opened = mode;
        reset_mpu401(devc);
 
        if (mode & OPEN_READ)
-         {
-                 mpu_cmd(midi_dev, 0x8B, 0);   /* Enable data in stop mode */
-                 mpu_cmd(midi_dev, 0x34, 0);   /* Return timing bytes in stop mode */
-                 mpu_cmd(midi_dev, 0x87, 0);   /* Enable pitch & controller */
-         }
+       {
+               mpu_cmd(midi_dev, 0x8B, 0);     /* Enable data in stop mode */
+               mpu_cmd(midi_dev, 0x34, 0);     /* Return timing bytes in stop mode */
+               mpu_cmd(midi_dev, 0x87, 0);     /* Enable pitch & controller */
+       }
        return 0;
 }
 
-static void
-mpu_synth_close(int dev)
-{
-       int             midi_dev;
+static void mpu_synth_close(int dev)
+{ 
+       int midi_dev;
        struct mpu_config *devc;
 
        midi_dev = synth_devs[dev]->midi_dev;
@@ -958,55+910,52 @@ static struct midi_operations mpu401_midi_proto =
 
 static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
 
-static void
-mpu401_chk_version(int n, struct mpu_config *devc)
+static void mpu401_chk_version(int n, struct mpu_config *devc)
 {
-       int             tmp;
-       unsigned long   flags;
+       int tmp;
+       unsigned long flags;
 
        devc->version = devc->revision = 0;
 
        save_flags(flags);
        cli();
        if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0)
-         {
-                 restore_flags(flags);
-                 return;
-         }
+       {
+               restore_flags(flags);
+               return;
+       }
        if ((tmp & 0xf0) > 0x20)        /* Why it's larger than 2.x ??? */
-         {
-                 restore_flags(flags);
-                 return;
-         }
+       {
+               restore_flags(flags);
+               return;
+       }
        devc->version = tmp;
 
        if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0)
-         {
-                 devc->version = 0;
-                 restore_flags(flags);
-                 return;
-         }
+       {
+               devc->version = 0;
+               restore_flags(flags);
+               return;
+       }
        devc->revision = tmp;
-
        restore_flags(flags);
 }
 
-void
-attach_mpu401(struct address_info *hw_config)
+void attach_mpu401(struct address_info *hw_config)
 {
-       unsigned long   flags;
-       char            revision_char;
+       unsigned long flags;
+       char revision_char;
 
-       int             m;
+       int m;
        struct mpu_config *devc;
 
        hw_config->slots[1] = -1;
        m = sound_alloc_mididev();
        if (m == -1)
-         {
-                 printk(KERN_WARNING "MPU-401: Too many midi devices detected\n");
-                 return;
-         }
+       {
+               printk(KERN_WARNING "MPU-401: Too many midi devices detected\n");
+               return;
+       }
        devc = &dev_conf[m];
        devc->base = hw_config->io_base;
        devc->osp = hw_config->osp;
@@ -1024,35+973,36 @@ attach_mpu401(struct address_info *hw_config)
        devc->irq = hw_config->irq;
 
        if (devc->irq < 0)
-         {
-                 devc->irq *= -1;
-                 devc->shared_irq = 1;
-         }
-       irq2dev[devc->irq] = m;
+       {
+               devc->irq *= -1;
+               devc->shared_irq = 1;
+       }
 
        if (!hw_config->always_detect)
-         {
-                 /* Verify the hardware again */
-                 if (!reset_mpu401(devc))
-                   {
-                           printk(KERN_WARNING "mpu401: Device didn't respond\n");
-                           sound_unload_mididev(m);
-                           return;
-                   }
-                 if (!devc->shared_irq)
-                         if (snd_set_irq_handler(devc->irq, mpuintr, "mpu401", devc->osp) < 0)
-                           {
-                                   printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq);
-                                   sound_unload_mididev(m);
-                                   return;
-                           }
-                 save_flags(flags);
-                 cli();
-                 mpu401_chk_version(m, devc);
-                 if (devc->version == 0)
-                         mpu401_chk_version(m, devc);
-                 restore_flags(flags);
-         }
+       {
+               /* Verify the hardware again */
+               if (!reset_mpu401(devc))
+               {
+                       printk(KERN_WARNING "mpu401: Device didn't respond\n");
+                       sound_unload_mididev(m);
+                       return;
+               }
+               if (!devc->shared_irq)
+               {
+                       if (request_irq(devc->irq, mpuintr, 0, "mpu401", (void *)m) < 0)
+                       {
+                               printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq);
+                               sound_unload_mididev(m);
+                               return;
+                       }
+               }
+               save_flags(flags);
+               cli();
+               mpu401_chk_version(m, devc);
+               if (devc->version == 0)
+                       mpu401_chk_version(m, devc);
+               restore_flags(flags);
+       }
        request_region(hw_config->io_base, 2, "mpu401");
 
        if (devc->version != 0)
@@ -1061,36+1011,32 @@ attach_mpu401(struct address_info *hw_config)
                                devc->capabilities |= MPU_CAP_INTLG;    /* Supports intelligent mode */
 
 
-       mpu401_synth_operations[m] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations)));
-       sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations);
-
-       if (sound_nblocks < 1024)
-               sound_nblocks++;;
+       mpu401_synth_operations[m] = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
 
        if (mpu401_synth_operations[m] == NULL)
-         {
-                 sound_unload_mididev(m);
-                 printk(KERN_ERR "mpu401: Can't allocate memory\n");
-                 return;
-         }
+       {
+               sound_unload_mididev(m);
+               printk(KERN_ERR "mpu401: Can't allocate memory\n");
+               return;
+       }
        if (!(devc->capabilities & MPU_CAP_INTLG))      /* No intelligent mode */
-         {
-                 memcpy((char *) mpu401_synth_operations[m],
-                        (char *) &std_midi_synth,
+       {
+               memcpy((char *) mpu401_synth_operations[m],
+                       (char *) &std_midi_synth,
                         sizeof(struct synth_operations));
-       } else
-         {
-                 memcpy((char *) mpu401_synth_operations[m],
-                        (char *) &mpu401_synth_proto,
+       }
+       else
+       {
+               memcpy((char *) mpu401_synth_operations[m],
+                       (char *) &mpu401_synth_proto,
                         sizeof(struct synth_operations));
-         }
+       }
 
        memcpy((char *) &mpu401_midi_operations[m],
               (char *) &mpu401_midi_proto,
               sizeof(struct midi_operations));
 
-       mpu401_midi_operations[m].converter =
-           mpu401_synth_operations[m];
+       mpu401_midi_operations[m].converter = mpu401_synth_operations[m];
 
        memcpy((char *) &mpu_synth_info[m],
               (char *) &mpu_synth_info_proto,
@@ -1099,37+1045,36 @@ attach_mpu401(struct address_info *hw_config)
        n_mpu_devs++;
 
        if (devc->version == 0x20 && devc->revision >= 0x07)    /* MusicQuest interface */
-         {
-                 int             ports = (devc->revision & 0x08) ? 32 : 16;
-
-                 devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE |
-                     MPU_CAP_CLS | MPU_CAP_2PORT;
-
-                 revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
-                 sprintf(mpu_synth_info[m].name,
-                         "MQX-%d%c MIDI Interface #%d",
-                         ports,
-                         revision_char,
-                         n_mpu_devs);
-       } else
-         {
-
-                 revision_char = devc->revision ? devc->revision + '@' : ' ';
-                 if ((int) devc->revision > ('Z' - '@'))
-                         revision_char = '+';
-
-                 devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
-
-                 if (hw_config->name)
-                         sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name);
-                 else
-                         sprintf(mpu_synth_info[m].name,
-                                 "MPU-401 %d.%d%c Midi interface #%d",
-                                 (int) (devc->version & 0xf0) >> 4,
-                                 devc->version & 0x0f,
-                                 revision_char,
-                                 n_mpu_devs);
-         }
+       {
+               int ports = (devc->revision & 0x08) ? 32 : 16;
+
+               devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE |
+                               MPU_CAP_CLS | MPU_CAP_2PORT;
+
+               revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
+               sprintf(mpu_synth_info[m].name, "MQX-%d%c MIDI Interface #%d",
+                               ports,
+                               revision_char,
+                               n_mpu_devs);
+       }
+       else
+       {
+               revision_char = devc->revision ? devc->revision + '@' : ' ';
+               if ((int) devc->revision > ('Z' - '@'))
+                       revision_char = '+';
+
+               devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
+
+               if (hw_config->name)
+                       sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name);
+               else
+                       sprintf(mpu_synth_info[m].name,
+                               "MPU-401 %d.%d%c Midi interface #%d",
+                               (int) (devc->version & 0xf0) >> 4,
+                               devc->version & 0x0f,
+                               revision_char,
+                               n_mpu_devs);
+       }
 
        strcpy(mpu401_midi_operations[m].info.name,
               mpu_synth_info[m].name);
@@ -1137,24+1082,21 @@ attach_mpu401(struct address_info *hw_config)
        conf_printf(mpu_synth_info[m].name, hw_config);
 
        mpu401_synth_operations[m]->midi_dev = devc->devno = m;
-       mpu401_synth_operations[devc->devno]->info =
-           &mpu_synth_info[devc->devno];
+       mpu401_synth_operations[devc->devno]->info = &mpu_synth_info[devc->devno];
 
        if (devc->capabilities & MPU_CAP_INTLG)         /* Intelligent mode */
                hw_config->slots[2] = mpu_timer_init(m);
 
-       irq2dev[devc->irq] = m;
        midi_devs[m] = &mpu401_midi_operations[devc->devno];
        hw_config->slots[1] = m;
        sequencer_init();
 }
 
-static int
-reset_mpu401(struct mpu_config *devc)
+static int reset_mpu401(struct mpu_config *devc)
 {
-       unsigned long   flags;
-       int             ok, timeout, n;
-       int             timeout_limit;
+       unsigned long flags;
+       int ok, timeout, n;
+       int timeout_limit;
 
        /*
         * Send the RESET command. Try again if no success at the first time.
@@ -1167,30+1109,30 @@ reset_mpu401(struct mpu_config *devc)
        devc->initialized = 1;
 
        for (n = 0; n < 2 && !ok; n++)
-         {
-                 for (timeout = timeout_limit; timeout > 0 && !ok; timeout--)
+       {
+               for (timeout = timeout_limit; timeout > 0 && !ok; timeout--)
                          ok = output_ready(devc);
 
-                 write_command(devc, MPU_RESET);       /*
+               write_command(devc, MPU_RESET); /*
                                                           * Send MPU-401 RESET Command
                                                         */
 
-                 /*
-                  * Wait at least 25 msec. This method is not accurate so let's make the
-                  * loop bit longer. Cannot sleep since this is called during boot.
-                  */
+               /*
+                * Wait at least 25 msec. This method is not accurate so let's make the
+                * loop bit longer. Cannot sleep since this is called during boot.
+                */
 
-                 for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--)
-                   {
-                           save_flags(flags);
-                           cli();
-                           if (input_avail(devc))
-                                   if (read_data(devc) == MPU_ACK)
-                                           ok = 1;
-                           restore_flags(flags);
-                   }
+               for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--)
+               {
+                       save_flags(flags);
+                       cli();
+                       if (input_avail(devc))
+                               if (read_data(devc) == MPU_ACK)
+                                       ok = 1;
+                       restore_flags(flags);
+               }
 
-         }
+       }
 
        devc->m_state = ST_INIT;
        devc->m_ptr = 0;
@@ -1201,43+1143,37 @@ reset_mpu401(struct mpu_config *devc)
        return ok;
 }
 
-static void
-set_uart_mode(int dev, struct mpu_config *devc, int arg)
+static void set_uart_mode(int dev, struct mpu_config *devc, int arg)
 {
        if (!arg && (devc->capabilities & MPU_CAP_INTLG))
-         {
-                 return;
-         }
+               return;
        if ((devc->uart_mode == 0) == (arg == 0))
-         {
-                 return;       /* Already set */
-         }
+               return;         /* Already set */
        reset_mpu401(devc);     /* This exits the uart mode */
 
        if (arg)
-         {
-                 if (mpu_cmd(dev, UART_MODE_ON, 0) < 0)
-                   {
-                           printk("MPU%d: Can't enter UART mode\n", devc->devno);
-                           devc->uart_mode = 0;
-                           return;
-                   }
-         }
+       {
+               if (mpu_cmd(dev, UART_MODE_ON, 0) < 0)
+               {
+                       printk(KERN_ERR "mpu401: Can't enter UART mode\n");
+                       devc->uart_mode = 0;
+                       return;
+               }
+       }
        devc->uart_mode = arg;
 
 }
 
-int
-probe_mpu401(struct address_info *hw_config)
+int probe_mpu401(struct address_info *hw_config)
 {
-       int             ok = 0;
+       int ok = 0;
        struct mpu_config tmp_devc;
 
        if (check_region(hw_config->io_base, 2))
-         {
-                 printk("\n\nmpu401.c: I/O port %x already in use\n\n", hw_config->io_base);
-                 return 0;
-         }
+       {
+               printk(KERN_ERR "mpu401: I/O port %x already in use\n\n", hw_config->io_base);
+               return 0;
+       }
        tmp_devc.base = hw_config->io_base;
        tmp_devc.irq = hw_config->irq;
        tmp_devc.initialized = 0;
@@ -1248,27+1184,32 @@ probe_mpu401(struct address_info *hw_config)
                return 1;
 
        if (inb(hw_config->io_base + 1) == 0xff)
-         {
-                 DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base));
-                 return 0;     /* Just bus float? */
-         }
+       {
+               DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base));
+               return 0;       /* Just bus float? */
+       }
        ok = reset_mpu401(&tmp_devc);
 
        if (!ok)
-         {
-                 DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base));
-         }
+       {
+               DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base));
+       }
        return ok;
 }
 
-void
-unload_mpu401(struct address_info *hw_config)
+void unload_mpu401(struct address_info *hw_config)
 {
+       void *p;
+       int n=hw_config->slots[1];
+       
        release_region(hw_config->io_base, 2);
        if (hw_config->always_detect == 0 && hw_config->irq > 0)
-               snd_release_irq(hw_config->irq);
-       sound_unload_mididev(hw_config->slots[1]);
+               free_irq(hw_config->irq, (void *)n);
+       p=mpu401_synth_operations[n];
+       sound_unload_mididev(n);
        sound_unload_timerdev(hw_config->slots[2]);
+       if(p)
+               kfree(p);
 }
 
 /*****************************************************
@@ -1285,23+1226,20 @@ static volatile unsigned long curr_ticks, curr_clocks;
 static unsigned long prev_event_time;
 static int      metronome_mode;
 
-static unsigned long
-clocks2ticks(unsigned long clocks)
+static unsigned long clocks2ticks(unsigned long clocks)
 {
        /*
-          * The MPU-401 supports just a limited set of possible timebase values.
-          * Since the applications require more choices, the driver has to
-          * program the HW to do its best and to convert between the HW and
-          * actual timebases.
+        * The MPU-401 supports just a limited set of possible timebase values.
+        * Since the applications require more choices, the driver has to
+        * program the HW to do its best and to convert between the HW and
+        * actual timebases.
         */
-
        return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase;
 }
 
-static void
-set_timebase(int midi_dev, int val)
+static void set_timebase(int midi_dev, int val)
 {
-       int             hw_val;
+       int hw_val;
 
        if (val < 48)
                val = 48;
@@ -1314,19+1252,18 @@ set_timebase(int midi_dev, int val)
                hw_val = max_timebase;
 
        if (mpu_cmd(midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0)
-         {
-                 printk("MPU: Can't set HW timebase to %d\n", hw_val * 24);
-                 return;
-         }
+       {
+               printk(KERN_WARNING "mpu401: Can't set HW timebase to %d\n", hw_val * 24);
+               return;
+       }
        hw_timebase = hw_val * 24;
        curr_timebase = val;
 
 }
 
-static void
-tmr_reset(void)
+static void tmr_reset(void)
 {
-       unsigned long   flags;
+       unsigned long flags;
 
        save_flags(flags);
        cli();
@@ -1336,8+1273,7 @@ tmr_reset(void)
        restore_flags(flags);
 }
 
-static void
-set_timer_mode(int midi_dev)
+static void set_timer_mode(int midi_dev)
 {
        if (timer_mode & TMR_MODE_CLS)
                mpu_cmd(midi_dev, 0x3c, 0);     /* Use CLS sync */
@@ -1345,31+1281,31 @@ set_timer_mode(int midi_dev)
                mpu_cmd(midi_dev, 0x3d, 0);     /* Use SMPTE sync */
 
        if (timer_mode & TMR_INTERNAL)
-         {
+       {
                  mpu_cmd(midi_dev, 0x80, 0);   /* Use MIDI sync */
-       } else
-         {
-                 if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))
-                   {
-                           mpu_cmd(midi_dev, 0x82, 0);         /* Use MIDI sync */
-                           mpu_cmd(midi_dev, 0x91, 0);         /* Enable ext MIDI ctrl */
-                 } else if (timer_mode & TMR_MODE_FSK)
-                         mpu_cmd(midi_dev, 0x81, 0);   /* Use FSK sync */
-         }
+       }
+       else
+       {
+               if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))
+               {
+                       mpu_cmd(midi_dev, 0x82, 0);             /* Use MIDI sync */
+                       mpu_cmd(midi_dev, 0x91, 0);             /* Enable ext MIDI ctrl */
+               }
+               else if (timer_mode & TMR_MODE_FSK)
+                       mpu_cmd(midi_dev, 0x81, 0);     /* Use FSK sync */
+       }
 }
 
-static void
-stop_metronome(int midi_dev)
+static void stop_metronome(int midi_dev)
 {
        mpu_cmd(midi_dev, 0x84, 0);     /* Disable metronome */
 }
 
-static void
-setup_metronome(int midi_dev)
+static void setup_metronome(int midi_dev)
 {
-       int             numerator, denominator;
-       int             clks_per_click, num_32nds_per_beat;
-       int             beats_per_measure;
+       int numerator, denominator;
+       int clks_per_click, num_32nds_per_beat;
+       int beats_per_measure;
 
        numerator = ((unsigned) metronome_mode >> 24) & 0xff;
        denominator = ((unsigned) metronome_mode >> 16) & 0xff;
@@ -1380,15+1316,14 @@ setup_metronome(int midi_dev)
        if (!metronome_mode)
                mpu_cmd(midi_dev, 0x84, 0);     /* Disable metronome */
        else
-         {
-                 mpu_cmd(midi_dev, 0xE4, clks_per_click);
-                 mpu_cmd(midi_dev, 0xE6, beats_per_measure);
-                 mpu_cmd(midi_dev, 0x83, 0);   /* Enable metronome without accents */
-         }
+       {
+               mpu_cmd(midi_dev, 0xE4, clks_per_click);
+               mpu_cmd(midi_dev, 0xE6, beats_per_measure);
+               mpu_cmd(midi_dev, 0x83, 0);     /* Enable metronome without accents */
+       }
 }
 
-static int
-mpu_start_timer(int midi_dev)
+static int mpu_start_timer(int midi_dev)
 {
        tmr_reset();
        set_timer_mode(midi_dev);
@@ -1397,25+1332,24 @@ mpu_start_timer(int midi_dev)
                return TIMER_NOT_ARMED;         /* Already running */
 
        if (timer_mode & TMR_INTERNAL)
-         {
-                 mpu_cmd(midi_dev, 0x02, 0);   /* Send MIDI start */
-                 tmr_running = 1;
-                 return TIMER_NOT_ARMED;
-       } else
-         {
-                 mpu_cmd(midi_dev, 0x35, 0);   /* Enable mode messages to PC */
-                 mpu_cmd(midi_dev, 0x38, 0);   /* Enable sys common messages to PC */
-                 mpu_cmd(midi_dev, 0x39, 0);   /* Enable real time messages to PC */
-                 mpu_cmd(midi_dev, 0x97, 0);   /* Enable system exclusive messages to PC */
-         }
-
+       {
+               mpu_cmd(midi_dev, 0x02, 0);     /* Send MIDI start */
+               tmr_running = 1;
+               return TIMER_NOT_ARMED;
+       }
+       else
+       {
+               mpu_cmd(midi_dev, 0x35, 0);     /* Enable mode messages to PC */
+               mpu_cmd(midi_dev, 0x38, 0);     /* Enable sys common messages to PC */
+               mpu_cmd(midi_dev, 0x39, 0);     /* Enable real time messages to PC */
+               mpu_cmd(midi_dev, 0x97, 0);     /* Enable system exclusive messages to PC */
+       }
        return TIMER_ARMED;
 }
 
-static int
-mpu_timer_open(int dev, int mode)
+static int mpu_timer_open(int dev, int mode)
 {
-       int             midi_dev = sound_timer_devs[dev]->devlink;
+       int midi_dev = sound_timer_devs[dev]->devlink;
 
        if (timer_open)
                return -EBUSY;
@@ -1435,10+1369,9 @@ mpu_timer_open(int dev, int mode)
        return 0;
 }
 
-static void
-mpu_timer_close(int dev)
+static void mpu_timer_close(int dev)
 {
-       int             midi_dev = sound_timer_devs[dev]->devlink;
+       int midi_dev = sound_timer_devs[dev]->devlink;
 
        timer_open = tmr_running = 0;
        mpu_cmd(midi_dev, 0x15, 0);     /* Stop all */
@@ -1447,86+1380,80 @@ mpu_timer_close(int dev)
        stop_metronome(midi_dev);
 }
 
-static int
-mpu_timer_event(int dev, unsigned char *event)
+static int mpu_timer_event(int dev, unsigned char *event)
 {
-       unsigned char   command = event[1];
-       unsigned long   parm = *(unsigned int *) &event[4];
-       int             midi_dev = sound_timer_devs[dev]->devlink;
+       unsigned char command = event[1];
+       unsigned long parm = *(unsigned int *) &event[4];
+       int midi_dev = sound_timer_devs[dev]->devlink;
 
        switch (command)
-         {
-         case TMR_WAIT_REL:
-                 parm += prev_event_time;
-         case TMR_WAIT_ABS:
-                 if (parm > 0)
-                   {
-                           long            time;
-
-                           if (parm <= curr_ticks)     /* It's the time */
-                                   return TIMER_NOT_ARMED;
-
-                           time = parm;
-                           next_event_time = prev_event_time = time;
-
-                           return TIMER_ARMED;
-                   }
-                 break;
-
-         case TMR_START:
-                 if (tmr_running)
-                         break;
-                 return mpu_start_timer(midi_dev);
-                 break;
-
-         case TMR_STOP:
-                 mpu_cmd(midi_dev, 0x01, 0);   /* Send MIDI stop */
-                 stop_metronome(midi_dev);
-                 tmr_running = 0;
-                 break;
-
-         case TMR_CONTINUE:
-                 if (tmr_running)
-                         break;
-                 mpu_cmd(midi_dev, 0x03, 0);   /* Send MIDI continue */
-                 setup_metronome(midi_dev);
-                 tmr_running = 1;
-                 break;
-
-         case TMR_TEMPO:
-                 if (parm)
-                   {
-                           if (parm < 8)
-                                   parm = 8;
-                           if (parm > 250)
-                                   parm = 250;
-
-                           if (mpu_cmd(midi_dev, 0xE0, parm) < 0)
-                                   printk("MPU: Can't set tempo to %d\n", (int) parm);
-                           curr_tempo = parm;
-                   }
-                 break;
-
-         case TMR_ECHO:
-                 seq_copy_to_input(event, 8);
-                 break;
-
-         case TMR_TIMESIG:
-                 if (metronome_mode)   /* Metronome enabled */
-                   {
-                           metronome_mode = parm;
-                           setup_metronome(midi_dev);
-                   }
-                 break;
-
-         default:;
-         }
+       {
+               case TMR_WAIT_REL:
+                       parm += prev_event_time;
+               case TMR_WAIT_ABS:
+                       if (parm > 0)
+                       {
+                               long time;
+
+                               if (parm <= curr_ticks) /* It's the time */
+                                       return TIMER_NOT_ARMED;
+                               time = parm;
+                               next_event_time = prev_event_time = time;
+
+                               return TIMER_ARMED;
+                       }
+                       break;
+
+               case TMR_START:
+                       if (tmr_running)
+                               break;
+                       return mpu_start_timer(midi_dev);
+
+               case TMR_STOP:
+                       mpu_cmd(midi_dev, 0x01, 0);     /* Send MIDI stop */
+                       stop_metronome(midi_dev);
+                       tmr_running = 0;
+                       break;
 
+               case TMR_CONTINUE:
+                       if (tmr_running)
+                               break;
+                       mpu_cmd(midi_dev, 0x03, 0);     /* Send MIDI continue */
+                       setup_metronome(midi_dev);
+                       tmr_running = 1;
+                       break;
+
+               case TMR_TEMPO:
+                       if (parm)
+                       {
+                               if (parm < 8)
+                                       parm = 8;
+                               if (parm > 250)
+                                       parm = 250;
+                               if (mpu_cmd(midi_dev, 0xE0, parm) < 0)
+                                       printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) parm);
+                               curr_tempo = parm;
+                       }
+                       break;
+
+               case TMR_ECHO:
+                       seq_copy_to_input(event, 8);
+                       break;
+
+               case TMR_TIMESIG:
+                       if (metronome_mode)     /* Metronome enabled */
+                       {
+                               metronome_mode = parm;
+                               setup_metronome(midi_dev);
+                       }
+                       break;
+
+               default:
+       }
        return TIMER_NOT_ARMED;
 }
 
-static unsigned long
-mpu_timer_get_time(int dev)
+static unsigned long mpu_timer_get_time(int dev)
 {
        if (!timer_open)
                return 0;
@@ -1534,128+1461,115 @@ mpu_timer_get_time(int dev)
        return curr_ticks;
 }
 
-static int
-mpu_timer_ioctl(int dev,
-               unsigned int command, caddr_t arg)
+static int mpu_timer_ioctl(int dev, unsigned int command, caddr_t arg)
 {
-       int             midi_dev = sound_timer_devs[dev]->devlink;
+       int midi_dev = sound_timer_devs[dev]->devlink;
 
        switch (command)
-         {
-         case SNDCTL_TMR_SOURCE:
-                 {
-                         int             parm;
-
-                         parm = *(int *) arg;
-                         parm &= timer_caps;
-
-                         if (parm != 0)
-                           {
-                                   timer_mode = parm;
-
-                                   if (timer_mode & TMR_MODE_CLS)
-                                           mpu_cmd(midi_dev, 0x3c, 0);         /* Use CLS sync */
-                                   else if (timer_mode & TMR_MODE_SMPTE)
-                                           mpu_cmd(midi_dev, 0x3d, 0);         /* Use SMPTE sync */
-                           }
-                         return (*(int *) arg = timer_mode);
-                 }
-                 break;
-
-         case SNDCTL_TMR_START:
-                 mpu_start_timer(midi_dev);
-                 return 0;
-                 break;
-
-         case SNDCTL_TMR_STOP:
-                 tmr_running = 0;
-                 mpu_cmd(midi_dev, 0x01, 0);   /* Send MIDI stop */
-                 stop_metronome(midi_dev);
-                 return 0;
-                 break;
-
-         case SNDCTL_TMR_CONTINUE:
-                 if (tmr_running)
-                         return 0;
-                 tmr_running = 1;
-                 mpu_cmd(midi_dev, 0x03, 0);   /* Send MIDI continue */
-                 return 0;
-                 break;
-
-         case SNDCTL_TMR_TIMEBASE:
-                 {
-                         int             val;
-
-                         val = *(int *) arg;
-                         if (val)
-                                 set_timebase(midi_dev, val);
-
-                         return (*(int *) arg = curr_timebase);
-                 }
-                 break;
-
-         case SNDCTL_TMR_TEMPO:
-                 {
-                         int             val;
-                         int             ret;
-
-                         val = *(int *) arg;
-
-                         if (val)
-                           {
-                                   if (val < 8)
-                                           val = 8;
-                                   if (val > 250)
-                                           val = 250;
-                                   if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0)
-                                     {
-                                             printk("MPU: Can't set tempo to %d\n", (int) val);
-                                             return ret;
-                                     }
-                                   curr_tempo = val;
-                           }
-                         return (*(int *) arg = curr_tempo);
-                 }
-                 break;
-
-         case SNDCTL_SEQ_CTRLRATE:
-                 {
-                         int             val;
-
-                         val = *(int *) arg;
-                         if (val != 0)         /* Can't change */
-                                 return -EINVAL;
-
-                         return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60);
-                 }
-                 break;
-
-         case SNDCTL_SEQ_GETTIME:
-                 return (*(int *) arg = curr_ticks);
-                 break;
-
-         case SNDCTL_TMR_METRONOME:
-                 metronome_mode = *(int *) arg;
-                 setup_metronome(midi_dev);
-                 return 0;
-                 break;
-
-         default:;
-         }
+       {
+               case SNDCTL_TMR_SOURCE:
+                       {
+                               int parm;
+       
+                               parm = *(int *) arg;
+                               parm &= timer_caps;
 
+                               if (parm != 0)
+                               {
+                                       timer_mode = parm;
+       
+                                       if (timer_mode & TMR_MODE_CLS)
+                                               mpu_cmd(midi_dev, 0x3c, 0);             /* Use CLS sync */
+                                       else if (timer_mode & TMR_MODE_SMPTE)
+                                               mpu_cmd(midi_dev, 0x3d, 0);             /* Use SMPTE sync */
+                               }
+                               return (*(int *) arg = timer_mode);
+                       }
+                       break;
+
+               case SNDCTL_TMR_START:
+                       mpu_start_timer(midi_dev);
+                       return 0;
+
+               case SNDCTL_TMR_STOP:
+                       tmr_running = 0;
+                       mpu_cmd(midi_dev, 0x01, 0);     /* Send MIDI stop */
+                       stop_metronome(midi_dev);
+                       return 0;
+
+               case SNDCTL_TMR_CONTINUE:
+                       if (tmr_running)
+                               return 0;
+                       tmr_running = 1;
+                       mpu_cmd(midi_dev, 0x03, 0);     /* Send MIDI continue */
+                       return 0;
+
+               case SNDCTL_TMR_TIMEBASE:
+                       {
+                               int val;
+
+                               val = *(int *) arg;
+                               if (val)
+                                       set_timebase(midi_dev, val);
+                               return (*(int *) arg = curr_timebase);
+                       }
+                       break;
+
+               case SNDCTL_TMR_TEMPO:
+                       {
+                               int val;
+                               int ret;
+
+                               val = *(int *) arg;
+
+                               if (val)
+                               {
+                                       if (val < 8)
+                                               val = 8;
+                                       if (val > 250)
+                                               val = 250;
+                                       if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0)
+                                       {
+                                               printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) val);
+                                               return ret;
+                                       }
+                                       curr_tempo = val;
+                               }
+                               return (*(int *) arg = curr_tempo);
+                       }
+                       break;
+
+               case SNDCTL_SEQ_CTRLRATE:
+                       {
+                               int val;
+
+                               val = *(int *) arg;
+                               if (val != 0)           /* Can't change */
+                                       return -EINVAL;
+                               return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60);
+                       }
+                       break;
+
+               case SNDCTL_SEQ_GETTIME:
+                       return (*(int *) arg = curr_ticks);
+
+               case SNDCTL_TMR_METRONOME:
+                       metronome_mode = *(int *) arg;
+                       setup_metronome(midi_dev);
+                       return 0;
+
+               default:
+       }
        return -EINVAL;
 }
 
-static void
-mpu_timer_arm(int dev, long time)
+static void mpu_timer_arm(int dev, long time)
 {
        if (time < 0)
                time = curr_ticks + 1;
        else if (time <= curr_ticks)    /* It's the time */
                return;
-
        next_event_time = prev_event_time = time;
-
        return;
 }
 
@@ -1672,10+1586,8 @@ static struct sound_timer_operations mpu_timer =
        mpu_timer_arm
 };
 
-static void
-mpu_timer_interrupt(void)
+static void mpu_timer_interrupt(void)
 {
-
        if (!timer_open)
                return;
 
@@ -1686,10+1598,10 @@ mpu_timer_interrupt(void)
        curr_ticks = clocks2ticks(curr_clocks);
 
        if (curr_ticks >= next_event_time)
-         {
-                 next_event_time = (unsigned long) -1;
-                 sequencer_timer(0);
-         }
+       {
+               next_event_time = (unsigned long) -1;
+               sequencer_timer(0);
+       }
 }
 
 static void timer_ext_event(struct mpu_config *devc, int event, int parm)
@@ -1706,8+1618,9 @@ static void timer_ext_event(struct mpu_config *devc, int event, int parm)
                        break;
 
                case TMR_START:
-                        printk("Ext MIDI start\n");
+                       printk("Ext MIDI start\n");
                        if (!tmr_running)
+                       {
                                if (timer_mode & TMR_EXTERNAL)
                                {
                                        tmr_running = 1;
@@ -1715,6+1628,7 @@ static void timer_ext_event(struct mpu_config *devc, int event, int parm)
                                        next_event_time = 0;
                                        STORE(SEQ_START_TIMER());
                                }
+                       }
                        break;
 
                case TMR_STOP:
index 36734c2..cd76880 100644 (file)
  * sound/opl3.c
  *
  * A low level driver for Yamaha YM3812 and OPL-3 -chips
- */
-/*
+ *
+*
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
+ *
+ *
+ * Changes
+ *     Thomas Sailer   ioctl code reworked (vmalloc/vfree removed)
+ *     Alan Cox        modularisation, fixed sound_mem allocs.
+ *
+ * Status
+ *     Believed to work. Badly needs rewriting a bit to support multiple
+ *     OPL3 devices.
  */
-/*
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
- */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 
 /*
  * Major improvements to the FM handling 30AUG92 by Rob Hooft,
- */
-/*
  * hooft@chem.ruu.nl
  */
 
@@ -109,32+114,32 @@ static int opl3_ioctl(int dev, unsigned int cmd, caddr_t arg)
        struct sbi_instrument ins;
        
        switch (cmd) {
-       case SNDCTL_FM_LOAD_INSTR:
-               printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
-               if (__copy_from_user(&ins, arg, sizeof(ins)))
-                       return -EFAULT;
-               if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) {
-                       printk("FM Error: Invalid instrument number %d\n", ins.channel);
-                       return -EINVAL;
-               }
-               return store_instr(ins.channel, &ins);
+               case SNDCTL_FM_LOAD_INSTR:
+                       printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
+                       if (copy_from_user(&ins, arg, sizeof(ins)))
+                               return -EFAULT;
+                       if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) {
+                               printk(KERN_WARNING "FM Error: Invalid instrument number %d\n", ins.channel);
+                               return -EINVAL;
+                       }
+                       return store_instr(ins.channel, &ins);
 
-       case SNDCTL_SYNTH_INFO:
-               devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
-               if (__copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info)))
-                       return -EFAULT;
-               return 0;
+               case SNDCTL_SYNTH_INFO:
+                       devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
+                       if (copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info)))
+                               return -EFAULT;
+                       return 0;
 
-       case SNDCTL_SYNTH_MEMAVL:
-               return 0x7fffffff;
+               case SNDCTL_SYNTH_MEMAVL:
+                       return 0x7fffffff;
 
-       case SNDCTL_FM_4OP_ENABLE:
-               if (devc->model == 2)
-                       enter_4op_mode();
-               return 0;
+               case SNDCTL_FM_4OP_ENABLE:
+                       if (devc->model == 2)
+                               enter_4op_mode();
+                       return 0;
 
-       default:
-               return -EINVAL;
+               default:
+                       return -EINVAL;
        }
 }
 
@@ -151,8+156,8 @@ int opl3_detect(int ioaddr, int *osp)
         * Note2! The chip is initialized if detected.
         */
 
-       unsigned char   stat1, signature;
-       int             i;
+       unsigned char stat1, signature;
+       int i;
 
        if (devc != NULL)
        {
@@ -160,10+165,7 @@ int opl3_detect(int ioaddr, int *osp)
                return 0;
        }
 
-       devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(*devc)));
-       sound_mem_sizes[sound_nblocks] = sizeof(*devc);
-       if (sound_nblocks < 1024)
-               sound_nblocks++;;
+       devc = (struct opl_devinfo *)kmalloc(sizeof(*devc), GFP_KERNEL);
 
        if (devc == NULL)
        {
@@ -333,7+335,7 @@ static char fm_volume_table[128] =
 
 static void calc_vol(unsigned char *regbyte, int volume, int main_vol)
 {
-       int level =     (~*regbyte & 0x3f);
+       int level = (~*regbyte & 0x3f);
 
        if (main_vol > 127)
                main_vol = 127;
@@ -814,7+816,8 @@ static int opl3_load_patch(int dev, int format, const char *addr,
                return -EINVAL;
        }
 
-       copy_from_user(&((char *) &ins)[offs], &(addr)[offs], sizeof(ins) - offs);
+       if(copy_from_user(&((char *) &ins)[offs], &(addr)[offs], sizeof(ins) - offs))
+               return -EFAULT;
 
        if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
        {
@@ -1199,6+1202,7 @@ void cleanup_module(void)
 {
        if (devc)
        {
+               kfree(devc);
                devc = NULL;
                sound_unload_synthdev(me);
        }
index 656034d..bf95b84 100644 (file)
@@ -164,7+164,7 @@ static int config_pas_hw(struct address_info *hw_config)
                }
                else
                {
-                       if (snd_set_irq_handler(pas_irq, pasintr, "PAS16", hw_config->osp) < 0)
+                       if (request_irq(pas_irq, pasintr, "PAS16", 0, NULL) < 0)
                                ok = 0;
                }
        }
@@ -355,7+355,7 @@ void
 unload_pas(struct address_info *hw_config)
 {
        sound_free_dma(hw_config->dma);
-       snd_release_irq(hw_config->irq);
+       free_irq(hw_config->irq, NULL);
 }
 
 #ifdef MODULE
index 9d62dd4..7a0a2e6 100644 (file)
  * for more info.
  */
 /*
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ * Thomas Sailer       ioctl code reworked (vmalloc/vfree removed)
+ * Alan Cox            modularisation, clean up.
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -62,12+63,12 @@ static int pss_synthLen = 0;
 #endif
 
 typedef struct pss_confdata
-  {
-         int             base;
-         int             irq;
-         int             dma;
-         int            *osp;
-  }
+{
+       int     base;
+       int     irq;
+       int     dma;
+       int     *osp;
+}
 
 pss_confdata;
 
@@ -77,12+78,11 @@ static pss_confdata *devc = &pss_data;
 static int      pss_initialized = 0;
 static int      nonstandard_microcode = 0;
 
-static void
-pss_write(int data)
+static void pss_write(int data)
 {
-       int             i, limit;
+       int i, limit;
 
-       limit = jiffies + 10;   /* The timeout is 0.1 seconds */
+       limit = jiffies + HZ/10;        /* The timeout is 0.1 seconds */
        /*
         * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
         * called while interrupts are disabled. This means that the timer is
@@ -92,21+92,20 @@ pss_write(int data)
         */
 
        for (i = 0; i < 5000000 && jiffies < limit; i++)
-         {
-                 if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY)
-                   {
-                           outw(devc->base + PSS_DATA, data);
-                           return;
-                   }
-         }
-       printk("PSS: DSP Command (%04x) Timeout.\n", data);
+       {
+               if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY)
+               {
+                       outw(devc->base + PSS_DATA, data);
+                       return;
+               }
+       }
+       printk(KERN_ERR "PSS: DSP Command (%04x) Timeout.\n", data);
 }
 
-int
-probe_pss(struct address_info *hw_config)
+int probe_pss(struct address_info *hw_config)
 {
-       unsigned short  id;
-       int             irq, dma;
+       unsigned short id;
+       int irq, dma;
 
        devc->base = hw_config->io_base;
        irq = devc->irq = hw_config->irq;
@@ -129,8+128,7 @@ probe_pss(struct address_info *hw_config)
        return 1;
 }
 
-static int
-set_irq(pss_confdata * devc, int dev, int irq)
+static int set_irq(pss_confdata * devc, int dev, int irq)
 {
        static unsigned short irq_bits[16] =
        {
@@ -148,16+146,15 @@ set_irq(pss_confdata * devc, int dev, int irq)
        tmp = inw(REG(dev)) & ~0x38;    /* Load confreg, mask IRQ bits out */
 
        if ((bits = irq_bits[irq]) == 0 && irq != 0)
-         {
-                 printk("PSS: Invalid IRQ %d\n", irq);
-                 return 0;
-         }
+       {
+               printk(KERN_ERR "PSS: Invalid IRQ %d\n", irq);
+               return 0;
+       }
        outw(tmp | bits, REG(dev));
        return 1;
 }
 
-static int
-set_io_base(pss_confdata * devc, int dev, int base)
+static int set_io_base(pss_confdata * devc, int dev, int base)
 {
        unsigned short  tmp = inw(REG(dev)) & 0x003f;
        unsigned short  bits = (base & 0x0ffc) << 4;
@@ -167,8+164,7 @@ set_io_base(pss_confdata * devc, int dev, int base)
        return 1;
 }
 
-static int
-set_dma(pss_confdata * devc, int dev, int dma)
+static int set_dma(pss_confdata * devc, int dev, int dma)
 {
        static unsigned short dma_bits[8] =
        {
@@ -184,150+180,139 @@ set_dma(pss_confdata * devc, int dev, int dma)
        tmp = inw(REG(dev)) & ~0x07;    /* Load confreg, mask DMA bits out */
 
        if ((bits = dma_bits[dma]) == 0 && dma != 4)
-         {
-                 printk("PSS: Invalid DMA %d\n", dma);
+       {
+                 printk(KERN_ERR "PSS: Invalid DMA %d\n", dma);
                  return 0;
-         }
+       }
        outw(tmp | bits, REG(dev));
        return 1;
 }
 
-static int
-pss_reset_dsp(pss_confdata * devc)
+static int pss_reset_dsp(pss_confdata * devc)
 {
-       unsigned long   i, limit = jiffies + 10;
+       unsigned long   i, limit = jiffies + HZ/10;
 
        outw(0x2000, REG(PSS_CONTROL));
-
-       for (i = 0; i < 32768 && jiffies < limit; i++)
+       for (i = 0; i < 32768 && (limit-jiffies >= 0); i++)
                inw(REG(PSS_CONTROL));
-
        outw(0x0000, REG(PSS_CONTROL));
-
        return 1;
 }
 
-static int
-pss_put_dspword(pss_confdata * devc, unsigned short word)
+static int pss_put_dspword(pss_confdata * devc, unsigned short word)
 {
-       int             i, val;
+       int i, val;
 
        for (i = 0; i < 327680; i++)
-         {
-                 val = inw(REG(PSS_STATUS));
-                 if (val & PSS_WRITE_EMPTY)
-                   {
-                           outw(word, REG(PSS_DATA));
-                           return 1;
-                   }
-         }
+       {
+               val = inw(REG(PSS_STATUS));
+               if (val & PSS_WRITE_EMPTY)
+               {
+                       outw(word, REG(PSS_DATA));
+                       return 1;
+               }
+       }
        return 0;
 }
 
-static int
-pss_get_dspword(pss_confdata * devc, unsigned short *word)
+static int pss_get_dspword(pss_confdata * devc, unsigned short *word)
 {
-       int             i, val;
+       int i, val;
 
        for (i = 0; i < 327680; i++)
-         {
-                 val = inw(REG(PSS_STATUS));
-                 if (val & PSS_READ_FULL)
-                   {
-                           *word = inw(REG(PSS_DATA));
-                           return 1;
-                   }
-         }
-
+       {
+               val = inw(REG(PSS_STATUS));
+               if (val & PSS_READ_FULL)
+               {
+                       *word = inw(REG(PSS_DATA));
+                       return 1;
+               }
+       }
        return 0;
 }
 
-static int
-pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags)
+static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags)
 {
-       int             i, limit, val, count;
+       int i, limit, val, count;
 
        if (flags & CPF_FIRST)
-         {
+       {
 /*_____ Warn DSP software that a boot is coming */
-                 outw(0x00fe, REG(PSS_DATA));
-
-                 limit = jiffies + 10;
+               outw(0x00fe, REG(PSS_DATA));
 
-                 for (i = 0; i < 32768 && jiffies < limit; i++)
-                         if (inw(REG(PSS_DATA)) == 0x5500)
-                                 break;
-
-                 outw(*block++, REG(PSS_DATA));
+               limit = jiffies + HZ/10;
+               for (i = 0; i < 32768 && jiffies < limit; i++)
+                       if (inw(REG(PSS_DATA)) == 0x5500)
+                               break;
 
-                 pss_reset_dsp(devc);
-         }
+               outw(*block++, REG(PSS_DATA));
+               pss_reset_dsp(devc);
+       }
        count = 1;
        while (1)
-         {
-                 int             j;
+       {
+               int j;
 
-                 for (j = 0; j < 327670; j++)
-                   {
+               for (j = 0; j < 327670; j++)
+               {
 /*_____ Wait for BG to appear */
-                           if (inw(REG(PSS_STATUS)) & PSS_FLAG3)
-                                   break;
-                   }
-
-                 if (j == 327670)
-                   {
-                           /* It's ok we timed out when the file was empty */
-                           if (count >= size && flags & CPF_LAST)
-                                   break;
-                           else
-                             {
-                                     printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size);
-                                     return 0;
-                             }
-                   }
+                       if (inw(REG(PSS_STATUS)) & PSS_FLAG3)
+                               break;
+               }
+
+               if (j == 327670)
+               {
+                       /* It's ok we timed out when the file was empty */
+                       if (count >= size && flags & CPF_LAST)
+                               break;
+                       else
+                       {
+                               printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size);
+                               return 0;
+                       }
+               }
 /*_____ Send the next byte */
-                 outw(*block++, REG(PSS_DATA));
-                 count++;
-         }
+               outw(*block++, REG(PSS_DATA));
+               count++;
+       }
 
        if (flags & CPF_LAST)
-         {
+       {
 /*_____ Why */
-                 outw(0, REG(PSS_DATA));
-
-                 limit = jiffies + 10;
-                 for (i = 0; i < 32768 && jiffies < limit; i++)
-                         val = inw(REG(PSS_STATUS));
-
-                 limit = jiffies + 10;
-                 for (i = 0; i < 32768 && jiffies < limit; i++)
-                   {
-                           val = inw(REG(PSS_STATUS));
-                           if (val & 0x4000)
-                                   break;
-                   }
-
-                 /* now read the version */
-                 for (i = 0; i < 32000; i++)
-                   {
-                           val = inw(REG(PSS_STATUS));
-                           if (val & PSS_READ_FULL)
-                                   break;
-                   }
-                 if (i == 32000)
-                         return 0;
-
-                 val = inw(REG(PSS_DATA));
-                 /* printk( "<PSS: microcode version %d.%d loaded>",  val/16,  val % 16); */
-         }
+               outw(0, REG(PSS_DATA));
+
+               limit = jiffies + HZ/10;
+               for (i = 0; i < 32768 && (limit - jiffies >= 0); i++)
+                       val = inw(REG(PSS_STATUS));
+
+               limit = jiffies + HZ/10;
+               for (i = 0; i < 32768 && (limit-jiffies >= 0); i++)
+               {
+                       val = inw(REG(PSS_STATUS));
+                       if (val & 0x4000)
+                               break;
+               }
+
+               /* now read the version */
+               for (i = 0; i < 32000; i++)
+               {
+                       val = inw(REG(PSS_STATUS));
+                       if (val & PSS_READ_FULL)
+                               break;
+               }
+               if (i == 32000)
+                       return 0;
+
+               val = inw(REG(PSS_DATA));
+               /* printk( "<PSS: microcode version %d.%d loaded>",  val/16,  val % 16); */
+       }
        return 1;
 }
 
-void
-attach_pss(struct address_info *hw_config)
+void attach_pss(struct address_info *hw_config)
 {
        unsigned short  id;
-       char            tmp[100];
+       char tmp[100];
 
        devc->base = hw_config->io_base;
        devc->irq = hw_config->irq;
@@ -350,20+335,20 @@ attach_pss(struct address_info *hw_config)
 
 #if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES
        if (sound_alloc_dma(hw_config->dma, "PSS"))
-         {
-                 printk("pss.c: Can't allocate DMA channel\n");
-                 return;
-         }
+       {
+               printk("pss.c: Can't allocate DMA channel.\n");
+               return;
+       }
        if (!set_irq(devc, CONF_PSS, devc->irq))
-         {
-                 printk("PSS: IRQ error\n");
-                 return;
-         }
+       {
+               printk("PSS: IRQ allocation error.\n");
+               return;
+       }
        if (!set_dma(devc, CONF_PSS, devc->dma))
-         {
-                 printk("PSS: DRQ error\n");
-                 return;
-         }
+       {
+               printk(KERN_ERR "PSS: DMA allocation error\n");
+               return;
+       }
 #endif
 
        pss_initialized = 1;
@@ -371,8+356,7 @@ attach_pss(struct address_info *hw_config)
        conf_printf(tmp, hw_config);
 }
 
-static void
-pss_init_speaker(void)
+static void pss_init_speaker(void)
 {
 /* Don't ask what are these commands. I really don't know */
        pss_write(0x0010);
@@ -387,53+371,52 @@ pss_init_speaker(void)
        pss_write(0x0800 | 0x00ce);     /* Stereo switch? */
 }
 
-int
-probe_pss_mpu(struct address_info *hw_config)
+int probe_pss_mpu(struct address_info *hw_config)
 {
-       int             timeout;
+       int timeout;
 
        if (!pss_initialized)
                return 0;
 
        if (check_region(hw_config->io_base, 2))
-         {
-                 printk("PSS: MPU I/O port conflict\n");
-                 return 0;
-         }
+       {
+               printk("PSS: MPU I/O port conflict\n");
+               return 0;
+       }
        if (!set_io_base(devc, CONF_MIDI, hw_config->io_base))
-         {
-                 printk("PSS: MIDI base error.\n");
+       {
+                 printk("PSS: MIDI base could not be set.\n");
                  return 0;
-         }
+       }
        if (!set_irq(devc, CONF_MIDI, hw_config->irq))
-         {
-                 printk("PSS: MIDI IRQ error.\n");
+       {
+                 printk("PSS: MIDI IRQ allocation error.\n");
                  return 0;
-         }
+       }
        if (!pss_synthLen)
-         {
-                 printk("PSS: Can't enable MPU. MIDI synth microcode not available.\n");
-                 return 0;
-         }
+       {
+               printk(KERN_ERR "PSS: Can't enable MPU. MIDI synth microcode not available.\n");
+               return 0;
+       }
        if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
-         {
-                 printk("PSS: Unable to load MIDI synth microcode to DSP.\n");
-                 return 0;
-         }
+       {
+               printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n");
+               return 0;
+       }
        pss_init_speaker();
 
-/*
- * Finally wait until the DSP algorithm has initialized itself and
- * deactivates receive interrupt.
- */
+       /*
       * Finally wait until the DSP algorithm has initialized itself and
       * deactivates receive interrupt.
       */
 
        for (timeout = 900000; timeout > 0; timeout--)
-         {
-                 if ((inb(hw_config->io_base + 1) & 0x80) == 0)        /* Input data avail */
-                         inb(hw_config->io_base);      /* Discard it */
-                 else
-                         break;        /* No more input */
-         }
+       {
+               if ((inb(hw_config->io_base + 1) & 0x80) == 0)  /* Input data avail */
+                       inb(hw_config->io_base);        /* Discard it */
+               else
+                       break;  /* No more input */
+       }
 
 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
        return probe_mpu401(hw_config);
@@ -442,62+425,56 @@ probe_pss_mpu(struct address_info *hw_config)
 #endif
 }
 
-static int
-pss_coproc_open(void *dev_info, int sub_device)
+static int pss_coproc_open(void *dev_info, int sub_device)
 {
        switch (sub_device)
-         {
-         case COPR_MIDI:
-
-                 if (pss_synthLen == 0)
-                   {
-                           printk("PSS: MIDI synth microcode not available.\n");
-                           return -EIO;
-                   }
-                 if (nonstandard_microcode)
-                         if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
-                           {
-                                   printk("PSS: Unable to load MIDI synth microcode to DSP.\n");
-                                   return -EIO;
-                           }
-                 nonstandard_microcode = 0;
-                 break;
-
-         default:;
-         }
+       {
+               case COPR_MIDI:
+                       if (pss_synthLen == 0)
+                       {
+                               printk(KERN_ERR "PSS: MIDI synth microcode not available.\n");
+                               return -EIO;
+                       }
+                       if (nonstandard_microcode)
+                               if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
+                       {
+                               printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n");
+                               return -EIO;
+                       }
+                       nonstandard_microcode = 0;
+                       break;
+
+               default:
+       }
        return 0;
 }
 
-static void
-pss_coproc_close(void *dev_info, int sub_device)
+static void pss_coproc_close(void *dev_info, int sub_device)
 {
        return;
 }
 
-static void
-pss_coproc_reset(void *dev_info)
+static void pss_coproc_reset(void *dev_info)
 {
        if (pss_synthLen)
                if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
-                 {
-                         printk("PSS: Unable to load MIDI synth microcode to DSP.\n");
-                 }
+               {
+                       printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n");
+               }
        nonstandard_microcode = 0;
 }
 
-static int
-download_boot_block(void *dev_info, copr_buffer * buf)
+static int download_boot_block(void *dev_info, copr_buffer * buf)
 {
        if (buf->len <= 0 || buf->len > sizeof(buf->data))
                return -EINVAL;
 
        if (!pss_download_boot(devc, buf->data, buf->len, buf->flags))
-         {
-                 printk("PSS: Unable to load microcode block to DSP.\n");
-                 return -EIO;
-         }
+       {
+               printk(KERN_ERR "PSS: Unable to load microcode block to DSP.\n");
+               return -EIO;
+       }
        nonstandard_microcode = 1;      /* The MIDI microcode has been overwritten */
-
        return 0;
 }
 
@@ -512,169+489,170 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int l
        int i, err;
        /* printk( "PSS coproc ioctl %x %x %d\n",  cmd,  arg,  local); */
        
-       switch (cmd) {
-       case SNDCTL_COPR_RESET:
-               pss_coproc_reset(dev_info);
-               return 0;
+       switch (cmd) 
+       {
+               case SNDCTL_COPR_RESET:
+                       pss_coproc_reset(dev_info);
+                       return 0;
 
-       case SNDCTL_COPR_LOAD:
-               buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
-               if (buf == NULL)
-                       return -ENOSPC;
-               if (__copy_from_user(buf, arg, sizeof(copr_buffer))) {
+               case SNDCTL_COPR_LOAD:
+                       buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
+                       if (buf == NULL)
+                               return -ENOSPC;
+                       if (copy_from_user(buf, arg, sizeof(copr_buffer))) {
+                               vfree(buf);
+                               return -EFAULT;
+                       }
+                       err = download_boot_block(dev_info, buf);
                        vfree(buf);
-                       return -EFAULT;
-               }
-               err = download_boot_block(dev_info, buf);
-               vfree(buf);
-               return err;
+                       return err;
                
-       case SNDCTL_COPR_SENDMSG:
-               mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
-               if (mbuf == NULL)
-                       return -ENOSPC;
-               if (__copy_from_user(mbuf, arg, sizeof(copr_msg))) {
-                       vfree(mbuf);
-                       return -EFAULT;
-               }
-               data = (unsigned short *)(mbuf->data);
-               save_flags(flags);
-               cli();
-               for (i = 0; i < mbuf->len; i++) {
-                       if (!pss_put_dspword(devc, *data++)) {
-                               restore_flags(flags);
-                               mbuf->len = i;  /* feed back number of WORDs sent */
-                               err = __copy_to_user(arg, mbuf, sizeof(copr_msg));
+               case SNDCTL_COPR_SENDMSG:
+                       mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+                       if (mbuf == NULL)
+                               return -ENOSPC;
+                       if (copy_from_user(mbuf, arg, sizeof(copr_msg))) {
                                vfree(mbuf);
-                               return err ? -EFAULT : -EIO;
+                               return -EFAULT;
                        }
-               }
-               restore_flags(flags);
-               vfree(mbuf);
-               return 0;
-
-       case SNDCTL_COPR_RCVMSG:
-               err = 0;
-               mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
-               if (mbuf == NULL)
-                       return -ENOSPC;
-               data = (unsigned short *)mbuf->data;
-               save_flags(flags);
-               cli();
-               for (i = 0; i < mbuf->len; i++) {
-                       mbuf->len = i;  /* feed back number of WORDs read */
-                       if (!pss_get_dspword(devc, data++)) {
-                               if (i == 0)
-                                       err = -EIO;
-                               break;
+                       data = (unsigned short *)(mbuf->data);
+                       save_flags(flags);
+                       cli();
+                       for (i = 0; i < mbuf->len; i++) {
+                               if (!pss_put_dspword(devc, *data++)) {
+                                       restore_flags(flags);
+                                       mbuf->len = i;  /* feed back number of WORDs sent */
+                                       err = copy_to_user(arg, mbuf, sizeof(copr_msg));
+                                       vfree(mbuf);
+                                       return err ? -EFAULT : -EIO;
+                               }
                        }
-               }
-               restore_flags(flags);
-               if (__copy_to_user(arg, mbuf, sizeof(copr_msg)))
-                       err = -EFAULT;
-               vfree(mbuf);
-               return err;
-               
-       case SNDCTL_COPR_RDATA:
-               if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
-                       return -EFAULT;
-               save_flags(flags);
-               cli();
-               if (!pss_put_dspword(devc, 0x00d0)) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
                        restore_flags(flags);
-                       return -EIO;
-               }
-               if (!pss_get_dspword(devc, &tmp)) {
+                       vfree(mbuf);
+                       return 0;
+
+               case SNDCTL_COPR_RCVMSG:
+                       err = 0;
+                       mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+                       if (mbuf == NULL)
+                               return -ENOSPC;
+                       data = (unsigned short *)mbuf->data;
+                       save_flags(flags);
+                       cli();
+                       for (i = 0; i < mbuf->len; i++) {
+                               mbuf->len = i;  /* feed back number of WORDs read */
+                               if (!pss_get_dspword(devc, data++)) {
+                                       if (i == 0)
+                                               err = -EIO;
+                                       break;
+                               }
+                       }
                        restore_flags(flags);
-                       return -EIO;
-               }
-               dbuf.parm1 = tmp;
-               restore_flags(flags);
-               if (__copy_to_user(arg, &dbuf, sizeof(dbuf)))
-                       return -EFAULT;
-               return 0;
+                       if (copy_to_user(arg, mbuf, sizeof(copr_msg)))
+                               err = -EFAULT;
+                       vfree(mbuf);
+                       return err;
                
-       case SNDCTL_COPR_WDATA:
-               if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
-                       return -EFAULT;
-               save_flags(flags);
-               cli();
-               if (!pss_put_dspword(devc, 0x00d1)) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               tmp = (unsigned int)dbuf.parm2 & 0xffff;
-               if (!pss_put_dspword(devc, tmp)) {
+               case SNDCTL_COPR_RDATA:
+                       if (copy_from_user(&dbuf, arg, sizeof(dbuf)))
+                               return -EFAULT;
+                       save_flags(flags);
+                       cli();
+                       if (!pss_put_dspword(devc, 0x00d0)) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       if (!pss_get_dspword(devc, &tmp)) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       dbuf.parm1 = tmp;
                        restore_flags(flags);
-                       return -EIO;
-               }
-               restore_flags(flags);
-               return 0;
+                       if (copy_to_user(arg, &dbuf, sizeof(dbuf)))
+                               return -EFAULT;
+                       return 0;
                
-       case SNDCTL_COPR_WCODE:
-               if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
-                       return -EFAULT;
-               save_flags(flags);
-               cli();
-               if (!pss_put_dspword(devc, 0x00d3)) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               tmp = (unsigned int)dbuf.parm2 & 0x00ff;
-               if (!pss_put_dspword(devc, tmp)) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff;
-               if (!pss_put_dspword(devc, tmp)) {
+               case SNDCTL_COPR_WDATA:
+                       if (copy_from_user(&dbuf, arg, sizeof(dbuf)))
+                               return -EFAULT;
+                       save_flags(flags);
+                       cli();
+                       if (!pss_put_dspword(devc, 0x00d1)) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       tmp = (unsigned int)dbuf.parm2 & 0xffff;
+                       if (!pss_put_dspword(devc, tmp)) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
                        restore_flags(flags);
-                       return -EIO;
-               }
-               restore_flags(flags);
-               return 0;
+                       return 0;
                
-       case SNDCTL_COPR_RCODE:
-               if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
-                       return -EFAULT;
-               save_flags(flags);
-               cli();
-               if (!pss_put_dspword(devc, 0x00d2)) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */
+               case SNDCTL_COPR_WCODE:
+                       if (copy_from_user(&dbuf, arg, sizeof(dbuf)))
+                               return -EFAULT;
+                       save_flags(flags);
+                       cli();
+                       if (!pss_put_dspword(devc, 0x00d3)) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       tmp = (unsigned int)dbuf.parm2 & 0x00ff;
+                       if (!pss_put_dspword(devc, tmp)) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff;
+                       if (!pss_put_dspword(devc, tmp)) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
                        restore_flags(flags);
-                       return -EIO;
-               }
-               dbuf.parm1 = tmp << 8;
-               if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */
+                       return 0;
+               
+               case SNDCTL_COPR_RCODE:
+                       if (copy_from_user(&dbuf, arg, sizeof(dbuf)))
+                               return -EFAULT;
+                       save_flags(flags);
+                       cli();
+                       if (!pss_put_dspword(devc, 0x00d2)) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       dbuf.parm1 = tmp << 8;
+                       if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */
+                               restore_flags(flags);
+                               return -EIO;
+                       }
+                       dbuf.parm1 |= tmp & 0x00ff;
                        restore_flags(flags);
-                       return -EIO;
-               }
-               dbuf.parm1 |= tmp & 0x00ff;
-               restore_flags(flags);
-               if (__copy_to_user(arg, &dbuf, sizeof(dbuf)))
-                       return -EFAULT;
-               return 0;
+                       if (copy_to_user(arg, &dbuf, sizeof(dbuf)))
+                               return -EFAULT;
+                       return 0;
 
-       default:
-               return -EINVAL;
+               default:
+                       return -EINVAL;
        }
        return -EINVAL;
 }
@@ -689,52+667,47 @@ static coproc_operations pss_coproc_operations =
        &pss_data
 };
 
-void
-attach_pss_mpu(struct address_info *hw_config)
+void attach_pss_mpu(struct address_info *hw_config)
 {
 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
-       {
-               attach_mpu401(hw_config);       /* Slot 1 */
-
-               if (hw_config->slots[1] != -1)  /* The MPU driver installed itself */
-                       midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations;
-       }
+       attach_mpu401(hw_config);       /* Slot 1 */
+       if (hw_config->slots[1] != -1)  /* The MPU driver installed itself */
+               midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations;
 #endif
 }
 
-int
-probe_pss_mss(struct address_info *hw_config)
+int probe_pss_mss(struct address_info *hw_config)
 {
-       volatile int    timeout;
+       volatile int timeout;
 
        if (!pss_initialized)
                return 0;
 
        if (check_region(hw_config->io_base, 8))
-         {
-                 printk("PSS: WSS I/O port conflict\n");
+       {
+                 printk(KERN_ERR "PSS: WSS I/O port conflicts.\n");
                  return 0;
-         }
+       }
        if (!set_io_base(devc, CONF_WSS, hw_config->io_base))
-         {
-                 printk("PSS: WSS base error.\n");
-                 return 0;
-         }
+       {
+               printk("PSS: WSS base not settable.\n");
+               return 0;
+       }
        if (!set_irq(devc, CONF_WSS, hw_config->irq))
-         {
-                 printk("PSS: WSS IRQ error.\n");
-                 return 0;
-         }
+       {
+               printk("PSS: WSS IRQ allocation error.\n");
+               return 0;
+       }
        if (!set_dma(devc, CONF_WSS, hw_config->dma))
-         {
-                 printk("PSS: WSS DRQ error\n");
-                 return 0;
-         }
+       {
+               printk(KERN_ERR "PSS: WSS DMA allocation error\n");
+               return 0;
+       }
        /*
-          * For some reason the card returns 0xff in the WSS status register
-          * immediately after boot. Probably MIDI+SB emulation algorithm
-          * downloaded to the ADSP2115 spends some time initializing the card.
-          * Let's try to wait until it finishes this task.
+        * For some reason the card returns 0xff in the WSS status register
+        * immediately after boot. Probably MIDI+SB emulation algorithm
+        * downloaded to the ADSP2115 spends some time initializing the card.
+        * Let's try to wait until it finishes this task.
         */
        for (timeout = 0;
        timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04;
@@ -748,8+721,7 @@ probe_pss_mss(struct address_info *hw_config)
        return probe_ms_sound(hw_config);
 }
 
-void
-attach_pss_mss(struct address_info *hw_config)
+void attach_pss_mss(struct address_info *hw_config)
 {
        attach_ms_sound(hw_config);     /* Slot 0 */
 
@@ -757,34+729,31 @@ attach_pss_mss(struct address_info *hw_config)
                audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations;
 }
 
-void
-unload_pss(struct address_info *hw_config)
+void unload_pss(struct address_info *hw_config)
 {
 }
 
-void
-unload_pss_mpu(struct address_info *hw_config)
+void unload_pss_mpu(struct address_info *hw_config)
 {
 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
        unload_mpu401(hw_config);
 #endif
 }
 
-void
-unload_pss_mss(struct address_info *hw_config)
+void unload_pss_mss(struct address_info *hw_config)
 {
        unload_ms_sound(hw_config);
 }
 
 #ifdef MODULE
 
-int pss_io = 0x220;
+int pss_io = -1;
 
-int mss_io = 0x530;
-int mss_irq = 11;
-int mss_dma = 1;
+int mss_io = -1;
+int mss_irq = -1;
+int mss_dma = -1;
 
-int mpu_io = 0x330;
+int mpu_io = -1;
 int mpu_irq = -1;
 
 struct address_info cfgpss = { 0 /* pss_io */, 0, -1, -1 };
@@ -798,22+767,20 @@ MODULE_PARM(mss_dma, "i");
 MODULE_PARM(mpu_io, "i");
 MODULE_PARM(mpu_irq, "i");
 
-static int      fw_load = 0;
-static int      pssmpu = 0, pssmss = 0;
+static int fw_load = 0;
+static int pssmpu = 0, pssmss = 0;
 
 /*
  *    Load a PSS sound card module
  */
 
-int 
-init_module(void)
+int init_module(void)
 {
-#if 0
-       if (pss_io == -1 || irq == -1 || dma == -1) {
-                 printk("pss: dma, irq and io must be set.\n");
-                 return -EINVAL;
+       if (pss_io == -1 || mss_io == -1 || mss_irq == -1 || mss_dma == -1) {
+               printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n");
+               return -EINVAL;
        }
-#endif
+
        cfgpss.io_base = pss_io;
 
        cfgmss.io_base = mss_io;
@@ -823,7+790,8 @@ init_module(void)
        cfgmpu.io_base = mpu_io;
        cfgmpu.irq = mpu_irq;
 
-       if (!pss_synth) {
+       if (!pss_synth) 
+       {
                fw_load = 1;
                pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth);
        }
@@ -845,8+813,7 @@ init_module(void)
        return 0;
 }
 
-void 
-cleanup_module(void)
+void cleanup_module(void)
 {
        if (fw_load && pss_synth)
                kfree(pss_synth);
index 9a0fe3c..bf3a8db 100644 (file)
@@ -1151,14+1151,14 @@ void sb_audio_init(sb_devc * devc, char *name)
        }
 
        if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
-                                                  name,
-                                                  driver,
-                                            sizeof(struct audio_driver),
-                                                  audio_flags,
-                                                  format_mask,
-                                                  devc,
-                                                  devc->dma8,
-                                                  devc->dma8)) < 0)
+                                               name,
+                                               driver,
+                                               sizeof(struct audio_driver),
+                                               audio_flags,
+                                               format_mask,
+                                               devc,
+                                               devc->dma8,
+                                               devc->dma8)) < 0)
        {
                  printk(KERN_ERR "sb: unable to install audio.\n");
                  return;
index fddf74b..941422c 100644 (file)
@@ -69,6+69,7 @@ int             trix = 0;     /* Set trix=1 to load this as support for trix */
 int             pas2 = 0;      /* Set pas2=1 to load this as support for pas2 */
 int             sm_games = 0;  /* Mixer - see sb_mixer.c */
 int             acer = 0;      /* Do acer notebook init */
+int            mwave_bug = 0;  /* Using the dreadful mwave sb emulation */
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
@@ -80,10+81,11 @@ MODULE_PARM(mad16, "i");
 MODULE_PARM(trix, "i");
 MODULE_PARM(pas2, "i");
 MODULE_PARM(sm_games, "i");
+MODULE_PARM(mwave_bug, "i");
 
-static int      sbmpu = 0;
+static int sbmpu = 0;
 
-void           *smw_free = NULL;
+void *smw_free = NULL;
 
 int init_module(void)
 {
@@ -119,8+121,7 @@ int init_module(void)
        return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
        if (smw_free)
                kfree(smw_free);
@@ -133,19+134,20 @@ cleanup_module(void)
 
 #else
 
-#ifdef SM_GAMES
+#ifdef CONFIG_SM_GAMES
 int             sm_games = 1;
-
 #else
 int             sm_games = 0;
-
 #endif
-#ifdef SB_ACER
+#ifdef CONFIG_SB_ACER
 int             acer = 1;
-
 #else
 int             acer = 0;
-
+#endif
+#ifdef CONFIG_SB_MWAVE
+int            mwave_bug = 1;
+#else
+int            mwave_bug = 0;
 #endif
 #endif
 #endif
index 0f3e1e6..fcdcfcf 100644 (file)
 
 static sb_devc *detected_devc = NULL;  /* For communication from probe to init */
 static sb_devc *last_devc = NULL;      /* For MPU401 initialization */
-static sb_devc *irq2devc[16] = {NULL};
 static unsigned char jazz_irq_bits[] = {
        0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6
 };
@@ -123,15+122,9 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy)
        int status;
        unsigned char   src = 0xff;
 
-       sb_devc *devc = irq2devc[irq];
+       sb_devc *devc = dev_id;
 
-       if (devc == NULL || devc->irq != irq)
-       {
-               DEB(printk("sbintr: Bogus interrupt IRQ%d\n", irq));
-               return;
-       }
        devc->irq_ok = 1;
-
        if (devc->model == MDL_SB16)
        {
                src = sb_getmixer(devc, IRQ_STAT);      /* Interrupt source register */
@@ -710,6+703,7 @@ void sb_dsp_init(struct address_info *hw_config)
        sb_devc *devc;
        char name[100];
        extern int sb_be_quiet;
+       extern int mwave_bug;
 
 /*
  * Check if we had detected a SB device earlier
@@ -743,21+737,19 @@ void sb_dsp_init(struct address_info *hw_config)
 
        if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && hw_config->irq > 0)
        {                       /* IRQ setup */
-               if (snd_set_irq_handler(hw_config->irq, sbintr, "soundblaster", devc->osp) < 0)
+               if (request_irq(hw_config->irq, sbintr, 0, "soundblaster", devc) < 0)
                {
                        printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq);
                        sound_unload_audiodev(devc->dev);
                        return;
                }
-               irq2devc[hw_config->irq] = devc;
                devc->irq_ok = 0;
 
                if (devc->major == 4)
                        if (!sb16_set_irq_hw(devc, devc->irq))  /* Unsupported IRQ */
                        {
-                               snd_release_irq(devc->irq);
+                               free_irq(devc->irq, devc);
                                sound_unload_audiodev(devc->dev);
-                               irq2devc[hw_config->irq] = NULL;
                                return;
                        }
                if ((devc->type == 0 || devc->type == MDL_ESS) &&
@@ -777,7+769,7 @@ void sb_dsp_init(struct address_info *hw_config)
                /* Skip IRQ detection if SMP (doesn't work) */
                devc->irq_ok = 1;
 #else
-               if (devc->major == 4 && devc->minor <= 11)      /* Won't work */
+               if ((devc->major == 4 && devc->minor <= 11 ) || mwave_bug )     /* Won't work */
                        devc->irq_ok = 1;
                else
                {
@@ -883,6+875,7 @@ void sb_dsp_init(struct address_info *hw_config)
                }
        }
        hw_config->card_subtype = devc->model;
+       hw_config->slots[0]=devc->dev;
        last_devc = devc;       /* For SB MPU detection */
 
        if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0)
@@ -915,15+908,8 @@ void sb_dsp_disable_recording(int io_base)
 void sb_dsp_unload(struct address_info *hw_config)
 {
        sb_devc *devc;
-       int irq = hw_config->irq;
 
-       if (irq < 0)
-               irq *= -1;
-
-       if (irq > 2 && irq < 16)
-               devc = irq2devc[irq];
-       else
-               devc = NULL;
+       devc = audio_devs[hw_config->slots[0]]->devc;
 
        if (devc && devc->base == hw_config->io_base)
        {
@@ -937,12+923,12 @@ void sb_dsp_unload(struct address_info *hw_config)
                }
                if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0)
                {
-                       snd_release_irq(devc->irq);
-                       irq2devc[devc->irq] = NULL;
+                       free_irq(devc->irq, devc);
                        sound_unload_mixerdev(devc->my_mixerdev);
                        sound_unload_mididev(devc->my_mididev);
                        sound_unload_audiodev(devc->my_dev);
                }
+               kfree(devc);
        }
        else
                release_region(hw_config->io_base, 16);
index 0ed168e..416737f 100644 (file)
@@ -83,8+83,9 @@ void MIDIbuf_init(void);
 /*     From soundcard.c        */
 void request_sound_timer (int count);
 void sound_stop_timer(void);
-int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp);
-void snd_release_irq(int vect);
+/* These two are about to die.. */
+int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp, void *dev_id);
+void snd_release_irq(int vect, void *ptr);
 void sound_dma_malloc(int dev);
 void sound_dma_free(int dev);
 void conf_printf(char *name, struct address_info *hw_config);
index 8a519e7..9866683 100644 (file)
@@ -47,6+47,14 @@ void reprogram_timer(void)
 {
        unsigned long   usecs_per_tick;
 
+       /*
+        *      The user is changing the timer rate before setting a timer
+        *      slap, bad bad not allowed.
+        */
+        
+       if(!tmr)
+               return;
+               
        usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
 
        /*
index 2e4cce0..fe3622a 100644 (file)
 #include <linux/fcntl.h>
 #include <linux/ctype.h>
 #include <linux/stddef.h>
+#include <linux/kmod.h>
 #ifdef __KERNEL__
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -438,7+439,7 @@ static int sound_open(struct inode *inode, struct file *file)
 
        case SND_DEV_CTL:
                dev >>= 4;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
        if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
                char modname[20];
                sprintf(modname, "mixer%d", dev);
@@ -554,14+555,14 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, caddr_t arg)
 {
        if (mixdev < 0 || mixdev >= MAX_MIXER_DEV)
                return -ENXIO;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
        /* Try to load the mixer... */
        if (mixer_devs[mixdev] == NULL) {
                char modname[20];
                sprintf(modname, "mixer%d", mixdev);
                request_module(modname);
        }
-#endif /* CONFIG_KERNELD */
+#endif /* CONFIG_KMOD */
        if (mixdev >= num_mixers || !mixer_devs[mixdev])
                return -ENXIO;
        if (cmd == SOUND_MIXER_INFO)
@@ -800,7+801,7 @@ free_all_irqs(void)
                if (irqs & (1ul << i))
                {
                        printk(KERN_WARNING "Sound warning: IRQ%d was left allocated - fixed.\n", i);
-                       snd_release_irq(i);
+                       snd_release_irq(i, NULL);
                }
        }
        irqs = 0;
@@ -894,14+895,14 @@ void cleanup_module(void)
 }
 #endif
 
-int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp)
+int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp, void *dev_id)
 {
-       int             retcode;
-       unsigned long   flags;
+       int retcode;
+       unsigned long flags;
 
        save_flags(flags);
        cli();
-       retcode = request_irq(interrupt_level, iproc, 0, name, NULL);
+       retcode = request_irq(interrupt_level, iproc, 0, name, dev_id);
        
        if (retcode < 0)
        {
@@ -914,13+915,13 @@ int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct
        return retcode;
 }
 
-void snd_release_irq(int vect)
+void snd_release_irq(int vect, void *dev_id)
 {
        if (!(irqs & (1ul << vect)))
                return;
 
        irqs &= ~(1ul << vect);
-       free_irq(vect, NULL);
+       free_irq(vect, dev_id);
 }
 
 int sound_alloc_dma(int chn, char *deviceID)
index 7293e90..2e7ed2a 100644 (file)
@@ -9,7+9,15 @@
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
+ *
+ * Changes:
+ *     Alan Cox        Reformatted, removed sound_mem usage, use normal Linux
+ *                     interrupt allocation.
+ *
+ * Status:
+ *             Untested
  */
 #include <linux/config.h>
 #include <linux/module.h>
 
 #if (defined(CONFIG_UART401)||defined(CONFIG_MIDI)) || defined(MODULE)
 
 typedef struct uart401_devc
-  {
-         int             base;
-         int             irq;
-         int            *osp;
-         void            (*midi_input_intr) (int dev, unsigned char data);
-         int             opened, disabled;
-         volatile unsigned char input_byte;
-         int             my_dev;
-         int             share_irq;
-  }
+{
+       int             base;
+       int             irq;
+       int            *osp;
+       void            (*midi_input_intr) (int dev, unsigned char data);
+       int             opened, disabled;
+       volatile unsigned char input_byte;
+       int             my_dev;
+       int             share_irq;
+}
 uart401_devc;
 
 static uart401_devc *detected_devc = NULL;
-static uart401_devc *irq2devc[16] =
-{NULL};
 
 #define        DATAPORT   (devc->base)
 #define        COMDPORT   (devc->base+1)
 #define        STATPORT   (devc->base+1)
 
-static int
-uart401_status(uart401_devc * devc)
+static int uart401_status(uart401_devc * devc)
 {
        return inb(STATPORT);
 }
+
 #define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL))
 #define output_ready(devc)     (!(uart401_status(devc)&OUTPUT_READY))
-static void
-uart401_cmd(uart401_devc * devc, unsigned char cmd)
+
+static void uart401_cmd(uart401_devc * devc, unsigned char cmd)
 {
        outb((cmd), COMDPORT);
 }
-static int
-uart401_read(uart401_devc * devc)
+
+static int uart401_read(uart401_devc * devc)
 {
        return inb(DATAPORT);
 }
-static void
-uart401_write(uart401_devc * devc, unsigned char byte)
+
+static void uart401_write(uart401_devc * devc, unsigned char byte)
 {
        outb((byte), DATAPORT);
 }
@@ -71,30+77,26 @@ uart401_write(uart401_devc * devc, unsigned char byte)
 static int      reset_uart401(uart401_devc * devc);
 static void     enter_uart_mode(uart401_devc * devc);
 
-static void
-uart401_input_loop(uart401_devc * devc)
+static void uart401_input_loop(uart401_devc * devc)
 {
        while (input_avail(devc))
-         {
-                 unsigned char   c = uart401_read(devc);
-
-                 if (c == MPU_ACK)
-                         devc->input_byte = c;
-                 else if (devc->opened & OPEN_READ && devc->midi_input_intr)
-                         devc->midi_input_intr(devc->my_dev, c);
-         }
+       {
+               unsigned char   c = uart401_read(devc);
+
+               if (c == MPU_ACK)
+                       devc->input_byte = c;
+               else if (devc->opened & OPEN_READ && devc->midi_input_intr)
+                       devc->midi_input_intr(devc->my_dev, c);
+       }
 }
 
-void
-uart401intr(int irq, void *dev_id, struct pt_regs *dummy)
+void uart401intr(int irq, void *dev_id, struct pt_regs *dummy)
 {
-       uart401_devc   *devc;
+       uart401_devc *devc = dev_id;
 
        if (irq < 1 || irq > 15)
                return;
 
-       devc = irq2devc[irq];
-
        if (devc == NULL)
                return;
 
@@ -108,12+110,12 @@ uart401_open(int dev, int mode,
             void            (*output) (int dev)
 )
 {
-       uart401_devc   *devc = (uart401_devc *) midi_devs[dev]->devc;
+       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
 
        if (devc->opened)
-         {
-                 return -EBUSY;
-         }
+       {
+               return -EBUSY;
+       }
        while (input_avail(devc))
                uart401_read(devc);
 
@@ -125,21+127,19 @@ uart401_open(int dev, int mode,
        return 0;
 }
 
-static void
-uart401_close(int dev)
+static void uart401_close(int dev)
 {
-       uart401_devc   *devc = (uart401_devc *) midi_devs[dev]->devc;
+       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
 
        reset_uart401(devc);
        devc->opened = 0;
 }
 
-static int
-uart401_out(int dev, unsigned char midi_byte)
+static int uart401_out(int dev, unsigned char midi_byte)
 {
-       int             timeout;
-       unsigned long   flags;
-       uart401_devc   *devc = (uart401_devc *) midi_devs[dev]->devc;
+       int timeout;
+       unsigned long flags;
+       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
 
        if (devc->disabled)
                return 1;
@@ -163,36+163,32 @@ uart401_out(int dev, unsigned char midi_byte)
        for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
 
        if (!output_ready(devc))
-         {
-                 printk("MPU-401: Timeout - Device not responding\n");
+       {
+                 printk(KERN_WARNING "uart401: Timeout - Device not responding\n");
                  devc->disabled = 1;
                  reset_uart401(devc);
                  enter_uart_mode(devc);
                  return 1;
-         }
+       }
        uart401_write(devc, midi_byte);
        return 1;
 }
 
-static int
-uart401_start_read(int dev)
+static int uart401_start_read(int dev)
 {
        return 0;
 }
 
-static int
-uart401_end_read(int dev)
+static int uart401_end_read(int dev)
 {
        return 0;
 }
 
-static void
-uart401_kick(int dev)
+static void uart401_kick(int dev)
 {
 }
 
-static int
-uart401_buffer_status(int dev)
+static int uart401_buffer_status(int dev)
 {
        return 0;
 }
@@ -203,7+199,9 @@ uart401_buffer_status(int dev)
 
 static struct midi_operations uart401_operations =
 {
-       {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401},
+       {
+               "MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401
+       },
        &std_midi_synth,
        {0},
        uart401_open,
@@ -218,11+216,10 @@ static struct midi_operations uart401_operations =
        NULL
 };
 
-static void
-enter_uart_mode(uart401_devc * devc)
+static void enter_uart_mode(uart401_devc * devc)
 {
-       int             ok, timeout;
-       unsigned long   flags;
+       int ok, timeout;
+       unsigned long flags;
 
        save_flags(flags);
        cli();
@@ -242,11+239,10 @@ enter_uart_mode(uart401_devc * devc)
        restore_flags(flags);
 }
 
-void
-attach_uart401(struct address_info *hw_config)
+void attach_uart401(struct address_info *hw_config)
 {
-       uart401_devc   *devc;
-       char           *name = "MPU-401 (UART) MIDI";
+       uart401_devc *devc;
+       char *name = "MPU-401 (UART) MIDI";
 
        if (hw_config->name)
                name = hw_config->name;
@@ -255,80+251,75 @@ attach_uart401(struct address_info *hw_config)
                return;
 
 
-       devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(uart401_devc)));
-       sound_mem_sizes[sound_nblocks] = sizeof(uart401_devc);
-       if (sound_nblocks < 1024)
-               sound_nblocks++;;
+       devc = (uart401_devc *) kmalloc(sizeof(uart401_devc), GFP_KERNEL);
        if (devc == NULL)
-         {
-                 printk(KERN_WARNING "uart401: Can't allocate memory\n");
-                 return;
-         }
+       {
+               printk(KERN_WARNING "uart401: Can't allocate memory\n");
+               return;
+       }
        memcpy((char *) devc, (char *) detected_devc, sizeof(uart401_devc));
        detected_devc = NULL;
 
        devc->irq = hw_config->irq;
        if (devc->irq < 0)
-         {
-                 devc->share_irq = 1;
-                 devc->irq *= -1;
-       } else
+       {
+               devc->share_irq = 1;
+               devc->irq *= -1;
+       }
+       else
                devc->share_irq = 0;
 
        if (devc->irq < 1 || devc->irq > 15)
+       {
+               kfree(devc);
                return;
+       }
 
        if (!devc->share_irq)
-               if (snd_set_irq_handler(devc->irq, uart401intr, "MPU-401 UART", devc->osp) < 0)
-                 {
-                         printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq);
-                         devc->share_irq = 1;
-                 }
-       irq2devc[devc->irq] = devc;
+       {
+               if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0)
+               {
+                       printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq);
+                       devc->share_irq = 1;
+               }
+       }
        devc->my_dev = sound_alloc_mididev();
 
        request_region(hw_config->io_base, 4, "MPU-401 UART");
        enter_uart_mode(devc);
 
        if (devc->my_dev == -1)
-         {
-                 printk(KERN_INFO "uart401: Too many midi devices detected\n");
-                 return;
-         }
+       {
+               printk(KERN_INFO "uart401: Too many midi devices detected\n");
+               kfree(devc);
+               return;
+       }
        conf_printf(name, hw_config);
 
        std_midi_synth.midi_dev = devc->my_dev;
-
-
-       midi_devs[devc->my_dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations)));
-       sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations);
-
-       if (sound_nblocks < 1024)
-               sound_nblocks++;;
+       midi_devs[devc->my_dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
        if (midi_devs[devc->my_dev] == NULL)
-         {
-                 printk("uart401: Failed to allocate memory\n");
-                 sound_unload_mididev(devc->my_dev);
-                 return;
-         }
+       {
+               printk(KERN_ERR "uart401: Failed to allocate memory\n");
+               sound_unload_mididev(devc->my_dev);
+               kfree(devc);
+               devc=NULL;
+               return;
+       }
        memcpy((char *) midi_devs[devc->my_dev], (char *) &uart401_operations,
               sizeof(struct midi_operations));
 
        midi_devs[devc->my_dev]->devc = devc;
-
-
-       midi_devs[devc->my_dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations)));
-       sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations);
-
-       if (sound_nblocks < 1024)
-               sound_nblocks++;
-
+       midi_devs[devc->my_dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
        if (midi_devs[devc->my_dev]->converter == NULL)
-         {
-                 printk(KERN_WARNING "uart401: Failed to allocate memory\n");
-                 sound_unload_mididev(devc->my_dev);
-                 return;
-         }
+       {
+               printk(KERN_WARNING "uart401: Failed to allocate memory\n");
+               sound_unload_mididev(devc->my_dev);
+               kfree(midi_devs[devc->my_dev]);
+               kfree(devc);
+               devc=NULL;
+               return;
+       }
        memcpy((char *) midi_devs[devc->my_dev]->converter, (char *) &std_midi_synth,
               sizeof(struct synth_operations));
 
@@ -339,10+330,9 @@ attach_uart401(struct address_info *hw_config)
        devc->opened = 0;
 }
 
-static int
-reset_uart401(uart401_devc * devc)
+static int reset_uart401(uart401_devc * devc)
 {
-       int             ok, timeout, n;
+       int ok, timeout, n;
 
        /*
         * Send the RESET command. Try again if no success at the first time.
@@ -351,31+341,33 @@ reset_uart401(uart401_devc * devc)
        ok = 0;
 
        for (n = 0; n < 2 && !ok; n++)
-         {
-                 for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
-
-                 devc->input_byte = 0;
-                 uart401_cmd(devc, MPU_RESET);
-
-                 /*
-                  * Wait at least 25 msec. This method is not accurate so let's make the
-                  * loop bit longer. Cannot sleep since this is called during boot.
-                  */
-
-                 for (timeout = 50000; timeout > 0 && !ok; timeout--)
-                         if (devc->input_byte == MPU_ACK)      /* Interrupt */
-                                 ok = 1;
-                         else if (input_avail(devc))
-                                 if (uart401_read(devc) == MPU_ACK)
-                                         ok = 1;
-
-         }
+       {
+               for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
+               devc->input_byte = 0;
+               uart401_cmd(devc, MPU_RESET);
+               /*
+                * Wait at least 25 msec. This method is not accurate so let's make the
+                * loop bit longer. Cannot sleep since this is called during boot.
+                */
+
+               for (timeout = 50000; timeout > 0 && !ok; timeout--)
+               {
+                       if (devc->input_byte == MPU_ACK)        /* Interrupt */
+                               ok = 1;
+                       else if (input_avail(devc))
+                       {
+                               if (uart401_read(devc) == MPU_ACK)
+                                       ok = 1;
+                       }
+               }
+       }
 
 
        if (ok)
-         {
-                 DEB(printk("Reset UART401 OK\n"));
-       } else
+       {
+               DEB(printk("Reset UART401 OK\n"));
+       }
+       else
                DDB(printk("Reset UART401 failed - No hardware detected.\n"));
 
        if (ok)
@@ -386,14+378,12 @@ reset_uart401(uart401_devc * devc)
        return ok;
 }
 
-int
-probe_uart401(struct address_info *hw_config)
+int probe_uart401(struct address_info *hw_config)
 {
-       int             ok = 0;
-       unsigned long   flags;
-
+       int ok = 0;
+       unsigned long flags;
        static uart401_devc hw_info;
-       uart401_devc   *devc = &hw_info;
+       uart401_devc *devc = &hw_info;
 
        DDB(printk("Entered probe_uart401()\n"));
 
@@ -422,21+412,10 @@ probe_uart401(struct address_info *hw_config)
        return ok;
 }
 
-void
-unload_uart401(struct address_info *hw_config)
+void unload_uart401(struct address_info *hw_config)
 {
-       uart401_devc   *devc;
-
-       int             irq = hw_config->irq;
-
-       if (irq < 0)
-         {
-                 irq *= -1;
-         }
-       if (irq < 1 || irq > 15)
-               return;
-
-       devc = irq2devc[irq];
+       uart401_devc *devc;
+       devc = midi_devs[hw_config->slots[4]]->devc;
        if (devc == NULL)
                return;
 
@@ -444,47+423,47 @@ unload_uart401(struct address_info *hw_config)
        release_region(hw_config->io_base, 4);
 
        if (!devc->share_irq)
-               snd_release_irq(devc->irq);
-
+               free_irq(devc->irq, devc);
+       sound_unload_mididev(hw_config->slots[4]);
        if (devc)
+       {
+               kfree(midi_devs[devc->my_dev]->converter);
+               kfree(midi_devs[devc->my_dev]);
+               kfree(devc);
                devc = NULL;
-       sound_unload_mididev(hw_config->slots[4]);
+       }
 }
 
 #ifdef MODULE
 
-int             io = -1;
-int             irq = -1;
+int io = -1;
+int irq = -1;
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 struct address_info hw;
 
-int 
-init_module(void)
+int init_module(void)
 {
        /* Can be loaded either for module use or to provide functions
           to others */
        if (io != -1 && irq != -1)
-         {
-                 printk("MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997");
-                 hw.irq = irq;
-                 hw.io_base = io;
-                 if (probe_uart401(&hw) == 0)
-                         return -ENODEV;
-                 attach_uart401(&hw);
-         }
+       {
+               printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997");
+               hw.irq = irq;
+               hw.io_base = io;
+               if (probe_uart401(&hw) == 0)
+                       return -ENODEV;
+               attach_uart401(&hw);
+       }
        SOUND_LOCK;
        return 0;
 }
 
-void 
-cleanup_module(void)
+void cleanup_module(void)
 {
        if (io != -1 && irq != -1)
-         {
-                 unload_uart401(&hw);
-         }
+               unload_uart401(&hw);
        /*  FREE SYMTAB */
        SOUND_LOCK_END;
 }
index 932be18..b26e75a 100644 (file)
  * Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver.
  * 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2.
  *
+ * Alan Cox:   Updated for new modular code. Removed snd_* irq handling. Now
+ *             uses native linux resources
+ *
+ *     Status: Testing required
+ *
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -297,7+302,7 @@ int probe_uart6850(struct address_info *hw_config)
        uart6850_base = hw_config->io_base;
        uart6850_irq = hw_config->irq;
 
-       if (snd_set_irq_handler(uart6850_irq, m6850intr, "MIDI6850", uart6850_osp) < 0)
+       if (request_irq(uart6850_irq, m6850intr, 0, "MIDI6850", NULL) < 0)
                return 0;
 
        ok = reset_uart6850();
@@ -307,7+312,7 @@ int probe_uart6850(struct address_info *hw_config)
 
 void unload_uart6850(struct address_info *hw_config)
 {
-       snd_release_irq(hw_config->irq);
+       free_irq(hw_config->irq, NULL);
        sound_unload_mididev(hw_config->slots[4]);
 }
 
index 12c221a..4820d5f 100644 (file)
  * sound/v_midi.c
  *
  * The low level driver for the Sound Blaster DS chips.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1996
  *
  * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  * ??
+ *
+ * Changes
+ *     Alan Cox                Modularisation, changed memory allocations
+ *
+ * Status
+ *     Untested
  */
+
 #include <linux/config.h>
 #include <linux/module.h>
 
index 7e45b22..ec844de 100644 (file)
@@ -731,7+731,8 @@ static void refill_freelist(int size)
        /* We are going to try to locate this much memory. */
        needed = bdf_prm.b_un.nrefill * size;  
 
-       while ((nr_free_pages > min_free_pages*2) && 
+       while ((nr_free_pages > freepages.min*2) &&
+               BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
                grow_buffers(GFP_BUFFER, size)) {
                obtained += PAGE_SIZE;
                if (obtained >= needed)
@@ -815,7+816,8 @@ repeat:
         * are _any_ free buffers.
         */
        while (obtained < (needed >> 1) &&
-              nr_free_pages > min_free_pages + 5 &&
+              nr_free_pages > freepages.min + 5 &&
+              BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
               grow_buffers(GFP_BUFFER, size))
                obtained += PAGE_SIZE;
 
index 7d4b2f3..916e88f 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -418,6+418,7 @@ static int exec_mmap(void)
        retval = new_page_tables(current);
        if (retval)
                goto fail_restore;
+       up(&mm->mmap_sem);
        mmput(old_mm);
        return 0;
 
index aa465a0..c063e3f 100644 (file)
-Wed Jan  7 19:33:33 1998  a sun  <asun@zoology.washington.edu>
+Wed Jan 21 14:04:26 1998  a sun  <asun@zoology.washington.edu>
+
+       * inode.c, sysdep.c
+       use d_iput to uncache dentry from catalog entry instead of relying
+       on put_inode. no more NULL pointer dereferences!
+
+       * catalog.c
+       cleaned up hfs_cat_put a little.
+       
+       ISSUES (non-fatal): mv dir dir2 while creating files in dir screws
+                           up directory counts.
+               
+                           deletion using netatalk screws up directory
+                           counts.
+
+Thu Jan 15 19:14:28 1998  a sun  <asun@zoology.washington.edu>
+
+       * catalog.c
+       make deletion happen when requested instead of waiting until
+       an hfs_cat_put as the dcache can hold onto entries for quite
+       some time.
+
+Wed Jan 14 14:43:16 1998  a sun  <asun@zoology.washington.edu>
+       
+       * catalog.c
+       the current catalog allocation scheme allocates
+       PAGE_SIZE/sizeof(struct hfs_cat_entry) entries at a time and keeps
+       a pool of free entries up to this allocation unit * 8.
 
        * inode.c
-       don't hfs_cat_put in hfs_iget. that's a bad idea and results
-       in screwed up entry counts.
+       make sure to always hfs_cat_put if hfs_iget is going to return
+       NULL.
+
+       * string.c, catalog.c
+       use linux' hashing method to generate hashes. the old hashing was
+       getting collisions. catalog.c also has a larger hash table to
+       prevent collisions.
+       
+Tue Jan 13 13:06:01 1998  a sun  <asun@zoology.washington.edu>
+
+       * version.c
+       bumped to 0.95+asun3
 
        * catalog.c
-       modified hfs_cat_put to undirty deleted entries without trying to 
-       write them out.
+       re-wrote to dynamically allocate/delete catalog entries. on a 486,
+       entries fit into the size-256 slab.
+
+Wed Jan  7 19:33:33 1998  a sun  <asun@zoology.washington.edu>
+
+       * inode.c 
+       don't hfs_cat_put gratuitously in hfs_iget. that's a bad
+       idea and results in screwed up entry counts.
 
 Tue Jan  6 14:38:24 1998  a sun  <asun@zoology.washington.edu>
 
index bab9a6e..7ea8e65 100644 (file)
@@ -1,5+1,5 @@
 #
-# Makefile for the linux nfs-filesystem routines.
+# Makefile for the linux hfs-filesystem routines.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
index 4055012..2435ceb 100644 (file)
  *
  * Cache code shamelessly stolen from 
  *     linux/fs/inode.c Copyright (C) 1991, 1992  Linus Torvalds
+ *     re-shamelessly stolen Copyright (C) 1997 Linus Torvalds
  *
  * In function preconditions the term "valid" applied to a pointer to
  * a structure means that the pointer is non-NULL and the structure it
 
 /*================ Variable-like macros ================*/
 
-#define NUM_FREE_ENTRIES 8
-
 /* Number of hash table slots */
-#define CCACHE_NR 128
-
-/* Max number of entries in memory */
-#define CCACHE_MAX 1024
+#define C_HASHBITS  10
+#define C_HASHSIZE  (1UL << C_HASHBITS)
+#define C_HASHMASK  (C_HASHSIZE - 1)
 
-/* Number of entries to fit in a single page on an i386 */
-#define CCACHE_INC ((PAGE_SIZE - sizeof(void *))/sizeof(struct hfs_cat_entry))
+/* Number of entries to fit in a single page on an i386.
+ * Actually, now it's used to increment the free entry pool. */
+#define CCACHE_INC (PAGE_SIZE/sizeof(struct hfs_cat_entry))
+#define CCACHE_MAX (CCACHE_INC * 8)
 
 /*================ File-local data types ================*/
 
@@ -94,18+94,11 @@ struct hfs_cat_rec {
        } u;
 };
 
-
-struct allocation_unit {
-       struct allocation_unit *next;
-       struct hfs_cat_entry entries[CCACHE_INC];
-};
-
 /*================ File-local variables ================*/
  
 static LIST_HEAD(entry_in_use);
-static LIST_HEAD(entry_dirty); /* all the dirty entries */
 static LIST_HEAD(entry_unused);
-static struct list_head hash_table[CCACHE_NR];
+static struct list_head hash_table[C_HASHSIZE];
 
 spinlock_t entry_lock = SPIN_LOCK_UNLOCKED;
 
@@ -114,8+107,6 @@ static struct {
         int nr_free_entries;
 } entries_stat;
 
-static struct allocation_unit *allocation = NULL;
-
 /*================ File-local functions ================*/
 
 /*
@@ -136,13+127,16 @@ static inline hfs_u32 brec_to_id(struct hfs_brec *brec)
  *
  * hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer.
  */
-static inline unsigned int hashfn(const struct hfs_mdb *mdb,
+static inline unsigned long hashfn(const struct hfs_mdb *mdb,
                                  const struct hfs_cat_key *key)
 {
 #define LSB(X) (((unsigned char *)(&X))[3])
-       return ((unsigned int)LSB(mdb->create_date) ^ 
-               (unsigned int)key->ParID[3] ^
-               hfs_strhash(&key->CName)) % CCACHE_NR;
+       unsigned long hash;
+       
+       hash = (unsigned long) mdb | (unsigned long) key->ParID[3] |
+         hfs_strhash(&key->CName);
+       hash = hash ^ (hash >> C_HASHBITS) ^ (hash >> C_HASHBITS*2);
+       return hash & C_HASHMASK;
 #undef LSB
 }
 
@@ -208,24+202,7 @@ static void unlock_entry(struct hfs_cat_entry * entry)
        hfs_wake_up(&entry->wait);
 }
 
-/*
- * clear_entry()
- *
- * Zero all the fields of an entry and place it on the free list.
- */
-static void clear_entry(struct hfs_cat_entry * entry)
-{
-       wait_on_entry(entry);
-       /* zero all but the wait queue */
-       memset(&entry->wait, 0,
-              sizeof(*entry) - offsetof(struct hfs_cat_entry, wait));
-       INIT_LIST_HEAD(&entry->hash);
-       INIT_LIST_HEAD(&entry->list);
-       INIT_LIST_HEAD(&entry->dirty);
-}
-
-/* put entry on mdb dirty list. this only does it if it's on the hash
- * list. we also add it to the global dirty list as well. */
+/* put entry on mdb dirty list. */
 void hfs_cat_mark_dirty(struct hfs_cat_entry *entry)
 {
         struct hfs_mdb *mdb = entry->mdb;
@@ -234,153+211,74 @@ void hfs_cat_mark_dirty(struct hfs_cat_entry *entry)
        if (!(entry->state & HFS_DIRTY)) {
                entry->state |= HFS_DIRTY;
 
-               /* Only add valid (ie hashed) entries to the
-                * dirty list */
+               /* Only add valid (ie hashed) entries to the dirty list. */
                if (!list_empty(&entry->hash)) {
                        list_del(&entry->list);
                        list_add(&entry->list, &mdb->entry_dirty);
-                       INIT_LIST_HEAD(&entry->dirty);
-                       list_add(&entry->dirty, &entry_dirty);
                }
        }
        spin_unlock(&entry_lock);
 }
 
-/* prune all entries */
-static void dispose_list(struct list_head *head)
+/* delete an entry and remove it from the hash table. */
+static void delete_entry(struct hfs_cat_entry *entry)
 {
-        struct list_head *next;
-       int count = 0;
-
-       next = head->next;
-       for (;;) {
-               struct list_head * tmp = next;
-
-               next = next->next;
-               if (tmp == head)
-                       break;
-               hfs_cat_prune(list_entry(tmp, struct hfs_cat_entry, list));
-               count++;
-       }
-}
-
-/*
- * try_to_free_entries works by getting the underlying 
- * cache system to release entries. it gets called with the entry lock
- * held. 
- *
- * count can be up to 2 due to both a resource and data fork being
- * listed. we can unuse dirty entries as well.
- */
-#define CAN_UNUSE(tmp) (((tmp)->count < 3) && ((tmp)->state <= HFS_DIRTY))
-static int try_to_free_entries(const int goal) 
-{
-        struct list_head *tmp, *head = &entry_in_use;
-       LIST_HEAD(freeable);
-       int found = 0, depth = goal << 1;
-
-       /* try freeing from entry_in_use */
-       while ((tmp = head->prev) != head && depth--) {
-               struct hfs_cat_entry *entry = 
-                 list_entry(tmp, struct hfs_cat_entry, list);
-               list_del(tmp);
-               if (CAN_UNUSE(entry)) {
-                       list_del(&entry->hash);
-                       INIT_LIST_HEAD(&entry->hash);
-                       list_add(tmp, &freeable);
-                       if (++found < goal)
-                              continue;
-                       break;
+        if (!(entry->state & HFS_DELETED)) {
+               entry->state |= HFS_DELETED;
+               list_del(&entry->hash);
+               INIT_LIST_HEAD(&entry->hash);
+
+               if (entry->type == HFS_CDR_FIL) {
+                 /* free all extents */
+                 entry->u.file.data_fork.lsize = 0;
+                 hfs_extent_adj(&entry->u.file.data_fork);
+                 entry->u.file.rsrc_fork.lsize = 0;
+                 hfs_extent_adj(&entry->u.file.rsrc_fork);
                }
-               list_add(tmp, head);
        }
+}
 
-       if (found < goal) { /* try freeing from global dirty list */
-               head = &entry_dirty;
-               depth = goal << 1;
-               while ((tmp = head->prev) != head && depth--) {
-                       struct hfs_cat_entry *entry = 
-                         list_entry(tmp, struct hfs_cat_entry, dirty);
-                       list_del(tmp);
-                       if (CAN_UNUSE(entry)) {
-                               list_del(&entry->hash);
-                               INIT_LIST_HEAD(&entry->hash);
-                               list_del(&entry->list);
-                               INIT_LIST_HEAD(&entry->list);
-                               list_add(&entry->list, &freeable);
-                               if (++found < goal)
-                                 continue;
-                               break;
-                       }
-                       list_add(tmp, head);
-               }
-       }
-               
-       if (found) {
-               spin_unlock(&entry_lock);
-               dispose_list(&freeable);
-               spin_lock(&entry_lock);
-       }
 
-       return found;
-}
-  
-/* init_once */
-static inline void init_once(struct hfs_cat_entry *entry)
+static inline void init_entry(struct hfs_cat_entry *entry)
 {
-       init_waitqueue(&entry->wait);
+       memset(entry, 0, sizeof(*entry));
+       hfs_init_waitqueue(&entry->wait);
        INIT_LIST_HEAD(&entry->hash);
        INIT_LIST_HEAD(&entry->list);
-       INIT_LIST_HEAD(&entry->dirty);
 }
 
 /*
- * grow_entries()
+ * hfs_cat_alloc()
  *
- * Try to allocate more entries, adding them to the free list. this returns
- * with the spinlock held if successful 
+ * Try to allocate another entry. 
  */
-static struct hfs_cat_entry *grow_entries(struct hfs_mdb *mdb)
+static inline struct hfs_cat_entry *hfs_cat_alloc(void)
 {
-       struct allocation_unit *tmp;
-       struct hfs_cat_entry * entry;
-       int i;
+        struct hfs_cat_entry *entry;
 
-       spin_unlock(&entry_lock);
-       if ((entries_stat.nr_entries < CCACHE_MAX) &&
-           HFS_NEW(tmp)) {
-               spin_lock(&entry_lock);
-               memset(tmp, 0, sizeof(*tmp));
-               tmp->next = allocation;
-               allocation = tmp;
-               entry = tmp->entries;
-               for (i = 1; i < CCACHE_INC; i++) {
-                       entry++;
-                       init_once(entry);
-                       list_add(&entry->list, &entry_unused);
-               }
-               init_once(tmp->entries);
+       if (!HFS_NEW(entry))
+               return NULL;
 
-               entries_stat.nr_entries += CCACHE_INC;
-               entries_stat.nr_free_entries += CCACHE_INC - 1;
-               return tmp->entries;
-       }
+       init_entry(entry);
+       return entry;
+}
 
-       /* allocation failed. do some pruning and try again */
-       spin_lock(&entry_lock);
-       try_to_free_entries(entries_stat.nr_entries >> 2);
-       {
-               struct list_head *tmp = entry_unused.next;
-               if (tmp != &entry_unused) {
-                       entries_stat.nr_free_entries--;
-                       list_del(tmp);
-                       entry = list_entry(tmp, struct hfs_cat_entry, list);
-                       return entry;
-               }
+/* this gets called with the spinlock held. */
+static int grow_entries(void)
+{
+        struct hfs_cat_entry *entry;
+       int i;
+       
+       for (i = 0; i < CCACHE_INC; i++) {
+               if (!(entry = hfs_cat_alloc()))
+                       break;
+               list_add(&entry->list, &entry_unused);
        }
-       spin_unlock(&entry_lock);
 
-       return NULL;
+       entries_stat.nr_entries += i;
+       entries_stat.nr_free_entries += i;
+               
+       return i;
 }
 
 /*
@@ -537,7+435,8 @@ static void __write_entry(const struct hfs_cat_entry *entry,
 /*
  * write_entry()
  *
- * Write a modified entry back to the catalog B-tree.
+ * Write a modified entry back to the catalog B-tree. this gets called
+ * with the entry locked.
  */
 static void write_entry(struct hfs_cat_entry * entry)
 {
@@ -577,6+476,7 @@ static void write_entry(struct hfs_cat_entry * entry)
 }
 
 
+/* this gets called with the spinlock held. */
 static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb,
                                        const struct hfs_cat_key *key)
 {
@@ -592,8+492,9 @@ static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb,
                entry = list_entry(tmp, struct hfs_cat_entry, hash);
                if (entry->mdb != mdb)
                        continue;
-               if (hfs_cat_compare(&entry->key, key))
+               if (hfs_cat_compare(&entry->key, key)) {
                        continue;
+               }
                entry->count++;
                break;
        }
@@ -609,13+510,14 @@ static struct hfs_cat_entry *get_new_entry(struct hfs_mdb *mdb,
 {
        struct hfs_cat_entry *entry;
        struct list_head *head = hash(mdb, key);
-       struct list_head *tmp = entry_unused.next;
+       struct list_head *tmp;
 
-       if (tmp != &entry_unused) {
+add_new_entry:
+       tmp = entry_unused.next;
+       if ((tmp != &entry_unused) ) {
                list_del(tmp);
                entries_stat.nr_free_entries--;
                entry = list_entry(tmp, struct hfs_cat_entry, list);
-add_new_entry:
                list_add(&entry->list, &entry_in_use);
                list_add(&entry->hash, head);
                entry->mdb = mdb;
@@ -629,7+531,8 @@ add_new_entry:
 
                   if (hfs_bfind(&brec, mdb->cat_tree,
                                 HFS_BKEY(key), HFS_BFIND_READ_EQ)) {
-                       /* uh oh. we failed to read the record */
+                       /* uh oh. we failed to read the record.
+                        * the entry doesn't actually exist. */
                        entry->state |= HFS_DELETED;
                        goto read_fail;
                   }
@@ -651,28+554,18 @@ add_new_entry:
                return entry;
        }
 
-       /*
-        * Uhhuh.. We need to expand. Note that "grow_entries()" will
-        * release the spinlock, but will return with the lock held
-        * again if the allocation succeeded.
-        */
-       entry = grow_entries(mdb);
-       if (entry) {
-               /* We released the lock, so.. */
-               struct hfs_cat_entry * old = find_entry(mdb, key);
-               if (!old)
-                       goto add_new_entry;
-               list_add(&entry->list, &entry_unused);
-               entries_stat.nr_free_entries++;
-               spin_unlock(&entry_lock);
-               wait_on_entry(old);
-               return old;
-       }
 
-       return entry;
+       /* try to allocate more entries. grow_entries() doesn't release
+        * the spinlock. */
+       if (grow_entries())
+               goto add_new_entry;
 
+       spin_unlock(&entry_lock);
+       return NULL;
 
-read_fail:
+read_fail: 
+       /* spinlock unlocked already. we don't need to mark the entry
+        * dirty here because we know that it doesn't exist. */
        remove_hash(entry);
        entry->state &= ~HFS_LOCK;
        hfs_wake_up(&entry->wait);
@@ -694,11+587,6 @@ static struct hfs_cat_entry *get_entry(struct hfs_mdb *mdb,
        struct hfs_cat_entry * entry;
 
        spin_lock(&entry_lock);
-       if (!entries_stat.nr_free_entries &&
-           (entries_stat.nr_entries >= CCACHE_MAX))
-               goto restock;
-
-search:
        entry = find_entry(mdb, key);
        if (!entry) {
                return get_new_entry(mdb, key, read);
@@ -706,10+594,6 @@ search:
        spin_unlock(&entry_lock);
        wait_on_entry(entry);
        return entry;
-
-restock:
-       try_to_free_entries(8);
-       goto search;
 }
 
 /* 
@@ -753,6+637,9 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir,
 
 /*
  * Add a writer to dir, excluding readers.
+ *
+ * XXX: this is wrong. it allows a move to occur when a directory
+ *      is being written to. 
  */
 static inline void start_write(struct hfs_cat_entry *dir)
 {
@@ -880,7+767,10 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
        goto done;
 
 bail1:
+       /* entry really didn't exist, so we don't need to really delete it.
+        * we do need to remove it from the hash, though. */
        entry->state |= HFS_DELETED;
+       remove_hash(entry);
        unlock_entry(entry);
 bail2:
        hfs_cat_put(entry);
@@ -900,13+790,21 @@ done:
  * entry that the entry is in a consistent state, since another
  * process may get the entry while we sleep. That is why we
  * 'goto repeat' after each operation that might sleep.
+ *
+ * ADDITIONAL NOTE: the sys_entries will remove themselves from 
+ *                  the sys_entry list on the final iput, so we don't need 
+ *                  to worry about them here.
+ *
+ *                  nothing in hfs_cat_put goes to sleep now except 
+ *                  on the initial entry.
  */
 void hfs_cat_put(struct hfs_cat_entry * entry)
 {
        if (entry) {
                wait_on_entry(entry);
 
-               if (!entry->count) {/* just in case */
+               /* just in case. this should never happen. */
+               if (!entry->count) { 
                  hfs_warn("hfs_cat_put: trying to free free entry: %p\n",
                           entry);
                  return;
@@ -914,52+812,41 @@ void hfs_cat_put(struct hfs_cat_entry * entry)
 
                spin_lock(&entry_lock);
                if (!--entry->count) {
-repeat:                  
-                       if ((entry->state & HFS_DELETED)) {
-                               if (entry->type == HFS_CDR_FIL) {
-                                 /* free all extents */
-                                 entry->u.file.data_fork.lsize = 0;
-                                 hfs_extent_adj(&entry->u.file.data_fork);
-                                 entry->u.file.rsrc_fork.lsize = 0;
-                                 hfs_extent_adj(&entry->u.file.rsrc_fork);
-                               }
-                               entry->state = 0;
-                       } else if (entry->type == HFS_CDR_FIL) {
+                       if ((entry->state & HFS_DELETED))
+                               goto entry_deleted;
+
+                       if ((entry->type == HFS_CDR_FIL)) {
                                /* clear out any cached extents */
                                if (entry->u.file.data_fork.first.next) {
                                  hfs_extent_free(&entry->u.file.data_fork);
-                                 spin_unlock(&entry_lock);
-                                 wait_on_entry(entry);
-                                 spin_lock(&entry_lock);
-                                 goto repeat;
                                }
                                if (entry->u.file.rsrc_fork.first.next) {
                                  hfs_extent_free(&entry->u.file.rsrc_fork);
-                                 spin_unlock(&entry_lock);
-                                 wait_on_entry(entry);
-                                 spin_lock(&entry_lock);
-                                 goto repeat;
                                }
                        }
 
                        /* if we put a dirty entry, write it out. */
                        if ((entry->state & HFS_DIRTY)) {
-                               list_del(&entry->dirty);
-                               INIT_LIST_HEAD(&entry->dirty);
-                               spin_unlock(&entry_lock);
+                               entry->state ^= HFS_DIRTY | HFS_LOCK;
                                write_entry(entry);
-                               spin_lock(&entry_lock);
-                               entry->state &= ~HFS_DIRTY;
-                               goto repeat;
+                               entry->state &= ~HFS_LOCK;
                        }
 
                        list_del(&entry->hash);
+entry_deleted:                 /* deleted entries have already been removed
+                        * from the hash list. */
                        list_del(&entry->list);
-                       spin_unlock(&entry_lock);
-                       clear_entry(entry);
-                       spin_lock(&entry_lock);
-                       list_add(&entry->list, &entry_unused);
-                       entries_stat.nr_free_entries++;
+                       if (entries_stat.nr_free_entries > CCACHE_MAX) {
+                               HFS_DELETE(entry);
+                               entries_stat.nr_entries--;
+                       } else {
+                               spin_unlock(&entry_lock);
+                               wait_on_entry(entry);
+                               init_entry(entry);
+                               spin_lock(&entry_lock);
+                               list_add(&entry->list, &entry_unused);
+                               entries_stat.nr_free_entries++;
+                       }
                }
                spin_unlock(&entry_lock);
        }
@@ -995,20+882,37 @@ static void invalidate_list(struct list_head *head, struct hfs_mdb *mdb,
                if (entry->mdb != mdb) {
                        continue;
                }
+
                if (!entry->count) {
                        list_del(&entry->hash);
                        INIT_LIST_HEAD(&entry->hash);
-                       list_del(&entry->dirty);
-                       INIT_LIST_HEAD(&entry->dirty);
                        list_del(&entry->list);
                        list_add(&entry->list, dispose);
                        continue;
                }
-               hfs_warn("hfs_fs: entry %p(%u:%lu) busy on removed device %s.\n",
-                        entry, entry->count, entry->state,
+               
+               hfs_warn("hfs_fs: entry %p(%u) busy on removed device %s.\n",
+                        entry, entry->count, 
                         hfs_mdb_name(entry->mdb->sys_mdb));
        }
+}
+
+/* delete entries from a list */
+static void delete_list(struct list_head *head) 
+{
+       struct list_head *next = head->next;
+       struct hfs_cat_entry *entry;
+       
+       for (;;) {
+               struct list_head * tmp = next;
 
+               next = next->next;
+               if (tmp == head) {
+                       break;
+               }
+               entry = list_entry(tmp, struct hfs_cat_entry, list);
+               HFS_DELETE(entry);
+       }
 }
 
 /* 
@@ -1026,7+930,7 @@ void hfs_cat_invalidate(struct hfs_mdb *mdb)
        invalidate_list(&mdb->entry_dirty, mdb, &throw_away);
        spin_unlock(&entry_lock);
 
-       dispose_list(&throw_away); 
+       delete_list(&throw_away);
 }
 
 /*
@@ -1052,9+956,6 @@ void hfs_cat_commit(struct hfs_mdb *mdb)
 
                       if (!entry->count)
                                insert = entry_in_use.prev;
-                      /* remove from global dirty list */
-                      list_del(&entry->dirty); 
-                      INIT_LIST_HEAD(&entry->dirty);
 
                       /* add to in_use list */
                       list_del(&entry->list);
@@ -1077,16+978,13 @@ void hfs_cat_commit(struct hfs_mdb *mdb)
  *
  * Releases all the memory allocated in grow_entries().
  * Must call hfs_cat_invalidate() on all MDBs before calling this.
+ * This only gets rid of the unused pool of entries. all the other
+ * entry references should have either been freed by cat_invalidate
+ * or moved onto the unused list.
  */
 void hfs_cat_free(void)
 {
-       struct allocation_unit *tmp;
-
-       while (allocation) {
-               tmp = allocation->next;
-               HFS_DELETE(allocation);
-               allocation = tmp;
-       }
+       delete_list(&entry_unused);
 }
 
 /*
@@ -1272,6+1170,9 @@ struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *entry)
  * Create a new file with the indicated name in the indicated directory.
  * The file will have the indicated flags, type and creator.
  * If successful an (struct hfs_cat_entry) is returned in '*result'.
+ *
+ * XXX: the presence of "record" probably means that the following two
+ *      aren't currently SMP safe and need spinlocks.
  */
 int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
                   hfs_u8 flags, hfs_u32 type, hfs_u32 creator,
@@ -1358,7+1259,7 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
 
        /* try to delete the file or directory */
        if (!error) {
-               lock_entry(entry);
+               lock_entry(entry);
                if ((entry->state & HFS_DELETED)) {
                        /* somebody beat us to it */
                        error = -ENOENT;
@@ -1371,8+1272,8 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
 
        if (!error) {
                /* Mark the entry deleted and remove it from the cache */
-               entry->state |= HFS_DELETED;
-               remove_hash(entry);
+               lock_entry(entry);
+               delete_entry(entry);
 
                /* try to delete the thread entry if it exists */
                if (with_thread) {
@@ -1380,6+1281,7 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
                        (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key));
                }
 
+               unlock_entry(entry);
                update_dir(mdb, parent, is_dir, -1);
        }
 
@@ -1430,10+1332,12 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,
                return -EINVAL;
        }
 
+       spin_lock(&entry_lock);
        while (mdb->rename_lock) {
                hfs_sleep_on(&mdb->rename_wait);
        }
        mdb->rename_lock = 1;
+       spin_unlock(&entry_lock);
 
        /* keep readers from getting confused by changing dir size */
        start_write(new_dir);
@@ -1501,7+1405,7 @@ restart:
                                    &new_record, is_dir ? 2 + sizeof(DIR_REC) :
                                                          2 + sizeof(FIL_REC));
                if (error == -EEXIST) {
-                       dest->state |= HFS_DELETED;
+                       delete_entry(dest);
                        unlock_entry(dest);
                        hfs_cat_put(dest);
                        goto restart;
@@ -1590,8+1494,7 @@ have_distinct:
                        /* Something went seriously wrong.
                           The dir/file has been deleted. */
                        /* XXX try some recovery? */
-                       entry->state |= HFS_DELETED;
-                       remove_hash(entry);
+                       delete_entry(entry);
                        goto bail1;
                }
        }
@@ -1620,7+1523,7 @@ have_distinct:
 
        /* delete any pre-existing or place-holder entry */
        if (dest) {
-               dest->state |= HFS_DELETED;
+               delete_entry(dest);
                unlock_entry(dest);
                if (removed && dest->cnid) {
                        *removed = dest;
@@ -1639,7+1542,7 @@ bail2:
                        (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(new_key));
                        update_dir(mdb, new_dir, is_dir, -1);
 bail3:
-                       dest->state |= HFS_DELETED;
+                       delete_entry(dest);
                }
                unlock_entry(dest);
                hfs_cat_put(dest);
@@ -1649,8+1552,10 @@ done:
                end_write(old_dir);
        }
        end_write(new_dir);
+       spin_lock(&entry_lock);
        mdb->rename_lock = 0;
        hfs_wake_up(&mdb->rename_wait);
+       spin_unlock(&entry_lock);
 
        return error;
 }
@@ -1663,7+1568,7 @@ void hfs_cat_init(void)
        int i;
        struct list_head *head = hash_table;
 
-        i = CCACHE_NR;
+        i = C_HASHSIZE;
         do {
                 INIT_LIST_HEAD(head);
                 head++;
index 144d9d4..afd7941 100644 (file)
@@ -95,7+95,7 @@ static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
 }
 
 /*
- * update_dirs_plus()
+ * update_dirs_minus()
  *
  * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
  * 'i_version' of the inodes associated with a directory that has
@@ -138,10+138,9 @@ static inline void mark_inodes_deleted(struct hfs_cat_entry *entry,
 
        for (i = 0; i < 4; ++i) {
                if ((de = entry->sys_entry[i]) && (dentry != de)) {
-                   entry->sys_entry[i] = NULL;
-                   dget(de);
-                   d_delete(de);
-                   dput(de);
+                     dget(de);
+                     d_delete(de);
+                     dput(de);
                }
        }
 }
@@ -198,7+197,7 @@ int hfs_create(struct inode * dir, struct dentry *dentry, int mode)
                        error = -EIO;
                } else {
                  if (HFS_I(dir)->d_drop_op)
-                   HFS_I(dir)->d_drop_op(HFS_I(dir)->file_type, dentry);
+                   HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);
                  d_instantiate(dentry, inode);
                }
        }
@@ -285,7+284,7 @@ int hfs_unlink(struct inode * dir, struct dentry *dentry)
        struct hfs_cat_key key;
        int error;
 
-       if (build_key(&key, dir, dentry->d_name.name, 
+       if (build_key(&key, dir, dentry->d_name.name,
                      dentry->d_name.len)) {
                error = -EPERM;
        } else if (!(victim = hfs_cat_get(entry->mdb, &key))) {
@@ -386,15+385,15 @@ int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                } else {
                  /* no existing inodes. just drop negative dentries */
                  if (HFS_I(new_dir)->d_drop_op) 
-                   HFS_I(new_dir)->d_drop_op(HFS_I(new_dir)->file_type,
-                                                  new_dentry);
+                   HFS_I(new_dir)->d_drop_op(new_dentry, 
+                                             HFS_I(new_dir)->file_type);
                  update_dirs_plus(new_parent, is_dir);
                }
 
                /* update dcache */
                d_move(old_dentry, new_dentry);
        }
-        
+
        hfs_cat_put(victim);    /* Note that hfs_cat_put(NULL) is safe. */
        return error;
 }
index d489c86..a7bb7f6 100644 (file)
@@ -1,5+1,4 @@
-/* linux/fs/hfs/dir_cap.c
- *
+/*
  * Copyright (C) 1995-1997  Paul H. Hargrove
  * This file may be distributed under the terms of the GNU Public License.
  *
@@ -154,11+153,12 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry)
        struct hfs_cat_entry *entry;
        struct hfs_cat_key key;
        struct inode *inode = NULL;
-       
+
        if (!dir || !S_ISDIR(dir->i_mode)) {
-               goto done;
+               return -ENOENT;
        }
 
+       dentry->d_op = &hfs_dentry_operations;
        entry = HFS_I(dir)->entry;
        dtype = HFS_ITYPE(dir->i_ino);
 
@@ -215,13+215,13 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry)
                         HFS_I(dir)->file_type, dentry);
 
        /* Don't return a resource fork for a directory */
-       if (inode && (dtype == HFS_CAP_RDIR) &&
+       if (inode && (dtype == HFS_CAP_RDIR) && 
            (HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
+               iput(inode); /* this does an hfs_cat_put */
                inode = NULL;
        }
 
 done:
-       dentry->d_op = &hfs_dentry_operations;
        d_add(dentry, inode);
        return 0;
 }
@@ -261,7+261,7 @@ static int cap_readdir(struct file * filp,
                return -EBADF;
        }
 
-        entry = HFS_I(dir)->entry;
+       entry = HFS_I(dir)->entry;
        type = HFS_ITYPE(dir->i_ino);
        skip_dirs = (type == HFS_CAP_RDIR);
 
@@ -368,7+368,7 @@ static int cap_readdir(struct file * filp,
  * related calls (create, rename, and mknod). the directory calls
  * should be immune. the relevant calls in dir.c call drop_dentry 
  * upon successful completion. */
-void hfs_cap_drop_dentry(const ino_t type, struct dentry *dentry)
+void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type)
 {
   if (type == HFS_CAP_DATA) { /* given name */
     hfs_drop_special(DOT_FINDERINFO, dentry->d_parent, dentry);
index c97247d..553fe8e 100644 (file)
@@ -135,11+135,12 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry)
        struct hfs_cat_entry *entry;
        struct hfs_cat_key key;
        struct inode *inode = NULL;
-       
+
        if (!dir || !S_ISDIR(dir->i_mode)) {
-               goto done;
+               return -ENOENT;
        }
 
+       dentry->d_op = &hfs_dentry_operations;
        entry = HFS_I(dir)->entry;
        
        /* Perform name-mangling */
@@ -175,12+176,11 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry)
                hfs_nameout(dir, &cname, dentry->d_name.name+1,
                            dentry->d_name.len-1);
                hfs_cat_build_key(entry->cnid, &cname, &key);
-               inode = hfs_iget(hfs_cat_get(entry->mdb, &key), 
+               inode = hfs_iget(hfs_cat_get(entry->mdb, &key),
                                 HFS_DBL_HDR, dentry);
        }
        
 done:
-       dentry->d_op = &hfs_dentry_operations;
        d_add(dentry, inode);
        return 0;
 }
@@ -219,7+219,7 @@ static int dbl_readdir(struct file * filp,
                return -EBADF;
        }
 
-        entry = HFS_I(dir)->entry;
+       entry = HFS_I(dir)->entry;
 
        if (filp->f_pos == 0) {
                /* Entry 0 is for "." */
@@ -414,14+414,14 @@ static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry,
 {
        int error;
 
-       if (is_hdr(new_dir, new_dentry->d_name.name, 
+       if (is_hdr(new_dir, new_dentry->d_name.name,
                   new_dentry->d_name.len)) {
                error = -EPERM;
        } else {
                error = hfs_rename(old_dir, old_dentry,
                                   new_dir, new_dentry);
                if ((error == -ENOENT) /*&& !must_be_dir*/ &&
-                   is_hdr(old_dir, old_dentry->d_name.name, 
+                   is_hdr(old_dir, old_dentry->d_name.name,
                           old_dentry->d_name.len)) {
                        error = -EPERM;
                }
@@ -435,9+435,8 @@ static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry,
  * as far as i can tell, the calls that need to do this are the file
  * related calls (create, rename, and mknod). the directory calls
  * should be immune. the relevant calls in dir.c call drop_dentry 
- * upon successful completion. this allocates an array for %name
- * on the first attempt to access it. */
-void hfs_dbl_drop_dentry(const ino_t type, struct dentry *dentry)
+ * upon successful completion. */
+void hfs_dbl_drop_dentry(struct dentry *dentry, const ino_t type)
 {
   unsigned char tmp_name[HFS_NAMEMAX + 1];
   struct dentry *de = NULL;
index 62c9ea2..b29bfdc 100644 (file)
@@ -142,9+142,10 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry)
        struct inode *inode = NULL;
 
        if (!dir || !S_ISDIR(dir->i_mode)) {
-               goto done;
+               return -ENOENT;
        }
 
+       dentry->d_op = &hfs_dentry_operations;
        entry = HFS_I(dir)->entry;
        dtype = HFS_ITYPE(dir->i_ino);
 
@@ -200,12+201,11 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry)
        if (inode && (dtype == HFS_NAT_HDIR) &&
            (HFS_I(inode)->entry != entry) &&
            (HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
-               iput(inode);
+               iput(inode); /* this does an hfs_cat_put */
                inode = NULL;
        }
 
 done:
-       dentry->d_op = &hfs_dentry_operations;
        d_add(dentry, inode);
        return 0;
 }
@@ -241,7+241,7 @@ static int nat_readdir(struct file * filp,
                return -EBADF;
        }
 
-        entry = HFS_I(dir)->entry;
+       entry = HFS_I(dir)->entry;
        type = HFS_ITYPE(dir->i_ino);
        skip_dirs = (type == HFS_NAT_HDIR);
 
@@ -329,7+329,7 @@ static int nat_readdir(struct file * filp,
  * related calls (create, rename, and mknod). the directory calls
  * should be immune. the relevant calls in dir.c call drop_dentry 
  * upon successful completion. */
-void hfs_nat_drop_dentry(const ino_t type, struct dentry *dentry)
+void hfs_nat_drop_dentry(struct dentry *dentry, const ino_t type)
 {
   struct dentry *de;
   
index 26f4983..e127920 100644 (file)
@@ -98,11+98,10 @@ struct buffer_head *hfs_getblk(struct hfs_fork *fork, int block, int create)
                   to the file until we return, so it can't have moved.
                */
               if (tmp) {
-                      hfs_cat_mark_dirty(fork->entry);
-                      return getblk(dev, tmp, HFS_SECTOR_SIZE);
+                hfs_cat_mark_dirty(fork->entry);
+                return getblk(dev, tmp, HFS_SECTOR_SIZE);
               }
               return NULL;
-
        } else {
                /* If reading the block, then retry since the
                   location on disk could have changed while
@@ -236,6+235,7 @@ static hfs_rwret_t hfs_file_write(struct file * filp, const char * buf,
  */
 static void hfs_file_truncate(struct inode * inode)
 {
+       /*struct inode *inode = dentry->d_inode;*/
        struct hfs_fork *fork = HFS_I(inode)->fork;
 
        fork->lsize = inode->i_size;
@@ -268,7+268,7 @@ static inline void xlate_to_user(char *buf, const char *data, int count)
  */
 static inline void xlate_from_user(char *data, const char *buf, int count)
 {
-       copy_from_user(data, buf, count);
+       count -= copy_from_user(data, buf, count);
        while (count--) {
                if (*data == '\n') {
                        *data = '\r';
@@ -398,16+398,16 @@ hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
                        } else {
                                chars = HFS_SECTOR_SIZE - offset;
                        }
-                       count -= chars;
-                       read += chars;
                        p = (*bhe)->b_data + offset;
                        if (convert) {
                                xlate_to_user(buf, p, chars);
                        } else {
-                               copy_to_user(buf, p, chars);
+                               chars -= copy_to_user(buf, p, chars);
                        }
                        brelse(*bhe);
+                       count -= chars;
                        buf += chars;
+                       read += chars;
                        offset = 0;
                        if (++bhe == &buflist[NBUF]) {
                                bhe = buflist;
@@ -479,7+479,7 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
                if (convert) {
                        xlate_from_user(p, buf, c);
                } else {
-                       copy_from_user(p, buf, c);
+                       c -= copy_from_user(p, buf, c);
                }
                update_vm_cache(inode,pos,p,c);
                pos += c;
index 7c29826..10f39f7 100644 (file)
@@ -164,8+164,7 @@ static hfs_rwret_t cap_info_read(struct file *filp, char *buf,
                        memcount = left;
                }
                cap_build_meta(&meta, entry);
-               /* is copy_to_user guaranteed to write memcount? */
-               copy_to_user(buf, ((char *)&meta) + pos, memcount);
+               memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount);
                left -= memcount;
                read += memcount;
                pos += memcount;
@@ -291,6+290,8 @@ static hfs_rwret_t cap_info_write(struct file *filp, const char *buf,
  */
 static void cap_info_truncate(struct inode *inode)
 {
+       /*struct inode *inode = dentry->d_inode;*/
+
        if (inode->i_size > HFS_FORK_MAX) {
                inode->i_size = HFS_FORK_MAX;
        }
index 468a3f5..049381d 100644 (file)
@@ -288,12+288,10 @@ static inline void adjust_forks(struct hfs_cat_entry *entry,
                    (descr->length != entry->u.file.data_fork.lsize)) {
                        entry->u.file.data_fork.lsize = descr->length;
                        hfs_extent_adj(&entry->u.file.data_fork);
-                       hfs_cat_mark_dirty(entry);
                } else if ((descr->id == HFS_HDR_RSRC) &&
                           (descr->length != entry->u.file.rsrc_fork.lsize)) {
                        entry->u.file.rsrc_fork.lsize = descr->length;
                        hfs_extent_adj(&entry->u.file.rsrc_fork);
-                       hfs_cat_mark_dirty(entry);
                }
        }
 }
@@ -414,7+412,7 @@ static hfs_rwret_t hdr_read(struct file * filp, char * buf,
                }
 
                hdr_build_meta(&meta, layout, entry);
-               copy_to_user(buf, ((char *)&meta) + pos, left);
+               left -= copy_to_user(buf, ((char *)&meta) + pos, left);
                count -= left;
                read += left;
                pos += left;
@@ -531,7+529,7 @@ static hfs_rwret_t hdr_read(struct file * filp, char * buf,
 
                /* transfer the data */
                if (p) {
-                       copy_to_user(buf, p + offset, left);
+                       left -= copy_to_user(buf, p + offset, left);
                } else if (fork) {
                        left = hfs_do_read(inode, fork, offset, buf, left,
                                           filp->f_reada != 0);
@@ -654,6+652,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
                /* Handle possible size changes for the forks */
                if (entry->type == HFS_CDR_FIL) {
                        adjust_forks(entry, layout);
+                       hfs_cat_mark_dirty(entry);
                }
        }
 
@@ -887,6+886,8 @@ done:
  */
 static void hdr_truncate(struct inode *inode)
 {
+       /*struct inode *inode = dentry->d_inode;*/
+       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
        struct hfs_hdr_layout *layout;
        size_t size = inode->i_size;
        int lcv, last;
@@ -907,14+908,14 @@ static void hdr_truncate(struct inode *inode)
                }
 
                if (descr->id == HFS_HDR_RSRC) {
-                       fork = &HFS_I(inode)->entry->u.file.rsrc_fork;
+                       fork = &entry->u.file.rsrc_fork;
 #if 0
 /* Can't yet truncate the data fork via a header file, since there is the
  * possibility to truncate via the data file, and the only locking is at
  * the inode level.
  */
                } else if (descr->id == HFS_HDR_DATA) {
-                       fork = &HFS_I(inode)->entry->u.file.data_fork;
+                       fork = &entry->u.file.data_fork;
 #endif
                } else {
                        continue;
index ccc2f0c..9112a6d 100644 (file)
 #define _HFS_H
 
 #include <linux/hfs_sysdep.h>
-#include <linux/hfs_fs.h>
 
 #define HFS_NEW(X)     ((X) = hfs_malloc(sizeof(*(X))))
-#define HFS_DELETE(X)  { hfs_free((X), sizeof(*(X))); (X) = NULL; }
+#define HFS_DELETE(X)  do { hfs_free((X), sizeof(*(X))); (X) = NULL; } \
+                        while (0)
  
 /* offsets to various blocks */
 #define HFS_DD_BLK             0 /* Driver Descriptor block */
@@ -337,13+337,12 @@ struct hfs_file {
  * This structure holds information about a
  * file or directory in an HFS filesystem.
  *
- * 'wait' must remain 1st and 'next' 2nd since we do some pointer arithmetic.
+ * 'wait' must remain 1st and 'hash' 2nd since we do some pointer arithmetic.
  */
 struct hfs_cat_entry {
        hfs_wait_queue          wait;
         struct list_head        hash;
         struct list_head        list;
-        struct list_head        dirty;
        struct hfs_mdb          *mdb;
        hfs_sysentry            sys_entry;
        struct hfs_cat_key      key;
@@ -366,7+365,6 @@ struct hfs_cat_entry {
 #define HFS_KEYDIRTY     2
 #define HFS_LOCK         4
 #define HFS_DELETED      8
-#define HFS_SUPERBLK    16
 
 /* 
  * struct hfs_bnode_ref
@@ -486,14+484,11 @@ extern void hfs_mdb_put(struct hfs_mdb *, int);
 extern int hfs_part_find(hfs_sysmdb, int, int, hfs_s32 *, hfs_s32 *);
 
 /* string.c */
-extern unsigned int hfs_strhash(const struct hfs_name *);
+extern unsigned long hfs_strhash(const struct hfs_name *);
 extern int hfs_strcmp(const struct hfs_name *, const struct hfs_name *);
 extern int hfs_streq(const struct hfs_name *, const struct hfs_name *);
 extern void hfs_tolower(unsigned char *, int);
 
-/* sysdep.c */
-extern void hfs_cat_prune(struct hfs_cat_entry *);
-
 extern __inline__ struct dentry 
 *hfs_lookup_dentry(const char *name, const int len, 
                   struct dentry *base)
index a0bf3d5..340e9be 100644 (file)
@@ -73,17+73,13 @@ static void init_file_inode(struct inode *inode, hfs_u8 fork)
  */
 void hfs_put_inode(struct inode * inode)
 {
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-
-       entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL;
-       hfs_cat_put(entry);
-
        if (inode->i_count == 1) {
-               struct hfs_hdr_layout *tmp = HFS_I(inode)->layout;
-               if (tmp) {
-                       HFS_I(inode)->layout = NULL;
-                       HFS_DELETE(tmp);
-               }
+         struct hfs_hdr_layout *tmp = HFS_I(inode)->layout;
+
+         if (tmp) {
+               HFS_I(inode)->layout = NULL;
+               HFS_DELETE(tmp);
+         }
        }
 }
 
@@ -153,7+149,7 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
        /* We must change all in-core inodes corresponding to this file. */
        for (i = 0; i < 4; ++i) {
          if (de[i] && (de[i] != dentry)) {
-                       inode_setattr(de[i]->d_inode, attr);
+               inode_setattr(de[i]->d_inode, attr);
          }
        }
 
@@ -213,7+209,7 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
  * benefit from a way to pass an additional (void *) through iget() to
  * the VFS read_inode() function.
  *
- * hfs_iget no longer touches hfs_cat_entries.
+ * this will hfs_cat_put() the entry if it fails.
  */
 struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type,
                       struct dentry *dentry)
@@ -239,25+235,15 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type,
        sb = entry->mdb->sys_mdb;
        sys_entry = &entry->sys_entry[HFS_ITYPE_TO_INT(type)];
 
-       if (*sys_entry && (inode = (*sys_entry)->d_inode)) {
-               /* There is an existing inode for this file/dir.  Use it. */
-               ++inode->i_count;
-               return inode;
-       }
-
-       if (!(inode = iget(sb, ntohl(entry->cnid) | type)))
+       if (!(inode = iget(sb, ntohl(entry->cnid) | type))) {
+               hfs_cat_put(entry);
                return NULL;
+       }
 
        if (inode->i_dev != sb->s_dev) {
-               iput(inode);
+               iput(inode); /* automatically does an hfs_cat_put */
                inode = NULL;
-       } else if (inode->i_mode) {
-               /* The inode has been initialized by another process.
-                  Note that if hfs_put_inode() is sleeping in hfs_cat_put()
-                  then we still need to attach it to the entry. */
-               if (!(*sys_entry))
-                       *sys_entry = dentry; /* cache dentry */
-       } else {
+       } else if (!inode->i_mode) {
                /* Initialize the inode */
                struct hfs_sb_info *hsb = HFS_SB(sb);
 
@@ -281,10+267,11 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type,
 
                if (!inode->i_mode) {
                        clear_inode(inode);
+                       hfs_cat_put(entry);
                        inode = NULL;
-               } 
+               } else
+                       *sys_entry = dentry; /* cache dentry */
 
-               *sys_entry = dentry; /* cache dentry */
        }
 
        return inode;
index cacc0a6..030850b 100644 (file)
@@ -81,11+81,14 @@ static unsigned char casefold[256] = {
 /*
  * Hash a string to an integer in a case-independent way
  */
-unsigned int hfs_strhash(const struct hfs_name *cname)
+unsigned long hfs_strhash(const struct hfs_name *cname)
 {
-       /* Currently just sum of the 'order' of first and last characters */
-       return ((unsigned int)caseorder[cname->Name[0]] +
-               (unsigned int)caseorder[cname->Name[cname->Len - 1]]);
+       unsigned long hash = init_name_hash();
+       unsigned int i;
+       for (i = 0; i < cname->Len; i++) {
+               hash = partial_name_hash(caseorder[cname->Name[i]], hash);
+       }
+       return end_name_hash(hash);
 }
 
 /*
index 8971302..9e278d3 100644 (file)
@@ -163,8+163,8 @@ static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len)
        tmp.f_blocks = mdb->alloc_blksz * mdb->fs_ablocks;
        tmp.f_bfree = mdb->alloc_blksz * mdb->free_ablocks;
        tmp.f_bavail = tmp.f_bfree;
-       tmp.f_files = mdb->fs_ablocks;   /* According to the statfs manual page, -1 is the  */
-       tmp.f_ffree = mdb->free_ablocks; /* correct value when the meaning is undefined. */ 
+       tmp.f_files = mdb->fs_ablocks;  
+       tmp.f_ffree = mdb->free_ablocks;
        tmp.f_namelen = HFS_NAMELEN;
 
        return copy_to_user(buf, &tmp, len) ? -EFAULT : 0;
@@ -459,16+459,13 @@ struct super_block *hfs_read_super(struct super_block *s, void *data,
        if (!root_inode) 
                goto bail_no_root;
          
-       /* cache the dentry in the inode */
-       s->s_root = 
-         HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] =
-         d_alloc_root(root_inode, NULL);
+       s->s_root = d_alloc_root(root_inode, NULL);
        if (!s->s_root) 
                goto bail_no_root;
 
-       /* HFS_SUPERBLK prevents the root inode from being flushed 
-        * inadvertantly. */
-       HFS_I(root_inode)->entry->state = HFS_SUPERBLK;
+       /* fix up pointers. */
+       HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] =
+         s->s_root;
        s->s_root->d_op = &hfs_dentry_operations;
 
        /* everything's okay */
index fc7368a..659d0b2 100644 (file)
 #include <linux/hfs_fs.h>
 
 static int hfs_hash_dentry(struct dentry *, struct qstr *);
-static int hfs_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
+static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
+static void hfs_dentry_iput(struct dentry *, struct inode *);
 struct dentry_operations hfs_dentry_operations =
 {
        NULL,                   /* d_validate(struct dentry *) */
        hfs_hash_dentry,        /* d_hash */
        hfs_compare_dentry,     /* d_compare */
-       NULL                    /* d_delete(struct dentry *) */
+       NULL,                   /* d_delete(struct dentry *) */
+       NULL,                   /* d_release(struct dentry *) */
+       hfs_dentry_iput         /* d_iput(struct dentry *, struct inode *) */
 };
 
 /*
@@ -55,19+58,16 @@ hfs_buffer hfs_buffer_get(hfs_sysmdb sys_mdb, int block, int read) {
 
 /* dentry case-handling: just lowercase everything */
 
-/* should we use hfs_strhash? if so, it probably needs to be beefed 
- * up a little. */
+/* hfs_strhash now uses the same hashing function as the dcache. */
 static int hfs_hash_dentry(struct dentry *dentry, struct qstr *this)
 {
-        unsigned char name[HFS_NAMELEN];
-       int len = this->len;
+        struct hfs_name cname;
        
-       if (len > HFS_NAMELEN)
+       if ((cname.Len = this->len) > HFS_NAMELEN)
                return 0;
-  
-       strncpy(name, this->name, len);
-       hfs_tolower(name, len);
-       this->hash = full_name_hash(name, len);
+       
+       strncpy(cname.Name, this->name, this->len);
+       this->hash = hfs_strhash(&cname);
        return 0;
 }
 
@@ -86,18+86,11 @@ static int hfs_compare_dentry(struct dentry *dentry, struct qstr *a,
        return hfs_streq(&s1, &s2);
 }
 
-
-/* toss a catalog entry. this does it by dropping the dentry. */
-void hfs_cat_prune(struct hfs_cat_entry *entry)
+static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode)
 {
-        int i;
+       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
 
-       for (i = 0; i < 4; i++) {
-              struct dentry *de = entry->sys_entry[i];
-              if (de) {
-                       dget(de);
-                       d_drop(de);
-                       dput(de);
-              }
-       }
+       entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL;
+        hfs_cat_put(entry);
+       iput(inode);
 }
index 8eb7408..8652c1c 100644 (file)
@@ -7,4+7,4 @@
  * This file contains the version string for this release.
  */
 
-const char hfs_version[]="0.95+asun2";
+const char hfs_version[]="0.95+asun3";
index f5124c2..5889ec8 100644 (file)
@@ -1,6+1,8 @@
 #ifndef _I386_PAGE_H
 #define _I386_PAGE_H
 
+#include <linux/config.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT     12
 #define PAGE_SIZE      (1UL << PAGE_SHIFT)
index de51db0..7eeb34a 100644 (file)
@@ -237,20+237,20 @@ extern const struct hfs_name hfs_cap_reserved2[];
 extern struct inode_operations hfs_cap_ndir_inode_operations;
 extern struct inode_operations hfs_cap_fdir_inode_operations;
 extern struct inode_operations hfs_cap_rdir_inode_operations;
-extern void hfs_cap_drop_dentry(const ino_t, struct dentry *);
+extern void hfs_cap_drop_dentry(struct dentry *, const ino_t);
 
 /* dir_dbl.c */
 extern const struct hfs_name hfs_dbl_reserved1[];
 extern const struct hfs_name hfs_dbl_reserved2[];
 extern struct inode_operations hfs_dbl_dir_inode_operations;
-extern void hfs_dbl_drop_dentry(const ino_t, struct dentry *);
+extern void hfs_dbl_drop_dentry(struct dentry *, const ino_t);
 
 /* dir_nat.c */
 extern const struct hfs_name hfs_nat_reserved1[];
 extern const struct hfs_name hfs_nat_reserved2[];
 extern struct inode_operations hfs_nat_ndir_inode_operations;
 extern struct inode_operations hfs_nat_hdir_inode_operations;
-extern void hfs_nat_drop_dentry(const ino_t, struct dentry *);
+extern void hfs_nat_drop_dentry(struct dentry *, const ino_t);
 
 /* dir_sngl.c */
 extern const struct hfs_name hfs_sngl_reserved1[];
@@ -301,7+301,6 @@ extern int hfs_mac2seven(char *, const struct hfs_name *);
 extern int hfs_mac2eight(char *, const struct hfs_name *);
 extern int hfs_mac2alpha(char *, const struct hfs_name *);
 extern int hfs_mac2triv(char *, const struct hfs_name *);
-extern void hfs_tolower(unsigned char *, int);
 
 #define        HFS_I(X)        (&((X)->u.hfs_i))
 #define        HFS_SB(X)       (&((X)->u.hfs_sb))
index cf9ed53..4538968 100644 (file)
@@ -34,7+34,7 @@ struct hfs_inode_info {
        struct hfs_hdr_layout           *layout;
 
         /* for dentry cleanup */
-        void (*d_drop_op)(const ino_t, struct dentry *);
+        void (*d_drop_op)(struct dentry *, const ino_t);
 };
 
 #endif
index 93de05a..22e2ac6 100644 (file)
@@ -78,6+78,10 @@ extern inline hfs_u32 hfs_time(void) {
  */
 typedef struct wait_queue *hfs_wait_queue;
 
+extern inline void hfs_init_waitqueue(hfs_wait_queue *queue) {
+        init_waitqueue(queue);
+}
+
 extern inline void hfs_sleep_on(hfs_wait_queue *queue) {
        sleep_on(queue);
 }
index 4d29114..494490c 100644 (file)
@@ -36,10+36,10 @@ struct swap_info_struct {
 extern int nr_swap_pages;
 extern int nr_free_pages;
 extern atomic_t nr_async_pages;
-extern int min_free_pages;
-extern int free_pages_low;
-extern int free_pages_high;
 extern struct inode swapper_inode;
+extern unsigned long page_cache_size;
+extern int buffermem;
+#define BUFFER_MEM ((buffermem >> PAGE_SHIFT) + page_cache_size)
 
 /* Incomplete types for prototype declarations: */
 struct task_struct;
index e71dcd0..cc169d2 100644 (file)
 
 /* Swap tuning control */
 
-/* First, enumerate the different reclaim policies */
-enum RCL_POLICY {RCL_ROUND_ROBIN, RCL_BUFF_FIRST, RCL_PERSIST};
-
-typedef struct swap_control_v5
+typedef struct swap_control_v6
 {
        unsigned int    sc_max_page_age;
        unsigned int    sc_page_advance;
        unsigned int    sc_page_decline;
        unsigned int    sc_page_initial_age;
-       unsigned int    sc_max_buff_age;
-       unsigned int    sc_buff_advance;
-       unsigned int    sc_buff_decline;
-       unsigned int    sc_buff_initial_age;
        unsigned int    sc_age_cluster_fract;
        unsigned int    sc_age_cluster_min;
        unsigned int    sc_pageout_weight;
        unsigned int    sc_bufferout_weight;
-       unsigned int    sc_buffer_grace;
-       unsigned int    sc_nr_buffs_to_free;
-       unsigned int    sc_nr_pages_to_free;
-       enum RCL_POLICY sc_policy;
-} swap_control_v5;
-typedef struct swap_control_v5 swap_control_t;
+} swap_control_v6;
+typedef struct swap_control_v6 swap_control_t;
 extern swap_control_t swap_control;
 
 typedef struct swapstat_v1
@@ -42,7+31,23 @@ typedef struct swapstat_v1
 typedef swapstat_v1 swapstat_t;
 extern swapstat_t swapstats;
 
-extern int min_free_pages, free_pages_low, free_pages_high;
+typedef struct buffer_mem_v1
+{
+       unsigned int    min_percent;
+       unsigned int    borrow_percent;
+       unsigned int    max_percent;
+} buffer_mem_v1;
+typedef buffer_mem_v1 buffer_mem_t;
+extern buffer_mem_t buffer_mem;
+
+typedef struct freepages_v1
+{
+       unsigned int    min;
+       unsigned int    low;
+       unsigned int    high;
+} freepages_v1;
+typedef freepages_v1 freepages_t;
+extern freepages_t freepages;
 
 #define SC_VERSION     1
 #define SC_MAX_VERSION 1
@@ -55,17+60,11 @@ extern int min_free_pages, free_pages_low, free_pages_high;
    failure to free a resource at any priority */
 #define RCL_FAILURE (RCL_MAXPRI + 1)
 
-#define RCL_POLICY             (swap_control.sc_policy)
 #define AGE_CLUSTER_FRACT      (swap_control.sc_age_cluster_fract)
 #define AGE_CLUSTER_MIN                (swap_control.sc_age_cluster_min)
 #define PAGEOUT_WEIGHT         (swap_control.sc_pageout_weight)
 #define BUFFEROUT_WEIGHT       (swap_control.sc_bufferout_weight)
 
-#define NR_BUFFS_TO_FREE       (swap_control.sc_nr_buffs_to_free)
-#define NR_PAGES_TO_FREE       (swap_control.sc_nr_pages_to_free)
-
-#define BUFFERMEM_GRACE                (swap_control.sc_buffer_grace)
-
 /* Page aging (see mm/swap.c) */
 
 #define MAX_PAGE_AGE           (swap_control.sc_max_page_age)
@@ -73,11+72,6 @@ extern int min_free_pages, free_pages_low, free_pages_high;
 #define PAGE_DECLINE           (swap_control.sc_page_decline)
 #define PAGE_INITIAL_AGE       (swap_control.sc_page_initial_age)
 
-#define MAX_BUFF_AGE           (swap_control.sc_max_buff_age)
-#define BUFF_ADVANCE           (swap_control.sc_buff_advance)
-#define BUFF_DECLINE           (swap_control.sc_buff_decline)
-#define BUFF_INITIAL_AGE       (swap_control.sc_buff_initial_age)
-
 /* Given a resource of N units (pages or buffers etc), we only try to
  * age and reclaim AGE_CLUSTER_FRACT per 1024 resources each time we
  * scan the resource list. */
index dd1ed43..7152aea 100644 (file)
@@ -84,6+84,7 @@ enum
        VM_FREEPG,              /* struct: Set free page thresholds */
        VM_BDFLUSH,             /* struct: Control buffer cache flushing */
        VM_OVERCOMMIT_MEMORY,   /* Turn off the virtual memory safety limit */
+       VM_BUFFERMEM            /* struct: Set cache memory thresholds */
 };
 
 
@@ -148,8+149,6 @@ enum
        NET_IPV4_FIB_HASH = 19,
 
        NET_IPV4_TCP_HOE_RETRANSMITS=32,
-       NET_IPV4_TCP_SACK,
-       NET_IPV4_TCP_TSACK,
        NET_IPV4_TCP_TIMESTAMPS,
        NET_IPV4_TCP_WINDOW_SCALING,
        NET_IPV4_TCP_VEGAS_CONG_AVOID,
index 8ad6a22..589f58c 100644 (file)
@@ -191,9+191,6 @@ struct raw_opt {
 
 struct tcp_opt
 {
-       /* TCP bind bucket hash linkage. */
-       struct sock             *bind_next;
-       struct sock             **bind_pprev;
        int     tcp_header_len; /* Bytes of tcp header to send          */
 
 /*
@@ -220,7+217,7 @@ struct tcp_opt
 
        __u32   snd_wl2;        /* Ack sequence for update              */
        __u32   snd_wnd;        /* The window we expect to receive      */
-       __u16   max_window;
+       __u32   max_window;
        __u8    pending;        /* pending events                       */
        __u8    retransmits;
        __u32   last_ack_sent;  /* last ack we sent                     */
@@ -262,8+259,7 @@ struct tcp_opt
  *      Options received (usually on last packet, some only on SYN packets).
  */
        char    tstamp_ok,      /* TIMESTAMP seen on SYN packet         */
-               wscale_ok,      /* Wscale seen on SYN packet            */
-               sack_ok;        /* SACK_PERM seen on SYN packet         */
+               wscale_ok;      /* Wscale seen on SYN packet            */
        char    saw_tstamp;     /* Saw TIMESTAMP on last packet         */
         __u16  in_mss;         /* MSS option received from sender      */
         __u8   snd_wscale;     /* Window scaling received from sender  */
@@ -272,9+268,6 @@ struct tcp_opt
         __u32  rcv_tsecr;      /* Time stamp echo reply                */
         __u32  ts_recent;      /* Time stamp to echo next              */
         __u32  ts_recent_stamp;/* Time we stored ts_recent (for aging) */
-        int    sacks;          /* Number of SACK blocks if any         */
-        __u32  left_sack[4];   /* Left edges of blocks                 */
-        __u32  right_sack[4];  /* Right edges of blocks                */
 
        struct timer_list       probe_timer;            /* Probes       */
        __u32   basertt;        /* Vegas baseRTT                        */
@@ -347,6+340,10 @@ struct sock
        struct sock             *sklist_next;
        struct sock             *sklist_prev;
 
+       /* Local port binding hash linkage. */
+       struct sock             *bind_next;
+       struct sock             **bind_pprev;
+
        /* Main hash linkage for various protocol lookup tables. */
        struct sock             *next;
        struct sock             **pprev;
index 2d64f21..3b04b7e 100644 (file)
@@ -131,17+131,53 @@ static __inline__ void tcp_sk_bindify(struct sock *sk)
                        tb->flags = 0;
        } else {
                if((tb->flags & TCPB_FLAG_FASTREUSE) &&
-                  ((sk->reuse != 0) || (sk->state == TCP_LISTEN)))
+                  ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
                        tb->flags &= ~TCPB_FLAG_FASTREUSE;
        }
-       if((sk->tp_pinfo.af_tcp.bind_next = tb->owners) != NULL)
-               tb->owners->tp_pinfo.af_tcp.bind_pprev =
-                       &sk->tp_pinfo.af_tcp.bind_next;
+       if((sk->bind_next = tb->owners) != NULL)
+               tb->owners->bind_pprev = &sk->bind_next;
        tb->owners = sk;
-       sk->tp_pinfo.af_tcp.bind_pprev = &tb->owners;
+       sk->bind_pprev = &tb->owners;
        sk->prev = (struct sock *) tb;
 }
 
+/* This is a TIME_WAIT bucket.  It works around the memory consumption
+ * problems of sockets in such a state on heavily loaded servers, but
+ * without violating the protocol specification.
+ */
+struct tcp_tw_bucket {
+       /* These _must_ match the beginning of struct sock precisely.
+        * XXX Yes I know this is gross, but I'd have to edit every single
+        * XXX networking file if I created a "struct sock_header". -DaveM
+        */
+       struct sock             *sklist_next;
+       struct sock             *sklist_prev;
+       struct sock             *bind_next;
+       struct sock             **bind_pprev;
+       struct sock             *next;
+       struct sock             **pprev;
+       __u32                   daddr;
+       __u32                   rcv_saddr;
+       int                     bound_dev_if;
+       unsigned short          num;
+       unsigned char           state,
+                               family;         /* sk->zapped */
+       __u16                   source;         /* sk->dummy_th.source */
+       __u16                   dest;           /* sk->dummy_th.dest */
+
+       /* And these are ours. */
+       __u32                   rcv_nxt;
+       struct tcp_func         *af_specific;
+       struct tcp_bind_bucket  *tb;
+       struct timer_list       timer;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct in6_addr         v6_daddr;
+       struct in6_addr         v6_rcv_saddr;
+#endif
+};
+
+extern kmem_cache_t *tcp_timewait_cachep;
+
 /* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6
  * because the v6 tcp code to intialize a connection needs to interoperate
  * with the v4 code using the same variables.
@@ -149,7+185,6 @@ static __inline__ void tcp_sk_bindify(struct sock *sk)
  * address family independent and just leave one copy in the ipv4 section.
  * This would also clean up some code duplication. -- erics
  */
-extern int sysctl_tcp_sack;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 
@@ -244,9+279,6 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
 #define TCPOPT_NOP             1       /* Padding */
 #define TCPOPT_EOL             0       /* End of options */
 #define TCPOPT_MSS             2       /* Segment size negotiating */
-/*
- *     We don't use these yet, but they are for PAWS and big windows
- */
 #define TCPOPT_WINDOW          3       /* Window scaling */
 #define TCPOPT_SACK_PERM        4       /* SACK Permitted */
 #define TCPOPT_SACK             5       /* SACK Block */
@@ -261,6+293,10 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
 #define TCPOLEN_SACK_PERM      2
 #define TCPOLEN_TIMESTAMP      10
 
+/* But this is what stacks really send out. */
+#define TCPOLEN_TSTAMP_ALIGNED 12
+#define TCPOLEN_WSCALE_ALIGNED 4
+
 /*
  *      TCP option flags for parsed options.
  */
@@ -310,7+346,6 @@ struct open_request {
        __u8                    __pad;
        unsigned snd_wscale : 4, 
                rcv_wscale : 4, 
-               sack_ok : 1,
                tstamp_ok : 1,
                wscale_ok : 1;
        /* The following two fields can be easily recomputed I think -AK */
@@ -406,7+441,7 @@ extern __inline int after(__u32 seq1, __u32 seq2)
 /* is s2<=s1<=s3 ? */
 extern __inline int between(__u32 seq1, __u32 seq2, __u32 seq3)
 {
-       return (after(seq1+1, seq2) && before(seq1, seq3+1));
+       return seq3 - seq2 >= seq1 - seq2;
 }
 
 
@@ -441,6+476,11 @@ extern int                 tcp_rcv_established(struct sock *sk,
                                                    struct tcphdr *th, 
                                                    __u16 len);
 
+extern int                     tcp_timewait_state_process(struct tcp_tw_bucket *tw,
+                                                          struct sk_buff *skb,
+                                                          struct tcphdr *th,
+                                                          void *opt, __u16 len);
+
 extern void                    tcp_close(struct sock *sk, 
                                          unsigned long timeout);
 extern struct sock *           tcp_accept(struct sock *sk, int flags);
@@ -695,37+735,44 @@ static __inline__ void tcp_set_state(struct sock *sk, int state)
        default:
                if (oldstate==TCP_ESTABLISHED)
                        tcp_statistics.TcpCurrEstab--;
-               if (state == TCP_TIME_WAIT)
-                       sk->prot->rehash(sk);
        }
 }
 
 static __inline__ void tcp_build_options(__u32 *ptr, struct tcp_opt *tp)
 {
-       /* FIXME: We will still need to do SACK here. */
        if (tp->tstamp_ok) {
-               *ptr = ntohl((TCPOPT_NOP << 24)
-                       | (TCPOPT_NOP << 16)
-                        | (TCPOPT_TIMESTAMP << 8)
-                       | TCPOLEN_TIMESTAMP);
+               *ptr = __constant_htonl((TCPOPT_NOP << 24) |
+                                       (TCPOPT_NOP << 16) |
+                                       (TCPOPT_TIMESTAMP << 8) |
+                                       TCPOLEN_TIMESTAMP);
                /* rest filled in by tcp_update_options */
        }
 }
 
 static __inline__ void tcp_update_options(__u32 *ptr, struct tcp_opt *tp)
 {
-       /* FIXME: We will still need to do SACK here. */
        if (tp->tstamp_ok) {
                *++ptr = htonl(jiffies);
                *++ptr = htonl(tp->ts_recent);
        }
 }
 
+static __inline__ void tcp_build_and_update_options(__u32 *ptr, struct tcp_opt *tp)
+{
+       if (tp->tstamp_ok) {
+               *ptr++ = __constant_htonl((TCPOPT_NOP << 24) |
+                                         (TCPOPT_NOP << 16) |
+                                         (TCPOPT_TIMESTAMP << 8) |
+                                         TCPOLEN_TIMESTAMP);
+               *ptr++ = htonl(jiffies);
+               *ptr   = htonl(tp->ts_recent);
+       }
+}
+
 /* 
  *     This routines builds a generic TCP header. 
  *     They also build the RFC1323 Timestamp, but don't fill the
  *     actual timestamp in (you need to call tcp_update_options for this).
- *     It can't (unfortunately) do SACK as well.
  *     XXX: pass tp instead of sk here.
  */
  
@@ -750,9+797,10 @@ static inline void tcp_build_header_data(struct tcphdr *th, struct sock *sk, int
  * It would be especially magical to compute the checksum for this
  * stuff on the fly here.
  */
-extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sack, int ts, int offer_wscale, int wscale)
+extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int ts, int offer_wscale, int wscale)
 {
-       int count = 4 + (offer_wscale ? 4 : 0) +  ((ts || sack) ? 4 : 0) +  (ts ? 8 : 0);
+       int count = 4 + (offer_wscale ? TCPOLEN_WSCALE_ALIGNED : 0) +
+               ((ts) ? TCPOLEN_TSTAMP_ALIGNED : 0);
        unsigned char *optr = skb_put(skb,count);
        __u32 *ptr = (__u32 *)optr;
 
@@ -761,20+809,10 @@ extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sa
         */
        *ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
        if (ts) {
-               if (sack) {
-                       *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16)
-                                       | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
-                       *ptr++ = htonl(jiffies);        /* TSVAL */
-                       *ptr++ = htonl(0);              /* TSECR */
-               } else {
-                       *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
-                                       | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
-                       *ptr++ = htonl(jiffies);        /* TSVAL */
-                       *ptr++ = htonl(0);              /* TSECR */
-               }
-       } else if (sack) {
-               *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16)
-                               | (TCPOPT_NOP << 8) | TCPOPT_NOP);
+               *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+                                         (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
+               *ptr++ = htonl(jiffies);        /* TSVAL */
+               *ptr++ = __constant_htonl(0);   /* TSECR */
        }
        if (offer_wscale)
                *ptr++ = htonl((TCPOPT_WINDOW << 24) | (TCPOLEN_WINDOW << 16) | (wscale << 8));
@@ -823,33+861,15 @@ extern __inline__ void tcp_select_initial_window(__u32 space, __u16 mss,
        (*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp);
 }
 
-/* #define SYNQ_DEBUG 1 */
-
 extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, struct open_request *prev)
 {
-#ifdef SYNQ_DEBUG
-       if (prev->dl_next != req) {
-               printk(KERN_DEBUG "synq_unlink: bad prev ptr: %p\n",prev);
-               return;
-       }
-#endif
-       if(!req->dl_next) {
-#ifdef SYNQ_DEBUG
-               if (tp->syn_wait_last != (void*) req)
-                       printk(KERN_DEBUG "synq_unlink: bad last ptr %p,%p\n",
-                              req,tp->syn_wait_last);
-#endif
+       if(!req->dl_next)
                tp->syn_wait_last = (struct open_request **)prev;
-       }
        prev->dl_next = req->dl_next;
 }
 
 extern __inline__ void tcp_synq_queue(struct tcp_opt *tp, struct open_request *req)
 { 
-#ifdef SYNQ_DEBUG
-       if (*tp->syn_wait_last != NULL)
-           printk("synq_queue: last ptr doesn't point to last req.\n"); 
-#endif
        req->dl_next = NULL;
        *tp->syn_wait_last = req; 
        tp->syn_wait_last = &req->dl_next;
@@ -864,14+884,11 @@ extern __inline__ void tcp_synq_init(struct tcp_opt *tp)
 extern __inline__ struct open_request *tcp_synq_unlink_tail(struct tcp_opt *tp)
 {
        struct open_request *head = tp->syn_wait_queue;
-#ifdef SYNQ_DEBUG
-       if (!head) {
-               printk(KERN_DEBUG "tail drop on empty queue? - bug\n"); 
-               return NULL;
-       }
-#endif
+#if 0
+       /* Should be a net-ratelimit'd thing, not all the time. */
        printk(KERN_DEBUG "synq tail drop with expire=%ld\n", 
               head->expires-jiffies);
+#endif
        if (head->dl_next == NULL)
                tp->syn_wait_last = &tp->syn_wait_queue;
        tp->syn_wait_queue = head->dl_next;
@@ -902,10+919,9 @@ extern __inline__ void tcp_dec_slow_timer(int timer)
 static __inline__ void tcp_sk_unbindify(struct sock *sk)
 {
        struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *) sk->prev;
-       if(sk->tp_pinfo.af_tcp.bind_next)
-               sk->tp_pinfo.af_tcp.bind_next->tp_pinfo.af_tcp.bind_pprev =
-                       sk->tp_pinfo.af_tcp.bind_pprev;
-       *(sk->tp_pinfo.af_tcp.bind_pprev) = sk->tp_pinfo.af_tcp.bind_next;
+       if(sk->bind_next)
+               sk->bind_next->bind_pprev = sk->bind_pprev;
+       *sk->bind_pprev = sk->bind_next;
        if(tb->owners == NULL)
                tcp_inc_slow_timer(TCP_SLT_BUCKETGC);
 }
index c309adf..5bb9e7f 100644 (file)
@@ -78,8+78,6 @@ extern void dquot_init(void);
 extern void smp_setup(char *str, int *ints);
 extern void ioapic_pirq_setup(char *str, int *ints);
 extern void no_scroll(char *str, int *ints);
-extern void swap_setup(char *str, int *ints);
-extern void buff_setup(char *str, int *ints);
 extern void panic_setup(char *str, int *ints);
 extern void bmouse_setup(char *str, int *ints);
 extern void msmouse_setup(char *str, int *ints);
@@ -490,8+488,6 @@ static struct kernel_param cooked_params[] __initdata = {
 #if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
        { "video=", video_setup },
 #endif
-       { "swap=", swap_setup },
-       { "buff=", buff_setup },
        { "panic=", panic_setup },
        { "console=", console_setup },
 #ifdef CONFIG_VT
index 1f1c4fd..806f692 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -3,7+3,6 @@
  * Copyright (C) 1992 Krishna Balasubramanian 
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/msg.h>
index b4ddebc..a08aa2c 100644 (file)
@@ -262,6+262,9 @@ fail_nomem:
 
 /*
  * Allocate and initialize an mm_struct.
+ *
+ * NOTE! The mm mutex will be locked until the
+ * caller decides that all systems are go..
  */
 struct mm_struct * mm_alloc(void)
 {
@@ -274,7+277,7 @@ struct mm_struct * mm_alloc(void)
                mm->count = 1;
                mm->map_count = 0;
                mm->def_flags = 0;
-               mm->mmap_sem = MUTEX;
+               mm->mmap_sem = MUTEX_LOCKED;
                /*
                 * Leave mm->pgd set to the parent's pgd
                 * so that pgd_offset() is always valid.
@@ -327,6+330,7 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
        retval = dup_mmap(mm);
        if (retval)
                goto free_pt;
+       up(&mm->mmap_sem);
        return 0;
 
 free_mm:
index 171a9dc..e686454 100644 (file)
@@ -193,12+193,14 @@ static ctl_table vm_table[] = {
        {VM_SWAPOUT, "swapout_interval",
         &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies},
        {VM_FREEPG, "freepages", 
-        &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
+        &freepages, sizeof(freepages_t), 0600, NULL, &proc_dointvec},
        {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
         &proc_dointvec_minmax, &sysctl_intvec, NULL,
         &bdflush_min, &bdflush_max},
        {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
         sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
+       {VM_BUFFERMEM, "buffermem",
+        &buffer_mem, sizeof(buffer_mem_t), 0600, NULL, &proc_dointvec},
        {0}
 };
 
index 80817ec..0ccf96d 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
  */
 
 /*
- * This file should contain most things doing the swapping from/to disk.
+ * This file contains the default values for the opereation of the
+ * Linux VM subsystem. Finetuning documentation can be found in
+ * linux/Documentation/sysctl/vm.txt.
  * Started 18.12.91
- *
  * Swap aging added 23.2.95, Stephen Tweedie.
+ * Buffermem limits added 12.3.98, Rik van Riel.
  */
 
 #include <linux/mm.h>
 
 /*
  * We identify three levels of free memory.  We never let free mem
- * fall below the min_free_pages except for atomic allocations.  We
- * start background swapping if we fall below free_pages_high free
- * pages, and we begin intensive swapping below free_pages_low.
+ * fall below the freepages.min except for atomic allocations.  We
+ * start background swapping if we fall below freepages.high free
+ * pages, and we begin intensive swapping below freepages.low.
  *
- * Keep these three variables contiguous for sysctl(2).  
+ * These values are there to keep GCC from complaining. Actual
+ * initialization is done in mm/page_alloc.c or arch/sparc(64)/mm/init.c.
  */
-int min_free_pages = 48;
-int free_pages_low = 72;
-int free_pages_high = 96;
+freepages_t freepages = {
+       48,     /* freepages.min */
+       72,     /* freepages.low */
+       96      /* freepages.high */
+};
 
 /* We track the number of pages currently being asynchronously swapped
    out, so that we don't try to swap TOO many pages out at once */
@@ -55,53+60,15 @@ atomic_t nr_async_pages = ATOMIC_INIT(0);
 
 swap_control_t swap_control = {
        20, 3, 1, 3,            /* Page aging */
-       10, 2, 2, 4,            /* Buffer aging */
        32, 4,                  /* Aging cluster */
        8192, 8192,             /* Pageout and bufferout weights */
-       -200,                   /* Buffer grace */
-       1, 1,                   /* Buffs/pages to free */
-       RCL_ROUND_ROBIN         /* Balancing policy */
 };
 
 swapstat_t swapstats = {0};
 
-/* General swap control */
-
-/* Parse the kernel command line "swap=" option at load time: */
-__initfunc(void swap_setup(char *str, int *ints))
-{
-       int * swap_vars[8] = {
-               &MAX_PAGE_AGE,
-               &PAGE_ADVANCE,
-               &PAGE_DECLINE,
-               &PAGE_INITIAL_AGE,
-               &AGE_CLUSTER_FRACT,
-               &AGE_CLUSTER_MIN,
-               &PAGEOUT_WEIGHT,
-               &BUFFEROUT_WEIGHT
-       };
-       int i;
-       for (i=0; i < ints[0] && i < 8; i++) {
-               if (ints[i+1])
-                       *(swap_vars[i]) = ints[i+1];
-       }
-}
-
-/* Parse the kernel command line "buff=" option at load time: */
-__initfunc(void buff_setup(char *str, int *ints))
-{
-       int * buff_vars[6] = {
-               &MAX_BUFF_AGE,
-               &BUFF_ADVANCE,
-               &BUFF_DECLINE,
-               &BUFF_INITIAL_AGE,
-               &BUFFEROUT_WEIGHT,
-               &BUFFERMEM_GRACE
-       };
-       int i;
-       for (i=0; i < ints[0] && i < 6; i++) {
-               if (ints[i+1])
-                       *(buff_vars[i]) = ints[i+1];
-       }
-}
+buffer_mem_t buffer_mem = {
+       6,      /* minimum percent buffer + cache memory */
+       20,     /* borrow percent buffer + cache memory */
+       90      /* maximum percent buffer + cache memory */
+};
 
index bd97e39..5d4188a 100644 (file)
@@ -6,7+6,7 @@
  *  Swap reorganised 29.12.95, Stephen Tweedie.
  *  kswapd added: 7.1.96  sct
  *  Removed kswapd_ctl limits, and swap out as many pages as needed
- *  to bring the system back to free_pages_high: 2.4.97, Rik van Riel.
+ *  to bring the system back to freepages.high: 2.4.97, Rik van Riel.
  *  Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $
  */
 
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
 
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
@@ -454,11+456,14 @@ static inline int do_try_to_free_page(int gfp_mask)
        stop = 3;
        if (gfp_mask & __GFP_WAIT)
                stop = 0;
+       if (BUFFER_MEM > buffer_mem.borrow_percent * num_physpages / 100)
+               state = 0;
 
        switch (state) {
                do {
                case 0:
-                       if (shrink_mmap(i, gfp_mask))
+                       if (BUFFER_MEM > (buffer_mem.min_percent * num_physpages /100) &&
+                                       shrink_mmap(i, gfp_mask))
                                return 1;
                        state = 1;
                case 1:
@@ -550,15+555,15 @@ int kswapd(void *unused)
                swapstats.wakeups++;
                /* Do the background pageout: 
                 * When we've got loads of memory, we try
-                * (free_pages_high - nr_free_pages) times to
+                * (freepages.high - nr_free_pages) times to
                 * free memory. As memory gets tighter, kswapd
                 * gets more and more agressive. -- Rik.
                 */
-               tries = free_pages_high - nr_free_pages;
-               if (tries < min_free_pages) {
-                       tries = min_free_pages;
+               tries = freepages.high - nr_free_pages;
+               if (tries < freepages.min) {
+                       tries = freepages.min;
                }
-               else if (nr_free_pages < (free_pages_low + min_free_pages) / 2) 
+               if (nr_free_pages < freepages.high + freepages.low)
                        tries <<= 1;
                while (tries--) {
                        int gfp_mask;
@@ -590,9+595,10 @@ void swap_tick(void)
        int want_wakeup = 0, memory_low = 0;
        int pages = nr_free_pages + atomic_read(&nr_async_pages);
 
-       if (pages < free_pages_low)
+       if (pages < freepages.low)
                memory_low = want_wakeup = 1;
-       else if (pages < free_pages_high && jiffies >= next_swap_jiffies)
+       else if ((pages < freepages.high || BUFFER_MEM > (num_physpages * buffer_mem.max_percent / 100))
+                       && jiffies >= next_swap_jiffies)
                want_wakeup = 1;
 
        if (want_wakeup) { 
index 0773d4c..19cd47a 100644 (file)
@@ -24,6+24,5 @@ ctl_table tr_table[] = {
        {NET_TR_RIF_TIMEOUT, "rif_timeout", &sysctl_tr_rif_timeout, sizeof(int),
         0644, NULL, &proc_dointvec},
        {0}
-        {0}
 };
 #endif
index 0e04483..5f7dc65 100644 (file)
@@ -511,12+511,14 @@ int rif_get_info(char *buffer,char **start, off_t offset, int length, int dummy)
  *     too much for this.
  */
 
+#ifdef CONFIG_PROC_FS
 static struct proc_dir_entry tr_rif_proc = {
        PROC_NET_TR_RIF, 6, "tr_rif",
        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_net_inode_operations,
        rif_get_info
 };
+#endif
 
 __initfunc(void rif_init(struct net_proto *unused))
 {
@@ -529,3+531,5 @@ __initfunc(void rif_init(struct net_proto *unused))
 #ifdef CONFIG_PROC_FS
        proc_net_register(&tr_rif_proc);
 #endif
+}
+}
index a3e7659..c56adc1 100644 (file)
@@ -1404,6+1404,31 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
                return (0);
        }
 
+#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)
+        /*
+         *      Check if IP-over-DDP
+         */
+        if(skb->data[12] == 22)
+        {
+                struct device *dev;
+
+               /* This needs to be able to handle ipddp"N" devices */
+                if((dev = dev_get("ipddp0")) == NULL)
+                        return (-ENODEV);
+
+                skb->protocol = htons(ETH_P_IP);
+                skb_pull(skb, 13);
+                skb->dev = dev;
+                skb->h.raw = skb->data;
+
+                ((struct net_device_stats *)dev->priv)->rx_packets++;
+                ((struct net_device_stats *)dev->priv)->rx_bytes += skb->len+13;
+                netif_rx(skb);  /* Send the SKB up to a higher place. */
+
+                return (0);
+        }
+#endif
+
        /*
         * Which socket - atalk_search_socket() looks for a *full match*
         * of the <net,node,port> tuple.
@@ -1420,38+1445,6 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
                return (0);
        }
 
-#ifdef CONFIG_IPDDP
-       /*
-        *      Check if IP-over-DDP
-        */
-       if(skb->data[12] == 22) 
-       {
-               struct device *dev;
-                struct net_device_stats *estats;
-
-               if((dev = dev_get("ipddp0")) == NULL)
-                       return (-ENODEV);
-
-               estats = (struct net_device_stats *) dev->priv;
-               skb->protocol = htons(ETH_P_IP);
-               skb_pull(skb, 13);
-               skb->dev = dev;
-               skb->h.raw = skb->data;
-               skb->nh.raw = skb->data;
-
-       /*      printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]);
-        *      printk("tot_len %d, skb->len %d\n",
-        *              ntohs(skb->h.iph->tot_len),skb->len);
-        */
-
-               estats->rx_packets++;
-               estats->rx_bytes += skb->len + 13;
-               netif_rx(skb);  /* Send the SKB up to a higher place. */
-
-               return (0);
-       }
-#endif /* CONFIG_IPDDP */
-       
        /*
         *      Queue packet (standard)
         */
index 5671699..107f481 100644 (file)
@@ -1237,6+1237,8 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
 
        newsk = skb->sk;
        newsk->pair = NULL;
+       newsk->socket = newsock;
+       newsk->sleep = &newsock->wait;
        sti();
 
        /* Now attach up the new socket */
index 843eed6..9e88736 100644 (file)
@@ -86,14+86,15 @@ out_free:
  
 int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
 {
-       int err = -EFAULT; 
+       int err;
 
        while(len>0)
        {
                if(iov->iov_len)
                {
                        int copy = min(iov->iov_len, len);
-                       if (copy_to_user(iov->iov_base, kdata, copy))
+                       err = copy_to_user(iov->iov_base, kdata, copy);
+                       if (err)
                                goto out;
                        kdata+=copy;
                        len-=copy;
index 6b8bc48..0b197fe 100644 (file)
@@ -7,7+7,7 @@
  *             PROC file system.  It is mainly used for debugging and
  *             statistics.
  *
- * Version:    $Id: proc.c,v 1.25 1998/03/11 07:12:56 davem Exp $
+ * Version:    $Id: proc.c,v 1.26 1998/03/13 08:02:12 davem Exp $
  *
  * Authors:    Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -77,11+77,12 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
        unsigned long  dest, src;
        unsigned short destp, srcp;
        int timer_active, timer_active1, timer_active2;
+       int tw_bucket = 0;
        unsigned long timer_expires;
        struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
 
        dest  = sp->daddr;
-       src   = sp->saddr;
+       src   = sp->rcv_saddr;
        destp = sp->dummy_th.dest;
        srcp  = sp->dummy_th.source;
        
@@ -96,30+97,47 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
        
        destp = ntohs(destp);
        srcp  = ntohs(srcp);
-       timer_active1 = del_timer(&tp->retransmit_timer);
-       timer_active2 = del_timer(&sp->timer);
-       if (!timer_active1) tp->retransmit_timer.expires=0;
-       if (!timer_active2) sp->timer.expires=0;
-       timer_active=0;
-       timer_expires=jiffies;
+       if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
+               struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
+
+               tw_bucket       = 1;
+               timer_active1   = timer_active2 = 0;
+               timer_active    = 3;
+               timer_expires   = tw->timer.expires;
+       } else {
+               timer_active1 = del_timer(&tp->retransmit_timer);
+               timer_active2 = del_timer(&sp->timer);
+               if (!timer_active1) tp->retransmit_timer.expires=0;
+               if (!timer_active2) sp->timer.expires=0;
+               timer_active    = 0;
+               timer_expires   = (unsigned) -1;
+       }
        if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
-               timer_active=1;
-               timer_expires=tp->retransmit_timer.expires;
+               timer_active    = 1;
+               timer_expires   = tp->retransmit_timer.expires;
        }
        if (timer_active2 && sp->timer.expires < timer_expires) {
-               timer_active=2;
-               timer_expires=sp->timer.expires;
+               timer_active    = 2;
+               timer_expires   = sp->timer.expires;
        }
+       if(timer_active == 0)
+               timer_expires = jiffies;
        sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
                i, src, srcp, dest, destp, sp->state, 
-               format==0?tp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc), 
-               format==0?tp->rcv_nxt-tp->copied_seq:atomic_read(&sp->rmem_alloc),
-                               timer_active, timer_expires-jiffies,
-               tp->retransmits,
-               sp->socket ? sp->socket->inode->i_uid:0,
-               timer_active?sp->timeout:0,
-               sp->socket ? sp->socket->inode->i_ino:0);
+               (tw_bucket ?
+                0 :
+                (format == 0) ?
+                tp->write_seq-tp->snd_una : atomic_read(&sp->wmem_alloc)),
+               (tw_bucket ?
+                0 :
+                (format == 0) ?
+                tp->rcv_nxt-tp->copied_seq: atomic_read(&sp->rmem_alloc)),
+               timer_active, timer_expires-jiffies,
+               (tw_bucket ? 0 : tp->retransmits),
+               (!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0,
+               (!tw_bucket && timer_active) ? sp->timeout : 0,
+               (!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0);
        
        if (timer_active1) add_timer(&tp->retransmit_timer);
        if (timer_active2) add_timer(&sp->timer);       
index d453e55..31c0a71 100644 (file)
@@ -1,7+1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.26 1998/03/08 05:56:35 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.27 1998/03/12 00:03:31 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -45,8+45,6 @@ extern int sysctl_ip_masq_debug;
 
 extern int sysctl_tcp_cong_avoidance;
 extern int sysctl_tcp_hoe_retransmits;
-extern int sysctl_tcp_sack;
-extern int sysctl_tcp_tsack;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_keepalive_time;
@@ -99,12+97,6 @@ ctl_table ipv4_table[] = {
         {NET_IPV4_TCP_HOE_RETRANSMITS, "tcp_hoe_retransmits",
          &sysctl_tcp_hoe_retransmits, sizeof(int), 0644, NULL,
          &proc_dointvec},
-        {NET_IPV4_TCP_SACK, "tcp_sack",
-         &sysctl_tcp_sack, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-        {NET_IPV4_TCP_TSACK, "tcp_tsack",
-         &sysctl_tcp_tsack, sizeof(int), 0644, NULL,
-         &proc_dointvec},
         {NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps",
          &sysctl_tcp_timestamps, sizeof(int), 0644, NULL,
          &proc_dointvec},
index 2be0e7d..133bda9 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.89 1998/03/11 07:12:51 davem Exp $
+ * Version:    $Id: tcp.c,v 1.94 1998/03/13 14:15:52 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -426,6+426,7 @@ struct tcp_mib      tcp_statistics;
 
 kmem_cache_t *tcp_openreq_cachep;
 kmem_cache_t *tcp_bucket_cachep;
+kmem_cache_t *tcp_timewait_cachep;
 
 /*
  *     Find someone to 'accept'. Must be called with
@@ -479,20+480,6 @@ static void tcp_close_pending (struct sock *sk)
 }
 
 /*
- *     Enter the time wait state.
- */
-
-void tcp_time_wait(struct sock *sk)
-{
-       tcp_set_state(sk,TCP_TIME_WAIT);
-       sk->shutdown = SHUTDOWN_MASK;
-       if (!sk->dead)
-               sk->state_change(sk);
-       tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-}
-
-
-/*
  *     Walk down the receive queue counting readable data.
  *
  *     Must be called with the socket lock held.
@@ -897,7+884,6 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
 
                        seglen -= copy;
                        tcp_build_header_data(skb->h.th, sk, seglen || iovlen);
-                       /* FIXME: still need to think about SACK options here. */
 
                        if (flags & MSG_OOB) {
                                skb->h.th->urg = 1;
@@ -1055,11+1041,10 @@ static void cleanup_rbuf(struct sock *sk, int copied)
 
        SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk));
 
-       /* We send a ACK if we can now advertise a non-zero window
+       /* We send an ACK if we can now advertise a non-zero window
         * which has been raised "significantly".
         */
-       if(tcp_timer_is_set(sk, TIME_DACK) ||
-          (copied >= tcp_receive_window(&sk->tp_pinfo.af_tcp)))
+       if(copied >= tcp_receive_window(&sk->tp_pinfo.af_tcp))
                tcp_read_wakeup(sk);
 }
 
@@ -1334,8+1319,7 @@ static int tcp_close_state(struct sock *sk, int dead)
         *      reset mistake.
         */
        if(dead && ns==TCP_FIN_WAIT2) {
-               int timer_active=del_timer(&sk->timer);
-               if(timer_active)
+               if(sk->timer.prev && del_timer(&sk->timer))
                        add_timer(&sk->timer);
                else
                        tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
@@ -1418,7+1402,7 @@ void tcp_close(struct sock *sk, unsigned long timeout)
        /*  Timeout is not the same thing - however the code likes
         *  to send both the same way (sigh).
         */
-       if (tcp_close_state(sk,1)==1)
+       if (tcp_close_state(sk,1))
                tcp_send_fin(sk);
 
        if (timeout) {
@@ -1447,8+1431,7 @@ void tcp_close(struct sock *sk, unsigned long timeout)
         * we may need to set up a timer.
          */
        if (sk->state==TCP_FIN_WAIT2) {
-               int timer_active=del_timer(&sk->timer);
-               if(timer_active)
+               if(sk->timer.prev && del_timer(&sk->timer))
                        add_timer(&sk->timer);
                else
                        tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
@@ -1632,4+1615,11 @@ __initfunc(void tcp_init(void))
                                              NULL, NULL);
        if(!tcp_bucket_cachep)
                panic("tcp_init: Cannot alloc tcp_bind_bucket cache.");
+
+       tcp_timewait_cachep = kmem_cache_create("tcp_tw_bucket",
+                                               sizeof(struct tcp_tw_bucket),
+                                               0, SLAB_HWCACHE_ALIGN,
+                                               NULL, NULL);
+       if(!tcp_timewait_cachep)
+               panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
 }
index 424e7bc..3263d2d 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.76 1998/03/11 07:12:46 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.81 1998/03/14 06:09:54 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -67,12+67,14 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
 
 extern int sysctl_tcp_fin_timeout;
 
+/* These are on by default so the code paths get tested.
+ * For the final 2.2 this may be undone at our discretion. -DaveM
+ */
+int sysctl_tcp_timestamps = 1;
+int sysctl_tcp_window_scaling = 1;
+
 int sysctl_tcp_cong_avoidance;
 int sysctl_tcp_hoe_retransmits;
-int sysctl_tcp_sack;
-int sysctl_tcp_tsack;
-int sysctl_tcp_timestamps;
-int sysctl_tcp_window_scaling;
 int sysctl_tcp_syncookies = SYNC_INIT; 
 int sysctl_tcp_stdurg;
 
@@ -126,9+128,9 @@ static void tcp_delack_estimator(struct tcp_opt *tp)
 
 static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
 {
-       long m;
-       /*
-        *      The following amusing code comes from Jacobson's
+       long m = mrtt; /* RTT */
+
+       /*      The following amusing code comes from Jacobson's
         *      article in SIGCOMM '88.  Note that rtt and mdev
         *      are scaled versions of rtt and mean deviation.
         *      This is designed to be as fast as possible 
@@ -137,12+139,9 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
         *      On a 1990 paper the rto value is changed to:
         *      RTO = rtt + 4 * mdev
         */
-
-       m = mrtt;  /* RTT */
-
+       if(m == 0)
+               m = 1;
        if (tp->srtt != 0) {
-               if(m<=0)
-                       m=1;            /* IS THIS RIGHT FOR <0 ??? */
                m -= (tp->srtt >> 3);   /* m is now error in rtt est */
                tp->srtt += m;          /* rtt = 7/8 rtt + 1/8 new */
                if (m < 0)
@@ -196,19+195,17 @@ extern __inline__ void tcp_replace_ts_recent(struct tcp_opt *tp, __u32 end_seq)
         */
        if (!before(end_seq,tp->last_ack_sent)) {
                tp->ts_recent = tp->rcv_tsval;
-               /* FIXME: need a corse timestamp. Days uptime
-                * would be good.
-                */
                tp->ts_recent_stamp = jiffies;
        }
 }
 
+#define PAWS_24DAYS    (HZ * 60 * 60 * 24 * 24)
+
 extern __inline__ int tcp_paws_discard(struct tcp_opt *tp)
 {
-       /* FIXME: must check that ts_recent is not
-        * more than 24 days old here. Yuck.
-        */
-       return ((s32)(tp->rcv_tsval-tp->ts_recent) < 0);
+       /* ts_recent must be younger than 24 days */
+       return (((jiffies - tp->ts_recent_stamp) >= PAWS_24DAYS) ||
+               ((s32)(tp->rcv_tsval-tp->ts_recent) < 0));
 }
 
 
@@ -251,8+248,6 @@ static void tcp_reset(struct sock *sk, struct sk_buff *skb)
 
        /* We want the right error as BSD sees it (and indeed as we do). */
        switch (sk->state) {
-               case TCP_TIME_WAIT:
-                       break;
                case TCP_SYN_SENT:
                        sk->err = ECONNREFUSED;
                        break;
@@ -262,23+257,8 @@ static void tcp_reset(struct sock *sk, struct sk_buff *skb)
                default:
                        sk->err = ECONNRESET;
        };
-#ifdef CONFIG_TCP_RFC1337
-       /*
-        *      Time wait assassination protection [RFC1337]
-        *
-        *      This is a good idea, but causes more sockets to take time to close.
-        *
-        *      Ian Heavens has since shown this is an inadequate fix for the protocol
-        *      bug in question.
-        */
-       if(sk->state!=TCP_TIME_WAIT) {
-               tcp_set_state(sk,TCP_CLOSE);
-               sk->shutdown = SHUTDOWN_MASK;
-       }
-#else  
        tcp_set_state(sk,TCP_CLOSE);
        sk->shutdown = SHUTDOWN_MASK;
-#endif 
        if (!sk->dead) 
                sk->state_change(sk);
 }
@@ -296,7+276,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
        int length=(th->doff*4)-sizeof(struct tcphdr);
 
        ptr = (unsigned char *)(th + 1);
-       tp->sacks = 0;
        tp->saw_tstamp = 0;
 
        while(length>0) {
@@ -330,10+309,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
                                                                tp->snd_wscale = *(__u8 *)ptr;
                                                        }
                                                break;
-                                       case TCPOPT_SACK_PERM:
-                                               if(opsize==TCPOLEN_SACK_PERM && th->syn)
-                                                       if (sysctl_tcp_sack && !no_fancy)
-                                                               tp->sack_ok = 1;
                                        case TCPOPT_TIMESTAMP:
                                                if(opsize==TCPOLEN_TIMESTAMP) {
                                                        /* Cheaper to set again then to
@@ -347,18+322,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
                                                        }
                                                }
                                                break;
-                                       case TCPOPT_SACK:
-                                               if (no_fancy || !sysctl_tcp_sack) 
-                                                       break; 
-                                               tp->sacks = (opsize-2)>>3;
-                                               if (tp->sacks<<3 == opsize-2) {
-                                                       int i;
-                                                       for (i = 0; i < tp->sacks; i++) {
-                                                               tp->left_sack[i] = ntohl(((__u32 *)ptr)[2*i]);
-                                                               tp->right_sack[i] = ntohl(((__u32 *)ptr)[2*i+1]);
-                                                       }
-                                               } else
-                                                       tp->sacks = 0;
                                }
                                ptr+=opsize-2;
                                length-=opsize;
@@ -368,7+331,7 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
 
 /* Fast parse options. This hopes to only see timestamps.
  * If it is wrong it falls back on tcp_parse_option().
- * This should probably get extended for timestamps + SACK as well.
+ * This should probably get extended for timestamps as well.
  * Assembly code anyone? -- erics
  */
 static __inline__ int tcp_fast_parse_options(struct tcphdr *th, struct tcp_opt *tp)
@@ -378,14+341,12 @@ static __inline__ int tcp_fast_parse_options(struct tcphdr *th, struct tcp_opt *
                return 0;
        if (th->doff == sizeof(struct tcphdr)>>2) {
                tp->saw_tstamp = 0;
-               tp->sacks = 0;
                return 0;
-       } else if (th->doff == (sizeof(struct tcphdr)>>2)+3) {
+       } else if (th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
                __u32 *ptr = (__u32 *)(th + 1);
-               if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
-                                 | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+               if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+                                            | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
                        tp->saw_tstamp = 1;
-                       tp->sacks = 0;
                        tp->rcv_tsval = ntohl(*++ptr);
                        tp->rcv_tsecr = ntohl(*++ptr);
                        return 1;
@@ -557,7+518,6 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
 
        expected = (tp->snd_nxt - tp->snd_una) * inv_basertt;
 
-       /* XXX sk->mss should move into tcp_opt as well -DaveM */
        inv_basebd = sk->mss * inv_basertt;
 
        /* Slow Start */
@@ -802,7+762,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
         */
        if (before(tp->snd_wl1, ack_seq) ||
            (tp->snd_wl1 == ack_seq && !after(tp->snd_wl2, ack))) {
-               unsigned long nwin = ntohs(th->window) << tp->snd_wscale;
+               u32 nwin = ntohs(th->window) << tp->snd_wscale;
 
                if ((tp->snd_wl2 != ack) || (nwin > tp->snd_wnd)) {
                        flag |= FLAG_WIN_UPDATE;
@@ -882,6+842,193 @@ uninteresting_ack:
        return 0;
 }
 
+/* New-style handling of TIME_WAIT sockets. */
+static void tcp_timewait_kill(unsigned long __arg)
+{
+       struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)__arg;
+
+       /* Zap the timer. */
+       del_timer(&tw->timer);
+
+       /* Unlink from various places. */
+       if(tw->bind_next)
+               tw->bind_next->bind_pprev = tw->bind_pprev;
+       *(tw->bind_pprev) = tw->bind_next;
+       if(tw->tb->owners == NULL)
+               tcp_inc_slow_timer(TCP_SLT_BUCKETGC);
+
+       if(tw->next)
+               tw->next->pprev = tw->pprev;
+       *tw->pprev = tw->next;
+
+       /* We decremented the prot->inuse count when we entered TIME_WAIT
+        * and the sock from which this came was destroyed.
+        */
+       tw->sklist_next->sklist_prev = tw->sklist_prev;
+       tw->sklist_prev->sklist_next = tw->sklist_next;
+
+       /* Ok, now free it up. */
+       kmem_cache_free(tcp_timewait_cachep, tw);
+}
+
+/* We come here as a special case from the AF specific TCP input processing,
+ * and the SKB has no owner.  Essentially handling this is very simple,
+ * we just keep silently eating rx'd packets until none show up for the
+ * entire timeout period.  The only special cases are for BSD TIME_WAIT
+ * reconnects and SYN/RST bits being set in the TCP header.
+ */
+int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
+                              struct tcphdr *th, void *opt, __u16 len)
+{
+       /*      RFC 1122:
+        *      "When a connection is [...] on TIME-WAIT state [...]
+        *      [a TCP] MAY accept a new SYN from the remote TCP to
+        *      reopen the connection directly, if it:
+        *      
+        *      (1)  assigns its initial sequence number for the new
+        *      connection to be larger than the largest sequence
+        *      number it used on the previous connection incarnation,
+        *      and
+        *
+        *      (2)  returns to TIME-WAIT state if the SYN turns out 
+        *      to be an old duplicate".
+        */
+       if(th->syn && !th->rst && after(skb->seq, tw->rcv_nxt)) {
+               struct sock *sk;
+               struct tcp_func *af_specific = tw->af_specific;
+               __u32 isn;
+
+               isn = tw->rcv_nxt + 128000;
+               if(isn == 0)
+                       isn++;
+               tcp_timewait_kill((unsigned long)tw);
+               sk = af_specific->get_sock(skb, th);
+               if(sk == NULL || !ipsec_sk_policy(sk,skb))
+                       return 0;
+               skb_set_owner_r(skb, sk);
+               af_specific = sk->tp_pinfo.af_tcp.af_specific;
+               if(af_specific->conn_request(sk, skb, opt, isn) < 0)
+                       return 1; /* Toss a reset back. */
+               return 0; /* Discard the frame. */
+       }
+
+       /* Check RST or SYN */
+       if(th->rst || th->syn) {
+               /* This is TIME_WAIT assasination, in two flavors.
+                * Oh well... nobody has a sufficient solution to this
+                * protocol bug yet.
+                */
+               tcp_timewait_kill((unsigned long)tw);
+
+               if(!th->rst)
+                       return 1; /* toss a reset back */
+       } else {
+               if(th->ack) {
+                       /* In this case we must reset the TIMEWAIT timer. */
+                       del_timer(&tw->timer);
+                       tw->timer.expires = jiffies + TCP_TIMEWAIT_LEN;
+                       add_timer(&tw->timer);
+               }
+       }
+       return 0; /* Discard the frame. */
+}
+
+/* Enter the time wait state.  This is always called from BH
+ * context.  Essentially we whip up a timewait bucket, copy the
+ * relevant info into it from the SK, and mess with hash chains
+ * and list linkage.
+ */
+static __inline__ void tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw)
+{
+       struct sock **head, *sktw;
+
+       /* Step 1: Remove SK from established hash. */
+       if(sk->next)
+               sk->next->pprev = sk->pprev;
+       *sk->pprev = sk->next;
+       sk->pprev = NULL;
+       tcp_reg_zap(sk);
+
+       /* Step 2: Put TW into bind hash where SK was. */
+       tw->tb = (struct tcp_bind_bucket *)sk->prev;
+       if((tw->bind_next = sk->bind_next) != NULL)
+               sk->bind_next->bind_pprev = &tw->bind_next;
+       tw->bind_pprev = sk->bind_pprev;
+       *sk->bind_pprev = (struct sock *)tw;
+
+       /* Step 3: Same for the protocol sklist. */
+       (tw->sklist_next = sk->sklist_next)->sklist_prev = (struct sock *)tw;
+       (tw->sklist_prev = sk->sklist_prev)->sklist_next = (struct sock *)tw;
+       sk->sklist_next = NULL;
+       sk->prot->inuse--;
+
+       /* Step 4: Hash TW into TIMEWAIT half of established hash table. */
+       head = &tcp_established_hash[sk->hashent + (TCP_HTABLE_SIZE/2)];
+       sktw = (struct sock *)tw;
+       if((sktw->next = *head) != NULL)
+               (*head)->pprev = &sktw->next;
+       *head = sktw;
+       sktw->pprev = head;
+}
+
+void tcp_time_wait(struct sock *sk)
+{
+       struct tcp_tw_bucket *tw;
+
+       tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC);
+       if(tw != NULL) {
+               /* Give us an identity. */
+               tw->daddr       = sk->daddr;
+               tw->rcv_saddr   = sk->rcv_saddr;
+               tw->bound_dev_if= sk->bound_dev_if;
+               tw->num         = sk->num;
+               tw->state       = TCP_TIME_WAIT;
+               tw->family      = sk->family;
+               tw->source      = sk->dummy_th.source;
+               tw->dest        = sk->dummy_th.dest;
+               tw->rcv_nxt     = sk->tp_pinfo.af_tcp.rcv_nxt;
+               tw->af_specific = sk->tp_pinfo.af_tcp.af_specific;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               if(tw->family == AF_INET6) {
+                       memcpy(&tw->v6_daddr,
+                              &sk->net_pinfo.af_inet6.daddr,
+                              sizeof(struct in6_addr));
+                       memcpy(&tw->v6_rcv_saddr,
+                              &sk->net_pinfo.af_inet6.rcv_saddr,
+                              sizeof(struct in6_addr));
+               }
+#endif
+               /* Linkage updates. */
+               tcp_tw_hashdance(sk, tw);
+
+               /* Get the TIME_WAIT timeout firing. */
+               init_timer(&tw->timer);
+               tw->timer.function = tcp_timewait_kill;
+               tw->timer.data = (unsigned long) tw;
+               tw->timer.expires = jiffies + TCP_TIMEWAIT_LEN;
+               add_timer(&tw->timer);
+
+               /* CLOSE the SK. */
+               if(sk->state == TCP_ESTABLISHED)
+                       tcp_statistics.TcpCurrEstab--;
+               sk->state = TCP_CLOSE;
+               net_reset_timer(sk, TIME_DONE,
+                               min(sk->tp_pinfo.af_tcp.srtt * 2, TCP_DONE_TIME));
+       } else {
+               /* Sorry, we're out of memory, just CLOSE this
+                * socket up.  We've got bigger problems than
+                * non-graceful socket closings.
+                */
+               tcp_set_state(sk, TCP_CLOSE);
+       }
+
+       /* Prevent rcvmsg/sndmsg calls, and wake people up. */
+       sk->shutdown = SHUTDOWN_MASK;
+       if(!sk->dead)
+               sk->state_change(sk);
+}
+
 /*
  *     Process the FIN bit. This now behaves as it is supposed to work
  *     and the FIN takes effect when it is validly part of sequence
@@ -897,13+1044,8 @@ uninteresting_ack:
  *     If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT.
  */
  
-static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
+static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
 {
-       if(sk->state == TCP_SYN_SENT) {
-               /* RFC793 says to drop the segment and return. */
-               return 1;
-       }
-
        sk->tp_pinfo.af_tcp.fin_seq = skb->end_seq;
 
        tcp_send_ack(sk);
@@ -931,12+1073,6 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
                case TCP_LAST_ACK:
                        /* RFC793: Remain in the LAST-ACK state. */
                        break;
-               case TCP_TIME_WAIT:
-                       /* Received a retransmission of the FIN,
-                        * restart the TIME_WAIT timer.
-                        */
-                       tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-                       break;
 
                case TCP_FIN_WAIT1:
                        /* This case occurs when a simultaneous close
@@ -953,21+1089,15 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
                        break;
                case TCP_FIN_WAIT2:
                        /* Received a FIN -- send ACK and enter TIME_WAIT. */
-                       tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-                       sk->shutdown |= SHUTDOWN_MASK;
-                       tcp_set_state(sk,TCP_TIME_WAIT);
-                       break;
-               case TCP_CLOSE:
-                       /* Already in CLOSE. */
+                       tcp_time_wait(sk);
                        break;
                default:
-                       /* Only TCP_LISTEN is left, in that case we should never
-                        * reach this piece of code.
+                       /* Only TCP_LISTEN and TCP_CLOSE are left, in these
+                        * cases we should never reach this piece of code.
                         */
                        printk("tcp_fin: Impossible, sk->state=%d\n", sk->state);
                        break;
        };
-       return 0;
 }
 
 /* This one checks to see if we can put data from the
@@ -994,6+1124,8 @@ static void tcp_ofo_queue(struct sock *sk)
                skb_unlink(skb);
                skb_queue_tail(&sk->receive_queue, skb);
                tp->rcv_nxt = skb->end_seq;
+               if(skb->h.th->fin)
+                       tcp_fin(skb, sk, skb->h.th);
        }
 }
 
@@ -1012,6+1144,10 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                dst_confirm(sk->dst_cache);
                skb_queue_tail(&sk->receive_queue, skb);
                tp->rcv_nxt = skb->end_seq;
+               if(skb->h.th->fin)
+                       tcp_fin(skb, sk, skb->h.th);
+               else
+                       tp->delayed_acks++;
                tcp_ofo_queue(sk);
                if (skb_queue_len(&tp->out_of_order_queue) == 0)
                        tp->pred_flags = htonl((0x5010 << 16) | tp->snd_wnd);
@@ -1022,7+1158,6 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
        if (!after(skb->end_seq, tp->rcv_nxt)) {
                /* A retransmit, 2nd most common case.  Force an imediate ack. */
                SOCK_DEBUG(sk, "retransmit received: seq %X\n", skb->seq);
-               tp->delayed_acks++;
                tcp_enter_quickack_mode(tp);
                kfree_skb(skb);
                return;
@@ -1091,8+1226,6 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
         if (skb->len == 0 && !th->fin)
                return(0);
 
-       /* FIXME: don't accept data after the received fin. */
-
        /* We no longer have anyone receiving data on this connection. */
        tcp_data_queue(sk, skb);
 
@@ -1101,9+1234,9 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
                tp->rcv_nxt = tp->copied_seq;
        }
 
-       tp->delayed_acks++;
-
-       /* Now tell the user we may have some data. */
+       /* Above, tcp_data_queue() increments delayed_acks appropriately.
+        * Now tell the user we may have some data.
+        */
        if (!sk->dead) {
                SOCK_DEBUG(sk, "Data wakeup.\n");
                sk->data_ready(sk,0);
@@ -1268,6+1401,12 @@ static void prune_queue(struct sock *sk)
        
        /* Now continue with the receive queue if it wasn't enough */
        while ((skb = skb_peek_tail(&sk->receive_queue))) {
+               /* Never toss anything when we've seen the FIN.
+                * It's just too complex to recover from it.
+                */
+               if(skb->h.th->fin)
+                       break;
+
                /* Never remove packets that have been already acked */
                if (before(skb->end_seq, tp->last_ack_sent+1)) {
                        printk(KERN_DEBUG "prune_queue: hit acked data c=%x,%x,%x\n",
@@ -1356,9+1495,11 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                        skb_queue_tail(&sk->receive_queue, skb);
                        tp->rcv_nxt = skb->end_seq;
 
+                       /* FIN bit check is not done since if FIN is set in
+                        * this frame, the pred_flags won't match up. -DaveM
+                        */
                        sk->data_ready(sk, 0);
                        tcp_delack_estimator(tp);
-
                        tp->delayed_acks++;
                        __tcp_ack_snd_check(sk);
                        return 0;
@@ -1398,10+1539,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
        /* step 7: process the segment text */
        queued = tcp_data(skb, sk, len);
 
-       /* step 8: check the FIN bit */
-       if (th->fin)
-               (void) tcp_fin(skb, sk, th);
-
        tcp_data_snd_check(sk);
 
        /* If our receive queue has grown past its limits shrink it */
@@ -1569,14+1706,15 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 
                        tcp_set_state(sk, TCP_ESTABLISHED);
                        tcp_parse_options(th,tp,0);
-                       /* FIXME: need to make room for SACK still */
+
                        if (tp->wscale_ok == 0) {
                                tp->snd_wscale = tp->rcv_wscale = 0;
                                tp->window_clamp = min(tp->window_clamp,65535);
                        }
                        if (tp->tstamp_ok) {
-                               tp->tcp_header_len = sizeof(struct tcphdr) + 12;        /* FIXME: Define constant! */
-                               sk->dummy_th.doff += 3;         /* reserve space of options */
+                               tp->tcp_header_len =
+                                       sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
+                               sk->dummy_th.doff += (TCPOLEN_TSTAMP_ALIGNED >> 2);
                        } else
                                tp->tcp_header_len = sizeof(struct tcphdr);
                        if (tp->saw_tstamp) {
@@ -1590,8+1728,12 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                        if (tp->in_mss)
                                sk->mss = min(sk->mss, tp->in_mss);
 
-                       /* Take out space for tcp options. */
-                       sk->mss -= tp->tcp_header_len - sizeof(struct tcphdr);
+                       /* Check for the case where we tried to advertise
+                        * a window including timestamp options, but did not
+                        * end up using them for this connection.
+                        */
+                       if((tp->tstamp_ok == 0) && sysctl_tcp_timestamps)
+                               sk->mss += TCPOLEN_TSTAMP_ALIGNED;
                        
                        sk->dummy_th.dest = th->source;
                        tp->copied_seq = tp->rcv_nxt;
@@ -1629,52+1771,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 
                }
                break;
-
-       case TCP_TIME_WAIT:
-               /*      RFC 1122:
-                *      "When a connection is [...] on TIME-WAIT state [...]
-                *      [a TCP] MAY accept a new SYN from the remote TCP to
-                *      reopen the connection directly, if it:
-                *      
-                *      (1)  assigns its initial sequence number for the new
-                 *     connection to be larger than the largest sequence
-                 *     number it used on the previous connection incarnation,
-                 *     and
-                *
-                *      (2)  returns to TIME-WAIT state if the SYN turns out 
-                *      to be an old duplicate".
-                */
-               if (th->syn && !th->rst && after(skb->seq, tp->rcv_nxt)) {
-                       __u32 isn;
-
-                       skb_orphan(skb);
-                        sk->err = ECONNRESET;
-                        tcp_set_state(sk, TCP_CLOSE);
-                        sk->shutdown = SHUTDOWN_MASK;
-
-                       isn = tp->rcv_nxt + 128000;
-                       if (isn == 0)  
-                               isn++; 
-
-                       sk = tp->af_specific->get_sock(skb, th);
-
-                       if (sk == NULL || !ipsec_sk_policy(sk,skb))
-                               goto discard;
-
-                       skb_set_owner_r(skb, sk);
-                       tp = &sk->tp_pinfo.af_tcp;
-
-                       if(tp->af_specific->conn_request(sk, skb, opt, isn) < 0)
-                               return 1;
-
-                       goto discard;
-               }
-
-               break;
        }
 
        /*   Parse the tcp_options present on this header.
-        *   By this point we really only expect timestamps and SACKs.
+        *   By this point we really only expect timestamps.
         *   Note that this really has to be here and not later for PAWS
         *   (RFC1323) to work.
         */
@@ -1781,13+1881,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                goto discard;
                        }
                        break;
-
-               case TCP_TIME_WAIT:
-                       /* Keep us in TIME_WAIT until we stop getting 
-                        * packets, reset the timeout.
-                        */
-                       tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-                       break;
                }
        } else
                goto discard;
@@ -1825,12+1918,6 @@ step6:
                break;
        }
 
-       /* step 8: check the FIN bit */
-       if (th->fin) {
-               if(tcp_fin(skb, sk, th) != 0)
-                       goto discard;
-       }
-
        tcp_data_snd_check(sk);
        tcp_ack_snd_check(sk);
 
index 3e1542e..ced7f99 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.101 1998/03/11 07:12:54 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.106 1998/03/13 14:15:54 davem Exp $
  *
  *             IPv4 specific functions
  *
 
 #include <linux/inet.h>
 
-extern int sysctl_tcp_sack;
-extern int sysctl_tcp_tsack;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_syncookies;
@@ -155,7+153,8 @@ struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum)
        if(tb != NULL) {
                struct tcp_bind_bucket **head =
                        &tcp_bound_hash[tcp_bhashfn(snum)];
-               tb->port = (snum | 0x10000);
+               tb->port = snum;
+               tb->flags = TCPB_FLAG_LOCKED;
                tb->owners = NULL;
                if((tb->next = *head) != NULL)
                        tb->next->pprev = &tb->next;
@@ -188,7+187,7 @@ static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
                        int sk_reuse = sk->reuse;
 
                        /* We must walk the whole port owner list in this case. -DaveM */
-                       for(sk2 = tb->owners; sk2; sk2 = sk2->tp_pinfo.af_tcp.bind_next) {
+                       for(sk2 = tb->owners; sk2; sk2 = sk2->bind_next) {
                                if(sk->bound_dev_if == sk2->bound_dev_if) {
                                        if(!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) {
                                                if(!sk2->rcv_saddr              ||
@@ -246,7+245,7 @@ static void tcp_v4_hash(struct sock *sk)
                struct sock **skp;
 
                SOCKHASH_LOCK();
-               skp = &tcp_established_hash[tcp_sk_hashfn(sk)];
+               skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
                if((sk->next = *skp) != NULL)
                        (*skp)->pprev = &sk->next;
                *skp = sk;
@@ -286,14+285,10 @@ static void tcp_v4_rehash(struct sock *sk)
        if(state != TCP_CLOSE) {
                struct sock **skp;
 
-               if(state == TCP_LISTEN) {
+               if(state == TCP_LISTEN)
                        skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
-               } else {
-                       int hash = tcp_sk_hashfn(sk);
-                       if(state == TCP_TIME_WAIT)
-                               hash += (TCP_HTABLE_SIZE/2);
-                       skp = &tcp_established_hash[hash];
-               }
+               else
+                       skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
 
                if((sk->next = *skp) != NULL)
                        (*skp)->pprev = &sk->next;
@@ -349,6+344,7 @@ static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int d
 
 /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
+ * It is assumed that this code only gets called from within NET_BH.
  */
 static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
                                           u32 saddr, u16 sport,
@@ -375,8+371,7 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
                goto hit;
 
        /* Optimize here for direct hit, only listening connections can
-        * have wildcards anyways.  It is assumed that this code only
-        * gets called from within NET_BH.
+        * have wildcards anyways.
         */
        hash = tcp_hashfn(daddr, hnum, saddr, sport);
        for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
@@ -447,7+442,7 @@ static struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
                s = tb->owners;
        }
 pass2:
-       for(; s; s = s->tp_pinfo.af_tcp.bind_next) {
+       for(; s; s = s->bind_next) {
                int score = 0;
                if(s->rcv_saddr) {
                        if((s->num != hpnum || s->rcv_saddr != paddr) &&
@@ -591,7+586,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        lock_sock(sk);
 
        /* Do this early, so there is less state to unwind on failure. */
-       buff = sock_wmalloc(sk, MAX_SYN_SIZE, 0, GFP_KERNEL);
+       buff = sock_wmalloc(sk, (MAX_SYN_SIZE + sizeof(struct sk_buff)),
+                           0, GFP_KERNEL);
        if (buff == NULL) {
                release_sock(sk);
                ip_rt_put(rt);
@@ -637,10+633,18 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
        /* No failure conditions can result past this point. */
 
+       /* We'll fix this up when we get a response from the other end.
+        * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
+        */
+       tp->tcp_header_len = sizeof(struct tcphdr) +
+               (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0);
+
        th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
        buff->h.th = th;
 
        memcpy(th,(void *)&(sk->dummy_th), sizeof(*th));
+       /* th->doff gets fixed up below if we tack on options. */
+
        buff->seq = tp->write_seq++;
        th->seq = htonl(buff->seq);
        tp->snd_nxt = tp->write_seq;
@@ -658,11+662,9 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if(sk->mtu < 64)
                sk->mtu = 64;   /* Sanity limit */
 
-       if (sk->user_mss)
-               sk->mss = sk->user_mss;
-       else
-               sk->mss = (sk->mtu - sizeof(struct iphdr) -
-                          sizeof(struct tcphdr));
+       sk->mss = (sk->mtu - sizeof(struct iphdr) - tp->tcp_header_len);
+       if(sk->user_mss)
+               sk->mss = min(sk->mss, sk->user_mss);
 
        if (sk->mss < 1) {
                printk(KERN_DEBUG "intial sk->mss below 1\n");
@@ -677,9+679,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                &tp->rcv_wscale);
        th->window = htons(tp->rcv_wnd);
 
-       tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack,
-               sysctl_tcp_timestamps,
-               sysctl_tcp_window_scaling,tp->rcv_wscale);
+       tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_timestamps,
+               sysctl_tcp_window_scaling, tp->rcv_wscale);
        buff->csum = 0;
        th->doff = (sizeof(*th)+ tmp)>>2;
 
@@ -861,7+862,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
        th = (struct tcphdr*)(dp+(iph->ihl<<2));
 
        sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex);
-       if (sk == NULL) {
+       if (sk == NULL || sk->state == TCP_TIME_WAIT) {
                icmp_statistics.IcmpInErrors++;
                return; 
        }
@@ -1018,7+1019,8 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
        skb1->csum = csum_partial((u8 *) th1, sizeof(*th1), 0);
        th1->check = tcp_v4_check(th1, sizeof(*th1), skb1->nh.iph->saddr,
                                  skb1->nh.iph->daddr, skb1->csum);
-       /* FIXME: should this carry an options packet? */
+
+       /* Do not place TCP options in a reset. */
        ip_queue_xmit(skb1);
        tcp_statistics.TcpOutSegs++;
        tcp_statistics.TcpOutRsts++;
@@ -1070,6+1072,10 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
        mss = (skb->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr));
        if (sk->user_mss)
                mss = min(mss, sk->user_mss);
+
+       /* tcp_syn_build_options will do an skb_put() to obtain the TCP
+        * options bytes below.
+        */
        skb->h.th = th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
 
        /* Don't offer more than they did.
@@ -1110,16+1116,7 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
                req->rcv_wscale = rcv_wscale; 
        }
        th->window = htons(req->rcv_wnd);
-
-       /* XXX Partial csum of 4 byte quantity is itself! -DaveM
-        * Yes, but it's a bit harder to special case now. It's
-        * now computed inside the tcp_v4_send_check() to clean up
-        * updating the options fields in the mainline send code.
-        * If someone thinks this is really bad let me know and
-        * I'll try to do it a different way. -- erics
-        */
-
-       tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
+       tmp = tcp_syn_build_options(skb, req->mss, req->tstamp_ok,
                req->wscale_ok,req->rcv_wscale);
        skb->csum = 0;
        th->doff = (sizeof(*th) + tmp)>>2;
@@ -1238,14+1235,13 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
        req->rcv_wnd = 0;               /* So that tcp_send_synack() knows! */
 
        req->rcv_isn = skb->seq;
-       tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+       tp.tstamp_ok = tp.wscale_ok = tp.snd_wscale = 0;
        tp.in_mss = 536;
        tcp_parse_options(th,&tp,want_cookie);
        if (tp.saw_tstamp)
                req->ts_recent = tp.rcv_tsval;
        req->mss = tp.in_mss;
        req->tstamp_ok = tp.tstamp_ok;
-       req->sack_ok = tp.sack_ok;
        req->snd_wscale = tp.snd_wscale;
        req->wscale_ok = tp.wscale_ok;
        req->rmt_port = th->source;
@@ -1374,7+1370,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
 
                newtp->saw_tstamp = 0;
                newtp->in_mss = 536;
-               newtp->sacks = 0;
 
                init_timer(&newtp->probe_timer);
                newtp->probe_timer.function = &tcp_probe_timer;
@@ -1448,7+1443,6 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        if (newsk->mtu < 64)
                newsk->mtu = 64;
 
-       newtp->sack_ok = req->sack_ok;
        newtp->tstamp_ok = req->tstamp_ok;
        newtp->window_clamp = req->window_clamp;
        newtp->rcv_wnd = req->rcv_wnd;
@@ -1463,8+1457,8 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        if (newtp->tstamp_ok) {
                newtp->ts_recent = req->ts_recent;
                newtp->ts_recent_stamp = jiffies;
-               newtp->tcp_header_len = sizeof(struct tcphdr) + 12;     /* FIXME: define constant! */
-               newsk->dummy_th.doff += 3;
+               newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
+               newsk->dummy_th.doff += (TCPOLEN_TSTAMP_ALIGNED >> 2);
        } else {
                newtp->tcp_header_len = sizeof(struct tcphdr);
        }
@@ -1653,6+1647,8 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
 
        skb->used = 0;
 
+       if (sk->state == TCP_TIME_WAIT)
+               goto do_time_wait;
        if (!sk->sock_readers)
                return tcp_v4_do_rcv(sk, skb);
 
@@ -1666,6+1662,12 @@ discard_it:
        /* Discard frame. */
        kfree_skb(skb);
        return 0;
+
+do_time_wait:
+       if(tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
+                                     skb, th, &(IPCB(skb)->opt), skb->len))
+               goto no_tcp_socket;
+       goto discard_it;
 }
 
 int tcp_v4_build_header(struct sock *sk, struct sk_buff *skb)
@@ -1816,11+1818,9 @@ static int tcp_v4_init_sock(struct sock *sk)
        /* FIXME: tie this to sk->rcvbuf? (May be unnecessary) */
        /* tp->rcv_wnd = 8192; */
        tp->tstamp_ok = 0;
-       tp->sack_ok = 0;
        tp->wscale_ok = 0;
        tp->in_mss = 536;
        tp->snd_wscale = 0;
-       tp->sacks = 0;
        tp->saw_tstamp = 0;
        tp->syn_backlog = 0;
 
index 2bdbb5d..2d278aa 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_output.c,v 1.58 1998/03/11 07:12:49 davem Exp $
+ * Version:    $Id: tcp_output.c,v 1.63 1998/03/13 14:15:55 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 
 #include <net/tcp.h>
 
-extern int sysctl_tcp_sack;
-extern int sysctl_tcp_tsack;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 
@@ -66,32+64,19 @@ static __inline__ void update_send_head(struct sock *sk)
  
 void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue)
 {
-       struct tcphdr * th = skb->h.th;
+       struct tcphdr *th = skb->h.th;
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
        int size;
 
        /* Length of packet (not counting length of pre-tcp headers). */
        size = skb->len - ((unsigned char *) th - skb->data);
 
-       /* Sanity check it.. */
-       if (size < tp->tcp_header_len || size > skb->len) {
-               printk(KERN_DEBUG "tcp_send_skb: bad skb "
-                      "(skb = %p, data = %p, th = %p, len = %u)\n",
-                      skb, skb->data, th, skb->len);
-               kfree_skb(skb);
-               return;
-       }
-
-       /* If we have queued a header size packet.. (these crash a few
-        * tcp stacks if ack is not set)
-        */
-       if (size == tp->tcp_header_len) {
-               /* If it's got a syn or fin discard. */
-               if(!th->syn && !th->fin) {
-                       printk(KERN_DEBUG "tcp_send_skb: attempt to queue a bogon.\n");
-                       kfree_skb(skb);
-                       return;
-               }
+       /* If there is a FIN or a SYN we add it onto the size. */
+       if (th->fin || th->syn) {
+               if(th->syn)
+                       size++;
+               if(th->fin)
+                       size++;
        }
 
        /* Actual processing. */
@@ -107,7+92,7 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue)
                tp->last_ack_sent = tp->rcv_nxt;
                th->ack_seq = htonl(tp->rcv_nxt);
                th->window = htons(tcp_select_window(sk));
-               tcp_update_options((__u32 *)(th+1),tp);
+               tcp_update_options((__u32 *)(th + 1),tp);
 
                tp->af_specific->send_check(sk, th, size, skb);
 
@@ -184,8+169,6 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
        buff->h.th = nth;
        memcpy(nth, th, tp->tcp_header_len);
 
-       /* FIXME: Make sure this gets tcp options right. */
-       
        /* Correct the new header. */
        buff->seq = skb->seq + len;
        buff->end_seq = skb->end_seq;
@@ -310,7+293,7 @@ void tcp_write_xmit(struct sock *sk)
 
                tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt);
                th->window = rcv_wnd;
-               tcp_update_options((__u32 *)(th+1),tp);
+               tcp_update_options((__u32 *)(th + 1),tp);
 
                tp->af_specific->send_check(sk, th, size, skb);
 
@@ -607,91+590,98 @@ void tcp_do_retransmit(struct sock *sk, int all)
        }
 }
 
-/*
- *     Send a fin.
+/* Send a fin.  The caller locks the socket for us.  This cannot be
+ * allowed to fail queueing a FIN frame under any circumstances.
  */
-
 void tcp_send_fin(struct sock *sk)
 {
-       struct tcphdr *th =(struct tcphdr *)&sk->dummy_th;
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);    
-       struct tcphdr *t1;
-       struct sk_buff *buff;
-       int tmp;
        
-       buff = sock_wmalloc(sk, BASE_ACK_SIZE + tp->tcp_header_len, 1, GFP_KERNEL);
-       if (buff == NULL) {
-               /* FIXME: This is a disaster if it occurs. */
-               printk(KERN_INFO "tcp_send_fin: Impossible malloc failure");
-               return;
-       }
+       /* Optimization, tack on the FIN if we have a queue of
+        * unsent frames.
+        */
+       if(tp->send_head != NULL) {
+               struct sk_buff *tail = skb_peek_tail(&sk->write_queue);
+               struct tcphdr *th = tail->h.th;
+               int data_len;
+
+               /* Unfortunately tcp_write_xmit won't check for going over
+                * the MSS due to the FIN sequence number, so we have to
+                * watch out for it here.
+                */
+               data_len = (tail->tail - (((unsigned char *)th)+tp->tcp_header_len));
+               if(data_len >= sk->mss)
+                       goto build_new_frame; /* ho hum... */
 
-       /* Administrivia. */
-       buff->csum = 0;
+               /* tcp_write_xmit() will checksum the header etc. for us. */
+               th->fin = 1;
+               tail->end_seq++;
+       } else {
+               struct sk_buff *buff;
+               struct tcphdr *th;
 
-       /* Put in the IP header and routing stuff. */
-       tmp = tp->af_specific->build_net_header(sk, buff);
-       if (tmp < 0) {
-               int t;
+build_new_frame:
+               buff = sock_wmalloc(sk,
+                                   (BASE_ACK_SIZE + tp->tcp_header_len +
+                                    sizeof(struct sk_buff)),
+                                   1, GFP_KERNEL);
+               if (buff == NULL) {
+                       /* We can only fail due to low memory situations, not
+                        * due to going over our sndbuf limits (due to the
+                        * force flag passed to sock_wmalloc).  So just keep
+                        * trying.  We cannot allow this fail.  The socket is
+                        * still locked, so we need not check if the connection
+                        * was reset in the meantime etc.
+                        */
+                       goto build_new_frame;
+               }
 
-               /* FIXME: We must not throw this out. Eventually we must
-                 * put a FIN into the queue, otherwise it never gets queued.
-                */
-               kfree_skb(buff);
-               tp->write_seq++;
-               t = del_timer(&sk->timer);
-               if (t)
-                       add_timer(&sk->timer);
-               else
-                       tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-               return;
-       }
-       
-       /* We ought to check if the end of the queue is a buffer and
-        * if so simply add the fin to that buffer, not send it ahead.
-        */
-       t1 =(struct tcphdr *)skb_put(buff,tp->tcp_header_len);
-       buff->h.th =  t1;
-       tcp_build_options((__u32 *)(t1+1),tp);
+               /* Administrivia. */
+               buff->csum = 0;
 
-       memcpy(t1, th, sizeof(*t1));
-       buff->seq = tp->write_seq;
-       tp->write_seq++;
-       buff->end_seq = tp->write_seq;
-       t1->seq = htonl(buff->seq);
-       t1->ack_seq = htonl(tp->rcv_nxt);
-       t1->window = htons(tcp_select_window(sk));
-       t1->fin = 1;
-
-       tp->af_specific->send_check(sk, t1, tp->tcp_header_len, buff);
-
-       /* The fin can only be transmited after the data. */
-       skb_queue_tail(&sk->write_queue, buff);
-       if (tp->send_head == NULL) {
-               /* FIXME: BUG! we need to check if the fin fits into the window
-                * here. If not we need to do window probing (sick, but true)
+               /* Put in the IP header and routing stuff.
+                *
+                * FIXME:
+                * We can fail if the interface for the route
+                * this socket takes goes down right before
+                * we get here.  ANK is there a way to point
+                * this into a "black hole" route in such a
+                * case?  Ideally, we should still be able to
+                * queue this and let the retransmit timer
+                * keep trying until the destination becomes
+                * reachable once more.  -DaveM
                 */
-               struct sk_buff *skb1;
-
-               tp->packets_out++;
-               tp->snd_nxt = tp->write_seq;
-               buff->when = jiffies;
-
-               skb1 = skb_clone(buff, GFP_KERNEL);
-               if (skb1) {
-                       skb_set_owner_w(skb1, sk);
-                       tp->af_specific->queue_xmit(skb1);
+               if(tp->af_specific->build_net_header(sk, buff) < 0) {
+                       kfree_skb(buff);
+                       goto update_write_seq;
                }
+               th = (struct tcphdr *) skb_put(buff, tp->tcp_header_len);
+               buff->h.th = th;
 
-                if (!tcp_timer_is_set(sk, TIME_RETRANS))
-                       tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+               memcpy(th, (void *) &(sk->dummy_th), sizeof(*th));
+               th->seq = htonl(tp->write_seq);
+               th->fin = 1;
+               tcp_build_options((__u32 *)(th + 1), tp);
+
+               /* This makes sure we do things like abide by the congestion
+                * window and other constraints which prevent us from sending.
+                */
+               tcp_send_skb(sk, buff, 0);
        }
+update_write_seq:
+       /* So that we recognize the ACK coming back for
+        * this FIN as being legitimate.
+        */
+       tp->write_seq++;
 }
 
 /* WARNING: This routine must only be called when we have already sent
  * a SYN packet that crossed the incoming SYN that caused this routine
  * to get called. If this assumption fails then the initial rcv_wnd
  * and rcv_wscale values will not be correct.
+ *
+ * XXX When you have time Dave, redo this to use tcp_send_skb() just
+ * XXX like tcp_send_fin() above now does.... -DaveM
  */
 int tcp_send_synack(struct sock *sk)
 {
@@ -701,7+691,7 @@ int tcp_send_synack(struct sock *sk)
        struct tcphdr *th;
        int tmp;
        
-       skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
+       skb = sock_wmalloc(sk, MAX_SYN_SIZE + sizeof(struct sk_buff), 1, GFP_ATOMIC);
        if (skb == NULL) 
                return -ENOMEM;
 
@@ -733,8+723,7 @@ int tcp_send_synack(struct sock *sk)
        tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt);
 
        tmp = tcp_syn_build_options(skb, sk->mss,
-               tp->sack_ok, tp->tstamp_ok,
-               tp->wscale_ok,tp->rcv_wscale);
+               tp->tstamp_ok, tp->wscale_ok, tp->rcv_wscale);
        skb->csum = 0;
        th->doff = (sizeof(*th) + tmp)>>2;
 
@@ -774,7+763,8 @@ void tcp_send_delayed_ack(struct tcp_opt *tp, int max_timeout)
        timeout += jiffies;
 
        /* Use new timeout only if there wasn't a older one earlier. */
-       if (!del_timer(&tp->delack_timer) || timeout < tp->delack_timer.expires)
+       if ((!tp->delack_timer.prev || !del_timer(&tp->delack_timer)) ||
+           (timeout < tp->delack_timer.expires))
                tp->delack_timer.expires = timeout;
 
        add_timer(&tp->delack_timer);
@@ -798,8+788,6 @@ void tcp_send_ack(struct sock *sk)
 
        /* We need to grab some memory, and put together an ack,
         * and then put it into the queue to be sent.
-        * FIXME: is it better to waste memory here and use a
-        * constant sized ACK?
         */
        buff = sock_wmalloc(sk, BASE_ACK_SIZE + tp->tcp_header_len, 1, GFP_ATOMIC);
        if (buff == NULL) {
@@ -826,13+814,13 @@ void tcp_send_ack(struct sock *sk)
 
        th = (struct tcphdr *)skb_put(buff,tp->tcp_header_len);
        memcpy(th, &sk->dummy_th, sizeof(struct tcphdr));
-       tcp_build_options((__u32 *)(th+1),tp);
 
        /* Swap the send and the receive. */
        th->window      = ntohs(tcp_select_window(sk));
        th->seq         = ntohl(tp->snd_nxt);
        tp->last_ack_sent = tp->rcv_nxt;
        th->ack_seq     = htonl(tp->rcv_nxt);
+       tcp_build_and_update_options((__u32 *)(th + 1), tp);
 
        /* Fill in the packet and send it. */
        tp->af_specific->send_check(sk, th, tp->tcp_header_len, buff);
@@ -881,6+869,7 @@ void tcp_write_wakeup(struct sock *sk)
                }
 
                th = skb->h.th;
+               tcp_update_options((__u32 *)(th + 1), tp);
                tp->af_specific->send_check(sk, th, th->doff * 4 + win_size, skb);
                buff = skb_clone(skb, GFP_ATOMIC);
                if (buff == NULL)
@@ -911,11+900,8 @@ void tcp_write_wakeup(struct sock *sk)
                        return;
                }
 
-               t1 = (struct tcphdr *) skb_put(buff, sizeof(struct tcphdr));
+               t1 = (struct tcphdr *) skb_put(buff, tp->tcp_header_len);
                memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
-               /* FIXME: should zero window probes have SACK and/or TIMESTAMP data?
-                * If so we have to tack them on here.
-                */
 
                /*      Use a previous sequence.
                 *      This should cause the other end to send an ack.
@@ -924,11+910,9 @@ void tcp_write_wakeup(struct sock *sk)
                t1->seq = htonl(tp->snd_nxt-1);
                t1->ack_seq = htonl(tp->rcv_nxt);
                t1->window = htons(tcp_select_window(sk));
+               tcp_build_and_update_options((__u32 *)(t1 + 1), tp);
 
-               /* Value from dummy_th may be larger. */
-               t1->doff = sizeof(struct tcphdr)/4;
-
-               tp->af_specific->send_check(sk, t1, sizeof(*t1), buff);
+               tp->af_specific->send_check(sk, t1, tp->tcp_header_len, buff);
        }
 
        /* Send it. */
index d67e04d..330f8e9 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_timer.c,v 1.38 1998/03/10 05:11:17 davem Exp $
+ * Version:    $Id: tcp_timer.c,v 1.39 1998/03/13 08:02:17 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -89,20+89,24 @@ void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when)
                 * The delayed ack timer can be set if we are changing the
                 * retransmit timer when removing acked frames.
                 */
-               del_timer(&tp->probe_timer);
-               del_timer(&tp->retransmit_timer);
+               if(tp->probe_timer.prev)
+                       del_timer(&tp->probe_timer);
+               if(tp->retransmit_timer.prev)
+                       del_timer(&tp->retransmit_timer);
                tp->retransmit_timer.expires=jiffies+when;
                add_timer(&tp->retransmit_timer);
                break;
 
        case TIME_DACK:
-               del_timer(&tp->delack_timer);
+               if(tp->delack_timer.prev)
+                       del_timer(&tp->delack_timer);
                tp->delack_timer.expires=jiffies+when;
                add_timer(&tp->delack_timer);
                break;
 
        case TIME_PROBE0:
-               del_timer(&tp->probe_timer);
+               if(tp->probe_timer.prev)
+                       del_timer(&tp->probe_timer);
                tp->probe_timer.expires=jiffies+when;
                add_timer(&tp->probe_timer);
                break;  
@@ -137,8+141,7 @@ static int tcp_write_err(struct sock *sk, int force)
        
        /* Time wait the socket. */
        if (!force && ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING))) {
-               tcp_set_state(sk,TCP_TIME_WAIT);
-               tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+               tcp_time_wait(sk);
        } else {
                /* Clean up time. */
                tcp_set_state(sk, TCP_CLOSE);
@@ -216,10+219,9 @@ void tcp_probe_timer(unsigned long data)
                        sk->err = ETIMEDOUT;
                sk->error_report(sk);
 
-               /* Time wait the socket. */
                if ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {
-                       tcp_set_state(sk, TCP_TIME_WAIT);
-                       tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+                       /* Time wait the socket. */
+                       tcp_time_wait(sk);
                } else {
                        /* Clean up time. */
                        tcp_set_state(sk, TCP_CLOSE);
index a719f59..6e97b5b 100644 (file)
@@ -5,7+5,7 @@
  *
  *             TIMER - implementation of software timers for IP.
  *
- * Version:    $Id: timer.c,v 1.9 1998/03/11 07:12:44 davem Exp $
+ * Version:    $Id: timer.c,v 1.10 1998/03/13 08:02:18 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 
 void net_delete_timer (struct sock *t)
 {
-       unsigned long flags;
-
-       save_flags (flags);
-       cli();
-
-       t->timeout = 0;
        if(t->timer.prev)
                del_timer (&t->timer);
-
-       restore_flags (flags);
+       t->timeout = 0;
 }
 
 void net_reset_timer (struct sock *t, int timeout, unsigned long len)
 {
        net_delete_timer (t);
        t->timeout = timeout;
-#if 1
-  /* FIXME: ??? */
-       if ((int) len < 0)      /* prevent close to infinite timers. THEY _DO_ */
-               len = 3;        /* happen (negative values ?) - don't ask me why ! -FB */
-#endif
        t->timer.expires = jiffies+len;
        add_timer (&t->timer);
 }
 
-
-/*
- *     Now we will only be called whenever we need to do
- *     something, but we must be sure to process all of the
- *     sockets that need it.
+/* Now we will only be called whenever we need to do
+ * something, but we must be sure to process all of the
+ * sockets that need it.
  */
-
 void net_timer (unsigned long data)
 {
        struct sock *sk = (struct sock*)data;
@@ -97,7+82,7 @@ void net_timer (unsigned long data)
        }
 
        /* Always see if we need to send an ack. */
-       if (sk->ack_backlog && !sk->zapped) {
+       if (sk->tp_pinfo.af_tcp.delayed_acks && !sk->zapped) {
                sk->prot->read_wakeup (sk);
                if (!sk->dead)
                        sk->data_ready(sk,0);
@@ -106,14+91,13 @@ void net_timer (unsigned long data)
        /* Now we need to figure out why the socket was on the timer. */
        switch (why) {
                case TIME_DONE:
-                       /* If the socket hasn't been closed off, re-try a bit later */
+                       /* If the socket hasn't been closed off, re-try a bit later. */
                        if (!sk->dead) {
                                net_reset_timer(sk, TIME_DONE, TCP_DONE_TIME);
                                break;
                        }
 
-                       if (sk->state != TCP_CLOSE) 
-                       {
+                       if (sk->state != TCP_CLOSE) {
                                printk (KERN_DEBUG "non CLOSE socket in time_done\n");
                                break;
                        }
@@ -121,11+105,9 @@ void net_timer (unsigned long data)
                        break;
 
                case TIME_DESTROY:
-               /*
-                *      We've waited for a while for all the memory associated with
-                *      the socket to be freed.
-                */
-
+                       /* We've waited for a while for all the memory associated with
+                        * the socket to be freed.
+                        */
                        destroy_sock(sk);
                        break;
 
index 39a98c5..1b3893a 100644 (file)
@@ -5,7+5,7 @@
  *
  *             The User Datagram Protocol (UDP).
  *
- * Version:    $Id: udp.c,v 1.51 1998/03/08 05:56:40 davem Exp $
+ * Version:    $Id: udp.c,v 1.53 1998/03/12 03:20:00 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -828,7+828,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
                                 * of this packet since that is all
                                 * that will be read.
                                 */
-                               amount = skb->tail - skb->h.raw;
+                               amount = skb->len - sizeof(struct udphdr);
                        }
                        return put_user(amount, (int *)arg);
                }
index b03b6ea..b87d469 100644 (file)
@@ -7,7+7,7 @@
  *             PROC file system.  This is very similar to the IPv4 version,
  *             except it reports the sockets in the INET6 address family.
  *
- * Version:    $Id: proc.c,v 1.5 1998/03/06 01:23:22 davem Exp $
+ * Version:    $Id: proc.c,v 1.6 1998/03/13 08:02:19 davem Exp $
  *
  * Authors:    David S. Miller (davem@caip.rutgers.edu)
  *
 #include <linux/net.h>
 #include <linux/in6.h>
 #include <net/sock.h>
+#include <net/tcp.h>
 #include <net/transp_v6.h>
 
 /* This is the main implementation workhorse of all these routines. */
@@ -52,21+53,35 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
        SOCKHASH_LOCK();
        sp = pro->sklist_next;
        while(sp != (struct sock *)pro) {
+               struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
+               int tw_bucket = 0;
+
                pos += 149;
                if(pos < offset)
                        goto next;
                tp = &(sp->tp_pinfo.af_tcp);
-               dest  = &sp->net_pinfo.af_inet6.daddr;
-               src   = &sp->net_pinfo.af_inet6.rcv_saddr;
+               if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
+                       tw_bucket = 1;
+                       dest  = &tw->v6_daddr;
+                       src   = &tw->v6_rcv_saddr;
+               } else {
+                       dest  = &sp->net_pinfo.af_inet6.daddr;
+                       src   = &sp->net_pinfo.af_inet6.rcv_saddr;
+               }
                destp = ntohs(sp->dummy_th.dest);
                srcp  = ntohs(sp->dummy_th.source);
-
-               timer_active1 = del_timer(&tp->retransmit_timer);
-               timer_active2 = del_timer(&sp->timer);
-               if(!timer_active1) tp->retransmit_timer.expires = 0;
-               if(!timer_active2) sp->timer.expires = 0;
-               timer_active = 0;
-               timer_expires = (unsigned) -1;
+               if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
+                       timer_active1   = timer_active2 = 0;
+                       timer_active    = 3;
+                       timer_expires   = tw->timer.expires;
+               } else {
+                       timer_active1 = del_timer(&tp->retransmit_timer);
+                       timer_active2 = del_timer(&sp->timer);
+                       if(!timer_active1) tp->retransmit_timer.expires = 0;
+                       if(!timer_active2) sp->timer.expires = 0;
+                       timer_active = 0;
+                       timer_expires = (unsigned) -1;
+               }
                if(timer_active1 && tp->retransmit_timer.expires < timer_expires) {
                        timer_active = timer_active1;
                        timer_expires = tp->retransmit_timer.expires;
@@ -75,6+90,8 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
                        timer_active = timer_active2;
                        timer_expires = sp->timer.expires;
                }
+               if(timer_active == 0)
+                       timer_expires = jiffies;
                sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
                        "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
                        i,
@@ -83,13+100,23 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
                        dest->s6_addr32[0], dest->s6_addr32[1],
                        dest->s6_addr32[2], dest->s6_addr32[3], destp,
                        sp->state,
-                       format==0?tp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc),
-                       format==0?tp->rcv_nxt-tp->copied_seq:atomic_read(&sp->rmem_alloc),
+                       (tw_bucket ?
+                        0 :
+                        (format == 0) ?
+                        tp->write_seq-tp->snd_una :
+                        atomic_read(&sp->wmem_alloc)),
+                       (tw_bucket ?
+                        0 :
+                        (format == 0) ?
+                        tp->rcv_nxt-tp->copied_seq :
+                        atomic_read(&sp->rmem_alloc)),
                        timer_active, timer_expires-jiffies,
-                       tp->retransmits,
-                       sp->socket ? sp->socket->inode->i_uid:0,
-                       timer_active?sp->timeout:0,
-                       sp->socket ? sp->socket->inode->i_ino:0);
+                       (tw_bucket ? 0 : tp->retransmits),
+                       ((!tw_bucket && sp->socket) ?
+                        sp->socket->inode->i_uid : 0),
+                       (!tw_bucket && timer_active) ? sp->timeout : 0,
+                       ((!tw_bucket && sp->socket) ?
+                        sp->socket->inode->i_ino : 0));
 
                if(timer_active1) add_timer(&tp->retransmit_timer);
                if(timer_active2) add_timer(&sp->timer);
index a9950b0..bfaaa93 100644 (file)
@@ -5,7+5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.56 1998/03/11 02:20:52 davem Exp $
+ *     $Id: tcp_ipv6.c,v 1.59 1998/03/13 08:02:20 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
 
 #define ICMP_PARANOIA
 
-extern int sysctl_tcp_sack;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 
@@ -113,7+112,7 @@ static int tcp_v6_verify_bind(struct sock *sk, unsigned short snum)
                        int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
 
                        /* We must walk the whole port owner list in this case. -DaveM */
-                       for(sk2 = tb->owners; sk2; sk2 = sk2->tp_pinfo.af_tcp.bind_next) {
+                       for(sk2 = tb->owners; sk2; sk2 = sk2->bind_next) {
                                if(!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) {
                                        if(addr_type == IPV6_ADDR_ANY   ||
                                           !sk2->rcv_saddr              ||
@@ -141,7+140,7 @@ static void tcp_v6_hash(struct sock *sk)
                struct sock **skp;
 
                SOCKHASH_LOCK();
-               skp = &tcp_established_hash[tcp_v6_sk_hashfn(sk)];
+               skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
                if((sk->next = *skp) != NULL)
                        (*skp)->pprev = &sk->next;
                *skp = sk;
@@ -181,14+180,10 @@ static void tcp_v6_rehash(struct sock *sk)
        if(state != TCP_CLOSE) {
                struct sock **skp;
 
-               if(state == TCP_LISTEN) {
+               if(state == TCP_LISTEN)
                        skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
-               } else {
-                       int hash = tcp_v6_sk_hashfn(sk);
-                       if(state == TCP_TIME_WAIT)
-                               hash += (TCP_HTABLE_SIZE/2);
-                       skp = &tcp_established_hash[hash];
-               }
+               else
+                       skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
 
                if((sk->next = *skp) != NULL)
                        (*skp)->pprev = &sk->next;
@@ -224,6+219,7 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor
 
 /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
+ * It is assumed that this code only gets called from within NET_BH.
  */
 static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
                                           struct in6_addr *saddr, u16 sport,
@@ -250,8+246,7 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
                goto hit;
 
        /* Optimize here for direct hit, only listening connections can
-        * have wildcards anyways.  It is assumed that this code only
-        * gets called from within NET_BH.
+        * have wildcards anyways.
         */
        hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
        for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
@@ -270,10+265,12 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
        for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
                if(sk->num              == hnum                 && /* local port     */
                   sk->family           == AF_INET6             && /* address family */
-                  sk->dummy_th.dest    == sport                && /* remote port    */
-                  !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.daddr, saddr) &&
-                  !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, daddr))
-                       goto hit;
+                  sk->dummy_th.dest    == sport) {                /* remote port    */
+                       struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
+                       if(!ipv6_addr_cmp(&tw->v6_daddr, saddr) &&
+                          !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr))
+                               goto hit;
+               }
 #ifdef USE_QUICKSYNS
 listener_shortcut:
 #endif
@@ -520,8+517,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
         *      Put in the TCP options to say MTU.
         */
 
-        tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack,
-                sysctl_tcp_timestamps,
+        tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_timestamps,
                 sysctl_tcp_window_scaling,tp->rcv_wscale);
         th->doff = sizeof(*th)/4 + (tmp>>2);
        buff->csum = 0;
@@ -623,7+619,7 @@ void tcp_v6_err(int type, int code, unsigned char *header, __u32 info,
 
        sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source);
 
-       if (sk == NULL) {
+       if (sk == NULL || sk->state == TCP_TIME_WAIT) {
                /* XXX: Update ICMP error count */
                return;
        }
@@ -800,7+796,7 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
        }
        th->window = htons(req->rcv_wnd);
 
-       tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
+       tmp = tcp_syn_build_options(skb, req->mss, req->tstamp_ok,
                req->wscale_ok,req->rcv_wscale);
        skb->csum = 0;
        th->doff = (sizeof(*th) + tmp)>>2;
@@ -873,14+869,13 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
 
        req->rcv_isn = skb->seq;
        req->snt_isn = isn;
-       tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+       tp.tstamp_ok = tp.wscale_ok = tp.snd_wscale = 0;
        tp.in_mss = 536;
        tcp_parse_options(skb->h.th,&tp,0);
        if (tp.saw_tstamp)
                 req->ts_recent = tp.rcv_tsval;
         req->mss = tp.in_mss;
         req->tstamp_ok = tp.tstamp_ok;
-        req->sack_ok = tp.sack_ok;
         req->snd_wscale = tp.snd_wscale;
         req->wscale_ok = tp.wscale_ok;
        req->rmt_port = skb->h.th->source;
@@ -984,7+979,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        ip6_dst_store(newsk, dst);
 
-        newtp->sack_ok = req->sack_ok;
         newtp->tstamp_ok = req->tstamp_ok;
        newtp->window_clamp = req->window_clamp;
        newtp->rcv_wnd = req->rcv_wnd;
@@ -1186,12+1180,14 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
                        goto no_tcp_socket;
                }
 
-               skb->sk = sk;
                skb->seq = ntohl(th->seq);
                skb->end_seq = skb->seq + th->syn + th->fin + len - th->doff*4;
                skb->ack_seq = ntohl(th->ack_seq);
-
                skb->used = 0;
+               if(sk->state == TCP_TIME_WAIT)
+                       goto do_time_wait;
+
+               skb->sk = sk;
        }
 
        /*
@@ -1254,6+1250,12 @@ discard_it:
 
        kfree_skb(skb);
        return 0;
+
+do_time_wait:
+       if(tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
+                                     skb, th, &(IPCB(skb)->opt), skb->len))
+               goto no_tcp_socket;
+       goto discard_it;
 }
 
 static int tcp_v6_rebuild_header(struct sock *sk, struct sk_buff *skb)
@@ -1407,10+1409,8 @@ static int tcp_v6_init_sock(struct sock *sk)
        tp->in_mss = 536;
        /* tp->rcv_wnd = 8192; */
        tp->tstamp_ok = 0;
-       tp->sack_ok = 0;
        tp->wscale_ok = 0;
        tp->snd_wscale = 0;
-       tp->sacks = 0;
        tp->saw_tstamp = 0;
        tp->syn_backlog = 0;
 
index 5324fdc..40e9b02 100644 (file)
@@ -7,7+7,7 @@
  *
  *     Based on linux/ipv4/udp.c
  *
- *     $Id: udp.c,v 1.23 1998/03/08 05:56:59 davem Exp $
+ *     $Id: udp.c,v 1.24 1998/03/12 03:20:21 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
index d800cf9..9d8a206 100644 (file)
@@ -759,6+759,8 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
 
        newsk = skb->sk;
        newsk->pair = NULL;
+       newsk->socket = newsock;
+       newsk->sleep = &newsock->wait;
        sti();
 
        /* Now attach up the new socket */
index 8831de3..ad51e9a 100644 (file)
@@ -244,7+244,6 @@ EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
 EXPORT_SYMBOL(__release_sock);
 EXPORT_SYMBOL(net_timer);
 /* UDP/TCP exported functions for TCPv6 */
-EXPORT_SYMBOL(sysctl_tcp_sack);
 EXPORT_SYMBOL(sysctl_tcp_timestamps);
 EXPORT_SYMBOL(sysctl_tcp_window_scaling);
 EXPORT_SYMBOL(sock_rspace);
@@ -272,6+271,7 @@ EXPORT_SYMBOL(tcp_slt_array);
 EXPORT_SYMBOL(__tcp_inc_slow_timer);
 EXPORT_SYMBOL(tcp_statistics);
 EXPORT_SYMBOL(tcp_rcv_state_process);
+EXPORT_SYMBOL(tcp_timewait_state_process);
 EXPORT_SYMBOL(tcp_do_sendmsg);
 EXPORT_SYMBOL(tcp_v4_build_header);
 EXPORT_SYMBOL(tcp_v4_rebuild_header);
@@ -293,6+293,11 @@ EXPORT_SYMBOL(ipv4_specific);
 EXPORT_SYMBOL(tcp_simple_retransmit);
 
 EXPORT_SYMBOL(xrlim_allow);
+
+EXPORT_SYMBOL(tcp_write_xmit);
+EXPORT_SYMBOL(dev_loopback_xmit);
+EXPORT_SYMBOL(tcp_regs);
+
 #endif
 
 #ifdef CONFIG_NETLINK
index f3893c9..74fc7af 100644 (file)
@@ -832,9+832,10 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, int len,
 
        /* We can't use skb_copy_datagram here */
        err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
-       if (err)
+       if (err) {
+               err = -EFAULT;
                goto out_free;
-
+       }
        sk->stamp=skb->stamp;
 
        if (msg->msg_name)
index 1056c7d..a575402 100644 (file)
@@ -847,6+847,8 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
 
        newsk = skb->sk;
        newsk->pair = NULL;
+       newsk->socket = newsock;
+       newsk->sleep = &newsock->wait;
        sti();
 
        /* Now attach up the new socket */
index c74a199..b04072d 100644 (file)
@@ -1265,7+1265,9 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size
                }
 
                chunk = min(skb->len, size);
-               /* N.B. This could fail with -EFAULT */
+               /* N.B. This could fail with a non-zero value (which means -EFAULT
+                *      and the non-zero value is the number of bytes not copied).
+                */
                memcpy_toiovec(msg->msg_iov, skb->data, chunk);
                copied += chunk;
                size -= chunk;
close