- pre12.4.0-test8pre1
authorLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:38:22 +0000 (23 15:38 -0500)
committerLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:38:22 +0000 (23 15:38 -0500)
    - Oops. Moved back stallion.c to drivers/char. It's not a TV driver.
      Never has been, and I don't see it ever really becoming one ;)
    - mca.c: outp_b() should be outb_p().  Obviously nobody actually
      _uses_ the MCA bus any more ;)
    - umsdos should be ok again after the page_address() type-changes.
    - re-enable asynchronous read-ahead code.
    - Sun ESP driver update
    - netfilter debug fixes
    - IPv6 needs to register before proto_init()
    - socket() error code fix (EAFNOSUPPORT instead of EINVAL)
    - potential TCP socket leak fix
    - don't self-deadlock on the kbd_controller_lock when probing for the mouse
    - CONFIG_SMB_NLS_REMOTE didn't work. Silly typo.
    - scheduler wakeup race condition could cause delayed scheduling on SMP..
    - net/packet/af_packet.c: use the standard macros for marking page resevredness
    - ncpfs buffer-overflow fix
    - thread groups, take 1.
    - USB storage driver update

52 files changed:
Documentation/Configure.help
Documentation/cachetlb.txt[new file with mode: 0644]
Makefile
arch/i386/kernel/apic.c
arch/i386/kernel/mca.c
arch/sparc64/defconfig
drivers/char/nvram.c
drivers/char/pc_keyb.c
drivers/char/stallion.c[moved from drivers/media/video/stallion.c with 100% similarity]
drivers/scsi/esp.c
drivers/scsi/qlogicpti.c
drivers/sound/sound_core.c
drivers/usb/Makefile
drivers/usb/storage/Makefile
drivers/usb/storage/debug.c
drivers/usb/storage/debug.h
drivers/usb/storage/dpcm.c
drivers/usb/storage/dpcm.h
drivers/usb/storage/freecom.c[new file with mode: 0644]
drivers/usb/storage/freecom.h[copied from drivers/usb/storage/dpcm.h with 64% similarity]
drivers/usb/storage/protocol.c
drivers/usb/storage/protocol.h
drivers/usb/storage/scsiglue.c
drivers/usb/storage/scsiglue.h
drivers/usb/storage/sddr09.c
drivers/usb/storage/sddr09.h
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/shuttle_usbat.h
drivers/usb/storage/transport.c
drivers/usb/storage/transport.h
drivers/usb/storage/usb.c
drivers/usb/storage/usb.h
fs/exec.c
fs/ncpfs/ioctl.c
fs/smbfs/inode.c
fs/umsdos/emd.c
include/linux/pagemap.h
include/linux/sched.h
include/linux/wait.h
kernel/exit.c
kernel/fork.c
kernel/sched.c
kernel/signal.c
kernel/timer.c
mm/bootmem.c
mm/filemap.c
net/ipv4/ip_gre.c
net/ipv4/ip_output.c
net/ipv4/ipip.c
net/ipv6/sit.c
net/packet/af_packet.c
net/socket.c

index dc223b3..2c157e5 100644 (file)
@@ -2329,7+2329,7 @@ CONFIG_AGP_VIA
 AMD Irongate support
 CONFIG_AGP_AMD
   This option gives you AGP support for the GLX component of the
-  XFree86 4.x on Intel AMD Irongate chipset.
+  XFree86 4.x on AMD Irongate chipset.
 
   For the moment, you should probably say N, unless you want to test
   the GLX component for XFree86 3.3.6, which can be downloaded from
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
new file mode 100644 (file)
index 0000000..578dcb3
--- /dev/null
@@ -0,0 +1,319 @@
+               Cache and TLB Flushing
+                    Under Linux
+
+           David S. Miller <davem@redhat.com>
+
+This document describes the cache/tlb flushing interfaces called
+by the Linux VM subsystem.  It enumerates over each interface,
+describes it's intended purpose, and what side effect is expected
+after the interface is invoked.
+
+The side effects described below are stated for a uniprocessor
+implementation, and what is to happen on that single processor.  The
+SMP cases are a simple extension, in that you just extend the
+definition such that the side effect for a particular interface occurs
+on all processors in the system.  Don't let this scare you into
+thinking SMP cache/tlb flushing must be so inefficient, this is in
+fact an area where many optimizations are possible.  For example,
+if it can be proven that a user address space has never executed
+on a cpu (see vma->cpu_vm_mask), one need not perform a flush
+for this address space on that cpu.
+
+First, the TLB flushing interfaces, since they are the simplest.  The
+"TLB" is abstracted under Linux as something the cpu uses to cache
+virtual-->physical address translations obtained from the software
+page tables.  Meaning that if the software page tables change, it is
+possible for stale translations to exist in this "TLB" cache.
+Therefore when software page table changes occur, the kernel will
+invoke one of the following flush methods _after_ the page table
+changes occur:
+
+1) void flush_tlb_all(void)
+
+       The most severe flush of all.  After this interface runs,
+       any previous page table modification whatsoever will be
+       visible to the cpu.
+
+       This is usually invoked when the kernel page tables are
+       changed, since such translations are "global" in nature.
+
+2) void flush_tlb_mm(struct mm_struct *mm)
+
+       This interface flushes an entire user address space from
+       the TLB.  After running, this interface must make sure that
+       any previous page table modifications for the address space
+       'mm' will be visible to the cpu.  That is, after running,
+       there will be no entries in the TLB for 'mm'.
+
+       This interface is used to handle whole address space
+       page table operations such as what happens during
+       fork, exit, and exec.
+
+3) void flush_tlb_range(struct mm_struct *mm,
+                       unsigned long start, unsigned long end)
+
+       Here we are flushing a specific range of (user) virtual
+       address translations from the TLB.  After running, this
+       interface must make sure that any previous page table
+       modifications for the address space 'mm' in the range 'start'
+       to 'end' will be visible to the cpu.  That is, after running,
+       there will be no entries in the TLB for 'mm' for virtual
+       addresses in the range 'start' to 'end'.
+
+       Primarily, this is used for munmap() type operations.
+
+       The interface is provided in hopes that the port can find
+       a suitably efficient method for removing multiple page
+       sized translations from the TLB, instead of having the kernel
+       call flush_tlb_page (see below) for each entry which may be
+       modified.
+
+4) void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+
+       This time we need to remove the PAGE_SIZE sized translation
+       from the TLB.  The 'vma' is the backing structure used by
+       Linux to keep track of mmap'd regions for a process, the
+       address space is available via vma->vm_mm.  Also, one may
+       test (vma->vm_flags & VM_EXEC) to see if this region is
+       executable (and thus could be in the 'instruction TLB' in
+       split-tlb type setups).
+
+       After running, this interface must make sure that any previous
+       page table modification for address space 'vma->vm_mm' for
+       user virtual address 'page' will be visible to the cpu.  That
+       is, after running, there will be no entries in the TLB for
+       'vma->vm_mm' for virtual address 'page'.
+
+       This is used primarily during fault processing.
+
+5) void flush_tlb_pgtables(struct mm_struct *mm,
+                          unsigned long start, unsigned long end)
+
+   The software page tables for address space 'mm' for virtual
+   addresses in the range 'start' to 'end' are being torn down.
+
+   Some platforms cache the lowest level of the software page tables
+   in a linear virtually mapped array, to make TLB miss processing
+   more efficient.  On such platforms, since the TLB is caching the
+   software page table structure, it needs to be flushed when parts
+   of the software page table tree are unlinked/freed.
+
+   Sparc64 is one example of a platform which does this.
+
+   Usually, when munmap()'ing an area of user virtual address
+   space, the kernel leaves the page table parts around and just
+   marks the individual pte's as invalid.  However, if very large
+   portions of the address space are unmapped, the kernel frees up
+   those portions of the software page tables to prevent potential
+   excessive kernel memory usage caused by erratic mmap/mmunmap
+   sequences.  It is at these times that flush_tlb_pgtables will
+   be invoked.
+
+6) void update_mmu_cache(struct vm_area_struct *vma,
+                        unsigned long address, pte_t pte)
+
+       At the end of every page fault, this routine is invoked to
+       tell the architecture specific code that a translation
+       described by "pte" now exists at virtual address "address"
+       for address space "vma->vm_mm", in the software page tables.
+
+       A port may use this information in any way it so chooses.
+       For example, it could use this event to pre-load TLB
+       translations for software managed TLB configurations.
+       The sparc64 port currently does this.
+
+Next, we have the cache flushing interfaces.  In general, when Linux
+is changing an existing virtual-->physical mapping to a new value,
+the sequence will be in one of the following forms:
+
+       1) flush_cache_mm(mm);
+          change_all_page_tables_of(mm);
+          flush_tlb_mm(mm);
+
+       2) flush_cache_range(mm, start, end);
+          change_range_of_page_tables(mm, start, end);
+          flush_tlb_range(mm, start, end);
+
+       3) flush_cache_page(vma, page);
+          set_pte(pte_pointer, new_pte_val);
+          flush_tlb_page(vma, page);
+
+The cache level flush will always be first, because this allows
+us to properly handle systems whose caches are strict and require
+a virtual-->physical translation to exist for a virtual address
+when that virtual address is flushed from the cache.  The HyperSparc
+cpu is one such cpu with this attribute.
+
+The cache flushing routines below need only deal with cache flushing
+to the extent that it is necessary for a particular cpu.  Mostly,
+these routines must be implemented for cpus which have virtually
+indexed caches which must be flushed when virtual-->physical
+translations are changed or removed.  So, for example, the physically
+indexed physically tagged caches of IA32 processors have no need to
+implement these interfaces since the caches are fully synchronized
+and have no dependency on translation information.
+
+Here are the routines, one by one:
+
+1) void flush_cache_all(void)
+
+       The most severe flush of all.  After this interface runs,
+       the entire cpu cache is flushed.
+
+       This is usually invoked when the kernel page tables are
+       changed, since such translations are "global" in nature.
+
+2) void flush_cache_mm(struct mm_struct *mm)
+
+       This interface flushes an entire user address space from
+       the caches.  That is, after running, there will be no cache
+       lines assosciated with 'mm'.
+
+       This interface is used to handle whole address space
+       page table operations such as what happens during
+       fork, exit, and exec.
+
+3) void flush_cache_range(struct mm_struct *mm,
+                         unsigned long start, unsigned long end)
+
+       Here we are flushing a specific range of (user) virtual
+       addresses from the cache.  After running, there will be no
+       entries in the cache for 'mm' for virtual addresses in the
+       range 'start' to 'end'.
+
+       Primarily, this is used for munmap() type operations.
+
+       The interface is provided in hopes that the port can find
+       a suitably efficient method for removing multiple page
+       sized regions from the cache, instead of having the kernel
+       call flush_cache_page (see below) for each entry which may be
+       modified.
+
+4) void flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+
+       This time we need to remove a PAGE_SIZE sized range
+       from the cache.  The 'vma' is the backing structure used by
+       Linux to keep track of mmap'd regions for a process, the
+       address space is available via vma->vm_mm.  Also, one may
+       test (vma->vm_flags & VM_EXEC) to see if this region is
+       executable (and thus could be in the 'instruction cache' in
+       "Harvard" type cache layouts).
+
+       After running, there will be no entries in the cache for
+       'vma->vm_mm' for virtual address 'page'.
+
+       This is used primarily during fault processing.
+
+There exists another whole class of cpu cache issues which currently
+require a whole different set of interfaces to handle properly.
+The biggest problem is that of virtual aliasing in the data cache
+of a processor.
+
+Is your port subsceptible to virtual aliasing in it's D-cache?
+Well, if your D-cache is virtually indexed, is larger in size than
+PAGE_SIZE, and does not prevent multiple cache lines for the same
+physical address from existing at once, you have this problem.
+
+If your D-cache has this problem, first define asm/shmparam.h SHMLBA
+properly, it should essentially be the size of your virtually
+addressed D-cache (or if the size is variable, the largest possible
+size).  This setting will force the SYSv IPC layer to only allow user
+processes to mmap shared memory at address which are a multiple of
+this value.
+
+Next, you have two methods to solve the D-cache aliasing issue for all
+other cases.  Please keep in mind that fact that, for a given page
+mapped into some user address space, there is always at least one more
+mapping, that of the kernel in it's linear mapping starting at
+PAGE_OFFSET.  So immediately, once the first user maps a given
+physical page into it's address space, by implication the D-cache
+aliasing problem has the potential to exist since the kernel already
+maps this page at it's virtual address.
+
+First, I describe the old method to deal with this problem.  I am
+describing it for documentation purposes, but it is deprecated and the
+latter method I describe next should be used by all new ports and all
+existing ports should move over to the new mechanism as well.
+
+  flush_page_to_ram(struct page *page)
+
+       The physical page 'page' is about to be place into the
+       user address space of a process.  If it is possible for
+       stores done recently by the kernel into this physical
+       page, to not be visible to an arbitray mapping in userspace,
+       you must flush this page from the D-cache.
+
+       If the D-cache is writeback in nature, the dirty data (if
+       any) for this physical page must be written back to main
+       memory before the cache lines are invalidated.
+
+Admittedly, the author did not think very much when designing this
+interface.  It does not give the architecture enough information about
+what exactly is going on, and there is not context with which to base
+any judgment about whether an alias is possible at all.  The new
+interfaces to deal with D-cache aliasing are meant to address this by
+telling the architecture specific code exactly which is going on at
+the proper points in time.
+
+Here is the new interface:
+
+  void copy_user_page(void *from, void *to, unsigned long address)
+  void clear_user_page(void *to, unsigned long address)
+
+       These two routines store data in user anonymous or COW
+       pages.  It allows a port to efficiently avoid D-cache alias
+       issues between userspace and the kernel.
+
+       For example, a port may temporarily map 'from' and 'to' to
+       kernel virtual addresses during the copy.  The virtual address
+       for these two pages is choosen in such a way that the kernel
+       load/store instructions happen to virtual addresses which are
+       of the same "color" as the user mapping of the page.  Sparc64
+       for example, uses this technique.
+
+       The "address" parameter tells the virtual address where the
+       user has this page mapped.
+
+       If D-cache aliasing is not an issue, these two routines may
+       simply call memcpy/memset directly and do nothing more.
+
+  void flush_dcache_page(struct page *page)
+
+       Any time the kernel writes to a page cache page, _OR_
+       the kernel is about to read from a page cache page and
+       user space shared/writable mappings of this page potentially
+       exist, this routine is called.
+
+       The phrase "kernel writes to a page cache page" means,
+       specifically, that the kernel executes store instructions
+       that dirty data in that page at the page->virtual mapping
+       of that page.  It is important to flush here to handle
+       D-cache aliasing, to make sure these kernel stores are
+       visible to user space mappings of that page.
+
+       The corollary case is just as important, if there are users
+       which have shared+writable mappings of this file, we must make
+       sure that kernel reads of these pages will see the most recent
+       stores done by the user.
+
+       If D-cache aliasing is not an issue, this routine may
+       simply be defined as a nop on that architecture.
+
+        TODO: If we set aside a few bits in page->flags as
+             "architecture private", these interfaces could
+             be implemented much more efficiently.  This would
+             allow one to "defer" (perhaps indefinitely) the
+             actual flush if there are currently no user processes
+             mapping this page.
+
+             The idea is, first at flush_dcache_page() time, if
+             page->mapping->i_mmap is an empty list, just mark
+             one of the architecture private page flag bits.
+              Later, in update_mmu_cache(), a check could be made
+             of this flag bit, and if set the flush is done
+             and the flag bit is cleared.
+
+XXX Not documented: flush_icache_page(), need to talk to Paul
+                    Mackerras, David Mosberger-Tang, et al.
+                   to see what the expected semantics of this
+                   interface are.  -DaveM
index cd24022..b9427e0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7+1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 0
-EXTRAVERSION = -test7
+EXTRAVERSION = -test8
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index aed2753..1626761 100644 (file)
@@ -671,14+671,7 @@ inline void smp_local_timer_interrupt(struct pt_regs * regs)
                }
 
 #ifdef CONFIG_SMP
-               /*
-                * update_process_times() expects us to have done irq_enter().
-                * Besides, if we don't timer interrupts ignore the global
-                * interrupt lock, which is the WrongThing (tm) to do.
-                */
-               irq_enter(cpu, 0);
                update_process_times(user);
-               irq_exit(cpu, 0);
 #endif
        }
 
@@ -706,17+699,26 @@ unsigned int apic_timer_irqs [NR_CPUS] = { 0, };
 
 void smp_apic_timer_interrupt(struct pt_regs * regs)
 {
+       int cpu = smp_processor_id();
+
        /*
         * the NMI deadlock-detector uses this.
         */
-       apic_timer_irqs[smp_processor_id()]++;
+       apic_timer_irqs[cpu]++;
 
        /*
         * NOTE! We'd better ACK the irq immediately,
         * because timer handling can be slow.
         */
        ack_APIC_irq();
+       /*
+        * update_process_times() expects us to have done irq_enter().
+        * Besides, if we don't timer interrupts ignore the global
+        * interrupt lock, which is the WrongThing (tm) to do.
+        */
+       irq_enter(cpu, 0);
        smp_local_timer_interrupt(regs);
+       irq_exit(cpu, 0);
 }
 
 /*
index e9c8377..104ae9e 100644 (file)
@@ -546,7+546,7 @@ unsigned char mca_read_pos(int slot, int reg)
                outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
 
                byte = inb_p(MCA_POS_REG(reg));
-               outp_b(0xff, MCA_MOTHERBOARD_SETUP_REG);
+               outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
        } else if(slot < MCA_MAX_SLOT_NR) {
 
                /* Make sure motherboard setup is off */
index cbbe206..b2088bc 100644 (file)
@@ -158,11+158,9 @@ CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
-# CONFIG_INET_ECN is not set
+CONFIG_INET_ECN=y
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
 # CONFIG_IPV6_EUI64 is not set
@@ -345,6+343,7 @@ CONFIG_IEEE1394_RAWIO=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
+CONFIG_TUN=m
 CONFIG_PPP=m
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
@@ -453,8+452,7 @@ CONFIG_NFSD_V3=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_REMOTE=""
+# CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
 # CONFIG_NCPFS_IOCTL_LOCKING is not set
index 6fa72fc..a8c2931 100644 (file)
@@ -246,7+246,8 @@ static ssize_t nvram_read(struct file * file,
 
        spin_unlock_irq (&rtc_lock);
 
-       copy_to_user_ret (buf, contents, tmp - contents, -EFAULT);
+       if (copy_to_user (buf, contents, tmp - contents))
+               return -EFAULT;
 
        *ppos = i;
 
@@ -264,10+265,9 @@ static ssize_t nvram_write(struct file * file,
        unsigned i = *ppos;
        char * tmp;
 
-       /* could comebody please help me indent this better? */
-       copy_from_user_ret (contents, buf, (NVRAM_BYTES - i) < count ?
-                                               (NVRAM_BYTES - i) : count,
-                               -EFAULT);
+       if (copy_from_user (contents, buf, (NVRAM_BYTES - i) < count ?
+                                               (NVRAM_BYTES - i) : count))
+               return -EFAULT;
 
        spin_lock_irq (&rtc_lock);
 
index 34e13c9..d9276b7 100644 (file)
@@ -62,6+62,7 @@ static void kbd_write_command_w(int data);
 static void kbd_write_output_w(int data);
 #ifdef CONFIG_PSMOUSE
 static void aux_write_ack(int val);
+static void __aux_write_ack(int val);
 #endif
 
 spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
@@ -404,7+405,7 @@ static inline void handle_mouse_event(unsigned char scancode)
        }
        else if(scancode == AUX_RECONNECT){
                queue->head = queue->tail = 0;  /* Flush input queue */
-               aux_write_ack(AUX_ENABLE_DEV);  /* ping the mouse :) */
+               __aux_write_ack(AUX_ENABLE_DEV);  /* ping the mouse :) */
                return;
        }
 
@@ -822,11+823,8 @@ static void aux_write_dev(int val)
 /*
  * Send a byte to the mouse & handle returned ack
  */
-static void aux_write_ack(int val)
+static void __aux_write_ack(int val)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&kbd_controller_lock, flags);
        kb_wait();
        kbd_write_command(KBD_CCMD_WRITE_MOUSE);
        kb_wait();
@@ -834,6+832,14 @@ static void aux_write_ack(int val)
        /* we expect an ACK in response. */
        mouse_reply_expected++;
        kb_wait();
+}
+
+static void aux_write_ack(int val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&kbd_controller_lock, flags);
+       __aux_write_ack(val);
        spin_unlock_irqrestore(&kbd_controller_lock, flags);
 }
 
index 1dcc8ac..6339d1e 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: esp.c,v 1.94 2000/03/30 02:09:10 davem Exp $
+/* $Id: esp.c,v 1.95 2000/08/23 22:32:37 davem Exp $
  * esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
  *
  * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#include <asm/machines.h>
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+
+#ifndef __sparc_v9__
+#include <asm/machines.h>
 #include <asm/idprom.h>
+#endif
 
 #include <linux/module.h>
 
@@ -1634,6+1637,7 @@ do_sync_known:
                 */
                int cdrom_hwbug_wkaround = 0;
 
+#ifndef __sparc_v9__
                /* Never allow disconnects or synchronous transfers on
                 * SparcStation1 and SparcStation1+.  Allowing those
                 * to be enabled seems to lockup the machine completely.
@@ -1654,6+1658,7 @@ do_sync_known:
                        esp->snip = 0;
                        goto do_sync_known;
                }
+#endif /* !(__sparc_v9__) */
 
                /* We've talked to this guy before,
                 * but never negotiated.  Let's try,
index d61c832..b510231 100644 (file)
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#include <asm/machines.h>
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
index aa2890f..8a85d4c 100644 (file)
@@ -456,7+456,11 @@ static int soundcore_open(struct inode *, struct file *);
 
 static struct file_operations soundcore_fops=
 {
-       owner:  THIS_MODULE,
+/*     owner:  THIS_MODULE,  * this is a bug: if we have an owner, the kernel 
+                               generates a MOD_INC_USE_COUNT - thus
+                               the module cannot be unloaded since the device
+                               is never released here ! - solution: owner
+                               has to be NULL. Patch by Peter Wahl <Peter.Wahl@epost.de> */
        open:   soundcore_open,
 };
 
index 7112ae6..d011f20 100644 (file)
@@ -79,7+79,7 @@ endif
 
 ifeq ($(CONFIG_USB_STORAGE),y)
        SUB_DIRS += storage
-       obj-y += storage/usb-storage.o
+       obj-y += storage/storage.o
 else
        ifeq ($(CONFIG_USB_STORAGE),m)
                MOD_IN_SUB_DIRS += storage
dissimilarity index 90%
index e776186..e09a8ca 100644 (file)
-#
-# Makefile for the USB Mass Storage device drivers.
-#
-
-O_TARGET       := usb-storage.o
-M_OBJS         := usb-storage.o
-O_OBJS         := scsiglue.o protocol.o transport.o usb.o 
-MOD_LIST_NAME  := USB_STORAGE_MODULES
-
-CFLAGS_scsiglue.o:= -I../../scsi/
-CFLAGS_protocol.o:= -I../../scsi/
-CFLAGS_transport.o:= -I../../scsi/
-CFLAGS_debug.o:= -I../../scsi/
-CFLAGS_usb.o:= -I../../scsi/
-CFLAGS_shuttle_usbat.o:= -I../../scsi/
-CFLAGS_sddr09.o:= -I../../scsi/
-CFLAGS_dpcm.o:= -I../../scsi/
-
-ifeq ($(CONFIG_USB_STORAGE_DEBUG),y)
-       O_OBJS += debug.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_HP8200e),y)
-       O_OBJS += shuttle_usbat.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_SDDR09),y)
-       O_OBJS += sddr09.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_FREECOM),y)
-       O_OBJS += freecom.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA),y)
-       O_OBJS += shuttle_sm.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH),y)
-       O_OBJS += shuttle_cf.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_DPCM),y)
-       O_OBJS += dpcm.o
-endif
-include $(TOPDIR)/Rules.make
+#
+# Makefile for the USB Mass Storage device drivers.
+#
+# 15 Aug 2000, Christoph Hellwig <hch@caldera.de>
+# Rewritten to use lists instead of if-statements.
+#
+
+O_TARGET       := storage.o
+EXTRA_CFLAGS   := -I../../scsi/
+
+list-multi     := usb-storage.o
+
+obj-$(CONFIG_USB_STORAGE)                      += usb-storage.o
+
+usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG)    += debug.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e)  += shuttle_usbat.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09)   += sddr09.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM)  += freecom.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA)   += shuttle_sm.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH) += shuttle_cf.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM)     += dpcm.o
+
+usb-storage-objs :=    scsiglue.o protocol.o transport.o usb.o \
+                       $(usb-storage-obj-y)
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+multi-y                := $(filter $(list-multi), $(obj-y))
+multi-m                := $(filter $(list-multi), $(obj-m))
+int-y          := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m          := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Take multi-part drivers out of obj-y and put components in.
+obj-y          := $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+O_OBJS         := $(obj-y)
+M_OBJS         := $(obj-m)
+MI_OBJS                := $(int-m)
+
+include $(TOPDIR)/Rules.make
+
+usb-storage.o: $(usb-storage-objs)
+       $(LD) -r -o $@ $(usb-storage-objs)
index 2a5127b..9f4693b 100644 (file)
@@ -1,9+1,9 @@
 /* Driver for USB Mass Storage compliant devices
  * Debugging Functions Source Code File
  *
- * $Id: debug.c,v 1.2 2000/07/19 17:21:39 groovyjava Exp $
+ * $Id: debug.c,v 1.3 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Initial work by:
index 04a08be..f03c533 100644 (file)
@@ -1,9+1,9 @@
 /* Driver for USB Mass Storage compliant devices
  * Debugging Functions Header File
  *
- * $Id: debug.h,v 1.3 2000/07/19 19:34:48 groovyjava Exp $
+ * $Id: debug.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Initial work by:
index 8b7195b..33cb674 100644 (file)
 /* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
  *
- * $Id: dpcm.c,v 1.1 2000/08/08 01:26:12 webbb Exp $
+ * $Id: dpcm.c,v 1.3 2000/08/25 00:13:51 mdharm Exp $
  *
  * DPCM driver v0.1:
  *
  * First release
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 2000 Brian Webb (webbb@earthlink.net)
  *
  * This device contains both a CompactFlash card reader, which
 #include "dpcm.h"
 #include "sddr09.h"
 
-
 /*
  * Transport for the Microtech DPCM-USB
  *
index d6e5f86..e6e5637 100644 (file)
 /* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
  *
- * $Id: dpcm.h,v 1.1 2000/08/08 01:26:12 webbb Exp $
+ * $Id: dpcm.h,v 1.2 2000/08/25 00:13:51 mdharm Exp $
  *
  * DPCM driver v0.1:
  *
  * First release
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 2000 Brian Webb (webbb@earthlink.net)
  *
  * See dpcm.c for more explanation
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
new file mode 100644 (file)
index 0000000..6b0914c
--- /dev/null
@@ -0,0 +1,375 @@
+/* Driver for Freecom USB/IDE adaptor
+ *
+ * $Id: freecom.c,v 1.7 2000/08/25 00:13:51 mdharm Exp $
+ *
+ * Freecom v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (C) 2000 David Brown <usb-storage@davidb.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver was developed with information provided in FREECOM's USB
+ * Programmers Reference Guide.  For further information contact Freecom
+ * (http://www.freecom.de/)
+ */
+
+#include <linux/config.h>
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "freecom.h"
+
+static void pdump (void *, int);
+
+struct freecom_udata {
+        __u8    buffer[64];             /* Common command block. */
+};
+typedef struct freecom_udata *freecom_udata_t;
+
+/* All of the outgoing packets are 64 bytes long. */
+struct freecom_cb_wrap {
+        __u8    Type;                   /* Command type. */
+        __u8    Timeout;                /* Timeout in seconds. */
+        __u8    Atapi[12];              /* An ATAPI packet. */
+        __u8    Filler[50];             /* Padding Data. */
+};
+
+struct freecom_xfer_wrap {
+        __u8    Type;                   /* Command type. */
+        __u8    Timeout;                /* Timeout in seconds. */
+        __u32   Count;                  /* Number of bytes to transfer. */
+        __u8    Pad[58];
+};
+
+struct freecom_status {
+        __u8    Status;
+        __u8    Reason;
+        __u16   Count;
+        __u8    Pad[60];
+};
+
+/* These are the packet types.  The low bit indicates that this command
+ * should wait for an interrupt. */
+#define FCM_PACKET_ATAPI  0x21
+
+/* Receive data from the IDE interface.  The ATAPI packet has already
+ * waited, so the data should be immediately available. */
+#define FCM_PACKET_INPUT  0x90
+
+/* All packets (except for status) are 64 bytes long. */
+#define FCM_PACKET_LENGTH 64
+
+static int
+freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
+                int ipipe, int opipe, int count)
+{
+        freecom_udata_t extra = (freecom_udata_t) us->extra;
+        struct freecom_xfer_wrap *fxfr =
+                (struct freecom_xfer_wrap *) extra->buffer;
+        int result, partial;
+        int offset;
+        __u8 *buffer = extra->buffer;
+
+        fxfr->Type = FCM_PACKET_INPUT | 0x00;
+        fxfr->Timeout = 0;    /* Short timeout for debugging. */
+        fxfr->Count = cpu_to_le32 (count);
+        memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
+
+        printk (KERN_DEBUG "Read data Freecom! (c=%d)\n", count);
+
+        /* Issue the transfer command. */
+        result = usb_stor_bulk_msg (us, fxfr, opipe,
+                        FCM_PACKET_LENGTH, &partial);
+        if (result != 0) {
+                US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n",
+                                result, partial);
+
+               /* -ENOENT -- we canceled this transfer */
+               if (result == -ENOENT) {
+                       US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+                       return US_BULK_TRANSFER_ABORTED;
+               }
+
+                return USB_STOR_TRANSPORT_ERROR;
+        }
+        printk (KERN_DEBUG "Done issuing read request: %d %d\n",
+                        result, partial);
+
+        /* Now transfer all of our blocks. */
+        if (srb->use_sg) {
+                US_DEBUGP ("Need to implement scatter-gather\n");
+                return USB_STOR_TRANSPORT_ERROR;
+        } else {
+                offset = 0;
+
+                while (offset < count) {
+                        printk (KERN_DEBUG "Start of read\n");
+                        /* Use the given buffer directly, but only if there
+                         * is space for an entire packet. */
+
+                        if (offset + 64 <= srb->request_bufflen) {
+                                result = usb_stor_bulk_msg (
+                                                us, srb->request_buffer+offset,
+                                                ipipe, 64, &partial);
+                                printk (KERN_DEBUG "Read111 = %d, %d\n",
+                                                result, partial);
+                                pdump (srb->request_buffer+offset,
+                                                partial);
+                        } else {
+                                result = usb_stor_bulk_msg (
+                                                us, buffer,
+                                                ipipe, 64, &partial);
+                                printk (KERN_DEBUG "Read112 = %d, %d\n",
+                                                result, partial);
+                                memcpy (srb->request_buffer+offset,
+                                                buffer,
+                                                srb->request_bufflen - offset);
+                                pdump (srb->request_buffer+offset,
+                                               srb->request_bufflen - offset);
+                        }
+
+                        if (result != 0) {
+                                US_DEBUGP ("Freecom readblock r=%d, p=%d\n",
+                                                result, partial);
+
+                               /* -ENOENT -- we canceled this transfer */
+                               if (result == -ENOENT) {
+                                       US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+                                       return US_BULK_TRANSFER_ABORTED;
+                               }
+
+                                return USB_STOR_TRANSPORT_ERROR;
+                        }
+
+                        offset += 64;
+                }
+        }
+
+        printk (KERN_DEBUG "freecom_readdata done!\n");
+        return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Transport for the Freecom USB/IDE adaptor.
+ *
+ */
+int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+        struct freecom_cb_wrap *fcb;
+        struct freecom_status  *fst;
+        int ipipe, opipe;             /* We need both pipes. */
+        int result;
+        int partial;
+        int length;
+        freecom_udata_t extra;
+
+        /* Allocate a buffer for us.  The upper usb transport code will
+         * free this for us when cleaning up. */
+        if (us->extra == NULL) {
+                us->extra = kmalloc (sizeof (struct freecom_udata),
+                                GFP_KERNEL);
+                if (us->extra == NULL) {
+                        printk (KERN_WARNING USB_STORAGE "Out of memory\n");
+                        return USB_STOR_TRANSPORT_ERROR;
+                }
+        }
+
+        extra = (freecom_udata_t) us->extra;
+
+        fcb = (struct freecom_cb_wrap *) extra->buffer;
+        fst = (struct freecom_status *) extra->buffer;
+
+        printk (KERN_DEBUG "Freecom TRANSPORT STARTED\n");
+
+        /* Get handles for both transports. */
+        opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
+        ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);
+
+#if 0
+        /* Yuck, let's see if this helps us.  Artificially increase the
+         * length on this. */
+        if (srb->cmnd[0] == 0x03 && srb->cmnd[4] == 0x12)
+                srb->cmnd[4] = 0x0E;
+#endif
+
+        /* The ATAPI Command always goes out first. */
+        fcb->Type = FCM_PACKET_ATAPI;
+        fcb->Timeout = 0;
+        memcpy (fcb->Atapi, srb->cmnd, 12);
+        memset (fcb->Filler, 0, sizeof (fcb->Filler));
+
+        pdump (srb->cmnd, 12);
+
+        /* Send it out. */
+        result = usb_stor_bulk_msg (us, fcb, opipe,
+                        FCM_PACKET_LENGTH, &partial);
+
+        /* The Freecom device will only fail if there is something wrong in
+         * USB land.  It returns the status in its own registers, which
+         * come back in the bulk pipe. */
+        if (result != 0) {
+                US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
+                                result, partial);
+
+               /* -ENOENT -- we canceled this transfer */
+               if (result == -ENOENT) {
+                       US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+                       return US_BULK_TRANSFER_ABORTED;
+               }
+
+                return USB_STOR_TRANSPORT_ERROR;
+        }
+
+        /* There are times we can optimize out this status read, but it
+         * doesn't hurt us to always do it now. */
+        result = usb_stor_bulk_msg (us, fst, ipipe,
+                        FCM_PACKET_LENGTH, &partial);
+        printk (KERN_DEBUG "foo Status result %d %d\n", result, partial);
+       /* -ENOENT -- we canceled this transfer */
+       if (result == -ENOENT) {
+               US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+               return US_BULK_TRANSFER_ABORTED;
+       }
+
+        pdump ((void *) fst, partial);
+        if (partial != 4 || result != 0) {
+                return USB_STOR_TRANSPORT_ERROR;
+        }
+        if ((fst->Reason & 1) != 0) {
+                printk (KERN_DEBUG "operation failed\n");
+                return USB_STOR_TRANSPORT_FAILED;
+        }
+
+        /* The device might not have as much data available as we
+         * requested.  If you ask for more than the device has, this reads
+         * and such will hang. */
+        printk (KERN_DEBUG "Device indicates that it has %d bytes available\n",
+                        le16_to_cpu (fst->Count));
+
+        /* Find the length we desire to read.  It is the lesser of the SCSI
+         * layer's requested length, and the length the device claims to
+         * have available. */
+        length = us_transfer_length (srb);
+        printk (KERN_DEBUG "SCSI requested %d\n", length);
+        if (length > le16_to_cpu (fst->Count))
+                length = le16_to_cpu (fst->Count);
+
+        /* What we do now depends on what direction the data is supposed to
+         * move in. */
+
+        switch (us->srb->sc_data_direction) {
+        case SCSI_DATA_READ:
+                result = freecom_readdata (srb, us, ipipe, opipe, length);
+                if (result != USB_STOR_TRANSPORT_GOOD)
+                        return result;
+                break;
+
+        default:
+                US_DEBUGP ("freecom unimplemented direction: %d\n",
+                                us->srb->sc_data_direction);
+                // Return fail, SCSI seems to handle this better.
+                return USB_STOR_TRANSPORT_FAILED;
+                break;
+        }
+
+#if 0
+        /* After the transfer, we can read our status register. */
+        printk (KERN_DEBUG "Going to read status register\n");
+        result = usb_stor_bulk_msg (us, &fst, ipipe,
+                        FCM_PACKET_LENGTH, &partial);
+        printk (KERN_DEBUG "Result from read %d %d\n", result, partial);
+        if (result != 0) {
+                return USB_STOR_TRANSPORT_ERROR;
+        }
+        if ((fst.Reason & 1) != 0) {
+                return USB_STOR_TRANSPORT_FAILED;
+        }
+#endif
+
+        return USB_STOR_TRANSPORT_GOOD;
+
+        printk (KERN_DEBUG "Freecom: transfer_length = %d\n",
+                        us_transfer_length (srb));
+
+        printk (KERN_DEBUG "Freecom: direction = %d\n",
+                        srb->sc_data_direction);
+
+        return USB_STOR_TRANSPORT_ERROR;
+}
+
+int usb_stor_freecom_reset(struct us_data *us)
+{
+        printk (KERN_DEBUG "freecom reset called\n");
+
+        /* We don't really have this feature. */
+        return USB_STOR_TRANSPORT_ERROR;
+}
+
+static void pdump (void *ibuffer, int length)
+{
+       static char line[80];
+       int offset = 0;
+       unsigned char *buffer = (unsigned char *) ibuffer;
+       int i, j;
+       int from, base;
+       
+       offset = 0;
+       for (i = 0; i < length; i++) {
+               if ((i & 15) == 0) {
+                       if (i > 0) {
+                               offset += sprintf (line+offset, " - ");
+                               for (j = i - 16; j < i; j++) {
+                                       if (buffer[j] >= 32 && buffer[j] <= 126)
+                                               line[offset++] = buffer[j];
+                                       else
+                                               line[offset++] = '.';
+                               }
+                               line[offset] = 0;
+                               printk (KERN_DEBUG "%s\n", line);
+                               offset = 0;
+                       }
+                       offset += sprintf (line+offset, "%08x:", i);
+               }
+               else if ((i & 7) == 0) {
+                       offset += sprintf (line+offset, " -");
+               }
+               offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
+       }
+       
+       /* Add the last "chunk" of data. */
+       from = (length - 1) % 16;
+       base = ((length - 1) / 16) * 16;
+       
+       for (i = from + 1; i < 16; i++)
+               offset += sprintf (line+offset, "   ");
+       if (from < 8)
+               offset += sprintf (line+offset, "  ");
+       offset += sprintf (line+offset, " - ");
+       
+       for (i = 0; i <= from; i++) {
+               if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
+                       line[offset++] = buffer[base+i];
+               else
+                       line[offset++] = '.';
+       }
+       line[offset] = 0;
+       printk (KERN_DEBUG "%s\n", line);
+       offset = 0;
+}
+
similarity index 64%
copy from drivers/usb/storage/dpcm.h
copy to drivers/usb/storage/freecom.h
index d6e5f86..98ac919 100644 (file)
-/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
+/* Driver for Freecom USB/IDE adaptor
  *
- * $Id: dpcm.h,v 1.1 2000/08/08 01:26:12 webbb Exp $
+ * $Id: freecom.h,v 1.3 2000/08/25 00:13:51 mdharm Exp $
  *
- * DPCM driver v0.1:
+ * Freecom v0.1:
  *
  * First release
  *
- * Current development and maintainance by:
- *   (c) 2000 Brian Webb (webbb@earthlink.net)
+ * Current development and maintenance by:
+ *   (c) 2000 David Brown <usb-storage@davidb.org>
  *
- * See dpcm.c for more explanation
+ * See freecom.c for more explanation
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifndef _MICROTECH_DPCM_USB_H
-#define _MICROTECH_DPCM_USB_H
+#ifndef _FREECOM_USB_H
+#define _FREECOM_USB_H
 
-extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us);
+extern int freecom_transport(Scsi_Cmnd *srb, struct us_data *us);
+extern int usb_stor_freecom_reset(struct us_data *us);
 
 #endif
index aee6b42..2aa83ea 100644 (file)
@@ -1,8+1,8 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: protocol.c,v 1.4 2000/08/01 22:01:19 mdharm Exp $
+ * $Id: protocol.c,v 1.5 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
index 239d379..a9306e6 100644 (file)
@@ -1,9+1,9 @@
 /* Driver for USB Mass Storage compliant devices
  * Protocol Functions Header File
  *
- * $Id: protocol.h,v 1.2 2000/08/01 22:01:19 mdharm Exp $
+ * $Id: protocol.h,v 1.3 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * This driver is based on the 'USB Mass Storage Class' document. This
index c823aae..9d4f983 100644 (file)
@@ -1,9+1,9 @@
 /* Driver for USB Mass Storage compliant devices
  * SCSI layer glue code
  *
- * $Id: scsiglue.c,v 1.8 2000/08/11 23:15:05 mdharm Exp $
+ * $Id: scsiglue.c,v 1.9 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
index f817876..13b9f3b 100644 (file)
@@ -1,9+1,9 @@
 /* Driver for USB Mass Storage compliant devices
  * SCSI Connecting Glue Header File
  *
- * $Id: scsiglue.h,v 1.3 2000/07/25 23:04:47 mdharm Exp $
+ * $Id: scsiglue.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * This driver is based on the 'USB Mass Storage Class' document. This
index 6bf9f14..5641a75 100644 (file)
 /* Driver for SanDisk SDDR-09 SmartMedia reader
  *
+ * $Id: sddr09.c,v 1.10 2000/08/25 00:13:51 mdharm Exp $
+ *
  * SDDR09 driver v0.1:
  *
  * First release
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 2000 Robert Baruch (autophile@dol.net)
  *
  * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
@@ -316,9+318,9 @@ int sddr09_read_data(struct us_data *us,
 
        // Figure out the initial LBA and page
 
-       pba = (address/info->pagesize)>>4;
+       pba = address >> (info->pageshift + info->blockshift);
        lba = info->pba_to_lba[pba];
-       page = (address/info->pagesize)&0x0F;
+       page = (address >> info->pageshift) & info->blockmask;
 
        // This could be made much more efficient by checking for
        // contiguous LBA's. Another exercise left to the student.
@@ -329,15+331,16 @@ int sddr09_read_data(struct us_data *us,
 
                // Read as many sectors as possible in this block
 
-               pages = 0x10-page;
+               pages = info->blocksize - page;
                if (pages > sectors)
                        pages = sectors;
 
-               US_DEBUGP("Read %01X pages, from PBA %04X"
-                       " (LBA %04X) page %01X\n",
+               US_DEBUGP("Read %02X pages, from PBA %04X"
+                       " (LBA %04X) page %02X\n",
                        pages, pba, lba, page);
 
-               address = ((pba<<4)+page)*info->pagesize;
+               address = ( (pba << info->blockshift) + page ) << 
+                       info->pageshift;
 
                // Unlike in the documentation, the address is in
                // words of 2 bytes.
@@ -370,7+373,7 @@ int sddr09_read_data(struct us_data *us,
 
                result = sddr09_bulk_transport(us,
                        SCSI_DATA_READ, ptr,
-                       pages*info->pagesize, 0);
+                       pages<<info->pageshift, 0);
 
                if (result != USB_STOR_TRANSPORT_GOOD) {
                        if (use_sg)
@@ -381,7+384,7 @@ int sddr09_read_data(struct us_data *us,
                page = 0;
                lba++;
                sectors -= pages;
-               ptr += pages*info->pagesize;
+               ptr += (pages << info->pageshift);
        }
 
        if (use_sg) {
@@ -435,7+438,7 @@ int sddr09_read_control(struct us_data *us,
 
        result = sddr09_bulk_transport(us,
                SCSI_DATA_READ, content,
-               blocks*0x40, use_sg);
+               blocks<<6, use_sg); // 0x40 bytes per block
 
        US_DEBUGP("Result for bulk read in read_control %d\n",
                result);
@@ -525,7+528,7 @@ int sddr09_reset(struct us_data *us) {
 }
 
 unsigned long sddr09_get_capacity(struct us_data *us,
-               unsigned int *pagesize) {
+               unsigned int *pagesize, unsigned int *blocksize) {
 
        unsigned char manufacturerID;
        unsigned char deviceID;
@@ -547,6+550,7 @@ unsigned long sddr09_get_capacity(struct us_data *us,
        US_DEBUGP("Manuf  ID = %02X\n", manufacturerID);
 
        *pagesize = 512;
+       *blocksize = 16;
 
        switch (deviceID) {
 
@@ -556,8+560,8 @@ unsigned long sddr09_get_capacity(struct us_data *us,
                *pagesize = 256;
                return 0x00100000;
 
-       case 0x5d: // 2MB
-       case 0xea: 
+       case 0xea: // 2MB
+       case 0x5d: // 5d is a ROM card with pagesize 512.
        case 0x64:
                if (deviceID!=0x5D)
                        *pagesize = 256;
@@ -574,9+578,11 @@ unsigned long sddr09_get_capacity(struct us_data *us,
                return 0x00800000;
 
        case 0x73: // 16MB
+               *blocksize = 32;
                return 0x01000000;
 
        case 0x75: // 32MB
+               *blocksize = 32;
                return 0x02000000;
 
        default: // unknown
@@ -587,7+593,7 @@ unsigned long sddr09_get_capacity(struct us_data *us,
 
 int sddr09_read_map(struct us_data *us) {
 
-       unsigned char *control;
+       struct scatterlist *sg;
        struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
        int numblocks;
        int i;
@@ -599,25+605,60 @@ int sddr09_read_map(struct us_data *us) {
                1, 0, 0, 1, 0, 1, 1, 0
        };
        int result;
+       int alloc_len;
+       int alloc_blocks;
 
        if (!info->capacity)
                return -1;
 
-       /* read 64 (2^6) bytes for every block (8192 (2^13) bytes)
-                of capacity:
-          64*(capacity/8192) = capacity*(2^6)*(2^-13) =
-          capacity*2^(6-13) = capacity*(2^-7)
-        */
-
-       control = kmalloc(info->capacity>>7, GFP_KERNEL);
+       // read 64 (1<<6) bytes for every block 
+       // ( 1 << ( blockshift + pageshift ) bytes)
+       //       of capacity:
+       // (1<<6)*capacity/(1<<(b+p)) =
+       // ((1<<6)*capacity)>>(b+p) =
+       // capacity>>(b+p-6)
+
+       alloc_len = info->capacity >> 
+               (info->blockshift + info->pageshift - 6);
+
+       // Allocate a number of scatterlist structures according to
+       // the number of 128k blocks in the alloc_len. Adding 128k-1
+       // and then dividing by 128k gives the correct number of blocks.
+       // 128k = 1<<17
+
+       alloc_blocks = (alloc_len + (1<<17) - 1) >> 17;
+       sg = kmalloc(alloc_blocks*sizeof(struct scatterlist),
+               GFP_KERNEL);
+       if (sg == NULL)
+               return 0;
 
+       for (i=0; i<alloc_blocks; i++) {
+               if (i<alloc_blocks-1) {
+                       sg[i].address = kmalloc( (1<<17), GFP_KERNEL );
+                       sg[i].length = (1<<17);
+               } else {
+                       sg[i].address = kmalloc(alloc_len, GFP_KERNEL);
+                       sg[i].length = alloc_len;
+               }
+               alloc_len -= sg[i].length;
+       }
+       for (i=0; i<alloc_blocks; i++)
+               if (sg[i].address == NULL) {
+                       for (i=0; i<alloc_blocks; i++)
+                               if (sg[i].address != NULL)
+                                       kfree(sg[i].address);
+                       kfree(sg);
+                       return 0;
+               }
 
-       numblocks = info->capacity>>13;
+       numblocks = info->capacity >> (info->blockshift + info->pageshift);
 
        if ( (result = sddr09_read_control(us, 0, numblocks,
-                       control, 0)) !=
+                       (unsigned char *)sg, alloc_blocks)) !=
                        USB_STOR_TRANSPORT_GOOD) {
-               kfree(control);
+               for (i=0; i<alloc_blocks; i++)
+                       kfree(sg[i].address);
+               kfree(sg);
                return -1;
        }
 
@@ -629,11+670,28 @@ int sddr09_read_map(struct us_data *us) {
                kfree(info->pba_to_lba);
        info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
        info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+
+       if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
+               if (info->lba_to_pba != NULL)
+                       kfree(info->lba_to_pba);
+               if (info->pba_to_lba != NULL)
+                       kfree(info->pba_to_lba);
+               info->lba_to_pba = NULL;
+               info->pba_to_lba = NULL;
+               for (i=0; i<alloc_blocks; i++)
+                       kfree(sg[i].address);
+               kfree(sg);
+               return 0;
+       }
+
        memset(info->lba_to_pba, 0, numblocks*sizeof(int));
        memset(info->pba_to_lba, 0, numblocks*sizeof(int));
 
+       // Each block is 64 bytes of control data, so block i is located in
+       // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
+
        for (i=0; i<numblocks; i++) {
-               ptr = control+64*i;
+               ptr = sg[i>>11].address+(i<<6);
                if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF ||
                    ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF)
                        continue;
@@ -655,20+713,30 @@ int sddr09_read_map(struct us_data *us) {
 
                lba = (lba&0x07FF)>>1;
 
+                       /* Every 1024 physical blocks, the LBA numbers
+                        * go back to zero, but are within a higher
+                        * block of LBA's. In other words, in blocks
+                        * 1024-2047 you will find LBA 0-1023 which are
+                        * really LBA 1024-2047.
+                        */
+
+               lba += (i&~0x3FF);
+
                if (lba>=numblocks) {
                        US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i);
                        continue;
                }
 
-               if (i<0x10)
-                       US_DEBUGP("LBA %04X <-> PBA %04X\n",
-                               lba, i);
+               if (lba<0x10)
+                       US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
 
                info->pba_to_lba[i] = lba;
                info->lba_to_pba[lba] = i;
        }
 
-       kfree(control);
+       for (i=0; i<alloc_blocks; i++)
+               kfree(sg[i].address);
+       kfree(sg);
        return 0;
 }
 
@@ -687,6+755,9 @@ static int init_sddr09(struct us_data *us) {
                0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0
        };
 
+       // What the hey is all this for? Doesn't seem to
+       // affect the device, so we won't do device inits.
+
        if ( (result = sddr09_send_control(us, command, data, 2)) !=
                        USB_STOR_TRANSPORT_GOOD)
                return result;
@@ -741,11+812,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
        int i;
        char string[64];
        unsigned char inquiry_response[36] = {
-               0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00,
-               'S', 'a', 'n', 'D', 'i', 's', 'k', ' ',
-               'I', 'm', 'a', 'g', 'e', 'M', 'a', 't',
-               'e', ' ', 'S', 'D', 'D', 'R', '0', '9',
-               ' ', ' ', ' ', ' '
+               0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
        };
        unsigned char mode_page_01[12] = {
                0x01, 0x0a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -758,17+825,11 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
        unsigned short pages;
        struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
 
-/*
-       if (us->flags & US_FL_NEED_INIT) {
-               US_DEBUGP("SDDR-09: initializing\n");
-               init_sddr09(us);
-               us->flags &= ~US_FL_NEED_INIT;
-       }
-*/
-
        if (!us->extra) {
                us->extra = kmalloc(
                        sizeof(struct sddr09_card_info), GFP_KERNEL);
+               if (!us->extra)
+                       return USB_STOR_TRANSPORT_ERROR;
                memset(us->extra, 0, sizeof(struct sddr09_card_info));
                us->extra_destructor = sddr09_card_info_destructor;
        }
@@ -779,14+840,29 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
           respond to INQUIRY commands */
 
        if (srb->cmnd[0] == INQUIRY) {
-               memcpy(ptr, inquiry_response, 36);
+               memset(inquiry_response+8, 0, 28);
+               fill_inquiry_response(us, inquiry_response, 36);
                return USB_STOR_TRANSPORT_GOOD;
        }
 
        if (srb->cmnd[0] == READ_CAPACITY) {
 
-               capacity = sddr09_get_capacity(us, &info->pagesize);
+               capacity = sddr09_get_capacity(us, &info->pagesize,
+                       &info->blocksize);
+
+               if (!capacity)
+                       return USB_STOR_TRANSPORT_FAILED;
+
                info->capacity = capacity;
+               for (info->pageshift=1; 
+                       (info->pagesize>>info->pageshift);
+                       info->pageshift++);
+               info->pageshift--;
+               for (info->blockshift=1; 
+                       (info->blocksize>>info->blockshift);
+                       info->blockshift++);
+               info->blockshift--;
+               info->blockmask = (1<<info->blockshift)-1;
 
                // Last page in the card
 
@@ -836,12+912,14 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
 
                // convert page to block and page-within-block
 
-               lba = page>>4;
-               page = page&0x0F;
+               lba = page >> info->blockshift;
+               page = page & info->blockmask;
 
                // locate physical block corresponding to logical block
 
-               if (lba>=(info->capacity>>13)) {
+               if (lba >=
+                       (info->capacity >> 
+                               (info->pageshift + info->blockshift) ) ) {
 
                        // FIXME: sense buffer?
 
@@ -866,8+944,8 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
                        pba, lba, page, pages);
 
                return sddr09_read_data(us,
-                       ((pba<<4)+page)*info->pagesize, pages,
-                       ptr, srb->use_sg);
+                       ( (pba << info->blockshift) + page) << info->pageshift,
+                       pages, ptr, srb->use_sg);
        }
 
        // Pass TEST_UNIT_READY and REQUEST_SENSE through
index ecd9b76..ac98446 100644 (file)
@@ -1,7+1,9 @@
 /* Driver for SanDisk SDDR-09 SmartMedia reader
  * Header File
  *
- * Current development and maintainance by:
+ * $Id: sddr09.h,v 1.5 2000/08/25 00:13:51 mdharm Exp $
+ *
+ * Current development and maintenance by:
  *   (c) 2000 Robert Baruch (autophile@dol.net)
  *
  * See sddr09.c for more explanation
 extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us);
 
 struct sddr09_card_info {
-       unsigned long           capacity; /* Size of card in bytes */
-       int                     pagesize;  /* Size of page in bytes */
-       int                     *lba_to_pba; /* logical to physical map */
-       int                     *pba_to_lba; /* physical to logical map */
+       unsigned long   capacity;       /* Size of card in bytes */
+       int             pagesize;       /* Size of page in bytes */
+       int             pageshift;      /* log2 of pagesize */
+       int             blocksize;      /* Size of block in pages */
+       int             blockshift;     /* log2 of blocksize */
+       int             blockmask;      /* 2^blockshift - 1 */
+       int             *lba_to_pba;    /* logical to physical map */
+       int             *pba_to_lba;    /* physical to logical map */
 };
 
 #endif
index 492bc72..6a96ad0 100644 (file)
@@ -1,6+1,6 @@
 /* Driver for SCM Microsystems USB-ATAPI cable
  *
- * $Id: shuttle_usbat.c,v 1.2 2000/08/03 00:03:39 groovyjava Exp $
+ * $Id: shuttle_usbat.c,v 1.4 2000/08/25 00:13:51 mdharm Exp $
  *
  * SCM driver v0.2:
  *
  *
  * First release - hp8200e.
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 2000 Robert Baruch (autophile@dol.net)
  *
  * Many originally ATAPI devices were slightly modified to meet the USB
@@ -734,7+734,7 @@ static int hp_8200e_select_and_test_registers(struct us_data *us) {
        return result;
 }
 
-static int init_8200e(struct us_data *us) {
+int init_8200e(struct us_data *us) {
 
        int result;
        unsigned char status;
@@ -895,11+895,11 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us)
          "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX"  /* C0-DF */
          "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
 
-       if (us->flags & US_FL_NEED_INIT) {
+/*     if (us->flags & US_FL_NEED_INIT) {
                US_DEBUGP("8200e: initializing\n");
                init_8200e(us);
                us->flags &= ~US_FL_NEED_INIT;
-       }
+       } */
 
        len = srb->request_bufflen;
 
index ff5c075..4bd2673 100644 (file)
@@ -1,9+1,9 @@
 /* Driver for SCM Microsystems USB-ATAPI cable
  * Header File
  *
- * $Id: shuttle_usbat.h,v 1.2 2000/08/03 00:03:39 groovyjava Exp $
+ * $Id: shuttle_usbat.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 2000 Robert Baruch (autophile@dol.net)
  *
  * See scm.c for more explanation
@@ -74,5+74,6 @@ extern int usbat_write_user_io(struct us_data *us,
 /* HP 8200e stuff */
 
 extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us);
+extern int init_8200e(struct us_data *us);
 
 #endif
index dd3c489..cad9253 100644 (file)
@@ -1,8+1,8 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: transport.c,v 1.12 2000/08/08 15:22:38 gowdy Exp $
+ * $Id: transport.c,v 1.18 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
 /* Calculate the length of the data transfer (not the command) for any
  * given SCSI command
  */
-static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us)
-{
-       int i;
-       unsigned int total = 0;
-       struct scatterlist *sg;
-
-       /* support those devices which need the length calculated
-        * differently 
-        */
-       if (srb->cmnd[0] == INQUIRY) {
-               srb->cmnd[4] = 36;
-       }
-
-       if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE))
-               return srb->cmnd[4];
-
-       if (srb->cmnd[0] == TEST_UNIT_READY)
-               return 0;
-
-       /* Are we going to scatter gather? */
-       if (srb->use_sg) {
-               /* Add up the sizes of all the scatter-gather segments */
-               sg = (struct scatterlist *) srb->request_buffer;
-               for (i = 0; i < srb->use_sg; i++)
-                       total += sg[i].length;
-
-               return total;
-       }
-       else
-               /* Just return the length of the buffer */
-               return srb->request_bufflen;
-}
-
-/* Calculate the length of the data transfer (not the command) for any
- * given SCSI command
- */
-static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us)
+static unsigned int us_transfer_length(Scsi_Cmnd *srb)
 {
        int i;
        int doDefault = 0;
@@ -245,10+209,6 @@ static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us)
           WRITE_SAME 41
        */
 
-       /* Not sure this is right as an INQUIRY can contain nonstandard info */
-       if (srb->cmnd[0] == INQUIRY)
-               srb->cmnd[4] = 36;
-          
        if (srb->sc_data_direction == SCSI_DATA_WRITE) {
                doDefault = 1;
        }
@@ -611,6+571,16 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
        int i;
        int result = -1;
        struct scatterlist *sg;
+       unsigned int total_transferred = 0;
+       unsigned int transfer_amount;
+
+       /* calculate how much we want to transfer */
+       transfer_amount = us_transfer_length(srb);
+
+       /* was someone foolish enough to request more data than available
+        * buffer space? */
+       if (transfer_amount > srb->request_bufflen)
+               transfer_amount = srb->request_bufflen;
 
        /* are we scatter-gathering? */
        if (srb->use_sg) {
@@ -620,8+590,19 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
                 */
                sg = (struct scatterlist *) srb->request_buffer;
                for (i = 0; i < srb->use_sg; i++) {
-                       result = us_transfer_partial(us, sg[i].address, 
-                                                    sg[i].length);
+
+                       /* transfer the lesser of the next buffer or the
+                        * remaining data */
+                       if (transfer_amount - total_transferred >= 
+                                       sg[i].length) {
+                               result = us_transfer_partial(us, sg[i].address, 
+                                               sg[i].length);
+                               total_transferred += sg[i].length;
+                       } else
+                               result = us_transfer_partial(us, sg[i].address,
+                                               transfer_amount - total_transferred);
+
+                       /* if we get an error, end the loop here */
                        if (result)
                                break;
                }
@@ -629,7+610,7 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
        else
                /* no scatter-gather, just make the request */
                result = us_transfer_partial(us, srb->request_buffer, 
-                                            srb->request_bufflen);
+                                            transfer_amount);
 
        /* return the result in the data structure itself */
        srb->result = result;
@@ -874,7+855,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
 
        /* DATA STAGE */
        /* transfer the data payload for this command, if one exists*/
-       if (us_transfer_length(srb, us)) {
+       if (us_transfer_length(srb)) {
                us_transfer(srb, us);
                US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
 
@@ -975,7+956,7 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
 
        /* DATA STAGE */
        /* transfer the data payload for this command, if one exists*/
-       if (us_transfer_length(srb, us)) {
+       if (us_transfer_length(srb)) {
                us_transfer(srb, us);
                US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
 
@@ -1039,10+1020,12 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
        
        /* set up the command wrapper */
        bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
-       bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us));
+       bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb));
        bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
        bcb.Tag = srb->serial_number;
        bcb.Lun = srb->cmnd[1] >> 5;
+       if (us->flags & US_FL_SCM_MULT_TARG)
+               bcb.Lun |= srb->target << 4;
        bcb.Length = srb->cmd_len;
        
        /* construct the pipe handle */
@@ -1053,8+1036,9 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
        memcpy(bcb.CDB, srb->cmnd, bcb.Length);
        
        /* send it to out endpoint */
-       US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
-                 le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun, 
+       US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
+                 le32_to_cpu(bcb.Signature), bcb.Tag,
+                 (bcb.Lun >> 4), (bcb.Lun & 0xFF), 
                  bcb.DataTransferLength, bcb.Flags, bcb.Length);
        result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, 
                                   &partial);
index 4615569..3f30005 100644 (file)
@@ -1,9+1,9 @@
 /* Driver for USB Mass Storage compliant devices
  * Transport Functions Header File
  *
- * $Id: transport.h,v 1.8 2000/08/08 01:23:55 webbb Exp $
+ * $Id: transport.h,v 1.11 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * This driver is based on the 'USB Mass Storage Class' document. This
 #ifndef _TRANSPORT_H_
 #define _TRANSPORT_H_
 
-#include <linux/config.h>
 #include <linux/blk.h>
+#include <linux/config.h>
 #include "usb.h"
 #include "scsi.h"
 
 #endif
 #define US_PR_DPCM_USB  0xf0           /* Combination CB/SDDR09 */
 
+#ifdef CONFIG_USB_STORAGE_FREECOM
+#define US_PR_FREECOM   0xf1            /* Freecom */
+#endif
+
 /*
  * Bulk only data structures
  */
index 50ebddd..07f0598 100644 (file)
@@ -1,8+1,8 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: usb.c,v 1.23 2000/08/08 20:46:45 mdharm Exp $
+ * $Id: usb.c,v 1.33 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/config.h>
 #include "usb.h"
 #include "scsiglue.h"
 #include "transport.h"
 #ifdef CONFIG_USB_STORAGE_DPCM
 #include "dpcm.h"
 #endif
+#ifdef CONFIG_USB_STORAGE_FREECOM
+#include "freecom.h"
+#endif
 
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
+#include <linux/config.h>
 
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -213,8+216,20 @@ static int usb_stor_control_thread(void * __us)
                        /* reject if target != 0 or if LUN is higher than
                         * the maximum known LUN
                         */
-                       if (us->srb->target || (us->srb->lun > us->max_lun)) {
-                               US_DEBUGP("Bad device number (%d/%d)\n",
+                       if (us->srb->target && 
+                                       !(us->flags & US_FL_SCM_MULT_TARG)) {
+                               US_DEBUGP("Bad target number (%d/%d)\n",
+                                         us->srb->target, us->srb->lun);
+                               us->srb->result = DID_BAD_TARGET << 16;
+
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               us->srb->scsi_done(us->srb);
+                               us->srb = NULL;
+                               break;
+                       }
+
+                       if (us->srb->lun > us->max_lun) {
+                               US_DEBUGP("Bad LUN (%d/%d)\n",
                                          us->srb->target, us->srb->lun);
                                us->srb->result = DID_BAD_TARGET << 16;
 
@@ -314,6+329,19 @@ static int usb_stor_control_thread(void * __us)
  * are free to use as many characters as you like.
  */
 
+int euscsi_init(struct us_data *us)
+{
+       unsigned char bar = 0x1;
+       int result;
+
+       US_DEBUGP("Attempting to init eUSCSI bridge...\n");
+       result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+                       0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
+                       0x01, 0x0, &bar, 0x1, 5*HZ);
+       US_DEBUGP("-- result is %d\n", result);
+       US_DEBUGP("-- bar afterwards is %d\n", bar);
+}
+
 static struct us_unusual_dev us_unusual_dev_list[] = {
 
        { 0x03f0, 0x0107, 0x0200, 0x0200, 
@@ -339,15+367,61 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
        { 0x04e6, 0x0002, 0x0100, 0x0100, 
                "Shuttle",
                "eUSCSI Bridge",
-               US_SC_SCSI, US_PR_BULK, NULL, 
-               0 }, 
+               US_SC_SCSI, US_PR_BULK, euscsi_init, 
+               US_FL_SCM_MULT_TARG }, 
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+       { 0x04e6, 0x0003, 0x0000, 0x9999, 
+               "Sandisk",
+               "ImageMate SDDR09",
+               US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+               US_FL_SINGLE_LUN | US_FL_START_STOP },
+#endif
+
+#ifdef CONFIG_USB_STORAGE_DPCM
+       { 0x0436, 0x0005, 0x0100, 0x0100,
+               "Microtech",
+               "CameraMate (DPCM_USB)",
+               US_SC_SCSI, US_PR_DPCM_USB, NULL,
+               US_FL_START_STOP },
+#endif
 
-       { 0x04e6, 0x0006, 0x0100, 0x0100, 
+       { 0x04e6, 0x0006, 0x0100, 0x0200, 
                "Shuttle",
                "eUSB MMC Adapter",
                US_SC_SCSI, US_PR_CB, NULL, 
                US_FL_SINGLE_LUN}, 
 
+       { 0x04e6, 0x0009, 0x0200, 0x0200, 
+               "Shuttle",
+               "ATA/ATAPI Bridge",
+               US_SC_8020, US_PR_CB, NULL, 
+               US_FL_SINGLE_LUN},
+
+       { 0x04e6, 0x000A, 0x0200, 0x0200, 
+               "Shuttle",
+               "Compact Flash Reader",
+               US_SC_8020, US_PR_CB, NULL, 
+               US_FL_SINGLE_LUN},
+
+       { 0x04e6, 0x000B, 0x0100, 0x0100, 
+               "Shuttle",
+               "eUSCSI Bridge",
+               US_SC_SCSI, US_PR_BULK, euscsi_init, 
+               US_FL_SCM_MULT_TARG }, 
+
+       { 0x04e6, 0x000C, 0x0100, 0x0100, 
+               "Shuttle",
+               "eUSCSI Bridge",
+               US_SC_SCSI, US_PR_BULK, euscsi_init, 
+               US_FL_SCM_MULT_TARG }, 
+
+       { 0x04e6, 0x0101, 0x0200, 0x0200, 
+               "Shuttle",
+               "CD-RW Device",
+               US_SC_8020, US_PR_CB, NULL, 
+               US_FL_SINGLE_LUN},
+
        { 0x054c, 0x0010, 0x0210, 0x0210, 
                "Sony",
                "DSC-S30/S70", 
@@ -372,6+446,24 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
                US_SC_UFI,  US_PR_CBI, NULL,
                US_FL_SINGLE_LUN},
 
+       { 0x059f, 0xa601, 0x0200, 0x0200, 
+               "LaCie",
+               "USB Hard Disk",
+               US_SC_RBC, US_PR_CB, NULL,
+               0 }, 
+
+       { 0x05ab, 0x0031, 0x0100, 0x0100, 
+               "In-System",
+               "USB/IDE Bridge",
+               US_SC_8070, US_PR_BULK, NULL,
+               0 }, 
+
+       { 0x0693, 0x0005, 0x0100, 0x0100,
+               "Hagiwara",
+               "Flashgate",
+               US_SC_SCSI, US_PR_BULK, NULL,
+               0 }, 
+
        { 0x0693, 0x0002, 0x0100, 0x0100, 
                "Hagiwara",
                "FlashGate SmartMedia",
@@ -401,14+493,21 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
        { 0x07af, 0x0004, 0x0100, 0x0100, 
                "Microtech",
                "USB-SCSI-DB25",
-               US_SC_SCSI, US_PR_BULK, NULL,
-               0 }, 
+               US_SC_SCSI, US_PR_BULK, euscsi_init,
+               US_FL_SCM_MULT_TARG }, 
+
+#ifdef CONFIG_USB_STORAGE_FREECOM
+        { 0x07ab, 0xfc01, 0x0921, 0x0921,
+                "Freecom",
+                "USB-IDE",
+                US_SC_8070, US_PR_FREECOM, NULL, US_FL_SINGLE_LUN },
+#endif
 
-       { 0x059f, 0xa601, 0x0200, 0x0200, 
-               "LaCie",
-               "USB Hard Disk",
-               US_SC_RBC, US_PR_CB, NULL,
-               0 }, 
+       { 0x07af, 0x0005, 0x0100, 0x0100, 
+               "Microtech",
+               "USB-SCSI-HD50",
+               US_SC_SCSI, US_PR_BULK, euscsi_init,
+               US_FL_SCM_MULT_TARG }, 
 
 #ifdef CONFIG_USB_STORAGE_DPCM
        { 0x07af, 0x0006, 0x0100, 0x0100,
@@ -417,25+516,6 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
                US_SC_SCSI, US_PR_DPCM_USB, NULL,
                US_FL_START_STOP },
 #endif
-
-       { 0x07af, 0x0005, 0x0100, 0x0100, 
-               "Microtech",
-               "USB-SCSI-HD50",
-               US_SC_SCSI, US_PR_BULK, NULL,
-               0 }, 
-
-       { 0x05ab, 0x0031, 0x0100, 0x0100, 
-               "In-System",
-               "USB/IDE Bridge",
-               US_SC_8070, US_PR_BULK, NULL,
-               0 }, 
-
-       { 0x0693, 0x0005, 0x0100, 0x0100,
-               "Hagiwara",
-               "Flashgate",
-               US_SC_SCSI, US_PR_BULK, NULL,
-               0 }, 
-
        { 0 }
 };
 
@@ -615,15+695,10 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
 
        /* set the interface -- STALL is an acceptable response here */
 #ifdef CONFIG_USB_STORAGE_SDDR09
-       if (protocol != US_PR_EUSB_SDDR09)
-               result = usb_set_interface(dev, 
-                       altsetting->bInterfaceNumber, 0);
-       else
+       if (protocol == US_PR_EUSB_SDDR09)
                result = usb_set_configuration(dev, 1);
-#else
-       result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
-#endif
-       US_DEBUGP("Result from usb_set_interface is %d\n", result);
+
+       US_DEBUGP("Result from usb_set_configuration is %d\n", result);
        if (result == -EPIPE) {
                US_DEBUGP("-- clearing stall on control interface\n");
                usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
@@ -632,6+707,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
                US_DEBUGP("-- Unknown error.  Rejecting device\n");
                return NULL;
        }
+#endif
 
        /* Do some basic sanity checks, and bail if we find a problem */
        if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
@@ -702,7+778,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
                 /* Re-Initialize the device if it needs it */
 
                if (unusual_dev && unusual_dev->initFunction)
-                       (*unusual_dev->initFunction)(ss);
+                       (unusual_dev->initFunction)(ss);
 
        } else { 
                /* New device -- allocate memory and initialize */
@@ -828,6+904,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
                        ss->max_lun = 1;
                        break;
 #endif
+
+#ifdef CONFIG_USB_STORAGE_FREECOM
+                case US_PR_FREECOM:
+                        ss->transport_name = "Freecom";
+                        ss->transport = freecom_transport;
+                        ss->transport_reset = usb_stor_freecom_reset;
+                        ss->max_lun = 0;
+                        break;
+#endif
                        
                default:
                        ss->transport_name = "Unknown";
@@ -909,7+994,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
                /* Just before we start our control thread, initialize
                 * the device if it needs initialization */
                if (unusual_dev && unusual_dev->initFunction)
-                       (*unusual_dev->initFunction)(ss);
+                       (unusual_dev->initFunction)(ss);
                
                /* start up our control thread */
                ss->pid = kernel_thread(usb_stor_control_thread, ss,
index 435ad97..38b0d42 100644 (file)
@@ -1,9+1,9 @@
 /* Driver for USB Mass Storage compliant devices
  * Main Header File
  *
- * $Id: usb.h,v 1.7 2000/08/15 00:06:38 mdharm Exp $
+ * $Id: usb.h,v 1.8 2000/08/25 00:13:51 mdharm Exp $
  *
- * Current development and maintainance by:
+ * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Initial work by:
index c0df3a6..f0c64b4 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -496,6+496,27 @@ static inline void flush_old_files(struct files_struct * files)
        write_unlock(&files->file_lock);
 }
 
+/*
+ * An execve() will automatically "de-thread" the process.
+ * Note: we don't have to hold the tasklist_lock to test
+ * whether we migth need to do this. If we're not part of
+ * a thread group, there is no way we can become one
+ * dynamically. And if we are, we only need to protect the
+ * unlink - even if we race with the last other thread exit,
+ * at worst the list_del_init() might end up being a no-op.
+ */
+static inline void de_thread(struct task_struct *tsk)
+{
+       if (!list_empty(&tsk->thread_group)) {
+               write_lock_irq(&tasklist_lock);
+               list_del_init(&tsk->thread_group);
+               write_unlock_irq(&tasklist_lock);
+       }
+
+       /* Minor oddity: this might stay the same. */
+       tsk->tgid = tsk->pid;
+}
+
 int flush_old_exec(struct linux_binprm * bprm)
 {
        char * name;
@@ -534,6+555,8 @@ int flush_old_exec(struct linux_binprm * bprm)
 
        flush_thread();
 
+       de_thread(current);
+
        if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
            permission(bprm->file->f_dentry->d_inode,MAY_READ))
                current->dumpable = 0;
index 24e6163..f1c9099 100644 (file)
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/highuid.h>
+#include <linux/vmalloc.h>
 
 #include <linux/ncp_fs.h>
 
 #define NCP_OBJECT_NAME_MAX_LEN        4096
 /* maximum limit for ncp_privatedata_ioctl */
 #define NCP_PRIVATE_DATA_MAX_LEN 8192
+/* maximum negotiable packet size */
+#define NCP_PACKET_SIZE_INTERNAL 65536
 
 int ncp_ioctl(struct inode *inode, struct file *filp,
              unsigned int cmd, unsigned long arg)
@@ -50,11+53,11 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                  NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) {
                        return -EINVAL;
                }
-               bouncebuffer = kmalloc(NCP_PACKET_SIZE, GFP_NFS);
+               bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL);
                if (!bouncebuffer)
                        return -ENOMEM;
                if (copy_from_user(bouncebuffer, request.data, request.size)) {
-                       kfree(bouncebuffer);
+                       vfree(bouncebuffer);
                        return -EFAULT;
                }
                ncp_lock_server(server);
@@ -67,7+70,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                memcpy(server->packet, bouncebuffer, request.size);
 
                result = ncp_request2(server, request.function, 
-                       bouncebuffer, NCP_PACKET_SIZE);
+                       bouncebuffer, NCP_PACKET_SIZE_INTERNAL);
                if (result < 0)
                        result = -EIO;
                else
@@ -78,7+81,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                if (result >= 0)
                        if (copy_to_user(request.data, bouncebuffer, result))
                                result = -EFAULT;
-               kfree(bouncebuffer);
+               vfree(bouncebuffer);
                return result;
 
        case NCP_IOC_CONN_LOGGED_IN:
index 7089519..b063860 100644 (file)
@@ -445,7+445,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
        memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
        strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
                SMB_NLS_MAXNAMELEN);
-       strncpy(mnt->codepage.local_name, CONFIG_SMB_NLS_REMOTE,
+       strncpy(mnt->codepage.remote_name, CONFIG_SMB_NLS_REMOTE,
                SMB_NLS_MAXNAMELEN);
 
        if (ver == SMB_MOUNT_OLDVERSION) {
index a8de0de..48515aa 100644 (file)
@@ -142,7+142,7 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di
        recsize = umsdos_evalrecsize(p->name_len);
        if (offs + recsize > PAGE_CACHE_SIZE) {
                struct page *page2;
-               int part = (page_address(page) + PAGE_CACHE_SIZE) - p->spare;
+               int part = (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare;
                page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT),
                                (filler_t*)mapping->a_ops->readpage, NULL);
                if (IS_ERR(page2)) {
@@ -261,7+261,7 @@ int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
                p->rdev = cpu_to_le16(entry->rdev);
                p->mode = cpu_to_le16(entry->mode);
                memcpy(p->name,entry->name,
-                       (page_address(page) + PAGE_CACHE_SIZE) - p->spare);
+                       (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare);
                memcpy(page_address(page2),
                                entry->spare+PAGE_CACHE_SIZE-offs,
                                offs+info->recsize-PAGE_CACHE_SIZE);
index a3b8973..89054f8 100644 (file)
@@ -62,7+62,6 @@ extern inline unsigned long _page_hashfn(struct address_space * mapping, unsigne
 #define s(x) ((x)+((x)>>PAGE_HASH_BITS))
        return s(i+index) & (PAGE_HASH_SIZE-1);
 #undef i
-#undef o
 #undef s
 }
 
index 46ae4c8..50ed518 100644 (file)
@@ -38,6+38,7 @@ extern unsigned long event;
 #define CLONE_PTRACE   0x00002000      /* set if we want to let tracing continue on the child too */
 #define CLONE_VFORK    0x00004000      /* set if the parent wants the child to wake it up on mm_release */
 #define CLONE_PARENT   0x00008000      /* set if we want to have the same parent as the cloner */
+#define CLONE_THREAD   0x00010000      /* set if we want to clone the "thread group" */
 
 /*
  * These are the constant used to fake the fixed-point load-average
@@ -311,6+312,7 @@ struct task_struct {
        pid_t pgrp;
        pid_t tty_old_pgrp;
        pid_t session;
+       pid_t tgid;
        /* boolean value for session group leader */
        int leader;
        /* 
@@ -319,6+321,7 @@ struct task_struct {
         * p->p_pptr->pid)
         */
        struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+       struct list_head thread_group;
 
        /* PID hash table linkage. */
        struct task_struct *pidhash_next;
@@ -435,6+438,7 @@ struct task_struct {
     prev_task:         &tsk,                                           \
     p_opptr:           &tsk,                                           \
     p_pptr:            &tsk,                                           \
+    thread_group:      LIST_HEAD_INIT(tsk.thread_group),               \
     wait_chldexit:     __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
     real_timer:                {                                               \
        function:               it_real_fn                              \
@@ -556,8+560,8 @@ extern int force_sig_info(int, struct siginfo *, struct task_struct *);
 extern int kill_pg_info(int, struct siginfo *, pid_t);
 extern int kill_sl_info(int, struct siginfo *, pid_t);
 extern int kill_proc_info(int, struct siginfo *, pid_t);
-extern int kill_something_info(int, struct siginfo *, int);
 extern void notify_parent(struct task_struct *, int);
+extern void do_notify_parent(struct task_struct *, int);
 extern void force_sig(int, struct task_struct *);
 extern int send_sig(int, struct task_struct *, int);
 extern int kill_pg(pid_t, int, int);
@@ -798,6+802,8 @@ do {                                                                        \
 #define for_each_task(p) \
        for (p = &init_task ; (p = p->next_task) != &init_task ; )
 
+#define next_thread(p) \
+       list_entry((p)->thread_group.next, struct task_struct, thread_group)
 
 static inline void del_from_runqueue(struct task_struct * p)
 {
@@ -818,6+824,7 @@ static inline void unhash_process(struct task_struct *p)
        nr_threads--;
        unhash_pid(p);
        REMOVE_LINKS(p);
+       list_del(&p->thread_group);
        write_unlock_irq(&tasklist_lock);
 }
 
index 222923a..a3687bf 100644 (file)
@@ -4,8+4,9 @@
 #define WNOHANG                0x00000001
 #define WUNTRACED      0x00000002
 
-#define __WALL         0x40000000
-#define __WCLONE       0x80000000
+#define __WNOTHREAD    0x20000000      /* Don't wait on children of other threads in this group */
+#define __WALL         0x40000000      /* Wait on all children, regardless of type */
+#define __WCLONE       0x80000000      /* Wait only on non-SIGCHLD children */
 
 #ifdef __KERNEL__
 
@@ -184,7+185,7 @@ extern inline void __add_wait_queue_tail(wait_queue_head_t *head,
        if (!head->task_list.next || !head->task_list.prev)
                WQ_BUG();
 #endif
-       list_add(&new->task_list, head->task_list.prev);
+       list_add_tail(&new->task_list, &head->task_list);
 }
 
 extern inline void __remove_wait_queue(wait_queue_head_t *head,
index ea7f310..580c021 100644 (file)
@@ -144,17+144,29 @@ static inline int has_stopped_jobs(int pgrp)
        return retval;
 }
 
+/*
+ * When we die, we re-parent all our children.
+ * Try to give them to another thread in our process
+ * group, and if no such member exists, give it to
+ * the global child reaper process (ie "init")
+ */
 static inline void forget_original_parent(struct task_struct * father)
 {
-       struct task_struct * p;
+       struct task_struct * p, *reaper;
 
        read_lock(&tasklist_lock);
+
+       /* Next in our thread group */
+       reaper = next_thread(father);
+       if (reaper == father)
+               reaper = child_reaper;
+
        for_each_task(p) {
                if (p->p_opptr == father) {
                        /* We dont want people slaying init */
                        p->exit_signal = SIGCHLD;
                        p->self_exec_id++;
-                       p->p_opptr = child_reaper; /* init */
+                       p->p_opptr = reaper;
                        if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
                }
        }
@@ -378,7+390,6 @@ static void exit_notify(void)
            && !capable(CAP_KILL))
                current->exit_signal = SIGCHLD;
 
-       notify_parent(current, current->exit_signal);
 
        /*
         * This loop does two things:
@@ -390,6+401,7 @@ static void exit_notify(void)
         */
 
        write_lock_irq(&tasklist_lock);
+       do_notify_parent(current, current->exit_signal);
        while (current->p_cptr != NULL) {
                p = current->p_cptr;
                current->p_cptr = p->p_osptr;
@@ -402,7+414,7 @@ static void exit_notify(void)
                        p->p_osptr->p_ysptr = p;
                p->p_pptr->p_cptr = p;
                if (p->state == TASK_ZOMBIE)
-                       notify_parent(p, p->exit_signal);
+                       do_notify_parent(p, p->exit_signal);
                /*
                 * process group orphan check
                 * Case ii: Our child is in a different pgrp
@@ -483,9+495,9 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc
 {
        int flag, retval;
        DECLARE_WAITQUEUE(wait, current);
-       struct task_struct *p;
+       struct task_struct *tsk;
 
-       if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL))
+       if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
                return -EINVAL;
 
        add_wait_queue(&current->wait_chldexit,&wait);
@@ -493,27+505,30 @@ repeat:
        flag = 0;
        current->state = TASK_INTERRUPTIBLE;
        read_lock(&tasklist_lock);
-       for (p = current->p_cptr ; p ; p = p->p_osptr) {
-               if (pid>0) {
-                       if (p->pid != pid)
-                               continue;
-               } else if (!pid) {
-                       if (p->pgrp != current->pgrp)
-                               continue;
-               } else if (pid != -1) {
-                       if (p->pgrp != -pid)
+       tsk = current;
+       do {
+               struct task_struct *p;
+               for (p = tsk->p_cptr ; p ; p = p->p_osptr) {
+                       if (pid>0) {
+                               if (p->pid != pid)
+                                       continue;
+                       } else if (!pid) {
+                               if (p->pgrp != current->pgrp)
+                                       continue;
+                       } else if (pid != -1) {
+                               if (p->pgrp != -pid)
+                                       continue;
+                       }
+                       /* Wait for all children (clone and not) if __WALL is set;
+                        * otherwise, wait for clone children *only* if __WCLONE is
+                        * set; otherwise, wait for non-clone children *only*.  (Note:
+                        * A "clone" child here is one that reports to its parent
+                        * using a signal other than SIGCHLD.) */
+                       if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+                           && !(options & __WALL))
                                continue;
-               }
-               /* Wait for all children (clone and not) if __WALL is set;
-                * otherwise, wait for clone children *only* if __WCLONE is
-                * set; otherwise, wait for non-clone children *only*.  (Note:
-                * A "clone" child here is one that reports to its parent
-                * using a signal other than SIGCHLD.) */
-               if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
-                   && !(options & __WALL))
-                       continue;
-               flag = 1;
-               switch (p->state) {
+                       flag = 1;
+                       switch (p->state) {
                        case TASK_STOPPED:
                                if (!p->exit_code)
                                        continue;
@@ -543,15+558,19 @@ repeat:
                                        REMOVE_LINKS(p);
                                        p->p_pptr = p->p_opptr;
                                        SET_LINKS(p);
+                                       do_notify_parent(p, SIGCHLD);
                                        write_unlock_irq(&tasklist_lock);
-                                       notify_parent(p, SIGCHLD);
                                } else
                                        release(p);
                                goto end_wait4;
                        default:
                                continue;
+                       }
                }
-       }
+               if (options & __WNOTHREAD)
+                       break;
+               tsk = next_thread(tsk);
+       } while (tsk != current);
        read_unlock(&tasklist_lock);
        if (flag) {
                retval = 0;
index 4ab0976..64dd0f9 100644 (file)
@@ -661,7+661,13 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
         * Let it rip!
         */
        retval = p->pid;
+       p->tgid = retval;
+       INIT_LIST_HEAD(&p->thread_group);
        write_lock_irq(&tasklist_lock);
+       if (clone_flags & CLONE_THREAD) {
+               p->tgid = current->tgid;
+               list_add(&p->thread_group, &current->thread_group);
+       }
        SET_LINKS(p);
        hash_pid(p);
        nr_threads++;
index fda8b5e..8b47b55 100644 (file)
@@ -455,17+455,35 @@ signed long schedule_timeout(signed long timeout)
 static inline void __schedule_tail(struct task_struct *prev)
 {
 #ifdef CONFIG_SMP
-       if ((prev->state == TASK_RUNNING) &&
-                       (prev != idle_task(smp_processor_id()))) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&runqueue_lock, flags);
-               prev->has_cpu = 0;
-               reschedule_idle(prev, flags); // spin_unlocks runqueue
-       } else {
-               wmb();
-               prev->has_cpu = 0;
-       }
+       unsigned long flags;
+
+       /*
+        * fast path falls through. We have to take the runqueue lock
+        * unconditionally to make sure that the test of prev->state
+        * and setting has_cpu is atomic wrt. interrupts. It's not
+        * a big problem in the common case because we recently took
+        * the runqueue lock so it's likely to be in this processor's
+        * cache.
+        */
+       spin_lock_irqsave(&runqueue_lock, flags);
+       prev->has_cpu = 0;
+       if (prev->state == TASK_RUNNING)
+               goto running_again;
+out_unlock:
+       spin_unlock_irqrestore(&runqueue_lock, flags);
+       return;
+
+       /*
+        * Slow path - we 'push' the previous process and
+        * reschedule_idle() will attempt to find a new
+        * processor for it. (but it might preempt the
+        * current process as well.)
+        */
+running_again:
+       if (prev == idle_task(smp_processor_id()))
+               goto out_unlock;
+       reschedule_idle(prev, flags); // spin_unlocks runqueue
+       return;
 #endif /* CONFIG_SMP */
 }
 
index 16bcdbe..77a9b8e 100644 (file)
@@ -179,7+179,7 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
                        if (!(current->notifier)(current->notifier_data)) {
                                current->sigpending = 0;
                                return 0;
-                       }
+                       }
                }
        }
 
@@ -287,6+287,18 @@ static int rm_sig_from_queue(int sig, struct task_struct *t)
 }
 
 /*
+ * Bad permissions for sending the signal
+ */
+int bad_signal(int sig, struct siginfo *info, struct task_struct *t)
+{
+       return (!info || ((unsigned long)info != 1 && SI_FROMUSER(info)))
+           && ((sig != SIGCONT) || (current->session != t->session))
+           && (current->euid ^ t->suid) && (current->euid ^ t->uid)
+           && (current->uid ^ t->suid) && (current->uid ^ t->uid)
+           && !capable(CAP_KILL);
+}
+
+/*
  * Determine whether a signal should be posted or not.
  *
  * Signals with SIG_IGN can be ignored, except for the
@@ -327,37+339,13 @@ static int ignored_signal(int sig, struct task_struct *t)
        return 1;
 }
 
-int
-send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
+/*
+ * Handle TASK_STOPPED.
+ * Also, return true for the unblockable signals that we
+ * should deliver to all threads..
+ */
+static void handle_stop_signal(int sig, struct task_struct *t)
 {
-       unsigned long flags;
-       int ret;
-       struct signal_queue *q = 0;
-
-
-#if DEBUG_SIG
-printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
-#endif
-
-       ret = -EINVAL;
-       if (sig < 0 || sig > _NSIG)
-               goto out_nolock;
-       /* The somewhat baroque permissions check... */
-       ret = -EPERM;
-       if ((!info || ((unsigned long)info != 1 && SI_FROMUSER(info)))
-           && ((sig != SIGCONT) || (current->session != t->session))
-           && (current->euid ^ t->suid) && (current->euid ^ t->uid)
-           && (current->uid ^ t->suid) && (current->uid ^ t->uid)
-           && !capable(CAP_KILL))
-               goto out_nolock;
-
-       /* The null signal is a permissions and process existance probe.
-          No signal is actually delivered.  Same goes for zombies. */
-       ret = 0;
-       if (!sig || !t->sig)
-               goto out_nolock;
-
-       spin_lock_irqsave(&t->sigmask_lock, flags);
        switch (sig) {
        case SIGKILL: case SIGCONT:
                /* Wake up the process if stopped.  */
@@ -376,19+364,12 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
                        recalc_sigpending(t);
                break;
        }
+       return 0;
+}
 
-       /* Optimize away the signal, if it's a signal that can be
-          handled immediately (ie non-blocked and untraced) and
-          that is ignored (either explicitly or by default).  */
-
-       if (ignored_signal(sig, t))
-               goto out;
-
-       /* Support queueing exactly one non-rt signal, so that we
-          can get more detailed information about the cause of
-          the signal. */
-       if (sig < SIGRTMIN && sigismember(&t->signal, sig))
-               goto out;
+static int deliver_signal(int sig, struct siginfo *info, struct task_struct *t)
+{
+       struct signal_queue * q = NULL;
 
        /* Real-time signals must be queued if sent by sigqueue, or
           some other real-time mechanism.  It is implementation
@@ -399,8+380,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
           pass on the info struct.  */
 
        if (atomic_read(&nr_queued_signals) < max_queued_signals) {
-               q = (struct signal_queue *)
-                       kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
+               q = kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
        }
 
        if (q) {
@@ -433,8+413,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
                 * Queue overflow, abort.  We may abort if the signal was rt
                 * and sent by user using something other than kill().
                 */
-               ret = -EAGAIN;
-               goto out;
+               return -EAGAIN;
        }
 
        sigaddset(&t->signal, sig);
@@ -459,12+438,118 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
                spin_unlock(&runqueue_lock);
 #endif /* CONFIG_SMP */
        }
+       return 0;
+}
+
+
+/*
+ * Send a thread-group-wide signal.
+ *
+ * Rule: SIGSTOP and SIGKILL get delivered to _everybody_.
+ *
+ * Others get delivered to the thread that doesn't have them
+ * blocked (just one such thread).
+ *
+ * If all threads have it blocked, it gets delievered to the
+ * thread group leader.
+ */
+static int send_tg_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+{
+       int retval = 0;
+       struct task_struct *tsk;
+
+       if (sig < 0 || sig > _NSIG)
+               return -EINVAL;
+
+       if (bad_signal(sig, info, p))
+               return -EPERM;
+
+       if (!sig)
+               return 0;
+
+       tsk = p;
+       do {
+               unsigned long flags;
+               tsk = next_thread(tsk);
+
+               /* Zombie? Ignore */
+               if (!tsk->sig)
+                       continue;
+
+               spin_lock_irqsave(&tsk->sigmask_lock, flags);
+               handle_stop_signal(sig, tsk);
+
+               /* Is the signal ignored by this thread? */
+               if (ignored_signal(sig, tsk))
+                       goto next;
+
+               /* Have we already delivered this non-queued signal? */
+               if (sig < SIGRTMIN && sigismember(&tsk->signal, sig))
+                       goto next;
+
+               /* Not blocked? Go, girl, go! */
+               if (tsk == p || !sigismember(&tsk->blocked, sig)) {
+                       retval = deliver_signal(sig, info, tsk);
+
+                       /* Signals other than SIGKILL and SIGSTOP have "once" semantics */
+                       if (sig != SIGKILL && sig != SIGSTOP)
+                               tsk = p;
+               }
+next:
+               spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
+               if ((tsk->state & TASK_INTERRUPTIBLE) && signal_pending(tsk))
+                       wake_up_process(tsk);
+       } while (tsk != p);
+       return retval;
+}
+
+
+int
+send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
+{
+       unsigned long flags;
+       int ret;
+
+
+#if DEBUG_SIG
+printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
+#endif
+
+       ret = -EINVAL;
+       if (sig < 0 || sig > _NSIG)
+               goto out_nolock;
+       /* The somewhat baroque permissions check... */
+       ret = -EPERM;
+       if (bad_signal(sig, info, t))
+               goto out_nolock;
+
+       /* The null signal is a permissions and process existance probe.
+          No signal is actually delivered.  Same goes for zombies. */
+       ret = 0;
+       if (!sig || !t->sig)
+               goto out_nolock;
+
+       spin_lock_irqsave(&t->sigmask_lock, flags);
+       handle_stop_signal(sig, t);
+
+       /* Optimize away the signal, if it's a signal that can be
+          handled immediately (ie non-blocked and untraced) and
+          that is ignored (either explicitly or by default).  */
+
+       if (ignored_signal(sig, t))
+               goto out;
+
+       /* Support queueing exactly one non-rt signal, so that we
+          can get more detailed information about the cause of
+          the signal. */
+       if (sig < SIGRTMIN && sigismember(&t->signal, sig))
+               goto out;
 
+       ret = deliver_signal(sig, info, t);
 out:
        spin_unlock_irqrestore(&t->sigmask_lock, flags);
-        if ((t->state & TASK_INTERRUPTIBLE) && signal_pending(t))
-                wake_up_process(t);
-
+       if ((t->state & TASK_INTERRUPTIBLE) && signal_pending(t))
+               wake_up_process(t);
 out_nolock:
 #if DEBUG_SIG
 printk(" %d -> %d\n", signal_pending(t), ret);
@@ -509,22+594,17 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
        int retval = -EINVAL;
        if (pgrp > 0) {
                struct task_struct *p;
-               int found = 0;
 
                retval = -ESRCH;
                read_lock(&tasklist_lock);
                for_each_task(p) {
                        if (p->pgrp == pgrp) {
                                int err = send_sig_info(sig, info, p);
-                               if (err != 0)
+                               if (retval)
                                        retval = err;
-                               else
-                                       found++;
                        }
                }
                read_unlock(&tasklist_lock);
-               if (found)
-                       retval = 0;
        }
        return retval;
 }
@@ -541,22+621,17 @@ kill_sl_info(int sig, struct siginfo *info, pid_t sess)
        int retval = -EINVAL;
        if (sess > 0) {
                struct task_struct *p;
-               int found = 0;
 
                retval = -ESRCH;
                read_lock(&tasklist_lock);
                for_each_task(p) {
                        if (p->leader && p->session == sess) {
                                int err = send_sig_info(sig, info, p);
-                               if (err)
+                               if (retval)
                                        retval = err;
-                               else
-                                       found++;
                        }
                }
                read_unlock(&tasklist_lock);
-               if (found)
-                       retval = 0;
        }
        return retval;
 }
@@ -576,6+651,33 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
        return error;
 }
 
+
+/*
+ * Send a signal to a thread group..
+ *
+ * If the pid is the thread group ID, we consider this
+ * a "thread group" signal. Otherwise it degenerates into
+ * a thread-specific signal.
+ */
+static int kill_tg_info(int sig, struct siginfo *info, pid_t pid)
+{
+       int error;
+       struct task_struct *p;
+
+       read_lock(&tasklist_lock);
+       p = find_task_by_pid(pid);
+       error = -ESRCH;
+       if (p) {
+               /* Is it the leader? Otherwise it degenerates into a per-thread thing */
+               if (p->tgid == pid)
+                       error = send_tg_sig_info(sig, info, p);
+               else
+                       error = send_sig_info(sig, info, p);
+       }
+       read_unlock(&tasklist_lock);
+       return error;
+}
+
 /*
  * kill_something_info() interprets pid in interesting ways just like kill(2).
  *
@@ -583,8+685,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
  * is probably wrong.  Should make it like BSD or SYSV.
  */
 
-int
-kill_something_info(int sig, struct siginfo *info, int pid)
+static int kill_something_info(int sig, struct siginfo *info, int pid)
 {
        if (!pid) {
                return kill_pg_info(sig, info, current->pgrp);
@@ -606,7+707,7 @@ kill_something_info(int sig, struct siginfo *info, int pid)
        } else if (pid < 0) {
                return kill_pg_info(sig, info, -pid);
        } else {
-               return kill_proc_info(sig, info, pid);
+               return kill_tg_info(sig, info, pid);
        }
 }
 
@@ -645,11+746,24 @@ kill_proc(pid_t pid, int sig, int priv)
 }
 
 /*
+ * Joy. Or not. Pthread wants us to wake up every thread
+ * in our parent group.
+ */
+static void wake_up_parent(struct task_struct *parent)
+{
+       struct task_struct *tsk = parent;
+
+       do {
+               wake_up_interruptible(&tsk->wait_chldexit);
+               tsk = next_thread(tsk);
+       } while (tsk != parent);
+}
+
+/*
  * Let a parent know about a status change of a child.
  */
 
-void
-notify_parent(struct task_struct *tsk, int sig)
+void do_notify_parent(struct task_struct *tsk, int sig)
 {
        struct siginfo info;
        int why, status;
@@ -693,7+807,23 @@ notify_parent(struct task_struct *tsk, int sig)
        info.si_status = status;
 
        send_sig_info(sig, &info, tsk->p_pptr);
-       wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
+       wake_up_parent(tsk->p_pptr);
+}
+
+
+/*
+ * We need the tasklist lock because it's the only
+ * thing that protects out "parent" pointer.
+ *
+ * exit.c calls "do_notify_parent()" directly, because
+ * it already has the tasklist lock.
+ */
+void
+notify_parent(struct task_struct *tsk, int sig)
+{
+       read_lock(&tasklist_lock);
+       do_notify_parent(tsk, sig);
+       read_unlock(&tasklist_lock);
 }
 
 EXPORT_SYMBOL(dequeue_signal);
index 00ab398..044ba49 100644 (file)
@@ -724,7+724,7 @@ asmlinkage unsigned long sys_alarm(unsigned int seconds)
 asmlinkage long sys_getpid(void)
 {
        /* This is SMP safe - current->pid doesn't change */
-       return current->pid;
+       return current->tgid;
 }
 
 /*
index fbcb2bb..0a8d37b 100644 (file)
@@ -205,7+205,7 @@ found:
                        bdata->last_pos = start+areasize-1;
                        bdata->last_offset = remaining_size;
                }
-               bdata->last_offset &= ~PAGE_MASK;
+               bdata->last_offset &= ~PAGE_MASK;
        } else {
                bdata->last_pos = start + areasize - 1;
                bdata->last_offset = size & ~PAGE_MASK;
index 107f9d8..9772254 100644 (file)
@@ -895,7+895,7 @@ static void generic_file_readahead(int reada_ok,
  * page only.
  */
        if (PageLocked(page)) {
-               if (!filp->f_ralen || index >= raend || index + filp->f_ralen < raend) {
+               if (!filp->f_ralen || index >= raend || index + filp->f_rawin < raend) {
                        raend = index;
                        if (raend < end_index)
                                max_ahead = filp->f_ramax;
@@ -1072,6+1072,7 @@ found_page:
 
                if (!Page_Uptodate(page))
                        goto page_not_up_to_date;
+               generic_file_readahead(reada_ok, filp, inode, page);
 page_ok:
                /*
                 * Ok, we have the page, and it's up-to-date, so
index c2a3ea2..e7167aa 100644 (file)
@@ -632,6+632,9 @@ int ipgre_rcv(struct sk_buff *skb, unsigned short len)
 #ifdef CONFIG_NETFILTER
                nf_conntrack_put(skb->nfct);
                skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+               skb->nf_debug = 0;
+#endif
 #endif
                ipgre_ecn_decapsulate(iph, skb);
                netif_rx(skb);
@@ -858,6+861,9 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 #ifdef CONFIG_NETFILTER
        nf_conntrack_put(skb->nfct);
        skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+       skb->nf_debug = 0;
+#endif
 #endif
 
        IPTUNNEL_XMIT();
index 5792c5d..3d0e2b4 100644 (file)
@@ -5,7+5,7 @@
  *
  *             The Internet Protocol (IP) output module.
  *
- * Version:    $Id: ip_output.c,v 1.83 2000/03/25 01:52:08 davem Exp $
+ * Version:    $Id: ip_output.c,v 1.84 2000/08/25 02:15:47 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -327,6+327,7 @@ static inline int ip_queue_xmit2(struct sk_buff *skb)
                        kfree_skb(skb);
                        return -EHOSTUNREACH;
                }
+               rt = (struct rtable *)skb->dst;
        }
 #endif
 
index 02af22f..eae29c0 100644 (file)
@@ -1,7+1,7 @@
 /*
  *     Linux NET3:     IP/IP protocol decoder. 
  *
- *     Version: $Id: ipip.c,v 1.38 2000/08/02 06:03:59 davem Exp $
+ *     Version: $Id: ipip.c,v 1.39 2000/08/25 02:15:47 davem Exp $
  *
  *     Authors:
  *             Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
@@ -496,6+496,9 @@ int ipip_rcv(struct sk_buff *skb, unsigned short len)
 #ifdef CONFIG_NETFILTER
                nf_conntrack_put(skb->nfct);
                skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+               skb->nf_debug = 0;
+#endif
 #endif
                ipip_ecn_decapsulate(iph, skb);
                netif_rx(skb);
@@ -639,6+642,9 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 #ifdef CONFIG_NETFILTER
        nf_conntrack_put(skb->nfct);
        skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+       skb->nf_debug = 0;
+#endif
 #endif
 
        IPTUNNEL_XMIT();
index b77f878..59048a2 100644 (file)
@@ -6,7+6,7 @@
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *     Alexey Kuznetsov        <kuznet@ms2.inr.ac.ru>
  *
- *     $Id: sit.c,v 1.42 2000/08/02 06:03:59 davem Exp $
+ *     $Id: sit.c,v 1.43 2000/08/25 02:15:47 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -401,6+401,9 @@ int ipip6_rcv(struct sk_buff *skb, unsigned short len)
 #ifdef CONFIG_NETFILTER
                nf_conntrack_put(skb->nfct);
                skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+               skb->nf_debug = 0;
+#endif
 #endif
                ipip6_ecn_decapsulate(iph, skb);
                netif_rx(skb);
@@ -567,6+570,9 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 #ifdef CONFIG_NETFILTER
        nf_conntrack_put(skb->nfct);
        skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+       skb->nf_debug = 0;
+#endif
 #endif
 
        IPTUNNEL_XMIT();
index 6175198..990431e 100644 (file)
@@ -1585,7+1585,7 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len)
 
                        pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1);
                        for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
-                               clear_bit(PG_reserved, &page->flags);
+                               ClearPageReserved(page);
                        free_pages(pg_vec[i], order);
                }
        }
@@ -1640,7+1640,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
 
                        pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1);
                        for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
-                               set_bit(PG_reserved, &page->flags);
+                               SetPageReserved(page);
                }
                /* Page vector is allocated */
 
index 015630d..5691718 100644 (file)
@@ -855,7+855,7 @@ int sock_create(int family, int type, int protocol, struct socket **res)
 
        net_family_read_lock();
        if (net_families[family] == NULL) {
-               i = -EINVAL;
+               i = -EAFNOSUPPORT;
                goto out;
        }
 
@@ -1710,10+1710,9 @@ void __init sock_init(void)
         *      Initialize the protocols module. 
         */
 
-       proto_init();
-
        register_filesystem(&sock_fs_type);
        sock_mnt = kern_mount(&sock_fs_type);
+       proto_init();
 
        /*
         *      The netlink device handler may be needed early.
close